target/mips: Add emulation of nanoMIPS 32-bit load and store instructions

Add emulation of various nanoMIPS load and store instructions.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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>
This commit is contained in:
Yongbok Kim 2018-08-02 16:16:22 +02:00 committed by Aleksandar Markovic
parent 821f2008c3
commit 8f1d9b6d63
1 changed files with 277 additions and 0 deletions

View File

@ -17905,10 +17905,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, cpu_gpr[rt], 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();
TCGv t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, s);
switch (extract32(ctx->opcode, 11, 4)) {
case NM_UALH:
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
MO_UNALN);
gen_store_gpr(t0, rt);
break;
case NM_UASH:
gen_load_gpr(t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
MO_UNALN);
break;
}
tcg_temp_free(t0);
tcg_temp_free(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();
TCGv t1 = tcg_temp_new();
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(t1, va, ctx->mem_idx,
memop | MO_TESL);
gen_store_gpr(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(t1, this_rt);
tcg_gen_qemu_st_tl(t1, va, ctx->mem_idx,
memop | MO_TEUL);
break;
}
counter++;
}
tcg_temp_free(va);
tcg_temp_free(t1);
}
break;
default:
generate_exception_end(ctx, EXCP_RI);
break;
}
}
break;
case NM_MOVE_BALC:
break;