asm.py: improve literal handling; parse source file only once
This commit is contained in:
parent
a75d9c6781
commit
d13d72ce8b
80
asm.py
80
asm.py
|
@ -32,11 +32,13 @@ REGISTERS = {
|
|||
'I': 0x06, 'J': 0x07, 'SP': 0x1b, 'PC': 0x1c, 'EX': 0x1d
|
||||
}
|
||||
|
||||
|
||||
class ASM(SimpleNamespace):
|
||||
|
||||
@staticmethod
|
||||
def addr(arg, is_a):
|
||||
if type(arg) == Expr:
|
||||
arg = arg.value
|
||||
return (0x1f, arg)
|
||||
if type(arg) == Register:
|
||||
return (REGISTERS[arg.name], None)
|
||||
elif type(arg) == int:
|
||||
|
@ -45,12 +47,8 @@ class ASM(SimpleNamespace):
|
|||
else:
|
||||
return (0x1f, arg)
|
||||
elif type(arg) == Indirect:
|
||||
if type(arg.disp) == Expr:
|
||||
disp = getattr(arg.disp, "value", 0)
|
||||
else:
|
||||
disp = arg.disp
|
||||
if arg.reg is None:
|
||||
return (0x1e, disp)
|
||||
return (0x1e, arg.disp)
|
||||
else:
|
||||
if arg.reg == 'SP':
|
||||
sp = getattr(arg, 'sp', None)
|
||||
|
@ -75,7 +73,8 @@ class ASM(SimpleNamespace):
|
|||
if arg.disp == 0:
|
||||
return (0x08+REGISTERS[r], None)
|
||||
else:
|
||||
return (0x10+REGISTERS[r], disp)
|
||||
return (0x10+REGISTERS[r], arg.disp)
|
||||
|
||||
def code(self):
|
||||
o, b = OPCODES[self.op]
|
||||
a_bits, a_extra = self.addr(self.a, True)
|
||||
|
@ -84,27 +83,15 @@ class ASM(SimpleNamespace):
|
|||
else:
|
||||
b_bits, b_extra = self.addr(self.b, False)
|
||||
r = [o | (a_bits << 10) | (b_bits << 5)]
|
||||
for e in a_extra, b_extra:
|
||||
for e in b_extra, a_extra:
|
||||
if e is not None:
|
||||
r.append(e)
|
||||
print("Assembing: %s %r, %r -> %r" % (self.op, self.b, self.a, r))
|
||||
return r
|
||||
|
||||
def words(self):
|
||||
r = 1
|
||||
if type(self.a) in (Expr, int): # literal (FIXME: optimize short literals)
|
||||
if type(self.a) == int:
|
||||
if not (-1 <= self.a <= 30):
|
||||
r += 1
|
||||
else:
|
||||
r += 1
|
||||
elif type(self.a) == Indirect:
|
||||
if self.a.disp != 0:
|
||||
r += 1
|
||||
if type(self.b) in (Expr, int): # literal
|
||||
r += 1
|
||||
elif type(self.b) == Indirect:
|
||||
if self.b.disp != 0:
|
||||
r += 1
|
||||
return r
|
||||
return len(self.code())
|
||||
|
||||
|
||||
class Expr(SimpleNamespace):
|
||||
def eval(self, ctx):
|
||||
|
@ -347,44 +334,33 @@ def expr_sym(p):
|
|||
lexer = lg.build()
|
||||
parser = pg.build()
|
||||
|
||||
def assemble(ctx, inst, step=1):
|
||||
def assemble(ctx, inst):
|
||||
if inst.label is not None:
|
||||
if step == 1 and inst.label in ctx:
|
||||
print(f"Redefining symbol {inst.label}")
|
||||
ctx[inst.label] = ctx['.addr']
|
||||
if type(inst) == Directive:
|
||||
if inst.directive == ".org":
|
||||
ctx['.addr'] = inst.args.eval(ctx)
|
||||
return None
|
||||
elif inst.directive in (".data", ".word", "DAT"):
|
||||
al = []
|
||||
for a in inst.args:
|
||||
if type(a) == str:
|
||||
al.extend([ord(x) for x in a])
|
||||
else:
|
||||
if step == 1:
|
||||
al.append(a)
|
||||
else:
|
||||
al.append(a.eval(ctx))
|
||||
if step > 1:
|
||||
print(ctx['.addr'], al)
|
||||
al.append(a.simplify(ctx))
|
||||
ctx['.addr'] += len(al)
|
||||
return al
|
||||
elif type(inst) == ASM:
|
||||
try:
|
||||
if type(inst.a) == Expr:
|
||||
inst.a = inst.a.eval(ctx)
|
||||
inst.a = inst.a.simplify(ctx)
|
||||
if type(inst.b) == Expr:
|
||||
inst.b = inst.b.eval(ctx)
|
||||
except KeyError as e:
|
||||
if step != 1:
|
||||
raise e
|
||||
inst.b = inst.b.simplify(ctx)
|
||||
if inst.b is not None:
|
||||
print(f"{ctx['.addr']} {inst.op} {inst.b}, {inst.a} [len={inst.words()}]")
|
||||
else:
|
||||
print(f"{ctx['.addr']} {inst.op} {inst.a} [len={inst.words()}]")
|
||||
|
||||
ctx['.addr'] += inst.words()
|
||||
|
||||
if step != 1:
|
||||
return inst.code()
|
||||
|
||||
|
||||
|
@ -392,20 +368,30 @@ if __name__ == '__main__':
|
|||
import sys
|
||||
sym = {}
|
||||
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)
|
||||
assemble(sym, inst)
|
||||
a = sym['.addr']
|
||||
c = assemble(sym, inst)
|
||||
if c is not None:
|
||||
insns.append((a, c))
|
||||
print(sym)
|
||||
print(insns)
|
||||
sym['.addr'] = 0
|
||||
binimage = b''
|
||||
for inst in code: # pylint: disable=E1133
|
||||
a = assemble(sym, inst, 2)
|
||||
if a is not None:
|
||||
print(["%04x" % x for x in a])
|
||||
for w in a:
|
||||
for a, c in insns: # pylint: disable=E1133
|
||||
words = []
|
||||
for w in c:
|
||||
if type(w) == int:
|
||||
words.append(w)
|
||||
else:
|
||||
words.append(w.eval(sym))
|
||||
if words:
|
||||
print(["%04x" % x for x in words])
|
||||
for w in words:
|
||||
binimage += struct.pack("<H", w)
|
||||
outfilename = filename[:filename.rfind('.')]+'.bin'
|
||||
with open(outfilename, 'wb') as binfile:
|
||||
|
|
Loading…
Reference in New Issue