diff options
author | Yongbok Kim <yongbok.kim@mips.com> | 2018-08-02 16:16:13 +0200 |
---|---|---|
committer | Aleksandar Markovic <amarkovic@wavecomp.com> | 2018-08-24 17:51:59 +0200 |
commit | c0280983034627a336248409711e969eb2ea8325 (patch) | |
tree | b2b79906e317b7f21bb299fc568a4f13072f5d70 /target | |
parent | bf0718c59a4b27dd01346a7b5b9a183ed1b18fb7 (diff) |
target/mips: Add emulation of some common nanoMIPS 32-bit instructions
Add emulation of SIGRIE, SYSCALL, BREAK, SDBBP, ADDIU, ADDIUPC,
ADDIUGP.W, LWGP, SWGP, ORI, XORI, ANDI, and other instructions.
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Yongbok Kim <yongbok.kim@mips.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Stefan Markovic <smarkovic@wavecomp.com>
Diffstat (limited to 'target')
-rw-r--r-- | target/mips/translate.c | 268 |
1 files changed, 267 insertions, 1 deletions
diff --git a/target/mips/translate.c b/target/mips/translate.c index cf3254bb4a..cbe3779ee1 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -16859,6 +16859,272 @@ static void gen_pool16c_nanomips_insn(DisasContext *ctx) } } +static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) +{ + uint16_t insn; + uint32_t op; + int rt, rs; + int offset; + int imm; + + insn = cpu_lduw_code(env, ctx->base.pc_next + 2); + ctx->opcode = (ctx->opcode << 16) | insn; + + rt = extract32(ctx->opcode, 21, 5); + rs = extract32(ctx->opcode, 16, 5); + + op = extract32(ctx->opcode, 26, 6); + switch (op) { + case NM_P_ADDIU: + if (rt == 0) { + /* P.RI */ + switch (extract32(ctx->opcode, 19, 2)) { + case NM_SIGRIE: + default: + generate_exception_end(ctx, EXCP_RI); + break; + case NM_P_SYSCALL: + if ((extract32(ctx->opcode, 18, 1)) == NM_SYSCALL) { + generate_exception_end(ctx, EXCP_SYSCALL); + } else { + generate_exception_end(ctx, EXCP_RI); + } + break; + case NM_BREAK: + generate_exception_end(ctx, EXCP_BREAK); + break; + case NM_SDBBP: + if (is_uhi(extract32(ctx->opcode, 0, 19))) { + gen_helper_do_semihosting(cpu_env); + } else { + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception_end(ctx, EXCP_RI); + } else { + generate_exception_end(ctx, EXCP_DBp); + } + } + break; + } + } else { + /* NM_ADDIU */ + imm = extract32(ctx->opcode, 0, 16); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], imm); + } + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + } + break; + case NM_ADDIUPC: + if (rt != 0) { + offset = sextract32(ctx->opcode, 0, 1) << 21 | + extract32(ctx->opcode, 1, 20) << 1; + target_long addr = addr_add(ctx, ctx->base.pc_next + 4, offset); + tcg_gen_movi_tl(cpu_gpr[rt], addr); + } + break; + case NM_POOL32A: + break; + case NM_P_GP_W: + switch (ctx->opcode & 0x03) { + case NM_ADDIUGP_W: + if (rt != 0) { + offset = extract32(ctx->opcode, 0, 21); + gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], offset); + } + break; + case NM_LWGP: + gen_ld(ctx, OPC_LW, rt, 28, extract32(ctx->opcode, 2, 19) << 2); + break; + case NM_SWGP: + gen_st(ctx, OPC_SW, rt, 28, extract32(ctx->opcode, 2, 19) << 2); + break; + default: + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + case NM_P48I: + return 6; + case NM_P_U12: + switch (extract32(ctx->opcode, 12, 4)) { + case NM_ORI: + gen_logic_imm(ctx, OPC_ORI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_XORI: + gen_logic_imm(ctx, OPC_XORI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_ANDI: + gen_logic_imm(ctx, OPC_ANDI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_P_SR: + switch (extract32(ctx->opcode, 20, 1)) { + case NM_PP_SR: + switch (ctx->opcode & 3) { + case NM_SAVE: + gen_save(ctx, rt, extract32(ctx->opcode, 16, 4), + extract32(ctx->opcode, 2, 1), + extract32(ctx->opcode, 3, 9) << 3); + break; + case NM_RESTORE: + case NM_RESTORE_JRC: + gen_restore(ctx, rt, extract32(ctx->opcode, 16, 4), + extract32(ctx->opcode, 2, 1), + extract32(ctx->opcode, 3, 9) << 3); + if ((ctx->opcode & 3) == NM_RESTORE_JRC) { + gen_compute_branch_nm(ctx, OPC_JR, 2, 31, 0, 0); + } + break; + default: + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + case NM_P_SR_F: + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + case NM_SLTI: + gen_slt_imm(ctx, OPC_SLTI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_SLTIU: + gen_slt_imm(ctx, OPC_SLTIU, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_SEQI: + { + TCGv t0 = tcg_temp_new(); + + imm = extract32(ctx->opcode, 0, 12); + gen_load_gpr(t0, rs); + tcg_gen_setcondi_tl(TCG_COND_EQ, t0, t0, imm); + gen_store_gpr(t0, rt); + + tcg_temp_free(t0); + } + break; + case NM_ADDIUNEG: + imm = (int16_t) extract32(ctx->opcode, 0, 12); + gen_arith_imm(ctx, OPC_ADDIU, rt, rs, -imm); + break; + case NM_P_SHIFT: + { + int shift = extract32(ctx->opcode, 0, 5); + switch (extract32(ctx->opcode, 5, 4)) { + case NM_P_SLL: + if (rt == 0 && shift == 0) { + /* NOP */ + } else if (rt == 0 && shift == 3) { + /* EHB - treat as NOP */ + } else if (rt == 0 && shift == 5) { + /* PAUSE - treat as NOP */ + } else if (rt == 0 && shift == 6) { + /* SYNC */ + gen_sync(extract32(ctx->opcode, 16, 5)); + } else { + /* SLL */ + gen_shift_imm(ctx, OPC_SLL, rt, rs, + extract32(ctx->opcode, 0, 5)); + } + break; + case NM_SRL: + gen_shift_imm(ctx, OPC_SRL, rt, rs, + extract32(ctx->opcode, 0, 5)); + break; + case NM_SRA: + gen_shift_imm(ctx, OPC_SRA, rt, rs, + extract32(ctx->opcode, 0, 5)); + break; + case NM_ROTR: + gen_shift_imm(ctx, OPC_ROTR, rt, rs, + extract32(ctx->opcode, 0, 5)); + break; + } + } + break; + case NM_P_ROTX: + break; + case NM_P_INS: + switch (((ctx->opcode >> 10) & 2) | + (extract32(ctx->opcode, 5, 1))) { + case NM_INS: + gen_bitops(ctx, OPC_INS, rt, rs, extract32(ctx->opcode, 0, 5), + extract32(ctx->opcode, 6, 5)); + break; + default: + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + case NM_P_EXT: + switch (((ctx->opcode >> 10) & 2) | + (extract32(ctx->opcode, 5, 1))) { + case NM_EXT: + gen_bitops(ctx, OPC_EXT, rt, rs, extract32(ctx->opcode, 0, 5), + extract32(ctx->opcode, 6, 5)); + break; + default: + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + default: + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + case NM_POOL32F: + break; + case NM_POOL32S: + break; + case NM_P_LUI: + switch (extract32(ctx->opcode, 1, 1)) { + case NM_LUI: + if (rt != 0) { + tcg_gen_movi_tl(cpu_gpr[rt], + sextract32(ctx->opcode, 0, 1) << 31 | + extract32(ctx->opcode, 2, 10) << 21 | + extract32(ctx->opcode, 12, 9) << 12); + } + break; + case NM_ALUIPC: + if (rt != 0) { + offset = sextract32(ctx->opcode, 0, 1) << 31 | + extract32(ctx->opcode, 2, 10) << 21 | + extract32(ctx->opcode, 12, 9) << 12; + target_long addr; + addr = ~0xFFF & addr_add(ctx, ctx->base.pc_next + 4, offset); + tcg_gen_movi_tl(cpu_gpr[rt], addr); + } + break; + } + break; + case NM_P_GP_BH: + break; + case NM_P_LS_U12: + break; + case NM_P_LS_S9: + break; + case NM_MOVE_BALC: + break; + case NM_P_BAL: + break; + case NM_P_J: + break; + case NM_P_BR1: + break; + case NM_P_BR2: + break; + case NM_P_BRI: + break; + default: + generate_exception_end(ctx, EXCP_RI); + break; + } + return 4; +} + static int decode_nanomips_opc(CPUMIPSState *env, DisasContext *ctx) { uint32_t op; @@ -17176,7 +17442,7 @@ static int decode_nanomips_opc(CPUMIPSState *env, DisasContext *ctx) case NM_MOVEPREV: break; default: - break; + return decode_nanomips_32_48_opc(env, ctx); } return 2; |