diff options
Diffstat (limited to 'target/hppa/op_helper.c')
-rw-r--r-- | target/hppa/op_helper.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index f36ce74163..0aa5fb99d4 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp) { @@ -54,6 +55,83 @@ void HELPER(tcond)(CPUHPPAState *env, target_ulong cond) } } +static void atomic_store_3(CPUHPPAState *env, target_ulong addr, uint32_t val, + uint32_t mask, uintptr_t ra) +{ + uint32_t old, new, cmp; + +#ifdef CONFIG_USER_ONLY + uint32_t *haddr = g2h(addr - 1); + old = *haddr; + while (1) { + new = (old & ~mask) | (val & mask); + cmp = atomic_cmpxchg(haddr, old, new); + if (cmp == old) { + return; + } + old = cmp; + } +#else +#error "Not implemented." +#endif +} + +void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val) +{ + uintptr_t ra = GETPC(); + + switch (addr & 3) { + case 3: + cpu_stb_data_ra(env, addr, val, ra); + break; + case 2: + cpu_stw_data_ra(env, addr, val, ra); + break; + case 1: + /* The 3 byte store must appear atomic. */ + if (parallel_cpus) { + atomic_store_3(env, addr, val, 0x00ffffffu, ra); + } else { + cpu_stb_data_ra(env, addr, val >> 16, ra); + cpu_stw_data_ra(env, addr + 1, val, ra); + } + break; + default: + cpu_stl_data_ra(env, addr, val, ra); + break; + } +} + +void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val) +{ + uintptr_t ra = GETPC(); + + switch (addr & 3) { + case 3: + /* The 3 byte store must appear atomic. */ + if (parallel_cpus) { + atomic_store_3(env, addr - 3, val, 0xffffff00u, ra); + } else { + cpu_stw_data_ra(env, addr - 3, val >> 16, ra); + cpu_stb_data_ra(env, addr - 1, val >> 8, ra); + } + break; + case 2: + cpu_stw_data_ra(env, addr - 2, val >> 16, ra); + break; + case 1: + cpu_stb_data_ra(env, addr - 1, val >> 24, ra); + break; + default: + /* Nothing is stored, but protection is checked and the + cacheline is marked dirty. */ +#ifndef CONFIG_USER_ONLY + probe_write(env, addr, cpu_mmu_index(env, 0), ra); +#endif + break; + } +} + void HELPER(loaded_fr0)(CPUHPPAState *env) { uint32_t shadow = env->fr[0] >> 32; |