// Main shifter. typedata *shift_content(enum SHIFT shift_type, uint32_t content, uint32_t shift_factor) { typedata *result = malloc(sizeof(typedata)); if (!shift_factor) { result->carry_out = 0; result->result_content = content; return result; } switch(shift_type) { case LOGIC_LEFT: result = (logical_left_shift(content, shift_factor)); break; case LOGIC_RIGHT: result = (logical_shift_right(content, shift_factor)); break; case ARITHMETIC_RIGHT: result = (arithmetic_right_shift(content, shift_factor)); break; case ROTATE_RIGHT: result = (rotate_right(content, shift_factor)); break; } return result; }
/** * Evaluate the last decoded instruction. */ static int eval(struct vm_state * state, uint32_t * mem) { /* Copy some data for (hopefully) faster access */ int opcode = state->opcode; int rj = state->rj; int ri = state->ri; int memsize = state->memsize; int param; /* Final second arg value will be stored to this variable */ int i, sp; /* Temp variables */ param = state->imm; /* Starting point for "parsing" the final value */ if (ri != 0) { /* Add indexing register Ri */ param += state->regs[ri]; } if (state->m == PTTK91_ADDRMOD_1) { /* Direct memory fetch */ if (VM_MEM_OUT_OF_BOUNDS(param, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } param = mem[param]; } else if (state->m == PTTK91_ADDRMOD_2) { /* Indirect meory fetch */ if ((opcode >= PTTK91_JUMP && opcode <= PTTK91_JNGRE) || (opcode == PTTK91_STORE)) { /* + For all branching instructions: mode 2 is bad access mode * + PTTK91_STORE doesn't support mode 2 */ return VM_ERR_BAD_ACCESS_MODE; } /* First fetch */ if (VM_MEM_OUT_OF_BOUNDS(param, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } param = mem[param]; /* Second fetch */ if (VM_MEM_OUT_OF_BOUNDS(param, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } param = mem[param]; } else if (state->m == PTTK91_ADDRMOD_3) { /* Mode 3 is not specified */ return VM_ERR_BAD_ACCESS_MODE; } /* Execute */ switch(opcode) { case PTTK91_NOP: break; /* Data transfer instructions */ case PTTK91_STORE: if (VM_MEM_OUT_OF_BOUNDS_STORE(param, state->code_sec_end, memsize)) { state->sr.fma = 1; return VM_ERR_WR_ADDRESS_OUT_OF_BOUNDS; } mem[param] = state->regs[rj]; break; case PTTK91_LOAD: state->regs[rj] = param; break; case PTTK91_IN: if (inp_handler(param, &(state->regs[rj]))) { return VM_ERR_INVALID_DEVICE; } break; case PTTK91_OUT: if (outp_handler(param, state->regs[rj])) { return VM_ERR_INVALID_DEVICE; } break; /* Arithmetic instructions */ case PTTK91_ADD: state->regs[rj] = state->regs[rj] + param; break; case PTTK91_SUB: state->regs[rj] = state->regs[rj] - param; break; case PTTK91_MUL: state->regs[rj] = state->regs[rj] * param; break; case PTTK91_DIV: /* Div by zero check */ if (param == 0) { state->sr.div = 1; return VM_ERR_PARAM_ERROR; } state->regs[rj] = state->regs[rj] / param; break; case PTTK91_MOD: /* Div by zero check */ if (param == 0) { state->sr.div = 1; return VM_ERR_PARAM_ERROR; } state->regs[rj] = state->regs[rj] % param; break; /* Logic instructions */ case PTTK91_AND: state->regs[rj] = (unsigned int)(state->regs[rj]) & (unsigned int)param; break; case PTTK91_OR: state->regs[rj] = (unsigned int)(state->regs[rj]) | (unsigned int)param; break; case PTTK91_XOR: state->regs[rj] = (unsigned int)(state->regs[rj]) ^ (unsigned int)param; break; case PTTK91_SHL: /* Shift left */ state->regs[rj] = (unsigned int)(state->regs[rj]) << (unsigned int)param; break; case PTTK91_SHR: /* Shift right */ state->regs[rj] = (unsigned int)(state->regs[rj]) >> (unsigned int)param; break; case PTTK91_NOT: state->regs[rj] = ~((unsigned int)(state->regs[rj])); break; case PTTK91_SHRA: /* Arithmetic shift right */ state->regs[rj] = arithmetic_right_shift(state->regs[rj], (unsigned int)param); break; case PTTK91_COMP: if (state->regs[rj] > param) { state->sr.gre = 1; state->sr.equ = 0; state->sr.les = 0; } else if (state->regs[rj] < param) { state->sr.gre = 0; state->sr.equ = 0; state->sr.les = 1; } else { state->sr.gre = 0; state->sr.equ = 1; state->sr.les = 0; } break; /* Branching instructions */ case PTTK91_JUMP: state->pc = param; break; case PTTK91_JNEG: if (state->regs[rj] < 0) { state->pc = param; } break; case PTTK91_JZER: if (state->regs[rj] == 0) { state->pc = param; } break; case PTTK91_JPOS: if (state->regs[rj] > 0) { state->pc = param; } break; case PTTK91_JNNEG: if (state->regs[rj] >= 0) { state->pc = param; } break; case PTTK91_JNZER: if (state->regs[rj] != 0) { state->pc = param; } break; case PTTK91_JNPOS: if (state->regs[rj] <= 0) { state->pc = param; } break; case PTTK91_JLES: if (state->sr.les) { state->pc = param; } break; case PTTK91_JEQU: if (state->sr.equ) { state->pc = param; } break; case PTTK91_JGRE: if (state->sr.gre) { state->pc = param; } break; case PTTK91_JNLES: if (state->sr.equ || state->sr.gre) { state->pc = param; } break; case PTTK91_JNEQU: if (state->sr.les || state->sr.gre) { state->pc = param; } break; case PTTK91_JNGRE: if (state->sr.les || state->sr.equ) { state->pc = param; } break; /* Subroutine instructions */ case PTTK91_CALL: state->regs[rj] = state->regs[rj] + 2; /* Check that the new stack pointer is valid */ if (VM_MEM_OUT_OF_BOUNDS_STORE(state->regs[rj], state->code_sec_end, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } mem[state->regs[rj] - 1] = state->pc; /* Push PC */ mem[state->regs[rj]] = state->regs[PTTK91_FP]; /* Push FP */ state->regs[PTTK91_FP] = state->regs[rj]; /* Set new FP */ state->pc = param; /* Branch */ break; case PTTK91_EXIT: sp = state->regs[PTTK91_FP]; /* Check that the old fp location is valid */ if (VM_MEM_OUT_OF_BOUNDS(sp, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } /* Check that the new sp & fp are valid */ if (VM_MEM_OUT_OF_BOUNDS(sp - 2 - param, memsize) || VM_MEM_OUT_OF_BOUNDS((int)(mem[sp]), memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } /* Read back the original sp & fp values */ state->regs[rj] = sp - 2 - param; state->regs[PTTK91_FP] = mem[sp]; state->pc = mem[sp - 1]; /* Return */ break; /* Stack instructions */ case PTTK91_PUSH: state->regs[rj] = state->regs[rj] + 1; sp = state->regs[rj]; /* Check that the new sp value is valid */ if (VM_MEM_OUT_OF_BOUNDS_STORE(sp, state->code_sec_end, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } mem[sp] = param; break; case PTTK91_POP: sp = state->regs[rj]; /* POP: Second operand should be always a register */ if (state->m != 0) { return VM_ERR_BAD_ACCESS_MODE; } if (VM_MEM_OUT_OF_BOUNDS_STORE(sp, state->code_sec_end, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } state->regs[ri] = mem[sp]; state->regs[rj] = sp - 1; break; case PTTK91_PUSHR: /* Push R0..R6 */ sp = state->regs[rj] + 1; state->regs[rj] = state->regs[rj] + PTTK91_NUM_REGS - 1; for (i = 0; i < PTTK91_NUM_REGS - 1; i++) { if (VM_MEM_OUT_OF_BOUNDS_STORE(sp, state->code_sec_end, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } mem[sp++] = state->regs[i]; } break; case PTTK91_POPR: /* Pop R6..R0 */ for (i = PTTK91_NUM_REGS - 2; i >= 0; i--) { if (VM_MEM_OUT_OF_BOUNDS_STORE(state->regs[rj], state->code_sec_end, memsize)) { return VM_ERR_ADDRESS_OUT_OF_BOUNDS; } state->regs[i] = mem[state->regs[rj - i]]; } state->regs[rj] = state->regs[rj] - (PTTK91_NUM_REGS - 1); break; /* System calls */ case PTTK91_SVC: #if VM_DEBUG == 1 printf("SVC %i\n", param); #endif if (svc_handler(state, mem, param)) { return VM_ERR_ILLEGAL_SVC; } break; default: state->sr.uni = 1; return VM_ERR_INVALID_OPCODE; } return 0; }