sob, tst, clean up label processing
This commit is contained in:
parent
f0a848910b
commit
7f2811f1df
1 changed files with 66 additions and 17 deletions
|
@ -214,6 +214,9 @@ class PDP11InstructionAssembler:
|
||||||
def dec(self, dst):
|
def dec(self, dst):
|
||||||
return self._1op(0o005300, dst)
|
return self._1op(0o005300, dst)
|
||||||
|
|
||||||
|
def tst(self, dst):
|
||||||
|
return self._1op(0o005700, dst)
|
||||||
|
|
||||||
def swab(self, dst):
|
def swab(self, dst):
|
||||||
return self._1op(0o000300, dst)
|
return self._1op(0o000300, dst)
|
||||||
|
|
||||||
|
@ -302,6 +305,31 @@ class InstructionBlock(PDP11InstructionAssembler, AbstractContextManager):
|
||||||
self.labels[name] = curoffs
|
self.labels[name] = curoffs
|
||||||
return curoffs
|
return curoffs
|
||||||
|
|
||||||
|
def _label_or_offset(self, x):
|
||||||
|
"""Return offset: either 'x' itself or computed from x as label.
|
||||||
|
|
||||||
|
DOES NO VALIDATION OF SIZE OF RESULT (because different instructions
|
||||||
|
have different requirements.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# convert negative numbers in 16-bit two's complement,
|
||||||
|
# as a convenience but also this determines int-vs-string
|
||||||
|
try:
|
||||||
|
if x < 0 and x >= -32768:
|
||||||
|
x += 65536
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if x < 0 or x > 65535:
|
||||||
|
raise ValueError(f"offset {x=} out of 16-bit range")
|
||||||
|
return x
|
||||||
|
|
||||||
|
# perhaps it is a label ... by definition (for now?)
|
||||||
|
# it has to be backwards if so. Return its naked offset
|
||||||
|
# (converted to 16-bit signed) and allow the naked KeyError
|
||||||
|
# to occur if the label is not found.
|
||||||
|
return self._label_or_offset(self.labels[x] - (len(self) + 1))
|
||||||
|
|
||||||
# Branch instruction support only exists within a given InstructionBlock
|
# Branch instruction support only exists within a given InstructionBlock
|
||||||
def bxx_offset(self, target, /):
|
def bxx_offset(self, target, /):
|
||||||
"""Generate offset for Bxx target
|
"""Generate offset for Bxx target
|
||||||
|
@ -313,26 +341,18 @@ class InstructionBlock(PDP11InstructionAssembler, AbstractContextManager):
|
||||||
# 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...
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if (target & 0o377) != target:
|
offs = self._label_or_offset(target)
|
||||||
raise ValueError(f"branch target ({target}) too far")
|
except (KeyError, ValueError):
|
||||||
return target
|
raise ValueError(f"branch target ({target}) too far or illegal")
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# perhaps it is a label ... by definition it has to be backwards if so
|
# offsets come back from _label.. in 16-bit form, convert to 8
|
||||||
try:
|
# and make sure not too big in either direction
|
||||||
# +255 not 256 bcs the Bxx instruction itself
|
if offs > 127 and offs < (65536 - 128):
|
||||||
offs = self.labels[target] - len(self) + 255
|
|
||||||
if offs < 128:
|
|
||||||
raise ValueError(f"branch target ('{target}') too far.")
|
raise ValueError(f"branch target ('{target}') too far.")
|
||||||
except KeyError:
|
|
||||||
raise ValueError(f"can't find branch target '{target}'")
|
|
||||||
|
|
||||||
if offs >= 0 and offs < 256:
|
return offs & 0o377
|
||||||
return offs
|
|
||||||
|
|
||||||
raise ValueError(f"branch target ('{target}') too far.")
|
|
||||||
|
|
||||||
def bne(self, target):
|
def bne(self, target):
|
||||||
return self.literal(BRANCH_CODES['bne'] | self.bxx_offset(target))
|
return self.literal(BRANCH_CODES['bne'] | self.bxx_offset(target))
|
||||||
|
@ -347,6 +367,15 @@ class InstructionBlock(PDP11InstructionAssembler, AbstractContextManager):
|
||||||
def br(self, target):
|
def br(self, target):
|
||||||
return self.literal(0o000400 | self.bxx_offset(target))
|
return self.literal(0o000400 | self.bxx_offset(target))
|
||||||
|
|
||||||
|
def sob(self, reg, target):
|
||||||
|
offs = self._label_or_offset(target)
|
||||||
|
|
||||||
|
# offsets are always negative and are allowed from 0 to -63
|
||||||
|
# but they come from _label... as two's complement, so:
|
||||||
|
if offs < 0o177701: # (65536-63)
|
||||||
|
raise ValueError(f"sob illegal target {target}")
|
||||||
|
return self.literal(0o077000 | (reg << 6) | ((-offs) & 0o77))
|
||||||
|
|
||||||
def instructions(self):
|
def instructions(self):
|
||||||
return self._instblock
|
return self._instblock
|
||||||
|
|
||||||
|
@ -368,12 +397,21 @@ class InstructionBlock(PDP11InstructionAssembler, AbstractContextManager):
|
||||||
self.literal(w)
|
self.literal(w)
|
||||||
return words_offs
|
return words_offs
|
||||||
|
|
||||||
|
def simh(self, *, startaddr=0o10000):
|
||||||
|
"""Generate lines of SIMH deposit commands."""
|
||||||
|
|
||||||
|
for offs, w in enumerate(self.instructions()):
|
||||||
|
yield f"D {oct(startaddr + (2 * offs))[2:]} {oct(w)[2:]}"
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
ASM = PDP11InstructionAssembler
|
ASM = PDP11InstructionAssembler
|
||||||
|
|
||||||
|
# NOTE: these are tests of instruction ASSEMBLY not execution.
|
||||||
class TestMethods(unittest.TestCase):
|
class TestMethods(unittest.TestCase):
|
||||||
|
|
||||||
def test_bne_label_distance(self):
|
def test_bne_label_distance(self):
|
||||||
# this should just execute without any issue
|
# this should just execute without any issue
|
||||||
for i in range(127):
|
for i in range(127):
|
||||||
|
@ -391,4 +429,15 @@ if __name__ == "__main__":
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
a.bne('foo')
|
a.bne('foo')
|
||||||
|
|
||||||
|
def test_sob(self):
|
||||||
|
for i in range(63): # 0..62 because the sob also counts
|
||||||
|
with self.subTest(i=i):
|
||||||
|
with ASM() as a:
|
||||||
|
a.label('foosob')
|
||||||
|
for _ in range(i):
|
||||||
|
a.mov('r0', 'r0')
|
||||||
|
inst = a.sob(0, 'foosob')
|
||||||
|
self.assertEqual(len(inst), 1)
|
||||||
|
self.assertEqual(inst[0] & 0o77, i+1)
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Add table
Reference in a new issue