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.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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:
Stefan Markovic 2018-08-02 16:15:54 +02:00 committed by Aleksandar Markovic
parent 80845edf37
commit bf0718c59a

View File

@ -1746,6 +1746,18 @@ 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)
{
tcg_gen_addi_tl(ret, base, ofs);
#if defined(TARGET_MIPS64)
if (ctx->hflags & MIPS_HFLAG_AWRAP) {
tcg_gen_ext32s_i64(ret, ret);
}
#endif
}
/* Addresses computation (translation time) */
static target_long addr_add(DisasContext *ctx, target_long base,
target_long offset)
@ -16770,6 +16782,62 @@ 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)
{
gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], u);
}
static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count,
uint8_t gp, uint16_t u)
{
int counter = 0;
TCGv va = tcg_temp_new();
TCGv t0 = tcg_temp_new();
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(t0, this_rt);
tcg_gen_qemu_st_tl(t0, va, ctx->mem_idx,
(MO_TEUL | ctx->default_tcg_memop_mask));
counter++;
}
/* adjust stack pointer */
gen_adjust_sp(ctx, -u);
tcg_temp_free(t0);
tcg_temp_free(va);
}
static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count,
uint8_t gp, uint16_t u)
{
int counter = 0;
TCGv va = tcg_temp_new();
TCGv t0 = tcg_temp_new();
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(t0, va, ctx->mem_idx, MO_TESL |
ctx->default_tcg_memop_mask);
tcg_gen_ext32s_tl(t0, t0);
gen_store_gpr(t0, this_rt);
counter++;
}
/* adjust stack pointer */
gen_adjust_sp(ctx, u);
tcg_temp_free(t0);
tcg_temp_free(va);
}
static void gen_pool16c_nanomips_insn(DisasContext *ctx)
{
int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RD(ctx->opcode));
@ -17087,6 +17155,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;