ZASM
Made while drunk because zombie kept giving me shitty bytecode Kill me now
This commit is contained in:
commit
61db978eae
1 changed files with 155 additions and 0 deletions
155
zasm.py
Normal file
155
zasm.py
Normal 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')
|
Loading…
Reference in a new issue