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.
Can you make it continue after an instruction fails?
Thank you for your work on these test case ROMs, I found some more bugs!
Any idea if you're going to add illegal opcode support?
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:
/* 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;
}
Is tmp an 8-bit variable, or more? It could be that one of the instructions used to do the tests isn't working correctly. What does kevtris' nestest say?
The variable tmp is an unsigned int; nestest gives all OK as does the older NEStress. Though not all of your other test pass yet if that matters too.
If tmp is an int, then your code calculates the Z flag wrong!
tmp = memory_read(addr);
tmp <<= 1;
zero_flag = !(tmp);
What happens if this reads 0x80 from memory into tmp? After the <<= 1, tmp=0x100 when it should be 0, and the zero flag is erroneously clear!
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
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
Code:
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
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.
$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.
Quote:
Maybe on the NES it's always ORed with $FF, at least it makes your test program a bit happier on my emu.
This might be the case for the NES, which for patent reasons uses a cut-down 6502 core lacking decimal mode.
I just tested and 9C and 9E are screwey. I need to take them off the test. Depending on X and Y they sometimes write to $700, among other things. Maybe someone else can figure them out properly.
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.
Quote:
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.
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.
Hi I'm new and am writing my first NES emulator... still have some bugs in the CPU methinks, and haven't done much as far as video is concerned. I ran the test ROM and it got to the point where it was polling the PPU I think... problem I don't have any PPU code written yet. Is there a way you could make the CPU test ROM store results in specified places in memory instead?
Thanks for the ROM though... I've already found a few bugs trying to get it going.
As for nestest 5, I'm sure it was not built with such keys, as it said in readme file. I tried:
Code:
ca65 -I common -o rom.o 01-implied.a
ld65 -C nes.cfg rom.o -o rom.nes
pause
, but got bunch of mistakes even in first included file (common.a). Also
Quote:
Don't bother trying to build a multi-test ROM
So what's then 'cpu.nes'?
griever wrote:
As for nestest 5, I'm sure it was not built with such keys, as it said in readme file.
What "keys" are you referring to? I see no mention of that in this thread or the readme.
Quote:
I tried:
Code:
ca65 -I common -o rom.o 01-implied.a
ld65 -C nes.cfg rom.o -o rom.nes
pause
, but got bunch of mistakes even in first included file (common.a).
I'm sorry to hear that (
hint, hint).
Quote:
Also
Quote:
Don't bother trying to build a multi-test ROM
So what's then 'cpu.nes'?
A multi-test ROM made of all the tests in source/. 'offical.nes' is the same, except the symbol OFFICIAL_ONLY is defined, which disables the unofficial instructions. The "multi" means it has a special shell that runs each individual test file's assembled output. Building such a multi-test wasn't simple enough to be worth releasing.
Quote:
What "keys" are you referring to?
Sorry, looks like language issues lead us to misunderstanding, I've meant command line parameters.
Here is the report, but sure thing, it's not a source bug and I've got something wrong...
BTW, I tried to build only one test. How can I build two or more tests, which sould be commited one by one (just bat file text will do just fine...)
I am having some trouble with the ARR from the 6502-NMOS-extra.opcodes by Adam Vardy, ARR is supposed to do an AND the operand value then ROR A, and from
http://nesdev.com/undocumented_opcodes.txt, it says ARR AND byte with accumulator, then rotate one bit right in accu-mulator then from bit 5 and 6 sets carry and overflow flag accordingly. Which one is right for the NES?
Here's what my NES seems to be doing for ARR flag calculation (the undocumented_opcodes.txt is correct for A, that is, A = (A & mask) >> 1):
Code:
// a = A, f = flags, imm = immediate byte. Returns new flags.
int arr( int a, int f, int imm )
{
a = (a & imm) >> 1;
if ( f & z02 )
f &= ~z02;
else if ( a == 0 )
f |= z02;
f &= ~(v40 | c01);
switch ( a & 0x60 )
{
case 0x00: break;
case 0x20: f |= v40; break;
case 0x40: f |= v40 | c01; break;
case 0x60: f |= c01; break;
}
return f;
}
The only difference from undocumented_opcodes.txt is the Z flag. If Z was already set before ARR executes, then Z is cleared regardless of A. If Z was clear before ARR, then it's set based on A after ARR finishes.
hap wrote:
Quote:
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.
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.
Could it be that the index gets shifted to the right when crossing a boundary on those instruction? That would explain the behavior although the test set is too limited to tell for sure.
Yeah, I make no claim to test the unofficial instructions thoroughly. I don't care about them enough to bother figuring out their full behavior (which could be very involved, no telling).
It's not obvious to me how to tell what is failing when it says there are errors? I get no errors from nestest on either official or unofficial instructions.
blargg wrote:
Replaced with version that doesn't stop on failure, so you get a list of all the instructions that failed.
What does error 1 mean? I get error 1 ten times with a group of several opcodes listed each time. Also, is instruction timing tested by this ROM?
CaptainMuscles wrote:
What does error 1 mean? I get error 1 ten times with a group of several opcodes listed each time. Also, is instruction timing tested by this ROM?
Error 1 just gets printed whenever your emu fails a group opcodes, just ignore it, instead focus on what opcode that fails, the test tells you the opcode number that fails, it does not test instruction timing, although blargg has made another test that specifically tests timing, you can get it at his site.
qeed wrote:
Error 1 just gets printed whenever your emu fails a group opcodes, just ignore it, instead focus on what opcode that fails, the test tells you the opcode number that fails...
Thanks for the response. I am afraid I still do not understand how to interpret the results. The final part of the output displays:
Errors: 10
Failed
Does this mean that opcode $10, BPL, failed? I am confused because it also happens that it says I am failing each of the 10 groups, and I don't see any other indicator that could be interpreted as an opcode.
EDIT:
Is the list of opcodes displayed in each section showing those that failed? That would make the most sense, but that would also mean that most, if not all, of my opcodes are failing, which I'm hoping is not the case.
CaptainMuscles wrote:
qeed wrote:
Error 1 just gets printed whenever your emu fails a group opcodes, just ignore it, instead focus on what opcode that fails, the test tells you the opcode number that fails...
Thanks for the response. I am afraid I still do not understand how to interpret the results. The final part of the output displays:
Errors: 10
Failed
Does this mean that opcode $10, BPL, failed? I am confused because it also happens that it says I am failing each of the 10 groups, and I don't see any other indicator that could be interpreted as an opcode.
EDIT:
Is the list of opcodes displayed in each section showing those that failed? That would make the most sense, but that would also mean that most, if not all, of my opcodes are failing, which I'm hoping is not the case.
Yes thats the errors you should be looking at, the list of opcodes displayed in each section. Successful opcode is not printed.
qeed wrote:
Yes thats the errors you should be looking at, the list of opcodes displayed in each section. Successful opcode is not printed.
That doesn't make any sense...there are so many opcodes printed that I couldn't possibly have a working emulator if that were the case.
Implied NOP is listed as failing...and about 20 other implied instructions (DEX, DEY, INX, INY)
I must be a complete idiot.
EDIT: I thought perhaps a failing opcode would have an asterisk next to it or something...but couldn't see anything like that in the output.
Perhaps we should let the test author explain it? I do not at all intend to suggest that his test is bunk...
NESICIDE wrote:
qeed wrote:
Yes thats the errors you should be looking at, the list of opcodes displayed in each section. Successful opcode is not printed.
That doesn't make any sense...there are so many opcodes printed that I couldn't possibly have a working emulator if that were the case.
Implied NOP is listed as failing...and about 20 other implied instructions (DEX, DEY, INX, INY)
I must be a complete idiot.
EDIT: I thought perhaps a failing opcode would have an asterisk next to it or something...but couldn't see anything like that in the output.
Perhaps we should let the test author explain it? I do not at all intend to suggest that his test is bunk...
I understand what you mean. My emulator seemed to be working almost completely with a couple of games and it passed all nestest.nes tests, but listed massive failures in Blargg's CPU test. I assumed at first that it was listing each opcode tested.
I figured out what the problem with mine was though. I was not setting status flags 5 and 6 properly for NMI/BRK/PHP. Since the status register is included in all of the checksums, a single incorrect bit can through all of the tests off. Once I fixed those according to a thread I found searching these boards, nearly all of my tests passed and only a few opcodes were listed.
blargg wrote:
I just tested and 9C and 9E are screwey. I need to take them off the test. Depending on X and Y they sometimes write to $700, among other things. Maybe someone else can figure them out properly.
Stumbled upon this thread after noticing that those fail in my emu ("9C SYA abs,X", "9E SXA abs,Y").
My guess is that the "AND addr_high + 1" behavior comes from always calculating addr_high + 1, regardless of whether its needed to correct the address. In that case, maybe the screwy behavior occurs when the value is actually used, i.e. when "addr + x" or "addr + y" crosses into a new page.
Maybe it affects AXA and TAS in addition to SYA and SXA in that case.
Implementing it like that does make the tests pass.
If we cross over into a new page, then the calculated
addr_high + 1 gets used, but for these opcodes
addr_high + 1 is corrupted (prolly due to the result being put on the same bus as
x/
y), and the target address for e.g. SYA becomes
((y & (addr_high + 1)) << 8) | addr_low instead of the normal
((addr_high + 1) << 8) | addr_low. If we don't wrap to a new page, then the corrupted value doesn't get used for the address, so nothing special happens.
I'm guessing it works like that for all the instructions where the value is influenced by
addr_high + 1, but confirmation would be nice.
blargg wrote:
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.zipThese 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.
The link is down. Could you reupload it, please?
Version 6.
Zepper wrote:
Version 6.
Thank you, man.