diff --git a/Cargo.lock b/Cargo.lock index 51525ae..c65940c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,6 +226,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.89" @@ -758,6 +807,46 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "clipboard-win" version = "3.1.1" @@ -848,6 +937,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "com" version = "0.6.0" @@ -1095,7 +1190,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] @@ -1734,6 +1829,14 @@ dependencies = [ "gemma", ] +[[package]] +name = "gemmautil" +version = "0.1.0" +dependencies = [ + "clap", + "gemma", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2068,6 +2171,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.4.0" @@ -2269,6 +2378,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "jni" version = "0.21.1" @@ -3804,6 +3919,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -4091,6 +4212,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index d4f6863..fa81538 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["gemma", "gemmaegui", "gemmaimgui", "gemmatelnet", "gemmasdl2" ] +members = ["gemma", "gemmaegui", "gemmaimgui", "gemmatelnet", "gemmasdl2", "gemmautil" ] resolver = "2" [workspace.dependencies] diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs index 0569a0b..831214a 100644 --- a/gemma/src/chip8/instructions.rs +++ b/gemma/src/chip8/instructions.rs @@ -143,6 +143,8 @@ pub enum Chip8CpuInstructions { /// Dxyn /// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision. /// + /// In Chip-8, + /// /// The interpreter reads n bytes from memory, starting at the address stored in I. /// These bytes are then displayed as sprites on screen at coordinates (Vx, Vy). /// Sprites are XORed onto the existing screen. If this causes any pixels to be erased, @@ -150,6 +152,11 @@ pub enum Chip8CpuInstructions { /// it is outside the coordinates of the display, it wraps around to the opposite side /// of the screen. See instruction 8xy3 for more information on XOR, and section 2.4, /// Display, for more information on the Chip-8 screen and sprites. + /// + /// In SCHIP + /// + /// Show N-byte sprite from M(I) at Coords (VX,VY) VF = Collision. + /// If N=0 AND ExtendedMode, 16x16 sprite DrawVxVyNibble(u8, u8, u8), /// Ex9E /// Skip next instruction if key with the value of Vx is pressed. @@ -213,153 +220,127 @@ pub enum Chip8CpuInstructions { /// V0 through Vx. LdVxI(u8), XXXXERRORINSTRUCTION, + /* START OF SCHIP-8 */ + /// 00CN + /// + /// Scrolll Display N Lines Down + ScrDn(u8), + /// 00FB + /// + /// Scroll 4 lines Right + ScrRt, + /// 00FC + /// + /// Scroll 4 lines Left + ScrLf, + /// 00FE + /// + /// Disable Extended Mode + VidDis, + /// 00FF + /// + /// Enable Extended Mode + VidEna, + /// 00FD + /// + /// Exit App + Exit, + /// FX30 + /// + /// Point I to 10 yte font sprite for digit VX (0..9) + LdFVx10(u8), + /// FX75 + /// + /// Store V0..VX in RPL user flags (X <= 7 + StRpl(u8), + /// FX85 + /// + /// Load V0..VX from RPL user flags (X <= 7) + LdRpl(u8), } impl Chip8CpuInstructions { pub fn name(&self) -> &str { match self { - Chip8CpuInstructions::SysAddr(_) => { - "SYS" - } - Chip8CpuInstructions::CLS => { - "CLS" - } - Chip8CpuInstructions::RET => { - "RET" - } - Chip8CpuInstructions::JpAddr(_) => { - "JPA" - } - Chip8CpuInstructions::CallAddr(_) => { - "CALL" - } - Chip8CpuInstructions::SeVxByte(_, _) => { - "SeVxByte" - } - Chip8CpuInstructions::SneVxByte(_, _) => { - "SneVxByte" - } - Chip8CpuInstructions::SeVxVy(_, _) => { - "SeVeVy" - } - Chip8CpuInstructions::LdVxByte(_, _) => { - "LdVxByte" - } - Chip8CpuInstructions::AddVxByte(_, _) => { - "AddVxByte" - } - Chip8CpuInstructions::LdVxVy(_, _) => { - "LdVxVy" - } - Chip8CpuInstructions::OrVxVy(_, _) => { - "OrVxVy" - } - Chip8CpuInstructions::AndVxVy(_, _) => { - "AndVxVy" - } - Chip8CpuInstructions::XorVxVy(_, _) => { - "XorVxVy" - } - Chip8CpuInstructions::AddVxVy(_, _) => { - "AddVxVy" - } - Chip8CpuInstructions::SubVxVy(_, _) => { - "SubVxVy" - } - Chip8CpuInstructions::ShrVxVy(_, _) => { - "ShrVxVy" - } - Chip8CpuInstructions::SubnVxVy(_, _) => { - "SubnVxVy" - } - Chip8CpuInstructions::ShlVxVy(_, _) => { - "ShlVxVy" - } - Chip8CpuInstructions::SneVxVy(_, _) => { - "SneVxVy" - } - Chip8CpuInstructions::LdIAddr(_) => { - "LdIAddr" - } - Chip8CpuInstructions::JpV0Addr(_) => { - "JpV0Addr" - } - Chip8CpuInstructions::RndVxByte(_, _) => { - "RndVxByte" - } - Chip8CpuInstructions::DrawVxVyNibble(_, _, _) => { - "DrawVxVyNibble" - } - Chip8CpuInstructions::SkpVx(_) => { - "SkpVx" - } - Chip8CpuInstructions::SnkpVx(_) => { - "SnkpVx" - } - Chip8CpuInstructions::LdVxDt(_) => { - "LdVxDt" - } - Chip8CpuInstructions::LdVxK(_) => { - "LdVxK" - } - Chip8CpuInstructions::LdDtVx(_) => { - "LdDtVx" - } - Chip8CpuInstructions::LdStVx(_) => { - "LdStVx" - } - Chip8CpuInstructions::AddIVx(_) => { - "AddIVx" - } - Chip8CpuInstructions::LdFVx(_) => { - "LdFVx" - } - Chip8CpuInstructions::LdBVx(_) => { - "LdBVx" - } - Chip8CpuInstructions::LdIVx(_) => { - "LdIVx" - } - Chip8CpuInstructions::LdVxI(_) => { - "LdVxI" - } - XXXXERRORINSTRUCTION => { - "XX ERROR XX" - } + Chip8CpuInstructions::AddIVx(_) => "AddIVx", + Chip8CpuInstructions::AddVxByte(_, _) => "AddVxByte", + Chip8CpuInstructions::AddVxVy(_, _) => "AddVxVy", + Chip8CpuInstructions::AndVxVy(_, _) => "AndVxVy", + Chip8CpuInstructions::CLS => "CLS", + Chip8CpuInstructions::CallAddr(_) => "CALL", + Chip8CpuInstructions::DrawVxVyNibble(_, _, _) => "DrawVxVyNibble", + Chip8CpuInstructions::Exit => "EXIT", + Chip8CpuInstructions::JpAddr(_) => "JPA", + Chip8CpuInstructions::JpV0Addr(_) => "JpV0Addr", + Chip8CpuInstructions::LdBVx(_) => "LdBVx", + Chip8CpuInstructions::LdDtVx(_) => "LdDtVx", + Chip8CpuInstructions::LdFVx(_) => "LdFVx", + Chip8CpuInstructions::LdFVx10(x) => "LdFVx10", + Chip8CpuInstructions::LdIAddr(_) => "LdIAddr", + Chip8CpuInstructions::LdIVx(_) => "LdIVx", + Chip8CpuInstructions::LdRpl(x) => "LdRpl", + Chip8CpuInstructions::LdStVx(_) => "LdStVx", + Chip8CpuInstructions::LdVxByte(_, _) => "LdVxByte", + Chip8CpuInstructions::LdVxDt(_) => "LdVxDt", + Chip8CpuInstructions::LdVxI(_) => "LdVxI", + Chip8CpuInstructions::LdVxK(_) => "LdVxK", + Chip8CpuInstructions::LdVxVy(_, _) => "LdVxVy", + Chip8CpuInstructions::OrVxVy(_, _) => "OrVxVy", + Chip8CpuInstructions::RET => "RET", + Chip8CpuInstructions::RndVxByte(_, _) => "RndVxByte", + Chip8CpuInstructions::ScrDn(_) => "ScrDn", + Chip8CpuInstructions::ScrLf => "ScrLf", + Chip8CpuInstructions::ScrRt => "ScrRt", + Chip8CpuInstructions::SeVxByte(_, _) => "SeVxByte", + Chip8CpuInstructions::SeVxVy(_, _) => "SeVeVy", + Chip8CpuInstructions::ShlVxVy(_, _) => "ShlVxVy", + Chip8CpuInstructions::ShrVxVy(_, _) => "ShrVxVy", + Chip8CpuInstructions::SkpVx(_) => "SkpVx", + Chip8CpuInstructions::SneVxByte(_, _) => "SneVxByte", + Chip8CpuInstructions::SneVxVy(_, _) => "SneVxVy", + Chip8CpuInstructions::SnkpVx(_) => "SnkpVx", + Chip8CpuInstructions::StRpl(x) => "StRpl", + Chip8CpuInstructions::SubVxVy(_, _) => "SubVxVy", + Chip8CpuInstructions::SubnVxVy(_, _) => "SubnVxVy", + Chip8CpuInstructions::SysAddr(_) => "SYS", + Chip8CpuInstructions::VidDis => "VidDis", + Chip8CpuInstructions::VidEna => "VidEna", + Chip8CpuInstructions::XorVxVy(_, _) => "XorVxVy", + XXXXERRORINSTRUCTION => "XX ERROR XX", } } pub fn operands(&self) -> String { match self { Chip8CpuInstructions::SysAddr(addr) | - Chip8CpuInstructions::JpV0Addr(addr) | + Chip8CpuInstructions::JpV0Addr(addr) | Chip8CpuInstructions::JpAddr(addr) | Chip8CpuInstructions::LdIAddr(addr) | Chip8CpuInstructions::CallAddr(addr) => { - format!("{addr:04x}") + format!("0x{addr:04x}") } Chip8CpuInstructions::SeVxByte(x, byte) | Chip8CpuInstructions::SneVxByte(x, byte) | Chip8CpuInstructions::LdVxByte(x, byte) | Chip8CpuInstructions::RndVxByte(x, byte) | Chip8CpuInstructions::AddVxByte(x, byte) => { - format!("{x:02x}, {byte:04x}") + format!("0x{x:02x}, 0x{byte:02x}") } - Chip8CpuInstructions::SeVxVy(x,y) | - Chip8CpuInstructions::LdVxVy(x,y) | - Chip8CpuInstructions::OrVxVy(x,y) | - Chip8CpuInstructions::AndVxVy(x,y) | - Chip8CpuInstructions::XorVxVy(x,y) | - Chip8CpuInstructions::AddVxVy(x,y) | - Chip8CpuInstructions::SubVxVy(x,y) | - Chip8CpuInstructions::ShrVxVy(x,y) | - Chip8CpuInstructions::SubnVxVy(x,y) | - Chip8CpuInstructions::ShlVxVy(x,y) | - Chip8CpuInstructions::SneVxVy(x,y) => { - format!("{x:02x}, {y:02x}") + Chip8CpuInstructions::SeVxVy(x, y) | + Chip8CpuInstructions::LdVxVy(x, y) | + Chip8CpuInstructions::OrVxVy(x, y) | + Chip8CpuInstructions::AndVxVy(x, y) | + Chip8CpuInstructions::XorVxVy(x, y) | + Chip8CpuInstructions::AddVxVy(x, y) | + Chip8CpuInstructions::SubVxVy(x, y) | + Chip8CpuInstructions::ShrVxVy(x, y) | + Chip8CpuInstructions::SubnVxVy(x, y) | + Chip8CpuInstructions::ShlVxVy(x, y) | + Chip8CpuInstructions::SneVxVy(x, y) => { + format!("0x{x:02x}, 0x{y:02x}") } - Chip8CpuInstructions::DrawVxVyNibble(x,y,nibble) => { - format!("{x:02x}, {y:02x}, {nibble:02x}") + Chip8CpuInstructions::DrawVxVyNibble(x, y, nibble) => { + format!("0x{x:02x}, 0x{y:02x}, 0x{nibble:02x}") } Chip8CpuInstructions::LdDtVx(x) | Chip8CpuInstructions::LdStVx(x) | @@ -371,12 +352,13 @@ impl Chip8CpuInstructions { Chip8CpuInstructions::LdVxDt(x) | Chip8CpuInstructions::LdVxK(x) | Chip8CpuInstructions::LdVxI(x) | - Chip8CpuInstructions::SnkpVx(x) => { - format!("{x:02x}") - } - _ => { - "".parse().unwrap() + Chip8CpuInstructions::LdFVx10(x) | + Chip8CpuInstructions::StRpl(x) | + Chip8CpuInstructions::LdRpl(x) | + Chip8CpuInstructions::SnkpVx(x) => { + format!("0x{x:02x}") } + _ => { String::new() } } } } @@ -427,7 +409,16 @@ impl Chip8CpuInstructions { Chip8CpuInstructions::LdBVx(x_register) => 0xF033 | ((*x_register as u16) << 8), Chip8CpuInstructions::LdIVx(x_register) => 0xF055 | ((*x_register as u16) << 8), Chip8CpuInstructions::LdVxI(x_register) => 0xF065 | ((*x_register as u16) << 8), - XXXXERRORINSTRUCTION => 0xFFFF, + Chip8CpuInstructions::ScrDn(x_register) => 0x00C0 | (*x_register as u16), + Chip8CpuInstructions::ScrRt => 0x00FB, + Chip8CpuInstructions::ScrLf => 0x00FC, + Chip8CpuInstructions::VidDis => 0x00FE, + Chip8CpuInstructions::VidEna => 0x00FF, + Chip8CpuInstructions::Exit => 0x00FD, + Chip8CpuInstructions::LdFVx10(x_register) => 0xF030 | ((*x_register as u16) << 8), + Chip8CpuInstructions::StRpl(x_register) => 0xF075 | ((*x_register as u16) << 8), + Chip8CpuInstructions::LdRpl(x_register) => 0xF085 | ((*x_register as u16) << 8), + XXXXERRORINSTRUCTION => 0xFFFF } } pub fn decode(input: u16) -> Chip8CpuInstructions { @@ -441,8 +432,14 @@ impl Chip8CpuInstructions { let last_nibble = (input & 0xF) as u8; match input { + 0x00C0..=0x00CF => Chip8CpuInstructions::ScrDn(last_nibble), 0x00E0 => Chip8CpuInstructions::CLS, 0x00EE => Chip8CpuInstructions::RET, + 0x00FB => Chip8CpuInstructions::ScrRt, + 0x00FC => Chip8CpuInstructions::ScrLf, + 0x00FD => Chip8CpuInstructions::Exit, + 0x00FE => Chip8CpuInstructions::VidDis, + 0x00FF => Chip8CpuInstructions::VidEna, 0x0000..=0x0FFF => Chip8CpuInstructions::SysAddr(addr_param), 0x1000..=0x1FFF => Chip8CpuInstructions::JpAddr(addr_param), 0x2000..=0x2FFF => Chip8CpuInstructions::CallAddr(addr_param), @@ -480,9 +477,12 @@ impl Chip8CpuInstructions { 0x18 => Chip8CpuInstructions::LdStVx(ubln), 0x1E => Chip8CpuInstructions::AddIVx(ubln), 0x29 => Chip8CpuInstructions::LdFVx(ubln), + 0x30 => Chip8CpuInstructions::LdFVx10(ubln), 0x33 => Chip8CpuInstructions::LdBVx(ubln), 0x55 => Chip8CpuInstructions::LdIVx(ubln), 0x65 => Chip8CpuInstructions::LdVxI(ubln), + 0x75 => Chip8CpuInstructions::StRpl(ubln), + 0x85 => Chip8CpuInstructions::LdRpl(ubln), _ => XXXXERRORINSTRUCTION } _ => XXXXERRORINSTRUCTION @@ -865,6 +865,33 @@ impl Chip8CpuInstructions { input.registers.poke_i(offset + 1); } Chip8CpuInstructions::XXXXERRORINSTRUCTION => {} + Chip8CpuInstructions::ScrDn(x) => { + println!("SCROLLING DOWN {x} LINES"); + } + Chip8CpuInstructions::ScrRt => { + println!("SCROLING RIGHT 4 LINES"); + } + Chip8CpuInstructions::ScrLf => { + println!("SCROLLING LEFT 4 LINES"); + } + Chip8CpuInstructions::VidDis => { + println!("DISABLE VIDEO MODE"); + } + Chip8CpuInstructions::VidEna => { + println!("ENABLE VIDEO MODE"); + } + Chip8CpuInstructions::Exit => { + println!("EXIT INTERPRETER"); + } + Chip8CpuInstructions::LdFVx10(x) => { + println!("POINTING TO FONT AT {x:02x}"); + } + Chip8CpuInstructions::StRpl(x) => { + println!("STORING FROM RPL FOR {x}"); + } + Chip8CpuInstructions::LdRpl(x) => { + println!("LOADING FROM RPL FOR {x}"); + } }; let cycle_time = Instant::now().duration_since(start_time).as_nanos(); // println!("\t\tTook {cycle_time}ms"); @@ -920,6 +947,26 @@ mod test { assert_eq!(Chip8CpuInstructions::LdBVx(0xd).encode(), 0xfd33); assert_eq!(Chip8CpuInstructions::LdIVx(0xe).encode(), 0xfe55); assert_eq!(Chip8CpuInstructions::LdVxI(0x3).encode(), 0xf365); + assert_eq!(Chip8CpuInstructions::ScrDn(0x1).encode(), 0x00C1); + assert_eq!(Chip8CpuInstructions::ScrLf.encode(), 0x00FC); + assert_eq!(Chip8CpuInstructions::ScrRt.encode(), 0x00FB); + assert_eq!(Chip8CpuInstructions::Exit.encode(), 0x00FD); + assert_eq!(Chip8CpuInstructions::VidEna.encode(), 0x00FF); + assert_eq!(Chip8CpuInstructions::VidDis.encode(), 0x00FE); + assert_eq!(Chip8CpuInstructions::LdFVx10(0).encode(), 0xF030); + assert_eq!(Chip8CpuInstructions::StRpl(1).encode(), 0xF175); + assert_eq!(Chip8CpuInstructions::LdRpl(1).encode(), 0xF185); + + assert!(matches!(Chip8CpuInstructions::decode(0xF175), Chip8CpuInstructions::StRpl(1))); + assert!(matches!(Chip8CpuInstructions::decode(0xF185), Chip8CpuInstructions::LdRpl(1))); + assert!(matches!(Chip8CpuInstructions::decode(0x00C1u16), Chip8CpuInstructions::ScrDn(0x01))); + assert!(matches!(Chip8CpuInstructions::decode(0x00FCu16), Chip8CpuInstructions::ScrLf)); + assert!(matches!(Chip8CpuInstructions::decode(0x00FBu16), Chip8CpuInstructions::ScrRt)); + assert!(matches!(Chip8CpuInstructions::decode(0x00FDu16), Chip8CpuInstructions::Exit)); + assert!(matches!(Chip8CpuInstructions::decode(0x00FEu16), Chip8CpuInstructions::VidDis)); + assert!(matches!(Chip8CpuInstructions::decode(0x00FFu16), Chip8CpuInstructions::VidEna)); + assert!(matches!(Chip8CpuInstructions::decode(0xF030u16), Chip8CpuInstructions::LdFVx10(0))); + assert!(matches!(Chip8CpuInstructions::decode(0x00E0u16), Chip8CpuInstructions::CLS)); assert!(matches!(Chip8CpuInstructions::decode(0x00EEu16), Chip8CpuInstructions::RET)); assert!(matches!(Chip8CpuInstructions::decode(0x0123), Chip8CpuInstructions::SysAddr(0x123))); diff --git a/gemma/src/chip8/video.rs b/gemma/src/chip8/video.rs index 2745938..5bb55d6 100644 --- a/gemma/src/chip8/video.rs +++ b/gemma/src/chip8/video.rs @@ -1,10 +1,18 @@ use log::{debug}; +use crate::chip8::video::Chip8VideoModes::{HighRes, LowRes}; use crate::constants::{CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH}; +#[derive(Clone, Copy)] +enum Chip8VideoModes { + LowRes, + HighRes +} + #[derive(Clone, Copy)] pub struct Chip8Video { memory: [bool; CHIP8_VIDEO_MEMORY], pub has_frame_changed: bool, + current_res: Chip8VideoModes } impl Chip8Video { @@ -13,8 +21,28 @@ impl Chip8Video { self.start_frame(); } + pub fn set_highres(&mut self) { + self.current_res = HighRes + } + + pub fn set_lowres(&mut self) { + self.current_res = LowRes + } + + pub fn get_screen_resolution(&mut self) -> Chip8VideoModes { + self.current_res + } + pub fn cls(&mut self) { - self.memory = [false; CHIP8_VIDEO_MEMORY]; + match self.current_res { + LowRes => { + self.memory = [false; CHIP8_VIDEO_MEMORY]; + } + HighRes => { + + // self.memory = [0u8; ] + } + } } pub fn start_frame(&mut self) { @@ -25,6 +53,7 @@ impl Chip8Video { Self { memory: initial_configuration, has_frame_changed: false, + current_res: Chip8VideoModes::LowRes, } } @@ -85,7 +114,7 @@ impl Chip8Video { impl Default for Chip8Video { fn default() -> Self { - Chip8Video { memory: [false; CHIP8_VIDEO_MEMORY], has_frame_changed: false } + Chip8Video { memory: [false; CHIP8_VIDEO_MEMORY], has_frame_changed: false, current_res: Chip8VideoModes::LowRes } } } diff --git a/gemma/src/constants.rs b/gemma/src/constants.rs index 53181b9..2af31d2 100644 --- a/gemma/src/constants.rs +++ b/gemma/src/constants.rs @@ -12,3 +12,6 @@ pub const CHIP8_KEYBOARD: [[u8; 4]; 4] = [ [0x0A, 0x00, 0x0B, 0x0F] ]; +pub const SCHIP_VIDEO_HEIGHT: i32 = 64; +pub const SCHIP_VIDEO_WIDTH: i32 = 128; +pub const SCHIP_VIDE_MEMORY: usize = (SCHIP_VIDEO_HEIGHT * SCHIP_VIDEO_WIDTH) as usize; diff --git a/gemmasdl2/src/bin/gemmasdl2.rs b/gemmasdl2/src/bin/gemmasdl2.rs index facd2d8..86c2c93 100644 --- a/gemmasdl2/src/bin/gemmasdl2.rs +++ b/gemmasdl2/src/bin/gemmasdl2.rs @@ -17,7 +17,6 @@ async fn run() -> anyhow::Result { let sdl = sdl2::init().map_err(|e| anyhow::anyhow!("Failed to create SDL context: {}", e))?; let mut video = sdl.video().map_err(|e| anyhow::anyhow!("Failed to initialize SDL video subsystem: {}", e))?; - // Create SDL2 window and OpenGL context let window = video.window("Window", SCREEN_WIDTH, SCREEN_HEIGHT) .opengl() @@ -114,6 +113,12 @@ async fn run() -> anyhow::Result { Event::ControllerButtonDown { button, .. } => { println!("BUTTON {:?}", button); } + Event::JoyButtonDown {button_idx, .. } => { + println!("JoyButtonDown {}", button_idx); + } + Event::JoyAxisMotion { which, axis_idx, .. } => { + println!("JoyAxismotion {which} {axis_idx}"); + } _ => platform.handle_event(&event, &sdl, &video), } } @@ -122,6 +127,9 @@ async fn run() -> anyhow::Result { if let Some(fps) = timestep.frame_rate() { println!("{:?} fps", fps); } + + let num_js = sdl.joystick().unwrap().num_joysticks().unwrap(); + println!("NUM JS = {num_js}"); } Ok(("").parse()?) diff --git a/gemmautil/Cargo.toml b/gemmautil/Cargo.toml new file mode 100644 index 0000000..54a63ff --- /dev/null +++ b/gemmautil/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "gemmautil" +version = "0.1.0" +edition = "2021" + +[dependencies] +gemma = { path = "../gemma" } +clap = { version = "4.5.20", features = ["derive"] } diff --git a/gemmautil/src/bin/ch8disasm.rs b/gemmautil/src/bin/ch8disasm.rs new file mode 100644 index 0000000..d29ebcf --- /dev/null +++ b/gemmautil/src/bin/ch8disasm.rs @@ -0,0 +1,58 @@ +use std::path::Path; +use clap::{command, Parser}; +use gemma::chip8::instructions::Chip8CpuInstructions; +use gemma::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION; + +/// ch8disasm +/// +/// Provide disassembled version of the CH8 file provided. + +#[derive(Parser)] +#[command(version, about, long_about = None)] +struct DisassemblerApp { + #[arg(short)] + input_file: Box, + #[arg(short)] + output_file: Option> +} + +fn main() { + println!("Taxation is Theft"); + let result = DisassemblerApp::parse(); + println!("PREPARING TO DISASSEMBLE {:?}", result.input_file.file_name()); + let mut last_byte: u8 = 0x00; + let mut working_instruction: u16 = 0x0000; + // read the input file and loop through it byte by byte. + + for (offset, byte) in std::fs::read(result.input_file).unwrap().iter().enumerate() { + working_instruction = (working_instruction << 8) | (*byte as u16); + if offset % 2 != 0 { + // println!("ODD BYTE -> {:02x} / WORKING: {working_instruction:04x}", *byte as u16); + let decoded = Chip8CpuInstructions::decode(working_instruction); + match decoded { + XXXXERRORINSTRUCTION => { + println!("\t\t; ERROR: BYTES: {} OFFSET: {}", working_instruction, offset); + println!("FOUND ERROR INSTRUCTION. LIKELY DATA."); + } + Chip8CpuInstructions::JpAddr(x) => { + if x == (offset + 0x1ff) as u16 { + println!("FOUND JUMP TO SELF. INFINITE LOOP DETECTED."); + } + } + _ => { + println!("{}\t\t; Bytes [{:04x}] ending offset [{:04x}]", decoded, working_instruction, offset); + } + } + working_instruction = 0x0000; + } + } + + match result.output_file { + None => { + println!("Output to console."); + } + Some(target) => { + println!("Output to {:?}", target); + } + } +} \ No newline at end of file