OP_HALT is its own opcode, fixed some other minor bugs
This commit is contained in:
6
Makefile
6
Makefile
@@ -86,13 +86,13 @@ interpret: $(VM_OUT)
|
|||||||
.PHONY: run-test-lib
|
.PHONY: run-test-lib
|
||||||
.ONESHELL:
|
.ONESHELL:
|
||||||
run-test-lib: $(TEST_LIB_OUT)
|
run-test-lib: $(TEST_LIB_OUT)
|
||||||
@echo "$(TERM_YELLOW)test/lib$(TERM_RESET): Starting test"
|
@echo "$(TERM_YELLOW)test/lib$(TERM_RESET): Starting tests"
|
||||||
@./$^;
|
@./$^;
|
||||||
if [ $$? -ne 0 ];
|
if [ $$? -ne 0 ];
|
||||||
then
|
then
|
||||||
echo "$(TERM_RED)test/lib$(TERM_RESET): Test failed";
|
echo "$(TERM_RED)test/lib$(TERM_RESET): Tests failed";
|
||||||
else
|
else
|
||||||
echo "$(TERM_GREEN)test/lib$(TERM_RESET): Test passed";
|
echo "$(TERM_GREEN)test/lib$(TERM_RESET): Tests passed";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Directories
|
# Directories
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
((inst_t){.opcode = OP_PUSH_##TYPE, .operand = D##TYPE(OP)})
|
((inst_t){.opcode = OP_PUSH_##TYPE, .operand = D##TYPE(OP)})
|
||||||
|
|
||||||
#define INST_MOV(TYPE, OP) \
|
#define INST_MOV(TYPE, OP) \
|
||||||
((inst_t){.opcode = OP_MOV_##TYPE, .operand = D##TYPE(OP)})
|
((inst_t){.opcode = OP_MOV_##TYPE, .operand = DWORD(OP)})
|
||||||
|
|
||||||
#define INST_POP(TYPE) ((inst_t){.opcode = OP_POP_##TYPE})
|
#define INST_POP(TYPE) ((inst_t){.opcode = OP_POP_##TYPE})
|
||||||
|
|
||||||
|
|||||||
28
lib/inst.c
28
lib/inst.c
@@ -245,7 +245,7 @@ void data_print(data_t datum, data_type_t type, FILE *fp)
|
|||||||
|
|
||||||
void inst_print(inst_t instruction, FILE *fp)
|
void inst_print(inst_t instruction, FILE *fp)
|
||||||
{
|
{
|
||||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_print: Out of date");
|
static_assert(NUMBER_OF_OPCODES == 99, "inst_print: Out of date");
|
||||||
fprintf(fp, "%s(", opcode_as_cstr(instruction.opcode));
|
fprintf(fp, "%s(", opcode_as_cstr(instruction.opcode));
|
||||||
if (UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_PUSH))
|
if (UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_PUSH))
|
||||||
{
|
{
|
||||||
@@ -264,7 +264,7 @@ void inst_print(inst_t instruction, FILE *fp)
|
|||||||
UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_MSET) ||
|
UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_MSET) ||
|
||||||
UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_MGET))
|
UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_MGET))
|
||||||
{
|
{
|
||||||
fprintf(fp, "n=%lu", instruction.operand.as_word);
|
fprintf(fp, "n=0x%lX", instruction.operand.as_word);
|
||||||
}
|
}
|
||||||
else if (instruction.opcode == OP_JUMP_ABS ||
|
else if (instruction.opcode == OP_JUMP_ABS ||
|
||||||
UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_JUMP_IF) ||
|
UNSIGNED_OPCODE_IS_TYPE(instruction.opcode, OP_JUMP_IF) ||
|
||||||
@@ -278,7 +278,7 @@ void inst_print(inst_t instruction, FILE *fp)
|
|||||||
|
|
||||||
size_t opcode_bytecode_size(opcode_t opcode)
|
size_t opcode_bytecode_size(opcode_t opcode)
|
||||||
{
|
{
|
||||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_bytecode_size: Out of date");
|
static_assert(NUMBER_OF_OPCODES == 99, "inst_bytecode_size: Out of date");
|
||||||
size_t size = 1; // for opcode
|
size_t size = 1; // for opcode
|
||||||
if (UNSIGNED_OPCODE_IS_TYPE(opcode, OP_PUSH))
|
if (UNSIGNED_OPCODE_IS_TYPE(opcode, OP_PUSH))
|
||||||
{
|
{
|
||||||
@@ -303,15 +303,16 @@ size_t opcode_bytecode_size(opcode_t opcode)
|
|||||||
|
|
||||||
size_t inst_write_bytecode(inst_t inst, byte_t *bytes)
|
size_t inst_write_bytecode(inst_t inst, byte_t *bytes)
|
||||||
{
|
{
|
||||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_write_bytecode: Out of date");
|
static_assert(NUMBER_OF_OPCODES == 99, "inst_write_bytecode: Out of date");
|
||||||
|
|
||||||
size_t written = 1;
|
|
||||||
bytes[0] = inst.opcode;
|
bytes[0] = inst.opcode;
|
||||||
|
size_t written = 1;
|
||||||
// Then append 0 or more operands
|
// Then append 0 or more operands
|
||||||
data_type_t to_append = DATA_TYPE_NIL;
|
data_type_t to_append = DATA_TYPE_NIL;
|
||||||
if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH))
|
if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH))
|
||||||
to_append = (data_type_t)inst.opcode;
|
to_append = OPCODE_DATA_TYPE(inst.opcode, OP_PUSH);
|
||||||
else if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH_REGISTER) ||
|
else if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH_REGISTER) ||
|
||||||
|
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_DUP) ||
|
||||||
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MOV) ||
|
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MOV) ||
|
||||||
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_DUP) ||
|
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_DUP) ||
|
||||||
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MALLOC) ||
|
UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MALLOC) ||
|
||||||
@@ -325,19 +326,22 @@ size_t inst_write_bytecode(inst_t inst, byte_t *bytes)
|
|||||||
{
|
{
|
||||||
case DATA_TYPE_NIL:
|
case DATA_TYPE_NIL:
|
||||||
break;
|
break;
|
||||||
case DATA_TYPE_BYTE:
|
case DATA_TYPE_BYTE: {
|
||||||
bytes[1] = inst.operand.as_byte;
|
bytes[1] = inst.operand.as_byte;
|
||||||
written += 1;
|
written += 1;
|
||||||
break;
|
break;
|
||||||
case DATA_TYPE_HWORD:
|
}
|
||||||
|
case DATA_TYPE_HWORD: {
|
||||||
convert_hword_to_bytes(inst.operand.as_hword, bytes + 1);
|
convert_hword_to_bytes(inst.operand.as_hword, bytes + 1);
|
||||||
written += HWORD_SIZE;
|
written += HWORD_SIZE;
|
||||||
break;
|
break;
|
||||||
case DATA_TYPE_WORD:
|
}
|
||||||
|
case DATA_TYPE_WORD: {
|
||||||
convert_word_to_bytes(inst.operand.as_word, bytes + 1);
|
convert_word_to_bytes(inst.operand.as_word, bytes + 1);
|
||||||
written += WORD_SIZE;
|
written += WORD_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,10 +379,10 @@ bool read_type_from_darr(byte_t *bytes, size_t size, data_type_t type,
|
|||||||
|
|
||||||
int inst_read_bytecode(inst_t *ptr, byte_t *bytes, size_t size_bytes)
|
int inst_read_bytecode(inst_t *ptr, byte_t *bytes, size_t size_bytes)
|
||||||
{
|
{
|
||||||
static_assert(NUMBER_OF_OPCODES == 98, "inst_read_bytecode: Out of date");
|
static_assert(NUMBER_OF_OPCODES == 99, "inst_read_bytecode: Out of date");
|
||||||
|
|
||||||
opcode_t opcode = *(bytes++);
|
opcode_t opcode = *(bytes++);
|
||||||
if (opcode > OP_HALT || opcode == NUMBER_OF_OPCODES || opcode < OP_NOOP)
|
if (opcode > OP_HALT || opcode < OP_NOOP)
|
||||||
return READ_ERR_INVALID_OPCODE;
|
return READ_ERR_INVALID_OPCODE;
|
||||||
|
|
||||||
inst_t inst = {opcode, {0}};
|
inst_t inst = {opcode, {0}};
|
||||||
@@ -409,7 +413,7 @@ int inst_read_bytecode(inst_t *ptr, byte_t *bytes, size_t size_bytes)
|
|||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
*ptr = inst;
|
*ptr = inst;
|
||||||
return (int)(READ_ERR_END) - (int)(size_bytes);
|
return (int)(size_bytes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return READ_ERR_OPERAND_NO_FIT;
|
return READ_ERR_OPERAND_NO_FIT;
|
||||||
|
|||||||
@@ -161,9 +161,9 @@ typedef enum
|
|||||||
OP_CALL_STACK,
|
OP_CALL_STACK,
|
||||||
OP_RET,
|
OP_RET,
|
||||||
|
|
||||||
|
OP_HALT,
|
||||||
// Should not be an opcode
|
// Should not be an opcode
|
||||||
NUMBER_OF_OPCODES,
|
NUMBER_OF_OPCODES,
|
||||||
OP_HALT = 0b11111111, // top of the byte is a HALT
|
|
||||||
} opcode_t;
|
} opcode_t;
|
||||||
|
|
||||||
size_t opcode_bytecode_size(opcode_t);
|
size_t opcode_bytecode_size(opcode_t);
|
||||||
|
|||||||
@@ -50,15 +50,15 @@ struct Test
|
|||||||
for (size_t i = 0; i < ARR_SIZE(SUITE); ++i) \
|
for (size_t i = 0; i < ARR_SIZE(SUITE); ++i) \
|
||||||
{ \
|
{ \
|
||||||
SUITE[i].src(); \
|
SUITE[i].src(); \
|
||||||
SUCCESS(SUITE[i].name, "%s\n", "Test succeeded"); \
|
SUCCESS(SUITE[i].name, "%s\n", "Test passed"); \
|
||||||
} \
|
} \
|
||||||
SUCCESS("<" #SUITE ">", "%s", "Finished test suite!\n")
|
SUCCESS("<" #SUITE ">", "%s", "Test suite passed!\n")
|
||||||
#else
|
#else
|
||||||
#define RUN_TEST_SUITE(SUITE) \
|
#define RUN_TEST_SUITE(SUITE) \
|
||||||
INFO("<" #SUITE ">", "%s", "Starting test suite...\n"); \
|
INFO("<" #SUITE ">", "%s", "Starting test suite...\n"); \
|
||||||
for (size_t i = 0; i < ARR_SIZE(SUITE); ++i) \
|
for (size_t i = 0; i < ARR_SIZE(SUITE); ++i) \
|
||||||
SUITE[i].src(); \
|
SUITE[i].src(); \
|
||||||
SUCCESS("<" #SUITE ">", "%s", "Finished test suite!\n")
|
SUCCESS("<" #SUITE ">", "%s", "Test suite passed!\n")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static size_t size_byte_array_to_string(const size_t n)
|
static size_t size_byte_array_to_string(const size_t n)
|
||||||
@@ -73,12 +73,11 @@ static void byte_array_to_string(const byte_t *bytes, size_t size_bytes,
|
|||||||
size_t j = 1;
|
size_t j = 1;
|
||||||
for (size_t i = 0; i < size_bytes; ++i)
|
for (size_t i = 0; i < size_bytes; ++i)
|
||||||
{
|
{
|
||||||
;
|
|
||||||
char buffer[7];
|
char buffer[7];
|
||||||
int k = i == size_bytes - 1 ? 0 : 2;
|
int k = i == size_bytes - 1 ? 0 : 2;
|
||||||
size_t n = 2 + (bytes[i] < 10 ? 1 : 2) + k;
|
size_t n = 4 + k;
|
||||||
|
|
||||||
sprintf(buffer, "0x%X, ", bytes[i]);
|
sprintf(buffer, "0x%s%X, ", (bytes[i] < 16 ? "_" : ""), bytes[i]);
|
||||||
memcpy(str + j, buffer, n);
|
memcpy(str + j, buffer, n);
|
||||||
j += n;
|
j += n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const char *err_as_cstr(err_t err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(NUMBER_OF_OPCODES == 98, "vm_execute: Out of date");
|
static_assert(NUMBER_OF_OPCODES == 99, "vm_execute: Out of date");
|
||||||
|
|
||||||
static_assert(DATA_TYPE_NIL == -1 && DATA_TYPE_WORD == 2,
|
static_assert(DATA_TYPE_NIL == -1 && DATA_TYPE_WORD == 2,
|
||||||
"Code using OPCODE_DATA_TYPE for quick same type opcode "
|
"Code using OPCODE_DATA_TYPE for quick same type opcode "
|
||||||
|
|||||||
Reference in New Issue
Block a user