]> git.proxmox.com Git - qemu.git/blob - target-alpha/helper.c
target-alpha: Mark helper_excp as NORETURN.
[qemu.git] / target-alpha / helper.c
1 /*
2 * Alpha emulation cpu helpers for qemu.
3 *
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
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23
24 #include "cpu.h"
25 #include "exec-all.h"
26 #include "softfloat.h"
27
28 uint64_t cpu_alpha_load_fpcr (CPUState *env)
29 {
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) {
71 case float_round_nearest_even:
72 r |= FPCR_DYN_NORMAL;
73 break;
74 case float_round_down:
75 r |= FPCR_DYN_MINUS;
76 break;
77 case float_round_up:
78 r |= FPCR_DYN_PLUS;
79 break;
80 case float_round_to_zero:
81 r |= FPCR_DYN_CHOPPED;
82 break;
83 }
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;
96 }
97
98 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
99 {
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;
141 break;
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
144 break;
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
147 break;
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
150 break;
151 }
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;
160 }
161
162 #if defined(CONFIG_USER_ONLY)
163
164 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
165 int mmu_idx, int is_softmmu)
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;
172
173 return 1;
174 }
175
176 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
177 {
178 return addr;
179 }
180
181 void do_interrupt (CPUState *env)
182 {
183 env->exception_index = -1;
184 }
185
186 #else
187
188 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
189 {
190 return -1;
191 }
192
193 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
194 int mmu_idx, int is_softmmu)
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
218 int 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
360 int 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
521 void do_interrupt (CPUState *env)
522 {
523 int excp;
524
525 env->ipr[IPR_EXC_ADDR] = env->pc | 1;
526 excp = env->exception_index;
527 env->exception_index = -1;
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
544 void cpu_dump_state (CPUState *env, FILE *f,
545 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
546 int flags)
547 {
548 static const char *linux_reg_names[] = {
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 }
571 cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock);
572 }