Describe the Function of the Program Status Word in Assembly Language

Describe the function of the program status word in Assembly language

Somewhere behind every jz, jnz, bcc, or beq instruction you’ve ever written, there’s a small, unglamorous register quietly doing the real work: the Program Status Word (PSW). It doesn’t hold your data, and it doesn’t hold an address. It holds the state of the CPU itself — the flags, the mode, the interrupt-enable bits. I used to skim right past it in reference manuals, until I hit a bug that only made sense once I understood exactly what the PSW was tracking. This post is the explanation I wish I’d read first.

What Exactly Is a Program Status Word?

The Program Status Word (sometimes called the flags register, status register, or on ARM, the Current Program Status Register — CPSR/xPSR) is a special-purpose register that packs together multiple single-bit and multi-bit fields describing the current state of the processor. It’s not one “thing” so much as a bitfield of many small things:

Different architectures name and organize this differently, but the underlying purpose is identical everywhere: give the CPU (and the programmer) a compact snapshot of “what just happened” and “what mode am I in” at any instant.

The x86/x86-64 View: EFLAGS/RFLAGS

On x86, the Program Status Word is the FLAGS register (16-bit), extended to EFLAGS (32-bit) and RFLAGS (64-bit). Key bits include:

FlagBitMeaning
CF (Carry)0Set on unsigned overflow/borrow
PF (Parity)2Set if low byte of result has even parity
ZF (Zero)6Set if result is zero
SF (Sign)7Set if result is negative (MSB = 1)
TF (Trap)8Enables single-step debugging
IF (Interrupt Enable)9Enables maskable hardware interrupts
DF (Direction)10Controls direction of string instructions
OF (Overflow)11Set on signed overflow

Example: Flags in Action

mov     eax, 5
sub     eax, 5          ; result is 0
jz      is_zero          ; jumps because ZF was set by SUB

mov     eax, 0x7FFFFFFF
add     eax, 1           ; signed overflow — OF gets set
jo      overflow_detected

Every conditional jump (JZ, JNZ, JC, JO, JL, JG, and dozens more) is really just a test of one or more bits in EFLAGS/RFLAGS. That’s the entire mechanism behind conditional control flow in x86 assembly.

Reading and Writing EFLAGS Directly

pushfq                  ; push RFLAGS onto the stack
pop     rax             ; RAX now holds the flags
or      rax, 0x40       ; manually set ZF bit (illustrative)
push    rax
popfq                   ; RFLAGS updated from stack

The ARM View: CPSR / APSR / xPSR

ARM splits this concept slightly differently depending on the profile:

FlagMeaning
NNegative result
ZZero result
CCarry/borrow occurred
VSigned overflow occurred
QSaturation occurred (DSP-oriented)
I / FIRQ / FIQ mask bits
TThumb execution state
Mode bitsCurrent privilege/execution mode

ARM Assembly Example

CMP     R0, R1          ; compare, updates N, Z, C, V in APSR
BEQ     equal_case       ; branch if Z is set

MRS     R2, APSR         ; read APSR into R2
MSR     APSR_nzcvq, R2   ; write flag bits back from R2

ARM’s conditional execution goes further than most architectures — many ARM instructions themselves can be conditionally executed based on PSW flags (e.g., ADDEQ, MOVNE), not just branches, which is a distinctive feature worth knowing if you’re comparing architectures.

Internal Working Process

sequenceDiagram
    participant ALU as ALU/Execute Stage
    participant PSW as Program Status Word
    participant CU as Control Unit

    ALU->>PSW: Write result flags (Z, C, N, V...)
    CU->>PSW: Read flags for conditional branch/instr
    PSW-->>CU: Flag values
    CU->>CU: Decide branch taken / instruction executes
    Note over PSW: PSW also holds mode & interrupt-enable bits,<br/>checked continuously by hardware

Why the PSW Matters Beyond Just Branching

  1. Context switching — when an OS switches between processes or threads, it must save and restore the PSW along with the general-purpose registers and program counter. Get this wrong, and a resumed process could behave as though a previous comparison or interrupt state still applied.
  2. Exception/interrupt handling — entering an ISR typically pushes the current PSW onto the stack automatically (x86’s INT/hardware interrupt entry does this; ARM pushes xPSR as part of exception entry), so the interrupted context can be perfectly restored afterward.
  3. Privilege enforcement — the mode bits inside the PSW (ARM’s mode field, x86’s CPL derived from segment selectors plus system flags) determine what the currently executing code is allowed to do, which is foundational to OS/user separation.
  4. String and loop instruction behavior — on x86, the Direction Flag (DF) in EFLAGS controls whether MOVS, CMPS, SCAS, etc., process memory forward or backward.

Comparison Table: PSW Across Architectures

Aspectx86/x86-64 (EFLAGS/RFLAGS)ARM (CPSR/xPSR)
Register nameEFLAGS / RFLAGSCPSR (A/R profile), xPSR (M profile)
Condition flagsCF, ZF, SF, OF, PF, AFN, Z, C, V (+ Q)
Interrupt controlIF flagI, F mask bits
Mode/privilege infoDerived from segment/CPL, separate from EFLAGSEncoded directly in CPSR mode field
Conditional execution scopeBranches onlyBranches + many data-processing instructions
Direct read/writePUSHF/POPF, LAHF/SAHFMRS/MSR

Advantage of x86’s approach: a single, well-known flat flags register that’s simple to save/restore. Advantage of ARM’s approach: built-in conditional execution of ordinary instructions reduces branch count, which — as covered in pipeline discussions — reduces misprediction risk.

Practical Use Cases

Debugging and Optimization Considerations

Best Practices

  1. Always check an instruction’s documented “flags affected” list before relying on it for a subsequent conditional operation.
  2. When writing interrupt handlers or context-switch code, never assume the PSW is preserved automatically unless the architecture explicitly documents that it pushes/restores it.
  3. Use PUSHF/POPF (x86) or MRS/MSR (ARM) sparingly and deliberately — manual flag manipulation is powerful but easy to misuse.
  4. When comparing signed vs. unsigned values, make sure you’re branching on the correct flag combination (JG/JL vs JA/JB on x86 test entirely different flag sets).

FAQs

Is the Program Status Word the same as the “flags register”? Functionally, yes, in most literature — “PSW” is the more general/textbook term, while specific architectures use their own names (EFLAGS, CPSR, xPSR).

Can user-mode code freely modify the entire PSW? No — mode/privilege bits and interrupt-enable bits are typically protected and can only be modified by privileged (kernel-mode) code, even though condition flags are freely modifiable by any code.

Why do signed and unsigned comparisons use different flags? Because “greater than” means something different depending on interpretation — unsigned comparisons rely on the Carry flag, signed comparisons rely on the relationship between the Sign and Overflow flags.

What happens to the PSW during a context switch? The OS scheduler saves the outgoing thread’s PSW (usually as part of its saved register/context block) and restores the incoming thread’s PSW, so each thread sees its own consistent flag/mode state.

Summary and Key Takeaways

The Program Status Word is the CPU’s compact record of “what just happened” and “what mode am I in” — condition flags from the last operation, control bits like interrupt-enable and direction, and privilege/mode information. Every conditional branch, every context switch, and every interrupt entry/exit depends on it being tracked and preserved correctly.

Key takeaways:

References

Exit mobile version