Add malloc, load-r, load-r8. fix endianess, refactor devices, init box, init window drawing
This commit is contained in:
parent
d6893b85a8
commit
77033e121b
|
@ -207,7 +207,7 @@ cd undar-lang && make
|
|||
(syscall DEVICE_WRITE $0 $1 $2)
|
||||
(load $3 &new-line)
|
||||
(string-length $4 $3)
|
||||
(syscall DEVICE-WRITE, $0, $3, $4)
|
||||
(syscall WRITE, $0, $3, $4)
|
||||
(halt)))
|
||||
(data
|
||||
(label terminal-str "/dev/term/0")
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
Device screen("/dev/screen/0");
|
||||
u8[] colors = [0,255,36,73,146,182,128,224,144,
|
||||
252,9,18,12,16,28,159,2,3,10,19,131,147,130,227,129,226,
|
||||
72,141,136,241,208,244];
|
||||
|
||||
fn main() {
|
||||
screen.open(0);
|
||||
screen.draw();
|
||||
|
||||
int x = 10;
|
||||
int y = 20;
|
||||
for (int i = 0; i < colors.length; i+=2) {
|
||||
draw_outline_swatch(colors[i], x, y);
|
||||
draw_outline_swatch(colors[i + 1], x + 20, y);
|
||||
x += 20;
|
||||
y += 20;
|
||||
}
|
||||
screen.draw();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fn draw_outline_swatch(u8 color, int x, int y) {
|
||||
u8 gray = colors[5];
|
||||
int outline_size = 20;
|
||||
int fill_size = 17;
|
||||
int offset = 2;
|
||||
|
||||
draw_box(gray, x, y, outline_size, outline_size);
|
||||
int swatch_pos = x + 2;
|
||||
int offset_pos = y + 2;
|
||||
draw_box(color, swatch_pos, offset_pos, fill_size, fill_size);
|
||||
return;
|
||||
}
|
||||
|
||||
fn draw_box(u8 color, int x, int y, int width, int height) {
|
||||
int screen_width = screen.width;
|
||||
int pos = y * 640 + x;
|
||||
|
||||
do (int i = height; i > 0; i--) {
|
||||
int row = pos + width;
|
||||
int pixel = offset;
|
||||
do (int j = ; pos;j++) {
|
||||
screen.buffer[j] = color;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,10 +36,10 @@ i32 console_close(void *data) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
i32 console_ioctl(void *data, u32 cmd, void *args) {
|
||||
i32 console_ioctl(void *data, u32 cmd, const u8 *buffer) {
|
||||
USED(data);
|
||||
USED(cmd);
|
||||
USED(args);
|
||||
USED(buffer);
|
||||
return -1; /* Unsupported */
|
||||
}
|
||||
|
||||
|
@ -81,13 +81,12 @@ i32 screen_write(void *data, const u8 *buffer, u32 size) {
|
|||
ScreenDeviceData *screen = (ScreenDeviceData *)data;
|
||||
USED(buffer);
|
||||
|
||||
if (size > screen->framebuffer_size * sizeof(u8)) {
|
||||
if (size > screen->size * sizeof(u8)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (screen->texture && screen->renderer) {
|
||||
SDL_UpdateTexture(screen->texture, nil,
|
||||
&screen->vm->memory[screen->framebuffer_pos],
|
||||
SDL_UpdateTexture(screen->texture, nil, &buffer[screen->pos],
|
||||
screen->width);
|
||||
|
||||
SDL_RenderClear(screen->renderer);
|
||||
|
@ -128,16 +127,23 @@ i32 screen_close(void *data) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
i32 screen_ioctl(void *data, u32 cmd, void *args) {
|
||||
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer) {
|
||||
ScreenDeviceData *screen = (ScreenDeviceData *)data;
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_GET_INFO: {
|
||||
u32 *info = (u32 *)args;
|
||||
memcpy(&screen->vm->memory[*info], &screen->framebuffer_pos, sizeof(u32));
|
||||
memcpy(&screen->vm->memory[*info + 1], &screen->framebuffer_size, sizeof(u32));
|
||||
memcpy(&screen->vm->memory[*info + 2], &screen->width, sizeof(u32));
|
||||
memcpy(&screen->vm->memory[*info + 3], &screen->height, sizeof(u32));
|
||||
u8 *info = (u8 *)buffer;
|
||||
u32 size;
|
||||
memcpy(&size, &info[0], sizeof(u32));
|
||||
|
||||
if (size < 16) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&info[4], &screen->pos, sizeof(u32));
|
||||
memcpy(&info[8], &screen->size, sizeof(u32));
|
||||
memcpy(&info[12], &screen->width, sizeof(u32));
|
||||
memcpy(&info[16], &screen->height, sizeof(u32));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -156,14 +162,47 @@ i32 mouse_open(void *data, u32 mode) {
|
|||
i32 mouse_read(void *data, u8 *buffer, u32 size) {
|
||||
MouseDeviceData *mouse = (MouseDeviceData *)data;
|
||||
|
||||
if (size < 3 * sizeof(u32))
|
||||
if (size < 12)
|
||||
return -1;
|
||||
|
||||
u32 *out = (u32 *)buffer;
|
||||
out[0] = mouse->x;
|
||||
out[1] = mouse->y;
|
||||
out[2] = (mouse->btn1 | (mouse->btn2 << 1) | (mouse->btn3 << 2) |
|
||||
(mouse->btn4 << 3));
|
||||
SDL_PumpEvents();
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse->x = event.motion.x;
|
||||
mouse->y = event.motion.y;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (event.button.button == SDL_BUTTON_LEFT)
|
||||
mouse->btn1 = 1;
|
||||
if (event.button.button == SDL_BUTTON_RIGHT)
|
||||
mouse->btn2 = 1;
|
||||
if (event.button.button == SDL_BUTTON_MIDDLE)
|
||||
mouse->btn3 = 1;
|
||||
if (event.button.button == SDL_BUTTON_X1)
|
||||
mouse->btn4 = 1;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (event.button.button == SDL_BUTTON_LEFT)
|
||||
mouse->btn1 = 0;
|
||||
if (event.button.button == SDL_BUTTON_RIGHT)
|
||||
mouse->btn2 = 0;
|
||||
if (event.button.button == SDL_BUTTON_MIDDLE)
|
||||
mouse->btn3 = 0;
|
||||
if (event.button.button == SDL_BUTTON_X1)
|
||||
mouse->btn4 = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *info = (u8 *)buffer;
|
||||
memcpy(&info[0], &mouse->x, sizeof(u32));
|
||||
memcpy(&info[4], &mouse->y, sizeof(u32));
|
||||
memcpy(&info[8], &mouse->btn1, sizeof(u8));
|
||||
memcpy(&info[9], &mouse->btn2, sizeof(u8));
|
||||
memcpy(&info[10], &mouse->btn3, sizeof(u8));
|
||||
memcpy(&info[11], &mouse->btn4, sizeof(u8));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,8 @@
|
|||
typedef struct screen_device_data_s {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 framebuffer_pos;
|
||||
u32 framebuffer_size;
|
||||
VM* vm;
|
||||
u32 pos;
|
||||
u32 size;
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Texture *texture;
|
||||
|
@ -24,19 +23,23 @@ typedef struct mouse_device_data_s {
|
|||
u8 btn2;
|
||||
u8 btn3;
|
||||
u8 btn4;
|
||||
u32 pos;
|
||||
u32 size;
|
||||
} MouseDeviceData;
|
||||
|
||||
/* Keyboard device data */
|
||||
typedef struct keyboard_device_data_s {
|
||||
const u8 *keys;
|
||||
i32 key_count;
|
||||
u32 pos;
|
||||
u32 size;
|
||||
} KeyboardDeviceData;
|
||||
|
||||
i32 screen_open(void *data, u32 mode);
|
||||
i32 screen_read(void *data, u8 *buffer, u32 size);
|
||||
i32 screen_write(void *data, const u8 *buffer, u32 size);
|
||||
i32 screen_close(void *data);
|
||||
i32 screen_ioctl(void *data, u32 cmd, void *args);
|
||||
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer);
|
||||
|
||||
i32 mouse_open(void *data, u32 mode);
|
||||
i32 mouse_read(void *data, u8 *buffer, u32 size);
|
||||
|
@ -52,4 +55,4 @@ i32 console_open(void *data, u32 mode);
|
|||
i32 console_read(void *data, u8 *buffer, u32 size);
|
||||
i32 console_write(void *data, const u8 *buffer, u32 size);
|
||||
i32 console_close(void *data);
|
||||
i32 console_ioctl(void *data, u32 cmd, void *args);
|
||||
i32 console_ioctl(void *data, u32 cmd, const u8 *buffer);
|
||||
|
|
|
@ -146,6 +146,7 @@ bool compileAndSave(const char *source_file, const char *output_file, VM *vm) {
|
|||
printf("Parse failed.\n");
|
||||
return false;
|
||||
} else {
|
||||
expr_print(ast, 0);
|
||||
assemble(vm, ast);
|
||||
expr_free(ast);
|
||||
|
||||
|
@ -237,16 +238,13 @@ void repl(VM *vm) {
|
|||
* This needs to be done dynamically eventually
|
||||
*/
|
||||
void register_sdl_devices(VM *vm) {
|
||||
screen_data.vm = vm;
|
||||
screen_data.width = 640;
|
||||
screen_data.height = 480;
|
||||
screen_data.framebuffer_size = 640 * 480;
|
||||
screen_data.framebuffer_pos = vm->mp;
|
||||
vm->mp += screen_data.framebuffer_size; /* advance memory pointer */
|
||||
screen_data.size = 640 * 480;
|
||||
screen_data.pos = vm->mp;
|
||||
vm->mp += screen_data.size; /* advance memory pointer */
|
||||
vm->frames[vm->fp].end = vm->mp;
|
||||
|
||||
printf("%d\n", screen_data.framebuffer_pos );
|
||||
|
||||
vm_register_device(vm, "/dev/screen/0", "screen", &screen_data, &screen_ops);
|
||||
|
||||
mouse_data.x = 0;
|
||||
|
@ -255,15 +253,98 @@ void register_sdl_devices(VM *vm) {
|
|||
mouse_data.btn2 = 0;
|
||||
mouse_data.btn3 = 0;
|
||||
mouse_data.btn4 = 0;
|
||||
mouse_data.size = 12;
|
||||
mouse_data.pos = vm->mp;
|
||||
vm->mp += mouse_data.size; /* advance memory pointer */
|
||||
vm->frames[vm->fp].end = vm->mp;
|
||||
|
||||
vm_register_device(vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops);
|
||||
|
||||
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
|
||||
|
||||
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
|
||||
&keyboard_ops);
|
||||
}
|
||||
|
||||
const char *opcode_to_string(Opcode op) {
|
||||
static const char *names[] = {[OP_HALT] = "halt",
|
||||
[OP_JMP] = "jump",
|
||||
[OP_JMPF] = "jump-if-flag",
|
||||
[OP_CALL] = "call",
|
||||
[OP_RETURN] = "return",
|
||||
[OP_LOAD] = "load",
|
||||
[OP_LOAD_REG] = "load-r",
|
||||
[OP_LOAD_REG8] = "load-r8",
|
||||
[OP_LOADI8] = "load-i8",
|
||||
[OP_LOADU8] = "load-u8",
|
||||
[OP_LOADI16] = "load-i16",
|
||||
[OP_LOADU16] = "load-u16",
|
||||
[OP_LOAD_IMM] = "load-immediate",
|
||||
[OP_MALLOC] = "malloc",
|
||||
[OP_STORE] = "store",
|
||||
[OP_STORE8] = "store-8",
|
||||
[OP_STORE16] = "store-16",
|
||||
[OP_PUSH] = "push",
|
||||
[OP_POP] = "pop",
|
||||
[OP_REG_MOV] = "register-move",
|
||||
[OP_SYSCALL] = "syscall",
|
||||
[OP_SLL] = "bit-shift-left",
|
||||
[OP_SRL] = "bit-shift-right",
|
||||
[OP_SRE] = "bit-shift-right-extend",
|
||||
[OP_BAND] = "bit-and",
|
||||
[OP_BOR] = "bit-or",
|
||||
[OP_BXOR] = "bit-xor",
|
||||
[OP_ADD_INT] = "add-int",
|
||||
[OP_SUB_INT] = "sub-int",
|
||||
[OP_MUL_INT] = "mul-int",
|
||||
[OP_DIV_INT] = "div-int",
|
||||
[OP_ADD_UINT] = "add-nat",
|
||||
[OP_SUB_UINT] = "sub-nat",
|
||||
[OP_MUL_UINT] = "mul-nat",
|
||||
[OP_DIV_UINT] = "div-nat",
|
||||
[OP_ADD_REAL] = "add-real",
|
||||
[OP_SUB_REAL] = "sub-real",
|
||||
[OP_MUL_REAL] = "mul-real",
|
||||
[OP_DIV_REAL] = "div-real",
|
||||
[OP_INT_TO_REAL] = "int-to-real",
|
||||
[OP_UINT_TO_REAL] = "nat-to-real",
|
||||
[OP_REAL_TO_INT] = "real-to-int",
|
||||
[OP_REAL_TO_UINT] = "real-to-nat",
|
||||
[OP_JEQ_INT] = "jump-eq-int",
|
||||
[OP_JGT_INT] = "jump-gt-int",
|
||||
[OP_JLT_INT] = "jump-lt-int",
|
||||
[OP_JLE_INT] = "jump-le-int",
|
||||
[OP_JGE_INT] = "jump-ge-int",
|
||||
[OP_JEQ_UINT] = "jump-eq-nat",
|
||||
[OP_JGT_UINT] = "jump-gt-nat",
|
||||
[OP_JLT_UINT] = "jump-lt-nat",
|
||||
[OP_JLE_UINT] = "jump-le-nat",
|
||||
[OP_JGE_UINT] = "jump-ge-nat",
|
||||
[OP_JEQ_REAL] = "jump-eq-real",
|
||||
[OP_JGE_REAL] = "jump-ge-real",
|
||||
[OP_JGT_REAL] = "jump-gt-real",
|
||||
[OP_JLT_REAL] = "jump-lt-real",
|
||||
[OP_JLE_REAL] = "jump-le-real",
|
||||
[OP_STRLEN] = "string-length",
|
||||
[OP_STREQ] = "string-eq",
|
||||
[OP_STRCAT] = "string-concat",
|
||||
[OP_STR_GET_CHAR] = "string-get-char",
|
||||
[OP_STR_FIND_CHAR] = "string-find-char",
|
||||
[OP_STR_SLICE] = "string-slice",
|
||||
[OP_INT_TO_STRING] = "int-to-string",
|
||||
[OP_UINT_TO_STRING] = "nat-to-string",
|
||||
[OP_REAL_TO_STRING] = "real-to-string",
|
||||
[OP_STRING_TO_INT] = "string-to-int",
|
||||
[OP_STRING_TO_UINT] = "string-to-nat",
|
||||
[OP_STRING_TO_REAL] = "string-to-real"};
|
||||
|
||||
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
|
||||
return "<invalid-opcode>";
|
||||
}
|
||||
|
||||
const char *name = names[op];
|
||||
return name ? name : "<unknown-opcode>";
|
||||
}
|
||||
|
||||
i32 main(i32 argc, char *argv[]) {
|
||||
bool gui_mode = false;
|
||||
bool dump_rom = false;
|
||||
|
@ -331,55 +412,22 @@ i32 main(i32 argc, char *argv[]) {
|
|||
bool running = true;
|
||||
|
||||
vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops);
|
||||
|
||||
if (gui_mode) {
|
||||
register_sdl_devices(&vm);
|
||||
|
||||
while (running) {
|
||||
for (u32 i = 0; i < vm.dc; i++) {
|
||||
Device *dev = &vm.devices[i];
|
||||
if (strcmp(dev->type, "mouse") == 0) {
|
||||
MouseDeviceData *mouse = (MouseDeviceData *)dev->data;
|
||||
SDL_PumpEvents();
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
running = false;
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse->x = event.motion.x;
|
||||
mouse->y = event.motion.y;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (event.button.button == SDL_BUTTON_LEFT)
|
||||
mouse->btn1 = 1;
|
||||
if (event.button.button == SDL_BUTTON_RIGHT)
|
||||
mouse->btn2 = 1;
|
||||
if (event.button.button == SDL_BUTTON_MIDDLE)
|
||||
mouse->btn3 = 1;
|
||||
if (event.button.button == SDL_BUTTON_X1)
|
||||
mouse->btn4 = 1;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (event.button.button == SDL_BUTTON_LEFT)
|
||||
mouse->btn1 = 0;
|
||||
if (event.button.button == SDL_BUTTON_RIGHT)
|
||||
mouse->btn2 = 0;
|
||||
if (event.button.button == SDL_BUTTON_MIDDLE)
|
||||
mouse->btn3 = 0;
|
||||
if (event.button.button == SDL_BUTTON_X1)
|
||||
mouse->btn4 = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step_vm(&vm);
|
||||
#ifdef ASM_DEBUG
|
||||
printf("| %d %s %d\n", vm.code[vm.pc], opcode_to_string(vm.code[vm.pc]),
|
||||
vm.pc);
|
||||
#endif
|
||||
running = step_vm(&vm);
|
||||
}
|
||||
} else {
|
||||
while (running) {
|
||||
#ifdef ASM_DEBUG
|
||||
printf("| %d %s %d\n", vm.code[vm.pc], opcode_to_string(vm.code[vm.pc]),
|
||||
vm.pc);
|
||||
#endif
|
||||
running = step_vm(&vm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "assembler.h"
|
||||
|
||||
typedef enum { SYMBOL_CODE, SYMBOL_DATA, SYMBOL_PLEX } SymbolType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -86,14 +85,12 @@ int get_instruction_byte_size(ExprNode *node) {
|
|||
strcmp(opname, "real-to-string") == 0 ||
|
||||
strcmp(opname, "int-to-real") == 0 ||
|
||||
strcmp(opname, "nat-to-real") == 0 ||
|
||||
strcmp(opname, "real-to-int") == 0 ||
|
||||
strcmp(opname, "real-to-int") == 0 || strcmp(opname, "load-r") == 0 ||
|
||||
strcmp(opname, "real-to-nat") == 0 || strcmp(opname, "int-to-nat") == 0 ||
|
||||
strcmp(opname, "nat-to-int") == 0 ||
|
||||
strcmp(opname, "string-length") == 0 || strcmp(opname, "load") == 0 ||
|
||||
strcmp(opname, "store") == 0 || strcmp(opname, "load-u8") == 0 ||
|
||||
strcmp(opname, "load-i8") == 0 || strcmp(opname, "store-8") == 0 ||
|
||||
strcmp(opname, "load-u16") == 0 || strcmp(opname, "load-i16") == 0 ||
|
||||
strcmp(opname, "store-16") == 0 || strcmp(opname, "register-move") == 0) {
|
||||
strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "load-r8") == 0 ||
|
||||
strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 ||
|
||||
strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 ||
|
||||
strcmp(opname, "register-move") == 0 || strcmp(opname, "malloc") == 0) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -117,7 +114,9 @@ int get_instruction_byte_size(ExprNode *node) {
|
|||
}
|
||||
|
||||
// Load, Load-immediate (6 bytes: 1 + 1 + 4)
|
||||
if (strcmp(opname, "load-immediate") == 0) {
|
||||
if (strcmp(opname, "load") == 0 || strcmp(opname, "load-immediate") == 0 ||
|
||||
strcmp(opname, "load-u16") == 0 || strcmp(opname, "load-i16") == 0 ||
|
||||
strcmp(opname, "load-i8") == 0) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
@ -365,7 +364,6 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) {
|
|||
for (int i = 0; i < len; i++) {
|
||||
write_u8(vm, memory, addr + 4 + i, unwrapped[i]);
|
||||
}
|
||||
vm->mp += 4 + len;
|
||||
free(unwrapped);
|
||||
}
|
||||
// Case 2: Hexadecimal integer (0x...)
|
||||
|
@ -380,14 +378,12 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) {
|
|||
|
||||
u32 addr = allocate_data(vm, table, name, 4);
|
||||
write_u32(vm, memory, addr, value);
|
||||
vm->mp += 4;
|
||||
}
|
||||
// Case 3: Floating-point (has decimal point)
|
||||
else if (strchr(token, '.')) {
|
||||
float f = atof(token);
|
||||
u32 addr = allocate_data(vm, table, name, 4);
|
||||
write_u32(vm, memory, addr, TO_FIXED(f));
|
||||
vm->mp += 4;
|
||||
}
|
||||
// Case 4: Decimal integer
|
||||
else {
|
||||
|
@ -442,6 +438,24 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
|||
} else if (strcmp(opname, "load") == 0) {
|
||||
emit_opcode(vm, OP_LOAD);
|
||||
int dest = parse_register(node->children[0]->token);
|
||||
u32 addr = resolve_symbol(table, node->children[1]->token);
|
||||
emit_byte(vm, dest);
|
||||
emit_u32(vm, addr);
|
||||
} else if (strcmp(opname, "load-r") == 0) {
|
||||
emit_opcode(vm, OP_LOAD_REG);
|
||||
int dest = parse_register(node->children[0]->token);
|
||||
int src1 = parse_register(node->children[1]->token);
|
||||
emit_byte(vm, dest);
|
||||
emit_byte(vm, src1);
|
||||
} else if (strcmp(opname, "load-r8") == 0) {
|
||||
emit_opcode(vm, OP_LOAD_REG8);
|
||||
int dest = parse_register(node->children[0]->token);
|
||||
int src1 = parse_register(node->children[1]->token);
|
||||
emit_byte(vm, dest);
|
||||
emit_byte(vm, src1);
|
||||
} else if (strcmp(opname, "malloc") == 0) {
|
||||
emit_opcode(vm, OP_MALLOC);
|
||||
int dest = parse_register(node->children[0]->token);
|
||||
int src1 = parse_register(node->children[1]->token);
|
||||
emit_byte(vm, dest);
|
||||
emit_byte(vm, src1);
|
||||
|
@ -507,17 +521,17 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
|||
// Parse syscall ID
|
||||
u32 syscall_id = 0;
|
||||
const char *syscall_name = node->children[0]->token;
|
||||
if (strcmp(syscall_name, "DEVICE-EXIT") == 0)
|
||||
if (strcmp(syscall_name, "EXIT") == 0)
|
||||
syscall_id = SYSCALL_EXIT;
|
||||
else if (strcmp(syscall_name, "DEVICE-OPEN") == 0)
|
||||
else if (strcmp(syscall_name, "OPEN") == 0)
|
||||
syscall_id = SYSCALL_DEVICE_OPEN;
|
||||
else if (strcmp(syscall_name, "DEVICE-READ") == 0)
|
||||
else if (strcmp(syscall_name, "READ") == 0)
|
||||
syscall_id = SYSCALL_DEVICE_READ;
|
||||
else if (strcmp(syscall_name, "DEVICE-WRITE") == 0)
|
||||
else if (strcmp(syscall_name, "WRITE") == 0)
|
||||
syscall_id = SYSCALL_DEVICE_WRITE;
|
||||
else if (strcmp(syscall_name, "DEVICE-CLOSE") == 0)
|
||||
else if (strcmp(syscall_name, "CLOSE") == 0)
|
||||
syscall_id = SYSCALL_DEVICE_CLOSE;
|
||||
else if (strcmp(syscall_name, "DEVICE-IOCTL") == 0)
|
||||
else if (strcmp(syscall_name, "IOCTL") == 0)
|
||||
syscall_id = SYSCALL_DEVICE_IOCTL;
|
||||
|
||||
emit_u32(vm, syscall_id);
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
#include "parser.h"
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <uchar.h>
|
||||
|
||||
// Helper function to allocate memory and handle errors
|
||||
void *safe_malloc(size_t size) {
|
||||
void *ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
void *ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Helper function to create a new node
|
||||
static ExprNode *expr_node_create(const char *token, int line) {
|
||||
ExprNode *node = (ExprNode *)safe_malloc(sizeof(ExprNode));
|
||||
node->token = strdup(token ? token : "");
|
||||
node->children = NULL;
|
||||
node->child_count = 0;
|
||||
node->line = line;
|
||||
return node;
|
||||
ExprNode *node = (ExprNode *)safe_malloc(sizeof(ExprNode));
|
||||
node->token = strdup(token ? token : "");
|
||||
node->children = NULL;
|
||||
node->child_count = 0;
|
||||
node->line = line;
|
||||
return node;
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
|
@ -29,216 +31,224 @@ static ExprNode *parse_expression(const char **ptr, int line);
|
|||
|
||||
// Skip whitespace characters and comments
|
||||
static const char *skip_whitespace(const char *ptr) {
|
||||
while (*ptr) {
|
||||
// Skip regular whitespace
|
||||
if (isspace(*ptr)) {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for comment start
|
||||
if (*ptr == ';') {
|
||||
// Skip everything until end of line
|
||||
while (*ptr && *ptr != '\n') {
|
||||
ptr++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
while (*ptr) {
|
||||
// Skip regular whitespace
|
||||
if (isspace(*ptr)) {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
return ptr;
|
||||
|
||||
// Check for comment start
|
||||
if (*ptr == ';') {
|
||||
// Skip everything until end of line
|
||||
while (*ptr && *ptr != '\n') {
|
||||
ptr++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Parse a token (atom)
|
||||
static char *parse_token(const char **ptr, int line) {
|
||||
const char *start = *ptr;
|
||||
const char *start = *ptr;
|
||||
|
||||
// Skip leading whitespace and comments
|
||||
start = skip_whitespace(start);
|
||||
if (!*start) {
|
||||
printf("Error at line:%d\n", line);
|
||||
return NULL;
|
||||
}
|
||||
// Skip leading whitespace and comments
|
||||
start = skip_whitespace(start);
|
||||
if (!*start) {
|
||||
printf("Error at line:%d\n", line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *end = start;
|
||||
const char *end = start;
|
||||
|
||||
// Handle quoted strings
|
||||
if (*start == '"') {
|
||||
end++; // Skip opening quote
|
||||
// Read until closing quote or end of string
|
||||
while (*end && *end != '"') {
|
||||
if (*end == '\\' && *(end + 1)) {
|
||||
end += 2; // Skip escaped character
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
if (*end == '"') {
|
||||
end++; // Include closing quote
|
||||
}
|
||||
}
|
||||
// Handle parentheses as separate tokens
|
||||
else if (*end == '(' || *end == ')') {
|
||||
// Handle quoted strings
|
||||
if (*start == '"') {
|
||||
end++; // Skip opening quote
|
||||
// Read until closing quote or end of string
|
||||
while (*end && *end != '"') {
|
||||
if (*end == '\\' && *(end + 1)) {
|
||||
end += 2; // Skip escaped character
|
||||
} else {
|
||||
end++;
|
||||
} else {
|
||||
// Read until whitespace, parentheses, or comment
|
||||
while (*end && !isspace(*end) && *end != '(' && *end != ')' && *end != ';') {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (end == start) {
|
||||
printf("Error at line:%d\n", line);
|
||||
return NULL;
|
||||
if (*end == '"') {
|
||||
end++; // Include closing quote
|
||||
}
|
||||
}
|
||||
// Handle parentheses as separate tokens
|
||||
else if (*end == '(' || *end == ')') {
|
||||
end++;
|
||||
} else {
|
||||
// Read until whitespace, parentheses, or comment
|
||||
while (*end && !isspace(*end) && *end != '(' && *end != ')' &&
|
||||
*end != ';') {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = end - start;
|
||||
char *token = (char *)safe_malloc(len + 1);
|
||||
memcpy(token, start, len);
|
||||
token[len] = '\0';
|
||||
if (end == start) {
|
||||
printf("Error at line:%d\n", line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*ptr = end;
|
||||
return token;
|
||||
size_t len = end - start;
|
||||
char *token = (char *)safe_malloc(len + 1);
|
||||
memcpy(token, start, len);
|
||||
token[len] = '\0';
|
||||
|
||||
*ptr = end;
|
||||
return token;
|
||||
}
|
||||
|
||||
// Parse a list (expression starting with '(')
|
||||
static ExprNode *parse_list(const char **ptr, int line) {
|
||||
// Skip the opening parenthesis
|
||||
// Skip the opening parenthesis
|
||||
(*ptr)++;
|
||||
|
||||
*ptr = skip_whitespace(*ptr);
|
||||
if (**ptr == ')') {
|
||||
// Empty list
|
||||
(*ptr)++;
|
||||
return expr_node_create("nil", line);
|
||||
}
|
||||
|
||||
// Parse all children first
|
||||
ExprNode **temp_children = NULL;
|
||||
size_t temp_count = 0;
|
||||
|
||||
while (**ptr && **ptr != ')') {
|
||||
ExprNode *child = parse_expression(ptr, line);
|
||||
if (child) {
|
||||
// Resize temp children array
|
||||
ExprNode **new_temp =
|
||||
(ExprNode **)safe_malloc(sizeof(ExprNode *) * (temp_count + 1));
|
||||
|
||||
// Copy existing children
|
||||
for (size_t i = 0; i < temp_count; i++) {
|
||||
new_temp[i] = temp_children[i];
|
||||
}
|
||||
|
||||
// Add new child
|
||||
new_temp[temp_count] = child;
|
||||
temp_count++;
|
||||
|
||||
// Free old array and update
|
||||
free(temp_children);
|
||||
temp_children = new_temp;
|
||||
}
|
||||
|
||||
*ptr = skip_whitespace(*ptr);
|
||||
if (**ptr == ')') {
|
||||
// Empty list
|
||||
(*ptr)++;
|
||||
return expr_node_create("nil", line);
|
||||
}
|
||||
|
||||
if (**ptr == ')') {
|
||||
(*ptr)++; // Skip closing parenthesis
|
||||
} else {
|
||||
fprintf(stderr, "Error: Missing closing parenthesis at line %d\n", line);
|
||||
}
|
||||
|
||||
// Create the actual node
|
||||
ExprNode *node;
|
||||
if (temp_count > 0 && temp_children[0]->child_count == 0) {
|
||||
// First child is an atom, use it as the operator
|
||||
node = expr_node_create(temp_children[0]->token, line);
|
||||
// Move remaining children
|
||||
node->child_count = temp_count - 1;
|
||||
if (node->child_count > 0) {
|
||||
node->children =
|
||||
(ExprNode **)safe_malloc(sizeof(ExprNode *) * node->child_count);
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
node->children[i] = temp_children[i + 1];
|
||||
}
|
||||
}
|
||||
// Free the first child since we used its token
|
||||
expr_free(temp_children[0]);
|
||||
} else {
|
||||
// No operator or first child is a list
|
||||
node = expr_node_create("list", line);
|
||||
node->children = temp_children;
|
||||
node->child_count = temp_count;
|
||||
}
|
||||
|
||||
// Parse all children first
|
||||
ExprNode **temp_children = NULL;
|
||||
size_t temp_count = 0;
|
||||
if (temp_count == 0) {
|
||||
free(temp_children);
|
||||
}
|
||||
|
||||
while (**ptr && **ptr != ')') {
|
||||
ExprNode *child = parse_expression(ptr, line);
|
||||
if (child) {
|
||||
// Resize temp children array
|
||||
ExprNode **new_temp = (ExprNode **)safe_malloc(sizeof(ExprNode *) * (temp_count + 1));
|
||||
|
||||
// Copy existing children
|
||||
for (size_t i = 0; i < temp_count; i++) {
|
||||
new_temp[i] = temp_children[i];
|
||||
}
|
||||
|
||||
// Add new child
|
||||
new_temp[temp_count] = child;
|
||||
temp_count++;
|
||||
|
||||
// Free old array and update
|
||||
free(temp_children);
|
||||
temp_children = new_temp;
|
||||
}
|
||||
|
||||
*ptr = skip_whitespace(*ptr);
|
||||
}
|
||||
|
||||
if (**ptr == ')') {
|
||||
(*ptr)++; // Skip closing parenthesis
|
||||
} else {
|
||||
fprintf(stderr, "Error: Missing closing parenthesis at line %d\n", line);
|
||||
}
|
||||
|
||||
// Create the actual node
|
||||
ExprNode *node;
|
||||
if (temp_count > 0 && temp_children[0]->child_count == 0) {
|
||||
// First child is an atom, use it as the operator
|
||||
node = expr_node_create(temp_children[0]->token, line);
|
||||
// Move remaining children
|
||||
node->child_count = temp_count - 1;
|
||||
if (node->child_count > 0) {
|
||||
node->children = (ExprNode **)safe_malloc(sizeof(ExprNode *) * node->child_count);
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
node->children[i] = temp_children[i + 1];
|
||||
}
|
||||
}
|
||||
// Free the first child since we used its token
|
||||
expr_free(temp_children[0]);
|
||||
} else {
|
||||
// No operator or first child is a list
|
||||
node = expr_node_create("list", line);
|
||||
node->children = temp_children;
|
||||
node->child_count = temp_count;
|
||||
}
|
||||
|
||||
if (temp_count == 0) {
|
||||
free(temp_children);
|
||||
}
|
||||
|
||||
return node;
|
||||
return node;
|
||||
}
|
||||
|
||||
// Parse an expression (either atom or list)
|
||||
static ExprNode *parse_expression(const char **ptr, int line) {
|
||||
*ptr = skip_whitespace(*ptr);
|
||||
*ptr = skip_whitespace(*ptr);
|
||||
|
||||
if (!**ptr) return NULL;
|
||||
if (!**ptr)
|
||||
return NULL;
|
||||
|
||||
if (**ptr == '(') {
|
||||
return parse_list(ptr, line);
|
||||
} else {
|
||||
// Parse atom
|
||||
char *token = parse_token(ptr, line);
|
||||
if (token) {
|
||||
ExprNode *node = expr_node_create(token, line);
|
||||
free(token);
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
if (**ptr == '(') {
|
||||
return parse_list(ptr, line);
|
||||
} else {
|
||||
// Parse atom
|
||||
char *token = parse_token(ptr, line);
|
||||
if (token) {
|
||||
ExprNode *node = expr_node_create(token, line);
|
||||
free(token);
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Main parsing function
|
||||
ExprNode *expr_parse(const char *source, size_t source_len) {
|
||||
if (!source || source_len == 0) return NULL;
|
||||
if (!source || source_len == 0)
|
||||
return NULL;
|
||||
|
||||
const char *ptr = source;
|
||||
int line = 1;
|
||||
const char *ptr = source;
|
||||
int line = 1;
|
||||
|
||||
ptr = skip_whitespace(ptr);
|
||||
if (!*ptr) return NULL;
|
||||
ptr = skip_whitespace(ptr);
|
||||
if (!*ptr)
|
||||
return NULL;
|
||||
|
||||
return parse_expression(&ptr, line);
|
||||
return parse_expression(&ptr, line);
|
||||
}
|
||||
|
||||
// Free an Expr AST (and all children)
|
||||
void expr_free(ExprNode *node) {
|
||||
if (!node) return;
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
free(node->token);
|
||||
free(node->token);
|
||||
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
expr_free(node->children[i]);
|
||||
}
|
||||
free(node->children);
|
||||
free(node);
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
expr_free(node->children[i]);
|
||||
}
|
||||
free(node->children);
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Debug: print AST (for dev)
|
||||
void expr_print(ExprNode *node, int indent) {
|
||||
if (!node) return;
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
if (node->child_count == 0) {
|
||||
// Atom
|
||||
printf("Atom: '%s' (line %d)\n", node->token, node->line);
|
||||
} else {
|
||||
// List
|
||||
printf("List: '%s' (line %d) [%zu children]\n",
|
||||
node->token, node->line, node->child_count);
|
||||
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
expr_print(node->children[i], indent + 1);
|
||||
}
|
||||
for (int i = 0; i < indent; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
if (node->child_count == 0) {
|
||||
// Atom
|
||||
printf("Atom: '%s' (line %d)\n", node->token, node->line);
|
||||
} else {
|
||||
// List
|
||||
printf("List: '%s' (line %d) [%zu children]\n", node->token, node->line,
|
||||
node->child_count);
|
||||
|
||||
for (size_t i = 0; i < node->child_count; i++) {
|
||||
expr_print(node->children[i], indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,15 +15,11 @@ struct ExprNode {
|
|||
int line; // Source line number (for errors)
|
||||
};
|
||||
|
||||
// Parse a string into an Expr AST
|
||||
ExprNode *expr_parse(const char *source, size_t source_len);
|
||||
|
||||
// Free an Expr AST (and all children)
|
||||
ExprNode* expand_macros(ExprNode* node);
|
||||
ExprNode* expand_lambda(ExprNode* lambda_node);
|
||||
void expr_free(ExprNode *node);
|
||||
|
||||
// Debug: print AST (for dev)
|
||||
void expr_print(ExprNode *node, int indent);
|
||||
|
||||
void *safe_malloc(size_t size);
|
||||
|
||||
#endif
|
|
@ -9,12 +9,15 @@ typedef enum {
|
|||
OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */
|
||||
OP_CALL, /* call : creates a new frame */
|
||||
OP_RETURN, /* return : returns from a frame to the parent frame */
|
||||
OP_LOAD, /* load : dest = memory[src1] */
|
||||
OP_LOADI8, /* load-i8 : dest = memory[src1] */
|
||||
OP_LOADU8, /* load-u8 : dest = memory[src1] */
|
||||
OP_LOADI16, /* load-i16 : dest = memory[src1] */
|
||||
OP_LOADU16, /* load-u16 : dest = memory[src1] */
|
||||
OP_LOAD, /* load : dest = memory[src1 as u32] */
|
||||
OP_LOAD_REG, /* load-r : dest = memory[registers[src1]] as u32 */
|
||||
OP_LOAD_REG8, /* load-r8 : dest = memory[registers[src1]] as u8 */
|
||||
OP_LOADI8, /* load-i8 : dest = memory[src1 as u32] */
|
||||
OP_LOADU8, /* load-u8 : dest = memory[src1 as u32] */
|
||||
OP_LOADI16, /* load-i16 : dest = memory[src1 as u32] */
|
||||
OP_LOADU16, /* load-u16 : dest = memory[src1 as u32] */
|
||||
OP_LOAD_IMM, /* load-immediate : dest = constant */
|
||||
OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */
|
||||
OP_STORE, /* store : memory[dest] = src1 */
|
||||
OP_STORE8, /* store-8 : memory[dest] = src1 << 8 */
|
||||
OP_STORE16, /* store-16 : memory[dest] = src1 << 16 */
|
||||
|
@ -95,7 +98,7 @@ typedef struct device_ops_s {
|
|||
i32 (*read)(void *device_data, u8 *buffer, u32 size);
|
||||
i32 (*write)(void *device_data, const u8 *buffer, u32 size);
|
||||
i32 (*close)(void *device_data);
|
||||
i32 (*ioctl)(void *device_data, u32 cmd, void *args); /* optional control */
|
||||
i32 (*ioctl)(void *device_data, u32 cmd, const u8 *buffer); /* optional control */
|
||||
} DeviceOps;
|
||||
|
||||
#define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */
|
||||
|
@ -133,12 +136,14 @@ typedef struct vm_s {
|
|||
} VM;
|
||||
|
||||
#define read_u8(vm, location, addr) ((vm)->location[addr])
|
||||
|
||||
#define read_u16(vm, location, addr) \
|
||||
(((u16)(vm)->location[(addr)] << 8) | ((u16)(vm)->location[(addr) + 1]))
|
||||
(((u16)(vm)->location[(addr) + 1] << 8) | ((u16)(vm)->location[(addr)]))
|
||||
|
||||
#define read_u32(vm, location, addr) \
|
||||
(((u32)(vm)->location[(addr)] << 24) | \
|
||||
((u32)(vm)->location[(addr) + 1] << 16) | \
|
||||
((u32)(vm)->location[(addr) + 2] << 8) | ((u32)(vm)->location[(addr) + 3]))
|
||||
(((u32)(vm)->location[(addr) + 3] << 24) | \
|
||||
((u32)(vm)->location[(addr) + 2] << 16) | \
|
||||
((u32)(vm)->location[(addr) + 1] << 8) | ((u32)(vm)->location[(addr)]))
|
||||
|
||||
#define write_u8(vm, location, addr, value) \
|
||||
do { \
|
||||
|
@ -150,18 +155,18 @@ typedef struct vm_s {
|
|||
#define write_u16(vm, location, addr, value) \
|
||||
do { \
|
||||
if ((addr) + 1 < sizeof((vm)->location)) { \
|
||||
(vm)->location[(addr)] = ((value) >> 8) & 0xFF; \
|
||||
(vm)->location[(addr) + 1] = (value) & 0xFF; \
|
||||
(vm)->location[(addr)] = (value) & 0xFF; \
|
||||
(vm)->location[(addr) + 1] = ((value) >> 8) & 0xFF; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define write_u32(vm, location, addr, value) \
|
||||
do { \
|
||||
if ((addr) + 3 < sizeof((vm)->location)) { \
|
||||
(vm)->location[(addr)] = ((value) >> 24) & 0xFF; \
|
||||
(vm)->location[(addr) + 1] = ((value) >> 16) & 0xFF; \
|
||||
(vm)->location[(addr) + 2] = ((value) >> 8) & 0xFF; \
|
||||
(vm)->location[(addr) + 3] = (value) & 0xFF; \
|
||||
(vm)->location[(addr)] = (value) & 0xFF; \
|
||||
(vm)->location[(addr) + 1] = ((value) >> 8) & 0xFF; \
|
||||
(vm)->location[(addr) + 2] = ((value) >> 16) & 0xFF; \
|
||||
(vm)->location[(addr) + 3] = ((value) >> 24) & 0xFF; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -124,11 +124,6 @@ void fixed_to_string(i32 value, char *buffer) {
|
|||
/* Convert fractional part to 5 decimal digits */
|
||||
frac_digits = (frac_part * 100000U) / 65536U;
|
||||
|
||||
/* Trim trailing zeros */
|
||||
while (frac_digits > 0 && frac_digits % 10 == 0) {
|
||||
frac_digits /= 10;
|
||||
}
|
||||
|
||||
if (frac_digits > 0) {
|
||||
end = write_digits_backwards(frac_digits, end, temp);
|
||||
*--end = '.';
|
||||
|
|
73
src/vm/vm.c
73
src/vm/vm.c
|
@ -97,6 +97,18 @@ bool step_vm(VM *vm) {
|
|||
of old slice, pop the frame */
|
||||
return true;
|
||||
}
|
||||
case OP_MALLOC: {
|
||||
u32 size;
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
frame->registers[dest] = vm->mp;
|
||||
size = frame->registers[src1];
|
||||
write_u32(vm, memory, vm->mp, size);
|
||||
vm->mp += (size + 4);
|
||||
return true;
|
||||
}
|
||||
case OP_LOAD_IMM: {
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
|
@ -106,24 +118,41 @@ bool step_vm(VM *vm) {
|
|||
return true;
|
||||
}
|
||||
case OP_LOAD: {
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
ptr = read_u32(vm, code, vm->pc);
|
||||
vm->pc += 4;
|
||||
v = read_u32(vm, memory, ptr);
|
||||
frame->registers[dest] = v;
|
||||
return true;
|
||||
}
|
||||
case OP_LOAD_REG: {
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
v = frame->registers[src1];
|
||||
ptr = frame->registers[dest];
|
||||
v = read_u32(vm, memory, ptr);
|
||||
frame->registers[dest] = v;
|
||||
ptr = read_u32(vm, memory, v);
|
||||
frame->registers[dest] = ptr;
|
||||
return true;
|
||||
}
|
||||
case OP_LOAD_REG8: {
|
||||
u8 v8;
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
v = frame->registers[src1];
|
||||
v8 = read_u8(vm, memory, v);
|
||||
frame->registers[dest] = v8;
|
||||
return true;
|
||||
}
|
||||
case OP_LOADI8: {
|
||||
i8 v8;
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
v = frame->registers[src1];
|
||||
ptr = frame->registers[dest];
|
||||
ptr = read_u32(vm, code, vm->pc);
|
||||
vm->pc += 4;
|
||||
v8 = (i8)read_u8(vm, memory, ptr);
|
||||
frame->registers[ptr] = v8;
|
||||
return true;
|
||||
|
@ -132,9 +161,8 @@ bool step_vm(VM *vm) {
|
|||
u8 v8;
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
ptr = frame->registers[src1];
|
||||
ptr = read_u32(vm, code, vm->pc);
|
||||
vm->pc += 4;
|
||||
v8 = read_u8(vm, memory, ptr);
|
||||
frame->registers[ptr] = v8;
|
||||
return true;
|
||||
|
@ -143,10 +171,8 @@ bool step_vm(VM *vm) {
|
|||
i16 v16;
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
v = frame->registers[src1];
|
||||
ptr = frame->registers[dest];
|
||||
ptr = read_u32(vm, code, vm->pc);
|
||||
vm->pc += 4;
|
||||
v16 = (i16)read_u16(vm, memory, ptr);
|
||||
frame->registers[dest] = v16;
|
||||
return true;
|
||||
|
@ -155,10 +181,8 @@ bool step_vm(VM *vm) {
|
|||
u16 v16;
|
||||
dest = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
src1 = read_u8(vm, code, vm->pc);
|
||||
vm->pc++;
|
||||
v = frame->registers[src1];
|
||||
ptr = frame->registers[dest];
|
||||
ptr = read_u32(vm, code, vm->pc);
|
||||
vm->pc += 4;
|
||||
v16 = read_u16(vm, memory, ptr);
|
||||
frame->registers[ptr] = v16;
|
||||
return true;
|
||||
|
@ -274,21 +298,12 @@ bool step_vm(VM *vm) {
|
|||
|
||||
path_ptr = frame->registers[path_reg]; /* path pointer */
|
||||
size = frame->registers[size_reg]; /* size */
|
||||
buffer_ptr = (dest > 32)
|
||||
? vm->mp
|
||||
: dest; /* dest ptr, if > 32 then use memory pointer*/
|
||||
buffer_ptr = frame->registers[dest];
|
||||
|
||||
dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]);
|
||||
if (dev && dev->ops->read) {
|
||||
vm->flag =
|
||||
dev->ops->read(dev->data, (u8 *)&vm->memory[buffer_ptr + 4], size);
|
||||
if (dest > 32) {
|
||||
vm->mp += size + 4;
|
||||
}
|
||||
write_u32(vm, memory, buffer_ptr, size);
|
||||
if (dest > 32) {
|
||||
frame->end = vm->mp;
|
||||
}
|
||||
dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size);
|
||||
frame->registers[buffer_reg] = buffer_ptr;
|
||||
} else {
|
||||
vm->flag = 0;
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
(load-immediate $3 &new-line)
|
||||
(pop $1)
|
||||
(string-length $2 $1)
|
||||
(syscall DEVICE-WRITE $0 $1 $2)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(string-length $4 $3)
|
||||
(syscall DEVICE-WRITE $0 $3 $4)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return)))
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
|
|
BIN
test/add.rom
BIN
test/add.rom
Binary file not shown.
|
@ -1,51 +1,159 @@
|
|||
((code
|
||||
(label main
|
||||
; Open screen
|
||||
; use load immediate because it is a pointer to a string, not a value
|
||||
(load-immediate $0 &screen-namespace)
|
||||
(load-immediate $1 0)
|
||||
(syscall DEVICE-OPEN $0 $1)
|
||||
(syscall OPEN $0 $1)
|
||||
; draw to the device because otherwise the screen wont open
|
||||
(syscall WRITE $0 $0 $0)
|
||||
|
||||
; Draw red box at (10, 20)
|
||||
(load-immediate $1 0xE0) ; color
|
||||
; first row
|
||||
(load $1 &BLACK)
|
||||
(push $1)
|
||||
(load-immediate $1 10) ; x
|
||||
(load-immediate $1 1)
|
||||
(push $1)
|
||||
(load-immediate $1 20) ; y
|
||||
(load-immediate $1 1)
|
||||
(push $1)
|
||||
(call &draw-box)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
; Draw green box at (10, 40)
|
||||
(load-immediate $1 0x1C) ; RGB332 green (00011100)
|
||||
(load $1 &WHITE)
|
||||
(push $1)
|
||||
(load-immediate $1 21)
|
||||
(push $1)
|
||||
(load-immediate $1 1)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
; row 2
|
||||
(load $1 &CHARCOAL)
|
||||
(push $1)
|
||||
(load-immediate $1 30)
|
||||
(push $1)
|
||||
(load-immediate $1 40)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
(load $1 &DARK-GRAY)
|
||||
(push $1)
|
||||
(load-immediate $1 10)
|
||||
(push $1)
|
||||
(load-immediate $1 40)
|
||||
(push $1)
|
||||
(call &draw-box)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
; row 3
|
||||
(load $1 &RED)
|
||||
(push $1)
|
||||
(load-immediate $1 30)
|
||||
(push $1)
|
||||
(load-immediate $1 60)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
(load $1 &ORANGE)
|
||||
(push $1)
|
||||
(load-immediate $1 10)
|
||||
(push $1)
|
||||
(load-immediate $1 60)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
; row 3
|
||||
(load $1 &YELLOW)
|
||||
(push $1)
|
||||
(load-immediate $1 30)
|
||||
(push $1)
|
||||
(load-immediate $1 80)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
(load $1 &GREEN)
|
||||
(push $1)
|
||||
(load-immediate $1 10)
|
||||
(push $1)
|
||||
(load-immediate $1 80)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
; row 4
|
||||
(load $1 &BLUE)
|
||||
(push $1)
|
||||
(load-immediate $1 30)
|
||||
(push $1)
|
||||
(load-immediate $1 100)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
(load $1 &PURPLE)
|
||||
(push $1)
|
||||
(load-immediate $1 10)
|
||||
(push $1)
|
||||
(load-immediate $1 100)
|
||||
(push $1)
|
||||
(call &draw-outlined-swatch)
|
||||
|
||||
; Flush and halt
|
||||
(syscall DEVICE-WRITE $0 $0 $0)
|
||||
(syscall WRITE $0 $0 $0)
|
||||
(halt))
|
||||
|
||||
(label draw-outlined-swatch
|
||||
(pop $3) ; y
|
||||
(pop $2) ; x
|
||||
(pop $1) ; color
|
||||
|
||||
; Constants
|
||||
(load $4 &GRAY)
|
||||
(load-immediate $5 20) ; outline size
|
||||
(load-immediate $6 17) ; fill size
|
||||
(load-immediate $7 2) ; offset
|
||||
|
||||
(push $4) ; color (gray)
|
||||
(push $2) ; x
|
||||
(push $3) ; y
|
||||
(push $5) ; width (20)
|
||||
(push $5) ; height (20)
|
||||
(call &draw-box)
|
||||
|
||||
(add-int $8 $2 $7) ; x + 2
|
||||
(add-int $9 $3 $7) ; y + 2
|
||||
|
||||
(push $1) ; color (original)
|
||||
(push $8) ; x + 2
|
||||
(push $9) ; y + 2
|
||||
(push $6) ; width (17)
|
||||
(push $6) ; height (17)
|
||||
(call &draw-box)
|
||||
|
||||
(return))
|
||||
|
||||
; draw-box(color, x, y)
|
||||
; Pops: y, x, color
|
||||
(label draw-box
|
||||
; Pop arguments (reverse order)
|
||||
(pop $14) ; height
|
||||
(pop $12) ; width
|
||||
(pop $13) ; y_start
|
||||
(pop $11) ; x_start
|
||||
(pop $3) ; color
|
||||
|
||||
;; get the screen width dynamically from the device
|
||||
(load-immediate $0 &screen-namespace)
|
||||
(load-immediate $16 1) ; device info call
|
||||
(load-immediate $17 16) ; sizeof screen device info
|
||||
(malloc $18 $17)
|
||||
(syscall IOCTL $0 $16 $18)
|
||||
(load-immediate $1 12) ; offset for width
|
||||
(add-nat $19 $18 $1)
|
||||
(load-r $2 $19) ; load width
|
||||
|
||||
; Constants
|
||||
(load-immediate $1 1) ; increment
|
||||
(load-immediate $2 640) ; row stride
|
||||
(load-immediate $10 36) ; framebuffer base
|
||||
(load-immediate $12 20) ; width
|
||||
(load-immediate $14 20) ; height
|
||||
|
||||
; Compute start address: base + y*640 + x
|
||||
(mul-int $15 $13 $2) ; $15 = y * 640
|
||||
(add-int $15 $15 $11) ; $15 += x
|
||||
(add-int $4 $10 $15) ; $4 = base + offset
|
||||
(register-move $4 $15)
|
||||
|
||||
; Outer loop: height times
|
||||
(register-move $5 $14) ; $5 = row counter
|
||||
|
@ -64,4 +172,37 @@
|
|||
(jump-gt-int &draw-box-outer $5 0))
|
||||
(return)))
|
||||
(data
|
||||
(label screen-namespace "/dev/screen/0")))
|
||||
(label screen-namespace "/dev/screen/0")
|
||||
(label mouse-namespace "/dev/mouse/0")
|
||||
(label BLACK 0)
|
||||
(label WHITE 255)
|
||||
(label CHARCOAL 36)
|
||||
(label DARK-GRAY 73)
|
||||
(label GRAY 146)
|
||||
(label LIGHT-GRAY 182)
|
||||
(label DARK-RED 128)
|
||||
(label RED 224)
|
||||
(label DARK-YELLOW 144)
|
||||
(label YELLOW 252)
|
||||
(label DARK-TEAL 9)
|
||||
(label TEAL 18)
|
||||
(label DARK-GREEN 12)
|
||||
(label GREEN 16)
|
||||
(label LIME 28)
|
||||
(label LIGHT-CYAN 159)
|
||||
(label NAVY 2)
|
||||
(label BLUE 3)
|
||||
(label DEEP-SKY-BLUE 10)
|
||||
(label LIGHT-BLUE 19)
|
||||
(label PURPLE 131)
|
||||
(label LIGHT-PURPLE 147)
|
||||
(label DARK-MAGENTA 130)
|
||||
(label MAGENTA 227)
|
||||
(label PLUM 129)
|
||||
(label PINK 226)
|
||||
(label SADDLE-BROWN 72)
|
||||
(label PERU 141)
|
||||
(label SIENNA 136)
|
||||
(label ORANGE 241)
|
||||
(label DARK-ORANGE 208)
|
||||
(label GOLD 244)))
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
(load-immediate $3 &new-line)
|
||||
(pop $1)
|
||||
(string-length $2 $1)
|
||||
(syscall DEVICE-WRITE $0 $1 $2)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(string-length $4 $3)
|
||||
(syscall DEVICE-WRITE $0 $3 $4)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return)))
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
|
|
BIN
test/fib.rom
BIN
test/fib.rom
Binary file not shown.
|
@ -3,7 +3,7 @@
|
|||
(load-immediate $0 &terminal-namespace) ; load terminal namespace
|
||||
(load-immediate $1 &hello-str) ; load hello string ptr
|
||||
(string-length $2 $1) ; get length to write to stdout
|
||||
(syscall DEVICE-WRITE $0 $1 $2) ; do the write syscall
|
||||
(syscall WRITE $0 $1 $2) ; do the write syscall
|
||||
(halt))) ; done
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
|
|
BIN
test/hello.rom
BIN
test/hello.rom
Binary file not shown.
|
@ -13,13 +13,11 @@
|
|||
(real-to-nat $1 $0)
|
||||
(load-immediate $7 &help)
|
||||
(string-length $8 $7)
|
||||
(syscall DEVICE-WRITE $10 $7 $8)
|
||||
(syscall WRITE $10 $7 $8)
|
||||
(load-immediate $8 32)
|
||||
(load-immediate $9 255)
|
||||
; note 255 is not a real register
|
||||
; it just means "append to end of memory"
|
||||
; technically any register > 32 will work
|
||||
(syscall DEVICE-READ $10 $2 $8 $255)
|
||||
|
||||
(malloc $11 $8)
|
||||
(syscall READ $10 $2 $8 $11)
|
||||
(push $2)
|
||||
(call &println)
|
||||
(nat-to-string $4 $1)
|
||||
|
@ -34,9 +32,9 @@
|
|||
(load-immediate $3 &new-line)
|
||||
(pop $1)
|
||||
(string-length $2 $1)
|
||||
(syscall DEVICE-WRITE $0 $1 $2)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(string-length $4 $3)
|
||||
(syscall DEVICE-WRITE $0 $3 $4)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return)))
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
|
|
BIN
test/loop.rom
BIN
test/loop.rom
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
((code
|
||||
(label main
|
||||
(load-immediate $0 &terminal-namespace) ; get terminal device
|
||||
(load-immediate $1 &help) ; print help message
|
||||
(push $1)
|
||||
(call &println)
|
||||
(load-immediate $1 32) ; read in a string of max 32 char length
|
||||
(malloc $2 $1) ; allocate memory for the string
|
||||
(syscall READ $0 $3 $1 $2) ; read the string
|
||||
(push $3)
|
||||
(call &println) ; print the string
|
||||
(halt))
|
||||
(label println
|
||||
(load-immediate $0 &terminal-namespace)
|
||||
(load-immediate $3 &new-line)
|
||||
(pop $1)
|
||||
(string-length $2 $1)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(string-length $4 $3)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return)))
|
||||
(data
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
(label help "Enter a string: ")
|
||||
(label new-line "\n")))
|
|
@ -12,9 +12,9 @@
|
|||
(load-immediate $3 &new-line)
|
||||
(pop $1)
|
||||
(string-length $2 $1)
|
||||
(syscall DEVICE-WRITE $0 $1 $2)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(string-length $4 $3)
|
||||
(syscall DEVICE-WRITE $0 $3 $4)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return)))
|
||||
(data (label terminal-namespace "/dev/term/0")
|
||||
(label new-line "\n")
|
||||
|
|
BIN
test/simple.rom
BIN
test/simple.rom
Binary file not shown.
|
@ -1,14 +1,83 @@
|
|||
((code
|
||||
(label main
|
||||
(load-immediate $0 &screen-namespace)
|
||||
(load-immediate $1 0)
|
||||
(syscall DEVICE-OPEN $0 $2)
|
||||
(load-immediate $11 0)
|
||||
(syscall OPEN $0 $11)
|
||||
(syscall WRITE $0 $0 $0)
|
||||
|
||||
(load-immediate $3 0x55)
|
||||
(load-immediate $4 36)
|
||||
(store-8 $4 $3)
|
||||
(syscall DEVICE-WRITE $0 $0 $0)
|
||||
(load-immediate $16 1) ; device info call
|
||||
(load-immediate $17 16) ; sizeof screen device info
|
||||
(malloc $18 $17)
|
||||
(syscall IOCTL $0 $16 $18)
|
||||
(load-immediate $1 12) ; offset for width
|
||||
(add-nat $19 $18 $1)
|
||||
(load-r $20 $19) ; load width
|
||||
|
||||
(halt)))
|
||||
(load-immediate $16 &mouse-namespace)
|
||||
(load-immediate $3 12) ; malloc sizeof mouse data
|
||||
(malloc $4 $3)
|
||||
|
||||
(label draw-loop
|
||||
; load mouse click data
|
||||
(syscall READ $16 $2 $3 $4)
|
||||
(load-immediate $5 4) ; offset for x
|
||||
(add-nat $6 $5 $2)
|
||||
(load-r $7 $6) ; load x
|
||||
(load-immediate $5 8) ; offset for y
|
||||
(add-nat $6 $5 $2)
|
||||
(load-r $8 $6) ; load y
|
||||
(load-immediate $5 12) ; offset for btn1
|
||||
(add-nat $6 $5 $2)
|
||||
(load-r8 $9 $6) ; load btn1 pressed
|
||||
(load-immediate $5 13) ; offset for btn2
|
||||
(add-nat $6 $5 $2)
|
||||
(load-r8 $10 $6) ; load btn2 pressed
|
||||
(load-r $12 $5) ; load x
|
||||
|
||||
(jump-eq-nat &draw-loop $9 $11)
|
||||
|
||||
;;(nat-to-string $1 $7)
|
||||
;;(push $1)
|
||||
;;(call &println)
|
||||
;;
|
||||
;;(nat-to-string $1 $8)
|
||||
;;(push $1)
|
||||
;;(call &println)
|
||||
;;
|
||||
;;(nat-to-string $1 $9)
|
||||
;;(push $1)
|
||||
;;(call &println)
|
||||
;;
|
||||
;;(nat-to-string $1 $10)
|
||||
;;(push $1)
|
||||
;;(call &println)
|
||||
;;
|
||||
;;(nat-to-string $1 $12)
|
||||
;;(push $1)
|
||||
;;(call &println)
|
||||
|
||||
; Compute start address: y*width + x
|
||||
(mul-nat $15 $8 $20) ; $15 = y * width
|
||||
(add-nat $15 $15 $7) ; $15 += x
|
||||
|
||||
(load $3 &WHITE) ; color
|
||||
(store-8 $15 $3) ; draw color at screen [x,y]
|
||||
(syscall WRITE $0 $0 $0) ; redraw
|
||||
|
||||
(jump-eq-nat &draw-loop $10 $11))
|
||||
(halt))
|
||||
(label println
|
||||
(load-immediate $0 &terminal-namespace)
|
||||
(load-immediate $3 &new-line)
|
||||
(pop $1)
|
||||
(string-length $2 $1)
|
||||
(syscall WRITE $0 $1 $2)
|
||||
(string-length $4 $3)
|
||||
(syscall WRITE $0 $3 $4)
|
||||
(return)))
|
||||
(data
|
||||
(label screen-namespace "/dev/screen/0")))
|
||||
(label screen-namespace "/dev/screen/0")
|
||||
(label mouse-namespace "/dev/mouse/0")
|
||||
(label terminal-namespace "/dev/term/0")
|
||||
(label new-line "\n")
|
||||
(label WHITE 255)))
|
||||
|
|
Loading…
Reference in New Issue