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 + diff --git a/asm/test.py b/asm/test.py index ca54f59..e59d40c 100644 --- a/asm/test.py +++ b/asm/test.py @@ -143,5 +143,16 @@ class ProgramTest(unittest.TestCase): self.assertEqual(ex.cenv.reg[0], 6) 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__": unittest.main() diff --git a/creole.c b/creole.c index b482d1e..1fa6b11 100644 --- a/creole.c +++ b/creole.c @@ -448,17 +448,18 @@ creole_compile(struct creole_env *env, struct creole_reader *r) return CREOLE_COMPILE_OK; } -enum creole_run_ret creole_reg_write(struct creole_env *env, - creole_word w, unsigned reg) +enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg, + creole_word w) { - if (!valid_register(env, reg)) - return CREOLE_REGISTER_OVERFLOW; + if (!valid_register(env, reg)) { + return CREOLE_REGISTER_OVERFLOW; + } env->reg[reg] = w; return CREOLE_STEP_CONTINUE; } -enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w, - unsigned reg) +enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg, + creole_word *w) { if (!valid_register(env, reg)) return CREOLE_REGISTER_OVERFLOW; @@ -472,7 +473,7 @@ static enum creole_run_ret read_val(struct creole_env *env, creole_word *w) { 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 { *w = ins->w[arg]; } @@ -526,7 +527,7 @@ enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc) break; case CREOLE_POP: check(creole_pop(env, &a1)); - check(creole_reg_write(env, a1, ins->w[0])); + check(creole_reg_write(env, ins->w[0], a1)); break; case CREOLE_ADD: check(read_val(env, ins, 1, &a1)); diff --git a/creole.h b/creole.h index cb43e8b..ba10dda 100644 --- a/creole.h +++ b/creole.h @@ -91,10 +91,10 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r); enum creole_compiler_ret creole_compile(struct creole_env *env, struct creole_reader *r); -enum creole_run_ret creole_reg_write(struct creole_env *env, creole_word w, - unsigned reg); -enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w, - unsigned reg); +enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg, + creole_word w); +enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg, + 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_step(struct creole_env *env, creole_word *sc);