simias / psx-guide

Guide to writing a Playstation emulator
255 stars 17 forks source link

Possible annexe: CPU trace #2

Open arcanis opened 9 years ago

arcanis commented 9 years ago

Something that helped me a lot when working on a GBC emulator was to have an exact trace of what the CPU executed, and how the registers (possibly the memory) were affected. I tweaked a reference emulator (Gambatte) to dump the same trace format than me, regularly diff'ing my output and Gambatte's one to find out what went wrong (I even had wrote a tool to help me in this process).

I feel like something like this might be very useful as an annexe - maybe not the full trace in the document itself, but at least on this repo and referenced in the document.

simias commented 9 years ago

I did basically the same thing as you for my GB emulator :)

I haven't tried to do it for this emulator yet but I can see a few potential issues:

Gambatte is basically cycle-accurate so it's fine to use it as a "perfect" reference, unfortunately no PSX emulator comes close to that.

Which is why I'm more focused on implementing a proper debugger. But of course I might change my mind when I encounter weird breakage for some games...

ghost commented 8 years ago

Another problem you'll run into is that the GB ran at ~1MHz, so the logs are a lot smaller. The PSX runs at ~33MHz and the logs would be gigantic. FWIW you could set up a local socket and have your emulator step in sync with a known working emulator, verifying as much as you want at each step. If something is different, stop both emulators and print your CPU state along with theirs.

Takes a little more work, but it's much more scalable/automated, and it'll tell you the exact instruction that differed so you don't have to go looking for it in giant log files.

simias commented 8 years ago

So since then I've implemented two things in my emulator, the first is GDB support which lets me debug the code running in the emulator:

gdb

I've also been working on trace support like @arcanis proposed, I dump a VCD file that traces selected variables in the emulator;

rustation-waveform

Obviously if I trace values that change a lot (like the PC or things like that) it gets very slow very fast, but it's convenient if you want to get an overview of how the emulator behaves over a certain time period. I've been using it to debug the DMA for instance, it helps understand race conditions and things like that.

ghost commented 8 years ago

That looks very handy indeed. I would highly suggest using a local socket for the debugger you have as well for a few reasons.

  1. It would separate the core and debugger cleanly
  2. It would allow other emudevs such as myself to "hook in" and communicate with your emulator to run side-by-side comparisons with.
  3. It's pretty standard design practice, at least for *nix systems.
simias commented 8 years ago

Yeah I completely agree, I really didn't want to add a whole lot of debugging code (UI and all) inside the emulator. That's why I opted for remote GDB over TCP, it's a simple enough protocol and GDB is a pretty powerful debugger.

Even the remote GDB implementation is abstracted away, I just pass an opaque Debugger object around which methods like pc_change, memory_read, etc... Then the GDB remote implements this trait.