]> Git Repo - qemu.git/blame - target-alpha/helper.c
target-i386: fix pcmpxstrx equal-ordered (strstr) mode
[qemu.git] / target-alpha / helper.c
CommitLineData
4c9649a9
JM
1/*
2 * Alpha emulation cpu helpers for qemu.
5fafdf24 3 *
4c9649a9
JM
4 * Copyright (c) 2007 Jocelyn Mayer
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 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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
4c9649a9
JM
18 */
19
20#include <stdint.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include "cpu.h"
6b4c305c 25#include "fpu/softfloat.h"
2ef6175a 26#include "exec/helper-proto.h"
ba0e276d 27
8443effb 28
f3d3aad4
RH
29#define CONVERT_BIT(X, SRC, DST) \
30 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
8443effb 31
f3d3aad4
RH
32uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
33{
34 return (uint64_t)env->fpcr << 32;
ba0e276d
RH
35}
36
4d5712f1 37void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
ba0e276d 38{
f3d3aad4
RH
39 uint32_t fpcr = val >> 32;
40 uint32_t t = 0;
8443effb 41
f3d3aad4
RH
42 t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
43 t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
44 t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
45 t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
46 t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
8443effb 47
f3d3aad4
RH
48 env->fpcr = fpcr;
49 env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
8443effb 50
f3d3aad4
RH
51 switch (fpcr & FPCR_DYN_MASK) {
52 case FPCR_DYN_NORMAL:
53 default:
54 t = float_round_nearest_even;
55 break;
8443effb
RH
56 case FPCR_DYN_CHOPPED:
57 t = float_round_to_zero;
ba0e276d 58 break;
8443effb
RH
59 case FPCR_DYN_MINUS:
60 t = float_round_down;
ba0e276d 61 break;
8443effb
RH
62 case FPCR_DYN_PLUS:
63 t = float_round_up;
ba0e276d
RH
64 break;
65 }
8443effb
RH
66 env->fpcr_dyn_round = t;
67
f3d3aad4
RH
68 env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
69 env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
ba0e276d 70}
4c9649a9 71
a44a2777
RH
72uint64_t helper_load_fpcr(CPUAlphaState *env)
73{
74 return cpu_alpha_load_fpcr(env);
75}
76
77void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
78{
79 cpu_alpha_store_fpcr(env, val);
80}
81
59124384
RH
82static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
83{
84#ifndef CONFIG_USER_ONLY
85 if (env->pal_mode) {
86 if (reg >= 8 && reg <= 14) {
87 return &env->shadow[reg - 8];
88 } else if (reg == 25) {
89 return &env->shadow[7];
90 }
91 }
92#endif
93 return &env->ir[reg];
94}
95
96uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
97{
98 return *cpu_alpha_addr_gr(env, reg);
99}
100
101void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
102{
103 *cpu_alpha_addr_gr(env, reg) = val;
104}
105
5fafdf24 106#if defined(CONFIG_USER_ONLY)
7510454e 107int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
a44a2777 108 int rw, int mmu_idx)
4c9649a9 109{
7510454e
AF
110 AlphaCPU *cpu = ALPHA_CPU(cs);
111
27103424 112 cs->exception_index = EXCP_MMFAULT;
7510454e 113 cpu->env.trap_arg0 = address;
4c9649a9
JM
114 return 1;
115}
4c9649a9 116#else
a3b9af16 117/* Returns the OSF/1 entMM failure indication, or -1 on success. */
4d5712f1 118static int get_physical_address(CPUAlphaState *env, target_ulong addr,
a3b9af16
RH
119 int prot_need, int mmu_idx,
120 target_ulong *pphys, int *pprot)
4c9649a9 121{
d2810ffd 122 CPUState *cs = CPU(alpha_env_get_cpu(env));
a3b9af16
RH
123 target_long saddr = addr;
124 target_ulong phys = 0;
125 target_ulong L1pte, L2pte, L3pte;
126 target_ulong pt, index;
127 int prot = 0;
128 int ret = MM_K_ACV;
129
130 /* Ensure that the virtual address is properly sign-extended from
131 the last implemented virtual address bit. */
132 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
133 goto exit;
134 }
135
136 /* Translate the superpage. */
137 /* ??? When we do more than emulate Unix PALcode, we'll need to
fa6e0a63
RH
138 determine which KSEG is actually active. */
139 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
140 /* User-space cannot access KSEG addresses. */
a3b9af16
RH
141 if (mmu_idx != MMU_KERNEL_IDX) {
142 goto exit;
143 }
144
fa6e0a63
RH
145 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
146 We would not do this if the 48-bit KSEG is enabled. */
a3b9af16 147 phys = saddr & ((1ull << 40) - 1);
fa6e0a63
RH
148 phys |= (saddr & (1ull << 40)) << 3;
149
a3b9af16
RH
150 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
151 ret = -1;
152 goto exit;
153 }
154
155 /* Interpret the page table exactly like PALcode does. */
156
157 pt = env->ptbr;
158
159 /* L1 page table read. */
160 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
2c17449b 161 L1pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
162
163 if (unlikely((L1pte & PTE_VALID) == 0)) {
164 ret = MM_K_TNV;
165 goto exit;
166 }
167 if (unlikely((L1pte & PTE_KRE) == 0)) {
168 goto exit;
169 }
170 pt = L1pte >> 32 << TARGET_PAGE_BITS;
171
172 /* L2 page table read. */
173 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
2c17449b 174 L2pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
175
176 if (unlikely((L2pte & PTE_VALID) == 0)) {
177 ret = MM_K_TNV;
178 goto exit;
179 }
180 if (unlikely((L2pte & PTE_KRE) == 0)) {
181 goto exit;
182 }
183 pt = L2pte >> 32 << TARGET_PAGE_BITS;
184
185 /* L3 page table read. */
186 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
2c17449b 187 L3pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
188
189 phys = L3pte >> 32 << TARGET_PAGE_BITS;
190 if (unlikely((L3pte & PTE_VALID) == 0)) {
191 ret = MM_K_TNV;
192 goto exit;
193 }
194
195#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
196# error page bits out of date
197#endif
198
199 /* Check access violations. */
200 if (L3pte & (PTE_KRE << mmu_idx)) {
201 prot |= PAGE_READ | PAGE_EXEC;
202 }
203 if (L3pte & (PTE_KWE << mmu_idx)) {
204 prot |= PAGE_WRITE;
205 }
206 if (unlikely((prot & prot_need) == 0 && prot_need)) {
207 goto exit;
208 }
209
210 /* Check fault-on-operation violations. */
211 prot &= ~(L3pte >> 1);
212 ret = -1;
213 if (unlikely((prot & prot_need) == 0)) {
214 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
215 prot_need & PAGE_WRITE ? MM_K_FOW :
216 prot_need & PAGE_READ ? MM_K_FOR : -1);
217 }
218
219 exit:
220 *pphys = phys;
221 *pprot = prot;
222 return ret;
4c9649a9
JM
223}
224
00b941e5 225hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
4c9649a9 226{
00b941e5 227 AlphaCPU *cpu = ALPHA_CPU(cs);
a3b9af16
RH
228 target_ulong phys;
229 int prot, fail;
230
00b941e5 231 fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
a3b9af16
RH
232 return (fail >= 0 ? -1 : phys);
233}
234
7510454e 235int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int rw,
97b348e7 236 int mmu_idx)
a3b9af16 237{
7510454e
AF
238 AlphaCPU *cpu = ALPHA_CPU(cs);
239 CPUAlphaState *env = &cpu->env;
a3b9af16
RH
240 target_ulong phys;
241 int prot, fail;
242
243 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
244 if (unlikely(fail >= 0)) {
27103424 245 cs->exception_index = EXCP_MMFAULT;
a3b9af16
RH
246 env->trap_arg0 = addr;
247 env->trap_arg1 = fail;
248 env->trap_arg2 = (rw == 2 ? -1 : rw);
249 return 1;
250 }
251
0c591eb0 252 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
a3b9af16 253 prot, mmu_idx, TARGET_PAGE_SIZE);
129d8aa5 254 return 0;
4c9649a9 255}
3a6fa678 256#endif /* USER_ONLY */
4c9649a9 257
97a8ea5a 258void alpha_cpu_do_interrupt(CPUState *cs)
4c9649a9 259{
97a8ea5a
AF
260 AlphaCPU *cpu = ALPHA_CPU(cs);
261 CPUAlphaState *env = &cpu->env;
27103424 262 int i = cs->exception_index;
3a6fa678
RH
263
264 if (qemu_loglevel_mask(CPU_LOG_INT)) {
265 static int count;
266 const char *name = "<unknown>";
267
268 switch (i) {
269 case EXCP_RESET:
270 name = "reset";
271 break;
272 case EXCP_MCHK:
273 name = "mchk";
274 break;
275 case EXCP_SMP_INTERRUPT:
276 name = "smp_interrupt";
277 break;
278 case EXCP_CLK_INTERRUPT:
279 name = "clk_interrupt";
280 break;
281 case EXCP_DEV_INTERRUPT:
282 name = "dev_interrupt";
283 break;
284 case EXCP_MMFAULT:
285 name = "mmfault";
286 break;
287 case EXCP_UNALIGN:
288 name = "unalign";
289 break;
290 case EXCP_OPCDEC:
291 name = "opcdec";
292 break;
293 case EXCP_ARITH:
294 name = "arith";
295 break;
296 case EXCP_FEN:
297 name = "fen";
298 break;
299 case EXCP_CALL_PAL:
300 name = "call_pal";
301 break;
302 case EXCP_STL_C:
303 name = "stl_c";
304 break;
305 case EXCP_STQ_C:
306 name = "stq_c";
307 break;
308 }
309 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
310 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
311 }
312
27103424 313 cs->exception_index = -1;
3a6fa678
RH
314
315#if !defined(CONFIG_USER_ONLY)
316 switch (i) {
317 case EXCP_RESET:
318 i = 0x0000;
319 break;
320 case EXCP_MCHK:
321 i = 0x0080;
322 break;
323 case EXCP_SMP_INTERRUPT:
324 i = 0x0100;
325 break;
326 case EXCP_CLK_INTERRUPT:
327 i = 0x0180;
328 break;
329 case EXCP_DEV_INTERRUPT:
330 i = 0x0200;
331 break;
332 case EXCP_MMFAULT:
333 i = 0x0280;
334 break;
335 case EXCP_UNALIGN:
336 i = 0x0300;
337 break;
338 case EXCP_OPCDEC:
339 i = 0x0380;
340 break;
341 case EXCP_ARITH:
342 i = 0x0400;
343 break;
344 case EXCP_FEN:
345 i = 0x0480;
346 break;
347 case EXCP_CALL_PAL:
348 i = env->error_code;
349 /* There are 64 entry points for both privileged and unprivileged,
350 with bit 0x80 indicating unprivileged. Each entry point gets
351 64 bytes to do its job. */
352 if (i & 0x80) {
353 i = 0x2000 + (i - 0x80) * 64;
354 } else {
355 i = 0x1000 + i * 64;
356 }
357 break;
358 default:
a47dddd7 359 cpu_abort(cs, "Unhandled CPU exception");
3a6fa678
RH
360 }
361
362 /* Remember where the exception happened. Emulate real hardware in
363 that the low bit of the PC indicates PALmode. */
364 env->exc_addr = env->pc | env->pal_mode;
365
366 /* Continue execution at the PALcode entry point. */
367 env->pc = env->palbr + i;
368
369 /* Switch to PALmode. */
59124384 370 env->pal_mode = 1;
3a6fa678 371#endif /* !USER_ONLY */
4c9649a9 372}
4c9649a9 373
dde7c241
RH
374bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
375{
376 AlphaCPU *cpu = ALPHA_CPU(cs);
377 CPUAlphaState *env = &cpu->env;
378 int idx = -1;
379
380 /* We never take interrupts while in PALmode. */
381 if (env->pal_mode) {
382 return false;
383 }
384
385 /* Fall through the switch, collecting the highest priority
386 interrupt that isn't masked by the processor status IPL. */
387 /* ??? This hard-codes the OSF/1 interrupt levels. */
388 switch (env->ps & PS_INT_MASK) {
389 case 0 ... 3:
390 if (interrupt_request & CPU_INTERRUPT_HARD) {
391 idx = EXCP_DEV_INTERRUPT;
392 }
393 /* FALLTHRU */
394 case 4:
395 if (interrupt_request & CPU_INTERRUPT_TIMER) {
396 idx = EXCP_CLK_INTERRUPT;
397 }
398 /* FALLTHRU */
399 case 5:
400 if (interrupt_request & CPU_INTERRUPT_SMP) {
401 idx = EXCP_SMP_INTERRUPT;
402 }
403 /* FALLTHRU */
404 case 6:
405 if (interrupt_request & CPU_INTERRUPT_MCHK) {
406 idx = EXCP_MCHK;
407 }
408 }
409 if (idx >= 0) {
410 cs->exception_index = idx;
411 env->error_code = 0;
412 alpha_cpu_do_interrupt(cs);
413 return true;
414 }
415 return false;
416}
417
878096ee
AF
418void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
419 int flags)
4c9649a9 420{
b55266b5 421 static const char *linux_reg_names[] = {
4c9649a9
JM
422 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
423 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
424 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
425 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
426 };
878096ee
AF
427 AlphaCPU *cpu = ALPHA_CPU(cs);
428 CPUAlphaState *env = &cpu->env;
4c9649a9
JM
429 int i;
430
129d8aa5 431 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
4c9649a9
JM
432 env->pc, env->ps);
433 for (i = 0; i < 31; i++) {
434 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
59124384 435 linux_reg_names[i], cpu_alpha_load_gr(env, i));
4c9649a9
JM
436 if ((i % 3) == 2)
437 cpu_fprintf(f, "\n");
438 }
6910b8f6
RH
439
440 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
441 env->lock_addr, env->lock_value);
442
4c9649a9
JM
443 for (i = 0; i < 31; i++) {
444 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
445 *((uint64_t *)(&env->fir[i])));
446 if ((i % 3) == 2)
447 cpu_fprintf(f, "\n");
448 }
6910b8f6 449 cpu_fprintf(f, "\n");
4c9649a9 450}
b9f0923e 451
b9f0923e
RH
452/* This should only be called from translate, via gen_excp.
453 We expect that ENV->PC has already been updated. */
454void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
455{
27103424
AF
456 AlphaCPU *cpu = alpha_env_get_cpu(env);
457 CPUState *cs = CPU(cpu);
458
459 cs->exception_index = excp;
b9f0923e 460 env->error_code = error;
5638d180 461 cpu_loop_exit(cs);
b9f0923e
RH
462}
463
464/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
20503968 465void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
b9f0923e
RH
466 int excp, int error)
467{
27103424
AF
468 AlphaCPU *cpu = alpha_env_get_cpu(env);
469 CPUState *cs = CPU(cpu);
470
471 cs->exception_index = excp;
b9f0923e 472 env->error_code = error;
a8a826a3 473 if (retaddr) {
3f38f309 474 cpu_restore_state(cs, retaddr);
ba9c5de5
RH
475 /* Floating-point exceptions (our only users) point to the next PC. */
476 env->pc += 4;
a8a826a3 477 }
5638d180 478 cpu_loop_exit(cs);
b9f0923e
RH
479}
480
20503968 481void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
b9f0923e
RH
482 int exc, uint64_t mask)
483{
484 env->trap_arg0 = exc;
485 env->trap_arg1 = mask;
486 dynamic_excp(env, retaddr, EXCP_ARITH, 0);
487}
This page took 0.819167 seconds and 4 git commands to generate.