wip casting, frames, equivilence, tests
This commit is contained in:
parent
11cfe34c95
commit
ee39c8ba95
|
|
@ -1,24 +1,76 @@
|
|||
#include "../../../vm/vm.h"
|
||||
#include "../../../tools/compiler/compiler.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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() {
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ typedef enum {
|
|||
PREC_COMPARISON, // < > <= >=
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * /
|
||||
PREC_UNARY, // ! -
|
||||
PREC_CAST, // as
|
||||
PREC_UNARY, // ! -
|
||||
PREC_CALL, // . ()
|
||||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
218
vm/vm.c
218
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];
|
||||
|
|
|
|||
191
vm/vm.h
191
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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue