diff --git a/src/arch/linux/devices.c b/src/arch/linux/devices.c index 0ac41ec..3f30787 100644 --- a/src/arch/linux/devices.c +++ b/src/arch/linux/devices.c @@ -11,16 +11,24 @@ i32 console_open(void *data, u32 mode) { i32 console_read(void *data, u8 *buffer, u32 size) { USED(data); - ssize_t result = read(STDIN_FILENO, buffer, size); - if (result < 0) return -1; /* Error */ - return (i32)result; /* Bytes read */ + for (u32 i = 0; i < size; i++) { + u8 ch = getchar(); + if (ch == '\0') + break; + if (ch == '\n') + break; + buffer[i] = ch; + } + return 0; } i32 console_write(void *data, const u8 *buffer, u32 size) { USED(data); - ssize_t result = write(STDOUT_FILENO, buffer, size); - if (result < 0) return -1; /* Error */ - return (i32)result; /* Bytes written */ + for (u32 i = 0; i < size; i++) { + putchar(buffer[i]); + } + return 0; + } i32 console_close(void *data) { diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 8fd0574..a1b1d2e 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -227,6 +227,73 @@ void register_sdl_devices(VM *vm) { &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_IMM] = "load-immediate", + [OP_STORE] = "store", + [OP_PUSH] = "push", + [OP_POP] = "pop", + [OP_REG_MOV] = "register-move", + [OP_SYSCALL] = "syscall", + [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 ""; + } + + const char* name = names[op]; + return name ? name : ""; +} + i32 main(i32 argc, char *argv[]) { struct CompilerConfig config = {0}; @@ -352,6 +419,7 @@ i32 main(i32 argc, char *argv[]) { } } else { while (running) { + //printf("| %d %s %d\n", vm.code[vm.pc], opcode_to_string(vm.code[vm.pc]), vm.pc); running = step_vm(&vm); } } diff --git a/src/tools/assembler.c b/src/tools/assembler.c index 5635817..569d226 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -58,7 +58,6 @@ Symbol *symbol_table_lookup(SymbolTable *table, const char *name) { return NULL; } -// Add this helper for your current code u32 find_label_in_table(SymbolTable *table, const char *name) { Symbol *sym = symbol_table_lookup(table, name); if (!sym) { @@ -77,39 +76,71 @@ int get_instruction_byte_size(ExprNode *node) { } // Register-based opcodes (2 bytes: opcode + register) - if (strcmp(opname, "pop") == 0 || strcmp(opname, "push") == 0) { + if (strcmp(opname, "pop") == 0 || strcmp(opname, "push") == 0 || + strcmp(opname, "jump") == 0 || strcmp(opname, "jump-if-flag") == 0) { return 2; } if (strcmp(opname, "int-to-string") == 0 || + strcmp(opname, "nat-to-string") == 0 || + 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-nat") == 0 || strcmp(opname, "int-to-nat") == 0 || + strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "string-length") == 0) { return 3; } // Load/store with register and address (5 bytes: 1 + 1 + 4) if (strcmp(opname, "load") == 0 || strcmp(opname, "store") == 0 || - strcmp(opname, "jump") == 0 || strcmp(opname, "jump-if-flag") == 0 || strcmp(opname, "call") == 0) { return 5; } // Register-register-register opcodes (4 bytes: 1 + 3) - if (strcmp(opname, "add-int") == 0 || strcmp(opname, "sub-int") == 0) { + 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 || + strcmp(opname, "mul-nat") == 0 || strcmp(opname, "div-nat") == 0 || + strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 || + strcmp(opname, "mul-real") == 0 || strcmp(opname, "div-real") == 0) { return 4; } - // Load-immediate (5 bytes: 1 + 1 + 4) - if (strcmp(opname, "load-immediate") == 0) { + // Load, Load-immediate (5 bytes: 1 + 1 + 4) + if (strcmp(opname, "load-immediate") == 0 || strcmp(opname, "load") == 0 || + strcmp(opname, "store") == 0) { return 6; } + // jump compare (7 bytes: 1 + 4 + 1 + 1) + if (strcmp(opname, "jump-eq-int") == 0 || + strcmp(opname, "jump-gt-int") == 0 || + strcmp(opname, "jump-lt-int") == 0 || + strcmp(opname, "jump-le-int") == 0 || + strcmp(opname, "jump-ge-int") == 0 || + strcmp(opname, "jump-eq-nat") == 0 || + strcmp(opname, "jump-gt-nat") == 0 || + strcmp(opname, "jump-lt-nat") == 0 || + strcmp(opname, "jump-le-nat") == 0 || + strcmp(opname, "jump-ge-nat") == 0 || + strcmp(opname, "jump-eq-real") == 0 || + strcmp(opname, "jump-gt-real") == 0 || + strcmp(opname, "jump-lt-real") == 0 || + strcmp(opname, "jump-le-real") == 0 || + strcmp(opname, "jump-ge-real") == 0) { + return 7; + } + // Syscall (1 + syscall_id (4) + args) if (strcmp(opname, "syscall") == 0) { return 1 + 4 + (node->child_count > 0 ? node->child_count - 1 : 0); } fprintf(stderr, "Unknown opcode for sizing: %s\n", opname); - return 4; // Conservative fallback + exit(-1); } int calculate_instruction_size(ExprNode *node) { @@ -125,12 +156,12 @@ void collect_symbols_in_node(SymbolTable *table, ExprNode *node, for (int i = 0; i < depth; i++) strcat(indent, " "); - printf("%sProcessing: %s (addr=%d)\n", indent, node->token, *current_addr); + //printf("%s%d %s ", indent, *current_addr, node->token); if (strcmp(node->token, "label") == 0) { if (node->child_count >= 1) { const char *name = node->children[0]->token; - printf("%s ADDING LABEL: %s -> %d\n", indent, name, *current_addr); + //printf(" %s -> %d\n", name, *current_addr); symbol_table_add(table, name, *current_addr, SYMBOL_CODE); } @@ -141,7 +172,8 @@ void collect_symbols_in_node(SymbolTable *table, ExprNode *node, } else { int size = get_instruction_byte_size(node); *current_addr += size; - printf("%s +%d bytes -> %d\n", indent, size, *current_addr); + //printf(" +%d bytes -> %d\n", size, *current_addr); + //printf("\n"); } } diff --git a/src/vm/opcodes.h b/src/vm/opcodes.h index 7ee81d3..0975f9c 100644 --- a/src/vm/opcodes.h +++ b/src/vm/opcodes.h @@ -98,8 +98,8 @@ typedef struct device_s { u32 flags; /* permissions, status, etc. */ } Device; -#define MEMORY_SIZE 1024 /*(640 * 480 + 65536)*/ -#define CODE_SIZE 128 /*8192*/ +#define MEMORY_SIZE (640 * 480 + 65536) +#define CODE_SIZE 8192 #define FRAMES_SIZE 128 #define STACK_SIZE 256 #define DEVICES_SIZE 8 @@ -111,7 +111,7 @@ typedef struct vm_s { u32 rp; /* return stack pointer (top of stack) */ u32 mp; /* memory pointer (last allocated value) */ u32 dc; /* device count */ - u32 flag; /* flag (temporary results like SYSCALL status) */ + i32 flag; /* flag (temporary results like SYSCALL status) */ Frame frames[FRAMES_SIZE]; /* function call frames */ u32 stack[STACK_SIZE]; /* main stack */ u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */ diff --git a/src/vm/vm.c b/src/vm/vm.c index 1566b2b..2d60e21 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -7,20 +7,19 @@ do { \ i32 cond; \ u32 mask, target; \ - u8 dest, src1, src2; \ + u8 src1, src2; \ type value; \ type value2; \ - dest = read_u8(vm, code, vm->pc); \ - vm->pc++; \ + target = read_u32(vm, code, vm->pc); \ + vm->pc+=4; \ src1 = read_u8(vm, code, vm->pc); \ vm->pc++; \ src2 = read_u8(vm, code, vm->pc); \ vm->pc++; \ - value = frame->registers[src1]; \ - value2 = frame->registers[src2]; \ + value = (type)frame->registers[src1]; \ + value2 = (type)frame->registers[src2]; \ cond = !!(value op value2); \ mask = -(u32)cond; \ - target = frame->registers[dest]; \ vm->pc = (target & mask) | (vm->pc & ~mask); \ return true; \ } while (0) @@ -33,8 +32,8 @@ vm->pc++; \ src2 = read_u8(vm, code, vm->pc); \ vm->pc++; \ - frame->registers[dest] = \ - (type)frame->registers[src1] op(type) frame->registers[src2]; \ + frame->registers[dest] = \ + (type)frame->registers[src1] op (type)frame->registers[src2]; \ return true; \ } while (0) @@ -79,7 +78,7 @@ bool step_vm(VM *vm) { return true; } case OP_RETURN: { - frame->rp = 0; /* reset register ptr */ + frame->rp = 0; /* reset register ptr */ vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */ vm->mp = vm->frames[vm->fp--].start; /* reset memory pointer to start @@ -215,9 +214,9 @@ bool step_vm(VM *vm) { size_reg = read_u8(vm, code, vm->pc); vm->pc++; - path_ptr = frame->registers[path_reg]; /* R0: path pointer */ + path_ptr = frame->registers[path_reg]; /* R0: path pointer */ buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */ - size = frame->registers[size_reg]; /* R2: size */ + size = frame->registers[size_reg]; /* R2: size */ dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]); if (dev && dev->ops->write) { @@ -262,7 +261,7 @@ bool step_vm(VM *vm) { args_ptr_reg = read_u8(vm, code, vm->pc); vm->pc++; - path_ptr = frame->registers[path_reg]; /* R0: device path */ + path_ptr = frame->registers[path_reg]; /* R0: device path */ cmd = frame->registers[cmd_reg]; /* R1: ioctl command */ args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */ diff --git a/test/add.asm.lisp b/test/add.asm.lisp index 99b9059..9ae330d 100644 --- a/test/add.asm.lisp +++ b/test/add.asm.lisp @@ -1,25 +1,31 @@ ((code - (label main ; 0 - (load-immediate $0 1) ; 6 - (push $0) ; 8 - (load-immediate $0 1) ; 14 - (push $0) ; 16 - (call &add) ; 19 - (pop $0) ; 21 - (int-to-string $1 $0) ; 24 - (load-immediate $3 &terminal-str) ; 30 - (string-length $2 $1) ; 33 - (syscall DEVICE-WRITE $3 $1 $2) ; 41 - (load-immediate $6 &new-line) - (string-length $7 $6) - (syscall DEVICE-WRITE $5 $6 $7) - (halt)) ; 42 + (label main + (load-immediate $0 1) + (push $0) + (load-immediate $0 1) + (push $0) + (call &add) + (pop $0) + (int-to-string $1 $0) + (push $1) + (call &println) + (halt)) - (label add ; 43 - (pop $0) ; 45 - (pop $1) ; 47 + (label add + (pop $0) + (pop $1) (add-int $2 $1 $0) (push $2) + (return)) + + (label println + (load-immediate $0 &terminal-str) + (load-immediate $3 &new-line) + (pop $1) + (string-length $2 $1) + (syscall DEVICE-WRITE $0 $1 $2) + (string-length $4 $3) + (syscall DEVICE-WRITE $0 $3 $4) (return))) (data (label terminal-str "/dev/term/0") diff --git a/test/fib.asm.lisp b/test/fib.asm.lisp index 875d7ad..279a2d8 100644 --- a/test/fib.asm.lisp +++ b/test/fib.asm.lisp @@ -5,20 +5,22 @@ (call &fib) (pop $0) (int-to-string $1 $0) - (load-immediate $2, &terminal-str) - (string-length $4, $3) - (syscall DEVICE-WRITE, $2, $1, $4) + (load-immediate $2 &terminal-str) + (string-length $4 $3) + (syscall DEVICE-WRITE $2 $1 $4) + (load-immediate $11 &new-line) + (string-length $12 $11) + (syscall DEVICE-WRITE $2 $11 $12) (halt)) (label fib (pop $0) (load-immediate $1 2) - (load $2 &base-case) - (jump-lt-int $2 $0 $1) - (load-immediate $2 2) + (jump-lt-int &base-case $0 $1) + (load-immediate $3 2) (sub-int $4 $0 $3) (push $4) (call &fib) - (load-immediate $2 1) + (load-immediate $3 1) (sub-int $4 $0 $3) (push $4) (call &fib) @@ -26,9 +28,10 @@ (pop $5) (add-int $6 $5 $4) (push $6) - (return)) - (label base-case - (push $0) - (return))) + (return) + (label base-case + (push $0) + (return)))) (data - (label terminal-str "/dev/term/0"))) + (label terminal-str "/dev/term/0") + (label new-line "\n")))