Skip to content

Commit

Permalink
Merge pull request #57 from TellowKrinkle/Labels
Browse files Browse the repository at this point in the history
Assembler: file and label support
  • Loading branch information
dougallj authored Apr 19, 2024
2 parents e8fca8a + 17211e3 commit 81dd556
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 11 deletions.
3 changes: 0 additions & 3 deletions applegpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -1595,14 +1595,11 @@ def encode_string(self, fields, opstr):
value = try_parse_integer(s[2:])
if value is not None:
masked = value & ((1 << self.size) - 1)
print('value', value, hex(masked))
if value != sign_extend(masked, self.size):
raise Exception('out of range BranchOffsetDesc %r' % (opstr,))
fields[self.name] = masked
print(fields)
return

# TODO: labels, somehow
raise Exception('invalid BranchOffsetDesc %r' % (opstr,))


Expand Down
86 changes: 78 additions & 8 deletions assemble.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import sys
import applegpu

# TODO: labels, file i/o
import disassemble

def begin_encoding(mnem, operand_strings):
for o in applegpu.instruction_descriptors:
Expand Down Expand Up @@ -34,12 +33,83 @@ def assemble_line(line):

return idesc.to_bytes(n)

def assemble_multiline(lines, print_asm=False):
seen_labels = {}
awaiting_labels = {}
output = bytearray()
try:
for line in lines:
line = line.strip()
if ':' in line and not ' ' in line[:line.index(':')]:
index = line.index(':')
label = line[:index].strip()
line = line[index+1:].strip()
pc = seen_labels[label] = len(output)
if label in awaiting_labels:
for (target, offset, size, text) in awaiting_labels[label]:
asm = assemble_line(text.replace(f'pc+{label}', f'pc+{pc-offset}'))
if len(asm) != size:
raise ValueError(f'Instruction "{text}" was a different size before setting the label vs after ({len(asm)} != {size})')
output[offset:offset+size] = asm
del awaiting_labels[label]
if not line:
continue
if 'pc+' in line and not line[line.index('pc+') + 3].isdigit():
index = line.index('pc+')
label = line[index + 3:].partition(',')[0]
if ' ' in label:
raise ValueError(f'Bad label "{label}" (cannot contain spaces)')
offset = len(output)
if label in seen_labels:
output.extend(assemble_line(line.replace(f'pc+{label}', f'pc-{offset-seen_labels[label]}')))
else:
asm = assemble_line(line.replace(f'pc+{label}', 'pc+0'))
if not label in awaiting_labels:
awaiting_labels[label] = []
awaiting_labels[label].append((label, offset, len(asm), line))
output.extend(asm)
else:
output.extend(assemble_line(line))
finally:
if print_asm:
disassemble.disassemble(output)
if awaiting_labels:
missing = ', '.join(awaiting_labels.keys())
raise ValueError(f'Missing required labels: {missing}')
return output


if __name__ == '__main__':
def printUsageAndExit():
print('Usage: python3 asssemble.py ([instruction text separated by semicolons] | -i ifile.S [-o ofile.bin] [-quiet])')
exit(1)
if len(sys.argv) > 1:
inp = ' '.join(sys.argv[1:]).split(';')
for line in inp:
asm_bytes = assemble_line(line)
print(asm_bytes.hex().ljust(32), applegpu.disassemble_bytes(asm_bytes))
if sys.argv[1].startswith('-'):
args = sys.argv[1:]
ifile = None
ofile = None
quiet = False
while args:
arg = args.pop(0)
if arg == '-i':
ifile = args.pop(0)
elif arg == '-o':
ofile = args.pop(0)
elif arg == '-quiet':
quiet = True
else:
print(f'Unrecognized argument {arg}')
printUsageAndExit()
if not ifile:
print('Input file required')
printUsageAndExit()
with open(ifile, 'r') as file:
asm = assemble_multiline(file, print_asm=not quiet)
if ofile:
with open(ofile, 'wb') as file:
file.write(asm)
else:
inp = ' '.join(sys.argv[1:]).split(';')
assemble_multiline(inp, print_asm=True)
else:
print('usage: python3 asssemble.py [instruction text separated by semicolons]')
exit(1)
printUsageAndExit()

0 comments on commit 81dd556

Please sign in to comment.