aboutsummaryrefslogtreecommitdiffstats
path: root/asm
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2023-02-12 18:06:08 +0000
committerGravatar Peter McGoron 2023-02-12 18:06:08 +0000
commit7b3eaf9b4f9aaec02ce63be638de373397fa9460 (patch)
tree8231125e0b6d1dad534fae72fe9880ba1bda33cb /asm
parentjump tests (diff)
add pseudoinstructions that compile to regular instructions
Diffstat (limited to 'asm')
-rw-r--r--asm/creole.py130
-rw-r--r--asm/ffi.py3
-rw-r--r--asm/test.py4
3 files changed, 83 insertions, 54 deletions
diff --git a/asm/creole.py b/asm/creole.py
index 4cb4b8c..b1481dd 100644
--- a/asm/creole.py
+++ b/asm/creole.py
@@ -17,6 +17,16 @@ def from_2c(w):
return w
return -word_2c(w)
+class Argument:
+ def __init__(self, argtype, val, sign=False):
+ self.at = argtype
+ self.sign = sign
+ self.val = val
+ def __str__(self):
+ return f'({self.at}, {self.sign}, {self.val})'
+ def high_bits(self):
+ return int(self.sign) << 1 | (self.at == ArgType.REG)
+
class ArgType(Enum):
""" Class denoting the type of an argument to an instruction. """
@@ -39,13 +49,13 @@ class ArgType(Enum):
the argument.
"""
if s.isnumeric():
- return (ArgType.IMM, int(s))
+ return Argument(ArgType.IMM, int(s))
elif s[0] == "-" and s[1:].isnumeric():
- return (ArgType.IMM, word_2c(int(s[1:])))
+ return Argument(ArgType.IMM, word_2c(int(s[1:])))
elif s[0] == 'r' and s[1:].isnumeric():
- return (ArgType.REG, int(s[1:]))
+ return Argument(ArgType.REG, int(s[1:]))
elif s[0] == 'l' and s[1:].isnumeric():
- return (ArgType.LAB, int(s[1:]))
+ return Argument(ArgType.LAB, int(s[1:]))
else:
raise MalformedArgument(s)
@@ -54,11 +64,11 @@ class ArgType(Enum):
the type of the enum value. """
t = ArgType.gettype(s)
if self == ArgType.VAL:
- if t[0] == ArgType.REG or t[0] == ArgType.IMM:
+ if t.at == ArgType.REG or t.at == ArgType.IMM:
return t
else:
return None
- elif t[0] == self:
+ elif t.at == self:
return t
else:
return None
@@ -84,29 +94,38 @@ class TypecheckException(Exception):
class Instruction(Enum):
""" Class of microcode instructions. The first number is the opcode
and the suceeding values are the types of each of the
- arguments. """
- NOP = 0
- PUSH = 1, ArgType.VAL
- POP = 2, ArgType.REG
- ADD = 3, ArgType.REG, ArgType.VAL, ArgType.VAL
- MUL = 4, ArgType.REG, ArgType.VAL, ArgType.VAL
- DIV = 5, ArgType.REG, ArgType.VAL, ArgType.VAL
- SDIV = 6, ArgType.REG, ArgType.VAL, ArgType.VAL
- SYS = 7, ArgType.VAL
- CLB = 8, ArgType.LAB
- JL = 9, ArgType.LAB, ArgType.VAL, ArgType.VAL
- JLE = 10, ArgType.LAB, ArgType.VAL, ArgType.VAL
- JG = 11, ArgType.LAB, ArgType.VAL, ArgType.VAL
- JGE = 12, ArgType.LAB, ArgType.VAL, ArgType.VAL
- JE = 13, ArgType.LAB, ArgType.VAL, ArgType.VAL
- JNE = 13, ArgType.LAB, ArgType.VAL, ArgType.VAL
-
- def __init__(self, opcode, *args):
- if opcode > 0x7F or opcode < 0:
+ arguments. The first argument is the opcode and the second
+ argument is if the argument is a signed variant of another
+ opcode. """
+ NOP = 0, False
+ PUSH = 1, False, ArgType.VAL
+ POP = 2, False, ArgType.REG
+ ADD = 3, False, ArgType.REG, ArgType.VAL, ArgType.VAL
+ MUL = 4, False, ArgType.REG, ArgType.VAL, ArgType.VAL
+ DIV = 5, False, ArgType.REG, ArgType.VAL, ArgType.VAL
+ SDIV = "DIV", True, ArgType.REG, ArgType.VAL, ArgType.VAL
+ SYS = 6, False, ArgType.VAL
+ CLB = 7, False, ArgType.LAB
+ JL = 8, False, ArgType.LAB, ArgType.VAL, ArgType.VAL
+ JLS = "JL", True, ArgType.LAB, ArgType.VAL, ArgType.VAL
+ JLE = 9, False, ArgType.LAB, ArgType.VAL, ArgType.VAL
+ JLES = "JLE", True, ArgType.LAB, ArgType.VAL, ArgType.VAL
+ JE = 10, False, ArgType.LAB, ArgType.VAL, ArgType.VAL
+ JNE = 11, False, ArgType.LAB, ArgType.VAL, ArgType.VAL
+
+ def __int__(self):
+ return self.opcode
+
+ def __init__(self, opcode, signed_instruction, *args):
+ if type(opcode) is int and (opcode > 0x7F or opcode < 0):
raise OpcodeException(opcode)
self.opcode = opcode
self.argtypes = args
+ if signed_instruction:
+ self.render = self._render_change_args
+ else:
+ self.render = self._default_render
def typecheck(self, sargs):
""" Pass arguments to the instruction and check if the
@@ -124,15 +143,31 @@ class Instruction(Enum):
rargs.append(t)
return rargs
+ # The following will be called using OPCODE.render() instead of being
+ # called directly.
+
+ def _render_change_args(self, args):
+ for i in range(0,len(args)):
+ if args[i].at != ArgType.LAB:
+ args[i].sign = True
+ return Instruction[self.opcode].render(args)
+
+ def _default_render(self, args):
+ b = bytes([self.opcode])
+ for a in args:
+ l = 2 if a.val < 0x80 else None
+ bex = encode_pseudo_utf8(a.val, a.high_bits(), l)
+ b = b + bex
+ return b + bytes([0])
+
encoding_types = {
-# start mask A B
+# start mask B
2: (0x7F, 0xC0, 7),
3: (0xFFF, 0xE0, 12),
- 4: (0x1FFFF, 0xF0, 16),
- 5: (0x3FFFFF, 0xF8, 21),
- 6: (0x7FFFFFF, 0xFC, 26),
- 7: (0xFFFFFFFF, 0xFE, 36),
-# A : number of bits in start byte
+ 4: (0x1FFFF, 0xF0, 17),
+ 5: (0x3FFFFF, 0xF8, 22),
+ 6: (0x7FFFFFF, 0xFC, 27),
+ 7: (0xFFFFFFFF, 0xFE, 32),
# B : Total number of bits excluding high bits
}
@@ -172,32 +207,25 @@ def encode_pseudo_utf8(n, high_bits, to):
class RangeCheckException(Exception):
pass
class Line:
- def __init__(self, opcode, args):
- self.opcode = opcode
+ def __init__(self, ins, args):
+ self.ins = ins
self.args = args
def check_line(self, lablen, reglen):
for a in self.args:
- if a[0] == ArgType.REG:
- if a[1] < 0 or a[1] >= reglen:
- raise RangeCheckException(a[0],
- a[1],
+ if a.at == ArgType.REG:
+ if a.val < 0 or a.val >= reglen:
+ raise RangeCheckException(a.at,
+ a.val,
reglen)
- elif a[0] == ArgType.LAB:
- if a[1] < 0 or a[1] >= lablen:
- raise RangeCheckException(a[0],
- a[1],
+ elif a.at == ArgType.LAB:
+ if a.val < 0 or a.val >= lablen:
+ raise RangeCheckException(a.at,
+ a.val,
reglen)
def __call__(self):
- b = bytes([self.opcode])
- for a in self.args:
- l = 2 if a[1] < 0x80 else None
- if a[0] == ArgType.REG:
- b = b + encode_pseudo_utf8(a[1],1,l)
- else:
- b = b + encode_pseudo_utf8(a[1],0,l)
- return b + bytes([0])
+ return self.ins.render(self.args)
class InstructionNotFoundException(Exception):
pass
@@ -212,12 +240,12 @@ class Program:
line[0] = line[0].casefold()
try:
# TODO: is there no better way to do this in Python?
- ins = getattr(Instruction, line[0].upper())
+ ins = Instruction[line[0].upper()]
except Exception as e:
raise InstructionNotFoundException(line[0])
args_w_type = ins.typecheck(line[1:])
- self.asm_push_line(ins.opcode, args_w_type)
+ self.asm_push_line(ins, args_w_type)
def parse_lines(self, lines):
for l in lines:
diff --git a/asm/ffi.py b/asm/ffi.py
index ba327bf..ccbe40d 100644
--- a/asm/ffi.py
+++ b/asm/ffi.py
@@ -22,10 +22,11 @@ class RunRet(Enum):
STOP = 2
STACK_OVERFLOW = 3
STACK_UNDERFLOW = 4
- RUN_LABEL_OVERFLOW = 5
+ LABEL_OVERFLOW = 5
REGISTER_OVERFLOW = 6
UNKNOWN_OPCODE = 7
DIVIDE_BY_ZERO = 8
+ HIGH_BIT_MALFORMED = 9
def is_halt(self):
return not (self == RunRet.CONTINUE or self == RunRet.SYSCALL)
diff --git a/asm/test.py b/asm/test.py
index 00e9e5e..4008e3d 100644
--- a/asm/test.py
+++ b/asm/test.py
@@ -50,7 +50,7 @@ class PushTest(unittest.TestCase):
p = Program(reglen=0x8000000)
p.parse_asm_line("PUSH r134217727")
b = p()
- self.assertEqual(b, b'\x01\xFC\x87\xbf\xbf\xbf\xbf\x00')
+ self.assertEqual(b, b'\x01\xFC\x8f\xbf\xbf\xbf\xbf\x00')
def test_compile_push(self):
p = Program()
@@ -318,7 +318,7 @@ class LabelTest(unittest.TestCase):
"CLB l0",
"add r0 r0 -1",
"add r1 r1 1",
- "jg l0 r0 0"
+ "jl l0 0 r0"
])
ex = ffi.Environment(p())
self.assertEqual(ex(), ffi.RunRet.STOP)