SkillAgentSearch skills...

AccuracyCoin

A large collection of NES accuracy tests on a single NROM cartridge.

Install / Use

/learn @100thCoin/AccuracyCoin
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

AccuracyCoin

AccuracyCoin is a large collection of NES accuracy tests on a single NROM cartridge.

This ROM was designed for an NTSC console with an RP2A03G CPU and RP2C02G PPU. Some tests might be automatically skipped on hardware with a different revision.

This ROM currently has 137 tests. These tests print "PASS" or "FAIL" on screen, and in the event of a failure, this ROM also provides an error code. In addition to those tests, this ROM also has 5 tests labeled "DRAW", which don't actually test for anything; rather, they simply print information on screen.

Here's an example of the menu in this ROM shown on an emulator failing a few tests, passing others, and a few tests on screen haven't been run yet. (The cursor is currently next to the "The Decimal Flag" test.)

<img width="256" height="240" alt="Page1" src="https://github.com/user-attachments/assets/335502f4-d5ac-4aed-ac1f-e31ea614d2a3" />

Navigating the menus

Use the D-Pad to move the cursor up or down.
Pressing A will run the highlighted test.
Pressing B will mark the highlighted test to be skipped. You can press B again to un-mark the test. This is useful if any tests are crashing the console or emulator and you still want to see the table of results.
If the cursor is at the top of the page (highlighting the current page index), pressing left and right will scroll to a new page of tests.
If the cursor is at the top of the page (highlighting the current page index), pressing A will run all tests on the page.
If the cursor is at the top of the page (highlighting the current page index), pressing B will mark all tests on the page to be skipped.
If the cursor is at the top of the page (highlighting the current page index), pressing Start will run all tests on the ROM, and then draw a table showing the results of every test.

Examples:

<img width="563" height="240" alt="TableComp" src="https://github.com/user-attachments/assets/33b6b6d0-0509-4791-a3de-041ab681a43f" />

Any test with multiple acceptable passing behaviors will be drawn with a light blue number over it.

The Debug Menu

After running a test, you can press "Select" to reveal this menu:

DebugMenu_0

This menu will print several bytes on screen and can be useful for debugging certain tests in a situation where you don't have a way to view everything in RAM. I suggest simply using some form of memory viewer if possible.

This menu does not apply to every test in the ROM, as many tests don't write anything to RAM, or the values written aren't relevant for what went wrong.

The topmost row will print the values from address $20 to $2F, which are values used in the Unofficial Instruction tests.
The second row will print the values from $50 to $6F, which are used in a handful of tests.
The remaining 8 rows will print every byte from address $500 to $5FF, which is typically where a test will store any bytes needed for it.

Here's a color-coded version of that image, with boxes around each byte:

DebugMenu_1

Error Codes

For more information, I recommend reading the fully commented assembly code for the test.

Page 1: CPU Behavior

ROM is not Writable

1: Writing to ROM should not overwrite the byte in ROM.

RAM Mirroring

1: Reading from a 13-bit mirror of an address in RAM should have the same value as the 11-bit address.
2: Writing to a 13-bit mirror of an address in RAM should write to the 11-bit address.

PC Wraparound

1: Executing address $FFFF should read addresses $0000 and $0001 as the operands.

The Decimal Flag

1: The 6502 "Binary Coded Decimal" flag should not affect the ADC or SBC instructions on the NES.
2: Despite this flag not working, it still gets pushed in a PHP/BRK instruction.

The B Flag

1: The B flag of the 6502 processor flags should be set by PHP.
2: The B flag of the 6502 processor flags should be set by BRK.
3: An IRQ should have occured.
4: The B flag of the 6502 processor flags should not be set by an IRQ.
5: The B flag of the 6502 processor flags should not be set by an NMI.
6: Bit 5 of the 6502 processor flags should be set by PHP.
7: Bit 5 of the 6502 processor flags should be set by BRK.
8: Bit 5 of the 6502 processor flags should be set by an IRQ.
9: Bit 5 of the 6502 processor flags should be set by an NMI.

Dummy read cycles

1: A mirror of PPU_STATUS ($2002) should be read twice by LDA $20F2, X (where X = $10).
2: The dummy read should not occur if a page boundary is not crossed.
3: The dummy read was on an incorrect address.
4: The STA, X instruction should have a dummy read.
5: The STA, X dummy read was on an incorrect address.
6: LDA (Indirect), Y should not have a dummy read if a page boundary is not crossed by the Y indexing.
7: LDA (Indirect), Y should have a dummy read if a page boundary is crossed by the Y indexing.
8: STA (Indirect), Y should not have a dummy read if a page boundary is not crossed by the Y indexing.
9: STA (Indirect), Y should have a dummy read if a page boundary is crossed by the Y indexing.
A: LDA (Indirect, X) should not have a dummy read.
B: STA (Indirect, X) should not have a dummy read.

