In case anyone ever gets an urge to write "JSR $2001" to their NES code, this test verifies that everything works as it should.
Download test at: http://bisqwit.iki.fi/src/nes_tests/cpu_exec_space.zip
Download test at: http://bisqwit.iki.fi/src/nes_tests/cpu_exec_space.zip
Code:
NES Memory Execution Tests
----------------------------------
These tests verify that the CPU can execute code from any possible
memory location, even if that is mapped as I/O space.
In addition, two obscure side effects are tested:
1. The PPU open bus. Any write to PPU will update the open bus.
Reading from 2002 updates the low 5 bits. Reading from 2007
updates 8 bits. The open bus is shown in any addresss/bit
that the PPU does not write to. Read from 2000, you get open bus.
Read from 2006, ditto. Read from 2002, you get that in high 3 bits.
Additionally, the open bus decays automatically to zero in about one
second if not refreshed.
This test requires that a value written to $2003 can be read back
from $2001 within a time window of one or two frames.
2. One-byte opcodes must issue a dummy read to the byte immediately
following that obcode. The CPU always does a fetch of the second
byte, before it has even begun executing the opcode in the first
place.
Additionally, the following PPU features must be working properly:
1. PPU memory writes and reads through $2006/$2007
2. The address high/low toggle reset at $2002
3. A single write through $2006 must not affect the address used by $2007
4. NMI should fire sometimes to salvage a broken program, if the JSR/JMP
never reaches its intended destination. (Only required in the
test IF the CPU and/or open bus are not working properly.)
The test is done FIVE times: Once with JSR $2001, again with JMP $2001,
and then with RTS (with target address of $2001), and then with a JMP
that expects to return with an RTI opcode. Finally, with a regular
JSR, but the return from the code is done through a BRK instruction.
Tests and results:
#2: PPU memory access through $2007 does not work properly. (Use other tests to determine the exact problem.)
#3: PPU open bus implementation is missing or incomplete: A write to $2003, followed by a read from $2001 should return the same value as was written.
#4: The RTS at $2001 was never executed. (If NMI has not been implemented in the emulator, the symptom of this failure is that the program crashes and does not output either "Fail" nor "Passed").
#5: An RTS opcode should still do a dummy fetch of the next opcode. (The same goes for all one-byte opcodes, really.)
#6: I have no idea what happened, but the test did not work as supposed to. In any case, the problem is in the PPU.
#7: A jump to $2001 should never execute code from $8001 / $9001 / $A001 / $B001 / $C001 / $D001 / $E001.
#8: Okay, the test passed when JSR was used, but NOT when the opcode was JMP. I definitely did not think any emulator would trigger this result.
#9: Your PPU is broken in mind-defyingly random ways.
#10: RTS to $2001 never returned. This message never gets displayed.
#11: The test passed when JSR was used, and when JMP was used, but NOT when RTS was used. Caught ya! Paranoia wins.
#12: Your PPU gave up reason at the last moment.
#13: JMP to $2001 never returned. Again, this message never gets displayed.
#14: An RTI opcode should still do a dummy fetch of the next opcode. (The same goes for all one-byte opcodes, really.)
#15: An RTI opcode should not destroy the PPU. Somehow that still appears to be the case here.
#16: IRQ occurred uncalled
#17: JSR to $2001 never returned. (Never displayed)
#18: The BRK instruction should issue an automatic fetch of the byte that follows right after the BRK. (The same goes for all one-byte opcodes, but with BRK it should be a bit more obvious than with others.
#19: A BRK opcode should not destroy the PPU. Somehow that still appears to be the case here.
Expected output:
TEST: test_cpu_exec_space
This program verifies that the
CPU can execute code from any
possible location that it can
address, including I/O space.
In addition, it will be tested
that an RTS instruction does a
dummy read of the byte that
immediately follows the
instructions.
JSR test OK
JMP test OK
RTS test OK
JMP+RTI test OK
BRK test OK
Passed
----------------------------------
These tests verify that the CPU can execute code from any possible
memory location, even if that is mapped as I/O space.
In addition, two obscure side effects are tested:
1. The PPU open bus. Any write to PPU will update the open bus.
Reading from 2002 updates the low 5 bits. Reading from 2007
updates 8 bits. The open bus is shown in any addresss/bit
that the PPU does not write to. Read from 2000, you get open bus.
Read from 2006, ditto. Read from 2002, you get that in high 3 bits.
Additionally, the open bus decays automatically to zero in about one
second if not refreshed.
This test requires that a value written to $2003 can be read back
from $2001 within a time window of one or two frames.
2. One-byte opcodes must issue a dummy read to the byte immediately
following that obcode. The CPU always does a fetch of the second
byte, before it has even begun executing the opcode in the first
place.
Additionally, the following PPU features must be working properly:
1. PPU memory writes and reads through $2006/$2007
2. The address high/low toggle reset at $2002
3. A single write through $2006 must not affect the address used by $2007
4. NMI should fire sometimes to salvage a broken program, if the JSR/JMP
never reaches its intended destination. (Only required in the
test IF the CPU and/or open bus are not working properly.)
The test is done FIVE times: Once with JSR $2001, again with JMP $2001,
and then with RTS (with target address of $2001), and then with a JMP
that expects to return with an RTI opcode. Finally, with a regular
JSR, but the return from the code is done through a BRK instruction.
Tests and results:
#2: PPU memory access through $2007 does not work properly. (Use other tests to determine the exact problem.)
#3: PPU open bus implementation is missing or incomplete: A write to $2003, followed by a read from $2001 should return the same value as was written.
#4: The RTS at $2001 was never executed. (If NMI has not been implemented in the emulator, the symptom of this failure is that the program crashes and does not output either "Fail" nor "Passed").
#5: An RTS opcode should still do a dummy fetch of the next opcode. (The same goes for all one-byte opcodes, really.)
#6: I have no idea what happened, but the test did not work as supposed to. In any case, the problem is in the PPU.
#7: A jump to $2001 should never execute code from $8001 / $9001 / $A001 / $B001 / $C001 / $D001 / $E001.
#8: Okay, the test passed when JSR was used, but NOT when the opcode was JMP. I definitely did not think any emulator would trigger this result.
#9: Your PPU is broken in mind-defyingly random ways.
#10: RTS to $2001 never returned. This message never gets displayed.
#11: The test passed when JSR was used, and when JMP was used, but NOT when RTS was used. Caught ya! Paranoia wins.
#12: Your PPU gave up reason at the last moment.
#13: JMP to $2001 never returned. Again, this message never gets displayed.
#14: An RTI opcode should still do a dummy fetch of the next opcode. (The same goes for all one-byte opcodes, really.)
#15: An RTI opcode should not destroy the PPU. Somehow that still appears to be the case here.
#16: IRQ occurred uncalled
#17: JSR to $2001 never returned. (Never displayed)
#18: The BRK instruction should issue an automatic fetch of the byte that follows right after the BRK. (The same goes for all one-byte opcodes, but with BRK it should be a bit more obvious than with others.
#19: A BRK opcode should not destroy the PPU. Somehow that still appears to be the case here.
Expected output:
TEST: test_cpu_exec_space
This program verifies that the
CPU can execute code from any
possible location that it can
address, including I/O space.
In addition, it will be tested
that an RTS instruction does a
dummy read of the byte that
immediately follows the
instructions.
JSR test OK
JMP test OK
RTS test OK
JMP+RTI test OK
BRK test OK
Passed