Skip to content

Commit

Permalink
target/openrisc: Allow fpcsr access in user mode
Browse files Browse the repository at this point in the history
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode.

Update mtspr and mfspr helpers to support this by moving the is_user
check into the helper.

Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf
Signed-off-by: Stafford Horne <shorne@gmail.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
stffrdhrn committed May 11, 2023
1 parent c1eb2dd commit 08f021d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 51 deletions.
45 changes: 34 additions & 11 deletions target/openrisc/sys_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,37 @@

#define TO_SPR(group, number) (((group) << 11) + (number))

static inline bool is_user(CPUOpenRISCState *env)
{
#ifdef CONFIG_USER_ONLY
return true;
#else
return (env->sr & SR_SM) == 0;
#endif
}

void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
{
#ifndef CONFIG_USER_ONLY
OpenRISCCPU *cpu = env_archcpu(env);
#ifndef CONFIG_USER_ONLY
CPUState *cs = env_cpu(env);
target_ulong mr;
int idx;
#endif

/* Handle user accessible SPRs first. */
switch (spr) {
case TO_SPR(0, 20): /* FPCSR */
cpu_set_fpcsr(env, rb);
return;
}

if (is_user(env)) {
raise_exception(cpu, EXCP_ILLEGAL);
}

#ifndef CONFIG_USER_ONLY
switch (spr) {
case TO_SPR(0, 11): /* EVBAR */
env->evbar = rb;
break;
Expand Down Expand Up @@ -187,27 +207,33 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
cpu_openrisc_timer_update(cpu);
qemu_mutex_unlock_iothread();
break;
#endif

case TO_SPR(0, 20): /* FPCSR */
cpu_set_fpcsr(env, rb);
break;
}
#endif
}

target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
target_ulong spr)
{
OpenRISCCPU *cpu = env_archcpu(env);
#ifndef CONFIG_USER_ONLY
uint64_t data[TARGET_INSN_START_WORDS];
MachineState *ms = MACHINE(qdev_get_machine());
OpenRISCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
int idx;
#endif

/* Handle user accessible SPRs first. */
switch (spr) {
case TO_SPR(0, 20): /* FPCSR */
return env->fpcsr;
}

if (is_user(env)) {
raise_exception(cpu, EXCP_ILLEGAL);
}

#ifndef CONFIG_USER_ONLY
switch (spr) {
case TO_SPR(0, 0): /* VR */
return env->vr;

Expand Down Expand Up @@ -324,11 +350,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
cpu_openrisc_count_update(cpu);
qemu_mutex_unlock_iothread();
return cpu_openrisc_count_get(cpu);
#endif

case TO_SPR(0, 20): /* FPCSR */
return env->fpcsr;
}
#endif

/* for rd is passed in, if rd unchanged, just keep it back. */
return rd;
Expand Down
72 changes: 32 additions & 40 deletions target/openrisc/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,57 +819,49 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a)

static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
{
check_r0_write(dc, a->d);

if (is_user(dc)) {
gen_illegal_exception(dc);
} else {
TCGv spr = tcg_temp_new();

if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
if (dc->delayed_branch) {
tcg_gen_mov_tl(cpu_pc, jmp_pc);
tcg_gen_discard_tl(jmp_pc);
} else {
tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
}
dc->base.is_jmp = DISAS_EXIT;
}
TCGv spr = tcg_temp_new();

tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
}
return true;
}

static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
{
if (is_user(dc)) {
gen_illegal_exception(dc);
} else {
TCGv spr;
check_r0_write(dc, a->d);

if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
/* For SR, we will need to exit the TB to recognize the new
* exception state. For NPC, in theory this counts as a branch
* (although the SPR only exists for use by an ICE). Save all
* of the cpu state first, allowing it to be overwritten.
*/
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
if (dc->delayed_branch) {
tcg_gen_mov_tl(cpu_pc, jmp_pc);
tcg_gen_discard_tl(jmp_pc);
} else {
tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
}
dc->base.is_jmp = DISAS_EXIT;
}

tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
return true;
}

static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
{
TCGv spr = tcg_temp_new();

spr = tcg_temp_new();
tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b));
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
/*
* For SR, we will need to exit the TB to recognize the new
* exception state. For NPC, in theory this counts as a branch
* (although the SPR only exists for use by an ICE). Save all
* of the cpu state first, allowing it to be overwritten.
*/
if (dc->delayed_branch) {
tcg_gen_mov_tl(cpu_pc, jmp_pc);
tcg_gen_discard_tl(jmp_pc);
} else {
tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
}
dc->base.is_jmp = DISAS_EXIT;

tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b));
return true;
}

Expand Down

0 comments on commit 08f021d

Please sign in to comment.