Dummy write cycles

1: PPU Open Bus should exist.
2: Read-modify-write instructions should write to $2006 twice.
3: Read-modify-write instructions with X indexing should write to $2006 twice.

Open Bus

1: Reading from open bus is not all zeroes.
2: Reading from open bus with LDA Absolute should simply return the high byte of the operand.
3: Indexed addressing crossing a page boundary should not update the data bus to the new high byte value.
4: Moving the program counter to open bus should read instructions from the floating data bus values. Write cycles should update the data bus.
5: Dummy reads should update the data bus.
6: The upper 3 bits when reading from the controller should be open bus.
7: Reading from $4015 should not update the databus.
8: Writing should always update the databus, even writing to $4015.
9: Bit 5 of address $4015 should be open bus.

All NOP Instructions

(See message printed on screen for more details)
1: Opcode $04 (NOP Zero Page) malfunctioned.
2: Opcode $0C (NOP Absolute) malfunctioned.
3: Opcode $14 (NOP Zero Page, X) malfunctioned.
4: Opcode $1A (NOP Implied) malfunctioned.
5: Opcode $1C (NOP Absolute, X) malfunctioned.
6: Opcode $34 (NOP Zero Page, X) malfunctioned.
7: Opcode $3A (NOP Implied) malfunctioned.
8: Opcode $3C (NOP Absolute, X) malfunctioned.
9: Opcode $44 (NOP Zero Page) malfunctioned.
A: Opcode $54 (NOP Zero Page, X) malfunctioned.
B: Opcode $5A (NOP Implied) malfunctioned.
C: Opcode $5C (NOP Absolute, X) malfunctioned.
D: Opcode $64 (NOP Zero Page) malfunctioned.
E: Opcode $74 (NOP Zero Page, X) malfunctioned.
F: Opcode $7A (NOP Implied) malfunctioned.
G: Opcode $7C (NOP Absolute, X) malfunctioned.
H: Opcode $80 (NOP Immediate) malfunctioned.
I: Opcode $82 (NOP Immediate) malfunctioned.
J: Opcode $89 (NOP Immediate) malfunctioned.
K: Opcode $C2 (NOP Immediate) malfunctioned.
L: Opcode $D4 (NOP Zero Page, X) malfunctioned.
M: Opcode $DA (NOP Implied) malfunctioned.
N: Opcode $DC (NOP Absolute, X) malfunctioned.
O: Opcode $E2 (NOP Immediate) malfunctioned.
P: Opcode $EA (NOP Implied) malfunctioned.
Q: Opcode $F4 (NOP Zero Page, X) malfunctioned.
R: Opcode $FA (NOP Implied) malfunctioned.
S: Opcode $FC (NOP Absolute, X) malfunctioned.

Page 2: Addressing Mode Wraparound

Absolute Indexed Wraparound

1: Absolute indexed addressing did not read from the correct address.
2: When indexing with X beyond address $FFFF, the instruction should read from the zero page.
3: When indexing with Y beyond address $FFFF, the instruction should read from the zero page.

Zero Page Indexed Wraparound

1: Zero Page indexed addressing did not read from the correct address.
2: When indexing with X beyond address $00FF, the instruction should still read from the zero page.
3: When indexing with Y beyond address $00FF, the instruction should still read from the zero page.

Indirect Addressing Wraparound

1: JMP (Indirect) did not move the program counter to the correct address.
2: The address bus should wrap around the page when reading the low and high bytes with indirect addressing.

Indirect Addressing, X Wraparound

1: Indirect, X addressing did not read from the correct address.
2: The indirect indexing should only occur on the zero page, even if X crosses a page boundary.
3: The address bus should wrap around the page when reading the low and high bytes with indirect addressing.

Indirect Addressing, Y Wraparound

1: Indirect, Y addressing did not read from the correct address.
2: The Y indexing should be able to cross a page boundary, and the high byte should be updated.
3: The address bus should wrap around the page when reading the low and high bytes with indirect addressing.

Relative Addressing Wraparound

1: You should be able to branch from the Zero Page to page $FF.
2: You should be able to branch from page $FF to the Zero Page.

Pages 3, 4, 5, 6, 7, 8, 9, 10, and 11: Unofficial Instructions

Unofficial Instructions: SLO, RLA, SRE, RRA, SAX, LAX, DCP, ISC, ANC, ASR, ARR, ANE, LXA, AXS, SBC, SHA, SHX, SHY, SHS, LAE

F: The high byte corruption did not match any known behavior. (Only applicable to SHA and SHS.)
0: This instruction had the wrong number of operand bytes.
1: The target address of the instruction was not correct.
2: The A register was not the correct value after the test.
3: The X register was not the corre

View on GitHub
GitHub Stars896
CategoryDevelopment
Updated12h ago
Forks19

Languages

Assembly

Security Score

95/100

Audited on Mar 29, 2026

No findings