What is the Processor Status, and why is it important?
Moderator: Moderators
What is the Processor Status, and why is it important?
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?
Re: What is the Processor Status, and why is it important?
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.
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
Re: What is the Processor Status, and why is it important?
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.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?
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.And moreso, what is the processor status used for?
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.
- 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?
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.
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.
Re: What is the Processor Status, and why is it important?
At the beginning.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.
i.e in Metroid:
Code: Select all
NMI:
php
pha
txa
pha
tya
pha
;NMI stuff
pla
tay
pla
tax
pla
plp
rti
Ah, so that's where those are storedMostly 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.
Re: What is the Processor Status, and why is it important?
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.
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
-
- Posts: 592
- Joined: Thu Aug 28, 2008 1:17 am
- Contact:
Re: What is the Processor Status, and why is it important?
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.Sogona wrote: Seems interesting they were able to make a game that complex without knowing that was redundant.
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".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).
__________________________
http://pcedev.wordpress.com
http://pcedev.wordpress.com
Re: What is the Processor Status, and why is it important?
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.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".
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
- 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?
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.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.
Re: What is the Processor Status, and why is it important?
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.
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.
Re: What is the Processor Status, and why is it important?
Ah, you're right. Limit it only to SEI and CLI. I edited my first post above.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.
http://WilsonMinesCo.com/ lots of 6502 resources
Re: What is the Processor Status, and why is it important?
I agree with most of this. Case in point: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).
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.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:You will find code like this in commercial games quite often.Code: Select all
LDA #$00 STA $2006 STA $2006
But one thing in the rest of your comment stuck at me:
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.koitsu wrote:...and let's also not forget Metroid was a first-generation NES game.
Re: What is the Processor Status, and why is it important?
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.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.