New CPU test ROM
Moderator: Moderators
New CPU test ROM
I've been working on a new test framework that can run multiple groups of tests and give better feedback. As a first use of it, here's a set of CPU tests that do most instructions, testing several edge cases. If it fails, it prints the opcode and instruction name. It only tests official instructions right now.
blargg_nes_cpu_test5.zip
These tests work like zexall, trying each instruction with all interesting combinations of inputs and checksumming the registers afterwards. After all the different combinations have been fed to a particular instruction, the checksum is compared with the correct one to determine pass/fail.
EDIT: Replaced with version that doesn't stop on failure, so you get a list of all the instructions that failed.
blargg_nes_cpu_test5.zip
These tests work like zexall, trying each instruction with all interesting combinations of inputs and checksumming the registers afterwards. After all the different combinations have been fed to a particular instruction, the checksum is compared with the correct one to determine pass/fail.
EDIT: Replaced with version that doesn't stop on failure, so you get a list of all the instructions that failed.
Last edited by blargg on Sat Jan 19, 2008 8:31 pm, edited 2 times in total.
-
- Posts: 82
- Joined: Sat Sep 22, 2007 8:32 am
- Location: Seattle, WA
- Contact:
-
- Posts: 323
- Joined: Fri Jun 29, 2007 10:25 pm
- Location: Earth, Milkyway Galaxy, The Universe, M-Theory
- Contact:
-
- Posts: 82
- Joined: Sat Sep 22, 2007 8:32 am
- Location: Seattle, WA
- Contact:
I've been trying to get this to pass since you've posted it. How exactly is this testing the functions? I'm failing several but is failing of one dependent on the others? I'm getting this (at bottom) but as I go over the functions, everything seems right. Example: ASL, a
Code: Select all
/* ASL */
#define ARITHMATIC_SHIFT_LEFT_A(CYCLES){
addr = (memory[program_counter + 1] << 8) | memory[program_counter];
tmp = memory_read(addr);
carry_flag = (carry_flag & 0xFE) | ((tmp >> 7) & 0x01);
tmp <<= 1;
write_memory(addr, tmp);
sign_flag = tmp & 0x80;
zero_flag = !(tmp);
program_counter += 2;
cycle_count -= CYCLES;
break;
}
-
- Posts: 82
- Joined: Sat Sep 22, 2007 8:32 am
- Location: Seattle, WA
- Contact:
New version, tests most unofficial instructions now, more thorough instruction coverage, and includes some documentation and full source code. Switched to MMC1, since apparently UxROM doesn't strictly support CHR ROM. Thanks to bunnyboy and thefox for testing help:
blargg_nes_cpu_test5.zip
blargg_nes_cpu_test5.zip
I like it, I got errors with cpu.nes on AB ATX, 9C SYA, 9E SXA. I was able to fix ATX by ORing A with $FF, according to documents it's ORed with $EE, $EF, $FE, or $FF depending on CPU internal state like the program counter. Maybe on the NES it's always ORed with $FF, at least it makes your test program a bit happier on my emu.
I couldn't fix my SYA and SXA implementations, can someone explain how these work? I'm currently using this method:
http://www.s-direktnet.de/homepages/k_nadj/opcodes.html
I couldn't fix my SYA and SXA implementations, can someone explain how these work? I'm currently using this method:
http://www.s-direktnet.de/homepages/k_nadj/opcodes.html
Code: Select all
SAY ***
This opcode ANDs the contents of the Y register with and stores the
result in memory.
One supported mode:
SAY abcd,X ;9C cd ab ;No. Cycles= 5
Example:
SAY $7700,X ;9C 00 77
Equivalent instructions:
PHA
TYA
AND #$78
STA $7700,X
PLA
XAS ***
This opcode ANDs the contents of the X register with and stores the
result in memory.
One supported mode:
XAS abcd,Y ;9E cd ab ;No. Cycles= 5
Example:
XAS $6430,Y ;9E 30 64
Equivalent instructions:
PHA
TXA
AND #$65
STA $6430,Y
PLA
$EF in particular looks like the mask for a carry coming out of the lower nibble, as might be seen in hardware handling packed binary-coded decimal, such as the original 6502 CPU manufactured by MOS Technology.hap wrote:I was able to fix ATX by ORing A with $FF, according to documents it's ORed with $EE, $EF, $FE, or $FF depending on CPU internal state like the program counter.
This might be the case for the NES, which for patent reasons uses a cut-down 6502 core lacking decimal mode.Maybe on the NES it's always ORed with $FF, at least it makes your test program a bit happier on my emu.
Opcode $AB is known to work differently depending on the machine. Possible outcomes I've seen reported:
1. OR with $EE always
2. OR with $EE, $EF, $FE, or $FF based on the contents of other registers
3. OR with a seemingly random value (possibly influenced by DMA transfers)
4. Perform no OR operation at all (go straight to the AND step)
I think this opcode is triggering a bus conflict, causing the bits in A to get forced high in some cases (machine-dependent). Unless people test this opcode on multiple NES's to see if it works the same on all of them or not, we should assume the exact behavior to be unpredictable.
Exactly what is causing errors with $9C and $9E? Specifically, do problems show up during page boundary crossing, when there's no page crossing, or both? I suspect that since the store value is affected by the upper byte of the target address (the "fixed" version, with 1 added to it), it's possible that a page crossing would also cause an issue with the upper address lines during the store cycle. I haven't seen any docs that give light to this possibility, but that may be because no one tested it.
1. OR with $EE always
2. OR with $EE, $EF, $FE, or $FF based on the contents of other registers
3. OR with a seemingly random value (possibly influenced by DMA transfers)
4. Perform no OR operation at all (go straight to the AND step)
I think this opcode is triggering a bus conflict, causing the bits in A to get forced high in some cases (machine-dependent). Unless people test this opcode on multiple NES's to see if it works the same on all of them or not, we should assume the exact behavior to be unpredictable.
Exactly what is causing errors with $9C and $9E? Specifically, do problems show up during page boundary crossing, when there's no page crossing, or both? I suspect that since the store value is affected by the upper byte of the target address (the "fixed" version, with 1 added to it), it's possible that a page crossing would also cause an issue with the upper address lines during the store cycle. I haven't seen any docs that give light to this possibility, but that may be because no one tested it.
"Last version was better," says Floyd. "More bugs. Bugs make game fun."
You're right. Not that I've verified this on the NES, but blargg_nes_cpu_test5 passes on my emu if I mask the high address byte with $00 if there's a page crossing on SYA or SXA. Simply ignoring the write on page crossing made it pass too. Though, ORing it with $700 on page crossing (making it sometimes write to $700 like blargg said), makes it fail.Specifically, do problems show up during page boundary crossing, when there's no page crossing, or both? I suspect that since the store value is affected by the upper byte of the target address (the "fixed" version, with 1 added to it), it's possible that a page crossing would also cause an issue with the upper address lines during the store cycle.