Add malloc, load-r, load-r8. fix endianess, refactor devices, init box, init window drawing

This commit is contained in:
zongor 2025-10-04 17:24:24 -07:00
parent d6893b85a8
commit 77033e121b
24 changed files with 783 additions and 379 deletions

View File

@ -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")

46
docs/draw.ul Normal file
View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -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 = '.';

View File

@ -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;

View File

@ -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")

Binary file not shown.

View File

@ -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)))

View File

@ -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")

Binary file not shown.

View File

@ -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")

Binary file not shown.

View File

@ -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")

Binary file not shown.

25
test/malloc.asm.lisp Normal file
View File

@ -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")))

View File

@ -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")

Binary file not shown.

View File

@ -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)))