Rumpulator: Change name to Chumpulator
This commit is contained in:
		
							
								
								
									
										18
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -2,6 +2,15 @@
 | 
			
		||||
# It is not intended for manual editing.
 | 
			
		||||
version = 3
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "chumpulator"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "owo-colors",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "owo-colors"
 | 
			
		||||
version = "3.5.0"
 | 
			
		||||
@@ -26,15 +35,6 @@ dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rumpulator"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "owo-colors",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.153"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "rumpulator"
 | 
			
		||||
name = "chumpulator"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ use std::{
 | 
			
		||||
/// Creates a new bus, instantiating BusConnectable devices
 | 
			
		||||
/// # Examples
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// # use rumpulator::prelude::*;
 | 
			
		||||
/// # use chumpulator::prelude::*;
 | 
			
		||||
/// let mut bus = bus! {
 | 
			
		||||
///     "RAM" [0x0000..0x8000] Mem::new(0x8000),
 | 
			
		||||
///     "ROM" [0x8000..0xFFFF] Mem::new(0x8000).w(false),
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,7 @@ impl CPU {
 | 
			
		||||
    /// Set a general purpose register in the CPU
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    /// ```rust
 | 
			
		||||
    /// # use rumpulator::prelude::*;
 | 
			
		||||
    /// # use chumpulator::prelude::*;
 | 
			
		||||
    /// // Create a new CPU, and set v4 to 0x41
 | 
			
		||||
    /// let cpu = CPU::default()
 | 
			
		||||
    ///     .set_gpr(0x4, 0x41);
 | 
			
		||||
@@ -97,7 +97,7 @@ impl CPU {
 | 
			
		||||
    /// | sp     | 0x0efe  | Initial top of stack.
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    /// ```rust
 | 
			
		||||
    /// # use rumpulator::prelude::*;
 | 
			
		||||
    /// # use chumpulator::prelude::*;
 | 
			
		||||
    /// let mut cpu = CPU::new(0xf00, 0x50, 0x200, 0xefe, Disassemble::default());
 | 
			
		||||
    /// ```
 | 
			
		||||
    pub fn new(screen: Adr, font: Adr, pc: Adr, sp: Adr, disassembler: Disassemble) -> Self {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										232
									
								
								src/cpu/instruction.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								src/cpu/instruction.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,232 @@
 | 
			
		||||
//! Represents a chip-8 instruction as a Rust enum
 | 
			
		||||
 | 
			
		||||
use super::{Adr, Nib, Reg};
 | 
			
		||||
type Word = Adr;
 | 
			
		||||
type Byte = u8;
 | 
			
		||||
type Ins = Nib;
 | 
			
		||||
 | 
			
		||||
/// Extract the instruction nibble from a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn i(ins: Word) -> Ins {
 | 
			
		||||
    (ins >> 12) as Ins & 0xf
 | 
			
		||||
}
 | 
			
		||||
/// Extracts the X-register nibble from a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn x(ins: Word) -> Reg {
 | 
			
		||||
    ins as Reg >> 8 & 0xf
 | 
			
		||||
}
 | 
			
		||||
/// Extracts the Y-register nibble from a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn y(ins: u16) -> Reg {
 | 
			
		||||
    ins as Reg >> 4 & 0xf
 | 
			
		||||
}
 | 
			
		||||
/// Extracts the nibble-sized immediate from a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn n(ins: Word) -> Nib {
 | 
			
		||||
    ins as Nib & 0xf
 | 
			
		||||
}
 | 
			
		||||
/// Extracts the byte-sized immediate from a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn b(ins: Word) -> Byte {
 | 
			
		||||
    ins as Byte
 | 
			
		||||
}
 | 
			
		||||
/// Extracts the address-sized immediate from a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn a(ins: Word) -> Adr {
 | 
			
		||||
    ins & 0x0fff
 | 
			
		||||
}
 | 
			
		||||
/// Restores the instruction nibble into a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn ii(i: Ins) -> u16 {
 | 
			
		||||
    (i as Word & 0xf) << 12
 | 
			
		||||
}
 | 
			
		||||
/// Restores the X-register nibble into a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn xi(x: Reg) -> Word {
 | 
			
		||||
    (x as Word & 0xf) << 8
 | 
			
		||||
}
 | 
			
		||||
/// Restores the Y-register nibble into a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn yi(y: Reg) -> Word {
 | 
			
		||||
    (y as Word & 0xf) << 4
 | 
			
		||||
}
 | 
			
		||||
/// Restores the nibble-sized immediate into a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn ni(n: Nib) -> Word {
 | 
			
		||||
    n as Word & 0xf
 | 
			
		||||
}
 | 
			
		||||
