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