From 3fe2fcde421426d1d6402e557fb456bd32b8ed00 Mon Sep 17 00:00:00 2001 From: Kyler <59854022+KylerOlsen@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:35:29 -0700 Subject: [PATCH] Started assembler --- language/assembler.py | 136 ++++++++++++++++++++++++++++++++++++++++++ language/compiler.py | 4 ++ 2 files changed, 140 insertions(+) create mode 100644 language/assembler.py create mode 100644 language/compiler.py diff --git a/language/assembler.py b/language/assembler.py new file mode 100644 index 0000000..daf0bc5 --- /dev/null +++ b/language/assembler.py @@ -0,0 +1,136 @@ +# Kyler Olsen +# Feb 2024 + +from collections import namedtuple + +class AssemblerError(Exception): pass + +class Instruction(namedtuple('Instruction', ['bb', 'bl', 'lb', 'll'])): + + def __int__(self) -> int: + return ( + (self.bb << 9) + + (self.bl << 6) + + (self.lb << 3) + + (self.ll) + ) + + def oct_str(self) -> str: + return ( + str(self.bb) + + str(self.bl) + + str(self.lb) + + str(self.ll) + ) + +def reg(reg: str) -> int: + register_names = [ + "ZR", + "PC", + "SP", + "MP", + "D0", + "D1", + "D2", + "D3", + ] + register_numbers = [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + ] + if reg.upper() in register_names: + return register_names.index(reg.upper()) + elif reg in register_numbers: + return register_numbers.index(reg) + else: + raise AssemblerError(f"Invalid Register: {reg}") + +def reg1(l: str) -> int: + args = l.split(' ') + if len(args) == 2: + return reg(args[1]) + else: + raise AssemblerError(f"Invalid number of arguments: {args[0]}") + +def reg2(l: str) -> tuple[int, int]: + args = l.split(' ') + if len(args) == 3: + return reg(args[2]), reg(args[1]) + else: + raise AssemblerError(f"Invalid number of arguments: {args[0]}") + +def reg3(l: str) -> tuple[int, int, int]: + args = l.split(' ') + if len(args) == 4: + return reg(args[2]), reg(args[3]), reg(args[1]) + else: + raise AssemblerError(f"Invalid number of arguments: {args[0]}") + +def immediate(l: str) -> Instruction: + args = l.split(' ') + if len(args) == 2: + if 'b' in args[1]: + value = int(args[1].split('b')[1], base=2) + elif 'o' in args[1]: + value = int(args[1].split('o')[1], base=8) + elif 'x' in args[1]: + value = int(args[1].split('x')[1], base=16) + else: + value = int(args[1]) + + return Instruction( + 0, + 2 + ((value & 0x040) >> 6), + (value & 0x038) >> 3, + value & 0x007, + ) + else: + raise AssemblerError(f"Invalid number of arguments: {args[0]}") + +def parse(s: str) -> list[Instruction]: + instruction_set = { + "NOP": lambda _: Instruction(0,0,0,0), + "HLT": lambda _: Instruction(0,0,0,1), + "INT": lambda _: Instruction(0,0,0,2), + "BNZ": lambda _: Instruction(0,0,0,3), + "BLK": lambda _: Instruction(0,0,0,4), + "ENB": lambda _: Instruction(0,0,0,5), + + "GLA": lambda l: Instruction(0,0,2,reg1(l)), + "GET": lambda l: Instruction(0,0,3,reg1(l)), + "LOD": lambda l: Instruction(0,0,4,reg1(l)), + "STR": lambda l: Instruction(0,0,5,reg1(l)), + "PSH": lambda l: Instruction(0,0,6,reg1(l)), + "POP": lambda l: Instruction(0,0,7,reg1(l)), + + "LDI": lambda l: immediate(l), + + "LSH": lambda l: Instruction(0,4,*reg2(l)), + "RSH": lambda l: Instruction(0,5,*reg2(l)), + "INC": lambda l: Instruction(0,6,*reg2(l)), + "DEC": lambda l: Instruction(0,7,*reg2(l)), + + "AND": lambda l: Instruction(1,*reg3(l)), + "OR": lambda l: Instruction(2,*reg3(l)), + "NAD": lambda l: Instruction(3,*reg3(l)), + "SUB": lambda l: Instruction(4,*reg3(l)), + "XOR": lambda l: Instruction(5,*reg3(l)), + "NOR": lambda l: Instruction(6,*reg3(l)), + "ADD": lambda l: Instruction(7,*reg3(l)), + } + instructions = [] + + for rl in s.splitlines(False): + l = rl.strip() + if l[:3] in instruction_set: + instructions.append(instruction_set[l[:3]](l)) + elif l[:2] in instruction_set: + instructions.append(instruction_set[l[:2]](l)) + + return instructions diff --git a/language/compiler.py b/language/compiler.py new file mode 100644 index 0000000..1b1db77 --- /dev/null +++ b/language/compiler.py @@ -0,0 +1,4 @@ +# Kyler Olsen +# Feb 2024 + +