target/sparc: Move WRASR to decodetree

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-10-02 00:25:46 -07:00
parent e8325dc02d
commit 0faef01b39
2 changed files with 216 additions and 156 deletions

View File

@ -22,6 +22,13 @@ SETHI 00 rd:5 100 i:22
CALL 01 i:s30
##
## Major Opcode 10 -- integer, floating-point, vis, and system insns.
##
&r_r_ri rd rs1 rs2_or_imm imm:bool
@n_r_ri .. ..... ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri rd=0
{
[
STBAR 10 00000 101000 01111 0 0000000000000
@ -44,6 +51,30 @@ CALL 01 i:s30
RDY 10 rd:5 101000 rs1:5 0 0000000000000
}
{
[
WRY 10 00000 110000 ..... . ............. @n_r_ri
WRCCR 10 00010 110000 ..... . ............. @n_r_ri
WRASI 10 00011 110000 ..... . ............. @n_r_ri
WRFPRS 10 00110 110000 ..... . ............. @n_r_ri
{
WRGSR 10 10011 110000 ..... . ............. @n_r_ri
WRPOWERDOWN 10 10011 110000 ..... . ............. @n_r_ri
}
WRSOFTINT_SET 10 10100 110000 ..... . ............. @n_r_ri
WRSOFTINT_CLR 10 10101 110000 ..... . ............. @n_r_ri
WRSOFTINT 10 10110 110000 ..... . ............. @n_r_ri
WRTICK_CMPR 10 10111 110000 ..... . ............. @n_r_ri
WRSTICK 10 11000 110000 ..... . ............. @n_r_ri
WRSTICK_CMPR 10 11001 110000 ..... . ............. @n_r_ri
]
# Before v8, rs1==0 was WRY, and the rest executed as nop.
[
NOP_v7 10 ----- 110000 ----- 0 00000000 -----
NOP_v7 10 ----- 110000 ----- 1 -------- -----
]
}
{
RDPSR 10 rd:5 101001 00000 0 0000000000000
RDHPR_hpstate 10 rd:5 101001 00000 0 0000000000000

View File

@ -38,11 +38,16 @@
#ifdef TARGET_SPARC64
# define gen_helper_rdpsr(D, E) qemu_build_not_reached()
# define gen_helper_power_down(E) qemu_build_not_reached()
#else
# define gen_helper_clear_softint(E, S) qemu_build_not_reached()
# define gen_helper_flushw(E) qemu_build_not_reached()
# define gen_helper_rdccr(D, E) qemu_build_not_reached()
# define gen_helper_rdcwp(D, E) qemu_build_not_reached()
# define gen_helper_set_softint(E, S) qemu_build_not_reached()
# define gen_helper_tick_get_count(D, E, T, C) qemu_build_not_reached()
# define gen_helper_wrccr(E, S) qemu_build_not_reached()
# define gen_helper_write_softint(E, S) qemu_build_not_reached()
# define MAXTL_MASK 0
#endif
@ -2866,12 +2871,14 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
#ifdef TARGET_SPARC64
# define avail_32(C) false
# define avail_ASR17(C) false
# define avail_POWERDOWN(C) false
# define avail_64(C) true
# define avail_GL(C) ((C)->def->features & CPU_FEATURE_GL)
# define avail_HYPV(C) ((C)->def->features & CPU_FEATURE_HYPV)
#else
# define avail_32(C) true
# define avail_ASR17(C) ((C)->def->features & CPU_FEATURE_ASR17)
# define avail_POWERDOWN(C) ((C)->def->features & CPU_FEATURE_POWERDOWN)
# define avail_64(C) false
# define avail_GL(C) false
# define avail_HYPV(C) false
@ -3077,6 +3084,10 @@ static bool trans_SETHI(DisasContext *dc, arg_SETHI *a)
return advance_pc(dc);
}
/*
* Major Opcode 10 -- integer, floating-point, vis, and system insns.
*/
static bool do_tcc(DisasContext *dc, int cond, int cc,
int rs1, bool imm, int rs2_or_imm)
{
@ -3573,6 +3584,179 @@ static bool trans_FLUSHW(DisasContext *dc, arg_FLUSHW *a)
return false;
}
static bool do_wr_special(DisasContext *dc, arg_r_r_ri *a, bool priv,
void (*func)(DisasContext *, TCGv))
{
TCGv src;
/* For simplicity, we under-decoded the rs2 form. */
if (!a->imm && (a->rs2_or_imm & ~0x1f)) {
return false;
}
if (!priv) {
return raise_priv(dc);
}
if (a->rs1 == 0 && (a->imm || a->rs2_or_imm == 0)) {
src = tcg_constant_tl(a->rs2_or_imm);
} else {
TCGv src1 = gen_load_gpr(dc, a->rs1);
if (a->rs2_or_imm == 0) {
src = src1;
} else {
src = tcg_temp_new();
if (a->imm) {
tcg_gen_xori_tl(src, src1, a->rs2_or_imm);
} else {
tcg_gen_xor_tl(src, src1, gen_load_gpr(dc, a->rs2_or_imm));
}
}
}
func(dc, src);
return advance_pc(dc);
}
static void do_wry(DisasContext *dc, TCGv src)
{
tcg_gen_ext32u_tl(cpu_y, src);
}
TRANS(WRY, ALL, do_wr_special, a, true, do_wry)
static void do_wrccr(DisasContext *dc, TCGv src)
{
gen_helper_wrccr(tcg_env, src);
}
TRANS(WRCCR, 64, do_wr_special, a, true, do_wrccr)
static void do_wrasi(DisasContext *dc, TCGv src)
{
TCGv tmp = tcg_temp_new();
tcg_gen_ext8u_tl(tmp, src);
tcg_gen_st32_tl(tmp, tcg_env, env64_field_offsetof(asi));
/* End TB to notice changed ASI. */
dc->base.is_jmp = DISAS_EXIT;
}
TRANS(WRASI, 64, do_wr_special, a, true, do_wrasi)
static void do_wrfprs(DisasContext *dc, TCGv src)
{
#ifdef TARGET_SPARC64
tcg_gen_trunc_tl_i32(cpu_fprs, src);
dc->fprs_dirty = 0;
dc->base.is_jmp = DISAS_EXIT;
#else
qemu_build_not_reached();
#endif
}
TRANS(WRFPRS, 64, do_wr_special, a, true, do_wrfprs)
static void do_wrgsr(DisasContext *dc, TCGv src)
{
gen_trap_ifnofpu(dc);
tcg_gen_mov_tl(cpu_gsr, src);
}
TRANS(WRGSR, 64, do_wr_special, a, true, do_wrgsr)
static void do_wrsoftint_set(DisasContext *dc, TCGv src)
{
gen_helper_set_softint(tcg_env, src);
}
TRANS(WRSOFTINT_SET, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_set)
static void do_wrsoftint_clr(DisasContext *dc, TCGv src)
{
gen_helper_clear_softint(tcg_env, src);
}
TRANS(WRSOFTINT_CLR, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_clr)
static void do_wrsoftint(DisasContext *dc, TCGv src)
{
gen_helper_write_softint(tcg_env, src);
}
TRANS(WRSOFTINT, 64, do_wr_special, a, supervisor(dc), do_wrsoftint)
static void do_wrtick_cmpr(DisasContext *dc, TCGv src)
{
#ifdef TARGET_SPARC64
TCGv_ptr r_tickptr = tcg_temp_new_ptr();
tcg_gen_mov_tl(cpu_tick_cmpr, src);
tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, tick));
translator_io_start(&dc->base);
gen_helper_tick_set_limit(r_tickptr, cpu_tick_cmpr);
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
#else
qemu_build_not_reached();
#endif
}
TRANS(WRTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrtick_cmpr)
static void do_wrstick(DisasContext *dc, TCGv src)
{
#ifdef TARGET_SPARC64
TCGv_ptr r_tickptr = tcg_temp_new_ptr();
tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick));
translator_io_start(&dc->base);
gen_helper_tick_set_count(r_tickptr, src);
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
#else
qemu_build_not_reached();
#endif
}
TRANS(WRSTICK, 64, do_wr_special, a, supervisor(dc), do_wrstick)
static void do_wrstick_cmpr(DisasContext *dc, TCGv src)
{
#ifdef TARGET_SPARC64
TCGv_ptr r_tickptr = tcg_temp_new_ptr();
tcg_gen_mov_tl(cpu_stick_cmpr, src);
tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick));
translator_io_start(&dc->base);
gen_helper_tick_set_limit(r_tickptr, cpu_stick_cmpr);
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
#else
qemu_build_not_reached();
#endif
}
TRANS(WRSTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrstick_cmpr)
static void do_wrpowerdown(DisasContext *dc, TCGv src)
{
save_state(dc);
gen_helper_power_down(tcg_env);
}
TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown)
static bool trans_NOP_v7(DisasContext *dc, arg_NOP_v7 *a)
{
/*
* TODO: Need a feature bit for sparcv8.
* In the meantime, treat all 32-bit cpus like sparcv7.
*/
if (avail_32(dc)) {
return advance_pc(dc);
}
return false;
}
#define CHECK_IU_FEATURE(dc, FEATURE) \
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
goto illegal_insn;
@ -4233,162 +4417,7 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
break;
#endif
case 0x30:
{
cpu_tmp0 = tcg_temp_new();
switch(rd) {
case 0: /* wry */
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff);
break;
#ifndef TARGET_SPARC64
case 0x01 ... 0x0f: /* undefined in the
SPARCv8 manual, nop
on the microSPARC
II */
case 0x10 ... 0x1f: /* implementation-dependent
in the SPARCv8
manual, nop on the
microSPARC II */
if ((rd == 0x13) && (dc->def->features &
CPU_FEATURE_POWERDOWN)) {
/* LEON3 power-down */
save_state(dc);
gen_helper_power_down(tcg_env);
}
break;
#else
case 0x2: /* V9 wrccr */
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
gen_helper_wrccr(tcg_env, cpu_tmp0);
tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
dc->cc_op = CC_OP_FLAGS;
break;
case 0x3: /* V9 wrasi */
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff);
tcg_gen_st32_tl(cpu_tmp0, tcg_env,
offsetof(CPUSPARCState, asi));
/*
* End TB to notice changed ASI.
* TODO: Could notice src1 = %g0 and IS_IMM,
* update DisasContext and not exit the TB.
*/
save_state(dc);
gen_op_next_insn();
tcg_gen_lookup_and_goto_ptr();
dc->base.is_jmp = DISAS_NORETURN;
break;
case 0x6: /* V9 wrfprs */
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
tcg_gen_trunc_tl_i32(cpu_fprs, cpu_tmp0);
dc->fprs_dirty = 0;
save_state(dc);
gen_op_next_insn();
tcg_gen_exit_tb(NULL, 0);
dc->base.is_jmp = DISAS_NORETURN;
break;
case 0xf: /* V9 sir, nop if user */
#if !defined(CONFIG_USER_ONLY)
if (supervisor(dc)) {
; // XXX
}
#endif
break;
case 0x13: /* Graphics Status */
if (gen_trap_ifnofpu(dc)) {
goto jmp_insn;
}
tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2);
break;
case 0x14: /* Softint set */
if (!supervisor(dc))
goto illegal_insn;
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
gen_helper_set_softint(tcg_env, cpu_tmp0);
break;
case 0x15: /* Softint clear */
if (!supervisor(dc))
goto illegal_insn;
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
gen_helper_clear_softint(tcg_env, cpu_tmp0);
break;
case 0x16: /* Softint write */
if (!supervisor(dc))
goto illegal_insn;
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
gen_helper_write_softint(tcg_env, cpu_tmp0);
break;
case 0x17: /* Tick compare */
#if !defined(CONFIG_USER_ONLY)
if (!supervisor(dc))
goto illegal_insn;
#endif
{
TCGv_ptr r_tickptr;
tcg_gen_xor_tl(cpu_tick_cmpr, cpu_src1,
cpu_src2);
r_tickptr = tcg_temp_new_ptr();
tcg_gen_ld_ptr(r_tickptr, tcg_env,
offsetof(CPUSPARCState, tick));
translator_io_start(&dc->base);
gen_helper_tick_set_limit(r_tickptr,
cpu_tick_cmpr);
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
}
break;
case 0x18: /* System tick */
#if !defined(CONFIG_USER_ONLY)
if (!supervisor(dc))
goto illegal_insn;
#endif
{
TCGv_ptr r_tickptr;
tcg_gen_xor_tl(cpu_tmp0, cpu_src1,
cpu_src2);
r_tickptr = tcg_temp_new_ptr();
tcg_gen_ld_ptr(r_tickptr, tcg_env,
offsetof(CPUSPARCState, stick));
translator_io_start(&dc->base);
gen_helper_tick_set_count(r_tickptr,
cpu_tmp0);
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
}
break;
case 0x19: /* System tick compare */
#if !defined(CONFIG_USER_ONLY)
if (!supervisor(dc))
goto illegal_insn;
#endif
{
TCGv_ptr r_tickptr;
tcg_gen_xor_tl(cpu_stick_cmpr, cpu_src1,
cpu_src2);
r_tickptr = tcg_temp_new_ptr();
tcg_gen_ld_ptr(r_tickptr, tcg_env,
offsetof(CPUSPARCState, stick));
translator_io_start(&dc->base);
gen_helper_tick_set_limit(r_tickptr,
cpu_stick_cmpr);
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
}
break;
case 0x10: /* Performance Control */
case 0x11: /* Performance Instrumentation
Counter */
case 0x12: /* Dispatch Control */
#endif
default:
goto illegal_insn;
}
}
break;
goto illegal_insn; /* WRASR in decodetree */
#if !defined(CONFIG_USER_ONLY)
case 0x31: /* wrpsr, V9 saved, restored */
{