creole/asm.py

125 lines
3.0 KiB
Python
Raw Normal View History

2023-02-07 11:38:04 -05:00
#!/usr/bin/python3
from enum import Enum
class ArgType(Enum):
TYPE_IMM = 1
TYPE_REG = 2
TYPE_VAL = 3
TYPE_LAB = 4
def gettype(s):
if s.isnumeric():
return (TYPE_IMM, int(s))
2023-02-07 11:48:22 -05:00
elif s[0] == 'r' and s[1:].isnumeric():
2023-02-07 11:38:04 -05:00
return (TYPE_REG, int(s[1:]))
2023-02-07 11:48:22 -05:00
elif s[0] == 'l' and s[1:].isnumeric():
2023-02-07 11:38:04 -05:00
return (TYPE_LAB, int(s[1:]))
else:
return None
def typecheck(self, s):
2023-02-07 11:48:22 -05:00
t = ArgType.gettype(s)
2023-02-07 11:38:04 -05:00
if t is None:
return None
if self == TYPE_VAL:
return t[0] == TYPE_REG or t[0] == TYPE_IMM
else:
return t[0] == self
class Instruction:
def __init__(self, opcode, argtypes):
self.opcode = opcode
assert self.opcode < 0x80 and self.opcode >= 0
self.argtypes = argtypes
def typecheck(self, sargs):
rargs = []
if len(sargs) != len(self.argtypes):
return None
for i in range(0, len(sargs)):
if not self.argtypes[i].typecheck(sargs[i]):
return None
rargs.append(ArgType.gettype(sargs[i]))
return rargs
instructions = {
"NOP" : Instruction(0, []),
"PUSH" : Instruction(1, [ArgType.TYPE_REG]),
"POP" : Instruction(2, [ArgType.TYPE_REG]),
"ADD" : Instruction(3, [ArgType.TYPE_VAL, ArgType.TYPE_VAL, ArgType.TYPE_VAL]),
"MUL" : Instruction(4, [ArgType.TYPE_VAL, ArgType.TYPE_VAL, ArgType.TYPE_VAL]),
"DIV" : Instruction(5, [ArgType.TYPE_VAL, ArgType.TYPE_VAL, ArgType.TYPE_VAL]),
"JL" : Instruction(6, [ArgType.TYPE_LAB, ArgType.TYPE_VAL, ArgType.TYPE_VAL]),
"CLB" : Instruction(7, [ArgType.TYPE_LAB]),
"SYS" : Instruction(8, [ArgType.TYPE_VAL])
}
encoding_types = {
# start mask A B
2: (0x7F, 0xC0, 7),
3: (0xFFF, 0xE0, 12),
4: (0x1FFFF, 0xF0, 16),
5: (0x3FFFFF, 0xF8, 21),
6: (0x7FFFFFF, 0xFC, 26),
7: (0xFFFFFFFF, 0xFE, 36),
# A : number of bits in start byte
# B : Total number of bits excluding high bits
}
def encode_pseudo_utf8(n, high_bits, to):
if to > 8 or to < 0:
return None
elif to == 1:
if n < 0x80:
return bytes([n])
else:
return None
(maxval, start_byte, n_tot) = encoding_types[to]
if n > maxval or high_bits > 15:
return None
n = n | (high_bits << n_tot)
all_bytes = []
for i in range(0, to - 1):
all_bytes.append(0x80 | (n & 0x3F))
n >>= 6
all_bytes.append(start_byte | n)
return bytes(reversed(all_bytes))
class Line:
def __init__(self, opcode, args):
self.opcode = opcode
self.args = args
2023-02-07 11:48:22 -05:00
def __call__(self):
b = bytes([self.opcode])
for a in args:
if a[0] == TYPE_REG:
b = b + encode_pseudo_utf8(a[1],1,None)
else:
b = b + encode_pseudo_utf8(a[1],0,None)
return b + bytes([0])
2023-02-07 11:38:04 -05:00
class Program:
def asm_push_line(self, ins, args):
2023-02-07 11:48:22 -05:00
self.asm.append(Line(ins, args))
2023-02-07 11:38:04 -05:00
def parse_asm_line(self, line):
2023-02-07 11:48:22 -05:00
line = line.split()
2023-02-07 11:38:04 -05:00
if line[0] not in instructions:
raise Exception
else:
2023-02-07 11:48:22 -05:00
ins = instructions[line[0]]
args_w_type = ins.typecheck(line[1:])
2023-02-07 11:38:04 -05:00
if r is None:
raise Exception
2023-02-07 11:48:22 -05:00
self.asm_push_line(ins.opcode, args_w_type)
def __call__(self):
b = bytes()
for line in self.asm:
b = b + line()
return b
def __init__(self):
self.asm = []