static void dec10_movem_m_r(DisasContext *dc) { int i, pfix = dc->tb_flags & PFIX_FLAG; TCGv addr, t0; LOG_DIS("%s [r%d], r%d pi=%d ir=%x\n", __func__, dc->src, dc->dst, dc->postinc, dc->ir); addr = tcg_temp_new(); t0 = tcg_temp_new(); crisv10_prepare_memaddr(dc, addr, 4); tcg_gen_mov_tl(t0, addr); for (i = dc->dst; i >= 0; i--) { gen_load(dc, cpu_R[i], addr, 4, 0); tcg_gen_addi_tl(addr, addr, 4); } if (pfix && dc->mode == CRISV10_MODE_AUTOINC) { tcg_gen_mov_tl(cpu_R[dc->src], t0); } if (!pfix && dc->mode == CRISV10_MODE_AUTOINC) { tcg_gen_mov_tl(cpu_R[dc->src], addr); } tcg_temp_free(addr); tcg_temp_free(t0); }
static int dec10_bdap_m(DisasContext *dc, int size) { int insn_len = 2; int rd = dc->dst; LOG_DIS("bdap_m pc=%x opcode=%d r%d r%d sz=%d\n", dc->pc, dc->opcode, dc->src, dc->dst, size); assert(dc->dst != 15); #if 0 /* 8bit embedded offset? */ if (!dc->postinc && (dc->ir & (1 << 11))) { int simm = dc->ir & 0xff; /* cpu_abort(dc->env, "Unhandled opcode"); */ /* sign extended. */ simm = (int8_t)simm; tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm); cris_set_prefix(dc); return insn_len; } #endif /* Now the rest of the modes are truly indirect. */ insn_len += dec10_prep_move_m(dc, 1, size, cpu_PR[PR_PREFIX]); tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_PR[PR_PREFIX], cpu_R[rd]); cris_set_prefix(dc); return insn_len; }
static int dec10_prep_move_m(DisasContext *dc, int s_ext, int memsize, TCGv dst) { unsigned int rs; uint32_t imm; int is_imm; int insn_len = 0; rs = dc->src; is_imm = rs == 15 && !(dc->tb_flags & PFIX_FLAG); LOG_DIS("rs=%d rd=%d is_imm=%d mode=%d pfix=%d\n", rs, dc->dst, is_imm, dc->mode, dc->tb_flags & PFIX_FLAG); /* Load [$rs] onto T1. */ if (is_imm) { if (memsize != 4) { if (s_ext) { if (memsize == 1) imm = ldsb_code(dc->pc + 2); else imm = ldsw_code(dc->pc + 2); } else { if (memsize == 1) imm = ldub_code(dc->pc + 2); else imm = lduw_code(dc->pc + 2); } } else imm = ldl_code(dc->pc + 2); tcg_gen_movi_tl(dst, imm); if (dc->mode == CRISV10_MODE_AUTOINC) { insn_len += memsize; if (memsize == 1) insn_len++; tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len); } } else { TCGv addr; addr = tcg_temp_new(); cris_flush_cc_state(dc); crisv10_prepare_memaddr(dc, addr, memsize); gen_load(dc, dst, addr, memsize, 0); if (s_ext) t_gen_sext(dst, dst, memsize); else t_gen_zext(dst, dst, memsize); insn_len += crisv10_post_memaddr(dc, memsize); tcg_temp_free(addr); } if (dc->mode == CRISV10_MODE_INDIRECT && (dc->tb_flags & PFIX_FLAG)) { dc->dst = dc->src; } return insn_len; }
static void dec_sw(DisasContext *dc) { TCGv t0; LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1); t0 = tcg_temp_new(); tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX); tcg_temp_free(t0); }
static void dec_lw(DisasContext *dc) { TCGv t0; LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16)); t0 = tcg_temp_new(); tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX); tcg_temp_free(t0); }
static int dec10_dip(DisasContext *dc) { int insn_len = 2; uint32_t imm; LOG_DIS("dip pc=%x opcode=%d r%d r%d\n", dc->pc, dc->opcode, dc->src, dc->dst); if (dc->src == 15) { imm = ldl_code(dc->pc + 2); tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm); if (dc->postinc) insn_len += 4; tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2); } else { gen_load(dc, cpu_PR[PR_PREFIX], cpu_R[dc->src], 4, 0); if (dc->postinc) tcg_gen_addi_tl(cpu_R[dc->src], cpu_R[dc->src], 4); } cris_set_prefix(dc); return insn_len; }
static unsigned int crisv10_post_memaddr(DisasContext *dc, unsigned int size) { unsigned int insn_len = 0; if (dc->tb_flags & PFIX_FLAG) { if (dc->mode == CRISV10_MODE_AUTOINC) { tcg_gen_mov_tl(cpu_R[dc->src], cpu_PR[PR_PREFIX]); } } else { if (dc->mode == CRISV10_MODE_AUTOINC) { if (dc->src == 15) { insn_len += size & ~1; } else { tcg_gen_addi_tl(cpu_R[dc->src], cpu_R[dc->src], size); } } } return insn_len; }
static void dec_add(DisasContext *dc) { if (dc->format == OP_FMT_RI) { if (dc->r0 == R_R0) { if (dc->r1 == R_R0 && dc->imm16 == 0) { LOG_DIS("nop\n"); } else { LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16)); } } else { LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16)); } } else { LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); } if (dc->format == OP_FMT_RI) { tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0], sign_extend(dc->imm16, 16)); } else { tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); } }
static unsigned int dec10_reg(DisasContext *dc) { TCGv t; unsigned int insn_len = 2; unsigned int size = dec10_size(dc->size); unsigned int tmp; if (dc->size != 3) { switch (dc->opcode) { case CRISV10_REG_MOVE_R: LOG_DIS("move.%d $r%d, $r%d\n", dc->size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_MOVE, size, 0); if (dc->dst == 15) { tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]); cris_prepare_jmp(dc, JMP_INDIRECT); dc->delayed_branch = 1; } break; case CRISV10_REG_MOVX: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_movs(dc); break; case CRISV10_REG_ADDX: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alux(dc, CC_OP_ADD); break; case CRISV10_REG_SUBX: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alux(dc, CC_OP_SUB); break; case CRISV10_REG_ADD: LOG_DIS("add $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_ADD, size, 0); break; case CRISV10_REG_SUB: LOG_DIS("sub $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_SUB, size, 0); break; case CRISV10_REG_CMP: LOG_DIS("cmp $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_CMP, size, 0); break; case CRISV10_REG_BOUND: LOG_DIS("bound $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_bound(dc, size); break; case CRISV10_REG_AND: LOG_DIS("and $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_AND, size, 0); break; case CRISV10_REG_ADDI: if (dc->src == 15) { /* nop. */ return 2; } t = tcg_temp_new(); LOG_DIS("addi r%d r%d size=%d\n", dc->src, dc->dst, dc->size); tcg_gen_shli_tl(t, cpu_R[dc->dst], dc->size & 3); tcg_gen_add_tl(cpu_R[dc->src], cpu_R[dc->src], t); tcg_temp_free(t); break; case CRISV10_REG_LSL: LOG_DIS("lsl $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_LSL, size, 0); break; case CRISV10_REG_LSR: LOG_DIS("lsr $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_LSR, size, 0); break; case CRISV10_REG_ASR: LOG_DIS("asr $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_ASR, size, 1); break; case CRISV10_REG_OR: LOG_DIS("or $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_OR, size, 0); break; case CRISV10_REG_NEG: LOG_DIS("neg $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_NEG, size, 0); break; case CRISV10_REG_BIAP: LOG_DIS("BIAP pc=%x reg %d r%d r%d size=%d\n", dc->pc, dc->opcode, dc->src, dc->dst, size); switch (size) { case 4: tmp = 2; break; case 2: tmp = 1; break; case 1: tmp = 0; break; default: cpu_abort(dc->env, "Unhandled BIAP"); break; } t = tcg_temp_new(); tcg_gen_shli_tl(t, cpu_R[dc->dst], tmp); if (dc->src == 15) { tcg_gen_addi_tl(cpu_PR[PR_PREFIX], t, ((dc->pc +2)| 1) + 1); } else { tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_R[dc->src], t); } tcg_temp_free(t); cris_set_prefix(dc); break; default: LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc, dc->opcode, dc->src, dc->dst); cpu_abort(dc->env, "Unhandled opcode"); break; } } else { switch (dc->opcode) { case CRISV10_REG_MOVX: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_movs(dc); break; case CRISV10_REG_ADDX: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alux(dc, CC_OP_ADD); break; case CRISV10_REG_SUBX: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alux(dc, CC_OP_SUB); break; case CRISV10_REG_MOVE_SPR_R: cris_evaluate_flags(dc); cris_cc_mask(dc, 0); dec10_reg_mov_pr(dc); break; case CRISV10_REG_MOVE_R_SPR: LOG_DIS("move r%d p%d\n", dc->src, dc->dst); cris_evaluate_flags(dc); if (dc->src != 11) /* fast for srp. */ dc->cpustate_changed = 1; t_gen_mov_preg_TN(dc, dc->dst, cpu_R[dc->src]); break; case CRISV10_REG_SETF: case CRISV10_REG_CLEARF: dec10_setclrf(dc); break; case CRISV10_REG_SWAP: dec10_reg_swap(dc); break; case CRISV10_REG_ABS: cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_abs(dc); break; case CRISV10_REG_LZ: LOG_DIS("lz $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_LZ, 4, 0); break; case CRISV10_REG_XOR: LOG_DIS("xor $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_alu(dc, CC_OP_XOR, 4, 0); break; case CRISV10_REG_BTST: LOG_DIS("btst $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); cris_update_cc_op(dc, CC_OP_FLAGS, 4); gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst], cpu_R[dc->src], cpu_PR[PR_CCS]); break; case CRISV10_REG_DSTEP: LOG_DIS("dstep $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_DSTEP, cpu_R[dc->dst], cpu_R[dc->dst], cpu_R[dc->src], 4); break; case CRISV10_REG_MSTEP: LOG_DIS("mstep $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_MSTEP, cpu_R[dc->dst], cpu_R[dc->dst], cpu_R[dc->src], 4); break; case CRISV10_REG_SCC: dec10_reg_scc(dc); break; default: LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc, dc->opcode, dc->src, dc->dst); cpu_abort(dc->env, "Unhandled opcode"); break; } } return insn_len; }
static unsigned int dec10_quick_imm(DisasContext *dc) { int32_t imm, simm; int op; /* sign extend. */ imm = dc->ir & ((1 << 6) - 1); simm = (int8_t) (imm << 2); simm >>= 2; switch (dc->opcode) { case CRISV10_QIMM_BDAP_R0: case CRISV10_QIMM_BDAP_R1: case CRISV10_QIMM_BDAP_R2: case CRISV10_QIMM_BDAP_R3: simm = (int8_t)dc->ir; LOG_DIS("bdap %d $r%d\n", simm, dc->dst); LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n", dc->pc, dc->mode, dc->opcode, dc->src, dc->dst); cris_set_prefix(dc); if (dc->dst == 15) { tcg_gen_movi_tl(cpu_PR[PR_PREFIX], dc->pc + 2 + simm); } else { tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm); } break; case CRISV10_QIMM_MOVEQ: LOG_DIS("moveq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_CMPQ: LOG_DIS("cmpq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_ADDQ: LOG_DIS("addq %d, $r%d\n", imm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_ADD, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); break; case CRISV10_QIMM_ANDQ: LOG_DIS("andq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_AND, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_ASHQ: LOG_DIS("ashq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); op = imm & (1 << 5); imm &= 0x1f; if (op) { cris_alu(dc, CC_OP_ASR, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); } else { /* BTST */ cris_update_cc_op(dc, CC_OP_FLAGS, 4); gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst], tcg_const_tl(imm), cpu_PR[PR_CCS]); } break; case CRISV10_QIMM_LSHQ: LOG_DIS("lshq %d, $r%d\n", simm, dc->dst); op = CC_OP_LSL; if (imm & (1 << 5)) { op = CC_OP_LSR; } imm &= 0x1f; cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, op, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); break; case CRISV10_QIMM_SUBQ: LOG_DIS("subq %d, $r%d\n", imm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_SUB, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); break; case CRISV10_QIMM_ORQ: LOG_DIS("andq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_OR, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_BCC_R0: case CRISV10_QIMM_BCC_R1: case CRISV10_QIMM_BCC_R2: case CRISV10_QIMM_BCC_R3: imm = dc->ir & 0xff; /* bit 0 is a sign bit. */ if (imm & 1) { imm |= 0xffffff00; /* sign extend. */ imm &= ~1; /* get rid of the sign bit. */ } imm += 2; LOG_DIS("b%s %d\n", cc_name(dc->cond), imm); cris_cc_mask(dc, 0); cris_prepare_cc_branch(dc, imm, dc->cond); break; default: LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n", dc->pc, dc->mode, dc->opcode, dc->src, dc->dst); cpu_abort(dc->env, "Unhandled quickimm\n"); break; } return 2; }