197. Instruction php
implement PHP behavior.
Lesson 197 of 356 · tests/chapter_01_cpu/test_197_instruction_php.py
In this step, change only `emulator/cpu/instructions.py by adding php(cpu). Prerequisite: FlagsHandler.set_break_flag` already exists.
Why this step exists
PHP pushes P with the emulator's Break marker set, then clears that transient marker from live CPU state. As with every push, it writes to $0100 | S before decrementing the 8-bit S.
Suggested implementation
def php(cpu: CPU):
cpu.flags.set_break_flag(True)
cpu.flags.set_one_flag(True)
cpu.bus.write(STACK_BASE | cpu.s, cpu.p)
cpu.flags.set_break_flag(False)
cpu.flags.set_one_flag(False)
cpu.s = (cpu.s - 1) & 0xFFInvariants: preserve every pre-existing status bit; set Break and ONE in the stacked copy; clear both from live P afterward; write before decrementing and wrap S; do not derive Z or N from the status byte.
Misconception: Break is not left enabled in `cpu.p` after PHP merely because it is set in the byte written to the stack.
Out of scope: opcode $08 registration belongs to step 198. Any later changes to the pushed status-byte rules belong to their own numbered steps.
Run this lesson
uv run pytest tests/chapter_01_cpu/test_197_instruction_php.py -v