From cfdc3230d0f9d4ea1da75f6dd8e8d97802a0ea9d Mon Sep 17 00:00:00 2001 From: sql-hkr Date: Sun, 26 Oct 2025 00:48:53 +0900 Subject: [PATCH] Add BRMI and BRPL instructions (#12) Implemented op_brmi and op_brpl methods in CPU to support branching on the negative flag. Added corresponding unit tests in test_control_flow.py to verify correct behavior. Also refactored some test cases to use r2 instead of r3 for consistency. --- src/tiny8/cpu.py | 26 ++++++++++++++++++- tests/test_control_flow.py | 52 ++++++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/tiny8/cpu.py b/src/tiny8/cpu.py index 5d8b6cb..f4437e1 100644 --- a/src/tiny8/cpu.py +++ b/src/tiny8/cpu.py @@ -52,7 +52,7 @@ class CPU: def __init__(self, memory: Optional[Memory] = None): self.mem = memory or Memory() # 32 general purpose 8-bit registers R0-R31 - self.regs: [int] = [0] * 32 + self.regs: list[int] = [0] * 32 # Program Counter (word-addressable for AVR) - we use byte addressing for simplicity self.pc: int = 0 # Stack Pointer - point into RAM @@ -927,6 +927,30 @@ def op_brlt(self, label: str | int): if s: self.op_jmp(label) + def op_brmi(self, label: str | int): + """BRMI - Branch if Minus (Negative flag set). + + Branches when the N flag is set (negative result). + + Args: + label: Destination label or address to jump to if the condition is met. + """ + n = self.get_flag(SREG_N) + if n: + self.op_jmp(label) + + def op_brpl(self, label: str | int): + """BRPL - Branch if Plus (Negative flag clear). + + Branches when the N flag is clear (non-negative result). + + Args: + label: Destination label or address to jump to if the condition is met. + """ + n = self.get_flag(SREG_N) + if not n: + self.op_jmp(label) + def op_push(self, rr: int): """Push a register value onto the stack. diff --git a/tests/test_control_flow.py b/tests/test_control_flow.py index c351250..0af5d67 100644 --- a/tests/test_control_flow.py +++ b/tests/test_control_flow.py @@ -106,16 +106,16 @@ def test_brlt(self): ldi r1, $01 ; 1 cp r0, r1 brlt less - ldi r3, $01 + ldi r2, $01 jmp done less: - ldi r3, $02 + ldi r2, $02 done: nop """ cpu = self.run_asm(src) - # -1 < 1 so branch taken -> r3 == 2 - self.assertEqual(cpu.read_reg(3), 0x02) + # -1 < 1 so branch taken -> r2 == 2 + self.assertEqual(cpu.read_reg(2), 0x02) def test_brge(self): # BRGE: branch when signed (Rd >= Rr). Use 1 >= -1 @@ -124,13 +124,49 @@ def test_brge(self): ldi r1, $FF ; -1 cp r0, r1 brge ge - ldi r3, $01 + ldi r2, $01 jmp done ge: - ldi r3, $02 + ldi r2, $02 + done: + nop + """ + cpu2 = self.run_asm(src2) + # 1 >= -1 so branch taken -> r2 == 2 + self.assertEqual(cpu2.read_reg(2), 0x02) + + def test_brmi(self): + # BRMI: branch when negative (N == 1) + src = """ + ldi r0, $FF ; -1 + ldi r1, $00 ; 0 + cp r0, r1 + brmi neg + ldi r2, $01 + jmp done + neg: + ldi r2, $02 done: nop """ + cpu = self.run_asm(src) + # -1 < 0 so negative -> branch taken -> r2 == 2 + self.assertEqual(cpu.read_reg(2), 0x02) + + def test_brpl(self): + # BRPL: branch when plus (N == 0) + src2 = """ + ldi r0, $02 ; 2 + ldi r1, $FF ; -1 + cp r0, r1 + brpl plus + ldi r2, $01 + jmp done2 + plus: + ldi r2, $02 + done2: + nop + """ cpu2 = self.run_asm(src2) - # 1 >= -1 so branch taken -> r3 == 2 - self.assertEqual(cpu2.read_reg(3), 0x02) + # 2 >= -1 so non-negative -> branch taken -> r2 == 2 + self.assertEqual(cpu2.read_reg(2), 0x02)