gianlucag / mos6502

A fast & simple MOS 6502 CPU emulator written in C++
MIT License
291 stars 59 forks source link

The dummy read before stack pulls doesn't seem to happen #16

Open omarandlorraine opened 1 year ago

omarandlorraine commented 1 year ago

The stack pointer hardware in the 6502 can only update the stack pointer after the stack access has happened. So, it decrements the stack pointer after pushing a value onto the stack, so that the stack pointer is ready for another push.

But when pulling, this means it has to pull some dummy data (just to update the stack pointer) before pulling the real data.

It looks as though gianlucag/mos6502 does not do this dummy read. While executing a plp instruction, which is a four-cycle instruction, gianlucag/mos6502 performs only two memory reads:

  1. the opcode byte
  2. the PSW from the stack

but the real chip will perform the following four memory reads:

  1. the opcode byte
  2. the next byte in the instruction stream (all instructions do this in cycle two, while the instruction is being decoded, just in case)
  3. the byte immediately below where the PSW is about to be read from
  4. the PSW from the stack

Exactly the same problem affects other instructions that read from the stack: rts, pla, and probably also rti.

gianlucag commented 1 year ago

Feel free to open a PR for this issue

essial commented 4 months ago

For anyone who winds up here because they are testing this against cycle-accurate unit tests, note that although this project listed "100% cycle accuracy" as "still to implement". This emulator is fundamentally unable to execute at a cycle-accurate level as the entire thing is built around instruction-accurate code. Cycle accurate code requires a very different (and more CPU intensive) microcode-centric approach.

gianlucag commented 3 months ago

For anyone who winds up here because they are testing this against cycle-accurate unit tests, note that although this project listed "100% cycle accuracy" as "still to implement". This emulator is fundamentally unable to execute at a cycle-accurate level as the entire thing is built around instruction-accurate code. Cycle accurate code requires a very different (and more CPU intensive) microcode-centric approach.

Please have a look at https://emulation.gametechwiki.com/index.php/Emulation_accuracy

Strictly speaking, this emulator is cycle-based accurate but not full-cycle accurate, meaning that it reproduces the system's functional behavior within a specified number of cycles (specified in the Run() method). The provided cycle amount is executed as fast as possible.

essial commented 1 month ago

That is true, but cycle-based accurate means it executes instructions idealistically, not realistically. There are scenarios where a value can be written somewhere mid-instructions that would cause a very different thing to happen than if it was executing as a full-cycle accurate system. Should these scenarios ever come up in the 'real world'? Not really, no, but it WILL fail these strange edge cases regardless as it is indeed not 100% accurate.

I'm not saying this project is garbage because it's not full-cycle accurate - there's usually no harm in doing it this way - I'm responding to the statement about opening a PR - I feel this issue is more of a "wontfix" because it requires a very different way of emulating the CPU that isn't in the spirit of the design of this emulation core.