Failing ALL blargg's tests but passing nestest.nes

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Failing ALL blargg's tests but passing nestest.nes
by on (#88014)
Argh! Started adding the shell of a PPU and now none of blargg's tests pass at all. (See example below). This makes no sense to me at all, because I can pass nestest.nes with flying colors until the undocumented instructions - about 5260 instructions in.

I'm guessing that I'm fouling up one instruction slightly that is in the harness of blargg's tests that is causing it to fail the tests even when they would pass. I tried comparing a nintendulator log with my run, but the comparison gets all fouled up because the test is banging the PPU:

Code:
E947  2C 02 20  BIT $2002 = FF                  A:00 X:31 Y:15 P:24 SP:FB CYC:300 SL:240
E94A  30 06     BMI $E952                       A:00 X:31 Y:15 P:26 SP:FB CYC:312 SL:240
E94C  CA        DEX                             A:00 X:31 Y:15 P:26 SP:FB CYC:318 SL:240
E94D  D0 F8     BNE $E947                       A:00 X:30 Y:15 P:24 SP:FB CYC:324 SL:240
E947  2C 02 20  BIT $2002 = FF                  A:00 X:30 Y:15 P:24 SP:FB CYC:333 SL:240
E94A  30 06     BMI $E952                       A:00 X:30 Y:15 P:A6 SP:FB CYC:  4 SL:241


(There's something I don't understand in this snippet where nintendulator does NOT set the negative flag on P after doing a BIT on $FF and $00 but then DOES set the negative flag a few instructions later doing the exact same thing. Is nintendulator lying about the value returned from the PPU? ($2002)).

I tried debugging the instruction test by hand, but it seems impossible. Does anyone know what I might be getting wrong to trip up blargg's tests but not nestest.nes? Any suggestions for alternate debug paths? Is there a way to whip up a version of the tests that don't access the PPU at all, so I could compare with nintendulator?

Aside from all that, I can run Donkey Kong with my faux PPU at least far enough to watch it set the different registers, throw data at it for the name tables and image/sprite palettes, and ask for DMA transfers.

// Failed instruction test:
2A ROL A
0A ASL A
6A ROR A
4A LSR A
8A TXA
98 TYA
AA TAX
A8 TAY
E8 INX
C8 INY
CA DEX
88 DEY
38 SEC
18 CLC
F8 SED
D8 CLD
58 CLI
B8 CLV
EA NOP
1A NOP
3A NOP
5A NOP
7A NOP
DA NOP
FA NOP

01-implied

Failed

by on (#88016)
Nintendulator always reports registers as having a value of FF so you cannot trust what it reports in the trace logs. Typically passing nestest.nes yet failing all of blarggs CPU tests means one your CPU flags isn't working correctly, I would check to make sure you are handling status bits 2, 3, 4, and 5 correctly.

by on (#88017)
i had the EXACT same problem you are having. passed nestest easily, but failed blargg's in the exact same way. check your BIT opcode. how are you settings the flags in that one?

the highest two bits of the status flag should match the highest two bits of the instruction's operand before any calculations.

here's what mine looks like:

Code:
static void bit() {
    value = getvalue();
    result = (uint16_t)a & value;
   
    zerocalc(result);
    status = (status & 0x3F) | (uint8_t)(value & 0xC0);
}


zerocalc of course sets the zero flag based on the AND result of the accumulator and the operand.

anyway, i'm betting your problem is incorrectly handling those flags like it was for me. my bug was a typo on the last line. i had (status & 0xBF) instead of 0x3F so if the sign flag was currently set, it remained set even if it was not set in the source operand.

by on (#88018)
NickMass wrote:
Nintendulator always reports registers as having a value of FF so you cannot trust what it reports in the trace logs.

Ah, hadn't noticed that yet, for some reason. It'd be nice if they were ?? if they couldn't be reported.

Quote:
Typically passing nestest.nes yet failing all of blarggs CPU tests means one your CPU flags isn't working correctly, I would check to make sure you are handling status bits 2, 3, 4, and 5 correctly.


Great guess! I was setting IRQ_DISABLE in php. Now I pass all of the tests except for the stack instructions (which I seem to "fail" all of) and brk. No clue with those either. Is failure there still likely to be P flags or something else?

(Having tests is awesome! Not having any idea why they believe they are failing is less awesome. :().

48 PHA
08 PHP
68 PLA
28 PLP
9A TXS
BA TSX

10-stack

Failed

00 BRK

14-brk

Failed

by on (#88019)
well that's promising. sounds like you're close. so your BIT is okay?

by on (#88020)
Quote:
anyway, i'm betting your problem is incorrectly handling those flags like it was for me..

I think IRQ_DISABLE was mostly the culprit here, since I'm now passing the majority of the tests. I double-checked my bit anyway, and it looks fine. Thanks for the advice, though.

Now if only I could find the problem with the stack functions and I'd be 99%.

by on (#88021)
what does your code look like for the stack ops?

by on (#88022)
A common issue people have that can break stack ops is with bits 5 and 4, I would look at http://wiki.nesdev.com/w/index.php/CPU_ ... g_behavior and make sure what you are doing matches the table in the B Flag section on that page.

by on (#88023)
Code:
      case 0x48:
        // PHA
        mmu.write(S + 0x100, A);
        S--;
        cycle += 3;
      break;

      case 0x08:
        // PHP
        mmu.write(S + 0x100, P | BRK_BIT);
        S--;
        cycle += 3;
      break;

      case 0x68:
        // PLA
        S++;
        A = mmu.read(S + 0x100);
        updateNZFlags(A); // NB The regular docs didn't have this, but it was specified in
                          // http://nesdev.com/6502jsm.zip
        cycle += 4;
      break;

      case 0x28:
        // PLP
        S++;
        // NB When pulling into the processor flags register, we have to ensure that
        // bit 5 is always set (it's hardwired that way), and the BRK_BIT is always clear
        // (See http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt)
        P = mmu.read(S + 0x100) & ~BRK_BIT | ALWAYS_SET_BIT;
        cycle += 4;
      break;

      case 0x9A:
        // TXS
        S = X;
        // updateNZFlags(S); // 6052jsm.txt has this as effecting P flags, but that doesn't agree with logs
        cycle += 2;          // TODO Check and see if true for other ops in same class
      break;

      case 0xBA:
        // TSX
        X = S;
        updateNZFlags(X);
        cycle += 2;
      break;

by on (#88024)
NickMass wrote:
A common issue people have that can break stack ops is with bits 5 and 4, I would look at http://wiki.nesdev.com/w/index.php/CPU_ ... g_behavior and make sure what you are doing matches the table in the B Flag section on that page.

I think what I have meets the spirit of that, e.g. I think "ignoring bits 4 and 5" is equivalent to asserting them low and high respectively. Basing that on the discussion in 6502 'B' flag & BRK opcode

by on (#88025)
all of that matches with mine, so the issue must be elsewhere and i pass blargg's stack test rom. one thing though, the proper precedence is slipping my mind at the moment; does the & operator have higher precedence than |? i ask because of your "& ~BRK_BIT | ALWAYS_SET_BIT" in 0x28. i think that's okay, but if i'm wrong that might be doing the OR before the AND?

EDIT: i guess that doesn't matter either way, as ~ definitely has the highest precedence of those operators... nevermind me.

by on (#88028)
Well, I haven't sorted out the stack opcodes yet, but I did figure out what was going on with break. I was setting IRQ_DISABLE high in P BEFORE it was being stored onto the stack. I guess test was seeing something like an IRQ_DISABLE set high after an rti.