]> git.proxmox.com Git - qemu.git/blame - target-alpha/helper.c
target-alpha: Implement IEEE FP qualifiers.
[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"
25#include "exec-all.h"
ba0e276d
RH
26#include "softfloat.h"
27
28uint64_t cpu_alpha_load_fpcr (CPUState *env)
29{
8443effb
RH
30 uint64_t r = 0;
31 uint8_t t;
32
33 t = env->fpcr_exc_status;
34 if (t) {
35 r = FPCR_SUM;
36 if (t & float_flag_invalid) {
37 r |= FPCR_INV;
38 }
39 if (t & float_flag_divbyzero) {
40 r |= FPCR_DZE;
41 }
42 if (t & float_flag_overflow) {
43 r |= FPCR_OVF;
44 }
45 if (t & float_flag_underflow) {
46 r |= FPCR_UNF;
47 }
48 if (t & float_flag_inexact) {
49 r |= FPCR_INE;
50 }
51 }
52
53 t = env->fpcr_exc_mask;
54 if (t & float_flag_invalid) {
55 r |= FPCR_INVD;
56 }
57 if (t & float_flag_divbyzero) {
58 r |= FPCR_DZED;
59 }
60 if (t & float_flag_overflow) {
61 r |= FPCR_OVFD;
62 }
63 if (t & float_flag_underflow) {
64 r |= FPCR_UNFD;
65 }
66 if (t & float_flag_inexact) {
67 r |= FPCR_INED;
68 }
69
70 switch (env->fpcr_dyn_round) {
ba0e276d 71 case float_round_nearest_even:
8443effb 72 r |= FPCR_DYN_NORMAL;
ba0e276d
RH
73 break;
74 case float_round_down:
8443effb 75 r |= FPCR_DYN_MINUS;
ba0e276d
RH
76 break;
77 case float_round_up:
8443effb 78 r |= FPCR_DYN_PLUS;
ba0e276d
RH
79 break;
80 case float_round_to_zero:
8443effb 81 r |= FPCR_DYN_CHOPPED;
ba0e276d
RH
82 break;
83 }
8443effb
RH
84
85 if (env->fpcr_dnz) {
86 r |= FPCR_DNZ;
87 }
88 if (env->fpcr_dnod) {
89 r |= FPCR_DNOD;
90 }
91 if (env->fpcr_undz) {
92 r |= FPCR_UNDZ;
93 }
94
95 return r;
ba0e276d
RH
96}
97
98void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
99{
8443effb
RH
100 uint8_t t;
101
102 t = 0;
103 if (val & FPCR_INV) {
104 t |= float_flag_invalid;
105 }
106 if (val & FPCR_DZE) {
107 t |= float_flag_divbyzero;
108 }
109 if (val & FPCR_OVF) {
110 t |= float_flag_overflow;
111 }
112 if (val & FPCR_UNF) {
113 t |= float_flag_underflow;
114 }
115 if (val & FPCR_INE) {
116 t |= float_flag_inexact;
117 }
118 env->fpcr_exc_status = t;
119
120 t = 0;
121 if (val & FPCR_INVD) {
122 t |= float_flag_invalid;
123 }
124 if (val & FPCR_DZED) {
125 t |= float_flag_divbyzero;
126 }
127 if (val & FPCR_OVFD) {
128 t |= float_flag_overflow;
129 }
130 if (val & FPCR_UNFD) {
131 t |= float_flag_underflow;
132 }
133 if (val & FPCR_INED) {
134 t |= float_flag_inexact;
135 }
136 env->fpcr_exc_mask = t;
137
138 switch (val & FPCR_DYN_MASK) {
139 case FPCR_DYN_CHOPPED:
140 t = float_round_to_zero;
ba0e276d 141 break;
8443effb
RH
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
ba0e276d 144 break;
8443effb
RH
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
ba0e276d 147 break;
8443effb
RH
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
ba0e276d
RH
150 break;
151 }
8443effb
RH
152 env->fpcr_dyn_round = t;
153
154 env->fpcr_flush_to_zero
155 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
156
157 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
ba0e276d 160}
4c9649a9 161
5fafdf24 162#if defined(CONFIG_USER_ONLY)
4c9649a9
JM
163
164int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6ebbf390 165 int mmu_idx, int is_softmmu)
4c9649a9
JM
166{
167 if (rw == 2)
168 env->exception_index = EXCP_ITB_MISS;
169 else
170 env->exception_index = EXCP_DFAULT;
171 env->ipr[IPR_EXC_ADDR] = address;
3b46e624 172
4c9649a9
JM
173 return 1;
174}
175
c227f099 176target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
4c9649a9
JM
177{
178 return addr;
179}
180
181void do_interrupt (CPUState *env)
182{
183 env->exception_index = -1;
184}
185
186#else
187
c227f099 188target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
4c9649a9
JM
189{
190 return -1;
191}
192
193int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6ebbf390 194 int mmu_idx, int is_softmmu)
4c9649a9
JM
195{
196 uint32_t opc;
197
198 if (rw == 2) {
199 /* Instruction translation buffer miss */
200 env->exception_index = EXCP_ITB_MISS;
201 } else {
202 if (env->ipr[IPR_EXC_ADDR] & 1)
203 env->exception_index = EXCP_DTB_MISS_PAL;
204 else
205 env->exception_index = EXCP_DTB_MISS_NATIVE;
206 opc = (ldl_code(env->pc) >> 21) << 4;
207 if (rw) {
208 opc |= 0x9;
209 } else {
210 opc |= 0x4;
211 }
212 env->ipr[IPR_MM_STAT] = opc;
213 }
214
215 return 1;
216}
217
218int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
219{
220 uint64_t hwpcb;
221 int ret = 0;
222
223 hwpcb = env->ipr[IPR_PCBB];
224 switch (iprn) {
225 case IPR_ASN:
226 if (env->features & FEATURE_ASN)
227 *valp = env->ipr[IPR_ASN];
228 else
229 *valp = 0;
230 break;
231 case IPR_ASTEN:
232 *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
233 break;
234 case IPR_ASTSR:
235 *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
236 break;
237 case IPR_DATFX:
238 /* Write only */
239 ret = -1;
240 break;
241 case IPR_ESP:
242 if (env->features & FEATURE_SPS)
243 *valp = env->ipr[IPR_ESP];
244 else
245 *valp = ldq_raw(hwpcb + 8);
246 break;
247 case IPR_FEN:
248 *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
249 break;
250 case IPR_IPIR:
251 /* Write-only */
252 ret = -1;
253 break;
254 case IPR_IPL:
255 *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
256 break;
257 case IPR_KSP:
258 if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
259 ret = -1;
260 } else {
261 if (env->features & FEATURE_SPS)
262 *valp = env->ipr[IPR_KSP];
263 else
264 *valp = ldq_raw(hwpcb + 0);
265 }
266 break;
267 case IPR_MCES:
268 *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
269 break;
270 case IPR_PERFMON:
271 /* Implementation specific */
272 *valp = 0;
273 break;
274 case IPR_PCBB:
275 *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
276 break;
277 case IPR_PRBR:
278 *valp = env->ipr[IPR_PRBR];
279 break;
280 case IPR_PTBR:
281 *valp = env->ipr[IPR_PTBR];
282 break;
283 case IPR_SCBB:
284 *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
285 break;
286 case IPR_SIRR:
287 /* Write-only */
288 ret = -1;
289 break;
290 case IPR_SISR:
291 *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
292 case IPR_SSP:
293 if (env->features & FEATURE_SPS)
294 *valp = env->ipr[IPR_SSP];
295 else
296 *valp = ldq_raw(hwpcb + 16);
297 break;
298 case IPR_SYSPTBR:
299 if (env->features & FEATURE_VIRBND)
300 *valp = env->ipr[IPR_SYSPTBR];
301 else
302 ret = -1;
303 break;
304 case IPR_TBCHK:
305 if ((env->features & FEATURE_TBCHK)) {
306 /* XXX: TODO */
307 *valp = 0;
308 ret = -1;
309 } else {
310 ret = -1;
311 }
312 break;
313 case IPR_TBIA:
314 /* Write-only */
315 ret = -1;
316 break;
317 case IPR_TBIAP:
318 /* Write-only */
319 ret = -1;
320 break;
321 case IPR_TBIS:
322 /* Write-only */
323 ret = -1;
324 break;
325 case IPR_TBISD:
326 /* Write-only */
327 ret = -1;
328 break;
329 case IPR_TBISI:
330 /* Write-only */
331 ret = -1;
332 break;
333 case IPR_USP:
334 if (env->features & FEATURE_SPS)
335 *valp = env->ipr[IPR_USP];
336 else
337 *valp = ldq_raw(hwpcb + 24);
338 break;
339 case IPR_VIRBND:
340 if (env->features & FEATURE_VIRBND)
341 *valp = env->ipr[IPR_VIRBND];
342 else
343 ret = -1;
344 break;
345 case IPR_VPTB:
346 *valp = env->ipr[IPR_VPTB];
347 break;
348 case IPR_WHAMI:
349 *valp = env->ipr[IPR_WHAMI];
350 break;
351 default:
352 /* Invalid */
353 ret = -1;
354 break;
355 }
356
357 return ret;
358}
359
360int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
361{
362 uint64_t hwpcb, tmp64;
363 uint8_t tmp8;
364 int ret = 0;
365
366 hwpcb = env->ipr[IPR_PCBB];
367 switch (iprn) {
368 case IPR_ASN:
369 /* Read-only */
370 ret = -1;
371 break;
372 case IPR_ASTEN:
373 tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
374 *oldvalp = tmp8;
375 tmp8 &= val & 0xF;
376 tmp8 |= (val >> 4) & 0xF;
377 env->ipr[IPR_ASTEN] &= ~0xF;
378 env->ipr[IPR_ASTEN] |= tmp8;
379 ret = 1;
380 break;
381 case IPR_ASTSR:
382 tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
383 *oldvalp = tmp8;
384 tmp8 &= val & 0xF;
385 tmp8 |= (val >> 4) & 0xF;
386 env->ipr[IPR_ASTSR] &= ~0xF;
387 env->ipr[IPR_ASTSR] |= tmp8;
388 ret = 1;
389 case IPR_DATFX:
390 env->ipr[IPR_DATFX] &= ~0x1;
391 env->ipr[IPR_DATFX] |= val & 1;
392 tmp64 = ldq_raw(hwpcb + 56);
393 tmp64 &= ~0x8000000000000000ULL;
394 tmp64 |= (val & 1) << 63;
395 stq_raw(hwpcb + 56, tmp64);
396 break;
397 case IPR_ESP:
398 if (env->features & FEATURE_SPS)
399 env->ipr[IPR_ESP] = val;
400 else
401 stq_raw(hwpcb + 8, val);
402 break;
403 case IPR_FEN:
404 env->ipr[IPR_FEN] = val & 1;
405 tmp64 = ldq_raw(hwpcb + 56);
406 tmp64 &= ~1;
407 tmp64 |= val & 1;
408 stq_raw(hwpcb + 56, tmp64);
409 break;
410 case IPR_IPIR:
411 /* XXX: TODO: Send IRQ to CPU #ir[16] */
412 break;
413 case IPR_IPL:
414 *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
415 env->ipr[IPR_IPL] &= ~0x1F;
416 env->ipr[IPR_IPL] |= val & 0x1F;
417 /* XXX: may issue an interrupt or ASR _now_ */
418 ret = 1;
419 break;
420 case IPR_KSP:
421 if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
422 ret = -1;
423 } else {
424 if (env->features & FEATURE_SPS)
425 env->ipr[IPR_KSP] = val;
426 else
427 stq_raw(hwpcb + 0, val);
428 }
429 break;
430 case IPR_MCES:
431 env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
432 env->ipr[IPR_MCES] |= val & 0x18;
433 break;
434 case IPR_PERFMON:
435 /* Implementation specific */
436 *oldvalp = 0;
437 ret = 1;
438 break;
439 case IPR_PCBB:
440 /* Read-only */
441 ret = -1;
442 break;
443 case IPR_PRBR:
444 env->ipr[IPR_PRBR] = val;
445 break;
446 case IPR_PTBR:
447 /* Read-only */
448 ret = -1;
449 break;
450 case IPR_SCBB:
451 env->ipr[IPR_SCBB] = (uint32_t)val;
452 break;
453 case IPR_SIRR:
454 if (val & 0xF) {
455 env->ipr[IPR_SISR] |= 1 << (val & 0xF);
456 /* XXX: request a software interrupt _now_ */
457 }
458 break;
459 case IPR_SISR:
460 /* Read-only */
461 ret = -1;
462 break;
463 case IPR_SSP:
464 if (env->features & FEATURE_SPS)
465 env->ipr[IPR_SSP] = val;
466 else
467 stq_raw(hwpcb + 16, val);
468 break;
469 case IPR_SYSPTBR:
470 if (env->features & FEATURE_VIRBND)
471 env->ipr[IPR_SYSPTBR] = val;
472 else
473 ret = -1;
474 case IPR_TBCHK:
475 /* Read-only */
476 ret = -1;
477 break;
478 case IPR_TBIA:
479 tlb_flush(env, 1);
480 break;
481 case IPR_TBIAP:
482 tlb_flush(env, 1);
483 break;
484 case IPR_TBIS:
485 tlb_flush_page(env, val);
486 break;
487 case IPR_TBISD:
488 tlb_flush_page(env, val);
489 break;
490 case IPR_TBISI:
491 tlb_flush_page(env, val);
492 break;
493 case IPR_USP:
494 if (env->features & FEATURE_SPS)
495 env->ipr[IPR_USP] = val;
496 else
497 stq_raw(hwpcb + 24, val);
498 break;
499 case IPR_VIRBND:
500 if (env->features & FEATURE_VIRBND)
501 env->ipr[IPR_VIRBND] = val;
502 else
503 ret = -1;
504 break;
505 case IPR_VPTB:
506 env->ipr[IPR_VPTB] = val;
507 break;
508 case IPR_WHAMI:
509 /* Read-only */
510 ret = -1;
511 break;
512 default:
513 /* Invalid */
514 ret = -1;
515 break;
516 }
517
518 return ret;
519}
520
521void do_interrupt (CPUState *env)
522{
523 int excp;
524
525 env->ipr[IPR_EXC_ADDR] = env->pc | 1;
526 excp = env->exception_index;
ee0dc6d3 527 env->exception_index = -1;
4c9649a9
JM
528 env->error_code = 0;
529 /* XXX: disable interrupts and memory mapping */
530 if (env->ipr[IPR_PAL_BASE] != -1ULL) {
531 /* We use native PALcode */
532 env->pc = env->ipr[IPR_PAL_BASE] + excp;
533 } else {
534 /* We use emulated PALcode */
535 call_pal(env);
536 /* Emulate REI */
537 env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
538 env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
539 /* XXX: re-enable interrupts and memory mapping */
540 }
541}
542#endif
543
5fafdf24 544void cpu_dump_state (CPUState *env, FILE *f,
4c9649a9
JM
545 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
546 int flags)
547{
b55266b5 548 static const char *linux_reg_names[] = {
4c9649a9
JM
549 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
550 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
551 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
552 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
553 };
554 int i;
555
556 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
557 env->pc, env->ps);
558 for (i = 0; i < 31; i++) {
559 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
560 linux_reg_names[i], env->ir[i]);
561 if ((i % 3) == 2)
562 cpu_fprintf(f, "\n");
563 }
564 cpu_fprintf(f, "\n");
565 for (i = 0; i < 31; i++) {
566 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
567 *((uint64_t *)(&env->fir[i])));
568 if ((i % 3) == 2)
569 cpu_fprintf(f, "\n");
570 }
57a92c8e 571 cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock);
4c9649a9 572}