Made while drunk because zombie kept giving me shitty bytecode

Kill me now
This commit is contained in:
Thomas Muller 2021-11-06 00:22:19 -04:00
commit 61db978eae
Signed by untrusted user: thomas
GPG key ID: AF006EB730564952

155
zasm.py Normal file
View file

@ -0,0 +1,155 @@
class Things:
opcodes = {
'nop': 0x00,
'hlt': 0x01,
'ld': 0x04,
'push': 0x05,
'pop': 0x06,
'jmp': 0x07,
'jz': 0x08,
'cmp': 0x09,
'inc': 0x0A,
'dec': 0x0B,
'addi': 0x0C,
'subi': 0x0D,
'add': 0x0E,
'sub': 0x0F,
'muli': 0x10,
'divi': 0x11,
'mul': 0x12,
'div': 0x13,
'test': 0x16,
'prt': 0x17,
'je': 0x08,
}
registers = {
'ip': 0x00,
'sp': 0x01,
'flags': 0x03,
'a': 0x04,
'b': 0x05,
'c': 0x06,
'd': 0x07,
'r8': 0x08,
'r9': 0x09,
'r10': 0x0A,
'r11': 0x0B,
'r12': 0x0C,
'r13': 0x0D,
'r14': 0x0E,
'r15': 0x0F,
'r16': 0x10,
}
class ZASM:
def __init__(self):
self._out = []
self._pc = 0
self._org = 0
self._labels = {}
self._to_be_resolved = {}
def emit8(self, value):
self._out.append(value & 0xFF)
self._pc += 1
def emit16(self, value):
self._out.append((value & 0xFF00) >> 8)
self._out.append(value & 0xFF)
self._pc += 2
def set8(self, addr, value):
self._out[addr - self._org] = bytes([value & 0xFF])
def set16(self, addr, value):
print(self._out)
self._out[addr - self._org] = (value & 0xFF00) >> 8
self._out[addr - self._org + 1] = value & 0xFF
def assemble(self, path):
with open(path, 'r') as f:
lines = f.readlines()
line_no = 0
for line in lines:
# Strip away bullshit
line = line.replace(',', '')
line = line.replace('\n', '')
# Increment line number
line_no += 1
# Ignore blank lines and comments
if line == '':
continue
if line.startswith('#'):
continue
# Is it a label?
if not line.startswith(' '):
if line.startswith('org'):
self._pc = int(line.split(' ')[1], 16)
self._org = self._pc
else:
self._labels[line.split(':')[0]] = self._pc
# It is code
else:
line = line[4:]
chunks = line.split(' ')
if chunks[0] in Things.opcodes:
self.emit8(Things.opcodes[chunks[0]])
else:
print(f'Unknown opcode: {chunks[0]} at {line_no}: {line}')
break
# SUUUUPER dirty hack to do indirect addressing
#if chunks[1].startswith('[') and chunks[1].endswith(']'):
# self.set8(self._pc - 1, Things.opcodes[chunks[0]] - 2)
# chunk[1] = chunk[1][1:-1]
if len(chunks) == 1:
self.emit16(0)
elif chunks[1].startswith('#'):
self.emit16(int(chunks[1][1:]))
elif chunks[1] in Things.registers:
self.emit16(Things.registers[chunks[1]])
else:
self._to_be_resolved[self._pc] = (chunks[1], line_no, line)
self.emit16(0xDADA)
# print(f'Unknown register or invalid immediate: {chunks[1]!r}')
# break
# SUUUUPER dirty hack to do indirect addressing
#if chunks[2].startswith('[') and chunks[2].endswith(']'):
# self.set8(self._pc - 2, Things.opcodes[chunks[0]] - 2)
# chunk[2] = chunk[2][1:-1]
if len(chunks) <= 2:
self.emit8(0)
elif chunks[2] in Things.registers:
self.emit8(Things.registers[chunks[2]])
elif chunks[2].startswith('#'):
self.emit8(int(chunks[2][1:]))
else:
print(f'Invalid immediate: {chunks[2]} at {line_no}: {line}')
break
for loc, (label, line_no, line) in self._to_be_resolved.items():
print(loc, label, line_no, line)
print(self._labels)
if label in self._labels.keys():
self.set16(loc, self._labels[label])
else:
print(f'Failed to resolve {label} at {line_no}: {line}')
break
def write(self, path):
with open(path, 'wb') as f:
f.write(bytes(self._out))
self._out = b''
if __name__ == '__main__':
asm = ZASM()
asm.assemble('test.zasm')
asm.write('test.bin')