From 04d09c68dc47c3fd72ff7dfe0956f151513a4f89 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Sat, 13 Feb 2021 14:26:01 +0000 Subject: [PATCH] Assembler: handle negative numbers, keep track of source code position, add support for case insensitive symbols, add alias for O register --- asm.py | 106 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 29 deletions(-) diff --git a/asm.py b/asm.py index 77a8676..1867b80 100755 --- a/asm.py +++ b/asm.py @@ -5,6 +5,8 @@ from rply import ParserGenerator, LexerGenerator import re import struct +CASE_INSENSITIVE = True + OPS = { 'ADD': lambda a, b: a + b, 'SUBTRACT': lambda a, b: a - b, @@ -30,10 +32,36 @@ OPCODES = { REGISTERS = { 'A': 0x00, 'B': 0x01, 'C': 0x02, 'X': 0x03, 'Y': 0x04, 'Z': 0x05, - 'I': 0x06, 'J': 0x07, 'SP': 0x1b, 'PC': 0x1c, 'EX': 0x1d + 'I': 0x06, 'J': 0x07, 'SP': 0x1b, 'PC': 0x1c, 'EX': 0x1d, + 'O': 0x1d # For compatibility with specs v1.1 } +class SymbolTable: + + def __init__(self, ignorecase=False): + self.ignorecase = ignorecase + self.symbols = {} + self.orig = {} + + def __getitem__(self, key): + if self.ignorecase: + key = self.orig[key.upper()] + return self.symbols[key] + + def __setitem__(self, key, value): + ukey = key.upper() + if ukey in self.orig: + key = self.orig[ukey] + else: + self.orig[ukey] = key + self.symbols[key] = value + + def __str__(self): + return '\n'.join([ + f"{k}: {v}" for k, v in sorted(self.symbols.items())]) + + class ASM(SimpleNamespace): @staticmethod @@ -102,7 +130,7 @@ class Expr(SimpleNamespace): return self.value else: return OPS[self.op](self.l.eval(ctx), self.r.eval(ctx)) - def simplify(self, ctx={}): + def simplify(self, ctx=SymbolTable(CASE_INSENSITIVE)): if self.op == 'NUMBER': return self elif self.op == 'SYMBOL': @@ -129,16 +157,18 @@ class Indirect(SimpleNamespace): lg = LexerGenerator() +STARTOP = r'(? 1: base = 8 text = text[1:] - return Expr(op='NUMBER', value=int(text, base)) + value = int(text, base) + if negate: + value = -value + return Expr(op='NUMBER', value=value) @pg.production("expr : SYMBOL") def expr_sym(p): @@ -367,25 +408,29 @@ def assemble(ctx, inst): return inst.code() +class AssemblerError(BaseException): + pass + + if __name__ == '__main__': import sys - sym = {} + sym = SymbolTable(CASE_INSENSITIVE) sym['.addr'] = 0 insns = [] for filename in sys.argv[1:]: with open(filename, 'r') as sourcefile: code = parser.parse(lexer.lex(sourcefile.read())) for inst in code: # pylint: disable=E1133 - # print(sym['.addr'], inst) + print(sym['.addr'], inst) a = sym['.addr'] c = assemble(sym, inst) if c is not None: - insns.append((a, c)) + insns.append((inst.pos, a, c)) print(sym) print(insns) sym['.addr'] = 0 binimage = b'' - for a, c in insns: # pylint: disable=E1133 + for pos, a, c in insns: # pylint: disable=E1133 words = [] for w in c: if type(w) == int: @@ -393,10 +438,13 @@ if __name__ == '__main__': else: words.append(w.eval(sym)) if words: - print(["%04x" % x for x in words]) + print(pos,["%04x" % x for x in words]) for w in words: + if w < 0: + w = (1<<16)+w + if w < 0 or w > 0xffff: + raise AssemblerError("Value out of bounds: "+str(w)) binimage += struct.pack("H", w) outfilename = filename[:filename.rfind('.')]+'.bin' with open(outfilename, 'wb') as binfile: binfile.write(binimage)