From 2982d12588873a49cbaf75bd149463f29bbbaaa7 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Mon, 13 Feb 2017 19:19:19 +1030 Subject: [PATCH] Implement labels in assembler --- asm.py | 28 +++++++++++++++++++++++++--- disasm.py | 5 ++++- libsynacor/bytecode.py | 23 ++++++++++++++++++----- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/asm.py b/asm.py index e969f1a..e4377e4 100755 --- a/asm.py +++ b/asm.py @@ -122,13 +122,35 @@ def assemble_instruction(source, tokens): if argstr.startswith('R'): # Register arg = OpRegister(int(argstr[1:])) + elif argstr.startswith('$'): + # Label + arg = OpLabel(argstr[1:]) else: # Hex literal arg = OpLiteral(int(argstr, 16)) instruction.args.append(arg) return [instruction], [] -# TODO: First pass +# First pass +labels = {} +SYN_MEM = [0] * 32768 +SYN_PTR = 0 + +with open(args.file, 'r') as source: + try: + while True: + instructions, inst_labels = assemble_next_instruction(source) + for label in inst_labels: + if label.startswith('$'): + labels[label[1:]] = SYN_PTR + if instructions is None: + break + for instruction in instructions: + code = instruction.assemble(None) + SYN_MEM[SYN_PTR:SYN_PTR+len(code)] = code + SYN_PTR += len(code) + except Exception as ex: + raise Exception('Error at line {}'.format(line_no)) from ex # Second pass SYN_MEM = [0] * 32768 @@ -137,11 +159,11 @@ SYN_PTR = 0 with open(args.file, 'r') as source: try: while True: - instructions, labels = assemble_next_instruction(source) + instructions, inst_labels = assemble_next_instruction(source) if instructions is None: break for instruction in instructions: - code = instruction.assemble() + code = instruction.assemble(labels) SYN_MEM[SYN_PTR:SYN_PTR+len(code)] = code SYN_PTR += len(code) except Exception as ex: diff --git a/disasm.py b/disasm.py index 86084e5..f89f349 100755 --- a/disasm.py +++ b/disasm.py @@ -172,7 +172,10 @@ while SYN_PTR < len(SYN_MEM): loc = op.get(None) if any(v == loc for k, v in labels.items()): label = next(k for k, v in labels.items() if v == loc) - print('{:04x}: {: <4} ${}'.format(SYN_PTR, instruction.name, label)) + if isinstance(instruction, InstructionJmp) or isinstance(instruction, InstructionCall): + print('{:04x}: {: <4} ${}'.format(SYN_PTR, instruction.name, label)) + else: + print('{:04x}: {: <4} {} ${}'.format(SYN_PTR, instruction.name, instruction.args[0].describe(), label)) else: print('{:04x}: {}'.format(SYN_PTR, instruction.describe())) else: diff --git a/libsynacor/bytecode.py b/libsynacor/bytecode.py index c155788..ea5224c 100644 --- a/libsynacor/bytecode.py +++ b/libsynacor/bytecode.py @@ -33,7 +33,7 @@ class OpLiteral(Operand): def describe(self): return '{:04x}'.format(self.value) - def assemble(self): + def assemble(self, labels): return self.value class OpRegister(Operand): @@ -46,9 +46,22 @@ class OpRegister(Operand): def describe(self): return 'R{}'.format(self.register) - def assemble(self): + def assemble(self, labels): return self.register + 32768 +# Used only in assembling process +class OpLabel(Operand): + def __init__(self, label): + self.label = label + + def assemble(self, labels): + if labels is None: + # First pass + return 0xffff + if self.label not in labels: + raise Exception('Unknown label {}'.format(self.label)) + return OpLiteral(labels[self.label]).assemble(labels) + instructions_by_opcode = {} instructions_by_name = {} @@ -74,8 +87,8 @@ class Instruction: description += ' {}'.format(self.args[i].describe()) return description - def assemble(self): - return [self.opcode] + [self.args[i].assemble() for i in range(self.nargs)] + def assemble(self, labels): + return [self.opcode] + [self.args[i].assemble(labels) for i in range(self.nargs)] @staticmethod def next_instruction(data, idx): @@ -228,6 +241,6 @@ class InstructionIn(Instruction): # Not actually an instruction, but convenient to think of it as one for the purposes of assembling # self.args is an array of literal values, rather than Operands class InstructionData(Instruction): - def assemble(self): + def assemble(self, labels): return self.args instructions_by_name['data'] = InstructionData