Implement labels in assembler
This commit is contained in:
parent
d8f472a31f
commit
2982d12588
28
asm.py
28
asm.py
@ -122,13 +122,35 @@ def assemble_instruction(source, tokens):
|
|||||||
if argstr.startswith('R'):
|
if argstr.startswith('R'):
|
||||||
# Register
|
# Register
|
||||||
arg = OpRegister(int(argstr[1:]))
|
arg = OpRegister(int(argstr[1:]))
|
||||||
|
elif argstr.startswith('$'):
|
||||||
|
# Label
|
||||||
|
arg = OpLabel(argstr[1:])
|
||||||
else:
|
else:
|
||||||
# Hex literal
|
# Hex literal
|
||||||
arg = OpLiteral(int(argstr, 16))
|
arg = OpLiteral(int(argstr, 16))
|
||||||
instruction.args.append(arg)
|
instruction.args.append(arg)
|
||||||
return [instruction], []
|
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
|
# Second pass
|
||||||
SYN_MEM = [0] * 32768
|
SYN_MEM = [0] * 32768
|
||||||
@ -137,11 +159,11 @@ SYN_PTR = 0
|
|||||||
with open(args.file, 'r') as source:
|
with open(args.file, 'r') as source:
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
instructions, labels = assemble_next_instruction(source)
|
instructions, inst_labels = assemble_next_instruction(source)
|
||||||
if instructions is None:
|
if instructions is None:
|
||||||
break
|
break
|
||||||
for instruction in instructions:
|
for instruction in instructions:
|
||||||
code = instruction.assemble()
|
code = instruction.assemble(labels)
|
||||||
SYN_MEM[SYN_PTR:SYN_PTR+len(code)] = code
|
SYN_MEM[SYN_PTR:SYN_PTR+len(code)] = code
|
||||||
SYN_PTR += len(code)
|
SYN_PTR += len(code)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
@ -172,7 +172,10 @@ while SYN_PTR < len(SYN_MEM):
|
|||||||
loc = op.get(None)
|
loc = op.get(None)
|
||||||
if any(v == loc for k, v in labels.items()):
|
if any(v == loc for k, v in labels.items()):
|
||||||
label = next(k for k, v in labels.items() if v == loc)
|
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:
|
else:
|
||||||
print('{:04x}: {}'.format(SYN_PTR, instruction.describe()))
|
print('{:04x}: {}'.format(SYN_PTR, instruction.describe()))
|
||||||
else:
|
else:
|
||||||
|
@ -33,7 +33,7 @@ class OpLiteral(Operand):
|
|||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return '{:04x}'.format(self.value)
|
return '{:04x}'.format(self.value)
|
||||||
def assemble(self):
|
def assemble(self, labels):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
class OpRegister(Operand):
|
class OpRegister(Operand):
|
||||||
@ -46,9 +46,22 @@ class OpRegister(Operand):
|
|||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return 'R{}'.format(self.register)
|
return 'R{}'.format(self.register)
|
||||||
def assemble(self):
|
def assemble(self, labels):
|
||||||
return self.register + 32768
|
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_opcode = {}
|
||||||
instructions_by_name = {}
|
instructions_by_name = {}
|
||||||
|
|
||||||
@ -74,8 +87,8 @@ class Instruction:
|
|||||||
description += ' {}'.format(self.args[i].describe())
|
description += ' {}'.format(self.args[i].describe())
|
||||||
return description
|
return description
|
||||||
|
|
||||||
def assemble(self):
|
def assemble(self, labels):
|
||||||
return [self.opcode] + [self.args[i].assemble() for i in range(self.nargs)]
|
return [self.opcode] + [self.args[i].assemble(labels) for i in range(self.nargs)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def next_instruction(data, idx):
|
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
|
# 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
|
# self.args is an array of literal values, rather than Operands
|
||||||
class InstructionData(Instruction):
|
class InstructionData(Instruction):
|
||||||
def assemble(self):
|
def assemble(self, labels):
|
||||||
return self.args
|
return self.args
|
||||||
instructions_by_name['data'] = InstructionData
|
instructions_by_name['data'] = InstructionData
|
||||||
|
Reference in New Issue
Block a user