WIP (untested) automatic string allocation, function call/return
This commit is contained in:
parent
0263d1511d
commit
bcc61a93eb
|
@ -34,6 +34,38 @@ void demo_add_compile(Value *memory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void demo_function_call_compile(Value *memory) {
|
||||||
|
uint32_t i = 0;
|
||||||
|
memory[i++].u = OP(OP_LOADU, 0, 0, 0);
|
||||||
|
memory[i++].u = 0;
|
||||||
|
memory[i++].u = OP(OP_LOADU, 1, 0, 0);
|
||||||
|
memory[i++].u = 5;
|
||||||
|
memory[i++].u = OP(OP_LOADU, 2, 0, 0);
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = OP(OP_LOADF, 3, 0, 0);
|
||||||
|
memory[i++].f = 5.0f;
|
||||||
|
memory[i++].u = OP(OP_LOADF, 4, 0, 0);
|
||||||
|
memory[i++].f = 5.0f;
|
||||||
|
memory[i++].u = OP(OP_LOADU, 5, 0, 0);
|
||||||
|
memory[i++].u = 200;
|
||||||
|
memory[i++].u = OP(OP_LOADU, 6, 0, 0);
|
||||||
|
memory[i++].u = 250;
|
||||||
|
memory[i++].u = OP(OP_LOADU, 7, 0, 0);
|
||||||
|
memory[i++].u = 252;
|
||||||
|
uint32_t jmp = i;
|
||||||
|
memory[i++].u = OP(OP_ADD_REAL, 4, 4, 3);
|
||||||
|
memory[i++].u = OP(OP_SUB_UINT, 1, 1, 2);
|
||||||
|
memory[i++].u = OP(OP_JGT_UINT, jmp, 1, 0);
|
||||||
|
memory[i++].u = OP(OP_REAL_TO_STRING, 5, 4, 0);
|
||||||
|
memory[i++].u = OP(OP_PRINT_STRING, 0, 5, 0);
|
||||||
|
memory[i++].u = OP(OP_REAL_TO_UINT, 1, 4, 4);
|
||||||
|
memory[i++].u = OP(OP_UINT_TO_STRING, 6, 1, 0);
|
||||||
|
memory[i++].u = OP(OP_PRINT_STRING, 0, 6, 0);
|
||||||
|
memory[i++].u = OP(OP_READ_STRING, 7, 0, 0);
|
||||||
|
memory[i++].u = OP(OP_PRINT_STRING, 0, 7, 0);
|
||||||
|
memory[i++].u = OP(OP_HALT, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void letDeclaration() {
|
static void letDeclaration() {
|
||||||
/* uint8_t global = parseVariable("Expect variable name."); */
|
/* uint8_t global = parseVariable("Expect variable name."); */
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
|
|
||||||
void demo_add_compile (Value* memory);
|
void demo_add_compile (Value *memory);
|
||||||
|
void demo_function_call_compile(Value *memory);
|
||||||
void compile (Value* memory, char *buffer);
|
void compile (Value* memory, char *buffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,23 +17,25 @@ typedef struct {
|
||||||
|
|
||||||
#define MAX_REGS 256
|
#define MAX_REGS 256
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Value registers[MAX_REGS]; /* R0-R255 */
|
Value registers[MAX_REGS]; /* R0-R[MAX_REGS-1] */
|
||||||
Slice allocated;
|
uint32_t rp; /* register pointer (last unused) */
|
||||||
|
Slice allocated; /* start and end of global allocated block */
|
||||||
} Frame;
|
} Frame;
|
||||||
|
|
||||||
#define MEMORY_SIZE 1024
|
#define MEMORY_SIZE 65536
|
||||||
#define STACK_SIZE 128
|
#define FRAME_STACK_SIZE 32
|
||||||
#define RETURN_STACK_SIZE 256
|
#define RETURN_STACK_SIZE 256
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Value memory[MEMORY_SIZE]; /* Memory array */
|
|
||||||
uint32_t memory_size;
|
|
||||||
Value return_stack[RETURN_STACK_SIZE];
|
|
||||||
uint32_t return_stack_size;
|
|
||||||
Frame stack[STACK_SIZE];
|
|
||||||
uint32_t stack_size;
|
|
||||||
uint32_t rp; /* Return stack pointer (top of stack) */
|
|
||||||
uint32_t sp; /* Stack pointer (top of stack) */
|
|
||||||
uint32_t pc; /* Program counter */
|
uint32_t pc; /* Program counter */
|
||||||
|
uint32_t fp; /* Frame pointer (last allocated value) */
|
||||||
|
uint32_t rp; /* Return stack pointer (top of stack) */
|
||||||
|
uint32_t mp; /* Memory pointer (last allocated value) */
|
||||||
|
uint32_t frame_stack_size;
|
||||||
|
Frame frame_stack[FRAME_STACK_SIZE];
|
||||||
|
uint32_t return_stack_size;
|
||||||
|
Value return_stack[RETURN_STACK_SIZE];
|
||||||
|
uint32_t memory_size;
|
||||||
|
Value memory[MEMORY_SIZE]; /* Memory array */
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
104
src/vm.c
104
src/vm.c
|
@ -3,18 +3,18 @@
|
||||||
|
|
||||||
#define COMPARE_AND_JUMP(type, accessor, op) \
|
#define COMPARE_AND_JUMP(type, accessor, op) \
|
||||||
do { \
|
do { \
|
||||||
type value = vm->stack[vm->sp].registers[src1].accessor; \
|
type value = vm->frame_stack[vm->fp].registers[src1].accessor; \
|
||||||
type value2 = vm->stack[vm->sp].registers[src2].accessor; \
|
type value2 = vm->frame_stack[vm->fp].registers[src2].accessor; \
|
||||||
vm->pc = (value op value2) ? dest : vm->pc; \
|
vm->pc = (value op value2) ? dest : vm->pc; \
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MATH_OP(accessor, op) \
|
#define MATH_OP(accessor, op) \
|
||||||
do { \
|
do { \
|
||||||
vm->stack[vm->sp].registers[dest].accessor = \
|
vm->frame_stack[vm->fp].registers[dest].accessor = \
|
||||||
vm->stack[vm->sp] \
|
vm->frame_stack[vm->fp] \
|
||||||
.registers[src1] \
|
.registers[src1] \
|
||||||
.accessor op vm->stack[vm->sp] \
|
.accessor op vm->frame_stack[vm->fp] \
|
||||||
.registers[src2] \
|
.registers[src2] \
|
||||||
.accessor; \
|
.accessor; \
|
||||||
return true; \
|
return true; \
|
||||||
|
@ -53,36 +53,45 @@ bool step_vm(VM *vm) {
|
||||||
case OP_HALT:
|
case OP_HALT:
|
||||||
return false;
|
return false;
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
vm->return_stack[vm->rp++].u = vm->pc; /* push the return address */
|
vm->return_stack[++vm->rp].u = vm->pc; /* push return address */
|
||||||
vm->sp++; /* increment to the next free frame */
|
vm->pc = vm->frame_stack[vm->fp]
|
||||||
|
.registers[dest]
|
||||||
|
.u; /* set pc to location of function in memory */
|
||||||
|
vm->fp++; /* increment to the next free frame */
|
||||||
|
vm->frame_stack[vm->fp].allocated.start =
|
||||||
|
vm->mp; /* set start of new memory block */
|
||||||
return true;
|
return true;
|
||||||
case OP_RETURN:
|
case OP_RETURN:
|
||||||
vm->pc = vm->return_stack[vm->rp].u; /* set pc to return address */
|
vm->pc = vm->return_stack[vm->rp].u; /* set pc to return address */
|
||||||
Slice s = vm->stack[vm->rp].allocated;
|
Slice s = vm->frame_stack[vm->fp].allocated; /* get allocated slice */
|
||||||
memset(&vm->memory[s.start], 0, s.end - s.start); /* deallocate memory from slice */
|
memset(&vm->memory[s.start], 0,
|
||||||
vm->return_stack[vm->rp--].u = 0; /* deallocate the stack */
|
s.end - s.start); /* deallocate memory from slice */
|
||||||
vm->return_stack[vm->rp] = vm->stack[vm->sp].registers[0]; /* push the return value onto the return stack (always register 0) */
|
uint32_t parent_rp = vm->frame_stack[vm->fp - 1].rp; /* get parents rp */
|
||||||
|
vm->frame_stack[vm->fp - 1].registers[parent_rp++] =
|
||||||
|
vm->frame_stack[vm->fp]
|
||||||
|
.registers[src1]; /* set the return value to the last register in
|
||||||
|
the parent frame */
|
||||||
|
memset(&vm->frame_stack[vm->fp], 0, sizeof(Frame)); /* reset the frame */
|
||||||
|
vm->fp--; /* pop the frame */
|
||||||
|
vm->mp = s.start; /* reset memory pointer to start of old slice */
|
||||||
return true;
|
return true;
|
||||||
case OP_LOADI:
|
case OP_LOADI:
|
||||||
vm->stack[vm->sp].registers[dest].i = vm->memory[vm->pc++].i;
|
vm->frame_stack[vm->fp].registers[dest].i = vm->memory[vm->pc++].i;
|
||||||
return true;
|
return true;
|
||||||
case OP_LOADU:
|
case OP_LOADU:
|
||||||
vm->stack[vm->sp].registers[dest].u = vm->memory[vm->pc++].u;
|
vm->frame_stack[vm->fp].registers[dest].u = vm->memory[vm->pc++].u;
|
||||||
return true;
|
return true;
|
||||||
case OP_LOADF:
|
case OP_LOADF:
|
||||||
vm->stack[vm->sp].registers[dest].f = vm->memory[vm->pc++].f;
|
vm->frame_stack[vm->fp].registers[dest].f = vm->memory[vm->pc++].f;
|
||||||
return true;
|
return true;
|
||||||
case OP_STOREI:
|
case OP_STOREI:
|
||||||
vm->memory[vm->pc++].i = vm->stack[vm->sp].registers[src1].i;
|
vm->memory[vm->pc++].i = vm->frame_stack[vm->fp].registers[src1].i;
|
||||||
return true;
|
return true;
|
||||||
case OP_STOREU:
|
case OP_STOREU:
|
||||||
vm->memory[vm->pc++].u = vm->stack[vm->sp].registers[src1].u;
|
vm->memory[vm->pc++].u = vm->frame_stack[vm->fp].registers[src1].u;
|
||||||
return true;
|
return true;
|
||||||
case OP_STOREF:
|
case OP_STOREF:
|
||||||
vm->memory[vm->pc++].f = vm->stack[vm->sp].registers[src1].f;
|
vm->memory[vm->pc++].f = vm->frame_stack[vm->fp].registers[src1].f;
|
||||||
return true;
|
return true;
|
||||||
case OP_ADD_INT:
|
case OP_ADD_INT:
|
||||||
MATH_OP(i, +);
|
MATH_OP(i, +);
|
||||||
|
@ -109,26 +118,27 @@ bool step_vm(VM *vm) {
|
||||||
case OP_DIV_REAL:
|
case OP_DIV_REAL:
|
||||||
MATH_OP(f, /);
|
MATH_OP(f, /);
|
||||||
case OP_REAL_TO_INT:
|
case OP_REAL_TO_INT:
|
||||||
vm->stack[vm->sp].registers[dest].i =
|
vm->frame_stack[vm->fp].registers[dest].i =
|
||||||
(int32_t)(vm->stack[vm->sp].registers[src1].f);
|
(int32_t)(vm->frame_stack[vm->fp].registers[src1].f);
|
||||||
return true;
|
return true;
|
||||||
case OP_INT_TO_REAL:
|
case OP_INT_TO_REAL:
|
||||||
vm->stack[vm->sp].registers[dest].f =
|
vm->frame_stack[vm->fp].registers[dest].f =
|
||||||
(float)(vm->stack[vm->sp].registers[src1].i);
|
(float)(vm->frame_stack[vm->fp].registers[src1].i);
|
||||||
return true;
|
return true;
|
||||||
case OP_REAL_TO_UINT:
|
case OP_REAL_TO_UINT:
|
||||||
vm->stack[vm->sp].registers[dest].u =
|
vm->frame_stack[vm->fp].registers[dest].u =
|
||||||
(uint32_t)(vm->stack[vm->sp].registers[src1].f);
|
(uint32_t)(vm->frame_stack[vm->fp].registers[src1].f);
|
||||||
return true;
|
return true;
|
||||||
case OP_UINT_TO_REAL:
|
case OP_UINT_TO_REAL:
|
||||||
vm->stack[vm->sp].registers[dest].f =
|
vm->frame_stack[vm->fp].registers[dest].f =
|
||||||
(float)(vm->stack[vm->sp].registers[src1].u);
|
(float)(vm->frame_stack[vm->fp].registers[src1].u);
|
||||||
return true;
|
return true;
|
||||||
case OP_MOV:
|
case OP_MOV:
|
||||||
vm->stack[vm->sp].registers[dest] = vm->stack[vm->sp].registers[src1];
|
vm->frame_stack[vm->fp].registers[dest] =
|
||||||
|
vm->frame_stack[vm->fp].registers[src1];
|
||||||
return true;
|
return true;
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
vm->pc = vm->stack[vm->sp].registers[src1].u; /* Jump to address */
|
vm->pc = vm->frame_stack[vm->fp].registers[src1].u; /* Jump to address */
|
||||||
return true;
|
return true;
|
||||||
case OP_JEQ_UINT: {
|
case OP_JEQ_UINT: {
|
||||||
COMPARE_AND_JUMP(uint32_t, u, ==);
|
COMPARE_AND_JUMP(uint32_t, u, ==);
|
||||||
|
@ -176,31 +186,38 @@ bool step_vm(VM *vm) {
|
||||||
COMPARE_AND_JUMP(float, u, <=);
|
COMPARE_AND_JUMP(float, u, <=);
|
||||||
}
|
}
|
||||||
case OP_INT_TO_STRING: {
|
case OP_INT_TO_STRING: {
|
||||||
int32_t a = (int32_t)vm->stack[vm->sp].registers[src1].i;
|
int32_t a = (int32_t)vm->frame_stack[vm->fp].registers[src1].i; /* get value */
|
||||||
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->frame_stack[vm->fp].allocated.end; /* get start of unallocated */
|
||||||
|
vm->frame_stack[vm->fp].registers[dest].u = str_dest; /* store ptr of string to dest register */
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
int len = sprintf(buffer, "%d", a);
|
int len = sprintf(buffer, "%d", a);
|
||||||
mem_strcpy(vm->memory, buffer, len, str_dest);
|
mem_strcpy(vm->memory, buffer, len, str_dest); /* copy buffer to dest */
|
||||||
|
vm->frame_stack[vm->fp].allocated.end += sizeof(uint32_t) + len * sizeof(char); /* increment to end of allocated */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_UINT_TO_STRING: {
|
case OP_UINT_TO_STRING: {
|
||||||
uint32_t a = (uint32_t)vm->stack[vm->sp].registers[src1].u;
|
uint32_t a = (uint32_t)vm->frame_stack[vm->fp].registers[src1].u; /* get value */
|
||||||
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->frame_stack[vm->fp].allocated.end; /* get start of unallocated */
|
||||||
|
vm->frame_stack[vm->fp].registers[dest].u = str_dest; /* store ptr of string to dest register */
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
int len = sprintf(buffer, "%d", a);
|
int len = sprintf(buffer, "%d", a);
|
||||||
mem_strcpy(vm->memory, buffer, len, str_dest);
|
mem_strcpy(vm->memory, buffer, len, str_dest); /* copy buffer to dest */
|
||||||
|
vm->frame_stack[vm->fp].allocated.end += sizeof(uint32_t) + len * sizeof(char); /* increment to end of allocated */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REAL_TO_STRING: {
|
case OP_REAL_TO_STRING: {
|
||||||
float a = (float)vm->stack[vm->sp].registers[src1].f;
|
float a = (float)vm->frame_stack[vm->fp].registers[src1].f; /* get value */
|
||||||
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->frame_stack[vm->fp].allocated.end; /* get start of unallocated */
|
||||||
|
vm->frame_stack[vm->fp].registers[dest].u = str_dest; /* store ptr of string to dest register */
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
int len = sprintf(buffer, "%f", a);
|
int len = sprintf(buffer, "%f", a);
|
||||||
mem_strcpy(vm->memory, buffer, len, str_dest);
|
mem_strcpy(vm->memory, buffer, len, str_dest); /* copy buffer to dest */
|
||||||
|
vm->frame_stack[vm->fp].allocated.end += sizeof(uint32_t) + len * sizeof(char); /* increment to end of allocated */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_READ_STRING: {
|
case OP_READ_STRING: {
|
||||||
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->frame_stack[vm->fp].allocated.end; /* get start of unallocated */
|
||||||
|
vm->frame_stack[vm->fp].registers[dest].u = str_dest; /* store ptr of string to dest register */
|
||||||
uint32_t buffer = str_dest + 1;
|
uint32_t buffer = str_dest + 1;
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -213,10 +230,11 @@ bool step_vm(VM *vm) {
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
vm->memory[str_dest].u = length;
|
vm->memory[str_dest].u = length;
|
||||||
|
vm->frame_stack[vm->fp].allocated.end += sizeof(uint32_t) + length * sizeof(char); /* increment to end of allocated */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_PRINT_STRING: {
|
case OP_PRINT_STRING: {
|
||||||
uint32_t ptr = (uint32_t)vm->stack[vm->sp].registers[src1].u;
|
uint32_t ptr = (uint32_t)vm->frame_stack[vm->fp].registers[src1].u;
|
||||||
uint32_t length = vm->memory[ptr].u;
|
uint32_t length = vm->memory[ptr].u;
|
||||||
uint32_t str_src = ptr + 1;
|
uint32_t str_src = ptr + 1;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
@ -230,8 +248,8 @@ bool step_vm(VM *vm) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_CMP_STRING: {
|
case OP_CMP_STRING: {
|
||||||
uint32_t addr1 = (uint32_t)vm->stack[vm->sp].registers[src1].u;
|
uint32_t addr1 = (uint32_t)vm->frame_stack[vm->fp].registers[src1].u;
|
||||||
uint32_t addr2 = (uint32_t)vm->stack[vm->sp].registers[src2].u;
|
uint32_t addr2 = (uint32_t)vm->frame_stack[vm->fp].registers[src2].u;
|
||||||
uint32_t length1 = vm->memory[addr1 - 1].u;
|
uint32_t length1 = vm->memory[addr1 - 1].u;
|
||||||
uint32_t length2 = vm->memory[addr2 - 1].u;
|
uint32_t length2 = vm->memory[addr2 - 1].u;
|
||||||
uint32_t equal = 1;
|
uint32_t equal = 1;
|
||||||
|
|
Loading…
Reference in New Issue