diff options
author | Astatin <[email protected]> | 2025-05-22 14:07:19 +0200 |
---|---|---|
committer | Astatin <[email protected]> | 2025-05-22 14:07:19 +0200 |
commit | 0c7f945407561f7c4531b2780e908bb2098551d8 (patch) | |
tree | 082b5cef5430a787ca524b0f846be999e5633334 | |
parent | 4fce95c86e12f91e127605d440118e1b6a64208b (diff) |
Add load/save parameters to the CLI & remove errors
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/desktop/load_save.rs | 131 | ||||
-rw-r--r-- | src/display.rs | 18 | ||||
-rw-r--r-- | src/interrupts_timers.rs | 7 | ||||
-rw-r--r-- | src/io.rs | 22 | ||||
-rw-r--r-- | src/main.rs | 29 | ||||
-rw-r--r-- | src/mmio.rs | 8 | ||||
-rw-r--r-- | src/opcodes.rs | 328 | ||||
-rw-r--r-- | src/state.rs | 63 |
9 files changed, 348 insertions, 259 deletions
@@ -2,4 +2,5 @@ target/ debug.txt assets/cgb_boot.bin assets/dmg_boot.bin +assets/dmg_boot.bin.bak *.record diff --git a/src/desktop/load_save.rs b/src/desktop/load_save.rs index 5c3a123..a7eadfc 100644 --- a/src/desktop/load_save.rs +++ b/src/desktop/load_save.rs @@ -76,45 +76,122 @@ impl LoadSave for FSLoadSave { Ok(()) } - fn save_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>) { - if let Some(state_file) = &self.state_file { - { - let mut vram_dump_file = File::create(format!("{}.vram", state_file)).unwrap(); + fn dump_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>) -> Result<(), std::io::Error> { + { + let mut vram_dump_file = File::create(format!("{}.vram.dump", self.rom_file))?; + + for addr in 0x8000..0xa000 { + vram_dump_file.write_all(format!("{:02X} ", state.mem.r(addr)).as_bytes())?; + } + } + + { + let mut wram_dump_file = File::create(format!("{}.wram.dump", self.rom_file))?; - for addr in 0x8000..0xa000 { - vram_dump_file - .write_all(format!("{:02X} ", state.mem.r(addr).unwrap()).as_bytes()); - } + for addr in 0xc000..0xe000 { + wram_dump_file.write_all(format!("{:02X} ", state.mem.r(addr)).as_bytes())?; } + } - { - let mut wram_dump_file = File::create(format!("{}.wram", state_file)).unwrap(); + { + let mut io_dump_file = File::create(format!("{}.io.dump", self.rom_file))?; - for addr in 0xc000..0xe000 { - wram_dump_file - .write_all(format!("{:02X} ", state.mem.r(addr).unwrap()).as_bytes()); - } + for addr in 0xff00..0xff80 { + io_dump_file.write_all(format!("{:02X} ", state.mem.r(addr)).as_bytes())?; } + } + + { + let mut hram_dump_file = File::create(format!("{}.hram.dump", self.rom_file))?; - { - let mut io_dump_file = File::create(format!("{}.io", state_file)).unwrap(); + for addr in 0xff80..=0xffff { + hram_dump_file.write_all(format!("{:02X} ", state.mem.r(addr)).as_bytes())?; + } + } + + { + let mut cpu_dump_file = File::create(format!("{}.cpu.dump", self.rom_file))?; + + for i in 0..8 { + cpu_dump_file.write_all(format!("{:02X} ", state.cpu.r[i]).as_bytes())?; + } + + cpu_dump_file.write_all(format!("{:04X} ", state.cpu.pc).as_bytes())?; + + cpu_dump_file.write_all(format!("{:04X} ", state.cpu.sp).as_bytes())?; + } + + Ok(()) + } - for addr in 0xff00..0xff80 { - io_dump_file - .write_all(format!("{:02X} ", state.mem.r(addr).unwrap()).as_bytes()); - } + fn save_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>) -> Result<(), std::io::Error> { + if let Some(state_file) = &self.state_file { + let mut state_file = File::create(state_file)?; + for addr in 0x8000..0xa000 { + state_file.write_all(&[state.mem.r(addr)])?; } - { - let mut hram_dump_file = File::create(format!("{}.hram", state_file)).unwrap(); + state_file.write_all(state.mem.wram_00.as_ref())?; + state_file.write_all(state.mem.wram_01.as_ref())?; - for addr in 0xff80..=0xffff { - hram_dump_file - .write_all(format!("{:02X} ", state.mem.r(addr).unwrap()).as_bytes()); - } + for addr in 0xff00..0xff80 { + state_file.write_all(&[state.mem.r(addr)])?; } + + state_file.write_all(state.mem.hram.as_ref())?; + state_file.write_all(&[state.mem.interrupts_register])?; + + state_file.write_all(&state.cpu.r)?; + state_file.write_all(&state.cpu.pc.to_le_bytes())?; + state_file.write_all(&state.cpu.sp.to_le_bytes())?; + state_file.write_all(&[state.mem.boot_rom_on.into(), state.mem.ime.into()])?; } else { - panic!("{:?}", self) + eprintln!("Tried to save state without state_file specified"); } + Ok(()) + } + + fn load_state<S: Serial, A: Audio>( + &self, + state: &mut GBState<S, A>, + ) -> Result<(), std::io::Error> { + if let Some(state_file) = &self.state_file { + let mut state_file = File::open(state_file)?; + + let mut vram = Box::new([0; 0x2000]); + state_file.read_exact(vram.as_mut())?; + for i in 0x0000..0x2000 { + state.mem.w(0x8000 + i, vram[i as usize]); + } + + state_file.read_exact(state.mem.wram_00.as_mut())?; + state_file.read_exact(state.mem.wram_01.as_mut())?; + + let mut io = [0; 0x80]; + state_file.read_exact(io.as_mut())?; + for i in 0x00..0x80 { + state.mem.w(0xff00 + i, io[i as usize]); + } + + state_file.read_exact(state.mem.hram.as_mut())?; + + let mut reg8 = [0; 1]; + state_file.read_exact(reg8.as_mut())?; + state.mem.interrupts_register = reg8[0]; + + state_file.read_exact(&mut state.cpu.r)?; + + let mut reg16 = [0; 2]; + state_file.read_exact(&mut reg16)?; + state.cpu.pc = u16::from_le_bytes(reg16); + state_file.read_exact(&mut reg16)?; + state.cpu.sp = u16::from_le_bytes(reg16); + + state_file.read_exact(reg8.as_mut())?; + state.mem.boot_rom_on = reg8[0] != 0; + state_file.read_exact(reg8.as_mut())?; + state.mem.ime = reg8[0] != 0; + } + Ok(()) } } diff --git a/src/display.rs b/src/display.rs index 917f330..0417a00 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,7 +1,6 @@ // Very readable, much clean wow. use crate::consts::DISPLAY_UPDATE_SLEEP_TIME_MICROS; -use crate::state::MemError; use std::time::SystemTime; const COLORS: [u32; 4] = [0x00e0f8d0, 0x0088c070, 0x346856, 0x00081820]; @@ -145,7 +144,7 @@ impl Display { } } - pub fn w(&mut self, addr: u16, value: u8) -> Result<(), MemError> { + pub fn w(&mut self, addr: u16, value: u8) { if self.vram_bank == 0 { if addr < 0x1800 { self.tiledata[addr as usize] = value; @@ -161,25 +160,24 @@ impl Display { self.bg_map_attr[addr as usize - 0x1800] = value; } } - Ok(()) } - pub fn r(&self, addr: u16) -> Result<u8, MemError> { + pub fn r(&self, addr: u16) -> u8 { if self.vram_bank == 0 { if addr < 0x1800 { - Ok(self.tiledata[addr as usize]) + self.tiledata[addr as usize] } else if addr >= 0x7e00 { - Ok(self.oam[addr as usize - 0x7e00]) + self.oam[addr as usize - 0x7e00] } else { - Ok(self.tilemaps[addr as usize - 0x1800]) + self.tilemaps[addr as usize - 0x1800] } } else { if addr < 0x1800 { - Ok(self.tiledata[addr as usize + 0x1800]) + self.tiledata[addr as usize + 0x1800] } else if addr < 0x1c00 { - Ok(self.bg_map_attr[addr as usize - 0x1800]) + self.bg_map_attr[addr as usize - 0x1800] } else { - Ok(0) + 0 } } } diff --git a/src/interrupts_timers.rs b/src/interrupts_timers.rs index b776777..f9ae84b 100644 --- a/src/interrupts_timers.rs +++ b/src/interrupts_timers.rs @@ -1,16 +1,16 @@ use crate::display::DisplayInterrupt; use crate::io::{Audio, Serial}; -use crate::state::{GBState, MemError}; +use crate::state::GBState; const TIMA_TIMER_SPEEDS: [u64; 4] = [1024, 16, 64, 256]; impl<S: Serial, A: Audio> GBState<S, A> { - pub fn check_interrupts(&mut self) -> Result<(), MemError> { + pub fn check_interrupts(&mut self) { if self.mem.ime { let interrupts = self.mem.io[0x0f] & self.mem.interrupts_register & 0b11111; for i in 0..5 { if interrupts & (1 << i) != 0 { - self.push(self.cpu.pc)?; + self.push(self.cpu.pc); self.mem.ime = false; self.cpu.pc = 0x40 + (i << 3); @@ -21,7 +21,6 @@ impl<S: Serial, A: Audio> GBState<S, A> { } } } - Ok(()) } pub fn tima_timer(&mut self, c: u64) { @@ -59,7 +59,10 @@ where fn load_rom(&self, rom: &mut [u8]) -> Result<(), Self::Error>; fn load_external_ram(&self, external_ram: &mut [u8]) -> Result<(), Self::Error>; fn save_external_ram(&self, external_ram: &[u8]) -> Result<(), Self::Error>; - fn save_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>); + fn dump_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>) -> Result<(), Self::Error>; + fn save_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>) -> Result<(), Self::Error>; + fn load_state<S: Serial, A: Audio>(&self, state: &mut GBState<S, A>) + -> Result<(), Self::Error>; } pub struct Gameboy<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> { @@ -81,6 +84,15 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A, } } + pub fn load_state(&mut self) -> Result<(), LS::Error> { + self.load_save.load_state(&mut self.state)?; + Ok(()) + } + + pub fn debug(&mut self) { + self.state.is_debug = true; + } + pub fn start(self) { let Self { mut window, @@ -115,7 +127,7 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A, } was_previously_halted = state.mem.halt; let c = if !state.mem.halt { - state.exec_opcode().unwrap() + state.exec_opcode() } else { halt_time += 4; 4 @@ -127,7 +139,7 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A, state.div_timer(c); state.tima_timer(c); state.update_display_interrupts(c); - state.check_interrupts().unwrap(); + state.check_interrupts(); state.mem.update_serial(); nanos_sleep += c as f64 * (consts::CPU_CYCLE_LENGTH_NANOS as f64 / speed) as f64; @@ -144,7 +156,9 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A, ); if save_state { - load_save.save_state(&state); + if let Err(err) = load_save.save_state(&state) { + eprintln!("FAILED SAVE STATE: {:?}", err); + } } if state.mem.joypad_is_action diff --git a/src/main.rs b/src/main.rs index 2e5c80c..9a48983 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,12 @@ struct Cli { #[arg(long)] replay_input: Option<String>, + #[arg(long)] + state_file: Option<String>, + + #[arg(short, long, default_value_t = false)] + load_state: bool, + #[arg(short, long, default_value_t = false)] keyboard: bool, @@ -65,13 +71,26 @@ fn main() { gamepad = Box::new(GamepadRecorder::new(gamepad, record_file)); }; - io::Gameboy::<_, _, _, desktop::audio::RodioAudio, _>::new( + let mut fs_load_save = FSLoadSave::new(&cli.rom, format!("{}.sav", &cli.rom)); + if let Some(state_file) = &cli.state_file { + fs_load_save = fs_load_save.state_file(state_file); + } + + let mut gameboy = io::Gameboy::<_, _, _, desktop::audio::RodioAudio, _>::new( gamepad, window, serial, - FSLoadSave::new(&cli.rom, format!("{}.sav", &cli.rom)) - .state_file(format!("{}.dump", &cli.rom)), + fs_load_save, cli.speed as f64, - ) - .start(); + ); + + if cli.debug { + gameboy.debug(); + } + + if cli.load_state { + gameboy.load_state().unwrap(); + } + + gameboy.start(); } diff --git a/src/mmio.rs b/src/mmio.rs index aa2f61d..366c94b 100644 --- a/src/mmio.rs +++ b/src/mmio.rs @@ -1,5 +1,5 @@ use crate::io::{Audio, Serial}; -use crate::state::{MemError, Memory}; +use crate::state::Memory; impl<S: Serial, A: Audio> Memory<S, A> { pub fn r_io(&self, addr: u8) -> u8 { @@ -61,7 +61,7 @@ impl<S: Serial, A: Audio> Memory<S, A> { } } - pub fn w_io(&mut self, addr: u8, value: u8) -> Result<(), MemError> { + pub fn w_io(&mut self, addr: u8, value: u8) { match addr { 0x00 => { self.joypad_is_action = !value & 0b00100000 != 0; @@ -213,7 +213,7 @@ impl<S: Serial, A: Audio> Memory<S, A> { let addr = (value as u16) << 8; for i in 0..0xa0 { - self.w(0xfe00 | i, self.r(addr | i)?)?; + self.w(0xfe00 | i, self.r(addr | i)) } } } @@ -262,7 +262,5 @@ impl<S: Serial, A: Audio> Memory<S, A> { self.audio.ch3.wave_pattern[i * 2] = value >> 4; self.audio.ch3.wave_pattern[i * 2 + 1] = value & 0xf; } - - Ok(()) } } diff --git a/src/opcodes.rs b/src/opcodes.rs index 3779af0..a8af25f 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -1,35 +1,35 @@ use crate::io::{Audio, Serial}; -use crate::state::{flag, reg, GBState, MemError}; +use crate::state::{flag, reg, GBState}; // The opcodes functions are returning the number of cycles used. impl<S: Serial, A: Audio> GBState<S, A> { - fn r_16b_from_pc(&mut self) -> Result<u16, MemError> { - let p: u16 = self.mem.r(self.cpu.pc)? as u16 | ((self.mem.r(self.cpu.pc + 1)? as u16) << 8); + fn r_16b_from_pc(&mut self) -> u16 { + let p: u16 = self.mem.r(self.cpu.pc) as u16 | ((self.mem.r(self.cpu.pc + 1) as u16) << 8); self.cpu.pc += 2; - Ok(p) + p } - fn r_8b_from_pc(&mut self) -> Result<u8, MemError> { - let p = self.mem.r(self.cpu.pc)?; + fn r_8b_from_pc(&mut self) -> u8 { + let p = self.mem.r(self.cpu.pc); self.cpu.pc += 1; - Ok(p) + p } - fn ldrr(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { + fn ldrr(&mut self, n1: u8, n2: u8) -> () { // Load a register into another register // LD r, r - self.w_reg(n1, self.r_reg(n2)?) + self.w_reg(n1, self.r_reg(n2)) } - fn ldr8(&mut self, n1: u8) -> Result<u64, MemError> { + fn ldr8(&mut self, n1: u8) -> u64 { // Load an raw 8b value into a register - let p = self.r_8b_from_pc()?; + let p = self.r_8b_from_pc(); - self.w_reg(n1, p)?; - Ok(8) + self.w_reg(n1, p); + 8 } fn ldrr16(&mut self, rr: u8, x: u16) { @@ -37,13 +37,13 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.cpu.w16(rr, x); } - fn ldnnsp(&mut self) -> Result<u64, MemError> { + fn ldnnsp(&mut self) -> u64 { // Load SP into an arbitrary position in memory - let p = self.r_16b_from_pc()?; + let p = self.r_16b_from_pc(); - self.mem.w(p, (self.cpu.sp & 0xff) as u8)?; - self.mem.w(p + 1, (self.cpu.sp >> 8) as u8)?; - Ok(20) + self.mem.w(p, (self.cpu.sp & 0xff) as u8); + self.mem.w(p + 1, (self.cpu.sp >> 8) as u8); + 20 } fn ldsphl(&mut self) -> u64 { @@ -51,48 +51,48 @@ impl<S: Serial, A: Audio> GBState<S, A> { 8 } - fn ldnna(&mut self, nn: u16) -> Result<(), MemError> { + fn ldnna(&mut self, nn: u16) -> () { // Load A into an arbitrary position in memory - self.mem.w(nn, self.cpu.r[reg::A as usize])?; - Ok(()) + self.mem.w(nn, self.cpu.r[reg::A as usize]); + () } - fn ldann(&mut self, nn: u16) -> Result<(), MemError> { + fn ldann(&mut self, nn: u16) -> () { // Load A from an arbitrary position in memory - self.cpu.r[reg::A as usize] = self.mem.r(nn)?; - Ok(()) + self.cpu.r[reg::A as usize] = self.mem.r(nn); + () } - pub fn push(&mut self, x: u16) -> Result<(), MemError> { + pub fn push(&mut self, x: u16) -> () { self.cpu.sp -= 2; - self.mem.w(self.cpu.sp, (x & 0xff) as u8)?; + self.mem.w(self.cpu.sp, (x & 0xff) as u8); - self.mem.w(self.cpu.sp + 1, (x >> 8) as u8)?; + self.mem.w(self.cpu.sp + 1, (x >> 8) as u8); - Ok(()) + () } - fn pop(&mut self) -> Result<u16, MemError> { - let res = self.mem.r(self.cpu.sp)? as u16 | ((self.mem.r(self.cpu.sp + 1)? as u16) << 8); + fn pop(&mut self) -> u16 { + let res = self.mem.r(self.cpu.sp) as u16 | ((self.mem.r(self.cpu.sp + 1) as u16) << 8); self.cpu.sp += 2; - Ok(res) + res } - fn jr8(&mut self) -> Result<u64, MemError> { + fn jr8(&mut self) -> u64 { // Unconditional relative jump - let p = self.r_8b_from_pc()?; + let p = self.r_8b_from_pc(); self.cpu.pc = (self.cpu.pc as i16 + p as i8 as i16) as u16; - Ok(12) + 12 } - fn jrcc8(&mut self, n1: u8) -> Result<u64, MemError> { + fn jrcc8(&mut self, n1: u8) -> u64 { // Conditional relative jump - let p = self.r_8b_from_pc()?; + let p = self.r_8b_from_pc(); let mut cycles = 8; if self.cpu.check_flag(n1 & 0b11) { @@ -100,16 +100,16 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.cpu.pc = (self.cpu.pc as i16 + p as i8 as i16) as u16; } - Ok(cycles) + cycles } - fn jp16(&mut self) -> Result<u64, MemError> { + fn jp16(&mut self) -> u64 { // Unconditional absolute jump - let p = self.r_16b_from_pc()?; + let p = self.r_16b_from_pc(); self.cpu.pc = p; - Ok(16) + 16 } fn jphl(&mut self) -> u64 { @@ -119,9 +119,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { 4 } - fn jpcc16(&mut self, n1: u8) -> Result<u64, MemError> { + fn jpcc16(&mut self, n1: u8) -> u64 { // Conditional absolute jump - let p = self.r_16b_from_pc()?; + let p = self.r_16b_from_pc(); let mut cycles = 8; if self.cpu.check_flag(n1 & 0b11) { @@ -129,35 +129,35 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.cpu.pc = p; } - Ok(cycles) + cycles } - fn call(&mut self) -> Result<u64, MemError> { + fn call(&mut self) -> u64 { // Unconditional function call - let p = self.r_16b_from_pc()?; + let p = self.r_16b_from_pc(); - self.push(self.cpu.pc)?; + self.push(self.cpu.pc); self.cpu.pc = p; - Ok(24) + 24 } - fn callcc(&mut self, n1: u8) -> Result<u64, MemError> { + fn callcc(&mut self, n1: u8) -> u64 { // Conditional function call - let p = self.r_16b_from_pc()?; + let p = self.r_16b_from_pc(); let mut cycles = 12; if self.cpu.check_flag(n1 & 0b11) { cycles += 12; - self.push(self.cpu.pc)?; + self.push(self.cpu.pc); self.cpu.pc = p; } - Ok(cycles) + cycles } - fn ret(&mut self) -> Result<u64, MemError> { - let res = self.pop()?; + fn ret(&mut self) -> u64 { + let res = self.pop(); if res == 0 { println!("DEBUG: {:?}", self.cpu); @@ -166,20 +166,20 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.cpu.pc = res; - Ok(16) + 16 } - fn retcc(&mut self, n1: u8) -> Result<u64, MemError> { + fn retcc(&mut self, n1: u8) -> u64 { let mut cycles = 8; if self.cpu.check_flag(n1 & 0b11) { cycles += 12; - self.cpu.pc = self.pop()?; + self.cpu.pc = self.pop(); } - Ok(cycles) + cycles } - fn ld00a(&mut self, n1: u8) -> Result<u64, MemError> { + fn ld00a(&mut self, n1: u8) -> u64 { // Load register A into or from memory pointed by rr (BC, DE or HL(+/-)) // LD (rr), A // LD A, (rr) @@ -190,10 +190,10 @@ impl<S: Serial, A: Audio> GBState<S, A> { }; if n1 & 0b001 == 1 { - self.cpu.r[reg::A as usize] = self.mem.r(self.cpu.r16(ptr_reg))?; + self.cpu.r[reg::A as usize] = self.mem.r(self.cpu.r16(ptr_reg)); } else { self.mem - .w(self.cpu.r16(ptr_reg), self.cpu.r[reg::A as usize])?; + .w(self.cpu.r16(ptr_reg), self.cpu.r[reg::A as usize]); } if n1 & 0b110 == 0b100 { @@ -204,39 +204,39 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.cpu.w16(reg::HL, self.cpu.r16(reg::HL) - 1); // (HL-) } - Ok(8) + 8 } - fn inc8(&mut self, n1: u8) -> Result<u64, MemError> { + fn inc8(&mut self, n1: u8) -> u64 { // Increment 8 bit register - self.w_reg(n1, self.r_reg(n1)? + 1)?; + self.w_reg(n1, self.r_reg(n1) + 1); self.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF | flag::H); - if self.r_reg(n1)? == 0 { + if self.r_reg(n1) == 0 { self.cpu.r[reg::F as usize] |= flag::ZF; } - if self.r_reg(n1)? & 0xf == 0x0 { + if self.r_reg(n1) & 0xf == 0x0 { self.cpu.r[reg::F as usize] |= flag::H; } - Ok(4) + 4 } - fn dec8(&mut self, n1: u8) -> Result<u64, MemError> { + fn dec8(&mut self, n1: u8) -> u64 { // Decrement 8 bit register - self.w_reg(n1, self.r_reg(n1)? - 1)?; + self.w_reg(n1, self.r_reg(n1) - 1); self.cpu.r[reg::F as usize] |= flag::N; self.cpu.r[reg::F as usize] &= !(flag::ZF | flag::H); - if self.r_reg(n1)? == 0 { + if self.r_reg(n1) == 0 { self.cpu.r[reg::F as usize] |= flag::ZF; } - if self.r_reg(n1)? & 0xf == 0xf { + if self.r_reg(n1) & 0xf == 0xf { self.cpu.r[reg::F as usize] |= flag::H; } - Ok(4) + 4 } fn inc16(&mut self, rr: u8) -> u64 { @@ -301,8 +301,8 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.cpu.r[reg::A as usize] ^= 0xff; } - fn addsp8(&mut self) -> Result<u64, MemError> { - let n = self.r_8b_from_pc()? as i8; + fn addsp8(&mut self) -> u64 { + let n = self.r_8b_from_pc() as i8; self.cpu.sp = (self.cpu.sp as i32 + n as i32) as u16; @@ -315,7 +315,7 @@ impl<S: Serial, A: Audio> GBState<S, A> { if (self.cpu.sp as i32 + n as i32) & !0xffff != 0 { self.cpu.r[reg::F as usize] |= flag::CY; } - Ok(16) + 16 } fn add(&mut self, x: u8) { @@ -473,9 +473,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { } } - fn rlc(&mut self, r_i: u8) -> Result<(), MemError> { + fn rlc(&mut self, r_i: u8) -> () { // ROTATE LEFT the input register - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); self.cpu.r[reg::F as usize] |= (n >> 7) << 4; n <<= 1; @@ -483,9 +483,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn rrc(&mut self, r_i: u8) -> Result<(), MemError> { + fn rrc(&mut self, r_i: u8) -> () { // ROTATE RIGHT the input register - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); self.cpu.r[reg::F as usize] |= (n & 1) << 4; n >>= 1; @@ -493,10 +493,10 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn rl(&mut self, r_i: u8) -> Result<(), MemError> { + fn rl(&mut self, r_i: u8) -> () { // ROTATE LEFT THROUGH CARRY the input register // (RLC IS ROTATE AND RL IS ROTATE THROUGH CARRY ! IT DOESN'T MAKE ANY SENSE !!) - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4; self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); @@ -506,9 +506,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn rr(&mut self, r_i: u8) -> Result<(), MemError> { + fn rr(&mut self, r_i: u8) -> () { // ROTATE RIGHT THROUGH CARRY the input register - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4; self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); @@ -518,9 +518,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn sla(&mut self, r_i: u8) -> Result<(), MemError> { + fn sla(&mut self, r_i: u8) -> () { // Shift left Arithmetic (b0=0) the input register - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); self.cpu.r[reg::F as usize] |= (n >> 7) << 4; @@ -533,9 +533,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn sra(&mut self, r_i: u8) -> Result<(), MemError> { + fn sra(&mut self, r_i: u8) -> () { // Shift right Arithmetic (b7=b7) the input register - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); self.cpu.r[reg::F as usize] |= (n & 0b1) << 4; @@ -550,9 +550,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn swap(&mut self, r_i: u8) -> Result<(), MemError> { + fn swap(&mut self, r_i: u8) -> () { // Swap the high nibble and low nibble - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); let nibble_low = n & 0b1111; let nibble_high = n >> 4; @@ -568,9 +568,9 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn srl(&mut self, r_i: u8) -> Result<(), MemError> { + fn srl(&mut self, r_i: u8) -> () { // Shift right Logical (b7=0) the input register - let mut n = self.r_reg(r_i)?; + let mut n = self.r_reg(r_i); self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); self.cpu.r[reg::F as usize] |= (n & 0b1) << 4; @@ -583,48 +583,48 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.w_reg(r_i, n) } - fn bit(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { - let z = (((self.r_reg(n2)? >> n1) & 1) ^ 1) << 7; + fn bit(&mut self, n1: u8, n2: u8) -> () { + let z = (((self.r_reg(n2) >> n1) & 1) ^ 1) << 7; self.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF); self.cpu.r[reg::F as usize] |= flag::H | z; - Ok(()) + () } - fn set(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { - self.w_reg(n2, self.r_reg(n2)? | (1 << n1)) + fn set(&mut self, n1: u8, n2: u8) -> () { + self.w_reg(n2, self.r_reg(n2) | (1 << n1)) } - fn res(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { - self.w_reg(n2, self.r_reg(n2)? & !(1 << n1)) + fn res(&mut self, n1: u8, n2: u8) -> () { + self.w_reg(n2, self.r_reg(n2) & !(1 << n1)) } // I don't remember why I separated op00, op01, op10 and op11 AND I'M NOT GOING TO CHANGE IT // BECAUSE I LOVE CHAOS - fn op00(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + fn op00(&mut self, n1: u8, n2: u8) -> u64 { // Dispatcher for the instructions starting with 0b00 based on their 3 LSB match n2 { 0b000 => match n1 { - 0b000 => Ok(4), + 0b000 => 4, 0b001 => self.ldnnsp(), 0b010 => todo!("STOP"), 0b011 => self.jr8(), _ => self.jrcc8(n1), }, 0b001 => match n1 { - 0b001 | 0b011 | 0b101 | 0b111 => Ok(self.addhlrr(n1 >> 1)), + 0b001 | 0b011 | 0b101 | 0b111 => self.addhlrr(n1 >> 1), 0b000 | 0b010 | 0b100 | 0b110 => { - let p = self.r_16b_from_pc()?; + let p = self.r_16b_from_pc(); self.ldrr16(n1 >> 1, p); - Ok(12) + 12 } _ => panic!(), }, 0b010 => self.ld00a(n1), 0b011 => match n1 { - 0b001 | 0b011 | 0b101 | 0b111 => Ok(self.dec16(n1 >> 1)), - 0b000 | 0b010 | 0b100 | 0b110 => Ok(self.inc16(n1 >> 1)), + 0b001 | 0b011 | 0b101 | 0b111 => self.dec16(n1 >> 1), + 0b000 | 0b010 | 0b100 | 0b110 => self.inc16(n1 >> 1), _ => panic!(), }, 0b100 => self.inc8(n1), @@ -632,77 +632,77 @@ impl<S: Serial, A: Audio> GBState<S, A> { 0b110 => self.ldr8(n1), 0b111 => { match n1 { - 0b000 => self.rlc(7)?, - 0b001 => self.rrc(7)?, - 0b010 => self.rl(7)?, - 0b011 => self.rr(7)?, + 0b000 => self.rlc(7), + 0b001 => self.rrc(7), + 0b010 => self.rl(7), + 0b011 => self.rr(7), 0b100 => self.daa(), 0b101 => self.cpl(), 0b110 => self.scf(), 0b111 => self.ccf(), _ => panic!(), }; - Ok(4) + 4 } _ => panic!(), } } - fn op01(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + fn op01(&mut self, n1: u8, n2: u8) -> u64 { // Dispatcher for the instructions starting with 0b01 (LD r,r and HALT) if n1 == 0b110 && n2 == 0b110 { self.mem.halt = true; - Ok(4) + 4 } else { - self.ldrr(n1, n2)?; + self.ldrr(n1, n2); if n1 == 0b110 || n2 == 0b110 { - Ok(8) + 8 } else { - Ok(4) + 4 } } } - fn op10(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + fn op10(&mut self, n1: u8, n2: u8) -> u64 { // Dispatcher for the instructions starting with 0b10 (Arithmetic) match n1 { - 0b000 => self.add(self.r_reg(n2)?), - 0b001 => self.adc(self.r_reg(n2)?), - 0b010 => self.sub(self.r_reg(n2)?), - 0b011 => self.sbc(self.r_reg(n2)?), - 0b100 => self.and(self.r_reg(n2)?), - 0b101 => self.xor(self.r_reg(n2)?), - 0b110 => self.or(self.r_reg(n2)?), - 0b111 => self.cp(self.r_reg(n2)?), + 0b000 => self.add(self.r_reg(n2)), + 0b001 => self.adc(self.r_reg(n2)), + 0b010 => self.sub(self.r_reg(n2)), + 0b011 => self.sbc(self.r_reg(n2)), + 0b100 => self.and(self.r_reg(n2)), + 0b101 => self.xor(self.r_reg(n2)), + 0b110 => self.or(self.r_reg(n2)), + 0b111 => self.cp(self.r_reg(n2)), _ => panic!(), } if n2 == 0b110 { - Ok(8) + 8 } else { - Ok(4) + 4 } } - fn op11(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + fn op11(&mut self, n1: u8, n2: u8) -> u64 { match n2 { 0b000 => match n1 { 0b100 => { - let n = self.r_8b_from_pc()?; - self.ldnna(n as u16 | 0xff00)?; - Ok(12) + let n = self.r_8b_from_pc(); + self.ldnna(n as u16 | 0xff00); + 12 } 0b101 => self.addsp8(), 0b110 => { - let n = self.r_8b_from_pc()?; - self.ldann(n as u16 | 0xff00)?; - Ok(12) + let n = self.r_8b_from_pc(); + self.ldann(n as u16 | 0xff00); + 12 } 0b111 => { - let n = self.r_8b_from_pc()?; + let n = self.r_8b_from_pc(); self.ldrr16(reg::HL, n as u16 + self.cpu.sp); - Ok(12) + 12 } _ => self.retcc(n1 & 0b11), }, @@ -713,33 +713,33 @@ impl<S: Serial, A: Audio> GBState<S, A> { self.ret() } - 0b101 => Ok(self.jphl()), - 0b111 => Ok(self.ldsphl()), + 0b101 => self.jphl(), + 0b111 => self.ldsphl(), _ => { - let p = self.pop()?; + let p = self.pop(); self.cpu.r[(n1 >> 1) as usize * 2 + 1] = (p & 0xff) as u8; self.cpu.r[(n1 >> 1) as usize * 2] = (p >> 8) as u8; - Ok(12) + 12 } }, 0b010 => match n1 { 0b100 => { - self.ldnna(self.cpu.r[reg::C as usize] as u16 | 0xff00)?; - Ok(8) + self.ldnna(self.cpu.r[reg::C as usize] as u16 | 0xff00); + 8 } 0b101 => { - let nn = self.r_16b_from_pc()?; - self.ldnna(nn)?; - Ok(16) + let nn = self.r_16b_from_pc(); + self.ldnna(nn); + 16 } 0b110 => { - self.ldann(self.cpu.r[reg::C as usize] as u16 | 0xff00)?; - Ok(8) + self.ldann(self.cpu.r[reg::C as usize] as u16 | 0xff00); + 8 } 0b111 => { - let nn = self.r_16b_from_pc()?; - self.ldann(nn)?; - Ok(16) + let nn = self.r_16b_from_pc(); + self.ldann(nn); + 16 } _ => self.jpcc16(n1 & 0b11), }, @@ -749,15 +749,15 @@ impl<S: Serial, A: Audio> GBState<S, A> { 0b011 | 0b100 | 0b101 => unimplemented!(), 0b010 => { self.cpu.print_debug(); - Ok(4) + 4 } 0b110 => { self.mem.ime = false; - Ok(4) + 4 } 0b111 => { self.mem.ime = true; - Ok(4) + 4 } _ => panic!(), }, @@ -768,12 +768,12 @@ impl<S: Serial, A: Audio> GBState<S, A> { _ => { let value = self.cpu.r[(n1 >> 1) as usize * 2 + 1] as u16 | ((self.cpu.r[(n1 >> 1) as usize * 2] as u16) << 8); - self.push(value)?; - Ok(16) + self.push(value); + 16 } }, 0b110 => { - let p = self.r_8b_from_pc()?; + let p = self.r_8b_from_pc(); match n1 { 0b000 => self.add(p), @@ -786,21 +786,21 @@ impl<S: Serial, A: Audio> GBState<S, A> { 0b111 => self.cp(p), _ => panic!(), } - Ok(8) + 8 } 0b111 => { let p = n1 << 3; - self.push(self.cpu.pc)?; + self.push(self.cpu.pc); self.cpu.pc = p as u16; - Ok(16) + 16 } // RST _ => panic!(), } } - fn op_bitwise(&mut self) -> Result<u64, MemError> { - let p = self.r_8b_from_pc()?; + fn op_bitwise(&mut self) -> u64 { + let p = self.r_8b_from_pc(); let opcode = p >> 6; let n1 = p >> 3 & 0b111; let n2 = p & 0b111; @@ -821,16 +821,16 @@ impl<S: Serial, A: Audio> GBState<S, A> { 0b10 => self.res(n1, n2), 0b11 => self.set(n1, n2), _ => panic!(), - }?; + }; if n2 == 0b110 { - Ok(16) + 16 } else { - Ok(8) + 8 } } - pub fn exec_opcode(&mut self) -> Result<u64, MemError> { - let opcode = self.mem.r(self.cpu.pc)?; + pub fn exec_opcode(&mut self) -> u64 { + let opcode = self.mem.r(self.cpu.pc); if self.is_debug { println!( diff --git a/src/state.rs b/src/state.rs index 67da18e..530296e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -128,10 +128,10 @@ pub struct Memory<S: Serial, A: Audio> { pub rom: Box<[u8; 0x200000]>, // 4 KiB Work RAM 00 - wram_00: Box<[u8; 0x1000]>, + pub wram_00: Box<[u8; 0x1000]>, // 4 KiB Work RAM 00 - wram_01: Box<[u8; 0x1000]>, + pub wram_01: Box<[u8; 0x1000]>, // External RAM pub external_ram: Box<[u8; 0x8000]>, @@ -142,7 +142,7 @@ pub struct Memory<S: Serial, A: Audio> { pub io: Box<[u8; 0x80]>, // High RAM - hram: Box<[u8; 0x7f]>, + pub hram: Box<[u8; 0x7f]>, pub audio: Channels<A>, @@ -173,13 +173,6 @@ pub struct Memory<S: Serial, A: Audio> { pub serial_control: u8, } -#[derive(Debug)] -pub enum MemError { - WritingToROM, - Unimplemented, - NotUsable, -} - mod serial_control_flags { pub const CLOCK_SELECT: u8 = 0b1; pub const TRANSFER_ENABLE: u8 = 0b10000000; @@ -249,79 +242,70 @@ impl<S: Serial, A: Audio> Memory<S, A> { } } - pub fn r(&self, addr: u16) -> Result<u8, MemError> { + pub fn r(&self, addr: u16) -> u8 { if (addr < 0x100 || (addr >= 0x200 && addr < 0x900)) && self.boot_rom_on { - Ok(self.boot_rom[addr as usize]) + self.boot_rom[addr as usize] } else if addr < 0x4000 { - Ok(self.rom[addr as usize]) + self.rom[addr as usize] } else if addr < 0x8000 { - Ok(self.rom[self.rom_bank as usize * 0x4000 + addr as usize - 0x4000 as usize]) + self.rom[self.rom_bank as usize * 0x4000 + addr as usize - 0x4000 as usize] } else if addr >= 0xa000 && addr < 0xc000 { if self.ram_bank_enabled { - Ok(self.external_ram[self.ram_bank as usize * 0x2000 + addr as usize - 0xa000]) + self.external_ram[self.ram_bank as usize * 0x2000 + addr as usize - 0xa000] } else { - Ok(0xff) + 0xff } } else if addr >= 0xc000 && addr < 0xd000 { - Ok(self.wram_00[addr as usize - 0xc000]) + self.wram_00[addr as usize - 0xc000] } else if addr >= 0xd000 && addr < 0xe000 { - Ok(self.wram_01[addr as usize - 0xd000]) + self.wram_01[addr as usize - 0xd000] } else if (addr >= 0x8000 && addr < 0xa000) || (addr >= 0xfe00 && addr < 0xfea0) { self.display.r(addr & !0x8000) } else if addr >= 0xff00 && addr < 0xff80 { - Ok(self.r_io((addr & 0xff) as u8)) + self.r_io((addr & 0xff) as u8) } else if addr >= 0xff80 && addr < 0xffff { - Ok(self.hram[addr as usize - 0xff80]) + self.hram[addr as usize - 0xff80] } else if addr == 0xffff { - Ok(self.interrupts_register) + self.interrupts_register } else { println!( "Trying to read at address 0x{:04x} which is unimplemented", addr ); - Ok(0) //Err(MemError::Unimplemented) + 0 } } - pub fn w(&mut self, addr: u16, value: u8) -> Result<(), MemError> { + pub fn w(&mut self, addr: u16, value: u8) { if addr < 0x2000 { self.ram_bank_enabled = value == 0x0a; - Ok(()) } else if addr >= 0x2000 && addr < 0x4000 { if value == 0 { self.rom_bank = 1 } else { self.rom_bank = value & 0b1111111; } - Ok(()) } else if addr >= 0x4000 && addr < 0x6000 { self.ram_bank = value & 0b11; - Ok(()) } else if addr >= 0xa000 && addr < 0xc000 { self.external_ram[self.ram_bank as usize * 0x2000 + addr as usize - 0xa000] = value; - Ok(()) } else if addr >= 0xc000 && addr < 0xd000 { self.wram_00[addr as usize - 0xc000] = value; - Ok(()) } else if addr >= 0xd000 && addr < 0xe000 { self.wram_01[addr as usize - 0xd000] = value; - Ok(()) } else if (addr >= 0x8000 && addr < 0xa000) || (addr >= 0xfe00 && addr < 0xfea0) { - self.display.w(addr & !0x8000, value) + self.display.w(addr & !0x8000, value); } else if addr >= 0xff00 && addr < 0xff80 { - Ok(self.w_io((addr & 0xff) as u8, value)?) + self.w_io((addr & 0xff) as u8, value); } else if addr >= 0xff80 && addr < 0xffff { self.hram[addr as usize - 0xff80] = value; - Ok(()) } else if addr == 0xffff { self.interrupts_register = value; - Ok(()) } else { println!( "Trying to write at address 0x{:04x} which is unimplemented (value: {:02x})", addr, value ); - Ok(()) //Err(MemError::Unimplemented) } } } @@ -349,11 +333,11 @@ impl<S: Serial, A: Audio> GBState<S, A> { } } - pub fn r_reg(&self, r_i: u8) -> Result<u8, MemError> { + pub fn r_reg(&self, r_i: u8) -> u8 { if r_i < 6 { - Ok(self.cpu.r[r_i as usize]) + self.cpu.r[r_i as usize] } else if r_i == 7 { - Ok(self.cpu.r[6]) + self.cpu.r[6] } else if r_i == 6 { self.mem.r(self.cpu.r16(reg::HL)) } else { @@ -361,17 +345,16 @@ impl<S: Serial, A: Audio> GBState<S, A> { } } - pub fn w_reg(&mut self, r_i: u8, value: u8) -> Result<(), MemError> { + pub fn w_reg(&mut self, r_i: u8, value: u8) { if r_i < 6 { self.cpu.r[r_i as usize] = value; } else if r_i == 7 { self.cpu.r[6] = value; } else if r_i == 6 { - self.mem.w(self.cpu.r16(reg::HL), value)?; + self.mem.w(self.cpu.r16(reg::HL), value); } else { panic!("r_i must be a 3 bits register input number") } - Ok(()) } pub fn debug(&self, s: &str) -> () { |