comments and negative immediates

This commit is contained in:
Peter McGoron 2023-02-11 17:04:17 +00:00
parent 582a0a2c9a
commit 15fb92e502
4 changed files with 64 additions and 15 deletions

View File

@ -5,15 +5,38 @@ from enum import Enum
class MalformedArgument(Exception): class MalformedArgument(Exception):
pass 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 ArgType(Enum):
""" Class denoting the type of an argument to an instruction. """
IMM = 1 IMM = 1
""" Immediate values are ones that must be numbers (positive or negative). """
REG = 2 REG = 2
""" Type of registers. """
VAL = 3 VAL = 3
""" Type that denotes either immediate values or registers. """
LAB = 4 LAB = 4
""" Type of labels. """
def gettype(s): 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(): if s.isnumeric():
return (ArgType.IMM, int(s)) 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(): elif s[0] == 'r' and s[1:].isnumeric():
return (ArgType.REG, int(s[1:])) return (ArgType.REG, int(s[1:]))
elif s[0] == 'l' and s[1:].isnumeric(): elif s[0] == 'l' and s[1:].isnumeric():
@ -22,6 +45,8 @@ class ArgType(Enum):
raise MalformedArgument(s) raise MalformedArgument(s)
def typecheck(self, 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) t = ArgType.gettype(s)
if self == ArgType.VAL: if self == ArgType.VAL:
if t[0] == ArgType.REG or t[0] == ArgType.IMM: if t[0] == ArgType.REG or t[0] == ArgType.IMM:
@ -50,7 +75,11 @@ class TypecheckException(Exception):
self.opcode = opcode self.opcode = opcode
def __str__(self): def __str__(self):
return f'opcode {self.opcode} has invalid value {self.sarg} (expected {self.argtype} in position {self.i}' return f'opcode {self.opcode} has invalid value {self.sarg} (expected {self.argtype} in position {self.i}'
class Instruction(Enum): 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 NOP = 0
PUSH = 1, ArgType.VAL PUSH = 1, ArgType.VAL
POP = 2, ArgType.REG POP = 2, ArgType.REG
@ -67,7 +96,10 @@ class Instruction(Enum):
self.opcode = opcode self.opcode = opcode
self.argtypes = args self.argtypes = args
def typecheck(self, sargs): def typecheck(self, sargs):
""" Pass arguments to the instruction and check if the
arguments are correct. """
rargs = [] rargs = []
if len(sargs) != len(self.argtypes): if len(sargs) != len(self.argtypes):
raise TypecheckLenException(self.opcode, sargs, raise TypecheckLenException(self.opcode, sargs,
@ -129,10 +161,12 @@ def encode_pseudo_utf8(n, high_bits, to):
class RangeCheckException(Exception): class RangeCheckException(Exception):
pass pass
class Line: class Line:
def __init__(self, opcode, args, labnum, regnum): def __init__(self, opcode, args):
self.opcode = opcode self.opcode = opcode
self.args = args 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[0] == ArgType.REG:
if a[1] < 0 or a[1] >= regnum: if a[1] < 0 or a[1] >= regnum:
raise RangeCheckException(a[0], raise RangeCheckException(a[0],
@ -158,7 +192,9 @@ class InstructionNotFoundException(Exception):
pass pass
class Program: class Program:
def asm_push_line(self, ins, args): 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): def parse_asm_line(self, line):
line = line.split() line = line.split()
@ -182,3 +218,4 @@ class Program:
self.asm = [] self.asm = []
self.labnum = labnum self.labnum = labnum
self.regnum = regnum self.regnum = regnum

View File

@ -143,5 +143,16 @@ class ProgramTest(unittest.TestCase):
self.assertEqual(ex.cenv.reg[0], 6) self.assertEqual(ex.cenv.reg[0], 6)
self.assertEqual(ex.cenv.reg[1], 5) self.assertEqual(ex.cenv.reg[1], 5)
def test_exec_add(self):
p = Program()
p.parse_asm_line("add r0 10 20")
p.parse_asm_line("add r1 5 0")
p.parse_asm_line("add r1 r0 -40")
ex = ffi.Environment()
self.assertEqual(ex.load(p()), ffi.CompileRet.OK)
self.assertEqual(ex(), ffi.RunRet.STOP)
self.assertEqual(ex.cenv.reg[0], 30)
self.assertEqual(ex.cenv.reg[1], word_2c(10))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -448,17 +448,18 @@ creole_compile(struct creole_env *env, struct creole_reader *r)
return CREOLE_COMPILE_OK; return CREOLE_COMPILE_OK;
} }
enum creole_run_ret creole_reg_write(struct creole_env *env, enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg,
creole_word w, unsigned reg) creole_word w)
{ {
if (!valid_register(env, reg)) if (!valid_register(env, reg)) {
return CREOLE_REGISTER_OVERFLOW; return CREOLE_REGISTER_OVERFLOW;
}
env->reg[reg] = w; env->reg[reg] = w;
return CREOLE_STEP_CONTINUE; return CREOLE_STEP_CONTINUE;
} }
enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w, enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg,
unsigned reg) creole_word *w)
{ {
if (!valid_register(env, reg)) if (!valid_register(env, reg))
return CREOLE_REGISTER_OVERFLOW; return CREOLE_REGISTER_OVERFLOW;
@ -472,7 +473,7 @@ static enum creole_run_ret read_val(struct creole_env *env,
creole_word *w) creole_word *w)
{ {
if (ins->w_flags[arg] == CREOLE_REGISTER) { if (ins->w_flags[arg] == CREOLE_REGISTER) {
return creole_reg_read(env, w, ins->w[arg]); return creole_reg_read(env, ins->w[arg], w);
} else { } else {
*w = ins->w[arg]; *w = ins->w[arg];
} }
@ -526,7 +527,7 @@ enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc)
break; break;
case CREOLE_POP: case CREOLE_POP:
check(creole_pop(env, &a1)); check(creole_pop(env, &a1));
check(creole_reg_write(env, a1, ins->w[0])); check(creole_reg_write(env, ins->w[0], a1));
break; break;
case CREOLE_ADD: case CREOLE_ADD:
check(read_val(env, ins, 1, &a1)); check(read_val(env, ins, 1, &a1));

View File

@ -91,10 +91,10 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r);
enum creole_compiler_ret enum creole_compiler_ret
creole_compile(struct creole_env *env, struct creole_reader *r); creole_compile(struct creole_env *env, struct creole_reader *r);
enum creole_run_ret creole_reg_write(struct creole_env *env, creole_word w, enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg,
unsigned reg); creole_word w);
enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w, enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg,
unsigned reg); creole_word *w);
enum creole_run_ret creole_push(struct creole_env *env, creole_word w); enum creole_run_ret creole_push(struct creole_env *env, creole_word w);
enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w); enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w);
enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc); enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc);