Introduced instructions to engage with a call stack
Essentially you may "call" an absolute program address, which pushes the current address onto the call stack. CALL_STACK does the same thing but the absolute program address is taken from the data stack. RET pops an address off the call stack then jumps to that address.
This commit is contained in:
24
lib/inst.c
24
lib/inst.c
@@ -199,6 +199,12 @@ const char *opcode_as_cstr(opcode_t code)
|
||||
return "JUMP_IF_HWORD";
|
||||
case OP_JUMP_IF_WORD:
|
||||
return "JUMP_IF_WORD";
|
||||
case OP_CALL:
|
||||
return "CALL";
|
||||
case OP_CALL_STACK:
|
||||
return "CALL_STACK";
|
||||
case OP_RET:
|
||||
return "RET";
|
||||
case OP_PRINT_CHAR:
|
||||
return "PRINT_CHAR";
|
||||
case OP_PRINT_BYTE:
|
||||
@@ -239,7 +245,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 == 95, "inst_bytecode_size: Out of date");
|
||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_bytecode_size: Out of date");
|
||||
fprintf(fp, "%s(", opcode_as_cstr(instruction.opcode));
|
||||
if (OPCODE_IS_TYPE(instruction.opcode, OP_PUSH))
|
||||
{
|
||||
@@ -261,7 +267,8 @@ void inst_print(inst_t instruction, FILE *fp)
|
||||
fprintf(fp, "n=%lu", instruction.operand.as_word);
|
||||
}
|
||||
else if (instruction.opcode == OP_JUMP_ABS ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_JUMP_IF))
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_JUMP_IF) ||
|
||||
instruction.opcode == OP_CALL)
|
||||
{
|
||||
fprintf(fp, "address=0x");
|
||||
data_print(instruction.operand, DATA_TYPE_WORD, fp);
|
||||
@@ -271,7 +278,7 @@ void inst_print(inst_t instruction, FILE *fp)
|
||||
|
||||
size_t inst_bytecode_size(inst_t inst)
|
||||
{
|
||||
static_assert(NUMBER_OF_OPCODES == 95, "inst_bytecode_size: Out of date");
|
||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_bytecode_size: Out of date");
|
||||
size_t size = 1; // for opcode
|
||||
if (OPCODE_IS_TYPE(inst.opcode, OP_PUSH))
|
||||
{
|
||||
@@ -288,14 +295,14 @@ size_t inst_bytecode_size(inst_t inst)
|
||||
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 ||
|
||||
OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF))
|
||||
OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF) || inst.opcode == OP_CALL)
|
||||
size += WORD_SIZE;
|
||||
return size;
|
||||
}
|
||||
|
||||
void inst_write_bytecode(inst_t inst, darr_t *darr)
|
||||
{
|
||||
static_assert(NUMBER_OF_OPCODES == 95, "inst_write_bytecode: Out of date");
|
||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_write_bytecode: Out of date");
|
||||
// Append opcode
|
||||
darr_append_byte(darr, inst.opcode);
|
||||
// Then append 0 or more operands
|
||||
@@ -308,7 +315,7 @@ void inst_write_bytecode(inst_t inst, darr_t *darr)
|
||||
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 ||
|
||||
OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF))
|
||||
OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF) || inst.opcode == OP_CALL)
|
||||
to_append = DATA_TYPE_WORD;
|
||||
|
||||
switch (to_append)
|
||||
@@ -370,7 +377,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 == 95, "inst_read_bytecode: Out of date");
|
||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_read_bytecode: Out of date");
|
||||
if (darr->used >= darr->available)
|
||||
return (inst_t){0};
|
||||
inst_t inst = {0};
|
||||
@@ -385,7 +392,8 @@ inst_t inst_read_bytecode(darr_t *darr)
|
||||
OPCODE_IS_TYPE(opcode, OP_MOV) || 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))
|
||||
opcode == OP_JUMP_ABS || OPCODE_IS_TYPE(opcode, OP_JUMP_IF) ||
|
||||
opcode == OP_CALL)
|
||||
inst.operand = read_type_from_darr(darr, DATA_TYPE_WORD);
|
||||
// Otherwise opcode doesn't take operands
|
||||
|
||||
|
||||
@@ -148,6 +148,10 @@ typedef enum
|
||||
OP_JUMP_IF_BYTE,
|
||||
OP_JUMP_IF_HWORD,
|
||||
OP_JUMP_IF_WORD,
|
||||
// Subroutines
|
||||
OP_CALL,
|
||||
OP_CALL_STACK,
|
||||
OP_RET,
|
||||
|
||||
// Should not be an opcode
|
||||
NUMBER_OF_OPCODES,
|
||||
@@ -231,6 +235,9 @@ inst_t *insts_read_bytecode_file(FILE *, size_t *);
|
||||
#define INST_JUMP_STACK ((inst_t){.opcode = OP_JUMP_STACK})
|
||||
#define INST_JUMP_IF(TYPE, OP) \
|
||||
((inst_t){.opcode = OP_JUMP_IF_##TYPE, .operand = DWORD(OP)})
|
||||
#define INST_CALL(OP) ((inst_t){.opcode = OP_CALL, .operand = DWORD(OP)})
|
||||
#define INST_CALL_STACK ((inst_t){.opcode = OP_CALL_STACK})
|
||||
#define INST_RET ((inst_t){.opcode = OP_RET})
|
||||
|
||||
#define INST_PRINT(TYPE) ((inst_t){.opcode = OP_PRINT_##TYPE})
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user