From 10ca0c7995cc544948441452b827449118474660 Mon Sep 17 00:00:00 2001 From: transistor Date: Sun, 26 Dec 2021 16:32:15 -0800 Subject: [PATCH] Added watch command to debugger It's a bit weirdly implemented because the Addressable trait doesn't have access to System, so it has to set a flag on the Bus which is then checked during the step function in System to activate the breakpoint if a watched memory location was written to --- docs/log.txt | 22 ++++++++++++++++++++++ src/debugger.rs | 17 +++++++++++++++++ src/memory.rs | 28 +++++++++++++++++++++++++++- src/peripherals/genesis/ym7101.rs | 14 ++++++++++---- src/system.rs | 6 +++++- 5 files changed, 81 insertions(+), 6 deletions(-) diff --git a/docs/log.txt b/docs/log.txt index 309cd31..d8eb3cb 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -194,6 +194,28 @@ before 2021-10-25 blanking bit reset at 16.6ms. I've now changed it to be proper, in that the blanking bit is set at 15ms, the count is reset at 16.6ms, and the blank bit is cleared at 1.2ms +2021-12-23 +- looking into the coprocessor not working. I tried Mortal Kombat 2 and apart from something weird + going on during the character select screen, everything worked until combat started and then it + crashed due to an invalid memory access to address 0x0068eebb, which occurs at PC: 0xffff0245, + so something is causing it to execute ram, which is probably not what's supposed to happen +- It looks like it's swapping stacks, and that's making it hard to trace. At some point, it swaps + the stack and then does a rts, but the stack return value is invalid and that causes it to mess up. + It almost looks like it does put a valid return on the stack but then unintentionally overwrites it + due to overlapping memory areas (I could just be tracing this wrong). I'll come back to this later + +2021-12-26 +- looking into the scroll black bits, I checked the scroll table for Sonic2 in BlastEm and the values + are clearly different for Scroll B. The values in BlastEm are close to 0xffff but the ones in Moa + are 0x10f2, 0x11f2, etc. And it's wrong in the source ram (0xffe000 which is copied to 0xfc00 in VRAM) +- I added watcher debug commands to watch for modifications to a given memory location, and used that + to watch 0xffe322, which is an scroll value for Scroll B in an area near the end of the hscroll table + where the scroll value is different from BlastEm. +- breakpoint occurs at 0xc670 where that value is written to. The function starts at 0xC57E and + calculates scroll values. +- so far I'm suspecting the DIV followed by the EXTW at 0xc62a might be doing something incorrect, + and then when it adds the result in %d0 to %d3 before using that as the scroll value, it's adding + too large a value (that should have been cut off to a word) diff --git a/src/debugger.rs b/src/debugger.rs index c6442a7..8673394 100644 --- a/src/debugger.rs +++ b/src/debugger.rs @@ -102,6 +102,23 @@ impl Debugger { } } }, + "w" | "watch" => { + if args.len() != 2 { + println!("Usage: watch "); + } else { + let addr = Address::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; + system.get_bus().add_watcher(addr); + } + }, + "rw" | "rwatch" | "remove_watch" => { + if args.len() != 2 { + println!("Usage: remove_watch "); + } else { + let addr = Address::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; + system.get_bus().remove_watcher(addr); + } + }, + "d" | "dump" => { if args.len() > 1 { let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; diff --git a/src/memory.rs b/src/memory.rs index 8dc35e7..3604b3d 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -118,8 +118,10 @@ pub struct Block { } pub struct Bus { - ignore_unmapped: bool, blocks: Vec, + ignore_unmapped: bool, + watchers: Vec
, + watcher_modified: bool, } impl Bus { @@ -127,6 +129,8 @@ impl Bus { Bus { ignore_unmapped: false, blocks: vec!(), + watchers: vec!(), + watcher_modified: false, } } @@ -177,6 +181,23 @@ impl Bus { println!("{}", line); } } + + pub fn add_watcher(&mut self, addr: Address) { + self.watchers.push(addr); + } + + pub fn remove_watcher(&mut self, addr: Address) { + self.watchers.push(addr); + if let Some(index) = self.watchers.iter().position(|a| *a == addr) { + self.watchers.remove(index); + } + } + + pub fn check_and_reset_watcher_modified(&mut self) -> bool { + let result = self.watcher_modified; + self.watcher_modified = false; + result + } } impl Addressable for Bus { @@ -199,6 +220,11 @@ impl Addressable for Bus { } fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + if let Some(_) = self.watchers.iter().position(|a| *a == addr) { + println!("watch: writing to address {:#06x} with {:?}", addr, data); + self.watcher_modified = true; + } + let (dev, relative_addr) = match self.get_device_at(addr, data.len()) { Ok(result) => result, Err(err) if self.ignore_unmapped => { diff --git a/src/peripherals/genesis/ym7101.rs b/src/peripherals/genesis/ym7101.rs index 54c444f..a3d4096 100644 --- a/src/peripherals/genesis/ym7101.rs +++ b/src/peripherals/genesis/ym7101.rs @@ -718,7 +718,7 @@ impl Addressable for Ym7101 { 0x20 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, mut addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { // Read from Data Port 0x00 | 0x02 => { @@ -734,10 +734,16 @@ impl Addressable for Ym7101 { }, // Read from Control Port - 0x04 | 0x06 => { + 0x04 | 0x05 | 0x06 | 0x07 => { debug!("{}: read status byte {:x}", DEV_NAME, self.state.status); - data[0] = (self.state.status >> 8) as u8; - data[1] = (self.state.status & 0x00FF) as u8; + for i in 0..data.len() { + data[i] = if (addr % 2) == 0 { + (self.state.status >> 8) as u8 + } else { + (self.state.status & 0x00FF) as u8 + }; + addr += 1; + } }, _ => { println!("{}: !!! unhandled read from {:x}", DEV_NAME, addr); }, diff --git a/src/system.rs b/src/system.rs index d144583..fa1af80 100644 --- a/src/system.rs +++ b/src/system.rs @@ -106,7 +106,11 @@ impl System { self.check_debugger(); match self.process_one_event() { - Ok(()) => { } + Ok(()) => { + if self.get_bus().check_and_reset_watcher_modified() { + self.enable_debugging(); + } + }, Err(err) if err.err == ErrorType::Breakpoint => { println!("Breakpoint reached: {}", err.msg); self.enable_debugging();