mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-25 19:36:50 +00:00
target/mips: Add emulation of nanoMIPS 32-bit load and store instructions
Add emulation of various nanoMIPS load and store instructions. Backports commit 8f1d9b6d63978b80971b15fef16636f454241879 from qemu
This commit is contained in:
parent
bcdee16199
commit
e18c921501
|
@ -18025,10 +18025,287 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
}
|
||||
break;
|
||||
case NM_P_GP_BH:
|
||||
{
|
||||
uint32_t u = extract32(ctx->opcode, 0, 18);
|
||||
|
||||
switch (extract32(ctx->opcode, 18, 3)) {
|
||||
case NM_LBGP:
|
||||
gen_ld(ctx, OPC_LB, rt, 28, u);
|
||||
break;
|
||||
case NM_SBGP:
|
||||
gen_st(ctx, OPC_SB, rt, 28, u);
|
||||
break;
|
||||
case NM_LBUGP:
|
||||
gen_ld(ctx, OPC_LBU, rt, 28, u);
|
||||
break;
|
||||
case NM_ADDIUGP_B:
|
||||
if (rt != 0) {
|
||||
gen_op_addr_addi(ctx, tcg_ctx->cpu_gpr[rt], tcg_ctx->cpu_gpr[28], u);
|
||||
}
|
||||
break;
|
||||
case NM_P_GP_LH:
|
||||
u &= ~1;
|
||||
switch (ctx->opcode & 1) {
|
||||
case NM_LHGP:
|
||||
gen_ld(ctx, OPC_LH, rt, 28, u);
|
||||
break;
|
||||
case NM_LHUGP:
|
||||
gen_ld(ctx, OPC_LHU, rt, 28, u);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_P_GP_SH:
|
||||
u &= ~1;
|
||||
switch (ctx->opcode & 1) {
|
||||
case NM_SHGP:
|
||||
gen_st(ctx, OPC_SH, rt, 28, u);
|
||||
break;
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_P_GP_CP1:
|
||||
u &= ~0x3;
|
||||
switch (ctx->opcode & 0x3) {
|
||||
case NM_LWC1GP:
|
||||
gen_cop1_ldst(ctx, OPC_LWC1, rt, 28, u);
|
||||
break;
|
||||
case NM_LDC1GP:
|
||||
gen_cop1_ldst(ctx, OPC_LDC1, rt, 28, u);
|
||||
break;
|
||||
case NM_SWC1GP:
|
||||
gen_cop1_ldst(ctx, OPC_SWC1, rt, 28, u);
|
||||
break;
|
||||
case NM_SDC1GP:
|
||||
gen_cop1_ldst(ctx, OPC_SDC1, rt, 28, u);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NM_P_LS_U12:
|
||||
{
|
||||
uint32_t u = extract32(ctx->opcode, 0, 12);
|
||||
|
||||
switch (extract32(ctx->opcode, 12, 4)) {
|
||||
case NM_P_PREFU12:
|
||||
if (rt == 31) {
|
||||
/* SYNCI */
|
||||
/* Break the TB to be able to sync copied instructions
|
||||
immediately */
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
} else {
|
||||
/* PREF */
|
||||
/* Treat as NOP. */
|
||||
}
|
||||
break;
|
||||
case NM_LB:
|
||||
gen_ld(ctx, OPC_LB, rt, rs, u);
|
||||
break;
|
||||
case NM_LH:
|
||||
gen_ld(ctx, OPC_LH, rt, rs, u);
|
||||
break;
|
||||
case NM_LW:
|
||||
gen_ld(ctx, OPC_LW, rt, rs, u);
|
||||
break;
|
||||
case NM_LBU:
|
||||
gen_ld(ctx, OPC_LBU, rt, rs, u);
|
||||
break;
|
||||
case NM_LHU:
|
||||
gen_ld(ctx, OPC_LHU, rt, rs, u);
|
||||
break;
|
||||
case NM_SB:
|
||||
gen_st(ctx, OPC_SB, rt, rs, u);
|
||||
break;
|
||||
case NM_SH:
|
||||
gen_st(ctx, OPC_SH, rt, rs, u);
|
||||
break;
|
||||
case NM_SW:
|
||||
gen_st(ctx, OPC_SW, rt, rs, u);
|
||||
break;
|
||||
case NM_LWC1:
|
||||
gen_cop1_ldst(ctx, OPC_LWC1, rt, rs, u);
|
||||
break;
|
||||
case NM_LDC1:
|
||||
gen_cop1_ldst(ctx, OPC_LDC1, rt, rs, u);
|
||||
break;
|
||||
case NM_SWC1:
|
||||
gen_cop1_ldst(ctx, OPC_SWC1, rt, rs, u);
|
||||
break;
|
||||
case NM_SDC1:
|
||||
gen_cop1_ldst(ctx, OPC_SDC1, rt, rs, u);
|
||||
break;
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NM_P_LS_S9:
|
||||
{
|
||||
int32_t s = (sextract32(ctx->opcode, 15, 1) << 8) |
|
||||
extract32(ctx->opcode, 0, 8);
|
||||
|
||||
switch (extract32(ctx->opcode, 8, 3)) {
|
||||
case NM_P_LS_S0:
|
||||
switch (extract32(ctx->opcode, 11, 4)) {
|
||||
case NM_LBS9:
|
||||
gen_ld(ctx, OPC_LB, rt, rs, s);
|
||||
break;
|
||||
case NM_LHS9:
|
||||
gen_ld(ctx, OPC_LH, rt, rs, s);
|
||||
break;
|
||||
case NM_LWS9:
|
||||
gen_ld(ctx, OPC_LW, rt, rs, s);
|
||||
break;
|
||||
case NM_LBUS9:
|
||||
gen_ld(ctx, OPC_LBU, rt, rs, s);
|
||||
break;
|
||||
case NM_LHUS9:
|
||||
gen_ld(ctx, OPC_LHU, rt, rs, s);
|
||||
break;
|
||||
case NM_SBS9:
|
||||
gen_st(ctx, OPC_SB, rt, rs, s);
|
||||
break;
|
||||
case NM_SHS9:
|
||||
gen_st(ctx, OPC_SH, rt, rs, s);
|
||||
break;
|
||||
case NM_SWS9:
|
||||
gen_st(ctx, OPC_SW, rt, rs, s);
|
||||
break;
|
||||
case NM_LWC1S9:
|
||||
gen_cop1_ldst(ctx, OPC_LWC1, rt, rs, s);
|
||||
break;
|
||||
case NM_LDC1S9:
|
||||
gen_cop1_ldst(ctx, OPC_LDC1, rt, rs, s);
|
||||
break;
|
||||
case NM_SWC1S9:
|
||||
gen_cop1_ldst(ctx, OPC_SWC1, rt, rs, s);
|
||||
break;
|
||||
case NM_SDC1S9:
|
||||
gen_cop1_ldst(ctx, OPC_SDC1, rt, rs, s);
|
||||
break;
|
||||
case NM_P_PREFS9:
|
||||
if (rt == 31) {
|
||||
/* SYNCI */
|
||||
/* Break the TB to be able to sync copied instructions
|
||||
immediately */
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
} else {
|
||||
/* PREF */
|
||||
/* Treat as NOP. */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_P_LS_S1:
|
||||
switch (extract32(ctx->opcode, 11, 4)) {
|
||||
case NM_UALH:
|
||||
case NM_UASH:
|
||||
{
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx);
|
||||
TCGv t1 = tcg_temp_new(tcg_ctx);
|
||||
|
||||
gen_base_offset_addr(ctx, t0, rs, s);
|
||||
|
||||
switch (extract32(ctx->opcode, 11, 4)) {
|
||||
case NM_UALH:
|
||||
tcg_gen_qemu_ld_tl(ctx->uc, t0, t0, ctx->mem_idx, MO_TESW |
|
||||
MO_UNALN);
|
||||
gen_store_gpr(tcg_ctx, t0, rt);
|
||||
break;
|
||||
case NM_UASH:
|
||||
gen_load_gpr(ctx, t1, rt);
|
||||
tcg_gen_qemu_st_tl(ctx->uc, t1, t0, ctx->mem_idx, MO_TEUW |
|
||||
MO_UNALN);
|
||||
break;
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
tcg_temp_free(tcg_ctx, t1);
|
||||
}
|
||||
break;
|
||||
case NM_P_LL:
|
||||
switch (ctx->opcode & 0x03) {
|
||||
case NM_LL:
|
||||
gen_ld(ctx, OPC_LL, rt, rs, s);
|
||||
break;
|
||||
case NM_LLWP:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_P_SC:
|
||||
switch (ctx->opcode & 0x03) {
|
||||
case NM_SC:
|
||||
gen_st_cond(ctx, OPC_SC, rt, rs, s);
|
||||
break;
|
||||
case NM_SCWP:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_CACHE:
|
||||
check_cp0_enabled(ctx);
|
||||
if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) {
|
||||
gen_cache_operation(ctx, rt, rs, s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_P_LS_WM:
|
||||
case NM_P_LS_UAWM:
|
||||
{
|
||||
int count = extract32(ctx->opcode, 12, 3);
|
||||
int counter = 0;
|
||||
|
||||
offset = sextract32(ctx->opcode, 15, 1) << 8 |
|
||||
extract32(ctx->opcode, 0, 8);
|
||||
TCGv va = tcg_temp_new(tcg_ctx);
|
||||
TCGv t1 = tcg_temp_new(tcg_ctx);
|
||||
TCGMemOp memop = (extract32(ctx->opcode, 8, 3)) ==
|
||||
NM_P_LS_UAWM ? MO_UNALN : 0;
|
||||
|
||||
count = (count == 0) ? 8 : count;
|
||||
while (counter != count) {
|
||||
int this_rt = ((rt + counter) & 0x1f) | (rt & 0x10);
|
||||
int this_offset = offset + (counter << 2);
|
||||
|
||||
gen_base_offset_addr(ctx, va, rs, this_offset);
|
||||
|
||||
switch (extract32(ctx->opcode, 11, 1)) {
|
||||
case NM_LWM:
|
||||
tcg_gen_qemu_ld_tl(ctx->uc, t1, va, ctx->mem_idx,
|
||||
memop | MO_TESL);
|
||||
gen_store_gpr(tcg_ctx, t1, this_rt);
|
||||
if ((this_rt == rs) &&
|
||||
(counter != (count - 1))) {
|
||||
/* UNPREDICTABLE */
|
||||
}
|
||||
break;
|
||||
case NM_SWM:
|
||||
this_rt = (rt == 0) ? 0 : this_rt;
|
||||
gen_load_gpr(ctx, t1, this_rt);
|
||||
tcg_gen_qemu_st_tl(ctx->uc, t1, va, ctx->mem_idx,
|
||||
memop | MO_TEUL);
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, va);
|
||||
tcg_temp_free(tcg_ctx, t1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NM_MOVE_BALC:
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue