From 582a0a2c9a476abe9dec3410ff4f555433ed9e0f Mon Sep 17 00:00:00 2001 From: Peter McGoron Date: Sat, 11 Feb 2023 14:28:43 +0000 Subject: [PATCH] enable compiling and add compile test --- asm/ffi.py | 25 +++++++++ asm/test.py | 43 ++++----------- creole.c | 148 ++++++++++++++++++++++++++++++++++++++-------------- creole.h | 20 +++++++ 4 files changed, 164 insertions(+), 72 deletions(-) diff --git a/asm/ffi.py b/asm/ffi.py index 39d9800..a1907c6 100644 --- a/asm/ffi.py +++ b/asm/ffi.py @@ -13,6 +13,20 @@ class CompileRet(Enum): LABEL_OVERFLOW = 7 TYPE_ERROR = 8 CLEARED_INSTRUCTION = 9 + PROGRAM_OVERFLOW = 10 + +class RunRet(Enum): + CONTINUE = 0 + SYSCALL = 1 + STOP = 2 + STACK_OVERFLOW = 3 + STACK_UNDERFLOW = 4 + RUN_LABEL_OVERFLOW = 5 + REGISTER_OVERFLOW = 6 + UNKNOWN_OPCODE = 7 + + def is_halt(self): + return not (self == RunRet.CONTINUE or self == RunRet.SYSCALL) class CIns(Structure): _fields_ = [("opcode", c_int), @@ -76,6 +90,17 @@ class Environment: ret = dll.creole_compile(byref(self.cenv), byref(rd)) return CompileRet(ret) + def syscall(self, sc): + pass + def __call__(self): + sc = c_size_t() + ret = RunRet.CONTINUE + while not ret.is_halt(): + ret = RunRet(dll.creole_step(byref(self.cenv), byref(sc))) + if ret == RunRet.SYSCALL: + self.syscall(sc) + return ret + class CParseLineException(Exception): pass def parse_line(line): diff --git a/asm/test.py b/asm/test.py index ba6d125..ca54f59 100644 --- a/asm/test.py +++ b/asm/test.py @@ -98,7 +98,6 @@ class PopTest(unittest.TestCase): def test_compile_throw_pop_literal(self): p = Program() - ex = ffi.Environment() with self.assertRaises(TypecheckException) as cm: p.parse_asm_line("pop 6") self.assertEqual(cm.exception.argtype, ArgType.REG) @@ -108,7 +107,6 @@ class PopTest(unittest.TestCase): def test_compile_throw_pop_label(self): p = Program() - ex = ffi.Environment() with self.assertRaises(TypecheckException) as cm: p.parse_asm_line("pop l9") self.assertEqual(cm.exception.argtype, ArgType.REG) @@ -128,45 +126,22 @@ class PopTest(unittest.TestCase): p = Program() with self.assertRaises(TypecheckLenException) as cm: p.parse_asm_line("push") - self.assertEqual(cm.exception.opcode, 2) + self.assertEqual(cm.exception.opcode, 1) self.assertEqual(cm.exception.insargs, []) self.assertEqual(cm.exception.argtypelen, 1) class ProgramTest(unittest.TestCase): - def test_two(self): + def test_exec_simple_reg(self): p = Program() - p.parse_asm_line("PUSH r1") - p.parse_asm_line("ADD r1 5 6") - b = p() - self.assertEqual(b, b'\x01\xC2\x81\x00\x03\xC2\x81\xC0\x85\xC0\x86\x00') - def test_label(self): - p = Program() - b_ex = bytes() - p.parse_asm_line("CLB l0") - b_ex = b_ex + b'\x07\xC0\x80\x00' + p.parse_asm_line("push 5") + p.parse_asm_line("push 6") p.parse_asm_line("pop r0") - b_ex = b_ex + b'\x02\xC2\x80\x00' p.parse_asm_line("pop r1") - b_ex = b_ex + b'\x02\xC2\x81\x00' - p.parse_asm_line("mul r2 r0 r1") - b_ex = b_ex + b'\x04\xC2\x82\xC2\x80\xC2\x81\x00' - p.parse_asm_line("push r2") - b_ex = b_ex + b'\x01\xC2\x82\x00' - p.parse_asm_line("push r2") - b_ex = b_ex + b'\x01\xC2\x82\x00' - p.parse_asm_line("jl l0 r2 10") - b_ex = b_ex + b'\x06\xC0\x80\xC2\x82\xC0\x8A\x00' - b = p() - self.assertEqual(b, b_ex) - - def test_parse_imm(self): - p = Program() - p.parse_asm_line("add r1 23 3648") - ins = ffi.parse_line(p()) - self.assertEqual(ins[0], Instruction.ADD.opcode) - self.assertEqual(ins[1][0], (1,1)) - self.assertEqual(ins[1][1], (0,23)) - self.assertEqual(ins[1][2], (0,3648)) + ex = ffi.Environment() + self.assertEqual(ex.load(p()), ffi.CompileRet.OK) + self.assertEqual(ex(), ffi.RunRet.STOP) + self.assertEqual(ex.cenv.reg[0], 6) + self.assertEqual(ex.cenv.reg[1], 5) if __name__ == "__main__": unittest.main() diff --git a/creole.c b/creole.c index 78beaa0..b482d1e 100644 --- a/creole.c +++ b/creole.c @@ -346,14 +346,27 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r) * High level compiling interface *************************************************************************/ -static int typecheck(enum creole_word_flag fl, enum creole_arg_type typ) +static int valid_register(struct creole_env *env, int reg) +{ + return reg < env->reglen; +} + +static int valid_label(struct creole_env *env, int reg) +{ + return reg < env->lablen; +} + +static int typecheck(struct creole_env *env, int val, + enum creole_word_flag fl, enum creole_arg_type typ) { switch (typ) { case TYPE_IMM: return fl == CREOLE_IMMEDIATE; - case TYPE_REG: return fl == CREOLE_REGISTER; + case TYPE_REG: return fl == CREOLE_REGISTER + && valid_register(env, val); case TYPE_VAL: return fl == CREOLE_IMMEDIATE || fl == CREOLE_REGISTER; - case TYPE_LAB: return fl == CREOLE_IMMEDIATE; + case TYPE_LAB: return fl == CREOLE_IMMEDIATE + && valid_label(env, val); default: return 0; } } @@ -364,7 +377,7 @@ static enum creole_compiler_ret typecheck_ins(struct creole_env *env, unsigned i; for (i = 0; i < opcode_info[ins->opcode].arglen; i++) { - if (!typecheck(ins->w_flags[i], + if (!typecheck(env, ins->w[i], ins->w_flags[i], opcode_info[ins->opcode].argtype[i])) return CREOLE_TYPE_ERROR; } @@ -373,11 +386,13 @@ static enum creole_compiler_ret typecheck_ins(struct creole_env *env, static void clear_ins(struct creole_ins *i) { - i->opcode = 0; - i->w[0] = i->w[1] = i->w[2] = i->w_flags[0] = - i->w_flags[1] = i->w_flags[2] = 0; + const struct creole_ins blank = {0}; + *i = blank; } +/**** + * Get rid of instructions that can be written out at compile time. + ***/ static enum creole_compiler_ret handle_compiletime_immediate(struct creole_env *env, struct creole_ins *cur_ins) @@ -433,61 +448,118 @@ creole_compile(struct creole_env *env, struct creole_reader *r) return CREOLE_COMPILE_OK; } -#if 0 - -static creole_word read_word(struct creole_ins *ins, int i) +enum creole_run_ret creole_reg_write(struct creole_env *env, + creole_word w, unsigned reg) { - if (env->w_flags[i] == CREOLE_REGISTER) - return env->reg[env->w[i]]; - else - return env->w[i]; + if (!valid_register(env, reg)) + return CREOLE_REGISTER_OVERFLOW; + env->reg[reg] = w; + return CREOLE_STEP_CONTINUE; } -int creole_step(struct creole_env *env) +enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w, + unsigned reg) +{ + if (!valid_register(env, reg)) + return CREOLE_REGISTER_OVERFLOW; + *w = env->reg[reg]; + return CREOLE_STEP_CONTINUE; +} + +static enum creole_run_ret read_val(struct creole_env *env, + struct creole_ins *ins, + unsigned arg, + creole_word *w) +{ + if (ins->w_flags[arg] == CREOLE_REGISTER) { + return creole_reg_read(env, w, ins->w[arg]); + } else { + *w = ins->w[arg]; + } + + return CREOLE_STEP_CONTINUE; +} + +enum creole_run_ret creole_push(struct creole_env *env, creole_word w) +{ + if (env->stkptr == env->stklen) + return CREOLE_STACK_OVERFLOW; + env->stk[env->stkptr++] = w; + return CREOLE_STEP_CONTINUE; +} + +enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w) +{ + if (env->stkptr == 0) + return CREOLE_STACK_UNDERFLOW; + *w = env->stk[--env->stkptr]; + return CREOLE_STEP_CONTINUE; +} + +static enum creole_run_ret +check_label(struct creole_env *env, creole_word label) +{ + return label < env->lablen + ? CREOLE_STEP_CONTINUE + : CREOLE_RUN_LABEL_OVERFLOW; +} + +#define check(fun) do { \ + rcode = fun; \ + if (rcode != CREOLE_STEP_CONTINUE) \ + return rcode; \ +} while(0) + +enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc) { struct creole_ins *ins = env->prg + env->prgptr; creole_word a1, a2; + int rcode = CREOLE_STEP_CONTINUE; if (env->prgptr == env->prgend) return CREOLE_STEP_STOP; - env->prgptr++; switch (ins->opcode) { case CREOLE_PUSH: - if (env->stkptr == env->stklen) - return CREOLE_STACK_OVERFLOW; - env->stk[env->stkptr++] = env->reg[env->w[0]]; + check(read_val(env, ins, 0, &a1)); + check(creole_push(env, a1)); break; case CREOLE_POP: - if (env->stkptr == 0) - return CREOLE_STACK_OVERFLOW; - env->reg[env->w[0]] = env->stk[--env->stkptr]; + check(creole_pop(env, &a1)); + check(creole_reg_write(env, a1, ins->w[0])); break; case CREOLE_ADD: - a1 = read_word(ins, 1); - a2 = read_word(ins, 2); - env->reg[env->w[0]] = a1 + a2; + check(read_val(env, ins, 1, &a1)); + check(read_val(env, ins, 2, &a2)); + check(creole_reg_write(env, ins->w[0], a1 + a2)); break; case CREOLE_MUL: - a1 = read_word(ins, 1); - a2 = read_word(ins, 2); - env->reg[env->w[0]] = a1 * a2; + check(read_val(env, ins, 1, &a1)); + check(read_val(env, ins, 2, &a2)); + check(creole_reg_write(env, ins->w[0], a1 * a2)); break; case CREOLE_DIV: - a1 = read_word(ins, 1); - a2 = read_word(ins, 2); - env->reg[env->w[0]] = a1 / a2; + check(read_val(env, ins, 1, &a1)); + check(read_val(env, ins, 2, &a2)); + check(creole_reg_write(env, ins->w[0], a1 / a2)); break; case CREOLE_JL: - a1 = read_word(ins, 1); - a2 = read_word(ins, 2); + check(read_val(env, ins, 1, &a1)); + check(read_val(env, ins, 2, &a2)); + check(check_label(env, ins->w[0])); if (a1 < a2) - env->prgptr = env->lab[env->w[0]]; + env->prgptr = env->lab[ins->w[0]]; break; - case SYS: - a1 = read_word(ins, 1); - /* do syscall */ + case CREOLE_SYS: + check(read_val(env, ins, 0, sc)); + rcode = CREOLE_STEP_SYSCALL; break; + default: + rcode = CREOLE_STEP_UNKNOWN_OPCODE; } + + env->prgptr++; + return rcode; } -#endif + +#undef check diff --git a/creole.h b/creole.h index 827fe82..cb43e8b 100644 --- a/creole.h +++ b/creole.h @@ -47,6 +47,18 @@ enum creole_compiler_ret { CREOLE_COMPILE_RET_LEN }; +enum creole_run_ret { + CREOLE_STEP_CONTINUE, + CREOLE_STEP_SYSCALL, + CREOLE_STEP_STOP, + CREOLE_STACK_OVERFLOW, + CREOLE_STACK_UNDERFLOW, + CREOLE_RUN_LABEL_OVERFLOW, + CREOLE_REGISTER_OVERFLOW, + CREOLE_STEP_UNKNOWN_OPCODE, + CREOLE_RUN_RET_LEN +}; + struct creole_ins { enum creole_opcode opcode; unsigned char w_flags[3]; @@ -79,4 +91,12 @@ 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_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); + #endif /* CREOLE_H */