aboutsummaryrefslogtreecommitdiffstats
path: root/asm/creole.py
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2023-02-11 17:04:17 +0000
committerGravatar Peter McGoron 2023-02-11 17:04:17 +0000
commit15fb92e5022eb6331806c6f9aeb8e0ca71fac6f2 (patch)
tree5bf313c4fea5632aadc50e4a50d54affb6d3c7bf /asm/creole.py
parentenable compiling and add compile test (diff)
comments and negative immediates
Diffstat (limited to 'asm/creole.py')
-rw-r--r--asm/creole.py43
1 files changed, 40 insertions, 3 deletions
diff --git a/asm/creole.py b/asm/creole.py
index 1d105a1..2092773 100644
--- a/asm/creole.py
+++ b/asm/creole.py
@@ -5,15 +5,38 @@ from enum import Enum
class MalformedArgument(Exception):
pass
+def word_2c(w):
+ """ Negate a non-negative integer using two's compliment. """
+ return (~w + 1) & 0xFFFFFFFF
+def ti(w):
+ """ Explicitly transform integer into two's compliment representation. """
+ return w if w >= 0 else word_wc(-w)
+
class ArgType(Enum):
+ """ Class denoting the type of an argument to an instruction. """
+
IMM = 1
+ """ Immediate values are ones that must be numbers (positive or negative). """
+
REG = 2
+ """ Type of registers. """
+
VAL = 3
+ """ Type that denotes either immediate values or registers. """
+
LAB = 4
+ """ Type of labels. """
def gettype(s):
+ """ Parses the type of the argument represented as a string
+ and returns a tuple with the first the first element being
+ the type and the second element being the integer value of
+ the argument.
+ """
if s.isnumeric():
return (ArgType.IMM, int(s))
+ elif s[0] == "-" and s[1:].isnumeric():
+ return (ArgType.IMM, word_2c(int(s[1:])))
elif s[0] == 'r' and s[1:].isnumeric():
return (ArgType.REG, int(s[1:]))
elif s[0] == 'l' and s[1:].isnumeric():
@@ -22,6 +45,8 @@ class ArgType(Enum):
raise MalformedArgument(s)
def typecheck(self, s):
+ """ Parses the type of the string and returns it if it fits
+ the type of the enum value. """
t = ArgType.gettype(s)
if self == ArgType.VAL:
if t[0] == ArgType.REG or t[0] == ArgType.IMM:
@@ -50,7 +75,11 @@ class TypecheckException(Exception):
self.opcode = opcode
def __str__(self):
return f'opcode {self.opcode} has invalid value {self.sarg} (expected {self.argtype} in position {self.i}'
+
class Instruction(Enum):
+ """ Class of microcode instructions. The first number is the opcode
+ and the suceeding values are the types of each of the
+ arguments. """
NOP = 0
PUSH = 1, ArgType.VAL
POP = 2, ArgType.REG
@@ -67,7 +96,10 @@ class Instruction(Enum):
self.opcode = opcode
self.argtypes = args
+
def typecheck(self, sargs):
+ """ Pass arguments to the instruction and check if the
+ arguments are correct. """
rargs = []
if len(sargs) != len(self.argtypes):
raise TypecheckLenException(self.opcode, sargs,
@@ -129,10 +161,12 @@ def encode_pseudo_utf8(n, high_bits, to):
class RangeCheckException(Exception):
pass
class Line:
- def __init__(self, opcode, args, labnum, regnum):
+ def __init__(self, opcode, args):
self.opcode = opcode
self.args = args
- for a in args:
+
+ def check_line(self, labnum, regnum):
+ for a in self.args:
if a[0] == ArgType.REG:
if a[1] < 0 or a[1] >= regnum:
raise RangeCheckException(a[0],
@@ -158,7 +192,9 @@ class InstructionNotFoundException(Exception):
pass
class Program:
def asm_push_line(self, ins, args):
- self.asm.append(Line(ins, args, self.labnum, self.regnum))
+ l = Line(ins, args)
+ l.check_line(self.labnum, self.regnum)
+ self.asm.append(l)
def parse_asm_line(self, line):
line = line.split()
@@ -182,3 +218,4 @@ class Program:
self.asm = []
self.labnum = labnum
self.regnum = regnum
+