mirror of
https://github.com/daniel5151/ANESE.git
synced 2025-04-02 10:32:00 -04:00
251 lines
6.9 KiB
Text
Vendored
251 lines
6.9 KiB
Text
Vendored
NES CPU Interrupt Tests
|
|
-----------------------
|
|
Tests behavior and timing of CPU in the presence of interrupts, both IRQ
|
|
and NMI.
|
|
|
|
|
|
CLI Latency Summary
|
|
-------------------
|
|
The RTI instruction affects IRQ inhibition immediately. If an IRQ is
|
|
pending and an RTI is executed that clears the I flag, the CPU will
|
|
invoke the IRQ handler immediately after RTI finishes executing.
|
|
|
|
The CLI, SEI, and PLP instructions effectively delay changes to the I
|
|
flag until after the next instruction. For example, if an interrupt is
|
|
pending and the I flag is currently set, executing CLI will execute the
|
|
next instruction before the CPU invokes the IRQ handler. This delay only
|
|
affects inhibition, not the value of the I flag itself; CLI followed by
|
|
PHP will leave the I flag cleared in the saved status byte on the stack
|
|
(bit 2), as expected.
|
|
|
|
|
|
1-cli_latency
|
|
-------------
|
|
Tests the delay in CLI taking effect, and some basic aspects of IRQ
|
|
handling and the APU frame IRQ (needed by the tests). It uses the APU's
|
|
frame IRQ and first verifies that it works well enough for the tests.
|
|
|
|
The later tests execute CLI followed by SEI and equivalent pairs of
|
|
instructions (CLI, PLP, where the PLP sets the I flag). These should
|
|
only allow at most one invocation of the IRQ handler, even if it doesn't
|
|
acknowledge the source of the IRQ. RTI is also tested, which behaves
|
|
differently. These tests also *don't* disable interrupts after the first
|
|
IRQ, in order to test whether a pair of instructions allows only one
|
|
interrupt or causes continuous interrupts that block the main code from
|
|
continuing.
|
|
|
|
2) RTI should not adjust return address (as RTS does)
|
|
3) APU should generate IRQ when $4017 = $00
|
|
4) Exactly one instruction after CLI should execute before IRQ is taken
|
|
5) CLI SEI should allow only one IRQ just after SEI
|
|
6) In IRQ allowed by CLI SEI, I flag should be set in saved status flags
|
|
7) CLI PLP should allow only one IRQ just after PLP
|
|
8) PLP SEI should allow only one IRQ just after SEI
|
|
9) PLP PLP should allow only one IRQ just after PLP
|
|
10) CLI RTI should not allow any IRQs
|
|
11) Unacknowledged IRQ shouldn't let any mainline code run
|
|
12) RTI RTI shouldn't let any mainline code run
|
|
|
|
|
|
2-nmi_and_brk
|
|
-------------
|
|
NMI behavior when it interrupts BRK. Occasionally fails on
|
|
NES due to PPU-CPU synchronization.
|
|
|
|
Result when run:
|
|
NMI BRK --
|
|
27 36 00 NMI before CLC
|
|
26 36 00 NMI after CLC
|
|
26 36 00
|
|
36 00 00 NMI interrupting BRK, with B bit set on stack
|
|
36 00 00
|
|
36 00 00
|
|
36 00 00
|
|
36 00 00
|
|
27 36 00 NMI after SEC at beginning of IRQ handler
|
|
27 36 00
|
|
|
|
|
|
3-nmi_and_irq
|
|
-------------
|
|
NMI behavior when it interrupts IRQ vectoring.
|
|
|
|
Result when run:
|
|
NMI IRQ
|
|
23 00 NMI occurs before LDA #1
|
|
21 00 NMI occurs after LDA #1 (Z flag clear)
|
|
21 00
|
|
20 00 NMI occurs after CLC, interrupting IRQ
|
|
20 00
|
|
20 00
|
|
20 00
|
|
20 00
|
|
20 00
|
|
20 00 Same result for 7 clocks before IRQ is vectored
|
|
25 20 IRQ occurs, then NMI occurs after SEC in IRQ handler
|
|
25 20
|
|
|
|
|
|
4-irq_and_dma
|
|
-------------
|
|
Has IRQ occur at various times around sprite DMA.
|
|
First column refers to what instruction IRQ occurred
|
|
after. Second column is time of IRQ, in CPU clocks relative
|
|
to some arbitrary starting point.
|
|
|
|
0 +0
|
|
1 +1
|
|
1 +2
|
|
2 +3
|
|
2 +4
|
|
4 +5
|
|
4 +6
|
|
7 +7
|
|
7 +8
|
|
7 +9
|
|
7 +10
|
|
8 +11
|
|
8 +12
|
|
8 +13
|
|
...
|
|
8 +524
|
|
8 +525
|
|
8 +526
|
|
9 +527
|
|
|
|
|
|
5-branch_delays_irq
|
|
-------------------
|
|
A taken non-page-crossing branch ignores IRQ during
|
|
its last clock, so that next instruction executes
|
|
before the IRQ. Other instructions would execute the
|
|
NMI before the next instruction.
|
|
|
|
The same occurs for NMI, though that's not tested here.
|
|
|
|
test_jmp
|
|
T+ CK PC
|
|
00 02 04 NOP
|
|
01 01 04
|
|
02 03 07 JMP
|
|
03 02 07
|
|
04 01 07
|
|
05 02 08 NOP
|
|
06 01 08
|
|
07 03 08 JMP
|
|
08 02 08
|
|
09 01 08
|
|
|
|
test_branch_not_taken
|
|
T+ CK PC
|
|
00 02 04 CLC
|
|
01 01 04
|
|
02 02 06 BCS
|
|
03 01 06
|
|
04 02 07 NOP
|
|
05 01 07
|
|
06 04 0A JMP
|
|
07 03 0A
|
|
08 02 0A
|
|
09 01 0A JMP
|
|
|
|
test_branch_taken_pagecross
|
|
T+ CK PC
|
|
00 02 0D CLC
|
|
01 01 0D
|
|
02 04 00 BCC
|
|
03 03 00
|
|
04 02 00
|
|
05 01 00
|
|
06 04 03 LDA $100
|
|
07 03 03
|
|
08 02 03
|
|
09 01 03
|
|
|
|
test_branch_taken
|
|
T+ CK PC
|
|
00 02 04 CLC
|
|
01 01 04
|
|
02 03 07 BCC
|
|
03 02 07
|
|
04 05 0A LDA $100 *** This is the special case
|
|
05 04 0A
|
|
06 03 0A
|
|
07 02 0A
|
|
08 01 0A
|
|
09 03 0A JMP
|
|
|
|
Multi-tests
|
|
-----------
|
|
The NES/NSF builds in the main directory consist of multiple sub-tests.
|
|
When run, they list the subtests as they are run. The final result code
|
|
refers to the first sub-test that failed. For more information about any
|
|
failed subtests, run them individually from rom_singles/ and
|
|
nsf_singles/.
|
|
|
|
|
|
Flashes, clicks, other glitches
|
|
-------------------------------
|
|
If a test prints "passed", it passed, even if there were some flashes or
|
|
odd sounds. Only a test which prints "done" at the end requires that you
|
|
watch/listen while it runs in order to determine whether it passed. Such
|
|
tests involve things which the CPU cannot directly test.
|
|
|
|
|
|
Alternate output
|
|
----------------
|
|
Tests generally print information on screen, but also report the final
|
|
result audibly, and output text to memory, in case the PPU doesn't work
|
|
or there isn't one, as in an NSF or a NES emulator early in development.
|
|
|
|
After the tests are done, the final result is reported as a series of
|
|
beeps (see below). For NSF builds, any important diagnostic bytes are
|
|
also reported as beeps, before the final result.
|
|
|
|
|
|
Output at $6000
|
|
---------------
|
|
All text output is written starting at $6004, with a zero-byte
|
|
terminator at the end. As more text is written, the terminator is moved
|
|
forward, so an emulator can print the current text at any time.
|
|
|
|
The test status is written to $6000. $80 means the test is running, $81
|
|
means the test needs the reset button pressed, but delayed by at least
|
|
100 msec from now. $00-$7F means the test has completed and given that
|
|
result code.
|
|
|
|
To allow an emulator to know when one of these tests is running and the
|
|
data at $6000+ is valid, as opposed to some other NES program, $DE $B0
|
|
$G1 is written to $6001-$6003.
|
|
|
|
|
|
Audible output
|
|
--------------
|
|
A byte is reported as a series of tones. The code is in binary, with a
|
|
low tone for 0 and a high tone for 1, and with leading zeroes skipped.
|
|
The first tone is always a zero. A final code of 0 means passed, 1 means
|
|
failure, and 2 or higher indicates a specific reason. See the source
|
|
code of the test for more information about the meaning of a test code.
|
|
They are found after the set_test macro. For example, the cause of test
|
|
code 3 would be found in a line containing set_test 3. Examples:
|
|
|
|
Tones Binary Decimal Meaning
|
|
- - - - - - - - - - - - - - - - - - - -
|
|
low 0 0 passed
|
|
low high 01 1 failed
|
|
low high low 010 2 error 2
|
|
|
|
|
|
NSF versions
|
|
------------
|
|
Many NSF-based tests require that the NSF player either not interrupt
|
|
the init routine with the play routine, or if it does, not interrupt the
|
|
play routine again if it hasn't returned yet. This is because many tests
|
|
need to run for a while without returning.
|
|
|
|
NSF versions also make periodic clicks to prevent the NSF player from
|
|
thinking the track is silent and thus ending the track before it's done
|
|
testing.
|
|
|
|
--
|
|
Shay Green <gblargg@gmail.com>
|