aboutsummaryrefslogtreecommitdiffstats
path: root/creole.c
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2023-02-18 05:55:04 +0000
committerGravatar Peter McGoron 2023-02-18 05:55:04 +0000
commit83c568c8dd060a8fb324aee33cdb030809dedbf3 (patch)
tree3a0331b5352041d57eda345581754d448e9585e7 /creole.c
parentadd version defines (diff)
add data, remove labels and make jumps absolute
Diffstat (limited to 'creole.c')
-rw-r--r--creole.c298
1 files changed, 132 insertions, 166 deletions
diff --git a/creole.c b/creole.c
index 01b40c0..5b2d16d 100644
--- a/creole.c
+++ b/creole.c
@@ -30,7 +30,6 @@ enum creole_arg_type {
TYPE_IMM,
TYPE_REG,
TYPE_VAL,
- TYPE_LAB,
CREOLE_ARG_TYPE_LEN
};
@@ -40,7 +39,7 @@ enum creole_arg_type {
*/
#define defop(s, n, a1, a2, a3) {n, {a1, a2, a3}}
static const struct {
- unsigned arglen;
+ int arglen;
enum creole_arg_type argtype[CREOLE_MAX_ARG];
} opcode_info[CREOLE_OPCODE_LEN] = {
defop(NOOP, 0, TYPE_NONE, TYPE_NONE, TYPE_NONE),
@@ -50,11 +49,11 @@ static const struct {
defop(MUL, 3, TYPE_REG, TYPE_VAL, TYPE_VAL),
defop(DIV, 3, TYPE_REG, TYPE_VAL, TYPE_VAL),
defop(SYS, 1, TYPE_VAL, TYPE_NONE, TYPE_NONE),
- defop(CLB, 1, TYPE_LAB, TYPE_NONE, TYPE_NONE),
- defop(JL, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL),
- defop(JLE, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL),
- defop(JE, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL),
- defop(JNE, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL)
+ defop(JL, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL),
+ defop(JLE, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL),
+ defop(JE, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL),
+ defop(JNE, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL),
+ defop(DB, 1, TYPE_IMM, TYPE_NONE, TYPE_NONE)
};
/*************************************************************************
@@ -330,52 +329,22 @@ int creole_encode(creole_word i, unsigned encode_to, unsigned high_bits,
* one single byte of all zeros.
*************************************************************************/
-enum creole_compiler_ret
-creole_parse_line(struct creole_ins *ins, struct creole_reader *r)
-{
- struct word w = {0};
- unsigned arg = 0;
-
- if (!decode_seq(r, &w))
- return CREOLE_OPCODE_READ_ERROR;
-
- ins->opcode = w.word;
- if (w.word >= CREOLE_OPCODE_LEN || w.len != 1) {
- return CREOLE_OPCODE_MALFORMED;
- }
-
- for (arg = 0; arg < opcode_info[ins->opcode].arglen; arg++) {
- if (!decode_seq(r, &w))
- return CREOLE_ARG_READ_ERROR;
- if (w.len == 1)
- return CREOLE_ARG_MALFORMED;
- ins->w[arg] = w.word;
- ins->w_flags[arg] = w.high_bits;
- }
-
- if (!decode_seq(r, &w))
- return CREOLE_LAST_READ_ERROR;
- if (w.word != 0 || w.len != 1)
- return CREOLE_LAST_MALFORMED;
- return CREOLE_COMPILE_OK;
-}
-
-/**************************************************************************
- * High level compiling interface
- *************************************************************************/
+struct ins {
+ unsigned char *start;
+ unsigned char *datapt;
+ enum creole_opcode opcode;
+ creole_word w[CREOLE_MAX_ARG];
+ creole_word w_flags[CREOLE_MAX_ARG];
+};
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)
+static int typecheck_arg(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;
@@ -383,13 +352,11 @@ static int typecheck(struct creole_env *env, int val,
&& valid_register(env, val);
case TYPE_VAL: return fl == CREOLE_IMMEDIATE
|| fl == CREOLE_REGISTER;
- case TYPE_LAB: return fl == CREOLE_IMMEDIATE
- && valid_label(env, val);
default: return 0;
}
}
-static enum creole_word_flag get_type_from_high_bit(unsigned high_bits)
+static enum creole_word_flag arg_get_type(unsigned high_bits)
{
if (high_bits & 1) {
return CREOLE_REGISTER;
@@ -398,89 +365,94 @@ static enum creole_word_flag get_type_from_high_bit(unsigned high_bits)
}
}
-static enum creole_compiler_ret typecheck_ins(struct creole_env *env,
- struct creole_ins *ins)
+static enum creole_compiler_ret
+parse_line(struct creole_env *env, struct ins *ins, struct creole_reader *r)
{
- unsigned i;
+ struct word w = {0};
+ int i;
+
+ ins->start = r->p;
+ if (!decode_seq(r, &w))
+ return CREOLE_OPCODE_READ_ERROR;
+ ins->opcode = w.word;
+ if (w.word >= CREOLE_OPCODE_LEN || w.len != 1) {
+ return CREOLE_OPCODE_MALFORMED;
+ }
+
+ if (opcode_info[ins->opcode].arglen >= CREOLE_MAX_ARG)
+ return CREOLE_OPCODE_MALFORMED;
for (i = 0; i < opcode_info[ins->opcode].arglen; i++) {
- if (!typecheck(env, ins->w[i],
- get_type_from_high_bit(ins->w_flags[i]),
- opcode_info[ins->opcode].argtype[i]))
+ if (!decode_seq(r, &w))
+ return CREOLE_ARG_READ_ERROR;
+ if (w.len == 1)
+ return CREOLE_ARG_MALFORMED;
+ ins->w[i] = w.word;
+ ins->w_flags[i] = w.high_bits;
+
+ if (!typecheck_arg(env, ins->w[i],
+ arg_get_type(ins->w_flags[i]),
+ opcode_info[ins->opcode].argtype[i]))
return CREOLE_TYPE_ERROR;
}
+
+ if (ins->opcode == CREOLE_DB) {
+ ins->datapt = r->p;
+ do {
+ if (!decode_seq(r, &w))
+ return CREOLE_ARG_READ_ERROR;
+ } while (w.len != 1);
+ if (w.word != 0)
+ return CREOLE_LAST_READ_ERROR;
+ return CREOLE_COMPILE_OK;
+ }
+
+ ins->datapt = NULL;
+ if (!decode_seq(r, &w))
+ return CREOLE_LAST_READ_ERROR;
+ if (w.word != 0 || w.len != 1)
+ return CREOLE_LAST_MALFORMED;
return CREOLE_COMPILE_OK;
}
-static void clear_ins(struct creole_ins *i)
-{
- const struct creole_ins blank = {0};
- *i = blank;
-}
+/**************************************************************************
+ * High level compiling interface
+ *************************************************************************/
-/****
- * 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)
+static void
+add_to_env(struct creole_env *env, struct ins *ins)
{
- switch (cur_ins->opcode) {
- case CREOLE_CLB:
- if (cur_ins->w[0] >= env->lablen)
- return CREOLE_LABEL_OVERFLOW;
- env->lab[cur_ins->w[0]] = env->prgptr;
- /* Delete instruction because it is a compile time
- * instruction. Place next instruction in its place. */
- clear_ins(cur_ins);
- return CREOLE_COMPILE_CLEARED_INSTRUCTION;
- case CREOLE_NOOP:
- clear_ins(cur_ins);
- return CREOLE_COMPILE_CLEARED_INSTRUCTION;
+ switch (ins->opcode) {
+ case CREOLE_DB:
+ env->dats[ins->w[0]] = ins->datapt;
+ break;
default:
- return typecheck_ins(env, cur_ins);
+ ;
}
}
-/* TODO: The compile step can be completely removed in favor of directly
- * executing the bytecode, disassembling it with creole_parse_line()
- * at every instance. This will also make the implementation simpler.
- */
-
enum creole_compiler_ret
-creole_compile(struct creole_env *env, struct creole_reader *r)
+creole_compile(struct creole_env *env)
{
- struct creole_ins *cur_ins = env->prg;
+ struct ins ins = {0};
int rcode;
- while (env->prgptr < env->prglen) {
- rcode = creole_parse_line(cur_ins, r);
- if (rcode != CREOLE_COMPILE_OK)
- return rcode;
+ env->r_current = env->r_start;
- rcode = handle_compiletime_immediate(env, cur_ins);
- switch (rcode) {
- case CREOLE_COMPILE_CLEARED_INSTRUCTION:
- break;
- case CREOLE_COMPILE_OK:
- cur_ins++;
- env->prgptr++;
- break;
- default:
+ while (!read_eof(&env->r_current)) {
+ rcode = parse_line(env, &ins, &env->r_current);
+ if (rcode != CREOLE_COMPILE_OK)
return rcode;
- }
-
- if (read_eof(r))
- break;
+ add_to_env(env, &ins);
}
- if (env->prgptr == env->prglen && !read_eof(r))
- return CREOLE_PROGRAM_OVERFLOW;
- env->prgend = env->prgptr;
- env->prgptr = 0;
return CREOLE_COMPILE_OK;
}
+/**************************************************************************
+ * Running and interaction interface
+ *************************************************************************/
+
enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg,
creole_word w)
{
@@ -501,11 +473,11 @@ enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg,
}
static enum creole_run_ret read_val(struct creole_env *env,
- struct creole_ins *ins,
+ struct ins *ins,
unsigned arg,
creole_word *w)
{
- if (get_type_from_high_bit(ins->w_flags[arg]) == CREOLE_REGISTER) {
+ if (arg_get_type(ins->w_flags[arg]) == CREOLE_REGISTER) {
return creole_reg_read(env, ins->w[arg], w);
} else {
*w = ins->w[arg];
@@ -530,14 +502,6 @@ enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w)
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;
-}
-
enum argument_signed {
ALL_UNSIGNED = 0, /* 0b00 */
FIRST_SIGNED = 2, /* 0b10 */
@@ -556,8 +520,18 @@ static enum argument_signed check_sign_bits(unsigned flags1, unsigned flags2)
return rcode; \
} while(0)
+int creole_jump(struct creole_env *env, creole_word off)
+{
+ /* When env->r_start.left == off, this is the end of the program. */
+ if (env->r_start.left < off)
+ return 0;
+ env->r_current.p = env->r_start.p + off;
+ env->r_current.left = env->r_start.left - off;
+ return 1;
+}
+
#define chk_sign_op(OPER) do { \
- switch (check_sign_bits(ins->w_flags[1], ins->w_flags[2])) { \
+ switch (check_sign_bits(ins.w_flags[1], ins.w_flags[2])) { \
case ALL_UNSIGNED: \
a1 = a1 OPER a2; \
break; \
@@ -577,90 +551,82 @@ static enum argument_signed check_sign_bits(unsigned flags1, unsigned flags2)
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;
+ struct ins ins = {0};
+ creole_word a0, a1, a2;
int rcode = CREOLE_STEP_CONTINUE;
- int increase_pointer = 1;
- if (env->prgptr == env->prgend)
+ if (env->r_current.left == 0)
return CREOLE_STEP_STOP;
- switch (ins->opcode) {
+ if (parse_line(env, &ins, &env->r_current) != CREOLE_COMPILE_OK)
+ return CREOLE_RUN_DECODE_ERROR;
+
+ switch (ins.opcode) {
case CREOLE_PUSH:
- check(read_val(env, ins, 0, &a1));
+ check(read_val(env, &ins, 0, &a1));
check(creole_push(env, a1));
break;
case CREOLE_POP:
check(creole_pop(env, &a1));
- check(creole_reg_write(env, ins->w[0], a1));
+ check(creole_reg_write(env, ins.w[0], a1));
break;
case CREOLE_ADD:
- check(read_val(env, ins, 1, &a1));
- check(read_val(env, ins, 2, &a2));
- check(creole_reg_write(env, ins->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:
- check(read_val(env, ins, 1, &a1));
- check(read_val(env, ins, 2, &a2));
- check(creole_reg_write(env, ins->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:
- check(read_val(env, ins, 1, &a1));
- check(read_val(env, ins, 2, &a2));
+ check(read_val(env, &ins, 1, &a1));
+ check(read_val(env, &ins, 2, &a2));
if (a2 == 0) {
return CREOLE_DIV_BY_ZERO;
}
chk_sign_op(/);
- check(creole_reg_write(env, ins->w[0], a1));
+ check(creole_reg_write(env, ins.w[0], a1));
break;
case CREOLE_SYS:
- check(read_val(env, ins, 0, sc));
+ check(read_val(env, &ins, 0, sc));
rcode = CREOLE_STEP_SYSCALL;
break;
case CREOLE_JL:
- check(read_val(env, ins, 1, &a1));
- check(read_val(env, ins, 2, &a2));
- check(check_label(env, ins->w[0]));
+ check(read_val(env, &ins, 0, &a0));
+ check(read_val(env, &ins, 1, &a1));
+ check(read_val(env, &ins, 2, &a2));
chk_sign_op(<);
- if (a1) {
- env->prgptr = env->lab[ins->w[0]];
- increase_pointer = 0;
- }
+ if (a1 && !creole_jump(env, a0))
+ return CREOLE_JUMP_OVERFLOW;
break;
case CREOLE_JLE:
- check(read_val(env, ins, 1, &a1));
- check(read_val(env, ins, 2, &a2));
- check(check_label(env, ins->w[0]));
+ check(read_val(env, &ins, 0, &a0));
+ check(read_val(env, &ins, 1, &a1));
+ check(read_val(env, &ins, 2, &a2));
chk_sign_op(<=);
- if (a1) {
- env->prgptr = env->lab[ins->w[0]];
- increase_pointer = 0;
- }
+ if (a1 && !creole_jump(env, a0))
+ return CREOLE_JUMP_OVERFLOW;
break;
case CREOLE_JE:
- 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[ins->w[0]];
- increase_pointer = 0;
- }
+ check(read_val(env, &ins, 0, &a0));
+ check(read_val(env, &ins, 1, &a1));
+ check(read_val(env, &ins, 2, &a2));
+ if (a1 == a2 && !creole_jump(env, a0))
+ return CREOLE_JUMP_OVERFLOW;
break;
case CREOLE_JNE:
- 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[ins->w[0]];
- increase_pointer = 0;
- }
+ check(read_val(env, &ins, 0, &a0));
+ check(read_val(env, &ins, 1, &a1));
+ check(read_val(env, &ins, 2, &a2));
+ if (a1 != a2 && !creole_jump(env, a0))
+ return CREOLE_JUMP_OVERFLOW;
break;
default:
rcode = CREOLE_STEP_UNKNOWN_OPCODE;
}
- if (increase_pointer)
- env->prgptr++;
return rcode;
}