start assembler

This commit is contained in:
Peter McGoron 2023-02-07 16:38:04 +00:00
parent aa1ed8a06e
commit a7308280cb
2 changed files with 116 additions and 0 deletions

View File

@ -21,3 +21,10 @@ The first four bytes determine the type:
All other values are reserved. Overlong values are allowed, and for some
argument values they are necessary. All lines are terminated by a byte
of all zeros.
## Design Philsophy
Creole is small but not minimal. It is easy to add instructions, and
the amount of labels, registers, and stack space can changed at runtime.
System calls can be added dynamically, but static instructions that take
at most 3 arguments should be hard-coded.

109
asm.py Normal file
View File

@ -0,0 +1,109 @@
#!/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))
elif s[0] == 'r' and is_num(s[1:]):
return (TYPE_REG, int(s[1:]))
elif s[0] == 'l' and is_num(s[1:]):
return (TYPE_LAB, int(s[1:]))
else:
return None
def typecheck(self, s):
t = gettype(s)
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
def render(self):
class Program:
def asm_push_line(self, ins, args):
self.asm.append((ins, args))
def parse_asm_line(self, line):
line = line.split(' ')
if line[0] not in instructions:
raise Exception
else:
r = instructions[line[0]].typecheck(line[1:])
if r is None:
raise Exception
asm_push_instruction(instructions[line[0]].opcode, r)
"""