diff --git a/applegpu.py b/applegpu.py index a84e4b9..c19c224 100644 --- a/applegpu.py +++ b/applegpu.py @@ -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,)) diff --git a/assemble.py b/assemble.py index 1e58446..695186c 100644 --- a/assemble.py +++ b/assemble.py @@ -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: @@ -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()