What is the Processor Status, and why is it important?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Sogona
Posts: 186
Joined: Thu Jul 23, 2015 7:54 pm
Location: USA
Contact:

What is the Processor Status, and why is it important?

Post by Sogona »

I've been looking at the source code of a couple games and noticed that a few of them push and pull the processor status onto and from the stack during NMI. Why exactly is this done? What's the reason for some games doing this while others not? And moreso, what is the processor status used for?
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: What is the Processor Status, and why is it important?

Post by thefox »

It's never required to manually push/pull it in interrupt handlers, because the processor automatically pushes (and pulls) it from the stack on interrupt entry/exit. Presumably some developers didn't know this and wanted to be safe.

Processor status contains various flags indicating the state of the processor, which can get mangled within the interrupt, so it's important to save and restore it.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: What is the Processor Status, and why is it important?

Post by tokumaru »

Sogona wrote:I've been looking at the source code of a couple games and noticed that a few of them push and pull the processor status onto and from the stack during NMI. Why exactly is this done? What's the reason for some games doing this while others not?
Was that at the beginning and the end of the NMI or in the middle of some calculation performed within the NMI? It's perfectly normal to temporarily save the status flags during calculations if you want to delay a decision for whatever reason, but like thefox said, backing up and restoring the status register manually on interrupts is not necessary because the CPU does that automatically.
And moreso, what is the processor status used for?
Mostly for storing flags related to the result of operations performed by the CPU. Whenever the result of an operation is 0, there's one flag that indicates that. When the result is negative, another flag indicates that. There also the carry flag (used for adding, subtracting and shifting), the overflow flag (indicates signed oveflows/underflows after additions/subtractions), and the decimal mode flag, that tells a normal 6502 to do BCD math instead of binary, but has no effect on the NES CPU. Unrelated to mathematical operations, there's the interrupt flag, which is used to enable/disable interrupts, and the B flag, which indicates when the BRK instruction is used.

All decisions that affect the program flow (branches) are based on these status flags. The CPU has instructions that check these flags and branch program execution or not based on their values.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: What is the Processor Status, and why is it important?

Post by rainwarrior »

I find php and plp useful when I want to do some common things before taking a branch, rather than duplicating that code in each branch. Like, do the test (lda or cmp or whatever), php to save the result, then do some other stuff, then plp when I want to take the branch later.

As for doing it at the start/end of the NMI or IRQ, there's really no point. That's probably just lack of understanding (it doesn't help, but doesn't really hurt either). On the SNES, though, there's a lot more need to push/pull status because of the 8 vs 16 bit modes.
User avatar
Sogona
Posts: 186
Joined: Thu Jul 23, 2015 7:54 pm
Location: USA
Contact:

Re: What is the Processor Status, and why is it important?

Post by Sogona »

tokumaru wrote: Was that at the beginning and the end of the NMI or in the middle of some calculation performed within the NMI? It's perfectly normal to temporarily save the status flags during calculations if you want to delay a decision for whatever reason, but like thefox said, backing up and restoring the status register manually on interrupts is not necessary because the CPU does that automatically.
At the beginning.
i.e in Metroid:

Code: Select all

NMI:
  php
  pha
  txa
  pha
  tya
  pha

  ;NMI stuff

  pla
  tay
  pla
  tax
  pla
  plp
  rti
Seems interesting they were able to make a game that complex without knowing that was redundant.
Mostly for storing flags related to the result of operations performed by the CPU. Whenever the result of an operation is 0, there's one flag that indicates that. When the result is negative, another flag indicates that. There also the carry flag (used for adding, subtracting and shifting), the overflow flag (indicates signed oveflows/underflows after additions/subtractions), and the decimal mode flag, that tells a normal 6502 to do BCD math instead of binary, but has no effect on the NES CPU. Unrelated to mathematical operations, there's the interrupt flag, which is used to enable/disable interrupts, and the B flag, which indicates when the BRK instruction is used.

All decisions that affect the program flow (branches) are based on these status flags. The CPU has instructions that check these flags and branch program execution or not based on their values.
Ah, so that's where those are stored
Garth
Posts: 246
Joined: Wed Nov 30, 2016 4:45 pm
Location: Southern California
Contact:

Re: What is the Processor Status, and why is it important?

Post by Garth »

