#include "vm.h" #define FRAME_HEADER_SIZE 12 u32 pc; /* program counter */ u32 cp; /* code pointer */ u32 mp; /* memory pointer */ u32 fp; /* frame pointer */ u32 flag; /* flag */ u8 interrupt; /* device interrupt */ u32 *code; /* code */ u8 *mem; /* memory */ bool step_vm() { u32 instruction = code[pc++]; u8 opcode = DECODE_OP(instruction); switch (opcode) { case OP_HALT: { /* no need to decode, all are zeros */ return false; } case OP_CALL: { DECODE_A(instruction) u32 fn_ptr, local_count, return_ptr; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; fn_ptr = READ_U32(rd); local_count = READ_U32(r1); return_ptr = READ_U32(r2); /* push parents frame value to reset the heap to */ WRITE_U32(mp, fp); mp += 4; /* push return address to child frame */ WRITE_U32(mp, pc + 1); mp += 4; /* push local address to return the value to */ WRITE_U32(mp, return_ptr); mp += 4; /* now set the frame pointer, where the locals start */ fp = mp; /* move mp by count many locals */ mp += (4 * local_count); /* jump to dest_ptr */ pc = fn_ptr; return true; } case OP_RETURN: { DECODE_B(instruction) u32 i, size = 0; u32 return_local = fp + dest; u32 return_value = READ_U32(return_local); bool is_ptr = (((u16)(1)) << 15) & imm; bool replaces_value = (((u16)(1)) << 14) & imm; /* reset mp to saved mp, use header size to get "real" start of frame */ u32 frame_start = fp - FRAME_HEADER_SIZE; u32 parent_fp = READ_U32(frame_start); u32 return_address = READ_U32(frame_start + 4); u32 parent_local_return_address = READ_U32(frame_start + 8); /* reset memory to parents end of memory */ mp = fp - FRAME_HEADER_SIZE; /* reset the frame pointer */ fp = parent_fp; /* copy value to end of mp if it is a pointer */ if (is_ptr) { WRITE_U32(parent_local_return_address, mp); size = READ_U32(return_value); WRITE_U32(mp, size); mp += 4; for (i = 0; i < size; i++) { u8 value = READ_U8(return_value + i); WRITE_U8(mp, value); mp++; } } else { /* otherwise just write the return value to its location */ WRITE_U32(parent_local_return_address, return_value); } /* jump to parent frame */ pc = return_address; return true; } case OP_SYSCALL: { DECODE_A(instruction) u32 id = fp + dest; u32 args = fp + src1; u32 mem_ptr = fp + src2; flag = syscall(id, args, mem_ptr); return true; } case OP_LOAD_IMM: { DECODE_B(instruction) u32 rd = fp + dest; WRITE_U32(rd, imm); return true; } case OP_LOAD_UPPER_IMM: { DECODE_B(instruction) u32 rd = fp + dest; u32 value = READ_U32(rd); WRITE_U32(rd, (value | (((u32)(imm)) << 16))); return true; } case OP_LOAD_IND_8: { } case OP_LOAD_IND_16: { } case OP_LOAD_IND_32: { } case OP_LOAD_ABS_8: { } case OP_LOAD_ABS_16: { } case OP_LOAD_ABS_32: { } case OP_LOAD_OFF_8: { } case OP_LOAD_OFF_16: { } case OP_LOAD_OFF_32: { } case OP_STORE_ABS_8: { } case OP_STORE_ABS_16: { } case OP_STORE_ABS_32: { } case OP_STORE_IND_8: { } case OP_STORE_IND_16: { } case OP_STORE_IND_32: { } case OP_STORE_OFF_8: { } case OP_STORE_OFF_16: { } case OP_STORE_OFF_32: { } case OP_MEM_ALLOC: { DECODE_A(instruction) u32 size, ldest; u32 rd = fp + dest; u32 r1 = fp + src1; USED(src2); ldest = READ_U32(rd); WRITE_U32(ldest, mp); size = READ_U32(r1); WRITE_U32(mp, size); mp += (size + 4); return true; } case OP_MEM_CPY_8: { DECODE_A(instruction) u32 i, count, mdest, msrc; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; mdest = READ_U32(rd); msrc = READ_U32(r1); count = READ_U32(r2); if (mdest + count >= mp) { flag = 1; return true; } for (i = 0; i < count; i++) { u8 value = READ_U8(mdest + i); WRITE_U8(msrc + i, value); } flag = 0; return true; } case OP_MEM_CPY_16: { DECODE_A(instruction) u32 i, count, mdest, msrc; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; mdest = READ_U32(rd); msrc = READ_U32(r1); count = READ_U32(r2); if (mdest + count >= mp) { flag = 1; return true; } for (i = 0; i < count; i++) { u16 value = READ_U16(mdest + i); WRITE_U16(msrc + i, value); } flag = 0; return true; } case OP_MEM_CPY_32: { DECODE_A(instruction) u32 i, count, mdest, msrc; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; mdest = READ_U32(rd); msrc = READ_U32(r1); count = READ_U32(r2); if (mdest + count >= mp) { flag = 1; return true; } for (i = 0; i < count; i++) { u32 value = READ_U32(mdest + i); WRITE_U32(msrc + i, value); } flag = 0; return true; } case OP_MEM_SET_8: { DECODE_A(instruction) u32 i, start, end; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; u8 value = (u8)READ_U32(r1); u32 count = READ_U32(r2); if (r2 == 0) { flag = 1; return true; } start = rd; end = start + count; if (start >= mp || r2 > mp || end > mp) { flag = 1; return true; } for (i = start; i < end; i++) { WRITE_U8(i, value); } flag = 0; return true; } case OP_MEM_SET_16: { DECODE_A(instruction) u32 i, start, end; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; u16 value = (u16)READ_U32(r1); u32 count = READ_U32(r2); if (r2 == 0) { flag = 1; return true; } start = rd; end = start + count; if (start >= mp || r2 > mp || end > mp) { flag = 1; return true; } for (i = start; i < end; i += 2) { WRITE_U16(i, value); } flag = 0; return true; } case OP_MEM_SET_32: { DECODE_A(instruction) u32 i, start, end; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; u32 value = READ_U32(r1); u32 count = READ_U32(r2); if (r2 == 0) { flag = 1; return true; } start = rd; end = start + count; if (start >= mp || r2 > mp || end > mp) { flag = 1; return true; } for (i = start; i < end; i += 4) { WRITE_U32(i, value); } flag = 0; return true; } case OP_MOV: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; u32 value = READ_U32(r1); USED(src2); WRITE_U32(rd, value); return true; } 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_NAT: { MATH_OP(u32, +); } case OP_SUB_NAT: { MATH_OP(u32, -); } case OP_MUL_NAT: { MATH_OP(u32, *); } case OP_DIV_NAT: { MATH_OP(u32, /); } case OP_ADD_REAL: { MATH_OP(i32, +); } case OP_SUB_REAL: { MATH_OP(i32, -); } case OP_MUL_REAL: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; i32 src1_whole = (i32)READ_U32(r1) >> 16; i32 src2_whole = (i32)READ_U32(r2) >> 16; i32 src1_decimal = (i32)READ_U32(r1) & 16; i32 src2_decimal = (i32)READ_U32(r2) & 16; i32 result = 0; result += (src1_whole * src2_whole) << 16; result += (src1_whole * src2_decimal); result += (src1_decimal * src2_whole); result += ((src1_decimal * src2_decimal) >> 16) & 16; WRITE_U32(rd, result); return true; } case OP_DIV_REAL: { DECODE_A(instruction) i32 result; u32 rd = fp + dest; u32 r1 = fp + src1; u32 r2 = fp + src2; i32 src1_val = (i32)READ_U32(r1); i32 src2_val = (i32)READ_U32(r2); u32 src2_reciprocal = 1; src2_reciprocal <<= 31; src2_reciprocal = (u32)(src2_reciprocal / src2_val); result = src1_val * src2_reciprocal; result <<= 1; WRITE_U32(rd, result); return true; } case OP_INT_TO_REAL: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; i32 result = (i32)READ_U32(r1) << 16; USED(src2); WRITE_U32(rd, result); return true; } case OP_INT_TO_NAT: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; u32 result = (u32)READ_U32(r1); USED(src2); WRITE_U32(rd, result); return true; } case OP_NAT_TO_REAL: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; i32 result = ((i32)READ_U32(r1) << 16); USED(src2); WRITE_U32(rd, result); return true; } case OP_NAT_TO_INT: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; i32 result = ((i32)READ_U32(r1)); USED(src2); WRITE_U32(rd, result); return true; } case OP_REAL_TO_INT: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; i32 result = ((i32)READ_U32(r1) >> 16); USED(src2); WRITE_U32(rd, result); return true; } case OP_REAL_TO_NAT: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; u32 result = ((u32)READ_U32(r1) >> 16); USED(src2); WRITE_U32(rd, result); return true; } case OP_BIT_SHIFT_LEFT: { MATH_OP_NO_CAST(<<); } case OP_BIT_SHIFT_RIGHT: { MATH_OP_NO_CAST(>>); } case OP_BIT_SHIFT_R_EXT: { MATH_OP(i32, >>); } case OP_BIT_AND: { MATH_OP_NO_CAST(&); } case OP_BIT_OR: { MATH_OP_NO_CAST(|); } case OP_BIT_XOR: { MATH_OP_NO_CAST(^); } case OP_JMP_IMM: { DECODE_C(instruction) pc = imm; return true; } case OP_JMP_ABS: { DECODE_A(instruction) u32 rd = fp + dest; u32 jmp_dest = READ_U32(rd); if (jmp_dest > cp) { flag = 1; return true; } USED(src1); USED(src2); pc = jmp_dest; return true; } case OP_JMP_OFF: { DECODE_A(instruction) u32 rd = fp + dest; u32 r1 = fp + src1; u32 jmp_dest = READ_U32(rd) + READ_U32(r1); if (jmp_dest > cp) { flag = 1; return true; } USED(src2); pc = jmp_dest; return true; } case OP_JMP_FLAG: { DECODE_A(instruction) u32 mask; u32 rd = fp + dest; u32 jmp_dest = READ_U32(rd); if (jmp_dest > cp) { flag = 1; return true; } USED(src1); USED(src2); mask = -(u32)(flag == 0); pc = (jmp_dest & mask) | (pc & ~mask); return true; } case OP_JEQ_INT: { COMPARE_AND_JUMP(i32, ==); } case OP_JNE_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_NAT: { COMPARE_AND_JUMP(u32, ==); } case OP_JNE_NAT: { COMPARE_AND_JUMP(u32, !=); } case OP_JGT_NAT: { COMPARE_AND_JUMP(u32, >); } case OP_JLT_NAT: { COMPARE_AND_JUMP(u32, <); } case OP_JLE_NAT: { COMPARE_AND_JUMP(u32, <=); } case OP_JGE_NAT: { COMPARE_AND_JUMP(u32, >=); } case OP_JEQ_REAL: { COMPARE_AND_JUMP(i32, ==); } case OP_JNE_REAL: { COMPARE_AND_JUMP(i32, !=); } case OP_JGE_REAL: { COMPARE_AND_JUMP(i32, >=); } case OP_JGT_REAL: { COMPARE_AND_JUMP(i32, >); } case OP_JLT_REAL: { COMPARE_AND_JUMP(i32, <); } case OP_JLE_REAL: { COMPARE_AND_JUMP(i32, <=); } } /* something went very wrong */ flag = 255; return false; }