[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 17/33] target/mips: Implement DSP ASE support for
From: |
Aleksandar Markovic |
Subject: |
[Qemu-devel] [PATCH v2 17/33] target/mips: Implement DSP ASE support for nanoMIPS |
Date: |
Mon, 9 Jul 2018 22:50:15 +0200 |
From: Stefan Markovic <address@hidden>
Add emulation of DSP ASE instructions for nanoMIPS.
Signed-off-by: Aleksandar Markovic <address@hidden>
Signed-off-by: Stefan Markovic <address@hidden>
---
target/mips/translate.c | 2242 ++++++++++++++++++++++++++++++++++++++---------
1 file changed, 1838 insertions(+), 404 deletions(-)
diff --git a/target/mips/translate.c b/target/mips/translate.c
index c55d809..564d459 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -14064,6 +14064,527 @@ static void gen_pool32fxf(DisasContext *ctx, int rt,
int rs)
}
}
+
+static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc,
+ int rd, int rs, int rt)
+{
+ int ret = rd;
+
+ TCGv t1;
+ TCGv v1_t;
+ TCGv v2_t;
+
+ t1 = tcg_temp_new();
+ v1_t = tcg_temp_new();
+ v2_t = tcg_temp_new();
+
+ gen_load_gpr(v1_t, rs);
+ gen_load_gpr(v2_t, rt);
+
+ switch (opc) {
+ case OPC_CMP_EQ_PH:
+ check_dsp(ctx);
+ gen_helper_cmp_eq_ph(v1_t, v2_t, cpu_env);
+ break;
+ case OPC_CMP_LT_PH:
+ check_dsp(ctx);
+ gen_helper_cmp_lt_ph(v1_t, v2_t, cpu_env);
+ break;
+ case OPC_CMP_LE_PH:
+ check_dsp(ctx);
+ gen_helper_cmp_le_ph(v1_t, v2_t, cpu_env);
+ break;
+ case OPC_CMPU_EQ_QB:
+ check_dsp(ctx);
+ gen_helper_cmpu_eq_qb(v1_t, v2_t, cpu_env);
+ break;
+ case OPC_CMPU_LT_QB:
+ check_dsp(ctx);
+ gen_helper_cmpu_lt_qb(v1_t, v2_t, cpu_env);
+ break;
+ case OPC_CMPU_LE_QB:
+ check_dsp(ctx);
+ gen_helper_cmpu_le_qb(v1_t, v2_t, cpu_env);
+ break;
+ case OPC_CMPGU_EQ_QB:
+ check_dsp(ctx);
+ gen_helper_cmpgu_eq_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_CMPGU_LT_QB:
+ check_dsp(ctx);
+ gen_helper_cmpgu_lt_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_CMPGU_LE_QB:
+ check_dsp(ctx);
+ gen_helper_cmpgu_le_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_CMPGDU_EQ_QB:
+ check_dspr2(ctx);
+ gen_helper_cmpgu_eq_qb(t1, v1_t, v2_t);
+ tcg_gen_mov_tl(cpu_gpr[ret], t1);
+ tcg_gen_andi_tl(cpu_dspctrl, cpu_dspctrl, 0xF0FFFFFF);
+ tcg_gen_shli_tl(t1, t1, 24);
+ tcg_gen_or_tl(cpu_dspctrl, cpu_dspctrl, t1);
+ break;
+ case OPC_CMPGDU_LT_QB:
+ check_dspr2(ctx);
+ gen_helper_cmpgu_lt_qb(t1, v1_t, v2_t);
+ tcg_gen_mov_tl(cpu_gpr[ret], t1);
+ tcg_gen_andi_tl(cpu_dspctrl, cpu_dspctrl, 0xF0FFFFFF);
+ tcg_gen_shli_tl(t1, t1, 24);
+ tcg_gen_or_tl(cpu_dspctrl, cpu_dspctrl, t1);
+ break;
+ case OPC_CMPGDU_LE_QB:
+ check_dspr2(ctx);
+ gen_helper_cmpgu_le_qb(t1, v1_t, v2_t);
+ tcg_gen_mov_tl(cpu_gpr[ret], t1);
+ tcg_gen_andi_tl(cpu_dspctrl, cpu_dspctrl, 0xF0FFFFFF);
+ tcg_gen_shli_tl(t1, t1, 24);
+ tcg_gen_or_tl(cpu_dspctrl, cpu_dspctrl, t1);
+ break;
+ case OPC_PACKRL_PH:
+ check_dsp(ctx);
+ gen_helper_packrl_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_PICK_QB:
+ check_dsp(ctx);
+ gen_helper_pick_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_PICK_PH:
+ check_dsp(ctx);
+ gen_helper_pick_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_ADDQ_S_W:
+ check_dsp(ctx);
+ gen_helper_addq_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_SUBQ_S_W:
+ check_dsp(ctx);
+ gen_helper_subq_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_ADDSC:
+ check_dsp(ctx);
+ gen_helper_addsc(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_ADDWC:
+ check_dsp(ctx);
+ gen_helper_addwc(cpu_gpr[rd], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_ADDQ_S_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* ADDQ_PH */
+ check_dsp(ctx);
+ gen_helper_addq_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* ADDQ_S_PH */
+ check_dsp(ctx);
+ gen_helper_addq_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_ADDQH_R_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* ADDQH_PH */
+ gen_helper_addqh_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* ADDQH_R_PH */
+ gen_helper_addqh_r_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_ADDQH_R_W:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* ADDQH_W */
+ gen_helper_addqh_w(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* ADDQH_R_W */
+ gen_helper_addqh_r_w(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_ADDU_S_QB:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* ADDU_QB */
+ check_dsp(ctx);
+ gen_helper_addu_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* ADDU_S_QB */
+ check_dsp(ctx);
+ gen_helper_addu_s_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_ADDU_S_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* ADDU_PH */
+ check_dspr2(ctx);
+ gen_helper_addu_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* ADDU_S_PH */
+ check_dspr2(ctx);
+ gen_helper_addu_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_ADDUH_R_QB:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* ADDUH_QB */
+ gen_helper_adduh_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* ADDUH_R_QB */
+ gen_helper_adduh_r_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_SHRAV_R_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SHRAV_PH */
+ check_dsp(ctx);
+ gen_helper_shra_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* SHRAV_R_PH */
+ check_dsp(ctx);
+ gen_helper_shra_r_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_SHRAV_R_QB:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SHRAV_QB */
+ check_dspr2(ctx);
+ gen_helper_shra_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* SHRAV_R_QB */
+ check_dspr2(ctx);
+ gen_helper_shra_r_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_SUBQ_S_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SUBQ_PH */
+ check_dsp(ctx);
+ gen_helper_subq_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* SUBQ_S_PH */
+ check_dsp(ctx);
+ gen_helper_subq_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_SUBQH_R_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SUBQH_PH */
+ gen_helper_subqh_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* SUBQH_R_PH */
+ gen_helper_subqh_r_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_SUBQH_R_W:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SUBQH_W */
+ gen_helper_subqh_w(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* SUBQH_R_W */
+ gen_helper_subqh_r_w(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_SUBU_S_QB:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SUBU_QB */
+ check_dsp(ctx);
+ gen_helper_subu_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* SUBU_S_QB */
+ check_dsp(ctx);
+ gen_helper_subu_s_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_SUBU_S_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SUBU_PH */
+ check_dspr2(ctx);
+ gen_helper_subu_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* SUBU_S_PH */
+ check_dspr2(ctx);
+ gen_helper_subu_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_SUBUH_R_QB:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SUBUH_QB */
+ gen_helper_subuh_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case 1:
+ /* SUBUH_R_QB */
+ gen_helper_subuh_r_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ }
+ break;
+ case OPC_SHLLV_S_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SHLLV_PH */
+ check_dsp(ctx);
+ gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* SHLLV_S_PH */
+ check_dsp(ctx);
+ gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_PRECR_SRA_R_PH_W:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* PRECR_SRA_PH_W */
+ check_dspr2(ctx);
+ {
+ TCGv_i32 sa_t = tcg_const_i32(rd);
+ gen_helper_precr_sra_ph_w(cpu_gpr[rt], sa_t, v1_t,
+ cpu_gpr[rt]);
+ tcg_temp_free_i32(sa_t);
+ }
+ break;
+ case 1:
+ /* PRECR_SRA_R_PH_W */
+ check_dspr2(ctx);
+ {
+ TCGv_i32 sa_t = tcg_const_i32(rd);
+ gen_helper_precr_sra_r_ph_w(cpu_gpr[rt], sa_t, v1_t,
+ cpu_gpr[rt]);
+ tcg_temp_free_i32(sa_t);
+ }
+ break;
+ }
+ break;
+ case OPC_MULEU_S_PH_QBL:
+ check_dsp(ctx);
+ gen_helper_muleu_s_ph_qbl(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MULEU_S_PH_QBR:
+ check_dsp(ctx);
+ gen_helper_muleu_s_ph_qbr(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MULQ_RS_PH:
+ check_dsp(ctx);
+ gen_helper_mulq_rs_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MULQ_S_PH:
+ check_dspr2(ctx);
+ gen_helper_mulq_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MULQ_RS_W:
+ gen_helper_mulq_rs_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MULQ_S_W:
+ gen_helper_mulq_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_APPEND:
+ {
+ TCGv t0;
+
+ t0 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+
+ if (rd != 0) {
+ tcg_gen_deposit_tl(cpu_gpr[rt], t0, cpu_gpr[rt], rd, 32 - rd);
+ }
+ tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]);
+ }
+ break;
+ case OPC_MODSUB:
+ check_dsp(ctx);
+ gen_helper_modsub(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_SHRAV_R_W:
+ check_dsp(ctx);
+ gen_helper_shra_r_w(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_SHRLV_PH:
+ check_dspr2(ctx);
+ gen_helper_shrl_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_SHRLV_QB:
+ check_dsp(ctx);
+ gen_helper_shrl_qb(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_SHLLV_QB:
+ check_dsp(ctx);
+ gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_SHLLV_S_W:
+ check_dsp(ctx);
+ gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_SHILO:
+ {
+ TCGv t0;
+ TCGv t1;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ int16_t imm = (ctx->opcode >> 16) & 0x3F;
+
+ tcg_gen_movi_tl(t0, rd >> 3);
+ tcg_gen_movi_tl(t1, imm);
+
+ gen_helper_shilo(t0, t1, cpu_env);
+ }
+ break;
+ case OPC_MULEQ_S_W_PHL:
+ check_dsp(ctx);
+ gen_helper_muleq_s_w_phl(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MULEQ_S_W_PHR:
+ check_dsp(ctx);
+ gen_helper_muleq_s_w_phr(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_MUL_S_PH:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* MUL_PH */
+ gen_helper_mul_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case 1:
+ /* MUL_S_PH */
+ gen_helper_mul_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_PRECR_QB_PH:
+ check_dspr2(ctx);
+ gen_helper_precr_qb_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_PRECRQ_QB_PH:
+ check_dsp(ctx);
+ gen_helper_precrq_qb_ph(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_PRECRQ_PH_W:
+ check_dsp(ctx);
+ gen_helper_precrq_ph_w(cpu_gpr[ret], v1_t, v2_t);
+ break;
+ case OPC_PRECRQ_RS_PH_W:
+ check_dsp(ctx);
+ gen_helper_precrq_rs_ph_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_PRECRQU_S_QB_PH:
+ check_dsp(ctx);
+ gen_helper_precrqu_s_qb_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+ break;
+ case OPC_SHRA_R_W:
+ {
+ TCGv t0;
+ t0 = tcg_temp_new();
+ tcg_gen_movi_tl(t0, rd);
+
+ check_dsp(ctx);
+ gen_helper_shra_r_w(cpu_gpr[rt], t0, v1_t);
+ break;
+ }
+ case OPC_SHRA_R_PH:
+ {
+ TCGv t0;
+ t0 = tcg_temp_new();
+ tcg_gen_movi_tl(t0, rd >> 1);
+
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case 0:
+ /* SHRA_PH */
+ check_dsp(ctx);
+ gen_helper_shra_ph(cpu_gpr[rt], t0, v1_t);
+ break;
+ case 1:
+ /* SHRA_R_PH */
+ check_dsp(ctx);
+ gen_helper_shra_r_ph(cpu_gpr[rt], t0, v1_t);
+ break;
+ }
+ }
+ break;
+ case OPC_SHLL_S_PH:
+ {
+ TCGv t0;
+ t0 = tcg_temp_new();
+ tcg_gen_movi_tl(t0, rd >> 1);
+
+ switch ((ctx->opcode >> 10) & 0x3) {
+ case 0:
+ /* SHLL_PH */
+ check_dsp(ctx);
+ gen_helper_shll_ph(cpu_gpr[rt], t0, v1_t, cpu_env);
+ break;
+ case 2:
+ /* SHLL_S_PH */
+ check_dsp(ctx);
+ gen_helper_shll_s_ph(cpu_gpr[rt], t0, v1_t, cpu_env);
+ break;
+ }
+ }
+ break;
+ case OPC_SHLL_S_W:
+ {
+ TCGv t0;
+ t0 = tcg_temp_new();
+ tcg_gen_movi_tl(t0, rd);
+
+ check_dsp(ctx);
+ gen_helper_shll_s_w(cpu_gpr[rt], t0, v1_t, cpu_env);
+ break;
+ }
+ break;
+ case OPC_REPL_PH:
+ check_dsp(ctx);
+ {
+ int16_t imm;
+ imm = (ctx->opcode >> 11) & 0x03FF;
+ imm = (int16_t)(imm << 6) >> 6;
+ tcg_gen_movi_tl(cpu_gpr[rt], \
+ (target_long)((int32_t)imm << 16 | \
+ (uint16_t)imm));
+ }
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
+}
+
+
static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
{
int32_t offset;
@@ -16172,10 +16693,154 @@ enum {
/* POOL32Axf instruction pool */
enum {
- NM_POOL32AXF_4 = 0x04,
- NM_POOL32AXF_5 = 0x05,
+ POOL32AXF_1 = 0x01,
+ POOL32AXF_2 = 0x02,
+ POOL32AXF_4 = 0x04,
+ POOL32AXF_5 = 0x05,
+ POOL32AXF_7 = 0x07,
+};
+
+/* POOL32Axf_1 instruction pool */
+enum {
+ POOL32AXF_1_0 = 0x00,
+ POOL32AXF_1_1 = 0x01,
+ POOL32AXF_1_3 = 0x03,
+ POOL32AXF_1_4 = 0x04,
+ POOL32AXF_1_5 = 0x05,
+ POOL32AXF_1_7 = 0x07,
+};
+
+/* POOL32Axf_2 instruction pool */
+enum {
+ POOL32AXF_2_0_7 = 0x00,
+ POOL32AXF_2_8_15 = 0x01,
+ POOL32AXF_2_16_23 = 0x02,
+ POOL32AXF_2_24_31 = 0x03,
+};
+
+/* POOL32Axf_{4, 5} instruction pool */
+enum {
+ /* nanoMIPS DSP instructions */
+ NM_ABSQ_S_QB = 0x00,
+ NM_ABSQ_S_PH = 0x08,
+ NM_ABSQ_S_W = 0x10,
+ NM_PRECEQ_W_PHL = 0x28,
+ NM_PRECEQ_W_PHR = 0x30,
+ NM_PRECEQU_PH_QBL = 0x38,
+ NM_PRECEQU_PH_QBR = 0x48,
+ NM_PRECEU_PH_QBL = 0x58,
+ NM_PRECEU_PH_QBR = 0x68,
+ NM_PRECEQU_PH_QBLA = 0x39,
+ NM_PRECEQU_PH_QBRA = 0x49,
+ NM_PRECEU_PH_QBLA = 0x59,
+ NM_PRECEU_PH_QBRA = 0x69,
+ NM_REPLV_PH = 0x01,
+ NM_REPLV_QB = 0x09,
+ NM_BITREV = 0x18,
+ NM_INSV = 0x20,
+ NM_RADDU_W_QB = 0x78,
+
+ NM_BITSWAP = 0x05,
+ NM_WSBH = 0x3d,
+};
+
+/* POOL32Axf_7 instruction pool */
+enum {
+ NM_SHRA_R_QB = 0x0,
+ NM_SHRL_PH = 0x1,
+ NM_REPL_QB = 0x2,
+};
+
+/* POOL32Axf_1_0 instruction pool */
+enum {
+ NM_MFHI = 0x0,
+ NM_MFLO = 0x1,
+ NM_MTHI = 0x2,
+ NM_MTLO = 0x3,
+};
+
+/* POOL32Axf_1_1 instruction pool */
+enum {
+ NM_MTHLIP = 0x0,
+ NM_SHILOV = 0x1,
+};
+
+/* POOL32Axf_1_3 instruction pool */
+enum {
+ NM_RDDSP = 0x0,
+ NM_WRDSP = 0x1,
+ NM_EXTP = 0x2,
+ NM_EXTPDP = 0x3,
+};
+
+/* POOL32Axf_1_4 instruction pool */
+enum {
+ NM_SHLL_QB = 0x0,
+ NM_SHRL_QB = 0x1,
+};
+
+/* POOL32Axf_1_5 instruction pool */
+enum {
+ NM_MAQ_S_W_PHR = 0x0,
+ NM_MAQ_S_W_PHL = 0x1,
+ NM_MAQ_SA_W_PHR = 0x2,
+ NM_MAQ_SA_W_PHL = 0x3,
+};
+
+/* POOL32Axf_1_7 instruction pool */
+enum {
+ NM_EXTR_W = 0x0,
+ NM_EXTR_R_W = 0x1,
+ NM_EXTR_RS_W = 0x2,
+ NM_EXTR_S_H = 0x3,
+};
+
+/* POOL32Axf_2_0_7 instruction pool */
+enum {
+ NM_DPA_W_PH = 0x0,
+ NM_DPAQ_S_W_PH = 0x1,
+ NM_DPS_W_PH = 0x2,
+ NM_DPSQ_S_W_PH = 0x3,
+ NM_BALIGN = 0x4,
+ NM_MADD = 0x5,
+ NM_MULT = 0x6,
+ NM_EXTRV_W = 0x7,
+};
+
+/* POOL32Axf_2_8_15 instruction pool */
+enum {
+ NM_DPAX_W_PH = 0x0,
+ NM_DPAQ_SA_L_W = 0x1,
+ NM_DPSX_W_PH = 0x2,
+ NM_DPSQ_SA_L_W = 0x3,
+ NM_MADDU = 0x5,
+ NM_MULTU = 0x6,
+ NM_EXTRV_R_W = 0x7,
};
+/* POOL32Axf_2_16_23 instruction pool */
+enum {
+ NM_DPAU_H_QBL = 0x0,
+ NM_DPAQX_S_W_PH = 0x1,
+ NM_DPSU_H_QBL = 0x2,
+ NM_DPSQX_S_W_PH = 0x3,
+ NM_EXTPV = 0x4,
+ NM_MSUB = 0x5,
+ NM_MULSA_W_PH = 0x6,
+ NM_EXTRV_RS_W = 0x7,
+};
+
+/* POOL32Axf_2_24_31 instruction pool */
+enum {
+ NM_DPAU_H_QBR = 0x0,
+ NM_DPAQX_SA_W_PH = 0x1,
+ NM_DPSU_H_QBR = 0x2,
+ NM_DPSQX_SA_W_PH = 0x3,
+ NM_EXTPDPV = 0x4,
+ NM_MSUBU = 0x5,
+ NM_MULSAQ_S_W_PH = 0x6,
+ NM_EXTRV_S_H = 0x7,
+};
/* POOL32Axf_{4, 5} instruction pool */
enum {
NM_CLO = 0x25,
@@ -16223,515 +16888,1260 @@ enum {
NM_OR16 = 0x03,
};
-/* PP.LSX and PP.LSXS instruction pool */
-enum {
- NM_LBX = 0x00,
- NM_LHX = 0x04,
- NM_LWX = 0x08,
- NM_LDX = 0x0c,
+/* PP.LSX and PP.LSXS instruction pool */
+enum {
+ NM_LBX = 0x00,
+ NM_LHX = 0x04,
+ NM_LWX = 0x08,
+ NM_LDX = 0x0c,
+
+ NM_SBX = 0x01,
+ NM_SHX = 0x05,
+ NM_SWX = 0x09,
+ NM_SDX = 0x0d,
+
+ NM_LBUX = 0x02,
+ NM_LHUX = 0x06,
+ NM_LWC1X = 0x0a,
+ NM_LDC1X = 0x0e,
+
+ NM_LWUX = 0x07,
+ NM_SWC1X = 0x0b,
+ NM_SDC1X = 0x0f,
+
+ NM_LHXS = 0x04,
+ NM_LWXS = 0x08,
+ NM_LDXS = 0x0c,
+
+ NM_SHXS = 0x05,
+ NM_SWXS = 0x09,
+ NM_SDXS = 0x0d,
+
+ NM_LHUXS = 0x06,
+ NM_LWC1XS = 0x0a,
+ NM_LDC1XS = 0x0e,
+
+ NM_LWUXS = 0x07,
+ NM_SWC1XS = 0x0b,
+ NM_SDC1XS = 0x0f,
+};
+
+/* ERETx instruction pool */
+enum {
+ NM_ERET = 0x00,
+ NM_ERETNC = 0x01,
+};
+
+/* POOL32FxF_{0, 1} insturction pool */
+enum {
+ NM_CFC1 = 0x40,
+ NM_CTC1 = 0x60,
+ NM_MFC1 = 0x80,
+ NM_MTC1 = 0xa0,
+ NM_MFHC1 = 0xc0,
+ NM_MTHC1 = 0xe0,
+
+ NM_CVT_S_PL = 0x84,
+ NM_CVT_S_PU = 0xa4,
+
+ NM_CVT_L_S = 0x004,
+ NM_CVT_L_D = 0x104,
+ NM_CVT_W_S = 0x024,
+ NM_CVT_W_D = 0x124,
+
+ NM_RSQRT_S = 0x008,
+ NM_RSQRT_D = 0x108,
+
+ NM_SQRT_S = 0x028,
+ NM_SQRT_D = 0x128,
+
+ NM_RECIP_S = 0x048,
+ NM_RECIP_D = 0x148,
+
+ NM_FLOOR_L_S = 0x00c,
+ NM_FLOOR_L_D = 0x10c,
+
+ NM_FLOOR_W_S = 0x02c,
+ NM_FLOOR_W_D = 0x12c,
+
+ NM_CEIL_L_S = 0x04c,
+ NM_CEIL_L_D = 0x14c,
+ NM_CEIL_W_S = 0x06c,
+ NM_CEIL_W_D = 0x16c,
+ NM_TRUNC_L_S = 0x08c,
+ NM_TRUNC_L_D = 0x18c,
+ NM_TRUNC_W_S = 0x0ac,
+ NM_TRUNC_W_D = 0x1ac,
+ NM_ROUND_L_S = 0x0cc,
+ NM_ROUND_L_D = 0x1cc,
+ NM_ROUND_W_S = 0x0ec,
+ NM_ROUND_W_D = 0x1ec,
+
+ NM_MOV_S = 0x01,
+ NM_MOV_D = 0x81,
+ NM_ABS_S = 0x0d,
+ NM_ABS_D = 0x8d,
+ NM_NEG_S = 0x2d,
+ NM_NEG_D = 0xad,
+ NM_CVT_D_S = 0x04d,
+ NM_CVT_D_W = 0x0cd,
+ NM_CVT_D_L = 0x14d,
+ NM_CVT_S_D = 0x06d,
+ NM_CVT_S_W = 0x0ed,
+ NM_CVT_S_L = 0x16d,
+};
+
+/* P.LL instruction pool */
+enum {
+ NM_LL = 0x00,
+ NM_LLWP = 0x01,
+};
+
+/* P.SC instruction pool */
+enum {
+ NM_SC = 0x00,
+ NM_SCWP = 0x01,
+};
+
+/* P.DVP instruction pool */
+enum {
+ NM_DVP = 0x00,
+ NM_EVP = 0x01,
+};
+
+
+/*
+ *
+ * nanoMIPS decoding engine
+ *
+ */
+
+static int decode_gpr_gpr3(int r)
+{
+ static const int map[] = { 16, 17, 18, 19, 4, 5, 6, 7 };
+
+ return map[r & 0x7];
+}
+
+/* Used for 16-bit store instructions. */
+static int decode_gpr_gpr3_src_store(int r)
+{
+ static const int map[] = { 0, 17, 18, 19, 4, 5, 6, 7 };
+
+ return map[r & 0x7];
+}
+
+static int decode_gpr_gpr4(int r)
+{
+ static const int map[] = { 8, 9, 10, 11, 4, 5, 6, 7,
+ 16, 17, 18, 19, 20, 21, 22, 23 };
+
+ return map[r & 0xf];
+}
+
+/* Used for 16-bit store instructions. */
+static int decode_gpr_gpr4_zero(int r)
+{
+ static const int map[] = { 8, 9, 10, 0, 4, 5, 6, 7,
+ 16, 17, 18, 19, 20, 21, 22, 23 };
+
+ return map[r & 0xf];
+}
+
+static void gen_adjust_sp(DisasContext *ctx, int u)
+{
+ TCGv tsp = tcg_temp_new();
+ gen_base_offset_addr(ctx, tsp, 29, u);
+ gen_store_gpr(tsp, 29);
+ tcg_temp_free(tsp);
+}
+
+static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count,
+ uint8_t gp, uint16_t u)
+{
+ int counter = 0;
+ TCGv va = tcg_temp_new();
+ TCGv t0 = tcg_temp_new();
+
+ while (counter != count) {
+ bool use_gp = gp && (counter == count - 1);
+ int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f);
+ int this_offset = -((counter + 1) << 2);
+ gen_base_offset_addr(ctx, va, 29, this_offset);
+ gen_load_gpr(t0, this_rt);
+ tcg_gen_qemu_st_tl(t0, va, ctx->mem_idx,
+ MO_TEUL | ctx->default_tcg_memop_mask);
+ counter++;
+ }
+
+ /* adjust stack pointer */
+ gen_adjust_sp(ctx, -u);
- NM_SBX = 0x01,
- NM_SHX = 0x05,
- NM_SWX = 0x09,
- NM_SDX = 0x0d,
+ tcg_temp_free(t0);
+ tcg_temp_free(va);
+}
- NM_LBUX = 0x02,
- NM_LHUX = 0x06,
- NM_LWC1X = 0x0a,
- NM_LDC1X = 0x0e,
+static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count,
+ uint8_t gp, uint16_t u)
+{
+ int counter = 0;
+ TCGv va = tcg_temp_new();
+ TCGv t0 = tcg_temp_new();
- NM_LWUX = 0x07,
- NM_SWC1X = 0x0b,
- NM_SDC1X = 0x0f,
+ while (counter != count) {
+ bool use_gp = gp && (counter == count - 1);
+ int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f);
+ int this_offset = u - ((counter + 1) << 2);
+ gen_base_offset_addr(ctx, va, 29, this_offset);
+ tcg_gen_qemu_ld_tl(t0, va, ctx->mem_idx, MO_TESL |
+ ctx->default_tcg_memop_mask);
+ tcg_gen_ext32s_tl(t0, t0);
+ gen_store_gpr(t0, this_rt);
+ counter++;
+ }
- NM_LHXS = 0x04,
- NM_LWXS = 0x08,
- NM_LDXS = 0x0c,
+ /* adjust stack pointer */
+ gen_adjust_sp(ctx, u);
- NM_SHXS = 0x05,
- NM_SWXS = 0x09,
- NM_SDXS = 0x0d,
+ tcg_temp_free(t0);
+ tcg_temp_free(va);
+}
- NM_LHUXS = 0x06,
- NM_LWC1XS = 0x0a,
- NM_LDC1XS = 0x0e,
+static void gen_pool16c_nanomips_insn(DisasContext *ctx)
+{
+ int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RD(ctx->opcode));
+ int rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS(ctx->opcode));
- NM_LWUXS = 0x07,
- NM_SWC1XS = 0x0b,
- NM_SDC1XS = 0x0f,
-};
+ switch ((ctx->opcode >> 2) & 0x3) {
+ case NM_NOT16:
+ gen_logic(ctx, OPC_NOR, rt, rs, 0);
+ break;
+ case NM_AND16:
+ gen_logic(ctx, OPC_AND, rt, rt, rs);
+ break;
+ case NM_XOR16:
+ gen_logic(ctx, OPC_XOR, rt, rt, rs);
+ break;
+ case NM_OR16:
+ gen_logic(ctx, OPC_OR, rt, rt, rs);
+ break;
+ }
+}
-/* ERETx instruction pool */
-enum {
- NM_ERET = 0x00,
- NM_ERETNC = 0x01,
-};
+static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx)
+{
+ int rt = (ctx->opcode >> 21) & 0x1f;
+ int rs = (ctx->opcode >> 16) & 0x1f;
+ int rd = (ctx->opcode >> 11) & 0x1f;
-/* POOL32FxF_{0, 1} insturction pool */
-enum {
- NM_CFC1 = 0x40,
- NM_CTC1 = 0x60,
- NM_MFC1 = 0x80,
- NM_MTC1 = 0xa0,
- NM_MFHC1 = 0xc0,
- NM_MTHC1 = 0xe0,
+ switch ((ctx->opcode >> 3) & 0x7f) {
+ case NM_P_TRAP:
+ switch ((ctx->opcode >> 10) & 0x1) {
+ case NM_TEQ:
+ gen_trap(ctx, OPC_TEQ, rs, rt, -1);
+ break;
+ case NM_TNE:
+ gen_trap(ctx, OPC_TNE, rs, rt, -1);
+ break;
+ }
+ break;
+ case NM_RDHWR:
+ gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3));
+ break;
+ case NM_SEB:
+ gen_bshfl(ctx, OPC_SEB, rs, rt);
+ break;
+ case NM_SEH:
+ gen_bshfl(ctx, OPC_SEH, rs, rt);
+ break;
+ case NM_SLLV:
+ gen_shift(ctx, OPC_SLLV, rd, rt, rs);
+ break;
+ case NM_SRLV:
+ gen_shift(ctx, OPC_SRLV, rd, rt, rs);
+ break;
+ case NM_SRAV:
+ gen_shift(ctx, OPC_SRAV, rd, rt, rs);
+ break;
+ case NM_ROTRV:
+ gen_shift(ctx, OPC_ROTRV, rd, rt, rs);
+ break;
+ case NM_ADD:
+ gen_arith(ctx, OPC_ADD, rd, rs, rt);
+ break;
+ case NM_ADDU:
+ gen_arith(ctx, OPC_ADDU, rd, rs, rt);
+ break;
+ case NM_SUB:
+ gen_arith(ctx, OPC_SUB, rd, rs, rt);
+ break;
+ case NM_SUBU:
+ gen_arith(ctx, OPC_SUBU, rd, rs, rt);
+ break;
+ case NM_P_CMOVE:
+ switch ((ctx->opcode >> 10) & 1) {
+ case NM_MOVZ:
+ gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt);
+ break;
+ case NM_MOVN:
+ gen_cond_move(ctx, OPC_MOVN, rd, rs, rt);
+ break;
+ }
+ break;
+ case NM_AND:
+ gen_logic(ctx, OPC_AND, rd, rs, rt);
+ break;
+ case NM_OR:
+ gen_logic(ctx, OPC_OR, rd, rs, rt);
+ break;
+ case NM_NOR:
+ gen_logic(ctx, OPC_NOR, rd, rs, rt);
+ break;
+ case NM_XOR:
+ gen_logic(ctx, OPC_XOR, rd, rs, rt);
+ break;
+ case NM_SLT:
+ gen_slt(ctx, OPC_SLT, rd, rs, rt);
+ break;
+ case NM_P_SLTU:
+ if (rd == 0) {
+ /* P_DVP */
+#ifndef CONFIG_USER_ONLY
+ TCGv t0 = tcg_temp_new();
+ switch ((ctx->opcode >> 10) & 1) {
+ case NM_DVP:
+ if (ctx->vp) {
+ check_cp0_enabled(ctx);
+ gen_helper_dvp(t0, cpu_env);
+ gen_store_gpr(t0, rt);
+ }
+ break;
+ case NM_EVP:
+ if (ctx->vp) {
+ check_cp0_enabled(ctx);
+ gen_helper_evp(t0, cpu_env);
+ gen_store_gpr(t0, rt);
+ }
+ break;
+ }
+ tcg_temp_free(t0);
+#endif
+ } else {
+ gen_slt(ctx, OPC_SLTU, rd, rs, rt);
+ }
+ break;
+ case NM_SOV:
+ {
+ TCGv t0 = tcg_temp_local_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+ TCGLabel *l1 = gen_new_label();
- NM_CVT_S_PL = 0x84,
- NM_CVT_S_PU = 0xa4,
+ gen_load_gpr(t1, rs);
+ gen_load_gpr(t2, rt);
+ tcg_gen_add_tl(t0, t1, t2);
+ tcg_gen_ext32s_tl(t0, t0);
+ tcg_gen_xor_tl(t1, t1, t2);
+ tcg_gen_xor_tl(t2, t0, t2);
+ tcg_gen_andc_tl(t1, t2, t1);
- NM_CVT_L_S = 0x004,
- NM_CVT_L_D = 0x104,
- NM_CVT_W_S = 0x024,
- NM_CVT_W_D = 0x124,
+ tcg_gen_movi_tl(t0, 0);
+ tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+ /* operands of same sign, result different sign */
+
+ tcg_gen_movi_tl(t0, 1);
+ gen_set_label(l1);
+ gen_store_gpr(t0, rd);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ }
+ break;
+ case NM_MUL:
+ gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt);
+ break;
+ case NM_MUH:
+ gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt);
+ break;
+ case NM_MULU:
+ gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt);
+ break;
+ case NM_MUHU:
+ gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt);
+ break;
+ case NM_DIV:
+ gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt);
+ break;
+ case NM_MOD:
+ gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt);
+ break;
+ case NM_DIVU:
+ gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt);
+ break;
+ case NM_MODU:
+ gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt);
+ break;
+#ifndef CONFIG_USER_ONLY
+ case NM_MFC0:
+ check_cp0_enabled(ctx);
+ if (rt == 0) {
+ /* Treat as NOP. */
+ break;
+ }
+ gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7);
+ break;
+ case NM_MTC0:
+ check_cp0_enabled(ctx);
+ {
+ TCGv t0 = tcg_temp_new();
- NM_RSQRT_S = 0x008,
- NM_RSQRT_D = 0x108,
+ gen_load_gpr(t0, rt);
+ gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7);
+ tcg_temp_free(t0);
+ }
+ break;
+ case NM_D_E_MT_VPE:
+ {
+ uint8_t sc = (ctx->opcode >> 10) & 1;
+ TCGv t0 = tcg_temp_new();
- NM_SQRT_S = 0x028,
- NM_SQRT_D = 0x128,
+ switch (sc) {
+ case 0:
+ if (rs == 1) {
+ /* DMT */
+ check_insn(ctx, ASE_MT);
+ gen_helper_dmt(t0);
+ gen_store_gpr(t0, rt);
+ } else if (rs == 0) {
+ /* DVPE */
+ check_insn(ctx, ASE_MT);
+ gen_helper_dvpe(t0, cpu_env);
+ gen_store_gpr(t0, rt);
+ } else {
+ generate_exception_end(ctx, EXCP_RI);
+ }
+ break;
+ case 1:
+ if (rs == 1) {
+ /* EMT */
+ check_insn(ctx, ASE_MT);
+ gen_helper_emt(t0);
+ gen_store_gpr(t0, rt);
+ } else if (rs == 0) {
+ /* EVPE */
+ check_insn(ctx, ASE_MT);
+ gen_helper_evpe(t0, cpu_env);
+ gen_store_gpr(t0, rt);
+ } else {
+ generate_exception_end(ctx, EXCP_RI);
+ }
+ break;
+ }
- NM_RECIP_S = 0x048,
- NM_RECIP_D = 0x148,
+ tcg_temp_free(t0);
+ }
+ break;
+ case NM_FORK:
+ check_insn(ctx, ASE_MT);
+ {
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
- NM_FLOOR_L_S = 0x00c,
- NM_FLOOR_L_D = 0x10c,
+ gen_load_gpr(t0, rt);
+ gen_load_gpr(t1, rs);
+ gen_helper_fork(t0, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ }
+ break;
+ case NM_MFTR:
+ case NM_MFHTR:
+ check_insn(ctx, ASE_MT);
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return;
+ }
+ gen_mftr(env, ctx, rs, rt, (ctx->opcode >> 10) & 1,
+ (ctx->opcode >> 11) & 0x1f, (ctx->opcode >> 3) & 1);
+ break;
+ case NM_MTTR:
+ case NM_MTHTR:
+ check_insn(ctx, ASE_MT);
+ gen_mttr(env, ctx, rs, rt, (ctx->opcode >> 10) & 1,
+ (ctx->opcode >> 11) & 0x1f, (ctx->opcode >> 3) & 1);
+ break;
+ case NM_YIELD:
+ check_insn(ctx, ASE_MT);
+ {
+ TCGv t0 = tcg_temp_new();
- NM_FLOOR_W_S = 0x02c,
- NM_FLOOR_W_D = 0x12c,
+ gen_load_gpr(t0, rs);
+ gen_helper_yield(t0, cpu_env, t0);
+ gen_store_gpr(t0, rt);
+ tcg_temp_free(t0);
+ }
+ break;
+#endif
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
+}
- NM_CEIL_L_S = 0x04c,
- NM_CEIL_L_D = 0x14c,
- NM_CEIL_W_S = 0x06c,
- NM_CEIL_W_D = 0x16c,
- NM_TRUNC_L_S = 0x08c,
- NM_TRUNC_L_D = 0x18c,
- NM_TRUNC_W_S = 0x0ac,
- NM_TRUNC_W_D = 0x1ac,
- NM_ROUND_L_S = 0x0cc,
- NM_ROUND_L_D = 0x1cc,
- NM_ROUND_W_S = 0x0ec,
- NM_ROUND_W_D = 0x1ec,
- NM_MOV_S = 0x01,
- NM_MOV_D = 0x81,
- NM_ABS_S = 0x0d,
- NM_ABS_D = 0x8d,
- NM_NEG_S = 0x2d,
- NM_NEG_D = 0xad,
- NM_CVT_D_S = 0x04d,
- NM_CVT_D_W = 0x0cd,
- NM_CVT_D_L = 0x14d,
- NM_CVT_S_D = 0x06d,
- NM_CVT_S_W = 0x0ed,
- NM_CVT_S_L = 0x16d,
-};
+static void gen_pool32axf_1_5_nanomips_insn(DisasContext *ctx, uint32_t opc,
+ int ret, int v1, int v2)
+{
+ TCGv_i32 t0;
+ TCGv v0_t;
+ TCGv v1_t;
-/* P.LL instruction pool */
-enum {
- NM_LL = 0x00,
- NM_LLWP = 0x01,
-};
+ t0 = tcg_temp_new_i32();
-/* P.SC instruction pool */
-enum {
- NM_SC = 0x00,
- NM_SCWP = 0x01,
-};
+ v0_t = tcg_temp_new();
+ v1_t = tcg_temp_new();
-/* P.DVP instruction pool */
-enum {
- NM_DVP = 0x00,
- NM_EVP = 0x01,
-};
+ tcg_gen_movi_i32(t0, v2 >> 3);
+ gen_load_gpr(v0_t, ret);
+ gen_load_gpr(v1_t, v1);
-/*
- *
- * nanoMIPS decoding engine
- *
- */
+ switch (opc) {
+ case NM_MAQ_S_W_PHR:
+ check_dsp(ctx);
+ gen_helper_maq_s_w_phr(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_MAQ_S_W_PHL:
+ check_dsp(ctx);
+ gen_helper_maq_s_w_phl(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_MAQ_SA_W_PHR:
+ check_dsp(ctx);
+ gen_helper_maq_sa_w_phr(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_MAQ_SA_W_PHL:
+ check_dsp(ctx);
+ gen_helper_maq_sa_w_phl(t0, v1_t, v0_t, cpu_env);
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
-static int decode_gpr_gpr3(int r)
-{
- static const int map[] = { 16, 17, 18, 19, 4, 5, 6, 7 };
+ tcg_temp_free_i32(t0);
- return map[r & 0x7];
+ tcg_temp_free(v0_t);
+ tcg_temp_free(v1_t);
}
-/* Used for 16-bit store instructions. */
-static int decode_gpr_gpr3_src_store(int r)
-{
- static const int map[] = { 0, 17, 18, 19, 4, 5, 6, 7 };
-
- return map[r & 0x7];
-}
-static int decode_gpr_gpr4(int r)
+static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc,
+ int ret, int v1, int v2)
{
- static const int map[] = { 8, 9, 10, 11, 4, 5, 6, 7,
- 16, 17, 18, 19, 20, 21, 22, 23 };
-
- return map[r & 0xf];
-}
+ int16_t imm;
-/* Used for 16-bit store instructions. */
-static int decode_gpr_gpr4_zero(int r)
-{
- static const int map[] = { 8, 9, 10, 0, 4, 5, 6, 7,
- 16, 17, 18, 19, 20, 21, 22, 23 };
+ TCGv t0;
+ TCGv t1;
+ TCGv v0_t;
+ TCGv v1_t;
- return map[r & 0xf];
-}
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
-static void gen_adjust_sp(DisasContext *ctx, int u)
-{
- TCGv tsp = tcg_temp_new();
- gen_base_offset_addr(ctx, tsp, 29, u);
- gen_store_gpr(tsp, 29);
- tcg_temp_free(tsp);
-}
+ v0_t = tcg_temp_new();
+ v1_t = tcg_temp_new();
-static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count,
- uint8_t gp, uint16_t u)
-{
- int counter = 0;
- TCGv va = tcg_temp_new();
- TCGv t0 = tcg_temp_new();
+ gen_load_gpr(v0_t, ret);
+ gen_load_gpr(v1_t, v1);
- while (counter != count) {
- bool use_gp = gp && (counter == count - 1);
- int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f);
- int this_offset = -((counter + 1) << 2);
- gen_base_offset_addr(ctx, va, 29, this_offset);
- gen_load_gpr(t0, this_rt);
- tcg_gen_qemu_st_tl(t0, va, ctx->mem_idx,
- (MO_TEUL | ctx->default_tcg_memop_mask));
- counter++;
+ switch (opc) {
+ case POOL32AXF_1_0:
+ switch ((ctx->opcode >> 12) & 0x03) {
+ case NM_MFHI:
+ gen_HILO(ctx, OPC_MFHI, v2 >> 3, ret);
+ break;
+ case NM_MFLO:
+ gen_HILO(ctx, OPC_MFLO, v2 >> 3, ret);
+ break;
+ case NM_MTHI:
+ gen_HILO(ctx, OPC_MTHI, v2 >> 3, v1);
+ break;
+ case NM_MTLO:
+ gen_HILO(ctx, OPC_MTLO, v2 >> 3, v1);
+ break;
+ }
+ break;
+ case POOL32AXF_1_1:
+ switch ((ctx->opcode >> 12) & 0x03) {
+ case NM_MTHLIP:
+ tcg_gen_movi_tl(t0, v2);
+ gen_helper_mthlip(t0, v1_t, cpu_env);
+ break;
+ case NM_SHILOV:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_shilo(t0, v1_t, cpu_env);
+ break;
+ }
+ break;
+ case POOL32AXF_1_3:
+ imm = (ctx->opcode >> 14) & 0x07F;
+ switch ((ctx->opcode >> 12) & 0x03) {
+ case NM_RDDSP:
+ tcg_gen_movi_tl(t0, imm);
+ gen_helper_rddsp(cpu_gpr[ret], t0, cpu_env);
+ break;
+ case NM_WRDSP:
+ tcg_gen_movi_tl(t0, imm);
+ gen_helper_wrdsp(v0_t, t0, cpu_env);
+ break;
+ case NM_EXTP:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ tcg_gen_movi_tl(t1, v1);
+ gen_helper_extp(cpu_gpr[ret], t0, t1, cpu_env);
+ break;
+ case NM_EXTPDP:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ tcg_gen_movi_tl(t1, v1);
+ gen_helper_extpdp(cpu_gpr[ret], t0, t1, cpu_env);
+ break;
+ }
+ break;
+ case POOL32AXF_1_4:
+ tcg_gen_movi_tl(t0, v2 >> 2);
+ switch ((ctx->opcode >> 12) & 0x01) {
+ case NM_SHLL_QB:
+ check_dsp(ctx);
+ gen_helper_shll_qb(cpu_gpr[ret], t0, v1_t, cpu_env);
+ break;
+ case NM_SHRL_QB:
+ check_dsp(ctx);
+ gen_helper_shrl_qb(cpu_gpr[ret], t0, v1_t);
+ break;
+ }
+ break;
+ case POOL32AXF_1_5:
+ {
+ uint32_t opc = (ctx->opcode >> 12) & 0x03;
+ gen_pool32axf_1_5_nanomips_insn(ctx, opc, ret, v1, v2);
+ }
+ break;
+ case POOL32AXF_1_7:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ tcg_gen_movi_tl(t1, v1);
+ switch ((ctx->opcode >> 12) & 0x03) {
+ case NM_EXTR_W:
+ gen_helper_extr_w(cpu_gpr[ret], t0, t1, cpu_env);
+ break;
+ case NM_EXTR_R_W:
+ gen_helper_extr_r_w(cpu_gpr[ret], t0, t1, cpu_env);
+ break;
+ case NM_EXTR_RS_W:
+ gen_helper_extr_rs_w(cpu_gpr[ret], t0, t1, cpu_env);
+ break;
+ case NM_EXTR_S_H:
+ gen_helper_extr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
+ break;
+ }
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
}
- /* adjust stack pointer */
- gen_adjust_sp(ctx, -u);
-
tcg_temp_free(t0);
- tcg_temp_free(va);
+ tcg_temp_free(t1);
+
+ tcg_temp_free(v0_t);
+ tcg_temp_free(v1_t);
}
-static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count,
- uint8_t gp, uint16_t u)
+static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc,
+ int ret, int v1, int v2)
{
- int counter = 0;
- TCGv va = tcg_temp_new();
- TCGv t0 = tcg_temp_new();
+ TCGv_i32 t0;
+ TCGv v0_t;
+ TCGv v1_t;
- while (counter != count) {
- bool use_gp = gp && (counter == count - 1);
- int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f);
- int this_offset = u - ((counter + 1) << 2);
- gen_base_offset_addr(ctx, va, 29, this_offset);
- tcg_gen_qemu_ld_tl(t0, va, ctx->mem_idx, MO_TESL |
- ctx->default_tcg_memop_mask);
- tcg_gen_ext32s_tl(t0, t0);
- gen_store_gpr(t0, this_rt);
- counter++;
- }
+ t0 = tcg_temp_new_i32();
- /* adjust stack pointer */
- gen_adjust_sp(ctx, u);
+ v0_t = tcg_temp_new();
+ v1_t = tcg_temp_new();
- tcg_temp_free(t0);
- tcg_temp_free(va);
-}
+ tcg_gen_movi_i32(t0, v2 >> 3);
-static void gen_pool16c_nanomips_insn(DisasContext *ctx)
-{
- int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RD(ctx->opcode));
- int rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS(ctx->opcode));
+ gen_load_gpr(v0_t, ret);
+ gen_load_gpr(v1_t, v1);
- switch ((ctx->opcode >> 2) & 0x3) {
- case NM_NOT16:
- gen_logic(ctx, OPC_NOR, rt, rs, 0);
+ switch (opc) {
+ case POOL32AXF_2_0_7:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPA_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpa_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_DPAQ_S_W_PH:
+ check_dsp(ctx);
+ gen_helper_dpaq_s_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_DPS_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dps_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_DPSQ_S_W_PH:
+ check_dsp(ctx);
+ gen_helper_dpsq_s_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
break;
- case NM_AND16:
- gen_logic(ctx, OPC_AND, rt, rt, rs);
+ case POOL32AXF_2_8_15:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPAX_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpax_w_ph(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_DPAQ_SA_L_W:
+ check_dsp(ctx);
+ gen_helper_dpaq_sa_l_w(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_DPSX_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpsx_w_ph(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_DPSQ_SA_L_W:
+ check_dsp(ctx);
+ gen_helper_dpsq_sa_l_w(t0, v0_t, v1_t, cpu_env);
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
break;
- case NM_XOR16:
- gen_logic(ctx, OPC_XOR, rt, rt, rs);
+ case POOL32AXF_2_16_23:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPAU_H_QBL:
+ check_dsp(ctx);
+ gen_helper_dpau_h_qbl(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_DPAQX_S_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpaqx_s_w_ph(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_DPSU_H_QBL:
+ check_dsp(ctx);
+ gen_helper_dpsu_h_qbl(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_DPSQX_S_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpsqx_s_w_ph(t0, v0_t, v1_t, cpu_env);
+ break;
+ case NM_MULSA_W_PH:
+ check_dspr2(ctx);
+ gen_helper_mulsa_w_ph(t0, v0_t, v1_t, cpu_env);
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
break;
- case NM_OR16:
- gen_logic(ctx, OPC_OR, rt, rt, rs);
+ case POOL32AXF_2_24_31:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPAU_H_QBR:
+ check_dsp(ctx);
+ gen_helper_dpau_h_qbr(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_DPAQX_SA_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpaqx_sa_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_DPSU_H_QBR:
+ check_dsp(ctx);
+ gen_helper_dpsu_h_qbr(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_DPSQX_SA_W_PH:
+ check_dspr2(ctx);
+ gen_helper_dpsqx_sa_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ case NM_MULSAQ_S_W_PH:
+ check_dsp(ctx);
+ gen_helper_mulsaq_s_w_ph(t0, v1_t, v0_t, cpu_env);
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
break;
}
+
+ tcg_temp_free_i32(t0);
+
+ tcg_temp_free(v0_t);
+ tcg_temp_free(v1_t);
}
-static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx)
+static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
+ int ret, int v1, int v2)
{
- int rt = (ctx->opcode >> 21) & 0x1f;
- int rs = (ctx->opcode >> 16) & 0x1f;
- int rd = (ctx->opcode >> 11) & 0x1f;
+ TCGv t0;
+ TCGv t1;
- switch ((ctx->opcode >> 3) & 0x7f) {
- case NM_P_TRAP:
- switch ((ctx->opcode >> 10) & 0x1) {
- case NM_TEQ:
- gen_trap(ctx, OPC_TEQ, rs, rt, -1);
+ TCGv v0_t;
+ TCGv v1_t;
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ v0_t = tcg_temp_new();
+ v1_t = tcg_temp_new();
+
+ gen_load_gpr(v0_t, ret);
+ gen_load_gpr(v1_t, v1);
+
+ switch (opc) {
+ case POOL32AXF_2_0_7:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPA_W_PH:
+ case NM_DPAQ_S_W_PH:
+ case NM_DPS_W_PH:
+ case NM_DPSQ_S_W_PH:
+ gen_pool32axf_2_multiply(ctx, opc, ret, v1, v2);
+ break;
+ case NM_BALIGN:
+ gen_load_gpr(t0, v1);
+ v2 &= 3;
+ if (v2 != 0 && v2 != 2) {
+ tcg_gen_shli_tl(cpu_gpr[ret], cpu_gpr[ret], 8 * v2);
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_shri_tl(t0, t0, 8 * (4 - v2));
+ tcg_gen_or_tl(cpu_gpr[ret], cpu_gpr[ret], t0);
+ }
+ tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]);
break;
- case NM_TNE:
- gen_trap(ctx, OPC_TNE, rs, rt, -1);
+ case NM_MADD:
+ {
+ int acc = (ctx->opcode >> 14) & 3;
+
+ gen_load_gpr(t0, ret);
+ gen_load_gpr(t1, v1);
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+
+ tcg_gen_ext_tl_i64(t2, t0);
+ tcg_gen_ext_tl_i64(t3, t1);
+ tcg_gen_mul_i64(t2, t2, t3);
+ tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+ tcg_gen_add_i64(t2, t2, t3);
+ tcg_temp_free_i64(t3);
+ gen_move_low32(cpu_LO[acc], t2);
+ gen_move_high32(cpu_HI[acc], t2);
+ tcg_temp_free_i64(t2);
+ }
break;
- }
- break;
- case NM_RDHWR:
- gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3));
- break;
- case NM_SEB:
- gen_bshfl(ctx, OPC_SEB, rs, rt);
- break;
- case NM_SEH:
- gen_bshfl(ctx, OPC_SEH, rs, rt);
- break;
- case NM_SLLV:
- gen_shift(ctx, OPC_SLLV, rd, rt, rs);
- break;
- case NM_SRLV:
- gen_shift(ctx, OPC_SRLV, rd, rt, rs);
- break;
- case NM_SRAV:
- gen_shift(ctx, OPC_SRAV, rd, rt, rs);
- break;
- case NM_ROTRV:
- gen_shift(ctx, OPC_ROTRV, rd, rt, rs);
- break;
- case NM_ADD:
- gen_arith(ctx, OPC_ADD, rd, rs, rt);
- break;
- case NM_ADDU:
- gen_arith(ctx, OPC_ADDU, rd, rs, rt);
- break;
- case NM_SUB:
- gen_arith(ctx, OPC_SUB, rd, rs, rt);
+ case NM_MULT:
+ {
+ int acc = (ctx->opcode >> 14) & 3;
+
+ gen_load_gpr(t0, v1);
+ gen_load_gpr(t1, ret);
+
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_muls2_i32(t2, t3, t2, t3);
+ tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+ tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ }
break;
- case NM_SUBU:
- gen_arith(ctx, OPC_SUBU, rd, rs, rt);
+ case NM_EXTRV_W:
+ gen_load_gpr(v1_t, v1);
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_extr_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+ break;
+ }
break;
- case NM_P_CMOVE:
- switch ((ctx->opcode >> 10) & 1) {
- case NM_MOVZ:
- gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt);
+ case POOL32AXF_2_8_15:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPAX_W_PH:
+ case NM_DPAQ_SA_L_W:
+ case NM_DPSX_W_PH:
+ case NM_DPSQ_SA_L_W:
+ gen_pool32axf_2_multiply(ctx, opc, ret, v1, v2);
break;
- case NM_MOVN:
- gen_cond_move(ctx, OPC_MOVN, rd, rs, rt);
+ case NM_MADDU:
+ {
+ int acc = (ctx->opcode >> 14) & 3;
+
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+
+ gen_load_gpr(t0, v1);
+ gen_load_gpr(t1, ret);
+
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_ext32u_tl(t1, t1);
+ tcg_gen_extu_tl_i64(t2, t0);
+ tcg_gen_extu_tl_i64(t3, t1);
+ tcg_gen_mul_i64(t2, t2, t3);
+ tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+ tcg_gen_add_i64(t2, t2, t3);
+ tcg_temp_free_i64(t3);
+ gen_move_low32(cpu_LO[acc], t2);
+ gen_move_high32(cpu_HI[acc], t2);
+ tcg_temp_free_i64(t2);
+ }
+ break;
+ case NM_MULTU:
+ {
+ int acc = (ctx->opcode >> 14) & 3;
+
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+
+ gen_load_gpr(t0, v1);
+ gen_load_gpr(t1, ret);
+
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_mulu2_i32(t2, t3, t2, t3);
+ tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+ tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ }
+ break;
+ case NM_EXTRV_R_W:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_extr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env);
break;
}
break;
- case NM_AND:
- gen_logic(ctx, OPC_AND, rd, rs, rt);
- break;
- case NM_OR:
- gen_logic(ctx, OPC_OR, rd, rs, rt);
- break;
- case NM_NOR:
- gen_logic(ctx, OPC_NOR, rd, rs, rt);
- break;
- case NM_XOR:
- gen_logic(ctx, OPC_XOR, rd, rs, rt);
- break;
- case NM_SLT:
- gen_slt(ctx, OPC_SLT, rd, rs, rt);
- break;
- case NM_P_SLTU:
- if (rd == 0) {
- /* P_DVP */
-#ifndef CONFIG_USER_ONLY
- TCGv t0 = tcg_temp_new();
- switch ((ctx->opcode >> 10) & 1) {
- case NM_DVP:
- if (ctx->vp) {
- check_cp0_enabled(ctx);
- gen_helper_dvp(t0, cpu_env);
- gen_store_gpr(t0, rt);
- }
- break;
- case NM_EVP:
- if (ctx->vp) {
- check_cp0_enabled(ctx);
- gen_helper_evp(t0, cpu_env);
- gen_store_gpr(t0, rt);
- }
- break;
+ case POOL32AXF_2_16_23:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPAU_H_QBL:
+ case NM_DPAQX_S_W_PH:
+ case NM_DPSU_H_QBL:
+ case NM_DPSQX_S_W_PH:
+ case NM_MULSA_W_PH:
+ gen_pool32axf_2_multiply(ctx, opc, ret, v1, v2);
+ break;
+ case NM_EXTPV:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_extp(cpu_gpr[ret], t0, v1_t, cpu_env);
+ break;
+ case NM_MSUB:
+ {
+ int acc = (ctx->opcode >> 14) & 3;
+
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+
+ gen_load_gpr(t0, v1);
+ gen_load_gpr(t1, ret);
+
+ tcg_gen_ext_tl_i64(t2, t0);
+ tcg_gen_ext_tl_i64(t3, t1);
+ tcg_gen_mul_i64(t2, t2, t3);
+ tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+ tcg_gen_sub_i64(t2, t3, t2);
+ tcg_temp_free_i64(t3);
+ gen_move_low32(cpu_LO[acc], t2);
+ gen_move_high32(cpu_HI[acc], t2);
+ tcg_temp_free_i64(t2);
+ }
+ break;
+ case NM_EXTRV_RS_W:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_extr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+ break;
+ }
+ break;
+ case POOL32AXF_2_24_31:
+ switch ((ctx->opcode >> 9) & 0x07) {
+ case NM_DPAU_H_QBR:
+ case NM_DPAQX_SA_W_PH:
+ case NM_DPSU_H_QBR:
+ case NM_DPSQX_SA_W_PH:
+ case NM_MULSAQ_S_W_PH:
+ gen_pool32axf_2_multiply(ctx, opc, ret, v1, v2);
+ break;
+ case NM_EXTPDPV:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_extpdp(cpu_gpr[ret], t0, v1_t, cpu_env);
+ break;
+ case NM_MSUBU:
+ {
+ int acc = (ctx->opcode >> 14) & 3;
+
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+
+ gen_load_gpr(t0, v1);
+ gen_load_gpr(t1, ret);
+
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_ext32u_tl(t1, t1);
+ tcg_gen_extu_tl_i64(t2, t0);
+ tcg_gen_extu_tl_i64(t3, t1);
+ tcg_gen_mul_i64(t2, t2, t3);
+ tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+ tcg_gen_sub_i64(t2, t3, t2);
+ tcg_temp_free_i64(t3);
+ gen_move_low32(cpu_LO[acc], t2);
+ gen_move_high32(cpu_HI[acc], t2);
+ tcg_temp_free_i64(t2);
}
- tcg_temp_free(t0);
-#endif
- } else {
- gen_slt(ctx, OPC_SLTU, rd, rs, rt);
+ break;
+ case NM_EXTRV_S_H:
+ tcg_gen_movi_tl(t0, v2 >> 3);
+ gen_helper_extr_s_h(cpu_gpr[ret], t0, v1_t, cpu_env);
+ break;
}
break;
- case NM_SOV:
- {
- TCGv t0 = tcg_temp_local_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- TCGLabel *l1 = gen_new_label();
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
- gen_load_gpr(t1, rs);
- gen_load_gpr(t2, rt);
- tcg_gen_add_tl(t0, t1, t2);
- tcg_gen_ext32s_tl(t0, t0);
- tcg_gen_xor_tl(t1, t1, t2);
- tcg_gen_xor_tl(t2, t0, t2);
- tcg_gen_andc_tl(t1, t2, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
- tcg_gen_movi_tl(t0, 0);
- tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
- /* operands of same sign, result different sign */
+ tcg_temp_free(v0_t);
+ tcg_temp_free(v1_t);
+}
- tcg_gen_movi_tl(t0, 1);
- gen_set_label(l1);
- gen_store_gpr(t0, rd);
+static void gen_pool32axf_4_nanomips_insn(DisasContext *ctx, uint32_t opc,
+ int ret, int v1, int v2)
+{
+ TCGv t0;
+ TCGv v0_t;
+ TCGv v1_t;
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- }
+ t0 = tcg_temp_new();
+
+ v0_t = tcg_temp_new();
+ v1_t = tcg_temp_new();
+
+ gen_load_gpr(v0_t, ret);
+ gen_load_gpr(v1_t, v1);
+
+ switch (opc) {
+ case NM_ABSQ_S_QB:
+ check_dspr2(ctx);
+ gen_helper_absq_s_qb(cpu_gpr[ret], v0_t, cpu_env);
break;
- case NM_MUL:
- gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt);
+ case NM_ABSQ_S_PH:
+ check_dsp(ctx);
+ gen_helper_absq_s_ph(cpu_gpr[ret], v1_t, cpu_env);
break;
- case NM_MUH:
- gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt);
+ case NM_ABSQ_S_W:
+ check_dsp(ctx);
+ gen_helper_absq_s_w(cpu_gpr[ret], v1_t, cpu_env);
break;
- case NM_MULU:
- gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt);
+ case NM_PRECEQ_W_PHL:
+ check_dsp(ctx);
+ tcg_gen_andi_tl(cpu_gpr[ret], v1_t, 0xFFFF0000);
+ tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]);
break;
- case NM_MUHU:
- gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt);
+ case NM_PRECEQ_W_PHR:
+ check_dsp(ctx);
+ tcg_gen_andi_tl(cpu_gpr[ret], v1_t, 0x0000FFFF);
+ tcg_gen_shli_tl(cpu_gpr[ret], cpu_gpr[ret], 16);
+ tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]);
break;
- case NM_DIV:
- gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt);
+ case NM_PRECEQU_PH_QBL:
+ check_dsp(ctx);
+ gen_helper_precequ_ph_qbl(cpu_gpr[ret], v1_t);
break;
- case NM_MOD:
- gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt);
+ case NM_PRECEQU_PH_QBR:
+ check_dsp(ctx);
+ gen_helper_precequ_ph_qbr(cpu_gpr[ret], v1_t);
break;
- case NM_DIVU:
- gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt);
+ case NM_PRECEQU_PH_QBLA:
+ check_dsp(ctx);
+ gen_helper_precequ_ph_qbla(cpu_gpr[ret], v1_t);
break;
- case NM_MODU:
- gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt);
+ case NM_PRECEQU_PH_QBRA:
+ check_dsp(ctx);
+ gen_helper_precequ_ph_qbra(cpu_gpr[ret], v1_t);
break;
-#ifndef CONFIG_USER_ONLY
- case NM_MFC0:
- check_cp0_enabled(ctx);
- if (rt == 0) {
- /* Treat as NOP. */
- break;
- }
- gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7);
+ case NM_PRECEU_PH_QBL:
+ check_dsp(ctx);
+ gen_helper_preceu_ph_qbl(cpu_gpr[ret], v1_t);
break;
- case NM_MTC0:
- check_cp0_enabled(ctx);
+ case NM_PRECEU_PH_QBR:
+ check_dsp(ctx);
+ gen_helper_preceu_ph_qbr(cpu_gpr[ret], v1_t);
+ break;
+ case NM_PRECEU_PH_QBLA:
+ check_dsp(ctx);
+ gen_helper_preceu_ph_qbla(cpu_gpr[ret], v1_t);
+ break;
+ case NM_PRECEU_PH_QBRA:
+ check_dsp(ctx);
+ gen_helper_preceu_ph_qbra(cpu_gpr[ret], v1_t);
+ break;
+ case NM_REPLV_PH:
+ check_dsp(ctx);
+ tcg_gen_ext16u_tl(cpu_gpr[ret], v1_t);
+ tcg_gen_shli_tl(t0, cpu_gpr[ret], 16);
+ tcg_gen_or_tl(cpu_gpr[ret], cpu_gpr[ret], t0);
+ tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]);
+ break;
+ case NM_REPLV_QB:
+ check_dsp(ctx);
{
- TCGv t0 = tcg_temp_new();
+ TCGv val_t;
- gen_load_gpr(t0, rt);
- gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7);
- tcg_temp_free(t0);
+ val_t = tcg_temp_new();
+ gen_load_gpr(val_t, v1);
+
+ tcg_gen_ext8u_tl(cpu_gpr[ret], val_t);
+ tcg_gen_shli_tl(t0, cpu_gpr[ret], 8);
+ tcg_gen_or_tl(cpu_gpr[ret], cpu_gpr[ret], t0);
+ tcg_gen_shli_tl(t0, cpu_gpr[ret], 16);
+ tcg_gen_or_tl(cpu_gpr[ret], cpu_gpr[ret], t0);
+ tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]);
}
break;
- case NM_D_E_MT_VPE:
+ case NM_BITREV:
+ check_dsp(ctx);
+ gen_helper_bitrev(cpu_gpr[ret], v1_t);
+ break;
+ case NM_INSV:
+ check_dsp(ctx);
{
- uint8_t sc = (ctx->opcode >> 10) & 1;
- TCGv t0 = tcg_temp_new();
+ TCGv t0, t1;
- switch (sc) {
- case 0:
- if (rs == 1) {
- /* DMT */
- check_insn(ctx, ASE_MT);
- gen_helper_dmt(t0);
- gen_store_gpr(t0, rt);
- } else if (rs == 0) {
- /* DVPE */
- check_insn(ctx, ASE_MT);
- gen_helper_dvpe(t0, cpu_env);
- gen_store_gpr(t0, rt);
- } else {
- generate_exception_end(ctx, EXCP_RI);
- }
- break;
- case 1:
- if (rs == 1) {
- /* EMT */
- check_insn(ctx, ASE_MT);
- gen_helper_emt(t0);
- gen_store_gpr(t0, rt);
- } else if (rs == 0) {
- /* EVPE */
- check_insn(ctx, ASE_MT);
- gen_helper_evpe(t0, cpu_env);
- gen_store_gpr(t0, rt);
- } else {
- generate_exception_end(ctx, EXCP_RI);
- }
- break;
- }
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
- tcg_temp_free(t0);
- }
- break;
- case NM_FORK:
- check_insn(ctx, ASE_MT);
- {
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
+ gen_load_gpr(t0, ret);
+ gen_load_gpr(t1, v1);
+
+ gen_helper_insv(cpu_gpr[ret], cpu_env, t1, t0);
- gen_load_gpr(t0, rt);
- gen_load_gpr(t1, rs);
- gen_helper_fork(t0, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
+ break;
}
+ case NM_RADDU_W_QB:
+ check_dsp(ctx);
+ gen_helper_raddu_w_qb(cpu_gpr[ret], v1_t);
break;
- case NM_MFTR:
- case NM_MFHTR:
- check_insn(ctx, ASE_MT);
- if (rd == 0) {
- /* Treat as NOP. */
- return;
- }
- gen_mftr(env, ctx, rs, rt, (ctx->opcode >> 10) & 1,
- (ctx->opcode >> 11) & 0x1f, (ctx->opcode >> 3) & 1);
+ case NM_BITSWAP:
+ gen_bitswap(ctx, OPC_BITSWAP, ret, v1);
break;
- case NM_MTTR:
- case NM_MTHTR:
- check_insn(ctx, ASE_MT);
- gen_mttr(env, ctx, rs, rt, (ctx->opcode >> 10) & 1,
- (ctx->opcode >> 11) & 0x1f, (ctx->opcode >> 3) & 1);
+ case NM_CLO:
+ gen_cl(ctx, OPC_CLO, ret, v1);
break;
- case NM_YIELD:
- check_insn(ctx, ASE_MT);
- {
- TCGv t0 = tcg_temp_new();
+ case NM_CLZ:
+ gen_cl(ctx, OPC_CLZ, ret, v1);
+ break;
+ case NM_WSBH:
+ gen_bshfl(ctx, OPC_WSBH, ret, v1);
+ break;
+ default:
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ }
- gen_load_gpr(t0, rs);
- gen_helper_yield(t0, cpu_env, t0);
- gen_store_gpr(t0, rt);
- tcg_temp_free(t0);
+ tcg_temp_free(t0);
+
+ tcg_temp_free(v0_t);
+ tcg_temp_free(v1_t);
+}
+
+static void gen_pool32axf_7_nanomips_insn(DisasContext *ctx, uint32_t opc,
+ int ret, int v1, int v2)
+{
+ int16_t imm;
+
+ TCGv t0;
+ TCGv v1_t;
+
+ t0 = tcg_temp_new();
+ v1_t = tcg_temp_new();
+
+ gen_load_gpr(v1_t, v1);
+
+ switch (opc) {
+ case NM_SHRA_R_QB:
+ tcg_gen_movi_tl(t0, v2 >> 2);
+ switch ((ctx->opcode >> 12) & 0x01) {
+ case 0:
+ /* NM_SHRA_QB */
+ check_dspr2(ctx);
+ gen_helper_shra_qb(cpu_gpr[ret], t0, v1_t);
+ break;
+ case 1:
+ /* NM_SHRA_R_QB */
+ check_dspr2(ctx);
+ gen_helper_shra_r_qb(cpu_gpr[ret], t0, v1_t);
+ break;
}
+ break;
+ case NM_SHRL_PH:
+ check_dspr2(ctx);
+ tcg_gen_movi_tl(t0, v2 >> 1);
+ gen_helper_shrl_ph(cpu_gpr[ret], t0, v1_t);
break;
-#endif
+ case NM_REPL_QB:
+ {
+ check_dsp(ctx);
+ target_long result;
+ imm = (ctx->opcode >> 13) & 0xFF;
+ result = (uint32_t)imm << 24 |
+ (uint32_t)imm << 16 |
+ (uint32_t)imm << 8 |
+ (uint32_t)imm;
+ result = (int32_t)result;
+ tcg_gen_movi_tl(cpu_gpr[ret], result);
+ }
+ break;
default:
generate_exception_end(ctx, EXCP_RI);
break;
- }
+ }
+ tcg_temp_free(t0);
+ tcg_temp_free(v1_t);
}
+
static void gen_pool32axf_nanomips_insn(CPUMIPSState *env, DisasContext *ctx)
{
int rt = (ctx->opcode >> 21) & 0x1f;
int rs = (ctx->opcode >> 16) & 0x1f;
+ int rd = (ctx->opcode >> 11) & 0x1f;
switch ((ctx->opcode >> 6) & 0x07) {
- case NM_POOL32AXF_4:
- case NM_POOL32AXF_5:
+ case POOL32AXF_1:
+ {
+ int32_t op1 = (ctx->opcode >> 9) & 0x07;
+ gen_pool32axf_1_nanomips_insn(ctx, op1, rt, rs, rd);
+ }
+ break;
+ case POOL32AXF_2:
+ {
+ int32_t op1 = (ctx->opcode >> 12) & 0x03;
+ gen_pool32axf_2_nanomips_insn(ctx, op1, rt, rs, rd);
+ }
+ break;
+ case POOL32AXF_4:
+ {
+ int32_t op1 = (ctx->opcode >> 9) & 0x7f;
+ gen_pool32axf_4_nanomips_insn(ctx, op1, rt, rs, rd);
+ }
+ break;
+ case POOL32AXF_5:
switch ((ctx->opcode >> 9) & 0x7f) {
case NM_CLO:
gen_cl(ctx, OPC_CLO, rt, rs);
@@ -16805,6 +18215,12 @@ static void gen_pool32axf_nanomips_insn(CPUMIPSState
*env, DisasContext *ctx)
break;
}
break;
+ case POOL32AXF_7:
+ {
+ int32_t op1 = (ctx->opcode >> 9) & 0x7;
+ gen_pool32axf_7_nanomips_insn(ctx, op1, rt, rs, rd);
+ }
+ break;
default:
generate_exception_end(ctx, EXCP_RI);
break;
@@ -17468,6 +18884,12 @@ static int decode_nanomips_32_48_opc(CPUMIPSState
*env, DisasContext *ctx)
case NM_POOL32A0:
gen_pool32a0_nanomips_insn(env, ctx);
break;
+ case NM_POOL32A5:
+ {
+ int32_t op1 = (ctx->opcode >> 3) & 0x7F;
+ gen_pool32a5_nanomips_insn(ctx, op1, rd, rs, rt);
+ }
+ break;
case NM_POOL32A7:
{
switch ((ctx->opcode >> 3) & 0x07) {
@@ -18108,6 +19530,18 @@ static int decode_nanomips_32_48_opc(CPUMIPSState
*env, DisasContext *ctx)
case NM_BC1NEZC:
gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rt, s, 0);
break;
+ case NM_BPOSGE32C:
+ check_dsp(ctx);
+ {
+ int32_t imm = ctx->opcode;
+ imm >>= 1;
+ imm &= 0x1fff;
+ imm |= (ctx->opcode & 1) << 13;
+
+ gen_compute_branch(ctx, OPC_BPOSGE32, 4, -1, -2,
+ (int32_t)imm, 4);
+ }
+ break;
default:
generate_exception_end(ctx, EXCP_RI);
break;
--
2.7.4
- Re: [Qemu-devel] [PATCH v2 12/33] target/mips: Implement emulation of nanoMIPS ROTX instruction, (continued)
- [Qemu-devel] [PATCH v2 13/33] target/mips: Implement emulation of nanoMIPS EXTW instruction, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 14/33] target/mips: Add emulation of nanoMIPS 32-bit load and store instructions, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 15/33] target/mips: Add emulation of nanoMIPS branch instructions, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 16/33] target/mips: Implement MT ASE support for nanoMIPS, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 18/33] target/mips: Add handling of branch delay slots for nanoMIPS, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 17/33] target/mips: Implement DSP ASE support for nanoMIPS,
Aleksandar Markovic <=
- [Qemu-devel] [PATCH v2 19/33] target/mips: Implement emualtion of nanoMIPS LLWP/SCWP pair, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 20/33] target/mips: Add updating BadInstr and BadInstrP registers for nanoMIPS, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 21/33] target/mips: Add updating CP0 BadInstrX register for nanoMIPs only, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 22/33] target/mips: Adjust behavior of Config3's ISAOnExc bit for nanoMIPS, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 23/33] target/mips: Adjust exception_resume_pc() for nanoMIPS, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 24/33] target/mips: Adjust set_hflags_for_handler() for nanoMIPS, Aleksandar Markovic, 2018/07/09
- [Qemu-devel] [PATCH v2 25/33] target/mips: Adjust set_pc() for nanoMIPS, Aleksandar Markovic, 2018/07/09