Code cleanup

This commit is contained in:
zongor 2025-12-08 21:42:59 -08:00
parent edb10db545
commit 80d9c67b9e
9 changed files with 321 additions and 545 deletions

View File

@ -66,7 +66,6 @@ void mainloop() {
mouse_data.btn4 = 0;
break;
// Touch events (map to mouse_data as left-click equivalent)
case SDL_FINGERMOTION:
case SDL_FINGERDOWN:
case SDL_FINGERUP: {
@ -77,8 +76,6 @@ void mainloop() {
mouse_data.x = (int)x;
mouse_data.y = (int)y;
// Only treat the first finger as mouse input (ignore multi-touch beyond 1
// finger)
if (event.tfinger.fingerId == 0) {
if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) {
mouse_data.btn1 = 1;
@ -91,9 +88,8 @@ void mainloop() {
}
}
// Run VM for a fixed number of cycles or a time slice
int cycles_this_frame = 0;
int max_cycles_per_frame = 2000; // Adjust this value
int max_cycles_per_frame = 2000;
while (cycles_this_frame < max_cycles_per_frame) {
if (!step_vm(&vm)) {
emscripten_cancel_main_loop();
@ -102,13 +98,12 @@ void mainloop() {
cycles_this_frame++;
}
// Render only if the screen buffer was updated AND at a reasonable rate
if (screen_data.update) {
if (screen_data.renderer && screen_data.texture) {
SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, NULL);
SDL_RenderPresent(screen_data.renderer);
}
screen_data.update = false; // Reset flag after rendering
screen_data.update = false;
}
}
@ -119,7 +114,6 @@ bool loadVM(const char *filename, VM *vm) {
return false;
}
// Read VM state
if (fread(&vm->pc, sizeof(u32), 1, file) != 1 ||
fread(&vm->cp, sizeof(u32), 1, file) != 1 ||
fread(&vm->fp, sizeof(u32), 1, file) != 1 ||
@ -132,14 +126,12 @@ bool loadVM(const char *filename, VM *vm) {
return false;
}
// Read code section
if (fread(vm->code, 1, vm->cp, file) != vm->cp) {
printf("Failed to read code section\n");
fclose(file);
return false;
}
// Read memory section
if (fread(vm->memory, 1, vm->mp, file) != vm->mp) {
printf("Failed to read memory section\n");
fclose(file);
@ -187,7 +179,6 @@ int main(int argc, char **argv) {
vm_register_device(&vm, "/dev/term/0", "terminal", &console_data,
&console_device_ops, 4);
// Set up main loop
emscripten_set_main_loop(mainloop, 0, 1);
return 0;
}

View File

@ -11,127 +11,127 @@
#include <stdlib.h>
#include <string.h>
/* FIXME: technically this is not allowed in C89 find another way */
const char *opcode_to_string(Opcode op) {
static const char *names[] = {
[OP_EXIT] = "exit",
[OP_JMP] = "jump",
[OP_JMPF] = "jump_if_flag",
[OP_CALL] = "call",
[OP_RETURN] = "return",
static const char *names[] = {[OP_EXIT] = "exit",
[OP_JMP] = "jump",
[OP_JMPF] = "jump_if_flag",
[OP_CALL] = "call",
[OP_RETURN] = "return",
[OP_LOAD_IMM] = "load_immediate",
[OP_LOAD_IMM] = "load_immediate",
/* Register_indirect loads */
[OP_LOAD_IND_8] = "load_indirect_8",
[OP_LOAD_IND_16] = "load_indirect_16",
[OP_LOAD_IND_32] = "load_indirect_32",
/* Register_indirect loads */
[OP_LOAD_IND_8] = "load_indirect_8",
[OP_LOAD_IND_16] = "load_indirect_16",
[OP_LOAD_IND_32] = "load_indirect_32",
/* Absolute address loads */
[OP_LOAD_ABS_8] = "load_absolute_8",
[OP_LOAD_ABS_16] = "load_absolute_16",
[OP_LOAD_ABS_32] = "load_absolute_32",
/* Absolute address loads */
[OP_LOAD_ABS_8] = "load_absolute_8",
[OP_LOAD_ABS_16] = "load_absolute_16",
[OP_LOAD_ABS_32] = "load_absolute_32",
/* Base+offset loads */
[OP_LOAD_OFF_8] = "load_offset_8",
[OP_LOAD_OFF_16] = "load_offset_16",
[OP_LOAD_OFF_32] = "load_offset_32",
/* Base+offset loads */
[OP_LOAD_OFF_8] = "load_offset_8",
[OP_LOAD_OFF_16] = "load_offset_16",
[OP_LOAD_OFF_32] = "load_offset_32",
/* Absolute address stores */
[OP_STORE_ABS_8] = "store_absolute_8",
[OP_STORE_ABS_16] = "store_absolute_16",
[OP_STORE_ABS_32] = "store_absolute_32",
/* Absolute address stores */
[OP_STORE_ABS_8] = "store_absolute_8",
[OP_STORE_ABS_16] = "store_absolute_16",
[OP_STORE_ABS_32] = "store_absolute_32",
/* Register_indirect stores */
[OP_STORE_IND_8] = "store_indirect_8",
[OP_STORE_IND_16] = "store_indirect_16",
[OP_STORE_IND_32] = "store_indirect_32",
/* Register_indirect stores */
[OP_STORE_IND_8] = "store_indirect_8",
[OP_STORE_IND_16] = "store_indirect_16",
[OP_STORE_IND_32] = "store_indirect_32",
/* Base+offset stores */
[OP_STORE_OFF_8] = "store_offset_8",
[OP_STORE_OFF_16] = "store_offset_16",
[OP_STORE_OFF_32] = "store_offset_32",
/* Base+offset stores */
[OP_STORE_OFF_8] = "store_offset_8",
[OP_STORE_OFF_16] = "store_offset_16",
[OP_STORE_OFF_32] = "store_offset_32",
/* Memory operations */
[OP_MALLOC] = "malloc",
[OP_MEMSET_8] = "memset_8",
[OP_MEMSET_16] = "memset_16",
[OP_MEMSET_32] = "memset_32",
/* Memory operations */
[OP_MALLOC] = "malloc",
[OP_MEMSET_8] = "memset_8",
[OP_MEMSET_16] = "memset_16",
[OP_MEMSET_32] = "memset_32",
/* Register operations */
[OP_REG_MOV] = "register_move",
[OP_SYSCALL] = "syscall",
/* Register operations */
[OP_REG_MOV] = "register_move",
[OP_SYSCALL] = "syscall",
/* Bit operations */
[OP_BIT_SHIFT_LEFT] = "bit_shift_left",
[OP_BIT_SHIFT_RIGHT] = "bit_shift_right",
[OP_BIT_SHIFT_R_EXT] = "bit_shift_re",
[OP_BAND] = "bit_and",
[OP_BOR] = "bit_or",
[OP_BXOR] = "bit_xor",
/* Bit operations */
[OP_BIT_SHIFT_LEFT] = "bit_shift_left",
[OP_BIT_SHIFT_RIGHT] = "bit_shift_right",
[OP_BIT_SHIFT_R_EXT] = "bit_shift_re",
[OP_BAND] = "bit_and",
[OP_BOR] = "bit_or",
[OP_BXOR] = "bit_xor",
/* Integer arithmetic */
[OP_ADD_INT] = "add_int",
[OP_SUB_INT] = "sub_int",
[OP_MUL_INT] = "mul_int",
[OP_DIV_INT] = "div_int",
/* Integer arithmetic */
[OP_ADD_INT] = "add_int",
[OP_SUB_INT] = "sub_int",
[OP_MUL_INT] = "mul_int",
[OP_DIV_INT] = "div_int",
/* Natural number arithmetic */
[OP_ADD_NAT] = "add_nat",
[OP_SUB_NAT] = "sub_nat",
[OP_MUL_NAT] = "mul_nat",
[OP_DIV_NAT] = "div_nat",
/* Natural number arithmetic */
[OP_ADD_NAT] = "add_nat",
[OP_SUB_NAT] = "sub_nat",
[OP_MUL_NAT] = "mul_nat",
[OP_DIV_NAT] = "div_nat",
/* Floating point operations */
[OP_ADD_REAL] = "add_real",
[OP_SUB_REAL] = "sub_real",
[OP_MUL_REAL] = "mul_real",
[OP_DIV_REAL] = "div_real",
/* Floating point operations */
[OP_ADD_REAL] = "add_real",
[OP_SUB_REAL] = "sub_real",
[OP_MUL_REAL] = "mul_real",
[OP_DIV_REAL] = "div_real",
/* Type conversions */
[OP_INT_TO_REAL] = "int_to_real",
[OP_NAT_TO_REAL] = "nat_to_real",
[OP_REAL_TO_INT] = "real_to_int",
[OP_REAL_TO_NAT] = "real_to_nat",
/* Type conversions */
[OP_INT_TO_REAL] = "int_to_real",
[OP_NAT_TO_REAL] = "nat_to_real",
[OP_REAL_TO_INT] = "real_to_int",
[OP_REAL_TO_NAT] = "real_to_nat",
/* Integer comparisons */
[OP_JEQ_INT] = "jump_eq_int",
[OP_JNEQ_INT] = "jump_neq_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",
/* Integer comparisons */
[OP_JEQ_INT] = "jump_eq_int",
[OP_JNEQ_INT] = "jump_neq_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",
/* Natural number comparisons */
[OP_JEQ_NAT] = "jump_eq_nat",
[OP_JNEQ_NAT] = "jump_neq_nat",
[OP_JGT_NAT] = "jump_gt_nat",
[OP_JLT_NAT] = "jump_lt_nat",
[OP_JLE_NAT] = "jump_le_nat",
[OP_JGE_NAT] = "jump_ge_nat",
/* Natural number comparisons */
[OP_JEQ_NAT] = "jump_eq_nat",
[OP_JNEQ_NAT] = "jump_neq_nat",
[OP_JGT_NAT] = "jump_gt_nat",
[OP_JLT_NAT] = "jump_lt_nat",
[OP_JLE_NAT] = "jump_le_nat",
[OP_JGE_NAT] = "jump_ge_nat",
/* Floating point comparisons */
[OP_JEQ_REAL] = "jump_eq_real",
[OP_JNEQ_REAL] = "jump_neq_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",
/* Floating point comparisons */
[OP_JEQ_REAL] = "jump_eq_real",
[OP_JNEQ_REAL] = "jump_neq_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",
/* String operations */
[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",
/* String operations */
[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",
/* String conversions */
[OP_INT_TO_STRING] = "int_to_string",
[OP_NAT_TO_STRING] = "nat_to_string",
[OP_REAL_TO_STRING] = "real_to_string",
[OP_STRING_TO_INT] = "string_to_int",
[OP_STRING_TO_NAT] = "string_to_nat",
[OP_STRING_TO_REAL] = "string_to_real"};
/* String conversions */
[OP_INT_TO_STRING] = "int_to_string",
[OP_NAT_TO_STRING] = "nat_to_string",
[OP_REAL_TO_STRING] = "real_to_string",
[OP_STRING_TO_INT] = "string_to_int",
[OP_STRING_TO_NAT] = "string_to_nat",
[OP_STRING_TO_REAL] = "string_to_real"};
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
return "<invalid-opcode>";
@ -141,7 +141,6 @@ const char *opcode_to_string(Opcode op) {
return name ? name : "<unknown-opcode>";
}
void emit_op(VM *vm, u8 byte) {
#ifdef DEBUG_PRINT
printf("code[%d] = %s\n", vm->cp, opcode_to_string(byte));
@ -186,9 +185,11 @@ u32 symbol_table_add(SymbolTable *table, Symbol s) {
}
if (!resize_or_check_size(table)) {
fprintf(stderr,
"Error: Symbol table is out of memory! This is likely because you built this in static mode."
"if you built using malloc, that means your computer is out of memory. Close a few tabs in your web browser and try again."
fprintf(stderr,
"Error: Symbol table is out of memory! This is likely because you "
"built the assembler in static mode, increase the static size."
"if you built using malloc, that means your computer is out of "
"memory. Close a few tabs in your web browser and try again."
"Count was %d, while capacity was %d\n",
table->count, table->capacity);
exit(1);
@ -212,7 +213,8 @@ u32 symbol_table_add(SymbolTable *table, Symbol s) {
u32 get_ref(SymbolTable *st, const char *name, u32 length) {
Symbol *sym = symbol_table_lookup(st, name, length);
if (!sym) {
fprintf(stderr, "Error: Undefined Symbol '%.*s'\n", length, name);
fprintf(stderr, "Error: Assembler has no idea what Symbol '%.*s' means.\n",
length, name);
exit(1);
return 0;
}
@ -232,15 +234,15 @@ u32 get_ptr(Token token, SymbolTable *st) {
char *endptr;
u32 out = (u32)strtoul(token.start, &endptr, 10);
if (endptr == token.start || *endptr != '\0') {
fprintf(stderr, "Invalid decimal literal: '%.*s'\n", token.length,
token.start);
fprintf(stderr, "Invalid decimal literal at line %d: %.*s\n", token.line,
token.length, token.start);
exit(1);
}
return out;
}
fprintf(stderr, "Error: Not a pointer or symbol '%.*s'\n", token.length,
token.start);
fprintf(stderr, "Error: Not a pointer or symbol at line %d: %.*s\n",
token.line, token.length, token.start);
exit(1);
}
@ -254,8 +256,8 @@ u32 get_reg(Token token, SymbolTable *st) {
return atoi(token.start);
}
fprintf(stderr, "Error: Not a register or symbol '%.*s'\n", token.length,
token.start);
fprintf(stderr, "Error: Not a register or symbol at line %d: %.*s\n",
token.line, token.length, token.start);
exit(1);
}
@ -439,16 +441,16 @@ bool define_global(VM *vm, SymbolTable *st) {
case '\\':
case '"':
case '\'':
break; // Keep as-is
break;
default:
i--; // Rewind for unknown escapes
i--; /* Rewind for unknown escapes */
}
}
write_u8(vm, memory, addr + 4 + len, c);
len++;
}
u32 size = len + 5; // 4 (len) + dst_len + 1 (null)
u32 size = len + 5; /* 4 (len) + dst_len + 1 (null) */
s.size = size;
vm->mp += size;
@ -610,9 +612,8 @@ void define_branch(VM *vm, SymbolTable *st) {
int get_instruction_byte_size(const char *opname) {
// Return (1 + 1)
if (strcmp(opname, "return") == 0) {
return 2; // 1 byte opcode + 1 byte return register
return 2;
}
if (strcmp(opname, "neg_int") == 0 || strcmp(opname, "abs_int") == 0 ||
@ -632,14 +633,13 @@ int get_instruction_byte_size(const char *opname) {
strcmp(opname, "store_indirect_32") == 0 ||
strcmp(opname, "real_to_nat") == 0 || strcmp(opname, "nat_to_int") == 0 ||
strcmp(opname, "int_to_nat") == 0 ||
strcmp(opname, "string_length") == 0 ||
strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 ||
strcmp(opname, "memset_8") == 0 || strcmp(opname, "memset_16") == 0 ||
strcmp(opname, "string_length") == 0 || strcmp(opname, "memset") == 0 ||
strcmp(opname, "memset") == 0 || strcmp(opname, "memset_8") == 0 ||
strcmp(opname, "memset_16") == 0 ||
strcmp(opname, "register_move") == 0 || strcmp(opname, "malloc") == 0) {
return 3;
}
// Register_register_register opcodes (4 bytes: 1 + 3)
if (strcmp(opname, "add_int") == 0 || strcmp(opname, "sub_int") == 0 ||
strcmp(opname, "mul_int") == 0 || strcmp(opname, "div_int") == 0 ||
strcmp(opname, "add_nat") == 0 || strcmp(opname, "sub_nat") == 0 ||
@ -654,13 +654,11 @@ int get_instruction_byte_size(const char *opname) {
return 4;
}
// (5 bytes: 1 + 4)
if (strcmp(opname, "halt") == 0 || strcmp(opname, "jump_if_flag") == 0 ||
strcmp(opname, "jump") == 0) {
return 5;
}
// Load, Load_immediate (6 bytes: 1 + 1 + 4)
if (strcmp(opname, "load_absolute_32") == 0 ||
strcmp(opname, "load_immediate") == 0 ||
strcmp(opname, "load_address") == 0 ||
@ -672,7 +670,6 @@ int get_instruction_byte_size(const char *opname) {
return 6;
}
// jump compare (7 bytes: 1 + 4 + 1 + 1)
if (strcmp(opname, "jump_eq_int") == 0 ||
strcmp(opname, "jump_neq_int") == 0 ||
strcmp(opname, "jump_gt_int") == 0 ||
@ -704,15 +701,17 @@ int get_instruction_byte_size(const char *opname) {
exit(-1);
}
#define FAKE_OP(op) \
} else if (strleq(token.start, op, token.length)) { \
do { \
while (token.type != TOKEN_SEMICOLON) { \
token = next_token(); \
} \
/*printf("code[%d]=%s\n %d + %d = %d\n", vm->cp, op, get_instruction_byte_size(op), vm->cp, vm->cp + get_instruction_byte_size(op)); */\
vm->cp += get_instruction_byte_size(op); \
} while(0);
#define FAKE_OP(op) \
} else if (strleq(token.start, op, token.length)) { \
do { \
while (token.type != TOKEN_SEMICOLON) { \
token = next_token(); \
} \
/*printf("code[%d]=%s\n %d + %d = %d\n", vm->cp, op, \
* get_instruction_byte_size(op), vm->cp, vm->cp + \
* get_instruction_byte_size(op)); */ \
vm->cp += get_instruction_byte_size(op); \
} while (0);
/**
* Build the symbol table and calculate the types/size/offsets of all values.
@ -771,11 +770,11 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
continue;
}
#ifdef DEBUG_PRINT
printf("-- %.*s --\n", token.length, token.start);
#endif
#ifdef DEBUG_PRINT
printf("-- %.*s --\n", token.length, token.start);
#endif
if (token.type == TOKEN_IDENTIFIER) {
// check to see if it is an opcode first
/* check to see if it is an opcode first */
if (strleq(token.start, "exit", token.length)) {
vm->cp++;
@ -783,9 +782,9 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
next_token();
vm->cp += 4;
#ifdef DEBUG_PRINT
printf("code[%d] = exit\n", vm->cp);
#endif
#ifdef DEBUG_PRINT
printf("code[%d] = exit\n", vm->cp);
#endif
next_token_is(TOKEN_SEMICOLON);
} else if (strleq(token.start, "call", token.length)) {
@ -799,9 +798,9 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
Token next = next_token_is(TOKEN_LPAREN);
next = next_token();
while (next.type != TOKEN_RPAREN) {
get_reg(next, st);
vm->cp++;
next = next_token();
get_reg(next, st);
vm->cp++;
next = next_token();
}
next = next_token();
@ -812,9 +811,9 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
get_reg(next, st);
vm->cp++;
}
#ifdef DEBUG_PRINT
printf("code[%d] = call\n", vm->cp);
#endif
#ifdef DEBUG_PRINT
printf("code[%d] = call\n", vm->cp);
#endif
continue;
} else if (strleq(token.start, "syscall", token.length)) {
@ -829,97 +828,97 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
vm->cp++;
next = next_token();
}
#ifdef DEBUG_PRINT
printf("code[%d] = syscall\n", vm->cp);
#endif
#ifdef DEBUG_PRINT
printf("code[%d] = syscall\n", vm->cp);
#endif
continue;
FAKE_OP("load_immediate")
FAKE_OP("load_address")
FAKE_OP("malloc")
FAKE_OP("memset_8")
FAKE_OP("memset_16")
FAKE_OP("memset_32")
FAKE_OP("load_offset_8")
FAKE_OP("load_offset_16")
FAKE_OP("load_offset_32")
FAKE_OP("load_indirect_8")
FAKE_OP("load_indirect_16")
FAKE_OP("load_indirect_32")
FAKE_OP("load_absolute_8")
FAKE_OP("load_absolute_16")
FAKE_OP("load_absolute_32")
FAKE_OP("store_absolute_8")
FAKE_OP("store_absolute_16")
FAKE_OP("store_absolute_32")
FAKE_OP("store_indirect_8")
FAKE_OP("store_indirect_16")
FAKE_OP("store_indirect_32")
FAKE_OP("store_offset_8")
FAKE_OP("store_offset_16")
FAKE_OP("store_offset_32")
FAKE_OP("register_move")
FAKE_OP("add_int")
FAKE_OP("sub_int")
FAKE_OP("mul_int")
FAKE_OP("div_int")
FAKE_OP("abs_int")
FAKE_OP("neg_int")
FAKE_OP("add_nat")
FAKE_OP("sub_nat")
FAKE_OP("mul_nat")
FAKE_OP("div_nat")
FAKE_OP("abs_nat")
FAKE_OP("neg_nat")
FAKE_OP("add_real")
FAKE_OP("sub_real")
FAKE_OP("mul_real")
FAKE_OP("div_real")
FAKE_OP("abs_real")
FAKE_OP("neg_real")
FAKE_OP("int_to_real")
FAKE_OP("nat_to_real")
FAKE_OP("real_to_int")
FAKE_OP("real_to_nat")
FAKE_OP("bit_shift_left")
FAKE_OP("bit_shift_right")
FAKE_OP("bit_shift_r_ext")
FAKE_OP("bit_and")
FAKE_OP("bit_or")
FAKE_OP("bit_xor")
FAKE_OP("jump")
FAKE_OP("jump_if_flag")
FAKE_OP("jump_eq_int")
FAKE_OP("jump_neq_int")
FAKE_OP("jump_gt_int")
FAKE_OP("jump_lt_int")
FAKE_OP("jump_le_int")
FAKE_OP("jump_ge_int")
FAKE_OP("jump_eq_nat")
FAKE_OP("jump_neq_nat")
FAKE_OP("jump_gt_nat")
FAKE_OP("jump_lt_nat")
FAKE_OP("jump_le_nat")
FAKE_OP("jump_ge_nat")
FAKE_OP("jump_eq_real")
FAKE_OP("jump_neq_real")
FAKE_OP("jump_ge_real")
FAKE_OP("jump_gt_real")
FAKE_OP("jump_lt_real")
FAKE_OP("jump_le_real")
FAKE_OP("string_length")
FAKE_OP("int_to_string")
FAKE_OP("nat_to_string")
FAKE_OP("real_to_string")
FAKE_OP("string_eq")
FAKE_OP("string_concat")
FAKE_OP("string_get_char")
FAKE_OP("string_find_char")
FAKE_OP("string_slice")
FAKE_OP("string_to_int")
FAKE_OP("string_to_nat")
FAKE_OP("string_to_real")
FAKE_OP("load_immediate")
FAKE_OP("load_address")
FAKE_OP("malloc")
FAKE_OP("memset_8")
FAKE_OP("memset_16")
FAKE_OP("memset_32")
FAKE_OP("load_offset_8")
FAKE_OP("load_offset_16")
FAKE_OP("load_offset_32")
FAKE_OP("load_indirect_8")
FAKE_OP("load_indirect_16")
FAKE_OP("load_indirect_32")
FAKE_OP("load_absolute_8")
FAKE_OP("load_absolute_16")
FAKE_OP("load_absolute_32")
FAKE_OP("store_absolute_8")
FAKE_OP("store_absolute_16")
FAKE_OP("store_absolute_32")
FAKE_OP("store_indirect_8")
FAKE_OP("store_indirect_16")
FAKE_OP("store_indirect_32")
FAKE_OP("store_offset_8")
FAKE_OP("store_offset_16")
FAKE_OP("store_offset_32")
FAKE_OP("register_move")
FAKE_OP("add_int")
FAKE_OP("sub_int")
FAKE_OP("mul_int")
FAKE_OP("div_int")
FAKE_OP("abs_int")
FAKE_OP("neg_int")
FAKE_OP("add_nat")
FAKE_OP("sub_nat")
FAKE_OP("mul_nat")
FAKE_OP("div_nat")
FAKE_OP("abs_nat")
FAKE_OP("neg_nat")
FAKE_OP("add_real")
FAKE_OP("sub_real")
FAKE_OP("mul_real")
FAKE_OP("div_real")
FAKE_OP("abs_real")
FAKE_OP("neg_real")
FAKE_OP("int_to_real")
FAKE_OP("nat_to_real")
FAKE_OP("real_to_int")
FAKE_OP("real_to_nat")
FAKE_OP("bit_shift_left")
FAKE_OP("bit_shift_right")
FAKE_OP("bit_shift_r_ext")
FAKE_OP("bit_and")
FAKE_OP("bit_or")
FAKE_OP("bit_xor")
FAKE_OP("jump")
FAKE_OP("jump_if_flag")
FAKE_OP("jump_eq_int")
FAKE_OP("jump_neq_int")
FAKE_OP("jump_gt_int")
FAKE_OP("jump_lt_int")
FAKE_OP("jump_le_int")
FAKE_OP("jump_ge_int")
FAKE_OP("jump_eq_nat")
FAKE_OP("jump_neq_nat")
FAKE_OP("jump_gt_nat")
FAKE_OP("jump_lt_nat")
FAKE_OP("jump_le_nat")
FAKE_OP("jump_ge_nat")
FAKE_OP("jump_eq_real")
FAKE_OP("jump_neq_real")
FAKE_OP("jump_ge_real")
FAKE_OP("jump_gt_real")
FAKE_OP("jump_lt_real")
FAKE_OP("jump_le_real")
FAKE_OP("string_length")
FAKE_OP("int_to_string")
FAKE_OP("nat_to_string")
FAKE_OP("real_to_string")
FAKE_OP("string_eq")
FAKE_OP("string_concat")
FAKE_OP("string_get_char")
FAKE_OP("string_find_char")
FAKE_OP("string_slice")
FAKE_OP("string_to_int")
FAKE_OP("string_to_nat")
FAKE_OP("string_to_real")
} else {
// some other identifier
/* some other identifier */
printf("Unknown id at line %d: %.*s\n", token.line, token.length,
token.start);
exit(1);
@ -944,17 +943,17 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
if (token.type != TOKEN_EOF) {
if (token.type == TOKEN_KEYWORD_GLOBAL) {
// ignore, already processed
next_token(); // type
next_token(); // var
next_token(); // eq
next_token(); // value
next_token(); // ;
/* ignore, already processed */
next_token(); /* type */
next_token(); /* var */
next_token(); /* eq */
next_token(); /* value */
next_token(); /* ; */
continue;
}
if (token.type == TOKEN_KEYWORD_FN) {
// ignore, already processed
/* ignore, already processed */
Token next = next_token();
while (next.type != TOKEN_RPAREN) {
next = next_token();
@ -967,19 +966,19 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
token.type == TOKEN_TYPE_U8 || token.type == TOKEN_TYPE_U16 ||
token.type == TOKEN_TYPE_NAT || token.type == TOKEN_TYPE_REAL ||
token.type == TOKEN_TYPE_STR) {
// ignore, already processed
next_token(); // type
next_token(); // var
next_token(); // reg
next_token(); // ;
/* ignore, already processed */
next_token(); /* type */
next_token(); /* var */
next_token(); /* reg */
next_token(); /* ; */
continue;
}
if (token.type == TOKEN_KEYWORD_LOOP || token.type == TOKEN_KEYWORD_IF ||
token.type == TOKEN_KEYWORD_ELSE || token.type == TOKEN_KEYWORD_DO ||
token.type == TOKEN_KEYWORD_FOR) {
// ignore, already processed
next_token(); // id
/* ignore, already processed */
next_token(); /* id */
}
if (token.type == TOKEN_KEYWORD_RETURN) {
@ -1001,11 +1000,11 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
continue;
}
#ifdef DEBUG_PRINT
printf("-- %.*s --\n", token.length, token.start);
#endif
#ifdef DEBUG_PRINT
printf("-- %.*s --\n", token.length, token.start);
#endif
if (token.type == TOKEN_IDENTIFIER) {
// check to see if it is an opcode first
/* check to see if it is an opcode first */
if (strleq(token.start, "exit", token.length)) {
emit_op(vm, OP_EXIT);
@ -1032,18 +1031,18 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
Token next = next_token_is(TOKEN_LPAREN);
next = next_token();
while (next.type != TOKEN_RPAREN) {
u8 arg = get_reg(next, st);
emit_byte(vm, arg);
vm->cp++;
arg_count++;
next = next_token();
u8 arg = get_reg(next, st);
emit_byte(vm, arg);
vm->cp++;
arg_count++;
next = next_token();
}
vm->code[arg_pos] = arg_count;
#ifdef DEBUG_PRINT
#ifdef DEBUG_PRINT
printf("^code[%d] = %d\n", arg_pos, arg_count);
#endif
#endif
next = next_token();
if (next.type == TOKEN_SEMICOLON) {
@ -1085,8 +1084,9 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
vm->cp += 4;
next = next_token();
while (next.type != TOKEN_SEMICOLON && next.type != TOKEN_ARROW_RIGHT) {
u8 arg =get_reg(next, st);
while (next.type != TOKEN_SEMICOLON &&
next.type != TOKEN_ARROW_RIGHT) {
u8 arg = get_reg(next, st);
emit_byte(vm, arg);
vm->cp++;
next = next_token();
@ -2404,7 +2404,7 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
} else if (strleq(token.start, "string_to_nat", token.length)) {
} else if (strleq(token.start, "string_to_real", token.length)) {
} else {
// some other identifier
/* some other identifier */
printf("Unknown id at line %d: %.*s\n", token.line, token.length,
token.start);
exit(1);

View File

@ -1,5 +1,7 @@
#include "lexer.h"
#include "compiler.h"
#include "../../vm/common.h"
#include "../../vm/opcodes.h"
#include "../../vm/libc.h"
#include <stdio.h>
#include <stdlib.h>
@ -178,101 +180,6 @@ ValueType *plex_get_field_by_name(PlexTable *plex_table,
return plex_get_field(plex_table, fields_table, plex_index, (u32)field_index);
}
Symbol *global(VM *vm) {
Symbol s;
ValueType t;
s.ref.global = vm->mp;
Token token_type = next_token();
Token array_or_eq = next_token();
if (array_or_eq.type == TOKEN_LBRACKET) {
Token rb = next_token();
if (rb.type != TOKEN_RBRACKET)
return nil;
Token eq = next_token();
if (eq.type != TOKEN_EQ)
return nil;
t.type = ARRAY;
ValueType array_type;
switch (token_type.type) {
case TOKEN_TYPE_I8:
array_type.type = I8;
break;
case TOKEN_TYPE_I16:
array_type.type = I16;
break;
case TOKEN_TYPE_INT:
array_type.type = I32;
break;
case TOKEN_TYPE_U8:
array_type.type = U8;
break;
case TOKEN_TYPE_U16:
array_type.type = U16;
break;
case TOKEN_TYPE_NAT:
array_type.type = U32;
break;
case TOKEN_TYPE_REAL:
array_type.type = F32;
break;
case TOKEN_TYPE_STR:
array_type.type = STR;
break;
case TOKEN_IDENTIFIER:
break;
default:
return nil;
}
} else {
// its not an array, so should be =
if (array_or_eq.type != TOKEN_EQ)
return nil;
switch (token_type.type) {
case TOKEN_TYPE_I8:
t.type = I8;
break;
case TOKEN_TYPE_I16:
t.type = I16;
break;
case TOKEN_TYPE_INT:
t.type = I32;
break;
case TOKEN_TYPE_U8:
t.type = U8;
break;
case TOKEN_TYPE_U16:
t.type = U16;
break;
case TOKEN_TYPE_NAT:
t.type = U32;
break;
case TOKEN_TYPE_REAL:
t.type = F32;
break;
case TOKEN_TYPE_STR:
t.type = STR;
break;
case TOKEN_IDENTIFIER:
break;
default:
return nil;
}
}
s.type = t;
Token value = next_token();
return nil;
}
typedef struct {
Token current;
Token previous;
@ -420,18 +327,18 @@ void number(Compiler *c, VM *vm) {
c->last = Symbol{ .type=parser.previous.type };
switch (parser.previous.type) {
case TOKEN_INT_LITERAL: {
case TOKEN_LITERAL_INT: {
char *endptr;
i32 value = (i32)strtol(parser.previous.start, &endptr, 10);
emit_u32(vm, value);
return;
}
case TOKEN_UINT_LITERAL: {
case TOKEN_LITERAL_NAT: {
long value = atol(parser.previous.start);
emit_u32(vm, value);
return;
}
case TOKEN_FLOAT_LITERAL: {
case TOKEN_LITERAL_REAL: {
float value = atof(parser.previous.start);
fixed_t fvalue = float_to_fixed(value);
emit_u32(vm, fvalue);
@ -454,10 +361,10 @@ static void unary(Compiler *c, VM *vm) {
switch (operatorType) {
case TOKEN_MINUS: {
switch (c->last.type) {
case TOKEN_UINT_LITERAL:
emit_opcode(vm, OP_NEG_UINT);
case TOKEN_FLOAT_LITERAL:
emit_opcode(vm, OP_NEG_FLOAT);
case TOKEN_LITERAL_NAT:
emit_opcode(vm, OP_NEG_NAT);
case TOKEN_LITERAL_REAL:
emit_opcode(vm, OP_NEG_REAL);
default:
emit_opcode(vm, OP_NEG_INT);
}
@ -472,7 +379,7 @@ static void unary(Compiler *c, VM *vm) {
}
static void emitHalt(Compiler *c, VM *vm) {
emit_opcode(vm, OP_HALT);
emit_opcode(vm, OP_EXIT);
advance();
number(c, vm);
}

View File

@ -3,7 +3,6 @@
#import "../../vm/common.h"
typedef enum { GLOBAL, LOCAL } ScopeType;
typedef enum {
VOID,
BOOL,
@ -33,6 +32,8 @@ typedef struct symbol_s Symbol;
typedef struct symbol_tab_s SymbolTable;
typedef struct names_tab_s NamesTable;
typedef struct plex_fields_tab_s PlexFieldsTable;
typedef struct scope_s Scope;
typedef struct scope_tab_s ScopeTable;
struct value_type_s {
SymbolType type;
@ -65,7 +66,6 @@ struct array_def_s {
struct symbol_s {
u32 name;
ValueType type;
ScopeType scope;
union {
u32 local; // register
u32 global; // address
@ -103,14 +103,20 @@ struct names_tab_s {
u32 capacity;
};
/**
* FIXME:
* Symbols need to be inside a scope so we can have duplicates
*/
struct symbol_tab_s {
Symbol *symbols;
u32 count;
u32 capacity;
};
struct scope_s {
SymbolTable table;
};
struct scope_tab_s {
Scope *scopes;
u32 count;
u32 capacity;
};
#endif

View File

@ -1,8 +1,5 @@
/* fixed.c - Q16.16 Fixed-Point Math Implementation */
#include "fixed.h"
/* Conversion functions */
fixed_t int_to_fixed(i32 i) { return i << 16; }
i32 fixed_to_int(fixed_t f) { return f >> 16; }
@ -16,38 +13,32 @@ fixed_t fixed_add(fixed_t a, fixed_t b) { return a + b; }
fixed_t fixed_sub(fixed_t a, fixed_t b) { return a - b; }
fixed_t fixed_mul(fixed_t a, fixed_t b) {
/* Extract high and low parts */
i32 a_hi = a >> 16;
u32 a_lo = (u32)a & 0xFFFFU;
i32 b_hi = b >> 16;
u32 b_lo = (u32)b & 0xFFFFU;
/* Compute partial products */
i32 p0 = (i32)(a_lo * b_lo) >> 16; /* Low * Low */
i32 p1 = a_hi * (i32)b_lo; /* High * Low */
i32 p2 = (i32)a_lo * b_hi; /* Low * High */
i32 p3 = (a_hi * b_hi) << 16; /* High * High */
i32 p0 = (i32)(a_lo * b_lo) >> 16;
i32 p1 = a_hi * (i32)b_lo;
i32 p2 = (i32)a_lo * b_hi;
i32 p3 = (a_hi * b_hi) << 16;
/* Combine results */
return p0 + p1 + p2 + p3;
}
fixed_t fixed_div(fixed_t a, fixed_t b) {
int negative;
i32 negative;
u32 ua, ub, quotient, remainder;
int i;
i32 i;
if (b == 0)
return 0; /* Handle division by zero */
return 0;
/* Determine sign */
negative = ((a < 0) ^ (b < 0));
/* Work with absolute values */
ua = (a < 0) ? -a : a;
ub = (b < 0) ? -b : b;
/* Perform division using long division in base 2^16 */
quotient = 0;
remainder = 0;
@ -71,111 +62,18 @@ fixed_t fixed_div(fixed_t a, fixed_t b) {
return negative ? -(i32)quotient : (i32)quotient;
}
int fixed_eq(fixed_t a, fixed_t b) { return a == b; }
i32 fixed_eq(fixed_t a, fixed_t b) { return a == b; }
int fixed_ne(fixed_t a, fixed_t b) { return a != b; }
i32 fixed_ne(fixed_t a, fixed_t b) { return a != b; }
int fixed_lt(fixed_t a, fixed_t b) { return a < b; }
i32 fixed_lt(fixed_t a, fixed_t b) { return a < b; }
int fixed_le(fixed_t a, fixed_t b) { return a <= b; }
i32 fixed_le(fixed_t a, fixed_t b) { return a <= b; }
int fixed_gt(fixed_t a, fixed_t b) { return a > b; }
i32 fixed_gt(fixed_t a, fixed_t b) { return a > b; }
int fixed_ge(fixed_t a, fixed_t b) { return a >= b; }
i32 fixed_ge(fixed_t a, fixed_t b) { return a >= b; }
/* Unary operations */
fixed_t fixed_neg(fixed_t f) { return -f; }
fixed_t fixed_abs(fixed_t f) { return (f < 0) ? -f : f; }
/* Square root using Newton-Raphson method */
fixed_t fixed_sqrt(fixed_t f) {
fixed_t x, prev;
if (f <= 0)
return 0;
x = f;
/* Newton-Raphson iteration: x = (x + f/x) / 2 */
do {
prev = x;
x = fixed_div(fixed_add(x, fixed_div(f, x)), int_to_fixed(2));
} while (
fixed_gt(fixed_abs(fixed_sub(x, prev)), 1)); /* Precision to 1/65536 */
return x;
}
/* Sine function using Taylor series */
fixed_t fixed_sin(fixed_t f) {
fixed_t result, term, f_squared;
int i;
/* Normalize angle to [-π, π] */
fixed_t pi2 = fixed_mul(FIXED_PI, int_to_fixed(2));
while (fixed_gt(f, FIXED_PI))
f = fixed_sub(f, pi2);
while (fixed_lt(f, fixed_neg(FIXED_PI)))
f = fixed_add(f, pi2);
/* Taylor series: sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ... */
result = f;
term = f;
f_squared = fixed_mul(f, f);
/* Calculate first few terms for reasonable precision */
for (i = 3; i <= 11; i += 2) {
term = fixed_mul(term, f_squared);
term = fixed_div(term, int_to_fixed(i * (i - 1)));
if ((i / 2) % 2 == 0) {
result = fixed_add(result, term);
} else {
result = fixed_sub(result, term);
}
}
return result;
}
/* Cosine function using Taylor series */
fixed_t fixed_cos(fixed_t f) {
/* cos(x) = 1 - x²/2! + x⁴/4! - x⁶/6! + ... */
fixed_t result = FIXED_ONE;
fixed_t term = FIXED_ONE;
fixed_t f_squared = fixed_mul(f, f);
int i;
for (i = 2; i <= 12; i += 2) {
term = fixed_mul(term, f_squared);
term = fixed_div(term, int_to_fixed(i * (i - 1)));
if ((i / 2) % 2 == 0) {
result = fixed_add(result, term);
} else {
result = fixed_sub(result, term);
}
}
return result;
}
/* Tangent function */
fixed_t fixed_tan(fixed_t f) {
fixed_t cos_val = fixed_cos(f);
if (cos_val == 0)
return 0; /* Handle undefined case */
return fixed_div(fixed_sin(f), cos_val);
}
/* Utility functions */
fixed_t fixed_min(fixed_t a, fixed_t b) { return (a < b) ? a : b; }
fixed_t fixed_max(fixed_t a, fixed_t b) { return (a > b) ? a : b; }
fixed_t fixed_clamp(fixed_t f, fixed_t min_val, fixed_t max_val) {
if (f < min_val)
return min_val;
if (f > max_val)
return max_val;
return f;
}

View File

@ -3,51 +3,34 @@
#include "common.h"
/* Q16.16 fixed-point type */
typedef i32 fixed_t;
/* Constants */
#define FIXED_ONE 0x00010000L /* 1.0 in Q16.16 */
#define FIXED_ZERO 0x00000000L /* 0.0 in Q16.16 */
#define FIXED_HALF 0x00008000L /* 0.5 in Q16.16 */
#define FIXED_PI 0x0003243FL /* π ≈ 3.14159 */
#define FIXED_E 0x0002B7E1L /* e ≈ 2.71828 */
#define FIXED_PI 0x0003243FL /* 3.14159 */
#define FIXED_E 0x0002B7E1L /* 2.71828 */
#define FIXED_MAX 0x7FFFFFFFL /* Maximum positive value */
#define FIXED_MIN 0x80000000L /* Minimum negative value */
/* Conversion functions */
fixed_t int_to_fixed(i32 i);
i32 fixed_to_int(fixed_t f);
fixed_t float_to_fixed(f32 f);
f32 fixed_to_float(fixed_t f);
/* Basic arithmetic operations */
fixed_t fixed_add(fixed_t a, fixed_t b);
fixed_t fixed_sub(fixed_t a, fixed_t b);
fixed_t fixed_mul(fixed_t a, fixed_t b);
fixed_t fixed_div(fixed_t a, fixed_t b);
/* Comparison functions */
int fixed_eq(fixed_t a, fixed_t b);
int fixed_ne(fixed_t a, fixed_t b);
int fixed_lt(fixed_t a, fixed_t b);
int fixed_le(fixed_t a, fixed_t b);
int fixed_gt(fixed_t a, fixed_t b);
int fixed_ge(fixed_t a, fixed_t b);
i32 fixed_eq(fixed_t a, fixed_t b);
i32 fixed_ne(fixed_t a, fixed_t b);
i32 fixed_lt(fixed_t a, fixed_t b);
i32 fixed_le(fixed_t a, fixed_t b);
i32 fixed_gt(fixed_t a, fixed_t b);
i32 fixed_ge(fixed_t a, fixed_t b);
/* Unary operations */
fixed_t fixed_neg(fixed_t f);
fixed_t fixed_abs(fixed_t f);
/* Advanced math functions */
fixed_t fixed_sqrt(fixed_t f);
fixed_t fixed_sin(fixed_t f); /* f in radians */
fixed_t fixed_cos(fixed_t f); /* f in radians */
fixed_t fixed_tan(fixed_t f); /* f in radians */
/* Utility functions */
fixed_t fixed_min(fixed_t a, fixed_t b);
fixed_t fixed_max(fixed_t a, fixed_t b);
fixed_t fixed_clamp(fixed_t f, fixed_t min, fixed_t max);
#endif /* FIXED_H */
#endif

View File

@ -20,9 +20,7 @@ plex Screen implements Device {
byte[] buffer;
draw() {
unsafe {
write(this, this.buffer, this.buffer.length);
}
write(this, this.buffer, this.buffer.length);
}
}
@ -82,8 +80,6 @@ function set_color(int box_size, int bx, int by, int mx, int my, byte color) {
if (my > bottom) return;
selected_color = color;
return;
}
/**
@ -97,22 +93,17 @@ function outline_swatch(Device screen, byte color, int x, int y) {
rectangle(screen, bg_color, x, y, 20, 20);
rectangle(screen, color, x + 2, y + 2, 17, 17);
return;
}
/**
* Draw a rectangle
*/
function rectangle(Device screen, byte color, int x, int y, int width, int height) {
// we need unsafe because we are using pointers `.ptr` and `memset` directly
// unsafe takes the guardrails off and allows you to access/modify memory directly
unsafe {
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;
}
}
return;
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;
}
}