From a7308280cb5daaff1f42eedbd450e6f3fc3c93b6 Mon Sep 17 00:00:00 2001 From: Peter McGoron Date: Tue, 7 Feb 2023 16:38:04 +0000 Subject: [PATCH] start assembler --- README.md | 7 ++++ asm.py | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 asm.py diff --git a/README.md b/README.md index d8de334..cf682b3 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,10 @@ The first four bytes determine the type: All other values are reserved. Overlong values are allowed, and for some argument values they are necessary. All lines are terminated by a byte of all zeros. + +## Design Philsophy + +Creole is small but not minimal. It is easy to add instructions, and +the amount of labels, registers, and stack space can changed at runtime. +System calls can be added dynamically, but static instructions that take +at most 3 arguments should be hard-coded. diff --git a/asm.py b/asm.py new file mode 100644 index 0000000..cd6a94d --- /dev/null +++ b/asm.py @@ -0,0 +1,109 @@ +#!/usr/bin/python3 + +from enum import Enum + +class ArgType(Enum): + TYPE_IMM = 1 + TYPE_REG = 2 + TYPE_VAL = 3 + TYPE_LAB = 4 + + def gettype(s): + if s.isnumeric(): + return (TYPE_IMM, int(s)) + elif s[0] == 'r' and is_num(s[1:]): + return (TYPE_REG, int(s[1:])) + elif s[0] == 'l' and is_num(s[1:]): + return (TYPE_LAB, int(s[1:])) + else: + return None + + def typecheck(self, s): + t = gettype(s) + if t is None: + return None + if self == TYPE_VAL: + return t[0] == TYPE_REG or t[0] == TYPE_IMM + else: + return t[0] == self + +class Instruction: + def __init__(self, opcode, argtypes): + self.opcode = opcode + assert self.opcode < 0x80 and self.opcode >= 0 + self.argtypes = argtypes + def typecheck(self, sargs): + rargs = [] + if len(sargs) != len(self.argtypes): + return None + for i in range(0, len(sargs)): + if not self.argtypes[i].typecheck(sargs[i]): + return None + rargs.append(ArgType.gettype(sargs[i])) + return rargs + +instructions = { +"NOP" : Instruction(0, []), +"PUSH" : Instruction(1, [ArgType.TYPE_REG]), +"POP" : Instruction(2, [ArgType.TYPE_REG]), +"ADD" : Instruction(3, [ArgType.TYPE_VAL, ArgType.TYPE_VAL, ArgType.TYPE_VAL]), +"MUL" : Instruction(4, [ArgType.TYPE_VAL, ArgType.TYPE_VAL, ArgType.TYPE_VAL]), +"DIV" : Instruction(5, [ArgType.TYPE_VAL, ArgType.TYPE_VAL, ArgType.TYPE_VAL]), +"JL" : Instruction(6, [ArgType.TYPE_LAB, ArgType.TYPE_VAL, ArgType.TYPE_VAL]), +"CLB" : Instruction(7, [ArgType.TYPE_LAB]), +"SYS" : Instruction(8, [ArgType.TYPE_VAL]) +} + +encoding_types = { +# start mask A 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 +# B : Total number of bits excluding high bits +} + +def encode_pseudo_utf8(n, high_bits, to): + if to > 8 or to < 0: + return None + elif to == 1: + if n < 0x80: + return bytes([n]) + else: + return None + + (maxval, start_byte, n_tot) = encoding_types[to] + if n > maxval or high_bits > 15: + return None + n = n | (high_bits << n_tot) + all_bytes = [] + for i in range(0, to - 1): + all_bytes.append(0x80 | (n & 0x3F)) + n >>= 6 + all_bytes.append(start_byte | n) + return bytes(reversed(all_bytes)) + +""" +class Line: + def __init__(self, opcode, args): + self.opcode = opcode + self.args = args + def render(self): + +class Program: + def asm_push_line(self, ins, args): + self.asm.append((ins, args)) + + def parse_asm_line(self, line): + line = line.split(' ') + if line[0] not in instructions: + raise Exception + else: + r = instructions[line[0]].typecheck(line[1:]) + if r is None: + raise Exception + asm_push_instruction(instructions[line[0]].opcode, r) +"""