It would be great if the debugger could show the previous value of the program counter somewhere in addition to the current value. That way, especially, when a breakpoint is triggered by an event (i.e. port read), it would be possible to trace back to the previous instruction (if it were a jump, rather than a call).
In addition—and this might be related—when even triggers are used as breakpoints, the debugger seems to skip the actual triggering event and stop at the next instruction instead. Since there's no way to scroll back the current instruction list (at least in the macOS version), one has to issue an additional disassembly command, guessing how many bytes to subtract from the current value of the porgram counter, and then manually put another breakpoint there to be able to single step to the actual instruction that triggered the debugger in the first place.
I was looking to learn about the fuse codebase and homed in on this ticket in a rather arbitrary way. How would saving the previous PC register work I asked myself? I started investigating, and from an initial parse of the fuse code it looks fairly straightforward.
In the z80 structure I created on of these:
regpair previous_pc;
In the z80_macros.h header I created these two macros:
#define PPC z80.previous_pc.w
and
#define SAVE_PREVIOUS_PC (PPC=PC)
then added a SAVE_PREVIOUS_PC call to the existing RET and RST macros.
I then added a SAVE_PREVIOUS_PC call in z80_ops.c at the end_opcode: label (just before the generated opcode handling code is pulled in).
That appears to do the trick. I hacked in a line into the debugger window so I could see the previous PC value while single stepping and it seems to behave correctly. That's not the correct user interface to the value, so I added it as a debugger variable instead, which seems to make more sense.
OK, so it's probably time to stop and ask the knowledgable folks:
1) is the approach I ended up with a reasonable one? Could it be done better?
2) are there any nuances of the fuse codebase or the z80 which are going to make this approach unreliable? Anything I need to look for?
3) what's the correct interface to a "previous PC" value?
Thanks for looking into this!
I don’t think there’s a “correct” way per se, but SpecEmu has a dedicated space for it in the main debugger window. See the attached screenshot.
(Note, that SpecEmu actually uses multiple debugger windows, including a separate one which shows the state of all registers.)
Small update: I took the calls to SAVE_PREVIOUS_PC out of the RET and RST macros. They weren't right there, producing off by one errors in the PrevPC value.
As for the interface, yes, it's tricky. The debugger variable value is neat but rather useless! It's a terribly inconvenient way to get at the value. I'm still using my hacked debugger window, which shows it at a glance. The thing is, the PrevPC value doesn't really fit anywhere in there. It's not a register, so can't go in with the registers, and it clearly isn't right in the disassembly or stack panes. Maybe it can go in with the T-states or interrupt mode values?
Hopefully a fuse expert will chip in. :)
Technically, there’s no need to display the stack pointer twice—once alongside the other registers and a second time in the actual stack widget (along with the values above it). The slot right next to the actual PC could then be used to display the previous PC value.