A little help with Blargg's nes_instr_test?

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

A little help with Blargg's nes_instr_test?

Post by jwdonal »

Okay, so now I've got all of the "official" opcodes working as far as I can tell from the Nestress and Kevtris' Nestest ROMs. I pass both of those 100% for official opcode and CPU tests. So now I've moved onto Blargg's nes_instr_test ROM. At the moment I am running the official-only test ROM. I get the following output:

Code: Select all

00 BRK
14-brk
Failed
While running test 14 of 15
I know that the readme says that the test is not supposed to tell you how to fix your CPU...but since I'm passing the other 2 test ROMs it seems strange that BRK would fail in this test ROM. Can anyone tell me what the BRK test actually "tests"? I looked at the source but it's hard for me to understand as I am not (yet) a very avid NES programmer and the assembler syntax is throwing me for a loop - especially with all the macros.

Are there CPU test ROMs that I should run before running this one? I'm not sure if there is a particular order in which I should be trying these ROMs. Haha.

Any input is appreciated.
pdq
Posts: 6
Joined: Fri Jun 25, 2010 6:15 am

Post by pdq »

Check that the PC pushed onto the stack is "PREV_PC+2", and that the P flags pushed onto the stack has the B bit set, but the actual P flags are not modified (B is still zero).

Also, ensure the RTI instruction overwrites the B flag to zero when P is popped from the stack.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

^^^ perfect example of the confusion the "B flag exists in status register" causes (pdq, nothing specific to you; this confusion is present in almost every 6502 book and web page).

As pdq said, BRK does the following:

1. Push address of BRK instruction + 2
2. PHP
3. SEI
4. JMP ($FFFE)
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

blargg wrote:^^^ perfect example of the confusion the "B flag exists in status register" causes (pdq, nothing specific to you; this confusion is present in almost every 6502 book and web page).

As pdq said, BRK does the following:

1. Push address of BRK instruction + 2
2. PHP
3. SEI
4. JMP ($FFFE)
Do you have verification of this claim on non-NES 6502 processors? You're going to have a hard time convincing me of that, mainly because this feature is used on the Apple II to detect the difference between a hardware and software IRQ.

If you want *me* to verify, I can bust out my IIGS and do exactly that. It's fairly easy to test for.
tepples
Posts: 22603
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

But then few peripherals on the 8-bit Apple II used /IRQ, mostly because so many things (such as disk access) needed cycle-timed code run with SEI.

Besides, I thought we determined last time that checking the stack to distinguish /IRQ from BRK takes too long.

EDIT: I've updated the wiki page to try to clarify this.
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Post by jwdonal »

thanks for the tips blargg, i will recheck my simulation

@Koitsu: I too was skeptical about the B flag not actually existing. However, in the research that I've done since then I'm pretty positive that Blargg et al. are correct about the B flag and it only being visible after it's been pushed to the stack during PHP/BRK instruction. Here are some resources I've found. All of which confirm the B flag not existing.

http://www.virtualdub.org/downloads/Alt ... Manual.pdf

http://nesdev.com/NinTech.txt

http://nesdev.com/the%20%27B%27%20flag% ... uction.txt

http://wiki.nesdev.com/w/index.php/CPU_ ... g_behavior

And it really is weird because the huge official NMOS 6502 hardware/software manuals that I have refer to it "like" it actually exists, but they never _actually_ explicitly state that it exists or not. Haha. Now that I've done a good bit of research and looking at how my only RTL is structured and what way would conserve the most physical resources it actually does make the most sense for the flag not to physically exist in the CPU.

Pz!
Last edited by jwdonal on Wed Jul 14, 2010 1:50 pm, edited 1 time in total.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

I just tried this on the Apple //c and got $38 in A:

Code: Select all

lda #$08
pha
plp
php
pla
PHP and BRK both always set bits 4 and 5 of the byte they push on the stack. NMI and IRQ both always clear bit 4 and set bit 5 of the byte they push on the stack. Thus, the status flags register only has 6 bits, not 8.

If you read the descriptions of the B flag, you'll see that based on most descriptions that say it exists, there's no way to actually read its contents, hence it doesn't actually exist. It's like the E bit hidden away in every 6502 processor, which enables a super 128-bit processing mode, but that can't ever be set by any instruction unfortunately.
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Post by jwdonal »

blargg wrote:It's like the E bit hidden away in every 6502 processor, which enables a super 128-bit processing mode, but that can't ever be set by any instruction unfortunately.
LOL, that's awesome.
lidnariq
Posts: 11320
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Post by lidnariq »

This line of thought led me to go and look at the 6502 reverse-engineered schematic someone made a year ago... found where "B" was and found that it was just a couple inverters triggered by the lines from BRK and PHP in the logic array, and the I flag.
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Post by jwdonal »

Ah, very cool. That settles it then.

