diff options
-rw-r--r-- | src/inst.c | 26 | ||||
-rw-r--r-- | src/inst.h | 20 | ||||
-rw-r--r-- | src/runtime.c | 77 |
3 files changed, 110 insertions, 13 deletions
@@ -132,6 +132,24 @@ const char *opcode_as_cstr(opcode_t code) case OP_JUMP_REGISTER: return "JUMP_REGISTER"; break; + case OP_PRINT_CHAR: + return "PRINT_CHAR"; + break; + case OP_PRINT_BYTE: + return "PRINT_BYTE"; + break; + case OP_PRINT_INT: + return "PRINT_INT"; + break; + case OP_PRINT_HWORD: + return "PRINT_HWORD"; + break; + case OP_PRINT_LONG: + return "PRINT_LONG"; + break; + case OP_PRINT_WORD: + return "PRINT_WORD"; + break; case OP_HALT: return "HALT"; break; @@ -186,7 +204,7 @@ word convert_bytes_to_word(byte *bytes) void inst_print(inst_t instruction, FILE *fp) { - static_assert(NUMBER_OF_OPCODES == 37, "inst_bytecode_size: Out of date"); + static_assert(NUMBER_OF_OPCODES == 43, "inst_bytecode_size: Out of date"); fprintf(fp, "%s(", opcode_as_cstr(instruction.opcode)); if (OPCODE_IS_TYPE(instruction.opcode, OP_PUSH)) { @@ -215,7 +233,7 @@ void inst_print(inst_t instruction, FILE *fp) size_t inst_bytecode_size(inst_t inst) { - static_assert(NUMBER_OF_OPCODES == 37, "inst_bytecode_size: Out of date"); + static_assert(NUMBER_OF_OPCODES == 43, "inst_bytecode_size: Out of date"); size_t size = 1; // for opcode if (OPCODE_IS_TYPE(inst.opcode, OP_PUSH)) { @@ -240,7 +258,7 @@ size_t inst_bytecode_size(inst_t inst) void inst_write_bytecode(inst_t inst, darr_t *darr) { - static_assert(NUMBER_OF_OPCODES == 37, "inst_write_bytecode: Out of date"); + static_assert(NUMBER_OF_OPCODES == 43, "inst_write_bytecode: Out of date"); // Append opcode darr_append_byte(darr, inst.opcode); // Then append 0 or more operands @@ -313,7 +331,7 @@ data_t read_type_from_darr(darr_t *darr, data_type_t type) inst_t inst_read_bytecode(darr_t *darr) { - static_assert(NUMBER_OF_OPCODES == 37, "inst_read_bytecode: Out of date"); + static_assert(NUMBER_OF_OPCODES == 43, "inst_read_bytecode: Out of date"); if (darr->used >= darr->available) return (inst_t){0}; inst_t inst = {0}; @@ -70,6 +70,14 @@ typedef enum OP_PLUS_HWORD, OP_PLUS_WORD, + // Simple I/O + OP_PRINT_CHAR, + OP_PRINT_BYTE, + OP_PRINT_INT, + OP_PRINT_HWORD, + OP_PRINT_LONG, + OP_PRINT_WORD, + // Program control flow OP_JUMP_ABS, OP_JUMP_STACK, @@ -127,12 +135,11 @@ inst_t *insts_read_bytecode_file(FILE *, size_t *); #define INST_DUP(TYPE, OP) \ ((inst_t){.opcode = OP_DUP_##TYPE, .operand = DWORD(OP)}) -#define INST_NOT(TYPE) ((inst_t){.opcode = OP_NOT_##TYPE}) -#define INST_OR(TYPE) ((inst_t){.opcode = OP_OR_##TYPE}) -#define INST_AND(TYPE) ((inst_t){.opcode = OP_AND_##TYPE}) -#define INST_XOR(TYPE) ((inst_t){.opcode = OP_XOR_##TYPE}) -#define INST_EQ(TYPE) ((inst_t){.opcode = OP_EQ_##TYPE}) - +#define INST_NOT(TYPE) ((inst_t){.opcode = OP_NOT_##TYPE}) +#define INST_OR(TYPE) ((inst_t){.opcode = OP_OR_##TYPE}) +#define INST_AND(TYPE) ((inst_t){.opcode = OP_AND_##TYPE}) +#define INST_XOR(TYPE) ((inst_t){.opcode = OP_XOR_##TYPE}) +#define INST_EQ(TYPE) ((inst_t){.opcode = OP_EQ_##TYPE}) #define INST_PLUS(TYPE) ((inst_t){.opcode = OP_PLUS_##TYPE}) #define INST_JUMP_ABS(OP) \ @@ -140,4 +147,5 @@ inst_t *insts_read_bytecode_file(FILE *, size_t *); #define INST_JUMP_STACK ((inst_t){.opcode = OP_JUMP_STACK}) #define INST_JUMP_REGISTER ((inst_t){.opcode = OP_JUMP_REGISTER}) +#define INST_PRINT(TYPE) ((inst_t){.opcode = OP_PRINT_##TYPE}) #endif diff --git a/src/runtime.c b/src/runtime.c index ac1cf58..f653ac3 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -11,6 +11,7 @@ */ #include <assert.h> +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -54,7 +55,7 @@ const char *err_as_cstr(err_t err) err_t vm_execute(vm_t *vm) { - static_assert(NUMBER_OF_OPCODES == 37, "vm_execute: Out of date"); + static_assert(NUMBER_OF_OPCODES == 43, "vm_execute: Out of date"); struct Program *prog = &vm->program; if (prog->ptr >= prog->max) return ERR_END_OF_PROGRAM; @@ -135,12 +136,82 @@ err_t vm_execute(vm_t *vm) return ERR_INVALID_PROGRAM_ADDRESS; prog->ptr = addr; } + else if (instruction.opcode >= OP_PRINT_CHAR && + instruction.opcode <= OP_PRINT_WORD) + { + data_t datum = {0}; + enum + { + TYPE_CHAR, + TYPE_BYTE, + TYPE_INT, + TYPE_HWORD, + TYPE_LONG, + TYPE_WORD + } print_type; + err_t err = ERR_OK; + if (instruction.opcode == OP_PRINT_BYTE || + instruction.opcode == OP_PRINT_CHAR) + { + print_type = instruction.opcode == OP_PRINT_BYTE ? TYPE_BYTE : TYPE_CHAR; + err = vm_pop_byte(vm, &datum); + } + else if (instruction.opcode == OP_PRINT_HWORD || + instruction.opcode == OP_PRINT_INT) + { + print_type = instruction.opcode == OP_PRINT_HWORD ? TYPE_HWORD : TYPE_INT; + err = vm_pop_hword(vm, &datum); + } + else if (instruction.opcode == OP_PRINT_WORD || + instruction.opcode == OP_PRINT_LONG) + { + print_type = instruction.opcode == OP_PRINT_WORD ? TYPE_WORD : TYPE_LONG; + err = vm_pop_word(vm, &datum); + } + + if (err) + return err; + + switch (print_type) + { + case TYPE_CHAR: { + char c = 0; + memcpy(&c, &datum.as_byte, 1); + printf("%c", c); + break; + } + case TYPE_BYTE: + printf("0x%x", datum.as_byte); + break; + case TYPE_INT: { + int32_t i = 0; + memcpy(&i, &datum.as_hword, HWORD_SIZE); + printf("%" PRId32, i); + break; + } + case TYPE_HWORD: + printf("%" PRIu32, datum.as_hword); + break; + case TYPE_LONG: { + int64_t i = 0; + memcpy(&i, &datum.as_word, WORD_SIZE); + printf("%" PRId64, i); + break; + } + case TYPE_WORD: + printf("%" PRIu64, datum.as_word); + break; + } + + prog->ptr++; + } else if (instruction.opcode == OP_HALT) { // Do nothing here. Should be caught by callers of vm_execute - return ERR_OK; } - return ERR_INVALID_OPCODE; + else + return ERR_INVALID_OPCODE; + return ERR_OK; } err_t vm_execute_all(vm_t *vm) |