target/mips: Implement emulation of nanoMIPS EXTW instruction

Implement emulation of nanoMIPS EXTW instruction. EXTW instruction
is similar to the MIPS r6 ALIGN instruction, except that it counts
the other way and in bits instead of bytes. We therefore generalise
gen_align() function into a new gen_align_bits() function (which
counts in bits instead of bytes and optimises when bits = size of
the word), and implement gen_align() and a new gen_ext() based on
that. Since we need to know the word size to check for when the
number of bits == the word size, the opc argument is replaced with
a wordsz argument (either 32 or 64).

Backports commit 821f2008c3c708e0e33158039ab55673a0f04519 from qemu
This commit is contained in:
James Hogan 2018-08-27 05:14:44 -04:00 committed by Lioncash
parent 06e5835cc7
commit bcdee16199
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -4938,8 +4938,8 @@ static void gen_lsa(DisasContext *ctx, int opc, int rd, int rs, int rt,
tcg_temp_free(tcg_ctx, t0);
}
static void gen_align(DisasContext *ctx, int opc, int rd, int rs, int rt,
int bp)
static void gen_align_bits(DisasContext *ctx, int wordsz, int rd, int rs,
int rt, int bits)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
TCGv *cpu_gpr = tcg_ctx->cpu_gpr;
@ -4949,35 +4949,40 @@ static void gen_align(DisasContext *ctx, int opc, int rd, int rs, int rt,
return;
}
t0 = tcg_temp_new(tcg_ctx);
gen_load_gpr(ctx, t0, rt);
if (bp == 0) {
switch (opc) {
case OPC_ALIGN:
if (bits == 0 || bits == wordsz) {
if (bits == 0) {
gen_load_gpr(ctx, t0, rt);
} else {
gen_load_gpr(ctx, t0, rs);
}
switch (wordsz) {
case 32:
tcg_gen_ext32s_tl(tcg_ctx, cpu_gpr[rd], t0);
break;
#if defined(TARGET_MIPS64)
case OPC_DALIGN:
case 64:
tcg_gen_mov_tl(tcg_ctx, cpu_gpr[rd], t0);
break;
#endif
}
} else {
TCGv t1 = tcg_temp_new(tcg_ctx);
gen_load_gpr(ctx, t0, rt);
gen_load_gpr(ctx, t1, rs);
switch (opc) {
case OPC_ALIGN:
switch (wordsz) {
case 32:
{
TCGv_i64 t2 = tcg_temp_new_i64(tcg_ctx);
tcg_gen_concat_tl_i64(tcg_ctx, t2, t1, t0);
tcg_gen_shri_i64(tcg_ctx, t2, t2, 8 * (4 - bp));
tcg_gen_shri_i64(tcg_ctx, t2, t2, 32 - bits);
gen_move_low32(tcg_ctx, cpu_gpr[rd], t2);
tcg_temp_free_i64(tcg_ctx, t2);
}
break;
#if defined(TARGET_MIPS64)
case OPC_DALIGN:
tcg_gen_shli_tl(tcg_ctx, t0, t0, 8 * bp);
tcg_gen_shri_tl(tcg_ctx, t1, t1, 8 * (8 - bp));
case 64:
tcg_gen_shli_tl(tcg_ctx, t0, t0, bits);
tcg_gen_shri_tl(tcg_ctx, t1, t1, 64 - bits);
tcg_gen_or_tl(tcg_ctx, cpu_gpr[rd], t1, t0);
break;
#endif
@ -4988,6 +4993,18 @@ static void gen_align(DisasContext *ctx, int opc, int rd, int rs, int rt,
tcg_temp_free(tcg_ctx, t0);
}
static void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt,
int bp)
{
gen_align_bits(ctx, wordsz, rd, rs, rt, bp * 8);
}
static void gen_ext(DisasContext *ctx, int wordsz, int rd, int rs, int rt,
int shift)
{
gen_align_bits(ctx, wordsz, rd, rs, rt, wordsz - shift);
}
static void gen_bitswap(DisasContext *ctx, int opc, int rd, int rt)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
@ -14512,8 +14529,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
break;
case ALIGN:
check_insn(ctx, ISA_MIPS32R6);
gen_align(ctx, OPC_ALIGN, rd, rs, rt,
extract32(ctx->opcode, 9, 2));
gen_align(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 9, 2));
break;
case EXT:
gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd);
@ -17738,6 +17754,9 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
gen_lsa(ctx, OPC_LSA, rd, rs, rt,
extract32(ctx->opcode, 9, 2) - 1);
break;
case NM_EXTW:
gen_ext(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 6, 5));
break;
case NM_POOL32AXF:
gen_pool32axf_nanomips_insn(env, ctx);
break;
@ -20590,7 +20609,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
switch (op2) {
case OPC_ALIGN:
case OPC_ALIGN_END:
gen_align(ctx, OPC_ALIGN, rd, rs, rt, sa & 3);
gen_align(ctx, 32, rd, rs, rt, sa & 3);
break;
case OPC_BITSWAP:
gen_bitswap(ctx, op2, rd, rt);
@ -20616,7 +20635,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
switch (op2) {
case OPC_DALIGN:
case OPC_DALIGN_END:
gen_align(ctx, OPC_DALIGN, rd, rs, rt, sa & 7);
gen_align(ctx, 64, rd, rs, rt, sa & 7);
break;
case OPC_DBITSWAP:
gen_bitswap(ctx, op2, rd, rt);