/// Restores the byte-sized immediate into a word
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn bi(b: Byte) -> Word {
 | 
			
		||||
    b as Word
 | 
			
		||||
}
 | 
			
		||||
/// Captures the operand and type of a Chip-8 instruction
 | 
			
		||||
pub enum Chip8Instruction {
 | 
			
		||||
    Unimplemented(Word),
 | 
			
		||||
    Clear,
 | 
			
		||||
    Return,
 | 
			
		||||
    Sys(Adr),
 | 
			
		||||
    Jump(Adr),
 | 
			
		||||
    Call(Adr),
 | 
			
		||||
    SkipEqualsByte(Reg, Byte),
 | 
			
		||||
    SkipNotEqualsByte(Reg, Byte),
 | 
			
		||||
    SkipEquals(Reg, Reg),
 | 
			
		||||
    LoadImmediate(Reg, Byte),
 | 
			
		||||
    AddImmediate(Reg, Byte),
 | 
			
		||||
    Copy(Reg, Reg),
 | 
			
		||||
    Or(Reg, Reg),
 | 
			
		||||
    And(Reg, Reg),
 | 
			
		||||
    Xor(Reg, Reg),
 | 
			
		||||
    Add(Reg, Reg),
 | 
			
		||||
    Sub(Reg, Reg),
 | 
			
		||||
    ShiftRight(Reg, Reg),
 | 
			
		||||
    BackwardsSub(Reg, Reg),
 | 
			
		||||
    ShiftLeft(Reg, Reg),
 | 
			
		||||
    SkipNotEquals(Reg, Reg),
 | 
			
		||||
    LoadIndirect(Adr),
 | 
			
		||||
    JumpIndexed(Adr),
 | 
			
		||||
    Rand(Reg, Byte),
 | 
			
		||||
    Draw(Reg, Reg, Nib),
 | 
			
		||||
    SkipEqualsKey(Reg),
 | 
			
		||||
    SkipNotEqualsKey(Reg),
 | 
			
		||||
    StoreDelay(Reg),
 | 
			
		||||
    WaitForKey(Reg),
 | 
			
		||||
    LoadDelay(Reg),
 | 
			
		||||
    LoadSound(Reg),
 | 
			
		||||
    AddIndirect(Reg),
 | 
			
		||||
    LoadSprite(Reg),
 | 
			
		||||
    BcdConvert(Reg),
 | 
			
		||||
    DmaStore(Reg),
 | 
			
