#include "vm.h" #include "device.h" #include "opcodes.h" #include "str.h" #define COMPARE_AND_JUMP(type, op) \ do { \ i32 cond; \ u32 mask, target; \ u8 src1, src2; \ type value; \ type value2; \ 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 = (type)frame->registers[src1]; \ value2 = (type)frame->registers[src2]; \ cond = !!(value op value2); \ mask = -(u32)cond; \ vm->pc = (target & mask) | (vm->pc & ~mask); \ return true; \ } while (0) #define MATH_OP(type, op) \ do { \ dest = read_u8(vm, code, vm->pc); \ vm->pc++; \ src1 = read_u8(vm, code, vm->pc); \ vm->pc++; \ src2 = read_u8(vm, code, vm->pc); \ vm->pc++; \ frame->registers[dest] = \ (type)frame->registers[src1] op(type) frame->registers[src2]; \ return true; \ } while (0) #define BIT_OP(op) \ do { \ dest = read_u8(vm, code, vm->pc); \ vm->pc++; \ src1 = read_u8(vm, code, vm->pc); \ vm->pc++; \ src2 = read_u8(vm, code, vm->pc); \ vm->pc++; \ frame->registers[dest] = frame->registers[src1] op frame->registers[src2]; \ return true; \ } while (0) u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length) { u32 str_addr = vm->mp; u32 i = 0; vm->mp += 4; while (i < length) { vm->memory[vm->mp++] = str[i++]; } vm->memory[vm->mp++] = '\0'; write_u32(vm, memory, str_addr, length); frame->end = vm->mp; return str_addr; } /** * Step to the next opcode in the vm. */ bool step_vm(VM *vm) { u16 opcode, dest, src1, src2; u32 v, ptr; i32 value; Frame *frame; /* Get current instruction & Advance to next instruction */ opcode = vm->code[vm->pc++]; frame = &vm->frames[vm->fp]; switch (opcode) { case OP_HALT: { return false; } case OP_CALL: { u32 jmp = read_u32(vm, code, vm->pc); /* location of function in code */ vm->pc += 4; 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 */ vm->pc = jmp; return true; } case OP_RETURN: { 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 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_MEMSET_32: { u32 i, start, end; u8 dest_reg = read_u8(vm, code, vm->pc++); u8 value_reg = read_u8(vm, code, vm->pc++); u8 count_reg = read_u8(vm, code, vm->pc++); u32 dest = frame->registers[dest_reg]; u32 value = frame->registers[value_reg]; u32 count = frame->registers[count_reg]; if (count == 0) { vm->flag = 1; return true; } start = dest; end = dest + count; if (start >= vm->mp || count > vm->mp || end > vm->mp) { vm->flag = 0; return true; } for (i = start; i < end; i+=4) { write_u32(vm, memory, i, value); } frame->registers[0] = dest; vm->flag = 1; return true; } case OP_MEMSET_16: { u32 i, start, end; u8 dest_reg = read_u8(vm, code, vm->pc++); u8 value_reg = read_u8(vm, code, vm->pc++); u8 count_reg = read_u8(vm, code, vm->pc++); u32 dest = frame->registers[dest_reg]; u16 value = (u16)(frame->registers[value_reg]); u32 count = frame->registers[count_reg]; if (count == 0) { vm->flag = 1; return true; } start = dest; end = dest + count; if (start >= vm->mp || count > vm->mp || end > vm->mp) { vm->flag = 0; return true; } for (i = start; i < end; i+=2) { write_u16(vm, memory, i, value); } frame->registers[0] = dest; vm->flag = 1; return true; } case OP_MEMSET_8: { u32 i, start, end; u8 dest_reg = read_u8(vm, code, vm->pc++); u8 value_reg = read_u8(vm, code, vm->pc++); u8 count_reg = read_u8(vm, code, vm->pc++); u32 dest = frame->registers[dest_reg]; u8 value = (u8)(frame->registers[value_reg]); u32 count = frame->registers[count_reg]; if (count == 0) { vm->flag = 1; return true; } start = dest; end = dest + count; if (start >= vm->mp || count > vm->mp || end > vm->mp) { vm->flag = 0; return true; } for (i = start; i < end; i++) { write_u8(vm, memory, i, value); } frame->registers[0] = dest; vm->flag = 1; return true; } case OP_LOAD_IMM: { dest = read_u8(vm, code, vm->pc); vm->pc++; v = read_u32(vm, code, vm->pc); vm->pc += 4; frame->registers[dest] = v; return true; } case OP_LOAD_32: { 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_16: { dest = read_u8(vm, code, vm->pc); vm->pc++; ptr = read_u32(vm, code, vm->pc); vm->pc += 4; v = read_u16(vm, memory, ptr); frame->registers[dest] = v; return true; } case OP_LOAD_8: { dest = read_u8(vm, code, vm->pc); vm->pc++; ptr = read_u32(vm, code, vm->pc); vm->pc += 4; v = read_u8(vm, memory, ptr); frame->registers[dest] = v; return true; } case OP_GET_32: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; v = frame->registers[src1]; ptr = read_u32(vm, memory, v); frame->registers[dest] = ptr; return true; } case OP_GET_16: { u16 v16; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; v = frame->registers[src1]; v16 = read_u16(vm, memory, v); frame->registers[dest] = v16; return true; } case OP_GET_8: { 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_STORE_32: { 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]; write_u32(vm, memory, ptr, v); return true; } case OP_STORE_16: { 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]; write_u16(vm, memory, ptr, v); return true; } case OP_STORE_8: { 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]; write_u8(vm, memory, ptr, v); return true; } case OP_PUT_32: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; ptr = frame->registers[dest]; v = frame->registers[src1]; write_u32(vm, memory, ptr, v); return true; } case OP_PUT_16: { u16 v16; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; ptr = frame->registers[dest]; v16 = frame->registers[src1]; write_u16(vm, memory, ptr, v16); return true; } case OP_PUT_8: { u8 v8; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; ptr = frame->registers[dest]; v8 = frame->registers[src1]; write_u8(vm, memory, ptr, v8); return true; } case OP_PUSH: { dest = read_u8(vm, code, vm->pc); vm->pc++; vm->stack[++vm->sp] = frame->registers[dest]; return true; } case OP_POP: { dest = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = vm->stack[vm->sp--]; return true; } case OP_REG_MOV: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = frame->registers[src1]; return true; } case OP_JMP: { dest = read_u8(vm, code, vm->pc); vm->pc++; vm->pc = frame->registers[dest]; /* Jump to address */ return true; } case OP_JMPF: { /* error handling for syscall, jump if flag == 0 */ u32 mask; dest = read_u8(vm, code, vm->pc); vm->pc++; mask = -(u32)(vm->flag == 0); vm->pc = (dest & mask) | (vm->pc & ~mask); return true; } case OP_SYSCALL: { u32 syscall_id; syscall_id = read_u32(vm, code, vm->pc); vm->pc += 4; switch (syscall_id) { case SYSCALL_DEVICE_OPEN: { Device *dev; u32 path_ptr, mode; u8 path_reg, mode_reg, dest_reg; dest_reg = read_u8(vm, code, vm->pc); vm->pc++; path_reg = read_u8(vm, code, vm->pc); vm->pc++; mode_reg = read_u8(vm, code, vm->pc); vm->pc++; path_ptr = frame->registers[path_reg]; mode = frame->registers[mode_reg]; dev = find_device_by_path(vm, (const char *)&vm->memory[path_ptr + 4]); if (dev) { if (dev->ops->open) { vm->flag = dev->ops->open(dev->data, mode); frame->registers[dest_reg] = dev->handle; } else { vm->flag = 1; /* success, no open needed */ } } else { vm->flag = 0; /* error */ } return true; } case SYSCALL_DEVICE_READ: { Device *dev; u32 handle, buffer_ptr, size; u16 handle_reg, buffer_reg, size_reg; handle_reg = read_u8(vm, code, vm->pc); vm->pc++; buffer_reg = read_u8(vm, code, vm->pc); vm->pc++; size_reg = read_u8(vm, code, vm->pc); vm->pc++; dest = read_u8(vm, code, vm->pc); vm->pc++; handle = frame->registers[handle_reg]; /* path pointer */ size = frame->registers[size_reg]; /* size */ buffer_ptr = frame->registers[dest]; dev = &vm->devices[handle]; if (dev && dev->ops->read) { vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size); frame->registers[buffer_reg] = buffer_ptr; } else { vm->flag = 0; } return true; } case SYSCALL_DEVICE_WRITE: { Device *dev; u32 handle, buffer_ptr, size; u16 handle_reg, buffer_reg, size_reg; handle_reg = read_u8(vm, code, vm->pc); vm->pc++; buffer_reg = read_u8(vm, code, vm->pc); vm->pc++; size_reg = read_u8(vm, code, vm->pc); vm->pc++; handle = frame->registers[handle_reg]; /* R0: path pointer */ buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */ size = frame->registers[size_reg]; /* R2: size */ dev = &vm->devices[handle]; if (dev && dev->ops->write) { vm->flag = dev->ops->write( dev->data, (const u8 *)&vm->memory[buffer_ptr + 4], size); } else { vm->flag = 0; } return true; } case SYSCALL_DEVICE_CLOSE: { Device *dev; u32 handle; u8 handle_reg; handle_reg = read_u8(vm, code, vm->pc); vm->pc++; handle = frame->registers[handle_reg]; /* R0: path pointer */ dev = &vm->devices[handle]; if (dev && dev->ops->close) { i32 result = dev->ops->close(dev->data); vm->flag = result; } else { vm->flag = 0; } return true; } case SYSCALL_DEVICE_IOCTL: { Device *dev; u32 handle, args_ptr, cmd; u8 handle_reg, cmd_reg, args_ptr_reg; handle_reg = read_u8(vm, code, vm->pc); vm->pc++; cmd_reg = read_u8(vm, code, vm->pc); vm->pc++; args_ptr_reg = read_u8(vm, code, vm->pc); vm->pc++; handle = frame->registers[handle_reg]; /* R0: device path */ cmd = frame->registers[cmd_reg]; /* R1: ioctl command */ args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */ dev = &vm->devices[handle]; if (dev && dev->ops && dev->ops->ioctl) { i32 result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]); vm->flag = result; } else { vm->flag = 0; /* error or no ioctl support */ } return true; } case SYSCALL_EXIT: { return false; } default: { vm->flag = 0; /* unknown syscall */ return true; } } return true; } case OP_SLL: BIT_OP(<<); case OP_SRL: BIT_OP(>>); case OP_SRE: MATH_OP(i32, >>); case OP_BAND: BIT_OP(&); case OP_BOR: BIT_OP(|); case OP_BXOR: BIT_OP(^); case OP_ADD_INT: MATH_OP(i32, +); case OP_SUB_INT: MATH_OP(i32, -); case OP_MUL_INT: MATH_OP(i32, *); case OP_DIV_INT: MATH_OP(i32, /); case OP_ADD_UINT: MATH_OP(u32, +); case OP_SUB_UINT: MATH_OP(u32, -); case OP_MUL_UINT: MATH_OP(u32, *); case OP_DIV_UINT: MATH_OP(u32, /); case OP_MUL_REAL: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; src2 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = (frame->registers[src1] * frame->registers[src2]) >> 16; return true; } case OP_DIV_REAL: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; src2 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = (frame->registers[src1] << 16) / frame->registers[src2]; return true; } case OP_ADD_REAL: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; src2 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = frame->registers[src1] + frame->registers[src2]; return true; } case OP_SUB_REAL: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; src2 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = frame->registers[src1] - frame->registers[src2]; return true; } case OP_REAL_TO_INT: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; value = frame->registers[src1]; if (value >= 0) { frame->registers[dest] = value >> 16; } else { frame->registers[dest] = -((-value) >> 16); } return true; } case OP_INT_TO_REAL: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = (frame->registers[src1] << 16); return true; } case OP_REAL_TO_UINT: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; value = frame->registers[src1]; if (value < 0) { frame->registers[dest] = 0; } else { frame->registers[dest] = AS_UINT(value >> 16); } return true; } case OP_UINT_TO_REAL: { dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = AS_INT(frame->registers[src1] << 16); return true; } case OP_JEQ_UINT: { COMPARE_AND_JUMP(u32, ==); } case OP_JNEQ_UINT: { COMPARE_AND_JUMP(u32, !=); } case OP_JGT_UINT: { COMPARE_AND_JUMP(u32, >); } case OP_JLT_UINT: { COMPARE_AND_JUMP(u32, <); } case OP_JLE_UINT: { COMPARE_AND_JUMP(u32, <=); } case OP_JGE_UINT: { COMPARE_AND_JUMP(u32, >=); } case OP_JEQ_INT: { COMPARE_AND_JUMP(i32, ==); } case OP_JNEQ_INT: { COMPARE_AND_JUMP(i32, !=); } case OP_JGT_INT: { COMPARE_AND_JUMP(i32, >); } case OP_JLT_INT: { COMPARE_AND_JUMP(i32, <); } case OP_JLE_INT: { COMPARE_AND_JUMP(i32, <=); } case OP_JGE_INT: { COMPARE_AND_JUMP(i32, >=); } case OP_JEQ_REAL: { COMPARE_AND_JUMP(i32, ==); } case OP_JNEQ_REAL: { COMPARE_AND_JUMP(i32, !=); } case OP_JGT_REAL: { COMPARE_AND_JUMP(i32, >); } case OP_JLT_REAL: { COMPARE_AND_JUMP(i32, <); } case OP_JGE_REAL: { COMPARE_AND_JUMP(i32, >=); } case OP_JLE_REAL: { COMPARE_AND_JUMP(i32, <=); } case OP_INT_TO_STRING: { char buffer[32]; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; int_to_string(AS_INT(frame->registers[src1]), buffer); ptr = str_alloc(vm, frame, buffer, strlength(buffer)); frame->registers[dest] = ptr; return true; } case OP_UINT_TO_STRING: { char buffer[32]; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; uint_to_string(frame->registers[src1], buffer); ptr = str_alloc(vm, frame, buffer, strlength(buffer)); frame->registers[dest] = ptr; return true; } case OP_REAL_TO_STRING: { char buffer[32]; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; fixed_to_string(AS_INT(frame->registers[src1]), buffer); ptr = str_alloc(vm, frame, buffer, strlength(buffer)); /* copy buffer to dest */ frame->registers[dest] = ptr; return true; } case OP_STRLEN: { u32 ptr, length; dest = read_u8(vm, code, vm->pc); vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; ptr = frame->registers[src1]; length = read_u32(vm, memory, ptr); frame->registers[dest] = length; return true; } case OP_STRCAT: { /* not implemented yet */ return false; } case OP_STR_GET_CHAR: { /* not implemented yet */ return false; } case OP_STR_FIND_CHAR: { /* not implemented yet */ return false; } case OP_STR_SLICE: { /* not implemented yet */ return false; } case OP_STRING_TO_INT: { /* not implemented yet */ return false; } case OP_STRING_TO_UINT: { /* not implemented yet */ return false; } case OP_STRING_TO_REAL: { /* not implemented yet */ return false; } } return false; /* something bad happened */ }