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
|
LABEL_OVERFLOW = 7
|
||||||
TYPE_ERROR = 8
|
TYPE_ERROR = 8
|
||||||
CLEARED_INSTRUCTION = 9
|
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):
|
class CIns(Structure):
|
||||||
_fields_ = [("opcode", c_int),
|
_fields_ = [("opcode", c_int),
|
||||||
|
@ -76,6 +90,17 @@ class Environment:
|
||||||
ret = dll.creole_compile(byref(self.cenv), byref(rd))
|
ret = dll.creole_compile(byref(self.cenv), byref(rd))
|
||||||
return CompileRet(ret)
|
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):
|
class CParseLineException(Exception):
|
||||||
pass
|
pass
|
||||||
def parse_line(line):
|
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):
|
def test_compile_throw_pop_literal(self):
|
||||||
p = Program()
|
p = Program()
|
||||||
ex = ffi.Environment()
|
|
||||||
with self.assertRaises(TypecheckException) as cm:
|
with self.assertRaises(TypecheckException) as cm:
|
||||||
p.parse_asm_line("pop 6")
|
p.parse_asm_line("pop 6")
|
||||||
self.assertEqual(cm.exception.argtype, ArgType.REG)
|
self.assertEqual(cm.exception.argtype, ArgType.REG)
|
||||||
|
@ -108,7 +107,6 @@ class PopTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_compile_throw_pop_label(self):
|
def test_compile_throw_pop_label(self):
|
||||||
p = Program()
|
p = Program()
|
||||||
ex = ffi.Environment()
|
|
||||||
with self.assertRaises(TypecheckException) as cm:
|
with self.assertRaises(TypecheckException) as cm:
|
||||||
p.parse_asm_line("pop l9")
|
p.parse_asm_line("pop l9")
|
||||||
self.assertEqual(cm.exception.argtype, ArgType.REG)
|
self.assertEqual(cm.exception.argtype, ArgType.REG)
|
||||||
|
@ -128,45 +126,22 @@ class PopTest(unittest.TestCase):
|
||||||
p = Program()
|
p = Program()
|
||||||
with self.assertRaises(TypecheckLenException) as cm:
|
with self.assertRaises(TypecheckLenException) as cm:
|
||||||
p.parse_asm_line("push")
|
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.insargs, [])
|
||||||
self.assertEqual(cm.exception.argtypelen, 1)
|
self.assertEqual(cm.exception.argtypelen, 1)
|
||||||
|
|
||||||
class ProgramTest(unittest.TestCase):
|
class ProgramTest(unittest.TestCase):
|
||||||
def test_two(self):
|
def test_exec_simple_reg(self):
|
||||||
p = Program()
|
p = Program()
|
||||||
p.parse_asm_line("PUSH r1")
|
p.parse_asm_line("push 5")
|
||||||
p.parse_asm_line("ADD r1 5 6")
|
p.parse_asm_line("push 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("pop r0")
|
p.parse_asm_line("pop r0")
|
||||||
b_ex = b_ex + b'\x02\xC2\x80\x00'
|
|
||||||
p.parse_asm_line("pop r1")
|
p.parse_asm_line("pop r1")
|
||||||
b_ex = b_ex + b'\x02\xC2\x81\x00'
|
ex = ffi.Environment()
|
||||||
p.parse_asm_line("mul r2 r0 r1")
|
self.assertEqual(ex.load(p()), ffi.CompileRet.OK)
|
||||||
b_ex = b_ex + b'\x04\xC2\x82\xC2\x80\xC2\x81\x00'
|
self.assertEqual(ex(), ffi.RunRet.STOP)
|
||||||
p.parse_asm_line("push r2")
|
self.assertEqual(ex.cenv.reg[0], 6)
|
||||||
b_ex = b_ex + b'\x01\xC2\x82\x00'
|
self.assertEqual(ex.cenv.reg[1], 5)
|
||||||
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))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.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
|
* 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) {
|
switch (typ) {
|
||||||
case TYPE_IMM: return fl == CREOLE_IMMEDIATE;
|
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
|
case TYPE_VAL: return fl == CREOLE_IMMEDIATE
|
||||||
|| fl == CREOLE_REGISTER;
|
|| fl == CREOLE_REGISTER;
|
||||||
case TYPE_LAB: return fl == CREOLE_IMMEDIATE;
|
case TYPE_LAB: return fl == CREOLE_IMMEDIATE
|
||||||
|
&& valid_label(env, val);
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,7 +377,7 @@ static enum creole_compiler_ret typecheck_ins(struct creole_env *env,
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < opcode_info[ins->opcode].arglen; 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]))
|
opcode_info[ins->opcode].argtype[i]))
|
||||||
return CREOLE_TYPE_ERROR;
|
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)
|
static void clear_ins(struct creole_ins *i)
|
||||||
{
|
{
|
||||||
i->opcode = 0;
|
const struct creole_ins blank = {0};
|
||||||
i->w[0] = i->w[1] = i->w[2] = i->w_flags[0] =
|
*i = blank;
|
||||||
i->w_flags[1] = i->w_flags[2] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****
|
||||||
|
* Get rid of instructions that can be written out at compile time.
|
||||||
|
***/
|
||||||
static enum creole_compiler_ret
|
static enum creole_compiler_ret
|
||||||
handle_compiletime_immediate(struct creole_env *env,
|
handle_compiletime_immediate(struct creole_env *env,
|
||||||
struct creole_ins *cur_ins)
|
struct creole_ins *cur_ins)
|
||||||
|
@ -433,61 +448,118 @@ creole_compile(struct creole_env *env, struct creole_reader *r)
|
||||||
return CREOLE_COMPILE_OK;
|
return CREOLE_COMPILE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
enum creole_run_ret creole_reg_write(struct creole_env *env,
|
||||||
|
creole_word w, unsigned reg)
|
||||||
static creole_word read_word(struct creole_ins *ins, int i)
|
|
||||||
{
|
{
|
||||||
if (env->w_flags[i] == CREOLE_REGISTER)
|
if (!valid_register(env, reg))
|
||||||
return env->reg[env->w[i]];
|
return CREOLE_REGISTER_OVERFLOW;
|
||||||
else
|
env->reg[reg] = w;
|
||||||
return env->w[i];
|
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;
|
struct creole_ins *ins = env->prg + env->prgptr;
|
||||||
creole_word a1, a2;
|
creole_word a1, a2;
|
||||||
|
int rcode = CREOLE_STEP_CONTINUE;
|
||||||
|
|
||||||
if (env->prgptr == env->prgend)
|
if (env->prgptr == env->prgend)
|
||||||
return CREOLE_STEP_STOP;
|
return CREOLE_STEP_STOP;
|
||||||
env->prgptr++;
|
|
||||||
|
|
||||||
switch (ins->opcode) {
|
switch (ins->opcode) {
|
||||||
case CREOLE_PUSH:
|
case CREOLE_PUSH:
|
||||||
if (env->stkptr == env->stklen)
|
check(read_val(env, ins, 0, &a1));
|
||||||
return CREOLE_STACK_OVERFLOW;
|
check(creole_push(env, a1));
|
||||||
env->stk[env->stkptr++] = env->reg[env->w[0]];
|
|
||||||
break;
|
break;
|
||||||
case CREOLE_POP:
|
case CREOLE_POP:
|
||||||
if (env->stkptr == 0)
|
check(creole_pop(env, &a1));
|
||||||
return CREOLE_STACK_OVERFLOW;
|
check(creole_reg_write(env, a1, ins->w[0]));
|
||||||
env->reg[env->w[0]] = env->stk[--env->stkptr];
|
|
||||||
break;
|
break;
|
||||||
case CREOLE_ADD:
|
case CREOLE_ADD:
|
||||||
a1 = read_word(ins, 1);
|
check(read_val(env, ins, 1, &a1));
|
||||||
a2 = read_word(ins, 2);
|
check(read_val(env, ins, 2, &a2));
|
||||||
env->reg[env->w[0]] = a1 + a2;
|
check(creole_reg_write(env, ins->w[0], a1 + a2));
|
||||||
break;
|
break;
|
||||||
case CREOLE_MUL:
|
case CREOLE_MUL:
|
||||||
a1 = read_word(ins, 1);
|
check(read_val(env, ins, 1, &a1));
|
||||||
a2 = read_word(ins, 2);
|
check(read_val(env, ins, 2, &a2));
|
||||||
env->reg[env->w[0]] = a1 * a2;
|
check(creole_reg_write(env, ins->w[0], a1 * a2));
|
||||||
break;
|
break;
|
||||||
case CREOLE_DIV:
|
case CREOLE_DIV:
|
||||||
a1 = read_word(ins, 1);
|
check(read_val(env, ins, 1, &a1));
|
||||||
a2 = read_word(ins, 2);
|
check(read_val(env, ins, 2, &a2));
|
||||||
env->reg[env->w[0]] = a1 / a2;
|
check(creole_reg_write(env, ins->w[0], a1 / a2));
|
||||||
break;
|
break;
|
||||||
case CREOLE_JL:
|
case CREOLE_JL:
|
||||||
a1 = read_word(ins, 1);
|
check(read_val(env, ins, 1, &a1));
|
||||||
a2 = read_word(ins, 2);
|
check(read_val(env, ins, 2, &a2));
|
||||||
|
check(check_label(env, ins->w[0]));
|
||||||
if (a1 < a2)
|
if (a1 < a2)
|
||||||
env->prgptr = env->lab[env->w[0]];
|
env->prgptr = env->lab[ins->w[0]];
|
||||||
break;
|
break;
|
||||||
case SYS:
|
case CREOLE_SYS:
|
||||||
a1 = read_word(ins, 1);
|
check(read_val(env, ins, 0, sc));
|
||||||
/* do syscall */
|
rcode = CREOLE_STEP_SYSCALL;
|
||||||
break;
|
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
|
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 {
|
struct creole_ins {
|
||||||
enum creole_opcode opcode;
|
enum creole_opcode opcode;
|
||||||
unsigned char w_flags[3];
|
unsigned char w_flags[3];
|
||||||
|
@ -79,4 +91,12 @@ 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,
|
||||||
|
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 */
|
#endif /* CREOLE_H */
|
||||||
|
|
Loading…
Reference in New Issue