Skip to content

Commit 6cb9c1b

Browse files
authored
Merge pull request #11 from sql-hkr/feat/implement-brge-brlt
Add BRGE and BRLT branch instructions (#10)
2 parents e6d697b + 3d5418c commit 6cb9c1b

3 files changed

Lines changed: 72 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ Below is a concise, categorized summary of the Tiny8 instruction set (mnemonics
221221
- JMP label / RJMP offset — unconditional jump
222222
- CALL label / RCALL offset — call subroutine (push return address)
223223
- RET / RETI — return from subroutine / return from interrupt (sets I)
224-
- BRNE / BREQ / BRCS / BRCC — conditional branches based on flags
224+
- BRNE / BREQ / BRCS / BRCC / BRGE / BRLT — conditional branches based on flags
225225
- CP Rd, Rr / CPI Rd, K — compare (sets flags)
226226
- CPSE Rd, Rr — compare and skip if equal
227227

src/tiny8/cpu.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,19 @@ def op_out(self, port: int, rr: int):
549549
val = self.read_reg(rr)
550550
self.write_ram(port, val)
551551

552-
def op_jmp(self, label: str):
552+
def op_jmp(self, label: str | int):
553+
"""Jump to a given label or numeric address by updating the program counter.
554+
555+
This operation sets the CPU's program counter (self.pc) to the target address minus one.
556+
The subtraction of one accounts for the fact that the instruction dispatcher will typically
557+
increment the program counter after the current instruction completes.
558+
559+
Args:
560+
label (str | int): The jump target. If a string, it is treated as a symbolic label
561+
and looked up in self.labels to obtain its numeric address. If an int (or any
562+
value convertible to int), it is used directly as the numeric address.
563+
"""
564+
553565
if isinstance(label, str):
554566
if label not in self.labels:
555567
raise KeyError(f"Label {label} not found")
@@ -893,6 +905,28 @@ def op_brcc(self, label: str):
893905
if not c:
894906
self.op_jmp(label)
895907

908+
def op_brge(self, label: str | int):
909+
"""BRGE - Branch if Greater or Equal (Signed)
910+
911+
Args:
912+
label: Destination label or address to jump to if the condition is met.
913+
"""
914+
915+
s = self.get_flag(SREG_S)
916+
if not s:
917+
self.op_jmp(label)
918+
919+
def op_brlt(self, label: str | int):
920+
"""BRLT - Branch if Less Than (Signed).
921+
922+
Args:
923+
label: Destination label or address to jump to if the condition is met.
924+
"""
925+
926+
s = self.get_flag(SREG_S)
927+
if s:
928+
self.op_jmp(label)
929+
896930
def op_push(self, rr: int):
897931
"""Push a register value onto the stack.
898932

tests/test_control_flow.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,39 @@ def test_cpse_skips_next(self):
9898
# If cpse skipped the next instruction, r6 should remain zero and r7 should be loaded
9999
self.assertEqual(cpu.read_reg(6), 0x00)
100100
self.assertEqual(cpu.read_reg(7), 0xBB)
101+
102+
def test_brlt(self):
103+
# BRLT: branch when signed (Rd < Rr). Use -1 (0xFF) < 1 (0x01)
104+
src = """
105+
ldi r0, $FF ; -1
106+
ldi r1, $01 ; 1
107+
cp r0, r1
108+
brlt less
109+
ldi r3, $01
110+
jmp done
111+
less:
112+
ldi r3, $02
113+
done:
114+
nop
115+
"""
116+
cpu = self.run_asm(src)
117+
# -1 < 1 so branch taken -> r3 == 2
118+
self.assertEqual(cpu.read_reg(3), 0x02)
119+
120+
def test_brge(self):
121+
# BRGE: branch when signed (Rd >= Rr). Use 1 >= -1
122+
src2 = """
123+
ldi r0, $01 ; 1
124+
ldi r1, $FF ; -1
125+
cp r0, r1
126+
brge ge
127+
ldi r3, $01
128+
jmp done
129+
ge:
130+
ldi r3, $02
131+
done:
132+
nop
133+
"""
134+
cpu2 = self.run_asm(src2)
135+
# 1 >= -1 so branch taken -> r3 == 2
136+
self.assertEqual(cpu2.read_reg(3), 0x02)

0 commit comments

Comments
 (0)