MOAR branch support
This commit is contained in:
parent
e03efaffaa
commit
c6dcec323c
2 changed files with 32 additions and 18 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue