// 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;
}
Example #2
0
File: vm.c Project: OlliV/pttk91
/**
 * 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;
}