diff --git a/src/tools/assembler.c b/src/tools/assembler.c index 5bb1a38..9fe4010 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -70,13 +70,13 @@ int get_instruction_byte_size(ExprNode *node) { const char *opname = node->token; // Simple opcodes (1 byte) - if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0) { + if (strcmp(opname, "halt") == 0) { return 1; } // Register-based opcodes (2 bytes: opcode + register) if (strcmp(opname, "pop") == 0 || strcmp(opname, "jump-if-flag") == 0 || - strcmp(opname, "jump") == 0 || strcmp(opname, "push") == 0) { + strcmp(opname, "jump") == 0 || strcmp(opname, "push") == 0 || strcmp(opname, "return") == 0) { return 2; } @@ -86,7 +86,7 @@ int get_instruction_byte_size(ExprNode *node) { strcmp(opname, "int-to-real") == 0 || strcmp(opname, "put-8") == 0 || strcmp(opname, "nat-to-real") == 0 || strcmp(opname, "put-16") == 0 || strcmp(opname, "real-to-int") == 0 || strcmp(opname, "put") == 0 || - strcmp(opname, "real-to-nat") == 0 || + strcmp(opname, "real-to-nat") == 0 || strcmp(opname, "get-arg") == 0 || strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "int-to-nat") == 0 || strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 || strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 || @@ -110,14 +110,9 @@ int get_instruction_byte_size(ExprNode *node) { return 4; } - // (5 bytes: 1 + 4) - if (strcmp(opname, "call") == 0) { - return 5; - } - // Load, Load-immediate (6 bytes: 1 + 1 + 4) if (strcmp(opname, "load") == 0 || strcmp(opname, "load-immediate") == 0 || - strcmp(opname, "load-16") == 0 || strcmp(opname, "load-8") == 0) { + strcmp(opname, "load-16") == 0 || strcmp(opname, "load-8") == 0 || strcmp(opname, "call") == 0) { return 6; } @@ -432,8 +427,12 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_opcode(vm, OP_CALL); u32 addr = resolve_symbol(table, node->children[0]->token); emit_u32(vm, addr); + int reg = parse_register(node->children[1]->token); + emit_byte(vm, reg); } else if (strcmp(opname, "return") == 0) { emit_opcode(vm, OP_RETURN); + int reg = parse_register(node->children[0]->token); + emit_byte(vm, reg); } else if (strcmp(opname, "load-immediate") == 0) { emit_opcode(vm, OP_LOAD_IMM); int reg = parse_register(node->children[0]->token); @@ -524,6 +523,12 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { int src1 = parse_register(node->children[1]->token); emit_byte(vm, dest); emit_byte(vm, src1); + } else if (strcmp(opname, "get-arg") == 0) { + emit_opcode(vm, OP_GET_ARG); + 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, "push") == 0) { emit_opcode(vm, OP_PUSH); int reg = parse_register(node->children[0]->token); diff --git a/src/vm/opcodes.h b/src/vm/opcodes.h index 332fec7..71584be 100644 --- a/src/vm/opcodes.h +++ b/src/vm/opcodes.h @@ -26,6 +26,7 @@ typedef enum { OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */ OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */ OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */ + OP_GET_ARG, /* get-arg : this.dest_reg = parent.src_reg */ OP_PUSH, /* push : push const of ref */ OP_POP, /* pop : pop cosnt or ref */ OP_REG_MOV, /* register-move : dest = src1 */ @@ -90,6 +91,7 @@ typedef struct frame_s { u32 rp; /* register pointer (last unused) */ u32 start; /* start and end of global allocated block */ u32 end; + u8 return_reg; } Frame; typedef enum { diff --git a/src/vm/str.c b/src/vm/str.c index 8dc736e..f6ca1bb 100644 --- a/src/vm/str.c +++ b/src/vm/str.c @@ -43,6 +43,42 @@ u32 strnlength(const char *str, u32 max_len) { return i; } +void *memcopy(void *dest, const void *src, u32 n) { + u8 *d = (u8 *)dest; + const u8 *s = (const u8 *)src; + + while (n >= sizeof(u32) && + (((uintptr_t)d & 3) == 0) && + (((uintptr_t)s & 3) == 0)) { + *(u32 *)d = *(u32 *)s; + d += sizeof(u32); + s += sizeof(u32); + n -= sizeof(u32); + } + + while (n--) { + *d++ = *s++; + } + + return dest; +} + +void *memmov(void *dest, const void *src, u32 n) { + u8 *d = (u8 *)dest; + const u8 *s = (const u8 *)src; + + if (d < s) { + return memcopy(dest, src, n); + } else if (d > s) { + d += n; + s += n; + while (n--) { + *--d = *--s; + } + } + + return dest; +} /* Static digit lookup table (0-9) */ const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; diff --git a/src/vm/str.h b/src/vm/str.h index 684756c..40d1da4 100644 --- a/src/vm/str.h +++ b/src/vm/str.h @@ -7,6 +7,8 @@ bool streq(const char *s1, const char *s2); i32 strcopy(char* to, const char *from, u32 length); u32 strlength(const char *str); u32 strnlength(const char *str, u32 max_len); +void *memcopy(void *dest, const void *src, u32 n); +void *memmov(void *dest, const void *src, u32 n); void uint_to_string(u32 value, char *buffer); void int_to_string(i32 value, char *buffer); void fixed_to_string(i32 value, char *buffer); diff --git a/src/vm/vm.c b/src/vm/vm.c index 13b7cc2..31aaf63 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -67,7 +67,7 @@ u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length) { * Step to the next opcode in the vm. */ bool step_vm(VM *vm) { - u16 opcode, dest, src1, src2; + i16 opcode, dest, src1, src2; u32 v, ptr; i32 value; Frame *frame; @@ -83,6 +83,11 @@ bool step_vm(VM *vm) { case OP_CALL: { u32 jmp = read_u32(vm, code, vm->pc); /* location of function in code */ vm->pc += 4; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + if (src1 >= 0) { + frame->return_reg = src1; + } vm->return_stack[vm->rp++] = vm->pc; /* set return address */ vm->fp++; /* increment to the next free frame */ vm->frames[vm->fp].start = vm->mp; /* set start of new memory block */ @@ -90,7 +95,13 @@ bool step_vm(VM *vm) { return true; } case OP_RETURN: { + Frame *parent = &vm->frames[vm->fp - 1]; frame->rp = 0; /* reset register ptr */ + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + if (src1 >= 0) { + parent->registers[parent->return_reg] = frame->registers[src1]; + } vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */ vm->mp = vm->frames[vm->fp--].start; /* reset memory pointer to start @@ -137,7 +148,6 @@ bool step_vm(VM *vm) { write_u32(vm, memory, i, value); } - frame->registers[0] = dest; vm->flag = 1; return true; } @@ -169,7 +179,6 @@ bool step_vm(VM *vm) { write_u16(vm, memory, i, value); } - frame->registers[0] = dest; vm->flag = 1; return true; } @@ -201,7 +210,6 @@ bool step_vm(VM *vm) { write_u8(vm, memory, i, value); } - frame->registers[0] = dest; vm->flag = 1; return true; } @@ -334,6 +342,16 @@ bool step_vm(VM *vm) { write_u8(vm, memory, ptr, v8); return true; } + case OP_GET_ARG: { + Frame *parent = &vm->frames[vm->fp - 1]; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + frame->registers[dest] = + parent->registers[src1]; + return true; + } case OP_PUSH: { dest = read_u8(vm, code, vm->pc); vm->pc++; diff --git a/test/add.asm.lisp b/test/add.asm.lisp index 68c4d93..cb4c4f6 100644 --- a/test/add.asm.lisp +++ b/test/add.asm.lisp @@ -1,24 +1,26 @@ -(module add - (const terminal-namespace "/dev/term/0") - (const new-line "\n") - - (fn :1 main () +((code + (label main (load-immediate $0 1) - (load-immediate $1 1) - (call &add ($0 $1) $2) - (int-to-string $1 $2) - (call &pln ($1)) + (call &add $0) + (int-to-string $1 $0) + (call &println nil) (halt)) - - (fn :1 add ($0 $1) + + (label add + (get-arg $0 $0) + (get-arg $1 $0) (add-int $2 $1 $0) (return $2)) - (fn :1 pln ($1) + (label println (load-immediate $0 &terminal-namespace) (load-immediate $3 &new-line) + (get-arg $1 $1) (string-length $2 $1) (syscall WRITE $0 $1 $2) (string-length $4 $3) (syscall WRITE $0 $3 $4) - (return))) + (return nil))) +(data + (label terminal-namespace "/dev/term/0") + (label new-line "\n")))