From 83c568c8dd060a8fb324aee33cdb030809dedbf3 Mon Sep 17 00:00:00 2001 From: Peter McGoron Date: Sat, 18 Feb 2023 05:55:04 +0000 Subject: [PATCH] add data, remove labels and make jumps absolute --- creole.c | 310 +++++++++++++++++++++++++------------------------------ creole.h | 46 ++++----- 2 files changed, 157 insertions(+), 199 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,12 +329,49 @@ 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 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 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; + case TYPE_REG: return fl == CREOLE_REGISTER + && valid_register(env, val); + case TYPE_VAL: return fl == CREOLE_IMMEDIATE + || fl == CREOLE_REGISTER; + default: return 0; + } +} + +static enum creole_word_flag arg_get_type(unsigned high_bits) +{ + if (high_bits & 1) { + return CREOLE_REGISTER; + } else { + return CREOLE_IMMEDIATE; + } +} + +static enum creole_compiler_ret +parse_line(struct creole_env *env, struct ins *ins, struct creole_reader *r) { struct word w = {0}; - unsigned arg = 0; + int i; + ins->start = r->p; if (!decode_seq(r, &w)) return CREOLE_OPCODE_READ_ERROR; @@ -344,15 +380,34 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r) return CREOLE_OPCODE_MALFORMED; } - for (arg = 0; arg < opcode_info[ins->opcode].arglen; arg++) { + if (opcode_info[ins->opcode].arglen >= CREOLE_MAX_ARG) + return CREOLE_OPCODE_MALFORMED; + for (i = 0; i < opcode_info[ins->opcode].arglen; i++) { 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; + 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) @@ -364,123 +419,40 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r) * High level compiling interface *************************************************************************/ -static int valid_register(struct creole_env *env, int reg) +static void +add_to_env(struct creole_env *env, struct ins *ins) { - 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 - && 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) -{ - if (high_bits & 1) { - return CREOLE_REGISTER; - } else { - return CREOLE_IMMEDIATE; - } -} - -static enum creole_compiler_ret typecheck_ins(struct creole_env *env, - struct creole_ins *ins) -{ - unsigned i; - - 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])) - return CREOLE_TYPE_ERROR; - } - return CREOLE_COMPILE_OK; -} - -static void clear_ins(struct creole_ins *i) -{ - 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) -{ - 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); + env->r_current = env->r_start; + + while (!read_eof(&env->r_current)) { + rcode = parse_line(env, &ins, &env->r_current); if (rcode != CREOLE_COMPILE_OK) return rcode; - - 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: - 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; } diff --git a/creole.h b/creole.h index b3fe29c..53e6ab7 100644 --- a/creole.h +++ b/creole.h @@ -41,11 +41,11 @@ enum creole_opcode { CREOLE_MUL, CREOLE_DIV, CREOLE_SYS, - CREOLE_CLB, CREOLE_JL, CREOLE_JLE, CREOLE_JE, CREOLE_JNE, + CREOLE_DB, CREOLE_OPCODE_LEN }; @@ -63,7 +63,7 @@ enum creole_compiler_ret { CREOLE_ARG_MALFORMED, CREOLE_LAST_READ_ERROR, CREOLE_LAST_MALFORMED, - CREOLE_LABEL_OVERFLOW, + CREOLE_DATA_OVERFLOW, CREOLE_TYPE_ERROR, CREOLE_COMPILE_CLEARED_INSTRUCTION, CREOLE_PROGRAM_OVERFLOW, @@ -76,45 +76,37 @@ enum creole_run_ret { CREOLE_STEP_STOP, CREOLE_STACK_OVERFLOW, CREOLE_STACK_UNDERFLOW, - CREOLE_RUN_LABEL_OVERFLOW, + CREOLE_RUN_DECODE_ERROR, CREOLE_REGISTER_OVERFLOW, CREOLE_STEP_UNKNOWN_OPCODE, CREOLE_DIV_BY_ZERO, CREOLE_STEP_HIGH_BIT_MALFORMED, + CREOLE_JUMP_OVERFLOW, CREOLE_RUN_RET_LEN }; -struct creole_ins { - enum creole_opcode opcode; - unsigned char w_flags[3]; - creole_word w[3]; -}; - -struct creole_env { - creole_word *reg; - size_t reglen; - - size_t *lab; - size_t lablen; - - creole_word *stk; - size_t stkptr, stklen; - - struct creole_ins *prg; - size_t prgptr, prgend, prglen; -}; - struct creole_reader { unsigned char *p; size_t left; }; +struct creole_env { + unsigned char **dats; + size_t datlen; + + creole_word *reg; + size_t reglen; + + creole_word *stk; + size_t stkptr, stklen; + + struct creole_reader r_current; + struct creole_reader r_start; +}; + int creole_encode(creole_word i, unsigned encode_to, unsigned high_bits, unsigned char buf[7]); -enum creole_compiler_ret -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_compiler_ret creole_compile(struct creole_env *env); enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg, creole_word w);