refactor to step intead of loop
This commit is contained in:
parent
4cb02c41d0
commit
838f3800cb
33
src/main.c
33
src/main.c
|
@ -1,13 +1,24 @@
|
|||
#include "vm.h"
|
||||
#include "debug.h"
|
||||
#include "vm.h"
|
||||
|
||||
/* #define MEMORY_SIZE 65536 /\* 64KB memory (adjustable) *\/ */
|
||||
#define MEMORY_SIZE 1024
|
||||
|
||||
void run_vm(Data *memory, uint32_t memory_size) {
|
||||
uint32_t pc = 1; /* Program counter */
|
||||
while (pc) {
|
||||
pc = step_vm(memory, memory_size, pc);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
Data memory[MEMORY_SIZE] = {0}; /* Memory array */
|
||||
|
||||
int i = 0;
|
||||
int i = 1;
|
||||
memory[0].c[0] = 'z';
|
||||
memory[0].c[1] = '0';
|
||||
memory[0].c[2] = '0';
|
||||
memory[0].c[3] = '0';
|
||||
memory[i++].u = OP_ADD_REAL;
|
||||
memory[i++].u = 102;
|
||||
memory[i++].u = 103;
|
||||
|
@ -19,27 +30,27 @@ int main() {
|
|||
memory[i++].u = OP_JGT_INT;
|
||||
memory[i++].u = 100;
|
||||
memory[i++].u = 99;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = OP_REAL_TO_INT;
|
||||
memory[i++].u = 103;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = 103;
|
||||
memory[i++].u = OP_INT_TO_STRING;
|
||||
memory[i++].u = 103;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = 104;
|
||||
memory[i++].u = OP_PRINT_STRING;
|
||||
memory[i++].u = 105;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = OP_READ_STRING;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = 109;
|
||||
memory[i++].u = OP_PRINT_STRING;
|
||||
memory[i++].u = 110;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = 1;
|
||||
memory[i++].u = OP_HALT;
|
||||
memory[i++].u = 0;
|
||||
memory[i++].u = 0;
|
||||
|
|
447
src/vm.c
447
src/vm.c
|
@ -6,239 +6,230 @@
|
|||
* String copy in data memory.
|
||||
*/
|
||||
void mem_strcpy(Data *memory, const char *str, uint32_t length,
|
||||
uint32_t dest_addr) {
|
||||
uint32_t dest_addr) {
|
||||
memory[dest_addr].u = length;
|
||||
uint32_t buffer_addr = dest_addr + 1;
|
||||
uint32_t i = 0;
|
||||
while (i < length) {
|
||||
char ch = str[i];
|
||||
if (ch == '\0') {
|
||||
break;
|
||||
}
|
||||
memory[buffer_addr + (i / 4)].c[i % 4] = ch;
|
||||
i++;
|
||||
uint32_t i;
|
||||
for (i = 0; i < length; i++) {
|
||||
memory[buffer_addr + (i / 4)].c[i % 4] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
void run_vm(Data *memory, uint32_t memory_size) {
|
||||
uint32_t pc = 0; /* Program counter */
|
||||
/**
|
||||
* Step to the next opcode in the vm.
|
||||
*/
|
||||
uint32_t step_vm(Data *memory, uint32_t memory_size, uint32_t pc) {
|
||||
Opcode opcode = memory[pc].u;
|
||||
uint32_t src1_addr = memory[pc + 1].u;
|
||||
uint32_t src2_addr = memory[pc + 2].u;
|
||||
uint32_t dest_addr = memory[pc + 3].u;
|
||||
pc += 4; /* Advance to next instruction */
|
||||
|
||||
while (pc < memory_size - 4) {
|
||||
|
||||
Opcode opcode = memory[pc].u;
|
||||
uint32_t src1_addr = memory[pc + 1].u;
|
||||
uint32_t src2_addr = memory[pc + 2].u;
|
||||
uint32_t dest_addr = memory[pc + 3].u;
|
||||
pc += 4; /* Advance to next instruction */
|
||||
|
||||
if (src1_addr >= memory_size || src2_addr >= memory_size ||
|
||||
dest_addr >= memory_size) {
|
||||
printf("Invalid memory address!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case OP_HALT:
|
||||
return;
|
||||
case OP_ADD:
|
||||
memory[dest_addr].u = memory[src1_addr].u + memory[src2_addr].u;
|
||||
break;
|
||||
|
||||
case OP_SUB:
|
||||
memory[dest_addr].u = memory[src1_addr].u - memory[src2_addr].u;
|
||||
break;
|
||||
|
||||
case OP_MUL:
|
||||
memory[dest_addr].u = memory[src1_addr].u * memory[src2_addr].u;
|
||||
break;
|
||||
|
||||
case OP_DIV:
|
||||
memory[dest_addr].u = memory[src1_addr].u / memory[src2_addr].u;
|
||||
break;
|
||||
|
||||
case OP_ADD_REAL:
|
||||
memory[dest_addr].f = memory[src1_addr].f + memory[src2_addr].f;
|
||||
break;
|
||||
|
||||
case OP_SUB_REAL:
|
||||
memory[dest_addr].f = memory[src1_addr].f - memory[src2_addr].f;
|
||||
break;
|
||||
|
||||
case OP_MUL_REAL:
|
||||
memory[dest_addr].f = memory[src1_addr].f * memory[src2_addr].f;
|
||||
break;
|
||||
|
||||
case OP_DIV_REAL:
|
||||
if (memory[src2_addr].f == 0.0f) {
|
||||
printf("Division by zero error at address %d\n", pc - 4);
|
||||
exit(1);
|
||||
}
|
||||
memory[dest_addr].f = memory[src1_addr].f / memory[src2_addr].f;
|
||||
break;
|
||||
case OP_REAL_TO_INT: {
|
||||
memory[dest_addr].u = (uint32_t)memory[src1_addr].f;
|
||||
break;
|
||||
}
|
||||
case OP_INT_TO_REAL: {
|
||||
memory[dest_addr].f = (float)memory[src1_addr].u;
|
||||
break;
|
||||
}
|
||||
case OP_MOV:
|
||||
memory[dest_addr] = memory[src1_addr];
|
||||
break;
|
||||
case OP_JMP:
|
||||
pc = src1_addr; /* Jump to address */
|
||||
break;
|
||||
case OP_JGT_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value > value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JLT_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value < value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JEQ_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value == value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JGT_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value > value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JLT_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value < value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JEQ_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value == value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JGE_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value >= value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JLE_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value <= value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JGE_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value >= value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_JLE_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value <= value2) ? jump_target : pc;
|
||||
break;
|
||||
}
|
||||
case OP_INT_TO_STRING: {
|
||||
int32_t a = (int32_t)memory[src1_addr].u;
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%d", a);
|
||||
mem_strcpy(memory, buffer, strlen(buffer), dest_addr);
|
||||
break;
|
||||
}
|
||||
case OP_REAL_TO_STRING: {
|
||||
float a = memory[src1_addr].f;
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%f", a);
|
||||
mem_strcpy(memory, buffer, strlen(buffer), dest_addr);
|
||||
break;
|
||||
}
|
||||
case OP_READ_STRING: {
|
||||
uint32_t buffer_addr = dest_addr + 1;
|
||||
uint32_t length = 0;
|
||||
while (1) {
|
||||
int ch = getchar();
|
||||
if (ch == '\n' || ch == EOF) {
|
||||
memory[buffer_addr + (length / 4)].c[length % 4] = '\0';
|
||||
break;
|
||||
}
|
||||
memory[buffer_addr + (length / 4)].c[length % 4] = ch;
|
||||
length++;
|
||||
}
|
||||
memory[dest_addr].u = length;
|
||||
break;
|
||||
}
|
||||
case OP_PRINT_STRING: {
|
||||
uint32_t string_addr = src1_addr;
|
||||
uint32_t length = memory[src1_addr - 1].u;
|
||||
uint32_t i;
|
||||
for (i = 0; i < length; i++) {
|
||||
uint8_t ch = memory[string_addr + (i / 4)].c[i % 4];
|
||||
if (ch == '\0')
|
||||
break;
|
||||
putchar(ch);
|
||||
}
|
||||
putchar('\n');
|
||||
break;
|
||||
}
|
||||
case OP_CMP_STRING: {
|
||||
uint32_t addr1 = src1_addr;
|
||||
uint32_t addr2 = src2_addr;
|
||||
uint32_t length1 = memory[src1_addr - 1].u;
|
||||
uint32_t length2 = memory[src2_addr - 1].u;
|
||||
uint32_t equal = 1;
|
||||
|
||||
if (length1 != length2) {
|
||||
equal = 0;
|
||||
} else {
|
||||
uint32_t i = 0;
|
||||
while (i < length1) {
|
||||
uint32_t char1 = memory[addr1 + i].u;
|
||||
uint32_t char2 = memory[addr2 + i].u;
|
||||
if (char1 != char2) {
|
||||
equal = 0;
|
||||
break;
|
||||
}
|
||||
if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
memory[dest_addr].u = equal;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unknown opcode: %d\n", opcode);
|
||||
return;
|
||||
}
|
||||
if (src1_addr >= memory_size || src2_addr >= memory_size ||
|
||||
dest_addr >= memory_size) {
|
||||
printf("Invalid memory address!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case OP_HALT:
|
||||
return 0;
|
||||
case OP_ADD:
|
||||
memory[dest_addr].u = memory[src1_addr].u + memory[src2_addr].u;
|
||||
return pc;
|
||||
|
||||
case OP_SUB:
|
||||
memory[dest_addr].u = memory[src1_addr].u - memory[src2_addr].u;
|
||||
return pc;
|
||||
|
||||
case OP_MUL:
|
||||
memory[dest_addr].u = memory[src1_addr].u * memory[src2_addr].u;
|
||||
return pc;
|
||||
|
||||
case OP_DIV:
|
||||
memory[dest_addr].u = memory[src1_addr].u / memory[src2_addr].u;
|
||||
return pc;
|
||||
|
||||
case OP_ADD_REAL:
|
||||
memory[dest_addr].f = memory[src1_addr].f + memory[src2_addr].f;
|
||||
return pc;
|
||||
|
||||
case OP_SUB_REAL:
|
||||
memory[dest_addr].f = memory[src1_addr].f - memory[src2_addr].f;
|
||||
return pc;
|
||||
|
||||
case OP_MUL_REAL:
|
||||
memory[dest_addr].f = memory[src1_addr].f * memory[src2_addr].f;
|
||||
return pc;
|
||||
|
||||
case OP_DIV_REAL:
|
||||
if (memory[src2_addr].f == 0.0f) {
|
||||
printf("Division by zero error at address %d\n", pc - 4);
|
||||
return 0;
|
||||
}
|
||||
memory[dest_addr].f = memory[src1_addr].f / memory[src2_addr].f;
|
||||
return pc;
|
||||
case OP_REAL_TO_INT: {
|
||||
memory[dest_addr].u = (uint32_t)memory[src1_addr].f;
|
||||
return pc;
|
||||
}
|
||||
case OP_INT_TO_REAL: {
|
||||
memory[dest_addr].f = (float)memory[src1_addr].u;
|
||||
return pc;
|
||||
}
|
||||
case OP_MOV:
|
||||
memory[dest_addr] = memory[src1_addr];
|
||||
return pc;
|
||||
case OP_JMP:
|
||||
pc = src1_addr; /* Jump to address */
|
||||
return pc;
|
||||
case OP_JEQ_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value == value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JGT_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value > value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JLT_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value < value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JLE_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value <= value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JGE_INT: {
|
||||
uint32_t value = memory[src1_addr].u;
|
||||
uint32_t value2 = memory[src2_addr].u;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value >= value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JEQ_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value == value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JGT_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value > value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JLT_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value < value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JGE_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value >= value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_JLE_REAL: {
|
||||
float value = memory[src1_addr].f;
|
||||
float value2 = memory[src2_addr].f;
|
||||
uint32_t jump_target = dest_addr;
|
||||
|
||||
pc = (value <= value2) ? jump_target : pc;
|
||||
return pc;
|
||||
}
|
||||
case OP_INT_TO_STRING: {
|
||||
int32_t a = (int32_t)memory[src1_addr].u;
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%d", a);
|
||||
mem_strcpy(memory, buffer, strlen(buffer), dest_addr);
|
||||
return pc;
|
||||
}
|
||||
case OP_REAL_TO_STRING: {
|
||||
float a = memory[src1_addr].f;
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%f", a);
|
||||
mem_strcpy(memory, buffer, strlen(buffer), dest_addr);
|
||||
return pc;
|
||||
}
|
||||
case OP_READ_STRING: {
|
||||
uint32_t buffer_addr = dest_addr + 1;
|
||||
uint32_t length = 0;
|
||||
while (1) {
|
||||
int ch = getchar();
|
||||
if (ch == '\n' || ch == EOF) {
|
||||
memory[buffer_addr + (length / 4)].c[length % 4] = '\0';
|
||||
break;
|
||||
}
|
||||
memory[buffer_addr + (length / 4)].c[length % 4] = ch;
|
||||
length++;
|
||||
}
|
||||
memory[dest_addr].u = length;
|
||||
return pc;
|
||||
}
|
||||
case OP_PRINT_STRING: {
|
||||
uint32_t string_addr = src1_addr;
|
||||
uint32_t length = memory[src1_addr - 1].u;
|
||||
uint32_t i;
|
||||
for (i = 0; i < length; i++) {
|
||||
uint8_t ch = memory[string_addr + (i / 4)].c[i % 4];
|
||||
if (ch == '\0')
|
||||
break;
|
||||
putchar(ch);
|
||||
}
|
||||
putchar('\n');
|
||||
return pc;
|
||||
}
|
||||
case OP_CMP_STRING: {
|
||||
uint32_t addr1 = src1_addr;
|
||||
uint32_t addr2 = src2_addr;
|
||||
uint32_t length1 = memory[src1_addr - 1].u;
|
||||
uint32_t length2 = memory[src2_addr - 1].u;
|
||||
uint32_t equal = 1;
|
||||
|
||||
if (length1 != length2) {
|
||||
equal = 0;
|
||||
} else {
|
||||
uint32_t i = 0;
|
||||
while (i < length1) {
|
||||
uint32_t char1 = memory[addr1 + i].u;
|
||||
uint32_t char2 = memory[addr2 + i].u;
|
||||
if (char1 != char2) {
|
||||
equal = 0;
|
||||
break;
|
||||
}
|
||||
if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0')
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
memory[dest_addr].u = equal;
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue