enable compiling and add compile test
This commit is contained in:
parent
98bf49d931
commit
582a0a2c9a
25
asm/ffi.py
25
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):
|
||||
|
|
43
asm/test.py
43
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()
|
||||
|
|
148
creole.c
148
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
|
||||
|
|
20
creole.h
20
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 */
|
||||
|
|
Loading…
Reference in New Issue