target/mips: Add emulation of nanoMIPS 16-bit save and restore instructions

Add emulation of SAVE16 and RESTORE.JRC16 instructions. Routines
gen_save(), gen_restore(), and gen_adjust_sp() are provided to support
this feature.

This patch at the same time provides function gen_op_addr_addi(). This
function will be used in emulation of some other nanoMIPS instructions.

Backports commit bf0718c59a4b27dd01346a7b5b9a183ed1b18fb7 from qemu
This commit is contained in:
Stefan Markovic 2018-08-27 04:40:09 -04:00 committed by Lioncash
parent b4fa0bfbba
commit 6b5dbbf6a3
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -1751,6 +1751,19 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv
#endif
}
static inline void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base,
target_long ofs)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
tcg_gen_addi_tl(tcg_ctx, ret, base, ofs);
#if defined(TARGET_MIPS64)
if (ctx->hflags & MIPS_HFLAG_AWRAP) {
tcg_gen_ext32s_i64(tcg_ctx, ret, ret);
}
#endif
}
/* Addresses computation (translation time) */
static target_long addr_add(DisasContext *ctx, target_long base,
target_long offset)
@ -16881,6 +16894,66 @@ static inline int decode_gpr_gpr4_zero(int r)
#define NANOMIPS_EXTRACT_RS5(op) (op & 0x1f)
static void gen_adjust_sp(DisasContext *ctx, int u)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
gen_op_addr_addi(ctx, tcg_ctx->cpu_gpr[29], tcg_ctx->cpu_gpr[29], u);
}
static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count,
uint8_t gp, uint16_t u)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
int counter = 0;
TCGv va = tcg_temp_new(tcg_ctx);
TCGv t0 = tcg_temp_new(tcg_ctx);
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(ctx, t0, this_rt);
tcg_gen_qemu_st_tl(ctx->uc, t0, va, ctx->mem_idx,
(MO_TEUL | ctx->default_tcg_memop_mask));
counter++;
}
/* adjust stack pointer */
gen_adjust_sp(ctx, -u);
tcg_temp_free(tcg_ctx, t0);
tcg_temp_free(tcg_ctx, va);
}
static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count,
uint8_t gp, uint16_t u)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
int counter = 0;
TCGv va = tcg_temp_new(tcg_ctx);
TCGv t0 = tcg_temp_new(tcg_ctx);
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(ctx->uc, t0, va, ctx->mem_idx, MO_TESL |
ctx->default_tcg_memop_mask);
tcg_gen_ext32s_tl(tcg_ctx, t0, t0);
gen_store_gpr(tcg_ctx, t0, this_rt);
counter++;
}
/* adjust stack pointer */
gen_adjust_sp(ctx, u);
tcg_temp_free(tcg_ctx, t0);
tcg_temp_free(tcg_ctx, va);
}
static void gen_pool16c_nanomips_insn(DisasContext *ctx)
{
int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RD(ctx->opcode));
@ -17193,6 +17266,21 @@ static int decode_nanomips_opc(CPUMIPSState *env, DisasContext *ctx)
}
break;
case NM_P16_SR:
{
int count = extract32(ctx->opcode, 0, 4);
int u = extract32(ctx->opcode, 4, 4) << 4;
rt = 30 + extract32(ctx->opcode, 9, 1);
switch (extract32(ctx->opcode, 8, 1)) {
case NM_SAVE16:
gen_save(ctx, rt, count, 0, u);
break;
case NM_RESTORE_JRC16:
gen_restore(ctx, rt, count, 0, u);
gen_compute_branch_nm(ctx, OPC_JR, 2, 31, 0, 0);
break;
}
}
break;
case NM_MOVEP:
break;