Implement labels in assembler

This commit is contained in:
RunasSudo 2017-02-13 19:19:19 +10:30
parent d8f472a31f
commit 2982d12588
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 47 additions and 9 deletions

28
asm.py
View File

@ -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:

View File

@ -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:

View File

@ -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