Compare commits
1 Commits
main
...
experiemen
| Author | SHA1 | Date |
|---|---|---|
|
|
c961edeb00 |
|
|
@ -1,35 +1,38 @@
|
||||||
#include "../../../vm/vm.h"
|
#include "../../../vm/vm.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
#define FRAMES_SIZE 128
|
||||||
#define CODE_SIZE 8192
|
#define CODE_SIZE 8192
|
||||||
#define MEMORY_SIZE 65536
|
#define MEMORY_SIZE 65536
|
||||||
u8 lmem[MEMORY_SIZE] = {0};
|
u8 lmem[MEMORY_SIZE] = {0};
|
||||||
u32 lcode[CODE_SIZE] = {0};
|
u32 lcode[CODE_SIZE] = {0};
|
||||||
|
Frame lframes[FRAMES_SIZE] = {0};
|
||||||
|
|
||||||
bool init_vm() {
|
|
||||||
mem = lmem;
|
|
||||||
memset(mem, 0, MEMORY_SIZE*sizeof(u8));
|
|
||||||
code = lcode;
|
|
||||||
lc = 0;
|
|
||||||
mp = 0;
|
|
||||||
cp = 0;
|
|
||||||
pc = 0;
|
|
||||||
interrupt = 0;
|
|
||||||
status = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 syscall(u32 id, u32 size, u32 mem_ptr) {
|
u32 syscall(u32 id, u32 size, u32 mem_ptr) {
|
||||||
USED(size);
|
USED(size);
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case SYSCALL_DBG_PRINT: {
|
case SYSCALL_CONSOLE_WRITE: {
|
||||||
u32 val = READ_U32(mem_ptr);
|
u32 size = *(u32 *)(mem + mem_ptr);
|
||||||
printf("%d\n", val);
|
u32 ptr = mem_ptr + 4;
|
||||||
|
for (u32 i = 0; i < size; i++) {
|
||||||
|
putchar(mem[ptr + i]);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case SYSCALL_CONSOLE_READ: {
|
||||||
|
for (u32 i = 0; i < size; i++) {
|
||||||
|
u8 ch = getchar();
|
||||||
|
if (ch == '\0')
|
||||||
|
break;
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
|
mem[mem_ptr + i] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 1; // generic error
|
return 1; // generic error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,10 +43,11 @@ void test_add_two_num() {
|
||||||
code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
|
code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 1);
|
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 1);
|
||||||
code[cp++] = ENCODE_B(OP_PUSH, 1, 0);
|
code[cp++] = ENCODE_B(OP_PUSH, 1, 0);
|
||||||
i32 add = cp + 4;
|
i32 add = cp + 5;
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, add);
|
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, add);
|
||||||
code[cp++] = ENCODE_A(OP_CALL, 2, 3, 3);
|
code[cp++] = ENCODE_A(OP_CALL, 2, 3, 0);
|
||||||
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 3);
|
code[cp++] = ENCODE_A(OP_INT_TO_STR, 4, 3, 0);
|
||||||
|
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_CONSOLE_WRITE, 1, 4);
|
||||||
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
|
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
|
||||||
|
|
||||||
/* add */
|
/* add */
|
||||||
|
|
@ -52,40 +56,47 @@ void test_add_two_num() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fibonacci() {
|
void test_fibonacci() {
|
||||||
i32 fib = 6;
|
|
||||||
i32 base_case = 20;
|
|
||||||
/* function main() */
|
/* function main() */
|
||||||
i32 main_local_count = 3;
|
i32 fib = 7;
|
||||||
mp += (4 * main_local_count);
|
i32 base_case = 21;
|
||||||
/* fib(35) */
|
/* fib(35) */
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35);
|
/*0*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35);
|
||||||
code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
|
/*1*/ code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib);
|
/*2*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib);
|
||||||
code[cp++] = ENCODE_A(OP_CALL, 1, 9, 2);
|
/*3*/ code[cp++] = ENCODE_A(OP_CALL, 1, 2, 0);
|
||||||
/* print */
|
/**/ /* print */
|
||||||
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 2);
|
/*4*/ code[cp++] = ENCODE_A(OP_INT_TO_STR, 3, 2, 0);
|
||||||
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
|
/*5*/ code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_CONSOLE_WRITE, 1, 3);
|
||||||
/* function fib (int n) int */
|
/*6*/ code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
|
||||||
//code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 0);
|
/**/ /* function fib (int n) int */
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 8, fib);
|
/*9*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 8, fib);
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2);
|
/*10*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2);
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, base_case);
|
/*11*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, base_case);
|
||||||
code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1);
|
/*12*/ code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1);
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2);
|
/*13*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 1);
|
||||||
code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
|
/*14*/ code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
|
||||||
code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
|
/*15*/ code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
|
||||||
code[cp++] = ENCODE_A(OP_CALL, 8, 9, 5);
|
/*16*/ code[cp++] = ENCODE_A(OP_CALL, 8, 5, 0);
|
||||||
code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 1);
|
/*17*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2);
|
||||||
code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
|
/*18*/ code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
|
||||||
code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
|
/*19*/ code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
|
||||||
code[cp++] = ENCODE_A(OP_CALL, 8, 9, 6);
|
/*20*/ code[cp++] = ENCODE_A(OP_CALL, 8, 6, 0);
|
||||||
code[cp++] = ENCODE_A(OP_ADD_INT, 7, 6, 5);
|
/*21*/ code[cp++] = ENCODE_A(OP_ADD_INT, 7, 6, 5);
|
||||||
code[cp++] = ENCODE_B(OP_RETURN, 7, 0);
|
/*22*/ code[cp++] = ENCODE_B(OP_RETURN, 7, 0);
|
||||||
code[cp++] = ENCODE_B(OP_RETURN, 0, 0);
|
/*23*/ code[cp++] = ENCODE_B(OP_RETURN, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 main() {
|
i32 main() {
|
||||||
init_vm();
|
mem = lmem;
|
||||||
|
code = lcode;
|
||||||
|
frames = lframes;
|
||||||
|
lc = 0;
|
||||||
|
mp = 0;
|
||||||
|
cp = 0;
|
||||||
|
pc = 0;
|
||||||
|
fp = 0;
|
||||||
|
interrupt = 0;
|
||||||
|
status = 0;
|
||||||
|
|
||||||
/* test_add_two_num(); */
|
/* test_add_two_num(); */
|
||||||
test_fibonacci();
|
test_fibonacci();
|
||||||
|
|
|
||||||
2
build
2
build
|
|
@ -66,7 +66,7 @@ fi
|
||||||
# setup the build flags based on the build mode
|
# setup the build flags based on the build mode
|
||||||
case $MODE in
|
case $MODE in
|
||||||
"debug")
|
"debug")
|
||||||
BUILD_FLAGS="-g -Wall -Wextra -Werror -pedantic"
|
BUILD_FLAGS="-g -pg -Wall -Wextra -Werror -pedantic"
|
||||||
;;
|
;;
|
||||||
"release")
|
"release")
|
||||||
BUILD_FLAGS="-O2 -Wall -Wextra -Werror -pedantic"
|
BUILD_FLAGS="-O2 -Wall -Wextra -Werror -pedantic"
|
||||||
|
|
|
||||||
218
vm/vm.c
218
vm/vm.c
|
|
@ -10,12 +10,32 @@ u8 status; /* status flag */
|
||||||
u8 interrupt; /* device interrupt */
|
u8 interrupt; /* device interrupt */
|
||||||
u32 *code; /* code */
|
u32 *code; /* code */
|
||||||
u8 *mem; /* memory */
|
u8 *mem; /* memory */
|
||||||
|
Frame *frames;/* stack frame */
|
||||||
|
|
||||||
|
#define MAX_LEN_INT32 11
|
||||||
|
#define MAX_INT32 2147483647
|
||||||
|
#define MIN_INT32 -2147483648
|
||||||
|
const char radix_set[11] = "0123456789";
|
||||||
|
|
||||||
|
u32 str_alloc(const char *str, u32 length) {
|
||||||
|
u32 str_addr = mp;
|
||||||
|
u32 i = 0;
|
||||||
|
mp += 4;
|
||||||
|
while (i < length) {
|
||||||
|
mem[mp++] = str[i++];
|
||||||
|
}
|
||||||
|
mem[mp++] = '\0';
|
||||||
|
|
||||||
|
WRITE_U32(str_addr, length);
|
||||||
|
return str_addr;
|
||||||
|
}
|
||||||
|
|
||||||
bool step_vm() {
|
bool step_vm() {
|
||||||
|
|
||||||
u32 instruction = code[pc++];
|
u32 instruction = code[pc++];
|
||||||
u8 opcode = DECODE_OP(instruction);
|
u8 opcode = DECODE_OP(instruction);
|
||||||
u32 *locals = (u32*)(&mem[fp]);
|
|
||||||
|
Frame *frame = &frames[fp];
|
||||||
u32 *globals = (u32*)(mem);
|
u32 *globals = (u32*)(mem);
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
|
@ -25,50 +45,40 @@ bool step_vm() {
|
||||||
}
|
}
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
|
Frame *child_frame = &frames[fp + 1];
|
||||||
/* function to jump to */
|
/* function to jump to */
|
||||||
u32 fn_ptr = locals[dest];
|
u32 fn_ptr = frame->local[dest];
|
||||||
/* get mp in 'global indexing mode' */
|
|
||||||
u32 gmp = mp / 4;
|
|
||||||
/* reset child locals counter */
|
/* reset child locals counter */
|
||||||
lc = 0;
|
lc = 0;
|
||||||
/* push parents frame value to reset the heap to */
|
|
||||||
globals[gmp] = fp;
|
|
||||||
/* push return address to child frame */
|
/* push return address to child frame */
|
||||||
globals[gmp + 1] = pc;
|
child_frame->return_address = pc;
|
||||||
/* push local address to return the value to */
|
/* push local address to return the value to */
|
||||||
globals[gmp + 2] = fp + (src2 * 4);
|
child_frame->parent_return_local = src1;
|
||||||
/* increase the mp to new size */
|
|
||||||
mp += FRAME_HEADER_SIZE;
|
|
||||||
/* now set the frame pointer, where the locals start */
|
/* now set the frame pointer, where the locals start */
|
||||||
fp = mp;
|
child_frame->start_mp = mp;
|
||||||
/* move mp forward by count many locals */
|
/* increment frame pointer */
|
||||||
mp += (4 * src1);
|
fp++;
|
||||||
/* jump to dest_ptr */
|
/* jump to dest_ptr */
|
||||||
pc = fn_ptr;
|
pc = fn_ptr;
|
||||||
|
USED(src2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_RETURN: {
|
case OP_RETURN: {
|
||||||
DECODE_B(instruction)
|
DECODE_B(instruction)
|
||||||
u32 i, size = 0;
|
u32 i, size = 0;
|
||||||
u32 return_value = locals[dest];
|
u32 return_value = frame->local[dest];
|
||||||
bool is_ptr = (((u32)(1)) << 15) & imm;
|
Frame *child = frame;
|
||||||
bool replaces_value = (((u32)(1)) << 14) & imm;
|
Frame *parent = &frames[fp - 1];
|
||||||
|
u32 parent_local_return_address = frame->parent_return_local;
|
||||||
|
USED(imm);
|
||||||
|
|
||||||
/* reset mp to saved mp, use header size to get "real" start of frame */
|
if (child->parent_return_local != 0xFF) {
|
||||||
u32 frame_start = (fp / 4) - 3;
|
|
||||||
u32 parent_fp = globals[frame_start];
|
|
||||||
u32 return_address = globals[frame_start + 1];
|
|
||||||
u32 parent_local_return_address = globals[frame_start + 2];
|
|
||||||
|
|
||||||
USED(replaces_value);
|
}
|
||||||
/* reset memory to parents end of memory */
|
|
||||||
mp = fp - FRAME_HEADER_SIZE;
|
|
||||||
/* reset the frame pointer */
|
|
||||||
fp = parent_fp;
|
|
||||||
|
|
||||||
if (is_ptr) {
|
if (false) {
|
||||||
/* copy value to end of mp if it is a pointer */
|
/* copy value to end of mp if it is a pointer */
|
||||||
WRITE_U32(parent_local_return_address, mp);
|
parent->local[parent_local_return_address] = mp;
|
||||||
size = READ_U32(return_value);
|
size = READ_U32(return_value);
|
||||||
WRITE_U32(mp, size);
|
WRITE_U32(mp, size);
|
||||||
mp += 4;
|
mp += 4;
|
||||||
|
|
@ -79,44 +89,48 @@ bool step_vm() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* otherwise just write the return value to its location */
|
/* otherwise just write the return value to its location */
|
||||||
WRITE_U32(parent_local_return_address, return_value);
|
parent->local[parent_local_return_address] = return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jump to parent frame */
|
/* jump to parent frame */
|
||||||
pc = return_address;
|
pc = frame->return_address;
|
||||||
|
/* reset memory to parents end of memory */
|
||||||
|
mp = frame->start_mp;
|
||||||
|
/* reset the frame pointer */
|
||||||
|
fp--;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_SYSCALL: {
|
case OP_SYSCALL: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
u32 id = dest; /* syscall id */
|
u32 id = dest; /* syscall id */
|
||||||
u32 size = src1; /* size of heap at that pointer */
|
u32 size = src1; /* size of heap at that pointer */
|
||||||
u32 rd = fp + (src2 * 4); /* the pointer */
|
u32 rd = frame->local[src2]; /* the pointer */
|
||||||
status = syscall(id, size, rd);
|
status = syscall(id, size, rd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_PUSH: {
|
case OP_PUSH: {
|
||||||
DECODE_B(instruction)
|
DECODE_B(instruction)
|
||||||
USED(imm);
|
Frame *child_frame = &frames[fp + 1];
|
||||||
globals[(mp / 4) + lc + 3] = locals[dest];
|
child_frame->local[lc] = frame->local[dest];
|
||||||
lc++;
|
lc++;
|
||||||
|
USED(imm);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_POP: {
|
case OP_POP: {
|
||||||
DECODE_C(instruction)
|
DECODE_C(instruction)
|
||||||
USED(imm);
|
USED(imm);
|
||||||
mp -= 4;
|
|
||||||
lc--;
|
lc--;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_LOAD_IMM: {
|
case OP_LOAD_IMM: {
|
||||||
DECODE_B(instruction)
|
DECODE_B(instruction)
|
||||||
locals[dest] = imm;
|
frame->local[dest] = imm;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_LOAD_UPPER_IMM: {
|
case OP_LOAD_UPPER_IMM: {
|
||||||
DECODE_B(instruction)
|
DECODE_B(instruction)
|
||||||
u32 value = locals[dest];
|
u32 value = frame->local[dest];
|
||||||
locals[dest] = (value | (((u32)(imm)) << 16));
|
frame->local[dest] = (value | (((u32)(imm)) << 16));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_LOAD_IND_8: {
|
case OP_LOAD_IND_8: {
|
||||||
|
|
@ -171,9 +185,9 @@ bool step_vm() {
|
||||||
case OP_MEM_CPY_8: {
|
case OP_MEM_CPY_8: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
u32 mdest = locals[dest];
|
u32 mdest = frame->local[dest];
|
||||||
u32 msrc = locals[src1];
|
u32 msrc = frame->local[src1];
|
||||||
u32 count = locals[src2];
|
u32 count = frame->local[src2];
|
||||||
|
|
||||||
if (mdest + count >= mp) {
|
if (mdest + count >= mp) {
|
||||||
status = 1;
|
status = 1;
|
||||||
|
|
@ -190,9 +204,9 @@ bool step_vm() {
|
||||||
case OP_MEM_CPY_16: {
|
case OP_MEM_CPY_16: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
u32 mdest = locals[dest];
|
u32 mdest = frame->local[dest];
|
||||||
u32 msrc = locals[src1];
|
u32 msrc = frame->local[src1];
|
||||||
u32 count = locals[src2] * 2;
|
u32 count = frame->local[src2] * 2;
|
||||||
|
|
||||||
if (mdest + count >= mp) {
|
if (mdest + count >= mp) {
|
||||||
status = 1;
|
status = 1;
|
||||||
|
|
@ -210,9 +224,9 @@ bool step_vm() {
|
||||||
case OP_MEM_CPY_32: {
|
case OP_MEM_CPY_32: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
u32 mdest = locals[dest];
|
u32 mdest = frame->local[dest];
|
||||||
u32 msrc = locals[src1];
|
u32 msrc = frame->local[src1];
|
||||||
u32 count = locals[src2];
|
u32 count = frame->local[src2];
|
||||||
|
|
||||||
if (mdest + count >= mp) {
|
if (mdest + count >= mp) {
|
||||||
status = 1;
|
status = 1;
|
||||||
|
|
@ -361,25 +375,25 @@ bool step_vm() {
|
||||||
case OP_MUL_REAL: {
|
case OP_MUL_REAL: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
|
|
||||||
i32 src1_whole = (i32)locals[src1] >> 16;
|
i32 src1_whole = (i32)frame->local[src1] >> 16;
|
||||||
i32 src2_whole = (i32)locals[src2] >> 16;
|
i32 src2_whole = (i32)frame->local[src2] >> 16;
|
||||||
|
|
||||||
i32 src1_decimal = (i32)locals[src1] & 16;
|
i32 src1_decimal = (i32)frame->local[src1] & 16;
|
||||||
i32 src2_decimal = (i32)locals[src2] & 16;
|
i32 src2_decimal = (i32)frame->local[src2] & 16;
|
||||||
|
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
result += (src1_whole * src2_whole) << 16;
|
result += (src1_whole * src2_whole) << 16;
|
||||||
result += (src1_whole * src2_decimal);
|
result += (src1_whole * src2_decimal);
|
||||||
result += (src1_decimal * src2_whole);
|
result += (src1_decimal * src2_whole);
|
||||||
result += ((src1_decimal * src2_decimal) >> 16) & 16;
|
result += ((src1_decimal * src2_decimal) >> 16) & 16;
|
||||||
locals[dest] = result;
|
frame->local[dest] = result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_DIV_REAL: {
|
case OP_DIV_REAL: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
i32 result;
|
i32 result;
|
||||||
i32 src1_val = (i32)locals[src1];
|
i32 src1_val = (i32)frame->local[src1];
|
||||||
i32 src2_val = (i32)locals[src2];
|
i32 src2_val = (i32)frame->local[src2];
|
||||||
|
|
||||||
u32 src2_reciprocal = 1;
|
u32 src2_reciprocal = 1;
|
||||||
src2_reciprocal <<= 31;
|
src2_reciprocal <<= 31;
|
||||||
|
|
@ -388,7 +402,7 @@ bool step_vm() {
|
||||||
result = src1_val * src2_reciprocal;
|
result = src1_val * src2_reciprocal;
|
||||||
result <<= 1;
|
result <<= 1;
|
||||||
|
|
||||||
locals[dest] = result;
|
frame->local[dest] = result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_INT_TO_REAL: {
|
case OP_INT_TO_REAL: {
|
||||||
|
|
@ -500,7 +514,7 @@ bool step_vm() {
|
||||||
case OP_JMP_FLAG: {
|
case OP_JMP_FLAG: {
|
||||||
DECODE_A(instruction)
|
DECODE_A(instruction)
|
||||||
u32 mask;
|
u32 mask;
|
||||||
u32 jmp_dest = locals[dest];
|
u32 jmp_dest = frame->local[dest];
|
||||||
if (jmp_dest > cp) {
|
if (jmp_dest > cp) {
|
||||||
status = 1;
|
status = 1;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -566,9 +580,101 @@ bool step_vm() {
|
||||||
case OP_JLE_REAL: {
|
case OP_JLE_REAL: {
|
||||||
COMPARE_AND_JUMP(i32, <=);
|
COMPARE_AND_JUMP(i32, <=);
|
||||||
}
|
}
|
||||||
|
case OP_INT_TO_STR: {
|
||||||
|
DECODE_A(instruction)
|
||||||
|
|
||||||
|
u32 i = MAX_LEN_INT32;
|
||||||
|
i32 v = (i32)frame->local[src1];
|
||||||
|
char buffer[MAX_LEN_INT32];
|
||||||
|
i32 n = v;
|
||||||
|
bool neg = n < 0;
|
||||||
|
USED(src2);
|
||||||
|
|
||||||
|
if (neg)
|
||||||
|
n = -n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
buffer[--i] = radix_set[n % 10];
|
||||||
|
n /= 10;
|
||||||
|
} while (n > 0);
|
||||||
|
if (neg)
|
||||||
|
buffer[--i] = '-';
|
||||||
|
/* Ensure at least one digit is written for 0 */
|
||||||
|
if (v == 0)
|
||||||
|
buffer[--i] = '0';
|
||||||
|
|
||||||
|
/* Copy from buffer[i] to buffer + MAX_LEN_INT32 */
|
||||||
|
frame->local[dest] = str_alloc(buffer + i, MAX_LEN_INT32 - i);
|
||||||
|
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
case OP_NAT_TO_STR: {
|
||||||
|
DECODE_A(instruction)
|
||||||
|
|
||||||
|
u32 v = (i32)frame->local[src1];
|
||||||
|
char buffer[MAX_LEN_INT32];
|
||||||
|
u32 n = v;
|
||||||
|
u32 i = MAX_LEN_INT32;
|
||||||
|
USED(src2);
|
||||||
|
do {
|
||||||
|
buffer[--i] = radix_set[n % 10];
|
||||||
|
n /= 10;
|
||||||
|
} while (n > 0);
|
||||||
|
/* Ensure at least one digit is written for 0 */
|
||||||
|
if (v == 0)
|
||||||
|
buffer[--i] = '0';
|
||||||
|
/* Copy from buffer[i] to buffer + MAX_LEN_INT32 */
|
||||||
|
frame->local[dest] = str_alloc(buffer + i, MAX_LEN_INT32 - i);
|
||||||
|
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
case OP_REAL_TO_STR: {
|
||||||
|
DECODE_A(instruction)
|
||||||
|
|
||||||
|
u32 i = 0, j = 0;
|
||||||
|
i32 q = (i32)frame->local[src1];
|
||||||
|
char buffer[MAX_LEN_INT32];
|
||||||
|
u32 int_part, frac_part;
|
||||||
|
|
||||||
|
if (q < 0) {
|
||||||
|
buffer[i++] = '-';
|
||||||
|
q = -q;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_part = q >> 16;
|
||||||
|
frac_part = q & 0xFFFF;
|
||||||
|
USED(src2);
|
||||||
|
|
||||||
|
if (int_part == 0) {
|
||||||
|
buffer[i++] = radix_set[0];
|
||||||
|
} else {
|
||||||
|
char tmp[16];
|
||||||
|
i32 tmp_i = 0;
|
||||||
|
while (int_part > 0) {
|
||||||
|
tmp[tmp_i++] = radix_set[int_part % 10];
|
||||||
|
int_part /= 10;
|
||||||
|
}
|
||||||
|
while (tmp_i > 0) {
|
||||||
|
buffer[i++] = tmp[--tmp_i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i++] = '.';
|
||||||
|
for (j = 0; j < 6; j++) {
|
||||||
|
frac_part *= 10;
|
||||||
|
buffer[i++] = radix_set[frac_part >> 16];
|
||||||
|
frac_part &= 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->local[dest] = str_alloc(buffer + i, MAX_LEN_INT32 - i);
|
||||||
|
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* something went very wrong */
|
/* something went very wrong */
|
||||||
status = 255;
|
status = 255;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
27
vm/vm.h
27
vm/vm.h
|
|
@ -115,14 +115,28 @@ typedef enum {
|
||||||
OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */
|
OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */
|
||||||
OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */
|
OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */
|
||||||
OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */
|
OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */
|
||||||
|
OP_INT_TO_STR,
|
||||||
|
OP_NAT_TO_STR,
|
||||||
|
OP_REAL_TO_STR,
|
||||||
OP_MAX_OPCODE /* not an opcode count of instructions */
|
OP_MAX_OPCODE /* not an opcode count of instructions */
|
||||||
} Opcode;
|
} Opcode;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SYSCALL_DBG_PRINT, /* temporary debugging print, use tunnel later */
|
SYSCALL_CONSOLE_WRITE,
|
||||||
|
SYSCALL_CONSOLE_READ,
|
||||||
SYSCALL_MAX
|
SYSCALL_MAX
|
||||||
} Syscall;
|
} Syscall;
|
||||||
|
|
||||||
|
#define MAX_LOCALS 32
|
||||||
|
typedef struct frame_s Frame;
|
||||||
|
struct frame_s {
|
||||||
|
u32 return_address;
|
||||||
|
u32 parent_return_local;
|
||||||
|
u32 start_mp;
|
||||||
|
u32 local_is_ptr;
|
||||||
|
u32 local[MAX_LOCALS];
|
||||||
|
};
|
||||||
|
|
||||||
extern u32 pc; /* program counter */
|
extern u32 pc; /* program counter */
|
||||||
extern u32 cp; /* code pointer */
|
extern u32 cp; /* code pointer */
|
||||||
extern u32 mp; /* memory pointer */
|
extern u32 mp; /* memory pointer */
|
||||||
|
|
@ -132,6 +146,7 @@ extern u8 status; /* status flag */
|
||||||
extern u8 interrupt; /* device interrupt */
|
extern u8 interrupt; /* device interrupt */
|
||||||
extern u32 *code; /* code */
|
extern u32 *code; /* code */
|
||||||
extern u8 *mem; /* memory */
|
extern u8 *mem; /* memory */
|
||||||
|
extern Frame *frames; /* stack frame */
|
||||||
|
|
||||||
#define READ_U8(addr) (mem[addr])
|
#define READ_U8(addr) (mem[addr])
|
||||||
|
|
||||||
|
|
@ -165,14 +180,14 @@ extern u8 *mem; /* memory */
|
||||||
#define MATH_OP(type, op) \
|
#define MATH_OP(type, op) \
|
||||||
do { \
|
do { \
|
||||||
DECODE_A(instruction) \
|
DECODE_A(instruction) \
|
||||||
locals[dest] = ((type)locals[src1] op (type)locals[src2]); \
|
frame->local[dest] = ((type)frame->local[src1] op (type)frame->local[src2]); \
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MATH_OP_NO_CAST(op) \
|
#define MATH_OP_NO_CAST(op) \
|
||||||
do { \
|
do { \
|
||||||
DECODE_A(instruction) \
|
DECODE_A(instruction) \
|
||||||
locals[dest] = (locals[src1] op locals[src2]); \
|
frame->local[dest] = (frame->local[src1] op frame->local[src2]); \
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
@ -181,9 +196,9 @@ extern u8 *mem; /* memory */
|
||||||
DECODE_A(instruction) \
|
DECODE_A(instruction) \
|
||||||
i32 cond; \
|
i32 cond; \
|
||||||
u32 mask; \
|
u32 mask; \
|
||||||
u32 target = locals[dest]; \
|
u32 target = frame->local[dest]; \
|
||||||
type value = (type)locals[src1]; \
|
type value = (type)frame->local[src1]; \
|
||||||
type value2 = (type)locals[src2]; \
|
type value2 = (type)frame->local[src2]; \
|
||||||
cond = !!(value op value2); \
|
cond = !!(value op value2); \
|
||||||
mask = -(u32)cond; \
|
mask = -(u32)cond; \
|
||||||
pc = (target & mask) | (pc & ~mask); \
|
pc = (target & mask) | (pc & ~mask); \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue