diff --git a/arch/linux/tui/main.c b/arch/linux/tui/main.c index cc5afb7..5a860fb 100644 --- a/arch/linux/tui/main.c +++ b/arch/linux/tui/main.c @@ -1,35 +1,38 @@ #include "../../../vm/vm.h" #include -#include +#define FRAMES_SIZE 128 #define CODE_SIZE 8192 #define MEMORY_SIZE 65536 u8 lmem[MEMORY_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) { USED(size); switch(id) { - case SYSCALL_DBG_PRINT: { - u32 val = READ_U32(mem_ptr); - printf("%d\n", val); + case SYSCALL_CONSOLE_WRITE: { + u32 size = *(u32 *)(mem + mem_ptr); + 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 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_LOAD_IMM, 1, 1); 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_A(OP_CALL, 2, 3, 3); - code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 3); + code[cp++] = ENCODE_A(OP_CALL, 2, 3, 0); + 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); /* add */ @@ -52,40 +56,47 @@ void test_add_two_num() { } void test_fibonacci() { - i32 fib = 6; - i32 base_case = 20; /* function main() */ - i32 main_local_count = 3; - mp += (4 * main_local_count); + i32 fib = 7; + i32 base_case = 21; /* fib(35) */ - code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35); - code[cp++] = ENCODE_B(OP_PUSH, 0, 0); - code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib); - code[cp++] = ENCODE_A(OP_CALL, 1, 9, 2); - /* print */ - code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 2); - code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0); - /* function fib (int n) int */ - //code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 0); - code[cp++] = ENCODE_B(OP_LOAD_IMM, 8, fib); - code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2); - code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, base_case); - code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1); - code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2); - code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); - code[cp++] = ENCODE_B(OP_PUSH, 4, 0); - code[cp++] = ENCODE_A(OP_CALL, 8, 9, 5); - code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 1); - code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); - code[cp++] = ENCODE_B(OP_PUSH, 4, 0); - code[cp++] = ENCODE_A(OP_CALL, 8, 9, 6); - code[cp++] = ENCODE_A(OP_ADD_INT, 7, 6, 5); - code[cp++] = ENCODE_B(OP_RETURN, 7, 0); - code[cp++] = ENCODE_B(OP_RETURN, 0, 0); + /*0*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35); + /*1*/ code[cp++] = ENCODE_B(OP_PUSH, 0, 0); + /*2*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib); + /*3*/ code[cp++] = ENCODE_A(OP_CALL, 1, 2, 0); + /**/ /* print */ + /*4*/ code[cp++] = ENCODE_A(OP_INT_TO_STR, 3, 2, 0); + /*5*/ code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_CONSOLE_WRITE, 1, 3); + /*6*/ code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0); + /**/ /* function fib (int n) int */ + /*9*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 8, fib); + /*10*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2); + /*11*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, base_case); + /*12*/ code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1); + /*13*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 1); + /*14*/ code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); + /*15*/ code[cp++] = ENCODE_B(OP_PUSH, 4, 0); + /*16*/ code[cp++] = ENCODE_A(OP_CALL, 8, 5, 0); + /*17*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2); + /*18*/ code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); + /*19*/ code[cp++] = ENCODE_B(OP_PUSH, 4, 0); + /*20*/ code[cp++] = ENCODE_A(OP_CALL, 8, 6, 0); + /*21*/ code[cp++] = ENCODE_A(OP_ADD_INT, 7, 6, 5); + /*22*/ code[cp++] = ENCODE_B(OP_RETURN, 7, 0); + /*23*/ code[cp++] = ENCODE_B(OP_RETURN, 0, 0); } 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_fibonacci(); diff --git a/build b/build index b53db51..020082d 100755 --- a/build +++ b/build @@ -66,7 +66,7 @@ fi # setup the build flags based on the build mode case $MODE in "debug") - BUILD_FLAGS="-g -Wall -Wextra -Werror -pedantic" + BUILD_FLAGS="-g -pg -Wall -Wextra -Werror -pedantic" ;; "release") BUILD_FLAGS="-O2 -Wall -Wextra -Werror -pedantic" diff --git a/vm/vm.c b/vm/vm.c index 7d3f19b..97305ff 100644 --- a/vm/vm.c +++ b/vm/vm.c @@ -10,12 +10,32 @@ u8 status; /* status flag */ u8 interrupt; /* device interrupt */ u32 *code; /* code */ 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() { u32 instruction = code[pc++]; u8 opcode = DECODE_OP(instruction); - u32 *locals = (u32*)(&mem[fp]); + + Frame *frame = &frames[fp]; u32 *globals = (u32*)(mem); switch (opcode) { @@ -25,50 +45,40 @@ bool step_vm() { } case OP_CALL: { DECODE_A(instruction) + Frame *child_frame = &frames[fp + 1]; /* function to jump to */ - u32 fn_ptr = locals[dest]; - /* get mp in 'global indexing mode' */ - u32 gmp = mp / 4; + u32 fn_ptr = frame->local[dest]; /* reset child locals counter */ lc = 0; - /* push parents frame value to reset the heap to */ - globals[gmp] = fp; /* push return address to child frame */ - globals[gmp + 1] = pc; + child_frame->return_address = pc; /* push local address to return the value to */ - globals[gmp + 2] = fp + (src2 * 4); - /* increase the mp to new size */ - mp += FRAME_HEADER_SIZE; + child_frame->parent_return_local = src1; /* now set the frame pointer, where the locals start */ - fp = mp; - /* move mp forward by count many locals */ - mp += (4 * src1); + child_frame->start_mp = mp; + /* increment frame pointer */ + fp++; /* jump to dest_ptr */ pc = fn_ptr; + USED(src2); return true; } case OP_RETURN: { DECODE_B(instruction) u32 i, size = 0; - u32 return_value = locals[dest]; - bool is_ptr = (((u32)(1)) << 15) & imm; - bool replaces_value = (((u32)(1)) << 14) & imm; + u32 return_value = frame->local[dest]; + Frame *child = frame; + 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 */ - 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]; + if (child->parent_return_local != 0xFF) { - 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 */ - WRITE_U32(parent_local_return_address, mp); + parent->local[parent_local_return_address] = mp; size = READ_U32(return_value); WRITE_U32(mp, size); mp += 4; @@ -79,44 +89,48 @@ bool step_vm() { } } else { /* 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 */ - 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; } case OP_SYSCALL: { DECODE_A(instruction) u32 id = dest; /* syscall id */ 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); return true; } case OP_PUSH: { DECODE_B(instruction) - USED(imm); - globals[(mp / 4) + lc + 3] = locals[dest]; + Frame *child_frame = &frames[fp + 1]; + child_frame->local[lc] = frame->local[dest]; lc++; + USED(imm); return true; } case OP_POP: { DECODE_C(instruction) - USED(imm); - mp -= 4; + USED(imm); lc--; return true; } case OP_LOAD_IMM: { DECODE_B(instruction) - locals[dest] = imm; + frame->local[dest] = imm; return true; } case OP_LOAD_UPPER_IMM: { DECODE_B(instruction) - u32 value = locals[dest]; - locals[dest] = (value | (((u32)(imm)) << 16)); + u32 value = frame->local[dest]; + frame->local[dest] = (value | (((u32)(imm)) << 16)); return true; } case OP_LOAD_IND_8: { @@ -171,9 +185,9 @@ bool step_vm() { case OP_MEM_CPY_8: { DECODE_A(instruction) u32 i = 0; - u32 mdest = locals[dest]; - u32 msrc = locals[src1]; - u32 count = locals[src2]; + u32 mdest = frame->local[dest]; + u32 msrc = frame->local[src1]; + u32 count = frame->local[src2]; if (mdest + count >= mp) { status = 1; @@ -190,9 +204,9 @@ bool step_vm() { case OP_MEM_CPY_16: { DECODE_A(instruction) u32 i = 0; - u32 mdest = locals[dest]; - u32 msrc = locals[src1]; - u32 count = locals[src2] * 2; + u32 mdest = frame->local[dest]; + u32 msrc = frame->local[src1]; + u32 count = frame->local[src2] * 2; if (mdest + count >= mp) { status = 1; @@ -210,9 +224,9 @@ bool step_vm() { case OP_MEM_CPY_32: { DECODE_A(instruction) u32 i = 0; - u32 mdest = locals[dest]; - u32 msrc = locals[src1]; - u32 count = locals[src2]; + u32 mdest = frame->local[dest]; + u32 msrc = frame->local[src1]; + u32 count = frame->local[src2]; if (mdest + count >= mp) { status = 1; @@ -361,25 +375,25 @@ bool step_vm() { case OP_MUL_REAL: { DECODE_A(instruction) - i32 src1_whole = (i32)locals[src1] >> 16; - i32 src2_whole = (i32)locals[src2] >> 16; + i32 src1_whole = (i32)frame->local[src1] >> 16; + i32 src2_whole = (i32)frame->local[src2] >> 16; - i32 src1_decimal = (i32)locals[src1] & 16; - i32 src2_decimal = (i32)locals[src2] & 16; + i32 src1_decimal = (i32)frame->local[src1] & 16; + i32 src2_decimal = (i32)frame->local[src2] & 16; i32 result = 0; result += (src1_whole * src2_whole) << 16; result += (src1_whole * src2_decimal); result += (src1_decimal * src2_whole); result += ((src1_decimal * src2_decimal) >> 16) & 16; - locals[dest] = result; + frame->local[dest] = result; return true; } case OP_DIV_REAL: { DECODE_A(instruction) i32 result; - i32 src1_val = (i32)locals[src1]; - i32 src2_val = (i32)locals[src2]; + i32 src1_val = (i32)frame->local[src1]; + i32 src2_val = (i32)frame->local[src2]; u32 src2_reciprocal = 1; src2_reciprocal <<= 31; @@ -388,7 +402,7 @@ bool step_vm() { result = src1_val * src2_reciprocal; result <<= 1; - locals[dest] = result; + frame->local[dest] = result; return true; } case OP_INT_TO_REAL: { @@ -500,7 +514,7 @@ bool step_vm() { case OP_JMP_FLAG: { DECODE_A(instruction) u32 mask; - u32 jmp_dest = locals[dest]; + u32 jmp_dest = frame->local[dest]; if (jmp_dest > cp) { status = 1; return true; @@ -566,9 +580,101 @@ bool step_vm() { case OP_JLE_REAL: { 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 */ status = 255; return false; } + \ No newline at end of file diff --git a/vm/vm.h b/vm/vm.h index 512e580..74246b6 100644 --- a/vm/vm.h +++ b/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_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_INT_TO_STR, + OP_NAT_TO_STR, + OP_REAL_TO_STR, OP_MAX_OPCODE /* not an opcode count of instructions */ } Opcode; typedef enum { - SYSCALL_DBG_PRINT, /* temporary debugging print, use tunnel later */ + SYSCALL_CONSOLE_WRITE, + SYSCALL_CONSOLE_READ, SYSCALL_MAX } 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 cp; /* code pointer */ extern u32 mp; /* memory pointer */ @@ -132,6 +146,7 @@ extern u8 status; /* status flag */ extern u8 interrupt; /* device interrupt */ extern u32 *code; /* code */ extern u8 *mem; /* memory */ +extern Frame *frames; /* stack frame */ #define READ_U8(addr) (mem[addr]) @@ -165,14 +180,14 @@ extern u8 *mem; /* memory */ #define MATH_OP(type, op) \ do { \ 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; \ } while (0) #define MATH_OP_NO_CAST(op) \ do { \ DECODE_A(instruction) \ - locals[dest] = (locals[src1] op locals[src2]); \ + frame->local[dest] = (frame->local[src1] op frame->local[src2]); \ return true; \ } while (0) @@ -181,9 +196,9 @@ extern u8 *mem; /* memory */ DECODE_A(instruction) \ i32 cond; \ u32 mask; \ - u32 target = locals[dest]; \ - type value = (type)locals[src1]; \ - type value2 = (type)locals[src2]; \ + u32 target = frame->local[dest]; \ + type value = (type)frame->local[src1]; \ + type value2 = (type)frame->local[src2]; \ cond = !!(value op value2); \ mask = -(u32)cond; \ pc = (target & mask) | (pc & ~mask); \