		||||
    DmaLoad(Reg),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TryFrom<Word> for Chip8Instruction {
 | 
			
		||||
    type Error = crate::error::Error;
 | 
			
		||||
    /// Converts a 16-bit word into a Chip8Instruction, when possible.
 | 
			
		||||
    fn try_from(opcode: Word) -> Result<Self, Self::Error> {
 | 
			
		||||
        use crate::error::Error::*;
 | 
			
		||||
        let (i, x, y, n, b, a) = (
 | 
			
		||||
            i(opcode),
 | 
			
		||||
            x(opcode),
 | 
			
		||||
            y(opcode),
 | 
			
		||||
            n(opcode),
 | 
			
		||||
            b(opcode),
 | 
			
		||||
            a(opcode),
 | 
			
		||||
        );
 | 
			
		||||
        if i > 0xf {
 | 
			
		||||
            return Err(FunkyMath {
 | 
			
		||||
                word: opcode,
 | 
			
		||||
                explanation: "Instruction nibble greater than 0xf".into(),
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        Ok(match i {
 | 
			
		||||
            // # Issue a system call
 | 
			
		||||
            // |opcode| effect                             |
 | 
			
		||||
            // |------|------------------------------------|
 | 
			
		||||
            // | 00e0 | Clear screen memory to all 0       |
 | 
			
		||||
            // | 00ee | Return from subroutine             |
 | 
			
		||||
            0x0 => match a {
 | 
			
		||||
                0xe0 => Self::Clear,
 | 
			
		||||
                0xee => Self::Return,
 | 
			
		||||
                _ => Self::Sys(a),
 | 
			
		||||
            },
 | 
			
		||||
            // | 1aaa | Sets pc to an absolute address
 | 
			
		||||
            0x1 => Self::Jump(a),
 | 
			
		||||
            // | 2aaa | Pushes pc onto the stack, then jumps to a
 | 
			
		||||
            0x2 => Self::Call(a),
 | 
			
		||||
            // | 3xbb | Skips next instruction if register X == b
 | 
			
		||||
            0x3 => Self::SkipEqualsByte(x, b),
 | 
			
		||||
            // | 4xbb | Skips next instruction if register X != b
 | 
			
		||||
            0x4 => Self::SkipNotEqualsByte(x, b),
 | 
			
		||||
            // # Performs a register-register comparison
 | 
			
		||||
            // |opcode| effect                             |
 | 
			
		||||
            // |------|------------------------------------|
 | 
			
		||||
            // | 9XY0 | Skip next instruction if vX == vY  |
 | 
			
		||||
            0x5 => match n {
 | 
			
		||||
                0x0 => Self::SkipEquals(x, y),
 | 
			
		||||
                _ => Self::Unimplemented(opcode),
 | 
			
		||||
            },
 | 
			
		||||
            // 6xbb: Loads immediate byte b into register vX
 | 
			
		||||
            0x6 => Self::LoadImmediate(x, b),
 | 
			
		||||
            // 7xbb: Adds immediate byte b to register vX
 | 
			
		||||
            0x7 => Self::AddImmediate(x, b),
 | 
			
		||||
            // # Performs ALU operation
 | 
			
		||||
            // |opcode| effect                             |
 | 
			
		||||
            // |------|------------------------------------|
 | 
			
		||||
            // | 8xy0 | X = Y                              |
 | 
			
		||||
            // | 8xy1 | X = X | Y                          |
 | 
			
		||||
            // | 8xy2 | X = X & Y                          |
 | 
			
		||||
            // | 8xy3 | X = X ^ Y                          |
 | 
			
		||||
            // | 8xy4 | X = X + Y; Set vF=carry            |
 | 
			
		||||
            // | 8xy5 | X = X - Y; Set vF=carry            |
 | 
			
		||||
            // | 8xy6 | X = X >> 1                         |
 | 
			
		||||
            // | 8xy7 | X = Y - X; Set vF=carry            |
 | 
			
		||||
            // | 8xyE | X = X << 1                         |
 | 
			
		||||
            0x8 => match n {
 | 
			
		||||
                0x0 => Self::Copy(x, y),
 | 
			
		||||
                0x1 => Self::Or(x, y),
 | 
			
		||||
                0x2 => Self::And(x, y),
 | 
			
		||||
                0x3 => Self::Xor(x, y),
 | 
			
		||||
                0x4 => Self::Add(x, y),
 | 
			
		||||
                0x5 => Self::Sub(x, y),
 | 
			
		||||
                0x6 => Self::ShiftRight(x, y),
 | 
			
		||||
                0x7 => Self::BackwardsSub(x, y),
 | 
			
		||||
                0xE => Self::ShiftLeft(x, y),
 | 
			
		||||
                _ => Self::Unimplemented(opcode),
 | 
			
		||||
            },
 | 
			
		||||
            // # Performs a register-register comparison
 | 
			
		||||
            // |opcode| effect                             |
 | 
			
		||||
            // |------|------------------------------------|
 | 
			
		||||
            // | 9XY0 | Skip next instruction if vX != vY  |
 | 
			
		||||
            0x9 => match n {
 | 
			
		||||
                0 => Self::SkipNotEquals(x, y),
 | 
			
		||||
                _ => Self::Unimplemented(opcode),
 | 
			
		||||
            },
 | 
			
		||||
            // Aaaa: Load address #a into register I
 | 
			
		||||
            0xa => Self::LoadIndirect(a),
 | 
			
		||||
            // Baaa: Jump to &adr + v0
 | 
			
		||||
            0xb => Self::JumpIndexed(a),
 | 
			
		||||
            // Cxbb: Stores a random number & the provided byte into vX
 | 
			
		||||
            0xc => Self::Rand(x, b),
 | 
			
		||||
            // Dxyn: Draws n-byte sprite to the screen at coordinates (vX, vY)
 | 
			
		||||
            0xd => Self::Draw(x, y, n),
 | 
			
		||||
 | 
			
		||||
            // # Skips instruction on value of keypress
 | 
			
		||||
            // |opcode| effect                             |
 | 
			
		||||
            // |------|------------------------------------|
 | 
			
		||||
            // | eX9e | Skip next instruction if key == #X |
 | 
			
		||||
            // | eXa1 | Skip next instruction if key != #X |
 | 
			
		||||
            0xe => match b {
 | 
			
		||||
                0x9e => Self::SkipEqualsKey(x),
 | 
			
		||||
                0xa1 => Self::SkipNotEqualsKey(x),
 | 
			
		||||
                _ => Self::Unimplemented(opcode),
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // # Performs IO
 | 
			
		||||
            // |opcode| effect                             |
 | 
			
		||||
            // |------|------------------------------------|
 | 
			
		||||
            // | fX07 | Set vX to value in delay timer     |
 | 
			
		||||
            // | fX0a | Wait for input, store in vX m      |
 | 
			
		||||
            // | fX15 | Set sound timer to the value in vX |
 | 
			
		||||
            // | fX18 | set delay timer to the value in vX |
 | 
			
		||||
            // | fX1e | Add x to I                         |
 | 
			
		||||
            // | fX29 | Load sprite for character x into I |
 | 
			
		||||
            // | fX33 | BCD convert X into I[0..3]         |
 | 
			
		||||
            // | fX55 | DMA Stor from I to registers 0..X  |
 | 
			
		||||
            // | fX65 | DMA Load from I to registers 0..X  |
 | 
			
		||||
            0xf => match b {
 | 
			
		||||
                0x07 => Self::StoreDelay(x),
 | 
			
		||||
                0x0A => Self::WaitForKey(x),
 | 
			
		||||
                0x15 => Self::LoadDelay(x),
 | 
			
		||||
                0x18 => Self::LoadSound(x),
 | 
			
		||||
                0x1E => Self::AddIndirect(x),
 | 
			
		||||
                0x29 => Self::LoadSprite(x),
 | 
			
		||||
                0x33 => Self::BcdConvert(x),
 | 
			
		||||
                0x55 => Self::DmaStore(x),
 | 
			
		||||
                0x65 => Self::DmaLoad(x),
 | 
			
		||||
                _ => Self::Unimplemented(opcode),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("i somehow mutated from <= 0xf to > 0xf"),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,7 @@ use std::ops::Range;
 | 
			
		||||
///
 | 
			
		||||
/// # Examples
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// # use rumpulator::prelude::*;
 | 
			
		||||
/// # use chumpulator::prelude::*;
 | 
			
		||||
/// let mem = Mem::new(0x50);
 | 
			
		||||
/// // Dumps the first 0x10 bytes
 | 
			
		||||
/// mem.dump(0x00..0x10);
 | 
			
		||||
@@ -19,7 +19,7 @@ pub trait Dumpable {
 | 
			
		||||
///
 | 
			
		||||
/// # Examples
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// # use rumpulator::prelude::*;
 | 
			
		||||
/// # use chumpulator::prelude::*;
 | 
			
		||||
/// let mem = bus! {
 | 
			
		||||
///    "mem" [0..0x10] = Mem::new(0x10)
 | 
			
		||||
/// };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
//! Error type for rumpulator
 | 
			
		||||
//! Error type for chumpulator
 | 
			
		||||
 | 
			
		||||
use thiserror::Error;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ pub mod dump;
 | 
			
		||||
pub mod error;
 | 
			
		||||
pub mod screen;
 | 
			
		||||
 | 
			
		||||
/// Common imports for rumpulator
 | 
			
		||||
/// Common imports for chumpulator
 | 
			
		||||
pub mod prelude {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    pub use crate::bus;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use rumpulator::{bus::Read, prelude::*};
 | 
			
		||||
use chumpulator::{bus::Read, prelude::*};
 | 
			
		||||
use std::fs::read;
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), std::io::Error> {
 | 
			
		||||
@@ -8,7 +8,7 @@ fn main() -> Result<(), std::io::Error> {
 | 
			
		||||
        // Load the ROM file into RAM
 | 
			
		||||
        "userram" [0x0200..0x0F00] = Mem::new(0xF00 - 0x200).load(0, &read("chip-8/Fishie.ch8")?),
 | 
			
		||||
        // Create a screen
 | 
			
		||||
        "screen"  [0x0F00..0x1000] = Screen::new(32, 64),
 | 
			
		||||
        "screen"  [0x0F00..0x1000] = Mem::new(32*64/8),
 | 
			
		||||
        // Create some stack memory
 | 
			
		||||
        "stack"   [0xF000..0xF800] = Mem::new(0x800).r(true).w(true),
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ impl Mem {
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    /// ``` rust
 | 
			
		||||
    /// # use rumpulator::prelude::*;
 | 
			
		||||
    /// # use chumpulator::prelude::*;
 | 
			
		||||
    /// let mem = Mem::new(0x100);
 | 
			
		||||
    /// assert_eq!(mem.len(), 0x100)
 | 
			
		||||
    /// ```
 | 
			
		||||
@@ -84,7 +84,7 @@ impl Mem {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Load a character set from rumpulator/src/mem/charset.bin into this memory section
 | 
			
		||||
    /// Load a character set from chumpulator/src/mem/charset.bin into this memory section
 | 
			
		||||
    pub fn load_charset(self, addr: u16) -> Self {
 | 
			
		||||
        let charset = include_bytes!("mem/charset.bin");
 | 
			
		||||
        self.load(addr, charset)
 | 
			
		||||
@@ -94,7 +94,7 @@ impl Mem {
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Examples
 | 
			
		||||
    /// ```rust
 | 
			
		||||
    /// # use rumpulator::prelude::*;
 | 
			
		||||
    /// # use chumpulator::prelude::*;
 | 
			
		||||
    /// let length = 0x100;
 | 
			
		||||
    /// let mem = Mem::new(length);
 | 
			
		||||
    /// ```
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user