Since the interrupt sequence pushes the processor status register, and that will normally include the I interrupt-disable bit clear, do not bracket the ISR with PHP and PLP (nor SEI and CLI). Why? Because these will then have the effect of re-enabling interrupts before the RTI; and if another interrupt happens to already be pending, you'll go into the ISR again without exiting the first instance of it. In an extreme case of this happening over and over, you'll overflow the stack and crash, whereas otherwise, there will be no crash (even if it's a long time before the processor gets back to the background program).

Edit: rainwarrior correctly pointed out below that PHP and PLP won't cause the problem. I apologize for wasting anyone's time. The problem is only with SEI and CLI. I need to slow down and think through the details more before posting. Thinking has been difficult recently with the problem with the neighbor's dog. I can't sleep, can't work (I work in my office at home), can't concentrate, am always tired.
Last edited by Garth on Tue Dec 20, 2016 2:38 pm, edited 3 times in total.
http://WilsonMinesCo.com/ lots of 6502 resources
tomaitheous
Posts: 592
Joined: Thu Aug 28, 2008 1:17 am
Contact:

Re: What is the Processor Status, and why is it important?

Post by tomaitheous »

Sogona wrote: Seems interesting they were able to make a game that complex without knowing that was redundant.
Yeah? You'd be surprised as what some devs do. I would probably chalk this up to a macro that was miss-used in the code. Or maybe they knew about it, bit didn't bother to change it (not write a new macro) because it didn't have any negative effect.
Since the interrupt sequence pushes the processor status register, and that will normally include the I interrupt-disable bit clear, do not bracket the ISR with PHP and PLP (nor SEI and CLI). Why? Because these will then have the effect of re-enabling interrupts before the RTI; and if another interrupt happens to already be pending, you'll go into the ISR again without exiting the first instance of it. In an extreme case of this happening over and over, you'll overflow the stack and crash, whereas otherwise, there will be no crash (even if it's a long time before the processor gets back to the background program).
I re-able interrupts in the HuC6280 inside of interrupt routines. I just set flags to indicate that what level of interrupt is already processing (in which case if another of the same level call happens, it just bails out each time until the flag is clear). It's the only way I can juggle three interrupt services at a time, with some interrupt routines having more critical timing concerns than others. I also use this for time-slicing or running background "processing threads".
__________________________
http://pcedev.wordpress.com
Garth
Posts: 246
Joined: Wed Nov 30, 2016 4:45 pm
Location: Southern California
Contact:

Re: What is the Processor Status, and why is it important?

Post by Garth »

tomaitheous wrote: I re-able interrupts in the HuC6280 inside of interrupt routines. I just set flags to indicate that what level of interrupt is already processing (in which case if another of the same level call happens, it just bails out each time until the flag is clear). It's the only way I can juggle three interrupt services at a time, with some interrupt routines having more critical timing concerns than others. I also use this for time-slicing or running background "processing threads".
Agreed. It is indeed appropriate sometimes to re-enable interrupts during an ISR, so something of high priority that's quick to service can cut in on the longer servicing of a lower-priority interrupt. Still, if the interrupt-disable flag is set, it should not be cleared right before the RTI. That's not the place to do it.

I have even gone the opposite direction in my system of servicing interrupts in high-level Forth with zero overhead, having the 7-instruction ISR set the I flag in the stacked status so even RTI won't re-enable interrupts. The next time NEXT runs, it re-routes to the Forth ISR, faster than the normal operation of NEXT. The Forth ISR ends with SYSRTI which is like unnest but with a CLI instruction.
http://WilsonMinesCo.com/ lots of 6502 resources
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: What is the Processor Status, and why is it important?

Post by rainwarrior »

Garth wrote:Still, if the interrupt-disable flag is set, it should not be cleared right before the RTI. That's not the place to do it.
A PHP / PLP bookending an IRQ routine won't clear the flag, though. The IRQ itself will set I, so such a PLP can only set the flag, not clear it.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: What is the Processor Status, and why is it important?

Post by koitsu »

I think a more likely explanation (vs. theories about macro usage) is that the programmers weren't fully familiar with the intricacies, or it was effectively "learned behaviour" (think: habit). Occam's razor applies. I'll try to explain my view of it more verbosely:

I've several 65xx books and most of them do not go over clearly/concisely, in a programmer-friendly fashion, the "behaviour" of interrupts as far as P (status register) goes. The Lichty/Eyes book has an entire chapter dedicated to interrupts, but doesn't explain this unless you really dig (it's deep within a long paragraph, and not clearly demonstrated, thus very easily overlooked), nor do any of the other 65xx books I own (many of which were published during the CPUs heyday) denote this aspect in a way. The only one I have which does is "6502 Assembly Language Programming" from Lance A. Leventhal, circa 1979, and is clear about it -- but it's smack dab mid-chapter (the interrupts chapter is 40 pages long), covered in a couple lines. In contrast, the book "Programming the 6502" from Rodnay Zaks (circa 1983) doesn't really go over this either, at least not clearly/concisely. I can provide quotes from all these books on the subject if asked, but that borders on obsessive-compulsive. (And yes, I DID actually pull said books from my library and review them)

In other words, bare minimum it's something easily overlooked/forgotten, bordering almost on "tribal knowledge" in a sense (cut me some slack).

Now add the following into the mix: Nintendo up to that point, to my knowledge, had little-to-no experience with the 6502 CPU. Here's a reference for that. They went looking at arcade systems when they chose to go with the 6502.

...then consider what the state of 6502 documentation in Japanese may have been at that time.

...and let's also not forget Metroid was a first-generation NES game.

There's a lot of things in NES games in general that induce "what the heck?" reactions when code reviewed. I'm sure if you were to review some of my code from my youth you'd find similar mistakes or oddities.
Garth
Posts: 246
Joined: Wed Nov 30, 2016 4:45 pm
Location: Southern California
Contact:

Re: What is the Processor Status, and why is it important?

Post by Garth »

rainwarrior wrote:A PHP / PLP bookending an IRQ routine won't clear the flag, though. The IRQ itself will set I, so such a PLP can only set the flag, not clear it.
Ah, you're right. Limit it only to SEI and CLI. I edited my first post above.
http://WilsonMinesCo.com/ lots of 6502 resources
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: What is the Processor Status, and why is it important?

Post by tepples »

koitsu wrote:I think a more likely explanation (vs. theories about macro usage) is that the programmers weren't fully familiar with the intricacies, or it was effectively "learned behaviour" (think: habit).
I agree with most of this. Case in point:
Over a decade and a half ago, in nestech.txt 2.00, koitsu exhibited such an 'oddity' when he wrote:Be sure to clear the internal VRAM address via $2006 semi-often. You will often encounter a situation where a palette fade or a VRAM update will cause the screen "to be trashed" (squares on the screen, or what seem to be graphical "glitches"). The reason for this is that your code took longer than a VBlank. When the VBlank goes to refresh the screen with the data in the PPU, it takes whatever value is in the internal VRAM address and uses that as the starting base for Name Table #0. The solution is to fix your code by re-assigning the VRAM address to $0000 (or $2000), so that the refresh may occur successfully. Such code would be:

Code: Select all

      LDA #$00
      STA $2006
      STA $2006
You will find code like this in commercial games quite often.
And we did indeed find misguided code like this in commercial games such as Super Mario Bros. But as knowledge of the machine's behavior increased, first among the commercial dev community and then among homebrewers, so did efficiency of the software. It was realized that two writes to $2005 (scroll position) and one to $2000 (NMI, pattern table address, sprite size, and scroll position high bits) before the pre-render line's hblank were necessary and sufficient to fully "clear" the VRAM address in games not using raster effects.

But one thing in the rest of your comment stuck at me:
koitsu wrote:...and let's also not forget Metroid was a first-generation NES game.
I thought the progression was NROM-128 and equivalents, NROM-256 (led by Xevious and Super Mario Bros.), and then FDS and CNROM-class mappers at roughly the same time. So it'd be from the third generation.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: What is the Processor Status, and why is it important?

Post by koitsu »

tepples wrote:I thought the progression was NROM-128 and equivalents, NROM-256 (led by Xevious and Super Mario Bros.), and then FDS and CNROM-class mappers at roughly the same time. So it'd be from the third generation.
You're probably right in this case (re: it not being a first-gen title), but ultimately it amounts to defining what "generation" means, as it's an eye-of-the-beholder thing. This subject is off-topic so I won't reply here, but I have an explanation saved to a .txt file anyway.
Post Reply