aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAryadev Chavali <aryadev@aryadevchavali.com>2023-11-01 21:15:13 +0000
committerAryadev Chavali <aryadev@aryadevchavali.com>2023-11-01 21:38:52 +0000
commiteda49755bc91e03092dc1619d78cded126998d64 (patch)
treeb04b40ca8ece612b116be902071069d140c32084 /lib
parent4e64f1fe235ffaed6f2eb6fdb228b480c4dfcb1b (diff)
downloadovm-eda49755bc91e03092dc1619d78cded126998d64.tar.gz
ovm-eda49755bc91e03092dc1619d78cded126998d64.tar.bz2
ovm-eda49755bc91e03092dc1619d78cded126998d64.zip
Added instructions for allocating, setting, getting and deleting heap memory
One may allocate any number of (bytes|hwords|words), set or get some index from allocated memory, and delete heap memory. The idea is that all the relevant datums will be on the stack, so no register usage. This means no instructions should use register space at all (other than POP, which I'm debating about currently). Register space is purely for users.
Diffstat (limited to 'lib')
-rw-r--r--lib/inst.c63
-rw-r--r--lib/inst.h20
2 files changed, 71 insertions, 12 deletions
diff --git a/lib/inst.c b/lib/inst.c
index 85d25f2..6d46e19 100644
--- a/lib/inst.c
+++ b/lib/inst.c
@@ -69,6 +69,36 @@ const char *opcode_as_cstr(opcode_t code)
case OP_DUP_WORD:
return "DUP_WORD";
break;
+ case OP_MALLOC_BYTE:
+ return "MALLOC_BYTE";
+ break;
+ case OP_MALLOC_HWORD:
+ return "MALLOC_HWORD";
+ break;
+ case OP_MALLOC_WORD:
+ return "MALLOC_WORD";
+ break;
+ case OP_MSET_BYTE:
+ return "MSET_BYTE";
+ break;
+ case OP_MSET_HWORD:
+ return "MSET_HWORD";
+ break;
+ case OP_MSET_WORD:
+ return "MSET_WORD";
+ break;
+ case OP_MGET_BYTE:
+ return "MGET_BYTE";
+ break;
+ case OP_MGET_HWORD:
+ return "MGET_HWORD";
+ break;
+ case OP_MGET_WORD:
+ return "MGET_WORD";
+ break;
+ case OP_MDELETE:
+ return "MDELETE";
+ break;
case OP_NOT_BYTE:
return "NOT_BYTE";
break;
@@ -269,7 +299,7 @@ void data_print(data_t datum, data_type_t type, FILE *fp)
void inst_print(inst_t instruction, FILE *fp)
{
- static_assert(NUMBER_OF_OPCODES == 73, "inst_bytecode_size: Out of date");
+ static_assert(NUMBER_OF_OPCODES == 83, "inst_bytecode_size: Out of date");
fprintf(fp, "%s(", opcode_as_cstr(instruction.opcode));
if (OPCODE_IS_TYPE(instruction.opcode, OP_PUSH))
{
@@ -284,7 +314,10 @@ void inst_print(inst_t instruction, FILE *fp)
fprintf(fp, "reg=0x");
data_print(instruction.operand, DATA_TYPE_BYTE, fp);
}
- else if (OPCODE_IS_TYPE(instruction.opcode, OP_DUP))
+ else if (OPCODE_IS_TYPE(instruction.opcode, OP_DUP) ||
+ OPCODE_IS_TYPE(instruction.opcode, OP_MALLOC) ||
+ OPCODE_IS_TYPE(instruction.opcode, OP_MSET) ||
+ OPCODE_IS_TYPE(instruction.opcode, OP_MGET))
{
fprintf(fp, "n=%lu", instruction.operand.as_word);
}
@@ -299,7 +332,7 @@ void inst_print(inst_t instruction, FILE *fp)
size_t inst_bytecode_size(inst_t inst)
{
- static_assert(NUMBER_OF_OPCODES == 73, "inst_bytecode_size: Out of date");
+ static_assert(NUMBER_OF_OPCODES == 83, "inst_bytecode_size: Out of date");
size_t size = 1; // for opcode
if (OPCODE_IS_TYPE(inst.opcode, OP_PUSH))
{
@@ -312,10 +345,11 @@ size_t inst_bytecode_size(inst_t inst)
}
else if (OPCODE_IS_TYPE(inst.opcode, OP_PUSH_REGISTER) ||
OPCODE_IS_TYPE(inst.opcode, OP_MOV) ||
- inst.opcode == OP_JUMP_REGISTER)
- // Only need a byte for the register
- ++size;
- else if (OPCODE_IS_TYPE(inst.opcode, OP_DUP) || inst.opcode == OP_JUMP_ABS ||
+ OPCODE_IS_TYPE(inst.opcode, OP_DUP) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_MALLOC) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_MSET) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_MGET) || inst.opcode == OP_JUMP_ABS ||
+ inst.opcode == OP_JUMP_REGISTER ||
OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF))
size += WORD_SIZE;
return size;
@@ -323,7 +357,7 @@ size_t inst_bytecode_size(inst_t inst)
void inst_write_bytecode(inst_t inst, darr_t *darr)
{
- static_assert(NUMBER_OF_OPCODES == 73, "inst_write_bytecode: Out of date");
+ static_assert(NUMBER_OF_OPCODES == 83, "inst_write_bytecode: Out of date");
// Append opcode
darr_append_byte(darr, inst.opcode);
// Then append 0 or more operands
@@ -332,8 +366,11 @@ void inst_write_bytecode(inst_t inst, darr_t *darr)
to_append = (data_type_t)inst.opcode;
else if (OPCODE_IS_TYPE(inst.opcode, OP_PUSH_REGISTER) ||
OPCODE_IS_TYPE(inst.opcode, OP_MOV) ||
- inst.opcode == OP_JUMP_REGISTER || inst.opcode == OP_JUMP_ABS ||
OPCODE_IS_TYPE(inst.opcode, OP_DUP) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_MALLOC) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_MSET) ||
+ OPCODE_IS_TYPE(inst.opcode, OP_MGET) ||
+ inst.opcode == OP_JUMP_REGISTER || inst.opcode == OP_JUMP_ABS ||
OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF))
to_append = DATA_TYPE_WORD;
@@ -396,7 +433,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 == 73, "inst_read_bytecode: Out of date");
+ static_assert(NUMBER_OF_OPCODES == 83, "inst_read_bytecode: Out of date");
if (darr->used >= darr->available)
return (inst_t){0};
inst_t inst = {0};
@@ -409,8 +446,10 @@ inst_t inst_read_bytecode(darr_t *darr)
// Read register (as a byte)
else if (OPCODE_IS_TYPE(opcode, OP_PUSH_REGISTER) ||
OPCODE_IS_TYPE(opcode, OP_MOV) || opcode == OP_JUMP_REGISTER ||
- opcode == OP_JUMP_ABS || OPCODE_IS_TYPE(opcode, OP_DUP) ||
- OPCODE_IS_TYPE(opcode, OP_JUMP_IF))
+ OPCODE_IS_TYPE(opcode, OP_DUP) ||
+ OPCODE_IS_TYPE(opcode, OP_MALLOC) ||
+ OPCODE_IS_TYPE(opcode, OP_MSET) || OPCODE_IS_TYPE(opcode, OP_MGET) ||
+ opcode == OP_JUMP_ABS || OPCODE_IS_TYPE(opcode, OP_JUMP_IF))
inst.operand = read_type_from_darr(darr, DATA_TYPE_WORD);
// Otherwise opcode doesn't take operands
diff --git a/lib/inst.h b/lib/inst.h
index e36d1c3..29cbd55 100644
--- a/lib/inst.h
+++ b/lib/inst.h
@@ -44,6 +44,18 @@ typedef enum
OP_DUP_HWORD,
OP_DUP_WORD,
+ // Dealing with the heap
+ OP_MALLOC_BYTE,
+ OP_MALLOC_HWORD,
+ OP_MALLOC_WORD,
+ OP_MSET_BYTE,
+ OP_MSET_HWORD,
+ OP_MSET_WORD,
+ OP_MGET_BYTE,
+ OP_MGET_HWORD,
+ OP_MGET_WORD,
+ OP_MDELETE,
+
// Boolean operations
OP_NOT_BYTE,
OP_NOT_HWORD,
@@ -170,6 +182,14 @@ 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_MALLOC(TYPE, OP) \
+ ((inst_t){.opcode = OP_MALLOC_##TYPE, .operand = DWORD(OP)})
+#define INST_MSET(TYPE, OP) \
+ ((inst_t){.opcode = OP_MSET_##TYPE, .operand = DWORD(OP)})
+#define INST_MGET(TYPE, OP) \
+ ((inst_t){.opcode = OP_MGET_##TYPE, .operand = DWORD(OP)})
+#define INST_MDELETE ((inst_t){.opcode = OP_MDELETE})
+
#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})