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. | # It is not intended for manual editing. | ||||||
| version = 3 | version = 3 | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "chumpulator" | ||||||
|  | version = "0.1.0" | ||||||
|  | dependencies = [ | ||||||
|  |  "owo-colors", | ||||||
|  |  "serde", | ||||||
|  |  "thiserror", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "owo-colors" | name = "owo-colors" | ||||||
| version = "3.5.0" | version = "3.5.0" | ||||||
| @@ -26,15 +35,6 @@ dependencies = [ | |||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "rumpulator" |  | ||||||
| version = "0.1.0" |  | ||||||
| dependencies = [ |  | ||||||
|  "owo-colors", |  | ||||||
|  "serde", |  | ||||||
|  "thiserror", |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde" | name = "serde" | ||||||
| version = "1.0.153" | version = "1.0.153" | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| [package] | [package] | ||||||
| name = "rumpulator" | name = "chumpulator" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| edition = "2021" | edition = "2021" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ use std::{ | |||||||
| /// Creates a new bus, instantiating BusConnectable devices | /// Creates a new bus, instantiating BusConnectable devices | ||||||
| /// # Examples | /// # Examples | ||||||
| /// ```rust | /// ```rust | ||||||
| /// # use rumpulator::prelude::*; | /// # use chumpulator::prelude::*; | ||||||
| /// let mut bus = bus! { | /// let mut bus = bus! { | ||||||
| ///     "RAM" [0x0000..0x8000] Mem::new(0x8000), | ///     "RAM" [0x0000..0x8000] Mem::new(0x8000), | ||||||
| ///     "ROM" [0x8000..0xFFFF] Mem::new(0x8000).w(false), | ///     "ROM" [0x8000..0xFFFF] Mem::new(0x8000).w(false), | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ impl CPU { | |||||||
|     /// Set a general purpose register in the CPU |     /// Set a general purpose register in the CPU | ||||||
|     /// # Examples |     /// # Examples | ||||||
|     /// ```rust |     /// ```rust | ||||||
|     /// # use rumpulator::prelude::*; |     /// # use chumpulator::prelude::*; | ||||||
|     /// // Create a new CPU, and set v4 to 0x41 |     /// // Create a new CPU, and set v4 to 0x41 | ||||||
|     /// let cpu = CPU::default() |     /// let cpu = CPU::default() | ||||||
|     ///     .set_gpr(0x4, 0x41); |     ///     .set_gpr(0x4, 0x41); | ||||||
| @@ -97,7 +97,7 @@ impl CPU { | |||||||
|     /// | sp     | 0x0efe  | Initial top of stack. |     /// | sp     | 0x0efe  | Initial top of stack. | ||||||
|     /// # Examples |     /// # Examples | ||||||
|     /// ```rust |     /// ```rust | ||||||
|     /// # use rumpulator::prelude::*; |     /// # use chumpulator::prelude::*; | ||||||
|     /// let mut cpu = CPU::new(0xf00, 0x50, 0x200, 0xefe, Disassemble::default()); |     /// 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 { |     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 | /// # Examples | ||||||
| /// ```rust | /// ```rust | ||||||
| /// # use rumpulator::prelude::*; | /// # use chumpulator::prelude::*; | ||||||
| /// let mem = Mem::new(0x50); | /// let mem = Mem::new(0x50); | ||||||
| /// // Dumps the first 0x10 bytes | /// // Dumps the first 0x10 bytes | ||||||
| /// mem.dump(0x00..0x10); | /// mem.dump(0x00..0x10); | ||||||
| @@ -19,7 +19,7 @@ pub trait Dumpable { | |||||||
| /// | /// | ||||||
| /// # Examples | /// # Examples | ||||||
| /// ```rust | /// ```rust | ||||||
| /// # use rumpulator::prelude::*; | /// # use chumpulator::prelude::*; | ||||||
| /// let mem = bus! { | /// let mem = bus! { | ||||||
| ///    "mem" [0..0x10] = Mem::new(0x10) | ///    "mem" [0..0x10] = Mem::new(0x10) | ||||||
| /// }; | /// }; | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| //! Error type for rumpulator | //! Error type for chumpulator | ||||||
|  |  | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ pub mod dump; | |||||||
| pub mod error; | pub mod error; | ||||||
| pub mod screen; | pub mod screen; | ||||||
|  |  | ||||||
| /// Common imports for rumpulator | /// Common imports for chumpulator | ||||||
| pub mod prelude { | pub mod prelude { | ||||||
|     use super::*; |     use super::*; | ||||||
|     pub use crate::bus; |     pub use crate::bus; | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| use rumpulator::{bus::Read, prelude::*}; | use chumpulator::{bus::Read, prelude::*}; | ||||||
| use std::fs::read; | use std::fs::read; | ||||||
|  |  | ||||||
| fn main() -> Result<(), std::io::Error> { | fn main() -> Result<(), std::io::Error> { | ||||||
| @@ -8,7 +8,7 @@ fn main() -> Result<(), std::io::Error> { | |||||||
|         // Load the ROM file into RAM |         // Load the ROM file into RAM | ||||||
|         "userram" [0x0200..0x0F00] = Mem::new(0xF00 - 0x200).load(0, &read("chip-8/Fishie.ch8")?), |         "userram" [0x0200..0x0F00] = Mem::new(0xF00 - 0x200).load(0, &read("chip-8/Fishie.ch8")?), | ||||||
|         // Create a screen |         // Create a screen | ||||||
|         "screen"  [0x0F00..0x1000] = Screen::new(32, 64), |         "screen"  [0x0F00..0x1000] = Mem::new(32*64/8), | ||||||
|         // Create some stack memory |         // Create some stack memory | ||||||
|         "stack"   [0xF000..0xF800] = Mem::new(0x800).r(true).w(true), |         "stack"   [0xF000..0xF800] = Mem::new(0x800).r(true).w(true), | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -63,7 +63,7 @@ impl Mem { | |||||||
|     /// |     /// | ||||||
|     /// # Examples |     /// # Examples | ||||||
|     /// ``` rust |     /// ``` rust | ||||||
|     /// # use rumpulator::prelude::*; |     /// # use chumpulator::prelude::*; | ||||||
|     /// let mem = Mem::new(0x100); |     /// let mem = Mem::new(0x100); | ||||||
|     /// assert_eq!(mem.len(), 0x100) |     /// assert_eq!(mem.len(), 0x100) | ||||||
|     /// ``` |     /// ``` | ||||||
| @@ -84,7 +84,7 @@ impl Mem { | |||||||
|         self |         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 { |     pub fn load_charset(self, addr: u16) -> Self { | ||||||
|         let charset = include_bytes!("mem/charset.bin"); |         let charset = include_bytes!("mem/charset.bin"); | ||||||
|         self.load(addr, charset) |         self.load(addr, charset) | ||||||
| @@ -94,7 +94,7 @@ impl Mem { | |||||||
|     /// |     /// | ||||||
|     /// # Examples |     /// # Examples | ||||||
|     /// ```rust |     /// ```rust | ||||||
|     /// # use rumpulator::prelude::*; |     /// # use chumpulator::prelude::*; | ||||||
|     /// let length = 0x100; |     /// let length = 0x100; | ||||||
|     /// let mem = Mem::new(length); |     /// let mem = Mem::new(length); | ||||||
|     /// ``` |     /// ``` | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user