MOAR branch support

This commit is contained in:
Neil Webber 2023-09-12 17:41:15 -06:00
parent e03efaffaa
commit c6dcec323c
2 changed files with 32 additions and 18 deletions

View file

@ -29,6 +29,7 @@
# #
from contextlib import AbstractContextManager from contextlib import AbstractContextManager
from branches import BRANCH_CODES
class PDP11InstructionAssembler: class PDP11InstructionAssembler:
@ -276,28 +277,40 @@ class InstructionBlock(PDP11InstructionAssembler, AbstractContextManager):
return curoffs return curoffs
# Branch instruction support only exists within a given InstructionBlock # Branch instruction support only exists within a given InstructionBlock
def bxx_offset(self, name1, name2=None): def bxx_offset(self, target, /):
"""Generate offset appropriate to Bxx between name1 and name2. """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 # XXX TODO XXX make forward references possible and automate the
# backpatching even if that gets one step closer # backpatching even if that gets one step closer
# to slowly implementing an entire assembler... # to slowly implementing an entire assembler...
if name2 is None: try:
# +255 not 256 because account for the Bxx instruction itself if (target & 0o377) != target:
offs = self.labels[name1] - len(self) + 255 raise ValueError(f"branch target ({target}) too far")
else: return target
raise ValueError("two name bxx_offset not yet implemented") except TypeError:
pass
offs8 = offs & 0o377 # perhaps it is a label
if offs8 != offs: try:
raise ValueError(f"distance to {name1} too far.") # +255 not 256 bcs the Bxx instruction itself
return offs8 offs = self.labels[target] - len(self) + 255
except KeyError:
raise ValueError(f"can't find branch target '{target}'")
def bne(self, name): if offs >= 0 and offs < 256:
return self.literal(0o001000 | self.bxx_offset(name)) 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): def instructions(self):
return self._instblock return self._instblock

View file

@ -23,6 +23,7 @@
from types import SimpleNamespace from types import SimpleNamespace
from machine import PDP1170 from machine import PDP1170
from branches import BRANCH_CODES
from pdptraps import PDPTraps from pdptraps import PDPTraps
import unittest import unittest
import random import random
@ -331,10 +332,10 @@ class TestMethods(unittest.TestCase):
with ASM() as a: with ASM() as a:
a.clr('r1') # if successful r1 will become goodval a.clr('r1') # if successful r1 will become goodval
a.clr('r0') a.clr('r0')
a.literal(0o101401) # BEQ +1 a.beq(+1)
a.halt() # stop here if BEQ fails a.halt() # stop here if BEQ fails
a.literal(0o000257) # 1f: CCC .. clear all the condition codes 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.halt() # stop here if BNE fails
a.mov(goodval, 'r1') # indicate success a.mov(goodval, 'r1') # indicate success
a.halt() a.halt()
@ -386,7 +387,7 @@ class TestMethods(unittest.TestCase):
# various condition code tests # various condition code tests
p = self.make_pdp() p = self.make_pdp()
insts = self._cc_unscc(0o3400, 0o3000) insts = self._cc_unscc(BRANCH_CODES['blt'], BRANCH_CODES['bgt'])
instloc = 0o4000 instloc = 0o4000
self.loadphysmem(p, insts, instloc) self.loadphysmem(p, insts, instloc)
@ -423,7 +424,7 @@ class TestMethods(unittest.TestCase):
# more stuff like test_cc but specifically testing unsigned Bxx codes # more stuff like test_cc but specifically testing unsigned Bxx codes
p = self.make_pdp() p = self.make_pdp()
insts = self._cc_unscc(0o103400, 0o101000) insts = self._cc_unscc(BRANCH_CODES['blo'], BRANCH_CODES['bhi'])
instloc = 0o4000 instloc = 0o4000
self.loadphysmem(p, insts, instloc) self.loadphysmem(p, insts, instloc)