]> git.proxmox.com Git - mirror_qemu.git/blob - target/hppa/op_helper.c
target/hppa: Extract FPU helpers to fpu_helper.c
[mirror_qemu.git] / target / hppa / op_helper.c
1 /*
2 * Helpers for HPPA instructions.
3 *
4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "qemu/log.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/helper-proto.h"
25 #include "exec/cpu_ldst.h"
26 #include "qemu/timer.h"
27 #include "sysemu/runstate.h"
28 #include "trace.h"
29
30 G_NORETURN void HELPER(excp)(CPUHPPAState *env, int excp)
31 {
32 CPUState *cs = env_cpu(env);
33
34 cs->exception_index = excp;
35 cpu_loop_exit(cs);
36 }
37
38 G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra)
39 {
40 CPUState *cs = env_cpu(env);
41
42 cs->exception_index = excp;
43 cpu_loop_exit_restore(cs, ra);
44 }
45
46 void HELPER(tsv)(CPUHPPAState *env, target_ureg cond)
47 {
48 if (unlikely((target_sreg)cond < 0)) {
49 hppa_dynamic_excp(env, EXCP_OVERFLOW, GETPC());
50 }
51 }
52
53 void HELPER(tcond)(CPUHPPAState *env, target_ureg cond)
54 {
55 if (unlikely(cond)) {
56 hppa_dynamic_excp(env, EXCP_COND, GETPC());
57 }
58 }
59
60 static void atomic_store_3(CPUHPPAState *env, target_ulong addr,
61 uint32_t val, uintptr_t ra)
62 {
63 int mmu_idx = cpu_mmu_index(env, 0);
64 uint32_t old, new, cmp, mask, *haddr;
65 void *vaddr;
66
67 vaddr = probe_access(env, addr, 3, MMU_DATA_STORE, mmu_idx, ra);
68 if (vaddr == NULL) {
69 cpu_loop_exit_atomic(env_cpu(env), ra);
70 }
71 haddr = (uint32_t *)((uintptr_t)vaddr & -4);
72 mask = addr & 1 ? 0x00ffffffu : 0xffffff00u;
73
74 old = *haddr;
75 while (1) {
76 new = be32_to_cpu((cpu_to_be32(old) & ~mask) | (val & mask));
77 cmp = qatomic_cmpxchg(haddr, old, new);
78 if (cmp == old) {
79 return;
80 }
81 old = cmp;
82 }
83 }
84
85 static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val,
86 bool parallel, uintptr_t ra)
87 {
88 switch (addr & 3) {
89 case 3:
90 cpu_stb_data_ra(env, addr, val, ra);
91 break;
92 case 2:
93 cpu_stw_data_ra(env, addr, val, ra);
94 break;
95 case 1:
96 /* The 3 byte store must appear atomic. */
97 if (parallel) {
98 atomic_store_3(env, addr, val, ra);
99 } else {
100 cpu_stb_data_ra(env, addr, val >> 16, ra);
101 cpu_stw_data_ra(env, addr + 1, val, ra);
102 }
103 break;
104 default:
105 cpu_stl_data_ra(env, addr, val, ra);
106 break;
107 }
108 }
109
110 void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ureg val)
111 {
112 do_stby_b(env, addr, val, false, GETPC());
113 }
114
115 void HELPER(stby_b_parallel)(CPUHPPAState *env, target_ulong addr,
116 target_ureg val)
117 {
118 do_stby_b(env, addr, val, true, GETPC());
119 }
120
121 static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val,
122 bool parallel, uintptr_t ra)
123 {
124 switch (addr & 3) {
125 case 3:
126 /* The 3 byte store must appear atomic. */
127 if (parallel) {
128 atomic_store_3(env, addr - 3, val, ra);
129 } else {
130 cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
131 cpu_stb_data_ra(env, addr - 1, val >> 8, ra);
132 }
133 break;
134 case 2:
135 cpu_stw_data_ra(env, addr - 2, val >> 16, ra);
136 break;
137 case 1:
138 cpu_stb_data_ra(env, addr - 1, val >> 24, ra);
139 break;
140 default:
141 /* Nothing is stored, but protection is checked and the
142 cacheline is marked dirty. */
143 probe_write(env, addr, 0, cpu_mmu_index(env, 0), ra);
144 break;
145 }
146 }
147
148 void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ureg val)
149 {
150 do_stby_e(env, addr, val, false, GETPC());
151 }
152
153 void HELPER(stby_e_parallel)(CPUHPPAState *env, target_ulong addr,
154 target_ureg val)
155 {
156 do_stby_e(env, addr, val, true, GETPC());
157 }
158
159 void HELPER(ldc_check)(target_ulong addr)
160 {
161 if (unlikely(addr & 0xf)) {
162 qemu_log_mask(LOG_GUEST_ERROR,
163 "Undefined ldc to unaligned address mod 16: "
164 TARGET_FMT_lx "\n", addr);
165 }
166 }
167
168 target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
169 uint32_t level, uint32_t want)
170 {
171 #ifdef CONFIG_USER_ONLY
172 return (page_check_range(addr, 1, want) == 0) ? 1 : 0;
173 #else
174 int prot, excp;
175 hwaddr phys;
176
177 trace_hppa_tlb_probe(addr, level, want);
178 /* Fail if the requested privilege level is higher than current. */
179 if (level < (env->iaoq_f & 3)) {
180 return 0;
181 }
182
183 excp = hppa_get_physical_address(env, addr, level, 0, &phys, &prot);
184 if (excp >= 0) {
185 if (env->psw & PSW_Q) {
186 /* ??? Needs tweaking for hppa64. */
187 env->cr[CR_IOR] = addr;
188 env->cr[CR_ISR] = addr >> 32;
189 }
190 if (excp == EXCP_DTLB_MISS) {
191 excp = EXCP_NA_DTLB_MISS;
192 }
193 hppa_dynamic_excp(env, excp, GETPC());
194 }
195 return (want & prot) != 0;
196 #endif
197 }
198
199 target_ureg HELPER(read_interval_timer)(void)
200 {
201 #ifdef CONFIG_USER_ONLY
202 /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist.
203 Just pass through the host cpu clock ticks. */
204 return cpu_get_host_ticks();
205 #else
206 /* In system mode we have access to a decent high-resolution clock.
207 In order to make OS-level time accounting work with the cr16,
208 present it with a well-timed clock fixed at 250MHz. */
209 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 2;
210 #endif
211 }
212
213 #ifndef CONFIG_USER_ONLY
214 void HELPER(write_interval_timer)(CPUHPPAState *env, target_ureg val)
215 {
216 HPPACPU *cpu = env_archcpu(env);
217 uint64_t current = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
218 uint64_t timeout;
219
220 /* Even in 64-bit mode, the comparator is always 32-bit. But the
221 value we expose to the guest is 1/4 of the speed of the clock,
222 so moosh in 34 bits. */
223 timeout = deposit64(current, 0, 34, (uint64_t)val << 2);
224
225 /* If the mooshing puts the clock in the past, advance to next round. */
226 if (timeout < current + 1000) {
227 timeout += 1ULL << 34;
228 }
229
230 cpu->env.cr[CR_IT] = timeout;
231 timer_mod(cpu->alarm_timer, timeout);
232 }
233
234 void HELPER(halt)(CPUHPPAState *env)
235 {
236 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
237 helper_excp(env, EXCP_HLT);
238 }
239
240 void HELPER(reset)(CPUHPPAState *env)
241 {
242 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
243 helper_excp(env, EXCP_HLT);
244 }
245
246 target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
247 {
248 target_ulong psw = env->psw;
249 /*
250 * Setting the PSW Q bit to 1, if it was not already 1, is an
251 * undefined operation.
252 *
253 * However, HP-UX 10.20 does this with the SSM instruction.
254 * Tested this on HP9000/712 and HP9000/785/C3750 and both
255 * machines set the Q bit from 0 to 1 without an exception,
256 * so let this go without comment.
257 */
258 env->psw = (psw & ~PSW_SM) | (nsm & PSW_SM);
259 return psw & PSW_SM;
260 }
261
262 void HELPER(rfi)(CPUHPPAState *env)
263 {
264 env->iasq_f = (uint64_t)env->cr[CR_IIASQ] << 32;
265 env->iasq_b = (uint64_t)env->cr_back[0] << 32;
266 env->iaoq_f = env->cr[CR_IIAOQ];
267 env->iaoq_b = env->cr_back[1];
268 cpu_hppa_put_psw(env, env->cr[CR_IPSW]);
269 }
270
271 void HELPER(getshadowregs)(CPUHPPAState *env)
272 {
273 env->gr[1] = env->shadow[0];
274 env->gr[8] = env->shadow[1];
275 env->gr[9] = env->shadow[2];
276 env->gr[16] = env->shadow[3];
277 env->gr[17] = env->shadow[4];
278 env->gr[24] = env->shadow[5];
279 env->gr[25] = env->shadow[6];
280 }
281
282 void HELPER(rfi_r)(CPUHPPAState *env)
283 {
284 helper_getshadowregs(env);
285 helper_rfi(env);
286 }
287 #endif