Status flags

From NESdev Wiki
Revision as of 20:17, 24 October 2018 by Rainwarrior (talk | contribs) (Merging from CPU status flag behaviour)
Jump to navigationJump to search

The flags register, also called processor status or just P, is one of the six architectural registers on the 6502 family CPU. It is composed of six one-bit registers (see Status flags); instructions modify one or more bits and leave others unchanged.

Instructions that save or restore the flags map them to bits in the architectural 'P' register as follows:

7  bit  0
---- ----
NVss DIZC
|||| ||||
|||| |||+- Carry: 1 if last addition or shift resulted in a carry, or if
|||| |||     last subtraction resulted in no borrow
|||| ||+-- Zero: 1 if last operation resulted in a 0 value
|||| |+--- Interrupt: Interrupt inhibit
|||| |       (0: /IRQ and /NMI get through; 1: only /NMI gets through)
|||| +---- Decimal: 1 to make ADC and SBC use binary-coded decimal arithmetic
||||         (ignored on second-source 6502 like that in the NES)
||++------ s: No effect, used by the stack copy, see note below
|+-------- Overflow: 1 if last ADC or SBC resulted in signed overflow,
|            or D6 from last BIT
+--------- Negative: Set to bit 7 of the last operation

The B flag

There are six and only six flags in the processor status register within the CPU. Despite what some 6502 references might appear to claim on a first reading, there is no "B flag" stored within the CPU's status register.

Two interrupts (/IRQ and /NMI) and two instructions (PHP and BRK) push the flags to the stack. In the byte pushed, bit 5 is always set to 1, and bit 4 is 1 if from an instruction (PHP or BRK) or 0 if from an interrupt line being pulled low (/IRQ or /NMI). This is the only time and place where the B flag actually exists: not in the status register itself, but in bit 4 of the copy that is written to the stack.

Instruction Bits 5 and 4 Side effects after pushing
PHP 11 None
BRK 11 I is set to 1
/IRQ 10 I is set to 1
/NMI 10 I is set to 1

Two instructions (PLP and RTI) pull a byte from the stack and set all the flags. They ignore bits 5 and 4.

The only way for an IRQ handler to distinguish /IRQ from BRK is to read the flags byte from the stack and test bit 4. The slowness of this is one reason why BRK wasn't used as a syscall mechanism. Instead, it was more often used to trigger a patching mechanism that hung off the /IRQ vector: a single byte in PROM, UVEPROM, flash, etc. would be forced to 0, and the IRQ handler would pick something to do instead based on the program counter.

Unlike bits 5 and 4, bit 3 actually exists in P, even though it doesn't affect the ALU operation on the 2A03 or 2A07 CPU the way it does in MOS Technology's own chips.

External links

Old Article

(A merge is in process combining these two articles.)


The 6502 has 6 status flags: carry, decimal mode, interrupt disable, negative, overflow, and zero. Each of these can either be set or clear. The processor stores the current state of each at all times. There are 2^6 = 64 total states these flags can be in.

During certain events, a copy of the flags is written to a byte in memory. There are 8 bits in a byte, and when writing to memory, all 8 bits must be written. Since there are only 6 status flags, the unused 2 bits must be given values.

There are four events that cause the flags to be written to memory: NMI and IRQ vectoring, and the BRK and PHP instructions. Rather than set the unused bits in the copy in memory to the same values in all cases, the 6502 sets one of them based on whether the event was interrupt vectoring or an executed instruction.

The flags are copied to memory in this arrangement:

Bit 7: Negative
Bit 6: Overflow
Bit 5: Always set
Bit 4: Clear if interrupt vectoring, set if BRK or PHP
Bit 3: Decimal mode (exists for compatibility, does not function on the Famicom/NES's 2A03/2A07)
Bit 2: Interrupt disable
Bit 1: Zero
Bit 0: Carry

Note bits 4 and 5. This means that the following will put $30 into A, not 0:

LDA #$00
PHA      ; pushes $00 on stack
PLP      ; clears all 6 status flags
PHP      ; pushes $30 on stack
PLA      ; pops the $30 off the stack

Since bit 4 is set if the cause was a BRK instruction, and clear if it was an IRQ, this allows code to determine the cause of its IRQ handler being invoked, since BRK and IRQ both use the vector at $FFFE:

irq:
        STA temp
        PLA        ; get saved flags off stack
        PHA        ; save again
        AND #$10   ; check bit 4
        BNE caused_by_brk
caused_by_irq:
        ...
caused_by_brk:
        ....

The above is the only way to determine the cause of the irq handler invocation. One might think that the following would work, if one thought that there was a status flag that told when it was a BRK instruction that invoked the IRQ handler:

; wrong way to determine cause of IRQ handler invocation
irq:
        STA temp
        PHP        ; save current flags
        PLA        ; get saved flags off stack
        AND #$10   ; check bit 4
        BNE caused_by_brk
caused_by_irq:
        ...
caused_by_brk:
        ....

This fails because there are only 6 status flags, none of which tell the reason the IRQ handler was invoked. This misunderstanding exists because many descriptions of the 6502 incorrectly state that the processor has 7 status flags, the 7th one being the break flag.

There is no break flag; there are only 6 status flags. As covered above, there are 8 bits in a byte, so when saving a copy of the status flags in memory, these unused two bits must be set to something. On the 6502, bit 5 of the copy is always set, and bit 4 is set BRK or PHP, clear if an interrupt. When restoring the flags from memory, bits 4 and 5 are ignored, since again, there are only 6 status flags, and thus the extra 2 bits of the byte must be ignored.

See also