diff --git a/arch/linux/gui/main.c b/arch/linux/gui/main.c index 97f6885..6ef0b52 100644 --- a/arch/linux/gui/main.c +++ b/arch/linux/gui/main.c @@ -1,24 +1,76 @@ #include "../../../vm/vm.h" +#include "../../../tools/compiler/compiler.h" + #include #include -#define CODE_SIZE 8192 #define MEMORY_SIZE 65536 +#define CODE_SIZE 8192 +#define STACK_SIZE 1024 + u8 lmem[MEMORY_SIZE] = {0}; -u32 lcode[CODE_SIZE] = {0}; +u8 lcode[CODE_SIZE] = {0}; +u32 lstack[STACK_SIZE] = {0}; +Frame lframes[STACK_SIZE] = {0}; + +void reset() { + pc = 0; + cp = 0; + mp = 0; + fp = 0; + sp = 0; + interrupt = 0; + status = 0; +} bool init_vm() { mem = lmem; code = lcode; - mp = 0; - cp = 0; - pc = 0; - interrupt = 0; + stack = lstack; + frames = lframes; + reset(); + return true; +} + +void error(const char* msg) { + printf("%s", msg); +} + +bool table_realloc(ScopeTable *table) { + USED(table); + // static so do nothing; return true; } u32 syscall(u32 id, u32 mem_ptr) { - return 0; // success + u32 size; + switch(id) { + case SYSCALL_CONSOLE_WRITE: { + u32 size = *(u32*)&mem[mem_ptr]; + u8 *ptr = &mem[mem_ptr + 4]; + for (u32 i = 0; i < size; i++) { + putchar(*(ptr++)); + } + return 0; + } + case SYSCALL_CONSOLE_READ: { + u8 *ptr = &mem[mp]; + mcpy(ptr, &size, sizeof(u32)); + ptr += 4; + for (u32 i = 0; i < size; i++) { + u8 ch = getchar(); + if (ch == '\0') + break; + if (ch == '\n') + break; + *(ptr++) = ch; + } + ptr[size] = '\0'; + mp += 4 + size + 1; + } + } + + return 1; // generic error } i32 main() { diff --git a/arch/linux/tui/main.c b/arch/linux/tui/main.c index ac6d2e4..4c25067 100644 --- a/arch/linux/tui/main.c +++ b/arch/linux/tui/main.c @@ -9,11 +9,12 @@ u8 lmem[MEMORY_SIZE] = {0}; u8 lcode[CODE_SIZE] = {0}; u32 lstack[STACK_SIZE] = {0}; +Frame lframes[STACK_SIZE] = {0}; void reset() { pc = 0; cp = 0; - mp = 255; // hardcoded for now, 255 locals + mp = 0; fp = 0; sp = 0; interrupt = 0; @@ -24,6 +25,7 @@ bool init_vm() { mem = lmem; code = lcode; stack = lstack; + frames = lframes; reset(); return true; } @@ -86,9 +88,7 @@ static void repl() { while(step_vm()) {} - syscall(SYSCALL_CONSOLE_WRITE, 255); - - printf("Result at top of stack: %d\n", stack[0]); + syscall(SYSCALL_CONSOLE_WRITE, stack[0]); } } diff --git a/test/add.ul b/test/add.ul new file mode 100644 index 0000000..7e42565 --- /dev/null +++ b/test/add.ul @@ -0,0 +1,31 @@ +/** + * Constants + */ +const str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + pln(add(1, 1).str); +} + +/** + * Add two numbers together + */ +function add(int a, int b) int { + return a + b; +} + +/** + * Print with a newline + */ +function pln(str message) { + Terminal term = open("term::/0", 0); + write(term, message, message.length); + write(term, nl, nl.length); +} diff --git a/test/fib.ul b/test/fib.ul new file mode 100644 index 0000000..3bfde3d --- /dev/null +++ b/test/fib.ul @@ -0,0 +1,32 @@ +/** + * Constants + */ +const str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + pln(fib(35).str); +} + +/** + * Recursively calculate fibonacci + */ +function fib(int n) int { + if (n < 2) { return n; } + return fib(n - 2) + fib(n - 1); +} + +/** + * Print with a newline + */ +function pln(str message) { + Terminal term = open("term::/0", 0); + write(term, message, message.length); + write(term, nl, nl.length); +} diff --git a/test/hello.ul b/test/hello.ul new file mode 100644 index 0000000..4943849 --- /dev/null +++ b/test/hello.ul @@ -0,0 +1,23 @@ +/** + * Plexes + */ +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + pln("nuqneH 'u'?"); +} + +/** + * Print with a newline + */ +function pln(str message) { + Terminal term = open("term::/0", 0); + write(term, message, message.length); + const str nl = "\n"; + write(term, nl, nl.length); +} diff --git a/test/malloc.ul b/test/malloc.ul new file mode 100644 index 0000000..1716001 --- /dev/null +++ b/test/malloc.ul @@ -0,0 +1,26 @@ +/** + * Constants + */ +const str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + Terminal term = open("term::/0", 0); + pln(term, "Enter a string: "); + pln(term, term.read(32)); + return 0; +} + +/** + * Print with a newline + */ +function pln(Terminal term, str message) { + write(term, message, message.length); + write(term, nl, nl.length); +} diff --git a/test/paint.ul b/test/paint.ul new file mode 100644 index 0000000..7a655c5 --- /dev/null +++ b/test/paint.ul @@ -0,0 +1,109 @@ +/** + * Constants + */ +const byte BLACK = 0; +const byte WHITE = 255; +const byte DARK_GRAY = 73; +const byte GRAY = 146; +const byte LIGHT_GRAY = 182; + +byte selected_color = 255; + +trait Device { + nat handle; +} + +plex Screen implements Device { + nat handle; + nat width; + nat height; + byte[] buffer; + + draw() { + write(this, this.buffer, this.buffer.length); + } +} + +plex Mouse implements Device { + nat handle; + nat x; + nat y; + bool left; + bool right; + bool middle; + bool btn4; +} + +/** + * Main function + */ +function main() { + Screen screen = open("screen::/0", 0); + Mouse mouse = open("mouse::/0", 0); + + outline_swatch(screen, BLACK, 1, 1); + outline_swatch(screen, WHITE, 21, 1); + screen.draw(); + + loop { + mouse.refresh(); + if (!mouse.left) continue; + + int box_size = 20; + int x = 1; + int y = 1; + byte color = BLACK; + outlined_swatch(screen, color, x, y); + set_color(box_size, x, y, mouse.x, mouse.y, color); + + color = WHITE; + x = 21; + outlined_swatch(screen, color, x, y); + set_color(box_size, x, y, mouse.x, mouse.y, color); + screen.draw(); + + rectangle(screen, selected_color, x, y, 5, 5); + } + exit(0); +} + +/** + * Checks if the click is within the bound and update the selected color if so. + */ +function set_color(int box_size, int bx, int by, int mx, int my, byte color) { + int right = bx + box_size; + int bottom = by + box_size; + + if (mx < bx) return; + if (mx > right) return; + if (my < by) return; + if (my > bottom) return; + + selected_color = color; +} + +/** + * Draw a color box with a grey outline, if selected use a darker color + */ +function outline_swatch(Device screen, byte color, int x, int y) { + byte bg_color = GRAY; + if (selected_color == color) { + bg_color = DARK_GRAY; + } + + rectangle(screen, bg_color, x, y, 20, 20); + rectangle(screen, color, x + 2, y + 2, 17, 17); +} + +/** + * Draw a rectangle + */ +function rectangle(Device screen, byte color, int x, int y, int width, int height) { + int base = y * screen.width + x + screen.buffer.ptr + 4; + + do (int i = height; i > 0; i--) { + int row = base + width; + memset(screen.buffer, row, color, width); + base += screen.width; + } +} diff --git a/test/simple.ul b/test/simple.ul new file mode 100644 index 0000000..b59a206 --- /dev/null +++ b/test/simple.ul @@ -0,0 +1,25 @@ +/** + * Constants + */ +const str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + pln((1.0 + 1.0) as str); + exit(0); +} + +/** + * Print with a newline + */ +function pln(str message) { + Terminal term = open("term::/0", 0); + write(term, message, message.length); + write(term, nl, nl.length); +} diff --git a/test/window.ul b/test/window.ul new file mode 100644 index 0000000..9a17453 --- /dev/null +++ b/test/window.ul @@ -0,0 +1,72 @@ +/** + * Constants + */ +const str screen_namespace = "screen::/0" +const str mouse_namespace = "mouse::/0" +const str terminal_namespace = "term::/0" +const str new_line = "\n" +const byte WHITE = 255 + +/** + * Devices + */ +plex Terminal { + nat handle; +} + +plex Screen { + nat handle; + nat width; + nat height; + byte[] buffer; + + draw() { + write(this, this.buffer, this.buffer_size); + } +} + +plex Mouse { + nat handle; + nat x; + nat y; + bool left; + bool right; + bool middle; + bool btn4; + nat size; +} + +/** + * Main function + */ +function main() { + Screen screen = open(screen_namespace, 0); + pln(screen.handle as str); + pln(screen.width as str); + pln(screen.size as str); + unsafe { + pln(screen.screen_buffer.ptr as str); + } + + Mouse mouse = open(mouse_namespace, 0); + screen.draw(); + + loop { + if (mouse.left) { + unsafe { + screen.buffer[mouse.y * width + mouse.x + + screen.buffer.ptr + 4] = WHITE; + screen.draw(); + } + } + } +} + +/** + * Print with a newline + */ +function pln(str message) { + Terminal term = open(terminal_namespace, 0); + write(term, message, message.length); + write(term, nl, nl.length); +} diff --git a/tools/compiler/compiler.c b/tools/compiler/compiler.c index a909904..950010d 100644 --- a/tools/compiler/compiler.c +++ b/tools/compiler/compiler.c @@ -235,9 +235,7 @@ static void grouping() { static void unary() { TokenType operatorType = parser.previous.type; - parsePrecedence(PREC_UNARY); - switch (operatorType) { case TOKEN_MINUS: { code[cp++] = OP_NEG; @@ -252,11 +250,67 @@ static void unary() { } } +static void cast(TokenType prev) { + switch (prev) { + case TOKEN_TYPE_I8: { + + break; + } + case TOKEN_TYPE_I16: { + + break; + } + case TOKEN_TYPE_INT: { + + break; + } + case TOKEN_TYPE_U8: { + + break; + } + case TOKEN_TYPE_U16: { + + break; + } + case TOKEN_TYPE_NAT: { + + break; + } + case TOKEN_TYPE_REAL: { + + break; + } + case TOKEN_TYPE_BOOL: { + + break; + } + case TOKEN_TYPE_STR: { + + break; + } + default: { + printf("Cannot cast to type (%s)\n", token_type_to_string(parser.previous.type)); + } + } +} + static void binary() { TokenType operatorType = parser.previous.type; + TokenType operand = parser.current.type; + ParseRule *rule = getRule(operatorType); parsePrecedence((Precedence)(rule->precedence + 1)); + + printf("before prev: %s, operatorType: %s, operand: %s\n", + token_type_to_string(parser.previous.type), + token_type_to_string(operatorType), + token_type_to_string(operand)); + switch (operatorType) { + case TOKEN_KEYWORD_AS: { + cast(parser.previous.type); + break; + } case TOKEN_PLUS: { switch (parser.previous.type) { case TOKEN_LITERAL_INT: @@ -273,7 +327,7 @@ static void binary() { break; default: printf("Unknown Add Arg=%d\n", parser.previous.type); - return; // Unreachable. + return; } break; } @@ -338,23 +392,111 @@ static void binary() { break; } case TOKEN_EQ_EQ: { - code[cp++] = OP_EQ; + switch (parser.previous.type) { + case TOKEN_LITERAL_INT: + case TOKEN_LITERAL_REAL: + code[cp++] = OP_EQS; + break; + case TOKEN_LITERAL_NAT: + code[cp++] = OP_EQU; + break; + case TOKEN_IDENTIFIER: + printf("FIXME: find the identifier's type for ==\n"); + break; + default: + printf("Unknown == Arg=%d\n", parser.previous.type); + return; // Unreachable. + } + break; + } + case TOKEN_BANG_EQ: { + switch (parser.previous.type) { + case TOKEN_LITERAL_INT: + case TOKEN_LITERAL_REAL: + code[cp++] = OP_NES; + break; + case TOKEN_LITERAL_NAT: + code[cp++] = OP_NEU; + break; + case TOKEN_IDENTIFIER: + printf("FIXME: find the identifier's type for !=\n"); + break; + default: + printf("Unknown != Arg=%d\n", parser.previous.type); + return; // Unreachable. + } break; } case TOKEN_GT: { - code[cp++] = OP_GT; + switch (parser.previous.type) { + case TOKEN_LITERAL_INT: + case TOKEN_LITERAL_REAL: + code[cp++] = OP_GTS; + break; + case TOKEN_LITERAL_NAT: + code[cp++] = OP_GTU; + break; + case TOKEN_IDENTIFIER: + printf("FIXME: find the identifier's type for >\n"); + break; + default: + printf("Unknown > Arg=%d\n", parser.previous.type); + return; // Unreachable. + } break; } case TOKEN_GTE: { - code[cp++] = OP_GE; + switch (parser.previous.type) { + case TOKEN_LITERAL_INT: + case TOKEN_LITERAL_REAL: + code[cp++] = OP_GES; + break; + case TOKEN_LITERAL_NAT: + code[cp++] = OP_GEU; + break; + case TOKEN_IDENTIFIER: + printf("FIXME: find the identifier's type for >=\n"); + break; + default: + printf("Unknown >= Arg=%d\n", parser.previous.type); + return; // Unreachable. + } break; } case TOKEN_LT: { - code[cp++] = OP_LT; + switch (parser.previous.type) { + case TOKEN_LITERAL_INT: + case TOKEN_LITERAL_REAL: + code[cp++] = OP_LTS; + break; + case TOKEN_LITERAL_NAT: + code[cp++] = OP_LTU; + break; + case TOKEN_IDENTIFIER: + printf("FIXME: find the identifier's type for <\n"); + break; + default: + printf("Unknown < Arg=%d\n", parser.previous.type); + return; // Unreachable. + } break; } case TOKEN_LTE: { - code[cp++] = OP_LE; + switch (parser.previous.type) { + case TOKEN_LITERAL_REAL: + case TOKEN_LITERAL_INT: + code[cp++] = OP_LES; + break; + case TOKEN_LITERAL_NAT: + code[cp++] = OP_LEU; + break; + case TOKEN_IDENTIFIER: + printf("FIXME: find the identifier's type for <=\n"); + break; + default: + printf("Unknown <= Arg=%d\n", parser.previous.type); + return; // Unreachable. + } break; } default: @@ -421,10 +563,12 @@ static void string() { WRITE_U32(addr, len); WRITE_U8(addr + 4 + len, '\0'); - // TODO: this really should always be tied to a global or local variable - // we can fake it for now - WRITE_U32(fp + lp, addr); - lp++; + /* push address of string on the stack */ + code[cp++] = OP_PUSH_32; + code[cp++] = (addr) & 0xFF; + code[cp++] = ((addr) >> 8) & 0xFF; + code[cp++] = ((addr) >> 16) & 0xFF; + code[cp++] = ((addr) >> 24) & 0xFF; } ParseRule rules[] = { @@ -453,6 +597,7 @@ ParseRule rules[] = { [TOKEN_LITERAL_NAT] = {number, NULL, PREC_NONE}, [TOKEN_LITERAL_REAL] = {number, NULL, PREC_NONE}, [TOKEN_AND] = {NULL, NULL, PREC_NONE}, + [TOKEN_KEYWORD_AS] = {NULL, binary, PREC_CAST}, [TOKEN_KEYWORD_PLEX] = {NULL, NULL, PREC_NONE}, [TOKEN_KEYWORD_ELSE] = {NULL, NULL, PREC_NONE}, [TOKEN_KEYWORD_FALSE] = {literal, NULL, PREC_NONE}, diff --git a/tools/compiler/compiler.h b/tools/compiler/compiler.h index 8f9fe41..11074cc 100644 --- a/tools/compiler/compiler.h +++ b/tools/compiler/compiler.h @@ -93,7 +93,8 @@ typedef enum { PREC_COMPARISON, // < > <= >= PREC_TERM, // + - PREC_FACTOR, // * / - PREC_UNARY, // ! - + PREC_CAST, // as + PREC_UNARY, // ! - PREC_CALL, // . () PREC_PRIMARY } Precedence; diff --git a/tools/compiler/parser.c b/tools/compiler/parser.c index 6f7fd68..1379a0d 100644 --- a/tools/compiler/parser.c +++ b/tools/compiler/parser.c @@ -206,12 +206,21 @@ static TokenType identifierType() { case 'e': if (lexer.current - lexer.start > 2) { switch (lexer.start[2]) { - case 'a': - return checkKeyword(3, 1, "d", TOKEN_KEYWORD_READ); case 'f': return checkKeyword(3, 4, "resh", TOKEN_KEYWORD_REFRESH); case 't': return checkKeyword(3, 3, "urn", TOKEN_KEYWORD_RETURN); + case 'a': + if (lexer.current - lexer.start > 3) { + switch (lexer.start[3]) { + case 'd': { + return checkKeyword(4, 0, "", TOKEN_KEYWORD_READ); + } + case 'l': { + return checkKeyword(4, 0, "", TOKEN_TYPE_REAL); + } + } + } } } break; diff --git a/vm/vm.c b/vm/vm.c index ea3a8dc..b0d2bf6 100644 --- a/vm/vm.c +++ b/vm/vm.c @@ -1,21 +1,19 @@ #include "vm.h" #define FRAME_HEADER_SIZE 12 -u32 pc; /* program counter */ -u32 cp; /* code pointer */ -u32 mp; /* memory pointer */ -u32 fp; /* frame pointer */ +u32 *stack; /* stack */ u32 sp; /* stack pointer */ -u8 lp; /* locals pointer */ +u8 *code; /* code */ +u32 cp; /* code pointer */ +u8 *mem; /* memory */ +u32 mp; /* memory pointer */ +Frame *frames; /* call frames */ +u32 fp; /* frame pointer */ +u32 pc; /* program counter */ u8 status; /* status flag */ u8 interrupt; /* device interrupt */ -u32 *stack; /* stack */ -u8 *code; /* code */ -u8 *mem; /* memory */ #define MAX_LEN_INT32 11 -#define MAX_INT32 2147483647 -#define MIN_INT32 -2147483648 const char radix_set[11] = "0123456789"; u32 str_alloc(char *str, u32 length) { @@ -41,7 +39,6 @@ bool step_vm() { return false; } case OP_CALL: { - /* TODO: Fix this one so it makes sense with a stack based system */ /* function to jump to */ u32 fn_ptr = stack[--sp]; /* get mp in 'global indexing mode' */ @@ -93,7 +90,7 @@ bool step_vm() { return false; } case OP_SYSCALL: { - u32 id = stack[--sp]; /* syscall id */ + u32 id = stack[--sp]; /* syscall id */ u32 rd = stack[--sp]; /* the pointer */ status = syscall(id, rd); return true; @@ -111,8 +108,9 @@ bool step_vm() { return true; } case OP_PUSH_32: { - u32 *values = (u32*)(code); - u32 value = values[pc/4]; + u32 value = ((u32)code[(pc) + 3] << 24) | + ((u32)code[(pc) + 2] << 16) | + ((u32)code[(pc) + 1] << 8) | ((u32)mem[(pc)]); pc+=4; stack[sp++] = value; return true; @@ -122,28 +120,44 @@ bool step_vm() { return true; } case OP_LOAD_8: { - return false; + u32 ptr = stack[--sp]; + u32 value = mem[ptr]; + stack[sp++] = value; + return true; } case OP_LOAD_16: { - return false; + u32 ptr = stack[--sp]; + u16 *values = (u16*)(&mem[ptr]); + u32 value = values[0]; + stack[sp++] = value; + return true; } case OP_LOAD_32: { - return false; + u32 ptr = stack[--sp]; + u32 *values = (u32*)(&mem[ptr]); + u32 value = values[0]; + stack[sp++] = value; + return true; } case OP_STORE_8: { - return false; + u32 ptr = stack[--sp]; + u8 value = (u8)stack[--sp]; + mem[ptr] = value; + return true; } case OP_STORE_16: { - return false; + u32 ptr = stack[--sp]; + u16 value = (u16)stack[--sp]; + u16 *values = (u16*)(&mem[ptr]); + values[0] = value; + return true; } case OP_STORE_32: { - return false; - } - case OP_SET: { - return false; - } - case OP_GET: { - return false; + u32 ptr = stack[--sp]; + u32 value = stack[--sp]; + u32 *values = (u32*)(&mem[ptr]); + values[0] = value; + return true; } case OP_MEM_ALLOC: { u32 size = stack[--sp]; @@ -153,113 +167,109 @@ bool step_vm() { return true; } case OP_MEM_CPY_8: { - u32 i = 0; + u8 *ptr_src; + u8 *ptr_dest; u32 count = stack[--sp]; - u8 msrc = (u8)stack[--sp]; - u32 mdest = stack[--sp]; + u32 src = stack[--sp]; + u32 dest = stack[--sp]; - if (mdest + count >= mp) { + if (dest + count >= mp) { status = 1; return true; } - for (i = 0; i < count; i++) { - mem[msrc + i] = mem[mdest + i]; - } + ptr_dest = &mem[dest]; + ptr_src = &mem[src]; + mcpy(ptr_dest, ptr_src, count*sizeof(u8)); status = 0; return true; } case OP_MEM_CPY_16: { - u32 i = 0; + u8 *ptr_src; + u8 *ptr_dest; u32 count = stack[--sp]; - u16 msrc = (u16)stack[--sp]; - u32 mdest = stack[--sp]; + u32 src = stack[--sp]; + u32 dest = stack[--sp]; - if (mdest + count >= mp) { + if (dest + count >= mp) { status = 1; return true; } - for (i = 0; i < count; i++) { - u16 value = READ_U16(mdest + i); - WRITE_U16(msrc + i, value); - } + ptr_dest = &mem[dest]; + ptr_src = &mem[src]; + mcpy(ptr_dest, ptr_src, count*sizeof(u16)); status = 0; return true; } case OP_MEM_CPY_32: { - u32 i = 0; + u8 *ptr_src; + u8 *ptr_dest; u32 count = stack[--sp]; - u32 msrc = stack[--sp]; - u32 mdest = stack[--sp]; + u32 src = stack[--sp]; + u32 dest = stack[--sp]; - if (mdest + count >= mp) { + if (dest + count >= mp) { status = 1; return true; } - for (i = 0; i < count; i++) { - globals[msrc + i] = globals[mdest + i]; - } + ptr_dest = &mem[dest]; + ptr_src = &mem[src]; + mcpy(ptr_dest, ptr_src, count*sizeof(u32)); status = 0; return true; } case OP_MEM_SET_8: { - u32 i, start, end; + u8 *ptr_dest; u8 value = (u8)stack[--sp]; u32 count = stack[--sp]; - start = stack[--sp]; - end = start + count; + u32 dest = stack[--sp]; - if (start >= mp || end > mp) { + if (dest + count >= mp) { status = 1; return true; } - for (i = start; i < end; i++) { - mem[i] = value; - } + ptr_dest = &mem[dest]; + mcpy(ptr_dest, &value, count*sizeof(u8)); status = 0; return true; } case OP_MEM_SET_16: { - u32 i, start, end; + u8 *ptr_dest; u16 value = (u16)stack[--sp]; u32 count = stack[--sp]; - start = stack[--sp]; - end = start + count; + u32 dest = stack[--sp]; - if (start >= mp || end > mp) { + if (dest + count >= mp) { status = 1; return true; } - for (i = start; i < end; i += 2) { - WRITE_U16(i, value); - } + ptr_dest = &mem[dest]; + mcpy(ptr_dest, &value, count*sizeof(u16)); status = 0; return true; } case OP_MEM_SET_32: { - u32 i, start, end; + u8 *ptr_dest; u32 value = stack[--sp]; u32 count = stack[--sp]; - start = stack[--sp]; - end = start + count; + u32 dest = stack[--sp]; - if (start >= mp || end > mp) { + if (dest + count >= mp) { status = 1; return true; } - for (i = start; i < end; i += 4) { - WRITE_U32(i, value); - } + ptr_dest = &mem[dest]; + mcpy(ptr_dest, &value, count*sizeof(u32)); status = 0; return true; @@ -288,9 +298,6 @@ bool step_vm() { stack[sp++] = b; return true; } - case OP_ROT: { - return false; - } case OP_DEPTH: { u32 a = sp; stack[sp++] = a; @@ -400,64 +407,71 @@ bool step_vm() { return true; } case OP_BIT_SHIFT_LEFT: { - MATH_OP_NO_CAST(<<); + MATH_OP(u32, <<); } case OP_BIT_SHIFT_RIGHT: { - MATH_OP_NO_CAST(>>); + MATH_OP(u32, >>); } case OP_BIT_SHIFT_R_EXT: { MATH_OP(i32, >>); } case OP_BIT_AND: { - MATH_OP_NO_CAST(&); + MATH_OP(u32, &); } case OP_BIT_OR: { - MATH_OP_NO_CAST(|); + MATH_OP(u32, |); } case OP_BIT_XOR: { - MATH_OP_NO_CAST(^); + MATH_OP(u32, ^); } - case OP_EQ: { - MATH_OP_NO_CAST(==); + case OP_EQS: { + MATH_OP(i32, ==); } - case OP_NE: { - MATH_OP_NO_CAST(!=); + case OP_NES: { + MATH_OP(i32, !=); } - case OP_GT: { - MATH_OP_NO_CAST(>); + case OP_GTS: { + MATH_OP(i32, >); } - case OP_LT: { - MATH_OP_NO_CAST(<); + case OP_LTS: { + MATH_OP(i32, <); } - case OP_LE: { - MATH_OP_NO_CAST(<=); + case OP_LES: { + MATH_OP(i32, <=); } - case OP_GE: { - MATH_OP_NO_CAST(>=); + case OP_GES: { + MATH_OP(i32, >=); + } + case OP_EQU: { + MATH_OP(u32, ==); + } + case OP_NEU: { + MATH_OP(u32, !=); + } + case OP_GTU: { + MATH_OP(u32, >); + } + case OP_LTU: { + MATH_OP(u32, <); + } + case OP_LEU: { + MATH_OP(u32, <=); + } + case OP_GEU: { + MATH_OP(u32, >=); } case OP_JMP: { - u32 jmp_dest = stack[--sp]; - if (jmp_dest > cp) { - status = 1; - return true; - } - - pc = jmp_dest; + pc = stack[--sp]; return true; } case OP_JMP_FLAG: { u32 mask; u32 jmp_dest = stack[--sp]; - if (jmp_dest > cp) { - status = 1; - return true; - } - mask = -(u32)(status == 0); pc = (jmp_dest & mask) | (pc & ~mask); return true; } - case OP_JMP_IF: { + case OP_JNZ: { u32 mask, target; i32 cond = stack[--sp]; target = stack[--sp]; diff --git a/vm/vm.h b/vm/vm.h index 3017631..cce5a37 100644 --- a/vm/vm.h +++ b/vm/vm.h @@ -4,80 +4,81 @@ #include "libc.h" typedef enum { - OP_HALT, /* - `halt` | halt execution */ - OP_CALL, /* ptr `call` | creates a new frame */ - OP_RETURN, /* - `return` | returns from a frame to the parent frame */ - OP_SYSCALL, /* id args mem_ptr `syscall` - | id args mem_ptr : does a system call based on id with args */ - OP_LOAD_8, /* dest `load-8` u8 | push memory[obj1] onto stack as u8 */ - OP_LOAD_16, /* dest `load-16` u16 | push memory[obj1] onto stack as u16 */ - OP_LOAD_32, /* dest `load` u32 | push memory[obj1] onto stack as u32 */ - OP_STORE_8, /* dest obj1 `store-8` - | memory[dest] = obj1 << 8 */ - OP_STORE_16, /* dest obj1 `store-16`- | memory[dest] = obj1 << 16 */ - OP_STORE_32, /* dest obj1 `store` - | memory[dest] = obj1 */ - OP_MALLOC, /* size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */ - OP_PUSH_8, /* const `push8` obj1 | push a 8 bit const onto the stack */ - OP_PUSH_16, /* const `push16` obj1 | push a 16 bit const onto the stack */ - OP_PUSH_32, /* const `push32` obj1 | push a 32 bit const onto the stack */ - OP_POP, /* - `pop` - | removes top item from the stack */ - OP_SET, /* obj1 local `set` - | set the value of the local slot */ - /*OP_SET_ADDRESS, addr local `set_address` - | set the address of the value of the local slot */ - OP_GET, /* local `get` obj1 | get the value of the local slot */ - /*OP_GET_ADDRESS, local `get_address` obj1 | get the address of the value of the local slot */ - OP_DUP, /* obj1 `dup` obj1 obj1 | duplicates the top of the stack */ - OP_EXCH, /* obj2 obj1 `exch` obj1 obj2 | swaps the top two values on the stack */ - OP_OVER, /* obj2 obj1 `over` obj2 | copys the 2nd to the top element and pushes to the stack */ - OP_PICK, /* N `pick` objN | gets the nth element on the stack and pushes it on top */ - OP_ROT, /* obj3 obj2 obj1 `rot` obj2 obj1 obj3 | takes the 3rd element and moves it to the top of the stack */ - OP_DEPTH, /* - `depth` heap_count | pushes the number of elements on the stack to the stack*/ - OP_MEM_ALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */ - OP_MEM_CPY_8, /* size src dest `memcpy_8` - | memory[src..src+size] = memory[dest..dest+size] */ - OP_MEM_CPY_16, /* size src dest `memcpy_16` - | memory[src..src+size] = memory[dest..dest+size] */ - OP_MEM_CPY_32, /* size src dest `memcpy_32` - | memory[src..src+size] = memory[dest..dest+size] */ - OP_MEM_SET_8, /* size src dest `memset_8` - | memory[dest..dest+size] = local[src] as u8 */ - OP_MEM_SET_16, /* size src dest `memset_16` - | memory[dest..dest+size] = local[src] as u16 */ - OP_MEM_SET_32, /* size src dest `memset_32` - | memory[dest..dest+size] = local[src] as u32 */ - OP_ADD_INT, /* obj2 obj1 `add_int` obj | obj1 + obj2 then push result on stack */ - OP_SUB_INT, /* obj2 obj1 `sub_int` obj | obj1 - obj2 then push result on stack */ - OP_MUL_INT, /* obj2 obj1 `mul_int` obj | obj1 * obj2 then push result on stack */ - OP_DIV_INT, /* obj2 obj1 `div_int` obj | obj1 / obj2 then push result on stack */ - OP_ADD_NAT, /* obj2 obj1 `add_nat` obj | obj1 + obj2 then push result on stack */ - OP_SUB_NAT, /* obj2 obj1 `sub_nat` obj | obj1 - obj2 then push result on stack */ - OP_MUL_NAT, /* obj2 obj1 `mul_nat` obj | obj1 * obj2 then push result on stack */ - OP_DIV_NAT, /* obj2 obj1 `div_nat` obj | obj1 / obj2 then push result on stack */ - OP_ADD_REAL, /* obj2 obj1 `add_real` obj | obj1 + obj2 then push result on stack */ - OP_SUB_REAL, /* obj2 obj1 `sub_real` obj | obj1 - obj2 then push result on stack */ - OP_MUL_REAL, /* obj2 obj1 `mul_real` obj | obj1 * obj2 then push result on stack */ - OP_DIV_REAL, /* obj2 obj1 `div_real` obj | obj1 / obj2 then push result on stack */ - OP_INT_TO_REAL, /* obj1 `int_to_real` obj1 as real | casts an int to a fixed number */ - OP_INT_TO_NAT, /* obj1 `int_to_nat` obj1 as nat | casts an int to a unsigned int */ - OP_NAT_TO_REAL, /* obj1 `nat_to_real` obj1 as real | casts a unsigned int to a fixed number */ - OP_NAT_TO_INT, /* obj1 `nat_to_int` obj1 as int | casts a unsigned int to an int */ - OP_REAL_TO_INT, /* obj1 `real_to_int` obj1 as int | casts a fixed number to an int */ - OP_REAL_TO_NAT, /* obj1 `real_to_nat` obj1 as nat | casts a fixed number to an unsigned int */ - OP_BIT_SHIFT_LEFT, /* obj2 obj1 `bit_shift_left` obj | src1] << locals[src2] */ - OP_BIT_SHIFT_RIGHT, /* obj2 obj1 `bit_shift_right` obj | src1] >> locals[src2] */ - OP_BIT_SHIFT_R_EXT, /* obj2 obj1 `bit_shift_r_ext` obj | src1 >> src2 then cast result as i32 */ - OP_BIT_AND, /* obj2 obj1 `bit_and` obj | obj1 & obj2 */ - OP_BIT_OR, /* obj2 obj1 `bit_or` obj | obj1 | obj2 */ - OP_BIT_XOR, /* obj2 obj1 `bit_xor` obj | obj1 ^ obj2 */ - OP_NEG, /* obj1 `neg` -obj | -obj1 */ - OP_NOT, /* obj1 `bit_xor` !obj | not obj1 */ - OP_JMP, /* pc `jump` | jump unconditionally */ - OP_JMP_FLAG, /* pc `jump_if_flag` | jump to pc if flag > 0 */ - OP_JMP_IF, /* obj1 pc `jump_if | jump to pc if obj1 != 0 */ - OP_EQ, /* obj2 obj1 `eq` | obj1 == obj2*/ - OP_NE, /* obj2 obj1 `ne` | obj1 != obj2*/ - OP_GT, /* obj2 obj1 `gt` | obj1 > obj2*/ - OP_LT, /* obj2 obj1 `lt` | obj1 < obj2*/ - OP_LE, /* obj2 obj1 `le` | obj1 <= obj2*/ - OP_GE, /* obj2 obj1 `ge` | obj1 >= obj2*/ - OP_INT_TO_STR, /* obj1 `int_to_string` str_ptr | convert obj1 to str */ - OP_NAT_TO_STR, /* obj1 `nat_to_string` str_ptr | convert obj1 to str */ - OP_REAL_TO_STR, /* obj1 `real_to_string` str_ptr | convert obj1 to str */ - OP_STR_TO_INT, /* str_ptr `string_to_int` obj | convert obj1 to int */ - OP_STR_TO_NAT, /* str_ptr `string_to_nat` obj | convert obj1 to nat */ - OP_STR_TO_REAL, /* str_ptr `string_to_real` obj | convert obj1 to real */ - OP_MAX_OPCODE /* not an opcode count of instructions */ + OP_HALT, /* - `halt` | halt execution */ + OP_CALL, /* ptr `call` - | creates a new frame */ + OP_RETURN, /* - `return` - | returns from a frame to the parent frame */ + OP_SYSCALL, /* id mem_ptr `syscall` - | does a system call based on id with args */ + OP_LOAD_8, /* dest `ld8` u8 | push memory[obj1] onto stack as u8 */ + OP_LOAD_16, /* dest `ld16` u16 | push memory[obj1] onto stack as u16 */ + OP_LOAD_32, /* dest `ld32` u32 | push memory[obj1] onto stack as u32 */ + OP_STORE_8, /* dest obj1 `st8` - | memory[dest] = obj1 << 8 */ + OP_STORE_16, /* dest obj1 `st16` - | memory[dest] = obj1 << 16 */ + OP_STORE_32, /* dest obj1 `st32` - | memory[dest] = obj1 */ + OP_MALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */ + OP_PUSH_8, /* const `push8` obj1 | push a 8 bit const onto the stack */ + OP_PUSH_16, /* const `push16` obj1 | push a 16 bit const onto the stack */ + OP_PUSH_32, /* const `push32` obj1 | push a 32 bit const onto the stack */ + OP_POP, /* - `pop` - | removes top item from the stack */ + OP_DUP, /* obj1 `dup` obj1 obj1 | duplicates the top of the stack */ + OP_EXCH, /* obj2 obj1 `exch` obj1 obj2 | swaps the top two values on the stack */ + OP_OVER, /* obj2 obj1 `over` obj2 | copys the 2nd to the top element and pushes to the stack */ + OP_PICK, /* N `pick` objN | gets the nth element on the stack and pushes it on top */ + OP_DEPTH, /* - `depth` stack_count | pushes the number of elements on the stack to the stack */ + OP_MEM_ALLOC, /* size `alloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack */ + OP_MEM_CPY_8, /* size src dest `mcpy8` - | memory[src..src+size] = memory[dest..dest+size] */ + OP_MEM_CPY_16, /* size src dest `mcpy16` - | memory[src..src+size] = memory[dest..dest+size] */ + OP_MEM_CPY_32, /* size src dest `mcpy32` - | memory[src..src+size] = memory[dest..dest+size] */ + OP_MEM_SET_8, /* size src dest `mset8` - | memory[dest..dest+size] = local[src] as u8 */ + OP_MEM_SET_16, /* size src dest `mset16` - | memory[dest..dest+size] = local[src] as u16 */ + OP_MEM_SET_32, /* size src dest `mset32` - | memory[dest..dest+size] = local[src] as u32 */ + OP_ADD_INT, /* obj2 obj1 `addi` obj | obj1 + obj2 then push result on stack */ + OP_SUB_INT, /* obj2 obj1 `subi` obj | obj1 - obj2 then push result on stack */ + OP_MUL_INT, /* obj2 obj1 `muli` obj | obj1 * obj2 then push result on stack */ + OP_DIV_INT, /* obj2 obj1 `divi` obj | obj1 / obj2 then push result on stack */ + OP_ADD_NAT, /* obj2 obj1 `addn` obj | obj1 + obj2 then push result on stack */ + OP_SUB_NAT, /* obj2 obj1 `subn` obj | obj1 - obj2 then push result on stack */ + OP_MUL_NAT, /* obj2 obj1 `muln` obj | obj1 * obj2 then push result on stack */ + OP_DIV_NAT, /* obj2 obj1 `divn` obj | obj1 / obj2 then push result on stack */ + OP_ADD_REAL, /* obj2 obj1 `addr` obj | obj1 + obj2 then push result on stack */ + OP_SUB_REAL, /* obj2 obj1 `subr` obj | obj1 - obj2 then push result on stack */ + OP_MUL_REAL, /* obj2 obj1 `mulr` obj | obj1 * obj2 then push result on stack */ + OP_DIV_REAL, /* obj2 obj1 `divr` obj | obj1 / obj2 then push result on stack */ + OP_INT_TO_REAL, /* obj1 `itor` real | casts an int to a fixed number */ + OP_INT_TO_NAT, /* obj1 `iton` nat | casts an int to a unsigned int */ + OP_NAT_TO_REAL, /* obj1 `ntor` real | casts a unsigned int to a fixed number */ + OP_NAT_TO_INT, /* obj1 `ntoi` int | casts a unsigned int to an int */ + OP_REAL_TO_INT, /* obj1 `rtoi` int | casts a fixed number to an int */ + OP_REAL_TO_NAT, /* obj1 `rton` nat | casts a fixed number to an unsigned int */ + OP_BIT_SHIFT_LEFT, /* obj2 obj1 `sll` obj | src1] << locals[src2] */ + OP_BIT_SHIFT_RIGHT, /* obj2 obj1 `srl` obj | src1] >> locals[src2] */ + OP_BIT_SHIFT_R_EXT, /* obj2 obj1 `sre` obj | src1 >> src2 then cast result as i32 */ + OP_BIT_AND, /* obj2 obj1 `band` obj | obj1 & obj2 */ + OP_BIT_OR, /* obj2 obj1 `bor` obj | obj1 | obj2 */ + OP_BIT_XOR, /* obj2 obj1 `bxor` obj | obj1 ^ obj2 */ + OP_NEG, /* obj1 `neg` obj | -obj1 */ + OP_NOT, /* obj1 `not` obj | not obj1 */ + OP_JMP, /* pc `jump` | jump unconditionally */ + OP_JMP_FLAG, /* pc `jmpf` | jump to pc if flag > 0 */ + OP_JNZ, /* obj1 pc `jnz` | jump to pc if obj1 != 0 */ + OP_EQU, /* obj2 obj1 `equ` bool | unsigned obj1 == obj2 */ + OP_NEU, /* obj2 obj1 `neu` bool | unsigned obj1 != obj2 */ + OP_GTU, /* obj2 obj1 `gtu` bool | unsigned obj1 > obj2 */ + OP_LTU, /* obj2 obj1 `ltu` bool | unsigned obj1 < obj2 */ + OP_LEU, /* obj2 obj1 `leu` bool | unsigned obj1 <= obj2 */ + OP_GEU, /* obj2 obj1 `geu` bool | unsigned obj1 >= obj2 */ + OP_EQS, /* obj2 obj1 `eqs` bool | signed obj1 == obj2 */ + OP_NES, /* obj2 obj1 `nes` bool | signed obj1 != obj2 */ + OP_GTS, /* obj2 obj1 `gts` bool | signed obj1 > obj2 */ + OP_LTS, /* obj2 obj1 `lts` bool | signed obj1 < obj2 */ + OP_LES, /* obj2 obj1 `les` bool | signed obj1 <= obj2 */ + OP_GES, /* obj2 obj1 `ges` bool | signed obj1 >= obj2 */ + OP_INT_TO_STR, /* obj1 `itos` str_ptr | convert obj1 to str */ + OP_NAT_TO_STR, /* obj1 `ntos` str_ptr | convert obj1 to str */ + OP_REAL_TO_STR, /* obj1 `rtos` str_ptr | convert obj1 to str */ + OP_STR_TO_INT, /* str_ptr `stoi` obj | convert obj1 to int */ + OP_STR_TO_NAT, /* str_ptr `ntoi` obj | convert obj1 to nat */ + OP_STR_TO_REAL, /* str_ptr `stor` obj | convert obj1 to real */ + OP_MAX_OPCODE /* not an opcode count of instructions */ } Opcode; typedef enum { @@ -92,17 +93,17 @@ struct frame_s { u32 start_mp; }; -extern u32 pc; /* program counter */ -extern u32 cp; /* code pointer */ -extern u32 mp; /* memory pointer */ -extern u32 fp; /* frame pointer */ -extern u32 sp; /* stack pointer */ -extern u8 lp; /* locals pointer */ -extern u8 status; /* status flag */ -extern u8 interrupt; /* device interrupt */ -extern u32 *stack; /* stack */ -extern u8 *code; /* code */ -extern u8 *mem; /* memory */ +extern u8 *code; /* code */ +extern u32 cp; /* code pointer */ +extern u8 *mem; /* memory */ +extern u32 mp; /* memory pointer */ +extern u32 *stack; /* stack */ +extern u32 sp; /* stack pointer */ +extern Frame *frames; /* call frames */ +extern u32 fp; /* frame pointer */ +extern u32 pc; /* program counter */ +extern u8 status; /* status flag */ +extern u8 interrupt; /* device interrupt */ #define READ_U8(addr) (mem[addr]) @@ -133,20 +134,12 @@ extern u8 *mem; /* memory */ mem[addr + 3] = ((value) >> 24) & 0xFF; \ } while (0) -#define MATH_OP(type, op) \ - do { \ - type b = (type)stack[--sp]; \ - type a = (type)stack[--sp]; \ - stack[sp++] = (type)(a op b); \ - return true; \ - } while (0) - -#define MATH_OP_NO_CAST(op) \ - do { \ - u32 b = stack[--sp]; \ - u32 a = stack[--sp]; \ - stack[sp++] = a op b; \ - return true; \ +#define MATH_OP(type, op) \ + do { \ + type b = (type)stack[--sp]; \ + type a = (type)stack[--sp]; \ + stack[sp++] = (type)(a op b); \ + return true; \ } while (0) extern bool init_vm();