Say, are these schematics available to dl somewhere? It would be really kewl to see how it was all originally implemented.

Pz
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

I'm still trying to find where on this schematic said logic is.
ReaperSMS
Posts: 174
Joined: Sun Sep 19, 2004 11:07 pm

Post by ReaperSMS »

Lower left center, labelled B flag, directly north of decode lines 116 and 115.

Inputs are lines 105 and 106 (PHP/BRK), and D1x1, which is a lovely mess of the B flag, RDY0, phi2, /IRQ, Bxx, and the general interrupt line.

That slew of lines is the data bus, usually pulled high and wired AND'd down I think.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

Why is everyone having trouble understanding what I'm saying? Frustrated koitsu commencing.

The wiki page states, in a highly convoluted way, what I've been saying and what pdq said. Somehow this got turned into a "guess what PHP does" discussion which isn't the point.

blargg's test above doesn't prove anything other than "what PHP and PLP do to bits 5 and 4". I really don't care what PHP/PLP does to bits 5 and 4, that isn't what we're discussing (but please see below). I also don't care about bit 5, because it's not applicable. Please, let's focus on bit 4.

Not once have I said that the P status register actually contains/uses bit 4. All I've been saying -- same as pdq, and as Brad Taylor -- is that when BRK is encountered, internally the CPU pushes the contents of P onto the stack *with bit 4 set*. A piece of code which is pointed to by the IRQ/BRK vector (at $FFFE-FFFF) can do the following to determine a hardware IRQ vs. software IRQ (BRK):

Code: Select all

irq_vector:
   PLA
   PHA
   AND #%00010000
   BNE IRQ_caused_by_BRK
All this code does is exactly that, followed by some code that gets the BRK signature byte and uses it as an offset into a jump table so different pieces of code can be called based upon what the signature byte is. I've never actually seen a program do this (though I did propose in a post a while back that it's highly possible -- case in point!), because the signature byte was usually used to indicate to the programmer (while debugging) "oh, it's this routine which called BRK".

History lesson: one of BRK's historic purposes is outlined in "Programming the 65816, Including the 6502, 65C02, and 65802" book by David Eyes and Ron Lichty on page 255. Quote:
The fact that the opcode for the BRK instruction is $00 is directly related to one of its uses: patching existing programs. Patching is the process of inserting instruction data in the middle of an existing program in memory to modify (usually to correct) the program without reassembling it. This is a favoured method of some programmers in debugging and testing assembly language programs, and is quite simple if you have a good machine-level monitor program that allows easy examination and modification of memory locations. However, if the program to be patched is stored in PROM (programmable read-only memory), the only way to modify a program that has already been "burned-in" is to change any remaining one bits to zeroes. Once a PROM bit has been "blown" to zero, it cannot be restored to a one. The only way to modify the flow of control is to insert BRK instructions -- all zeroes -- at the patch location and to have the BRK handling routing take control from there.
I will point out that the aforementioned book erroneously states on page 70 that the P register's bit 4 is "dedicated to determining software vs. hardware IRQ" -- as blargg has said, the P register actually doesn't use bits 5 and 4. Otherwise, everything I said above stands.

Finally, I don't know about pdq's claim that RTI clears bit 4 of the status registers popped off the stack by RTI itself. The documentation I have doesn't indicate that happens, but it might.
tepples
Posts: 22603
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

koitsu wrote:The wiki page states, in a highly convoluted way, what I've been saying and what pdq said.
I tried to make it less convoluted this time; could you go in and fix it further?
A piece of code which is pointed to by the IRQ/BRK vector (at $FFFE-FFFF) can do the following to determine a hardware IRQ vs. software IRQ (BRK):

Code: Select all

irq_vector:
   PLA
   PHA
   AND #%00010000
   BNE IRQ_caused_by_BRK
This illustrates the point, but don't try it in production code. The old contents of A have been destroyed, and if the IRQ wasn't caused by BRK, the main program won't expect this.
one of BRK's historic purposes is outlined in "Programming the 65816, Including the 6502, 65C02, and 65802" book by David Eyes and Ron Lichty on page 255. Quote:
That was interesting. Thanks.
Finally, I don't know about pdq's claim that RTI clears bit 4 of the status registers popped off the stack by RTI itself. The documentation I have doesn't indicate that happens, but it might.
As I understand it, RTI and PLP don't "clear" bit 4, that is, they don't write back to the stack. They just ignore it.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

koitsu, no disagreement with what you wrote. The byte on the stack that holds the status flags also holds a flag indicating whether it was a BRK or IRQ. I suppose it is a "B flag", but it's not a flag like any of the other status flags are (not saying you said it was, just noting this in how it's often discussed, for example shown in the processor flags graphic along with all the main registers).

tepples, throw an STA in there and it works:

Code: Select all

irq_vector:
    sta saved_a
    pla
    pha
    and #%00010000
    bne was_brk
    ...
Post Reply