mirror of
https://github.com/transistorfet/moa.git
synced 2025-02-16 11:30:33 +00:00
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
This commit is contained in:
parent
588c0b56a2
commit
10ca0c7995
22
docs/log.txt
22
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
|
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
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,6 +102,23 @@ impl Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"w" | "watch" => {
|
||||||
|
if args.len() != 2 {
|
||||||
|
println!("Usage: watch <addr>");
|
||||||
|
} 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 <addr>");
|
||||||
|
} 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" => {
|
"d" | "dump" => {
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?;
|
let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?;
|
||||||
|
@ -118,8 +118,10 @@ pub struct Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
ignore_unmapped: bool,
|
|
||||||
blocks: Vec<Block>,
|
blocks: Vec<Block>,
|
||||||
|
ignore_unmapped: bool,
|
||||||
|
watchers: Vec<Address>,
|
||||||
|
watcher_modified: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
@ -127,6 +129,8 @@ impl Bus {
|
|||||||
Bus {
|
Bus {
|
||||||
ignore_unmapped: false,
|
ignore_unmapped: false,
|
||||||
blocks: vec!(),
|
blocks: vec!(),
|
||||||
|
watchers: vec!(),
|
||||||
|
watcher_modified: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +181,23 @@ impl Bus {
|
|||||||
println!("{}", line);
|
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 {
|
impl Addressable for Bus {
|
||||||
@ -199,6 +220,11 @@ impl Addressable for Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
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()) {
|
let (dev, relative_addr) = match self.get_device_at(addr, data.len()) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(err) if self.ignore_unmapped => {
|
Err(err) if self.ignore_unmapped => {
|
||||||
|
@ -718,7 +718,7 @@ impl Addressable for Ym7101 {
|
|||||||
0x20
|
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 {
|
match addr {
|
||||||
// Read from Data Port
|
// Read from Data Port
|
||||||
0x00 | 0x02 => {
|
0x00 | 0x02 => {
|
||||||
@ -734,10 +734,16 @@ impl Addressable for Ym7101 {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Read from Control Port
|
// Read from Control Port
|
||||||
0x04 | 0x06 => {
|
0x04 | 0x05 | 0x06 | 0x07 => {
|
||||||
debug!("{}: read status byte {:x}", DEV_NAME, self.state.status);
|
debug!("{}: read status byte {:x}", DEV_NAME, self.state.status);
|
||||||
data[0] = (self.state.status >> 8) as u8;
|
for i in 0..data.len() {
|
||||||
data[1] = (self.state.status & 0x00FF) as u8;
|
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); },
|
_ => { println!("{}: !!! unhandled read from {:x}", DEV_NAME, addr); },
|
||||||
|
@ -106,7 +106,11 @@ impl System {
|
|||||||
self.check_debugger();
|
self.check_debugger();
|
||||||
|
|
||||||
match self.process_one_event() {
|
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 => {
|
Err(err) if err.err == ErrorType::Breakpoint => {
|
||||||
println!("Breakpoint reached: {}", err.msg);
|
println!("Breakpoint reached: {}", err.msg);
|
||||||
self.enable_debugging();
|
self.enable_debugging();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user