From 546800f34426e1c61dd4c9aa53b47b1d25e9b778 Mon Sep 17 00:00:00 2001 From: baldeau Date: Mon, 28 Apr 2025 19:10:40 +0200 Subject: [PATCH] initial commit --- README.md | 4 + chip8_core/.gitignore | 1 + chip8_core/Cargo.lock | 157 ++++++++++++++ chip8_core/Cargo.toml | 7 + chip8_core/src/lib.rs | 445 +++++++++++++++++++++++++++++++++++++++ desktop/.gitignore | 1 + desktop/Cargo.lock | 206 ++++++++++++++++++ desktop/Cargo.toml | 8 + desktop/c8games/15PUZZLE | Bin 0 -> 384 bytes desktop/c8games/BLINKY | Bin 0 -> 2356 bytes desktop/c8games/BLITZ | Bin 0 -> 391 bytes desktop/c8games/BRIX | Bin 0 -> 280 bytes desktop/c8games/CONNECT4 | Bin 0 -> 194 bytes desktop/c8games/GUESS | Bin 0 -> 148 bytes desktop/c8games/HIDDEN | Bin 0 -> 850 bytes desktop/c8games/INVADERS | Bin 0 -> 1283 bytes desktop/c8games/KALEID | Bin 0 -> 120 bytes desktop/c8games/MAZE | Bin 0 -> 34 bytes desktop/c8games/MERLIN | Bin 0 -> 345 bytes desktop/c8games/MISSILE | Bin 0 -> 180 bytes desktop/c8games/PONG | Bin 0 -> 246 bytes desktop/c8games/PONG2 | Bin 0 -> 264 bytes desktop/c8games/PUZZLE | Bin 0 -> 184 bytes desktop/c8games/SYZYGY | Bin 0 -> 946 bytes desktop/c8games/TANK | Bin 0 -> 560 bytes desktop/c8games/TETRIS | Bin 0 -> 494 bytes desktop/c8games/TICTAC | Bin 0 -> 486 bytes desktop/c8games/UFO | Bin 0 -> 224 bytes desktop/c8games/VBRIX | Bin 0 -> 507 bytes desktop/c8games/VERS | Bin 0 -> 230 bytes desktop/c8games/WIPEOFF | Bin 0 -> 206 bytes desktop/macos.sh | 4 + desktop/src/main.rs | 133 ++++++++++++ 33 files changed, 966 insertions(+) create mode 100644 README.md create mode 100644 chip8_core/.gitignore create mode 100644 chip8_core/Cargo.lock create mode 100644 chip8_core/Cargo.toml create mode 100644 chip8_core/src/lib.rs create mode 100644 desktop/.gitignore create mode 100644 desktop/Cargo.lock create mode 100644 desktop/Cargo.toml create mode 100644 desktop/c8games/15PUZZLE create mode 100644 desktop/c8games/BLINKY create mode 100644 desktop/c8games/BLITZ create mode 100644 desktop/c8games/BRIX create mode 100644 desktop/c8games/CONNECT4 create mode 100644 desktop/c8games/GUESS create mode 100644 desktop/c8games/HIDDEN create mode 100644 desktop/c8games/INVADERS create mode 100644 desktop/c8games/KALEID create mode 100644 desktop/c8games/MAZE create mode 100644 desktop/c8games/MERLIN create mode 100644 desktop/c8games/MISSILE create mode 100644 desktop/c8games/PONG create mode 100644 desktop/c8games/PONG2 create mode 100644 desktop/c8games/PUZZLE create mode 100644 desktop/c8games/SYZYGY create mode 100644 desktop/c8games/TANK create mode 100644 desktop/c8games/TETRIS create mode 100644 desktop/c8games/TICTAC create mode 100644 desktop/c8games/UFO create mode 100644 desktop/c8games/VBRIX create mode 100644 desktop/c8games/VERS create mode 100644 desktop/c8games/WIPEOFF create mode 100755 desktop/macos.sh create mode 100644 desktop/src/main.rs diff --git a/README.md b/README.md new file mode 100644 index 0000000..706fc34 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# chip8_rust + +Full chip8 implementation in Rust. +For learning purposes only. diff --git a/chip8_core/.gitignore b/chip8_core/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/chip8_core/.gitignore @@ -0,0 +1 @@ +/target diff --git a/chip8_core/Cargo.lock b/chip8_core/Cargo.lock new file mode 100644 index 0000000..635e5a6 --- /dev/null +++ b/chip8_core/Cargo.lock @@ -0,0 +1,157 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chip8_core" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/chip8_core/Cargo.toml b/chip8_core/Cargo.toml new file mode 100644 index 0000000..114c724 --- /dev/null +++ b/chip8_core/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "chip8_core" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.9.1" diff --git a/chip8_core/src/lib.rs b/chip8_core/src/lib.rs new file mode 100644 index 0000000..43eaf61 --- /dev/null +++ b/chip8_core/src/lib.rs @@ -0,0 +1,445 @@ +use rand::random; + +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} + +const FONTSET_SIZE: usize = 80; +const FONTSET: [u8; FONTSET_SIZE] = [ + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80, // F +]; + +pub const SCREEN_WIDTH: usize = 64; +pub const SCREEN_HEIGHT: usize = 32; +const RAM_SIZE: usize = 4096; +const NUM_REGS: usize = 16; +const STACK_SIZE: usize = 16; +const NUM_KEYS: usize = 16; +pub struct Emu { + // Program Counter + pc: u16, + ram: [u8; RAM_SIZE], + screen: [bool; SCREEN_WIDTH * SCREEN_HEIGHT], + // V 8-bit registers + v_reg: [u8; NUM_REGS], + // I 16-bit register + i_reg: u16, + // stack pointer + sp: u16, + // 16-bit stack + stack: [u16; STACK_SIZE], + keys: [bool; NUM_KEYS], + // delay timer + dt: u8, + // sound timer + st: u8, +} + +// Chip-8 programs have to start at 0x200 +const START_ADDR: u16 = 0x200; + +impl Emu { + pub fn new() -> Self { + let mut new_emu = Self { + pc: START_ADDR, + ram: [0; RAM_SIZE], + screen: [false; SCREEN_WIDTH * SCREEN_HEIGHT], + v_reg: [0; NUM_REGS], + i_reg: 0, + sp: 0, + stack: [0; STACK_SIZE], + keys: [false; NUM_KEYS], + dt: 0, + st: 0, + }; + new_emu.ram[..FONTSET_SIZE].copy_from_slice(&FONTSET); + new_emu + } + + pub fn reset(&mut self) { + self.pc = START_ADDR; + self.ram = [0; RAM_SIZE]; + self.screen = [false; SCREEN_WIDTH * SCREEN_HEIGHT]; + self.v_reg = [0; NUM_REGS]; + self.i_reg = 0; + self.sp = 0; + self.stack = [0; STACK_SIZE]; + self.keys = [false; NUM_KEYS]; + self.dt = 0; + self.st = 0; + self.ram[..FONTSET_SIZE].copy_from_slice(&FONTSET); + } + + // push to the stack + fn push(&mut self, val: u16) { + self.stack[self.sp as usize] = val; + self.sp += 1; + } + + // pop from the stack + fn pop(&mut self) -> u16 { + self.sp -= 1; + self.stack[self.sp as usize] + } + + // CPU tick + pub fn tick(&mut self) { + // Fetch + let op = self.fetch(); + // Decode & Execute + self.execute(op); + } + fn execute(&mut self, op: u16) { + let digit1 = (op & 0xF000) >> 12; + let digit2 = (op & 0x0F00) >> 8; + let digit3 = (op & 0x00F0) >> 4; + let digit4 = op & 0x000F; + match (digit1, digit2, digit3, digit4) { + // Nop + (0, 0, 0, 0) => return, + // clear screen + (0, 0, 0xE, 0) => self.screen = [false; SCREEN_WIDTH * SCREEN_HEIGHT], + // RET: return from subroutine + (0, 0, 0xE, 0xE) => { + let ret_addr = self.pop(); + self.pc = ret_addr + } + // JMP NNN: jump instruction + (1, _, _, _) => { + let nnn = op & 0xFFF; + self.pc = nnn; + } + // CALL NNN: call subroutine + (2, _, _, _) => { + let nnn = op & 0xFFF; + self.push(self.pc); + self.pc = nnn; + } + // 3XNN: skip next if VX == NN + (3, _, _, _) => { + let x = digit2 as usize; + let nn = (op & 0xFF) as u8; + if self.v_reg[x] == nn { + self.pc += 2; + } + } + // 4XNN: skip next if VX != NN + (4, _, _, _) => { + let x = digit2 as usize; + let nn = (op & 0xFF) as u8; + if self.v_reg[x] != nn { + self.pc += 2; + } + } + // 5XY0: skip next if VX == VY + (5, _, _, 0) => { + let x = digit2 as usize; + let y = digit3 as usize; + if self.v_reg[x] == self.v_reg[y] { + self.pc += 2; + } + } + // 6XNN: VX = NN + // set the V register specified by the second digit + // to the value given + (6, _, _, _) => { + let x = digit2 as usize; + let nn = (op & 0xFF) as u8; + self.v_reg[x] = nn; + } + // 7XNN: VX += NN + // adds the given number to the specified V register + (7, _, _, _) => { + let x = digit2 as usize; + let nn = (op & 0xFF) as u8; + self.v_reg[x] = self.v_reg[x].wrapping_add(nn); + } + // 8XY0: VX = VY + (8, _, _, 0) => { + let x = digit2 as usize; + let y = digit3 as usize; + self.v_reg[x] = self.v_reg[y]; + } + // 8XY1, 8XY2, 8XY3: bitwise operations + // VX |= VY + (8, _, _, 1) => { + let x = digit2 as usize; + let y = digit3 as usize; + self.v_reg[x] |= self.v_reg[y]; + } + // VX &= VY + (8, _, _, 2) => { + let x = digit2 as usize; + let y = digit3 as usize; + self.v_reg[x] &= self.v_reg[y]; + } + // VX ^= VY + (8, _, _, 3) => { + let x = digit2 as usize; + let y = digit3 as usize; + self.v_reg[x] ^= self.v_reg[y]; + } + // 8XY4: VX += VY + (8, _, _, 4) => { + let x = digit2 as usize; + let y = digit3 as usize; + let (new_vx, carry) = self.v_reg[x].overflowing_add(self.v_reg[y]); + // set 16th V register to 1 if overflow + // the 16th V register handles over- and underflows + let new_vf = if carry { 1 } else { 0 }; + self.v_reg[x] = new_vx; + self.v_reg[0xF] = new_vf; + } + // 8XY5: VX -= VY + (8, _, _, 5) => { + let x = digit2 as usize; + let y = digit3 as usize; + let (new_vx, borrow) = self.v_reg[x].overflowing_sub(self.v_reg[y]); + let new_vf = if borrow { 0 } else { 1 }; + self.v_reg[x] = new_vx; + self.v_reg[0xF] = new_vf; + } + // 8XY6: VX >>= 1 + // single right shift on value VX + (8, _, _, 6) => { + let x = digit2 as usize; + let lsb = self.v_reg[x] & 1; + self.v_reg[x] >>= 1; + self.v_reg[0xF] = lsb; + } + // 8XY7: VX = VY - VX + (8, _, _, 7) => { + let x = digit2 as usize; + let y = digit3 as usize; + let (new_vx, borrow) = self.v_reg[y].overflowing_sub(self.v_reg[x]); + let new_vf = if borrow { 0 } else { 1 }; + self.v_reg[x] = new_vx; + self.v_reg[0xF] = new_vf; + } + // 8XYE: VX <<= 1 + // single left shift on value VX + (8, _, _, 0xE) => { + let x = digit2 as usize; + let msb = (self.v_reg[x] >> 7) & 1; + self.v_reg[x] <<= 1; + self.v_reg[0xF] = msb; + } + // 9XY0: skip if VX != VY + (9, _, _, 0) => { + let x = digit2 as usize; + let y = digit3 as usize; + if self.v_reg[x] != self.v_reg[y] { + self.pc += 2; + } + } + // ANNN: I = NNN + // set I register to the 0xNNN value encoded in this opcode + (0xA, _, _, _) => { + let nnn = op & 0xFFF; + self.i_reg = nnn; + } + // BNNN: jump to V0 + NNN + (0xB, _, _, _) => { + let nnn = op & 0xFFF; + self.pc = (self.v_reg[0] as u16) + nnn; + } + // CXNN: VX = rand() & NN + (0xC, _, _, _) => { + let x = digit2 as usize; + let nn = (op & 0xFF) as u8; + let rng: u8 = random(); + self.v_reg[x] = rng & nn; + } + // DRAW + (0xD, _, _, _) => { + // Get the (x, y) coords for our sprite + let x_coord = self.v_reg[digit2 as usize] as u16; + let y_coord = self.v_reg[digit3 as usize] as u16; + // The last digit determines how many rows high our sprite is + let num_rows = digit4; + // Keep track if any pixels were flipped + let mut flipped = false; + // Iterate over each row of our sprite + for y_line in 0..num_rows { + // Determine which memory address our row's data is stored + let addr = self.i_reg + y_line as u16; + let pixels = self.ram[addr as usize]; + // Iterate over each column in our row + for x_line in 0..8 { + if (pixels & (0b1000_0000 >> x_line)) != 0 { + // Sprites should wrap around screen, so apply modulo + let x = (x_coord + x_line) as usize % SCREEN_WIDTH; + let y = (y_coord + y_line) as usize % SCREEN_HEIGHT; + // Get our pixel's index for our 1D screen array + let idx = x + SCREEN_WIDTH * y; + // Check if we're about to flip the pixel and set + flipped |= self.screen[idx]; + self.screen[idx] ^= true; + } + } + } + // Populate VF register + if flipped { + self.v_reg[0xF] = 1; + } else { + self.v_reg[0xF] = 0; + } + } + // EX9E: skip if key pressed + (0xE, _, 9, 0xE) => { + let x = digit2 as usize; + let vx = self.v_reg[x]; + let key = self.keys[vx as usize]; + if key { + self.pc += 2; + } + } + // EXA1: skip if key not pressed + (0xE, _, 0xA, 1) => { + let x = digit2 as usize; + let vx = self.v_reg[x]; + let key = self.keys[vx as usize]; + if !key { + self.pc += 2; + } + } + // VX = DT + (0xF, _, 0, 7) => { + let x = digit2 as usize; + self.v_reg[x] = self.dt; + } + // FX0A: wait for key press + (0xF, _, 0, 0xA) => { + let x = digit2 as usize; + let mut pressed = false; + for i in 0..self.keys.len() { + if self.keys[i] { + self.v_reg[x] = i as u8; + pressed = true; + break; + } + } + if !pressed { + // Redo opcode + self.pc -= 2; + } + } + // FX15: DT = VX + (0xF, _, 1, 5) => { + let x = digit2 as usize; + self.dt = self.v_reg[x]; + } + // FX18: ST = VX + (0xF, _, 1, 8) => { + let x = digit2 as usize; + self.st = self.v_reg[x]; + } + // FX1E: I += VX + (0xF, _, 1, 0xE) => { + let x = digit2 as usize; + let vx = self.v_reg[x] as u16; + self.i_reg = self.i_reg.wrapping_add(vx); + } + // FX29: set I to font address + (0xF, _, 2, 9) => { + let x = digit2 as usize; + let c = self.v_reg[x] as u16; + self.i_reg = c * 5; + } + // FX33: | = BCD of VX + // storing the binary-coded decimal of + // a number stored in the V registers into the I register + (0xF, _, 3, 3) => { + let x = digit2 as usize; + let vx = self.v_reg[x] as f32; + // Fetch the hundreds digit by dividing by 100 and tossing the decimal + let hundreds = (vx / 100.0).floor() as u8; + // Fetch the tens digit by dividing by 10, tossing the ones digit and the decimal + let tens = ((vx / 10.0) % 10.0).floor() as u8; + // Fetch the ones digit by tossing the hundreds and the tens + let ones = (vx % 10.0) as u8; + self.ram[self.i_reg as usize] = hundreds; + self.ram[(self.i_reg + 1) as usize] = tens; + self.ram[(self.i_reg + 2) as usize] = ones; + } + // FX55: Store V0 - VX into I + (0xF, _, 5, 5) => { + let x = digit2 as usize; + let i = self.i_reg as usize; + for idx in 0..=x { + self.ram[i + idx] = self.v_reg[idx]; + } + } + // FX65: load I into V0 - VX + (0xF, _, 6, 5) => { + let x = digit2 as usize; + let i = self.i_reg as usize; + for idx in 0..=x { + self.v_reg[idx] = self.ram[i + idx]; + } + } + (_, _, _, _) => unimplemented!("Unimplemented opcode: {}", op), + } + } + + // grab the instruction we are about to execute (opcode) + pub fn fetch(&mut self) -> u16 { + let higher_byte = self.ram[self.pc as usize] as u16; + let lower_byte = self.ram[(self.pc + 1) as usize] as u16; + let op = (higher_byte << 8) | lower_byte; + self.pc += 2; + op + } + + pub fn tick_timers(&mut self) { + if self.dt > 0 { + self.dt -= 1; + } + if self.st > 0 { + if self.st == 1 { + // BEEP + } + self.st -= 1; + } + } + + pub fn get_display(&self) -> &[bool] { + &self.screen + } + + pub fn keypress(&mut self, idx: usize, pressed: bool) { + self.keys[idx] = pressed; + } + + pub fn load(&mut self, data: &[u8]) { + let start = START_ADDR as usize; + let end = (START_ADDR as usize) + data.len(); + self.ram[start..end].copy_from_slice(data); + } +} diff --git a/desktop/.gitignore b/desktop/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/desktop/.gitignore @@ -0,0 +1 @@ +/target diff --git a/desktop/Cargo.lock b/desktop/Cargo.lock new file mode 100644 index 0000000..2ee8a09 --- /dev/null +++ b/desktop/Cargo.lock @@ -0,0 +1,206 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chip8_core" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "desktop" +version = "0.1.0" +dependencies = [ + "chip8_core", + "sdl2", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "sdl2" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b498da7d14d1ad6c839729bd4ad6fc11d90a57583605f3b4df2cd709a9cd380" +dependencies = [ + "bitflags 1.3.2", + "lazy_static", + "libc", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951deab27af08ed9c6068b7b0d05a93c91f0a8eb16b6b816a5e73452a43521d3" +dependencies = [ + "cfg-if", + "libc", + "version-compare", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml new file mode 100644 index 0000000..c49da0d --- /dev/null +++ b/desktop/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "desktop" +version = "0.1.0" +edition = "2024" + +[dependencies] +chip8_core = { path = "../chip8_core" } +sdl2 = "0.37.0" diff --git a/desktop/c8games/15PUZZLE b/desktop/c8games/15PUZZLE new file mode 100644 index 0000000000000000000000000000000000000000..3ef0bc8e6937b45b8ce559f520fe59ff20ab494b GIT binary patch literal 384 zcmZR0ki+1^kjKA>IYHq=D8mD#eM)6YeM)gkZbAZy3`ye2ERF&U?-srIDEA@NfkDXR zgXSgELdGK26y_Eo69yrrB=KT4AtfO1Q7Uumr6~an?_8J}-lZ_MJW*OE702KcZ z7LQBe0jlSLst1Yx0gIQRi1Pr&S-|3bi(Y&I+P~<t9D$Z+`mMNpl5)=_xgS39m(q>)#b7WgmM%In@ zl5SCvP-OkE;)hLCBK=ZI>xUsyVU;oz%eW3H`H&^;5OE>doK6^5pZC2aZ6>?qeeZdG z&;MWEyYM}M1ET1Q9Pqs{o`@$-kNf%#y?W>s;k7>8CEJT@jgc5z{JB1oKXYkRIE~7} zWhs=eNJ9S3$({-G`-eV2A2J{H2+`ub&83pEe|-?~Q{bPth;HmmzuWsa*+y3(kf2kiir3C>D&J)DxY{}oGacG?!w(xTodk&p@iuK8n@2xQzqu0 z+n9)T`HO?d{!>d&F=-|!+TUvFPueG$0hj&c)2t~qtp<_(($nmd>HxBT1KFYS{L32? zd`~VZb>%A4_~MLYs9kdeq%PRsmQ1k6B_r&aNLQMPptKrcQcOgbQgKL*3fHqpGLcCg zpG!vU%T~gyV=ioPEQXDaKZU6DIA6*4eH{8E>W&isQ_OCJ{r)IqbXX{^cHmG&!;_u< zP`QbB`a?GkixBQqOsdxH1 zmC=wKI10Hom(DTTDUO@-&!XC>t&Kxna=PP);=UH1Y5AKdj@x+4Ur+EK>zEgjbBnN% ztvW56OV|S4-H*dOE(ev>ILxWZE-ntUHt|v%X4h(yOq3@Pc%q!Pcyhf{Qo`bS;OV>? z_DwNi+mu>TT0FV+LFCpGo`#U?0?fVv_wNoO*B6whRnYzbZ9QLg>w%{|dZ({jukqy8 zmz48NNy%5qlNuN4eW6E67#{fJaR!dh}|h*eShwtWW_#N6n-GNivQNVw*se`K*&9p-G7FO_)yI~ zmt;;c@P;(V7VR@1Y;S%+_Z-}>>ROsBvQc>(<}|B z13j)a67tp&;D`Ln5dA@-fC|qKAygYgo-YfwLO+pi0_^YQ+Wk;4B`s>ldK?&%%+a3 z`$?TkuyAeDFUziS|I=BBu(IZE7V>nn77+L99LI7A13Sxc{UjQ;S(1V3hE*_ftd&HX zOlHVJ1#+WZSi!_`X?B@(unJ+zS|7_)0c@GwfOzWL4Zbu3iPjWI*3EK|1nNQMZBlrF z1ho`)6^zCdy8)G)wo9S&c)5>(B#Fx%;LGF`W0gr)$km3g}h6hSF zL1bUSV!3SjGx9x0?rgGW6!N^YNyzdPdlh5#zdM_%{#!8!`PTinV-T{;X6Px%WyoV# zEPeN}J%i9eYX+gl1l9-hgxa$iJ1$f(bv~$MUMzQGV&jJd)(@f|*bNwjx~&<7Rxg$_ zWV|u4lF?E@XmvJ&Aw$i79|ob_AX93YY#oGl<}%bV3Z*hUC}$GV1&JnzBr+v&FIKo9 z4RkAqfsW8wq3a1;iM&ayi`g%Tg2l9i9ySyd{A*xa-2TD%Q)+_lN6kdu3!(+ApENIs zGQ4YUYHs@df}?}=(Y^&c6zm#+;77xcKL-x{Y`lH?H^Z;4Su=mU*LtC;$&jC+=hF{V vv|%5^J|#PoO*d{Z96rndBM%&4fTP<$z#t(3MW{Rp37{M^Ge{1o{`PGER~?*% literal 0 HcmV?d00001 diff --git a/desktop/c8games/BRIX b/desktop/c8games/BRIX new file mode 100644 index 0000000000000000000000000000000000000000..ad639d95754002ee1d541444a6658dbab3f6dcaf GIT binary patch literal 280 zcmc~}O=ZYt%VJo}b8BN2iUhRkPusrLazK`fjbwKz9lduGAtIlAXvb$nD2sM zg2M;V59|gELMF%f)8#T4GygBk;HXzBAVBf=Z=ORd^t)+cRf_)oP zqI|oMyS&gEH--#GH~WnL?hKiX*9z?!g;oJYS0%7El-e@@X~qu{4GD>V8iW?}TqsQV z*U7B(t&~yen`?s5Jt4Qu{|yNZM}c}yB{DUL0_g`}@*S9bk)ZHFVliLc|Aq$*EQt&k z1nn4v4214g{P*~m@n7g&1)~R324e!t2Z_x8LIsOOz8Zf@{ivC2p2Be1wV3sj=4Drg PcMljE82&J8;^b2tfTD1FH>Y^>*LNggM7_%92`Sau#EluD} zG)iK)pnp-nh~G#~$mD|JMa3e<1g=H%L99jd?>_v)b@!nUt5BT{i%?ee|JvWSTtZdZ zY`MBZRW@uwGpZSDS#6DgB0%%*J`@UAwB@(lhg63@LNmG;3VweG?QC8&&yr!$!n;dA UW(fr(eE5(sVM0O!Dv&|}01EU=>i_@% literal 0 HcmV?d00001 diff --git a/desktop/c8games/GUESS b/desktop/c8games/GUESS new file mode 100644 index 0000000000000000000000000000000000000000..36f783da104d05d22093fe2a349736e0da38589d GIT binary patch literal 148 zcmc~}WO$Ivn8ldQ*mI%hkq?8ALdOLqJ1Ykvg)GKuHXHj|Mq7I!t`A%etesE#p4d4E zF=feQ^L9*Nc%Wn_WV2|>593d%N+GwlR