diff options
| author | 2023-02-12 18:06:08 +0000 | |
|---|---|---|
| committer | 2023-02-12 18:06:08 +0000 | |
| commit | 7b3eaf9b4f9aaec02ce63be638de373397fa9460 (patch) | |
| tree | 8231125e0b6d1dad534fae72fe9880ba1bda33cb /asm | |
| parent | jump tests (diff) | |
add pseudoinstructions that compile to regular instructions
Diffstat (limited to 'asm')
| -rw-r--r-- | asm/creole.py | 130 | ||||
| -rw-r--r-- | asm/ffi.py | 3 | ||||
| -rw-r--r-- | asm/test.py | 4 |
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: @@ -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) |
