aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/op_helper.c
diff options
context:
space:
mode:
authorMichael Clark <mjc@sifive.com>2018-04-09 09:25:25 +1200
committerPalmer Dabbelt <palmer@sifive.com>2018-10-17 13:02:09 -0700
commit85ba724fd6ad51360d61045476fd96d25dc15b9a (patch)
tree5be393f199a93feefd3a5aa2d35bc9e22cf41d45 /target/riscv/op_helper.c
parent09558375a634e17cea6cfbfec883ac2376d2dc7f (diff)
RISC-V: Allow setting and clearing multiple irqs
Change the API of riscv_set_local_interrupt to take a write mask and value to allow setting and clearing of multiple local interrupts atomically in a single call. Rename the new function to riscv_cpu_update_mip. Signed-off-by: Michael Clark <mjc@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Palmer Dabbelt <palmer@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Diffstat (limited to 'target/riscv/op_helper.c')
-rw-r--r--target/riscv/op_helper.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index aec7558e1b..d0883d329b 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -171,10 +171,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
*/
qemu_mutex_lock_iothread();
RISCVCPU *cpu = riscv_env_get_cpu(env);
- riscv_set_local_interrupt(cpu, MIP_SSIP,
- (val_to_write & MIP_SSIP) != 0);
- riscv_set_local_interrupt(cpu, MIP_STIP,
- (val_to_write & MIP_STIP) != 0);
+ riscv_cpu_update_mip(cpu, MIP_SSIP | MIP_STIP,
+ (val_to_write & (MIP_SSIP | MIP_STIP)));
/*
* csrs, csrc on mip.SEIP is not decomposable into separate read and
* write steps, so a different implementation is needed
@@ -657,16 +655,24 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
#ifndef CONFIG_USER_ONLY
/* iothread_mutex must be held */
-void riscv_set_local_interrupt(RISCVCPU *cpu, target_ulong mask, int value)
+uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
{
- target_ulong old_mip = cpu->env.mip;
- cpu->env.mip = (old_mip & ~mask) | (value ? mask : 0);
+ CPURISCVState *env = &cpu->env;
+ uint32_t old, new, cmp = atomic_read(&env->mip);
- if (cpu->env.mip && !old_mip) {
+ do {
+ old = cmp;
+ new = (old & ~mask) | (value & mask);
+ cmp = atomic_cmpxchg(&env->mip, old, new);
+ } while (old != cmp);
+
+ if (new && !old) {
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
- } else if (!cpu->env.mip && old_mip) {
+ } else if (!new && old) {
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
+
+ return old;
}
void riscv_set_mode(CPURISCVState *env, target_ulong newpriv)