aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/inst.c26
-rw-r--r--src/inst.h20
-rw-r--r--src/runtime.c77
3 files changed, 110 insertions, 13 deletions
diff --git a/src/inst.c b/src/inst.c
index 72b2706..dbfb885 100644
--- a/src/inst.c
+++ b/src/inst.c
@@ -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};
diff --git a/src/inst.h b/src/inst.h
index e10d744..b9e0e9b 100644
--- a/src/inst.h
+++ b/src/inst.h
@@ -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)