From c6dcec323cf50f2ddc8191d90d1b6a4e0cbdff6c Mon Sep 17 00:00:00 2001 From: Neil Webber Date: Tue, 12 Sep 2023 17:41:15 -0600 Subject: [PATCH] MOAR branch support --- pdpasmhelper.py | 41 +++++++++++++++++++++++++++-------------- pdptests.py | 9 +++++---- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/pdpasmhelper.py b/pdpasmhelper.py index 03bb98d..771a0ec 100644 --- a/pdpasmhelper.py +++ b/pdpasmhelper.py @@ -29,6 +29,7 @@ # from contextlib import AbstractContextManager +from branches import BRANCH_CODES class PDP11InstructionAssembler: @@ -276,28 +277,40 @@ class InstructionBlock(PDP11InstructionAssembler, AbstractContextManager): return curoffs # Branch instruction support only exists within a given InstructionBlock - def bxx_offset(self, name1, name2=None): - """Generate offset appropriate to Bxx between name1 and name2. + def bxx_offset(self, target, /): + """Generate offset for Bxx target - If name2 is None, generate offset, backwards, from current to name1. + A target can be a string label or a number. Numbers are taken as-is. + Names are looked up in the labels and offsets generated. """ # XXX TODO XXX make forward references possible and automate the # backpatching even if that gets one step closer # to slowly implementing an entire assembler... - if name2 is None: - # +255 not 256 because account for the Bxx instruction itself - offs = self.labels[name1] - len(self) + 255 - else: - raise ValueError("two name bxx_offset not yet implemented") + try: + if (target & 0o377) != target: + raise ValueError(f"branch target ({target}) too far") + return target + except TypeError: + pass - offs8 = offs & 0o377 - if offs8 != offs: - raise ValueError(f"distance to {name1} too far.") - return offs8 + # perhaps it is a label + try: + # +255 not 256 bcs the Bxx instruction itself + offs = self.labels[target] - len(self) + 255 + except KeyError: + raise ValueError(f"can't find branch target '{target}'") - def bne(self, name): - return self.literal(0o001000 | self.bxx_offset(name)) + if offs >= 0 and offs < 256: + return offs + + raise ValueError(f"branch target ('{target}') too far.") + + def bne(self, target): + return self.literal(BRANCH_CODES['bne'] | self.bxx_offset(target)) + + def beq(self, target): + return self.literal(BRANCH_CODES['beq'] | self.bxx_offset(target)) def instructions(self): return self._instblock diff --git a/pdptests.py b/pdptests.py index d254cee..6990a04 100644 --- a/pdptests.py +++ b/pdptests.py @@ -23,6 +23,7 @@ from types import SimpleNamespace from machine import PDP1170 +from branches import BRANCH_CODES from pdptraps import PDPTraps import unittest import random @@ -331,10 +332,10 @@ class TestMethods(unittest.TestCase): with ASM() as a: a.clr('r1') # if successful r1 will become goodval a.clr('r0') - a.literal(0o101401) # BEQ +1 + a.beq(+1) a.halt() # stop here if BEQ fails a.literal(0o000257) # 1f: CCC .. clear all the condition codes - a.literal(0o001001) # BNE +1 + a.bne(+1) a.halt() # stop here if BNE fails a.mov(goodval, 'r1') # indicate success a.halt() @@ -386,7 +387,7 @@ class TestMethods(unittest.TestCase): # various condition code tests p = self.make_pdp() - insts = self._cc_unscc(0o3400, 0o3000) + insts = self._cc_unscc(BRANCH_CODES['blt'], BRANCH_CODES['bgt']) instloc = 0o4000 self.loadphysmem(p, insts, instloc) @@ -423,7 +424,7 @@ class TestMethods(unittest.TestCase): # more stuff like test_cc but specifically testing unsigned Bxx codes p = self.make_pdp() - insts = self._cc_unscc(0o103400, 0o101000) + insts = self._cc_unscc(BRANCH_CODES['blo'], BRANCH_CODES['bhi']) instloc = 0o4000 self.loadphysmem(p, insts, instloc)