aboutsummaryrefslogtreecommitdiff
path: root/src/inst.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/inst.c')
-rw-r--r--src/inst.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/inst.c b/src/inst.c
new file mode 100644
index 0000000..49d35d3
--- /dev/null
+++ b/src/inst.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 2023 Aryadev Chavali
+
+ * You may distribute and modify this code under the terms of the
+ * GPLv2 license. You should have received a copy of the GPLv2
+ * license with this file. If not, please write to:
+ * aryadev@aryadevchavali.com.
+
+ * Created: 2023-10-15
+ * Author: Aryadev Chavali
+ * Description: Implementation of bytecode for instructions
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "./inst.h"
+
+data_type_t get_opcode_data_type(opcode_t opcode)
+{
+ data_type_t type = DATA_TYPE_NIL;
+ if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH))
+ type = opcode >> 1;
+ else if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH_REGISTER))
+ type = opcode >> 2;
+ else if (OPCODE_IS_TYPE(opcode, OP_TYPE_POP))
+ type = opcode >> 3;
+ else if (OPCODE_IS_TYPE(opcode, OP_TYPE_MOV))
+ type = opcode >> 4;
+ return type;
+}
+
+size_t inst_bytecode_size(inst_t inst)
+{
+ size_t size = 1; // for opcode
+ if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH))
+ {
+ if (inst.opcode == OP_PUSH_BYTE)
+ ++size;
+ else if (inst.opcode == OP_PUSH_WORD)
+ size += sizeof(word);
+ else if (inst.opcode == OP_PUSH_FLOAT)
+ size += sizeof(f64);
+ }
+ else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH_REGISTER))
+ ++size;
+ else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_POP))
+ {
+ // No operand or register so leave as is
+ }
+ else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_MOV))
+ {
+ if (inst.opcode == OP_MOV_BYTE)
+ ++size;
+ else if (inst.opcode == OP_MOV_WORD)
+ size += sizeof(word);
+ else if (inst.opcode == OP_MOV_FLOAT)
+ size += sizeof(f64);
+ // For the register
+ ++size;
+ }
+ return size;
+}
+
+void inst_write_bytecode(inst_t inst, darr_t *darr)
+{
+ // Append opcode
+ darr_append_byte(darr, inst.opcode);
+ // Then append 0 or more operands
+ data_type_t to_append = DATA_TYPE_NIL;
+ if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH))
+ to_append = (data_type_t)inst.opcode;
+ else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH_REGISTER) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_TYPE_MOV))
+ to_append = DATA_TYPE_BYTE;
+
+ switch (to_append)
+ {
+ case DATA_TYPE_NIL:
+ break;
+ case DATA_TYPE_BYTE:
+ darr_append_byte(darr, inst.operand.as_byte);
+ break;
+ case DATA_TYPE_WORD:
+ darr_append_bytes(darr, (byte *)&inst.operand.as_word, sizeof(word));
+ break;
+ case DATA_TYPE_FLOAT:
+ darr_append_bytes(darr, (byte *)&inst.operand.as_float, sizeof(f64));
+ break;
+ }
+}
+
+data_t read_type_from_darr(darr_t *darr, data_type_t type)
+{
+ switch (type)
+ {
+ case DATA_TYPE_NIL:
+ break;
+ case DATA_TYPE_BYTE:
+ if (darr->used >= darr->available)
+ // TODO: Error (darr has no space left)
+ return DBYTE(0);
+ return DBYTE(darr->data[darr->used++]);
+ break;
+ case DATA_TYPE_WORD:
+ if (darr->used + sizeof(word) >= darr->available)
+ // TODO: Error (darr has no space left)
+ return DWORD(0);
+ word w = 0;
+ memcpy(&w, darr->data + darr->used, sizeof(w));
+ darr->used += sizeof(w);
+ return DWORD(w);
+ break;
+ case DATA_TYPE_FLOAT:
+ if (darr->used + sizeof(word) >= darr->available)
+ // TODO: Error (darr has no space left)
+ return DWORD(0);
+ f64 f = 0;
+ memcpy(&f, darr->data + darr->used, sizeof(f));
+ darr->used += sizeof(f);
+ return DFLOAT(f);
+ break;
+ }
+ // TODO: Error (unrecognised type)
+ return DBYTE(0);
+}
+
+inst_t inst_read_bytecode(darr_t *darr)
+{
+ if (darr->used >= darr->available)
+ return (inst_t){0};
+ inst_t inst = {0};
+ opcode_t opcode = darr->data[darr->used++];
+ if (opcode > OP_HALT)
+ // Translate to NOOP
+ return inst;
+ // Read operands
+ if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH))
+ inst.operand = read_type_from_darr(darr, get_opcode_data_type(opcode));
+ // Read register (as a byte)
+ if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH_REGISTER) ||
+ OPCODE_IS_TYPE(opcode, OP_TYPE_MOV))
+ inst.operand = read_type_from_darr(darr, DATA_TYPE_BYTE);
+ // Otherwise opcode doesn't take operands
+
+ return inst;
+}