Merge remote branch 'qmp/for-anthony' into staging
[qemu.git] / target-alpha / helper.c
blob9a039cb96b1ae7ad0722643b1cd2a861b27c1edf
1 /*
2 * Alpha emulation cpu helpers for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
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.
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.
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/>.
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
24 #include "cpu.h"
25 #include "exec-all.h"
26 #include "softfloat.h"
28 uint64_t cpu_alpha_load_fpcr (CPUState *env)
30 uint64_t r = 0;
31 uint8_t t;
33 t = env->fpcr_exc_status;
34 if (t) {
35 r = FPCR_SUM;
36 if (t & float_flag_invalid) {
37 r |= FPCR_INV;
39 if (t & float_flag_divbyzero) {
40 r |= FPCR_DZE;
42 if (t & float_flag_overflow) {
43 r |= FPCR_OVF;
45 if (t & float_flag_underflow) {
46 r |= FPCR_UNF;
48 if (t & float_flag_inexact) {
49 r |= FPCR_INE;
53 t = env->fpcr_exc_mask;
54 if (t & float_flag_invalid) {
55 r |= FPCR_INVD;
57 if (t & float_flag_divbyzero) {
58 r |= FPCR_DZED;
60 if (t & float_flag_overflow) {
61 r |= FPCR_OVFD;
63 if (t & float_flag_underflow) {
64 r |= FPCR_UNFD;
66 if (t & float_flag_inexact) {
67 r |= FPCR_INED;
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;
85 if (env->fpcr_dnz) {
86 r |= FPCR_DNZ;
88 if (env->fpcr_dnod) {
89 r |= FPCR_DNOD;
91 if (env->fpcr_undz) {
92 r |= FPCR_UNDZ;
95 return r;
98 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
100 uint8_t t;
102 t = 0;
103 if (val & FPCR_INV) {
104 t |= float_flag_invalid;
106 if (val & FPCR_DZE) {
107 t |= float_flag_divbyzero;
109 if (val & FPCR_OVF) {
110 t |= float_flag_overflow;
112 if (val & FPCR_UNF) {
113 t |= float_flag_underflow;
115 if (val & FPCR_INE) {
116 t |= float_flag_inexact;
118 env->fpcr_exc_status = t;
120 t = 0;
121 if (val & FPCR_INVD) {
122 t |= float_flag_invalid;
124 if (val & FPCR_DZED) {
125 t |= float_flag_divbyzero;
127 if (val & FPCR_OVFD) {
128 t |= float_flag_overflow;
130 if (val & FPCR_UNFD) {
131 t |= float_flag_underflow;
133 if (val & FPCR_INED) {
134 t |= float_flag_inexact;
136 env->fpcr_exc_mask = t;
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;
152 env->fpcr_dyn_round = t;
154 env->fpcr_flush_to_zero
155 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
157 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
162 #if defined(CONFIG_USER_ONLY)
164 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
165 int mmu_idx, int is_softmmu)
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;
173 return 1;
176 void do_interrupt (CPUState *env)
178 env->exception_index = -1;
181 #else
183 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
185 return -1;
188 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
189 int mmu_idx, int is_softmmu)
191 uint32_t opc;
193 if (rw == 2) {
194 /* Instruction translation buffer miss */
195 env->exception_index = EXCP_ITB_MISS;
196 } else {
197 if (env->ipr[IPR_EXC_ADDR] & 1)
198 env->exception_index = EXCP_DTB_MISS_PAL;
199 else
200 env->exception_index = EXCP_DTB_MISS_NATIVE;
201 opc = (ldl_code(env->pc) >> 21) << 4;
202 if (rw) {
203 opc |= 0x9;
204 } else {
205 opc |= 0x4;
207 env->ipr[IPR_MM_STAT] = opc;
210 return 1;
213 int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
215 uint64_t hwpcb;
216 int ret = 0;
218 hwpcb = env->ipr[IPR_PCBB];
219 switch (iprn) {
220 case IPR_ASN:
221 if (env->features & FEATURE_ASN)
222 *valp = env->ipr[IPR_ASN];
223 else
224 *valp = 0;
225 break;
226 case IPR_ASTEN:
227 *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
228 break;
229 case IPR_ASTSR:
230 *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
231 break;
232 case IPR_DATFX:
233 /* Write only */
234 ret = -1;
235 break;
236 case IPR_ESP:
237 if (env->features & FEATURE_SPS)
238 *valp = env->ipr[IPR_ESP];
239 else
240 *valp = ldq_raw(hwpcb + 8);
241 break;
242 case IPR_FEN:
243 *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
244 break;
245 case IPR_IPIR:
246 /* Write-only */
247 ret = -1;
248 break;
249 case IPR_IPL:
250 *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
251 break;
252 case IPR_KSP:
253 if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
254 ret = -1;
255 } else {
256 if (env->features & FEATURE_SPS)
257 *valp = env->ipr[IPR_KSP];
258 else
259 *valp = ldq_raw(hwpcb + 0);
261 break;
262 case IPR_MCES:
263 *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
264 break;
265 case IPR_PERFMON:
266 /* Implementation specific */
267 *valp = 0;
268 break;
269 case IPR_PCBB:
270 *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
271 break;
272 case IPR_PRBR:
273 *valp = env->ipr[IPR_PRBR];
274 break;
275 case IPR_PTBR:
276 *valp = env->ipr[IPR_PTBR];
277 break;
278 case IPR_SCBB:
279 *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
280 break;
281 case IPR_SIRR:
282 /* Write-only */
283 ret = -1;
284 break;
285 case IPR_SISR:
286 *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
287 case IPR_SSP:
288 if (env->features & FEATURE_SPS)
289 *valp = env->ipr[IPR_SSP];
290 else
291 *valp = ldq_raw(hwpcb + 16);
292 break;
293 case IPR_SYSPTBR:
294 if (env->features & FEATURE_VIRBND)
295 *valp = env->ipr[IPR_SYSPTBR];
296 else
297 ret = -1;
298 break;
299 case IPR_TBCHK:
300 if ((env->features & FEATURE_TBCHK)) {
301 /* XXX: TODO */
302 *valp = 0;
303 ret = -1;
304 } else {
305 ret = -1;
307 break;
308 case IPR_TBIA:
309 /* Write-only */
310 ret = -1;
311 break;
312 case IPR_TBIAP:
313 /* Write-only */
314 ret = -1;
315 break;
316 case IPR_TBIS:
317 /* Write-only */
318 ret = -1;
319 break;
320 case IPR_TBISD:
321 /* Write-only */
322 ret = -1;
323 break;
324 case IPR_TBISI:
325 /* Write-only */
326 ret = -1;
327 break;
328 case IPR_USP:
329 if (env->features & FEATURE_SPS)
330 *valp = env->ipr[IPR_USP];
331 else
332 *valp = ldq_raw(hwpcb + 24);
333 break;
334 case IPR_VIRBND:
335 if (env->features & FEATURE_VIRBND)
336 *valp = env->ipr[IPR_VIRBND];
337 else
338 ret = -1;
339 break;
340 case IPR_VPTB:
341 *valp = env->ipr[IPR_VPTB];
342 break;
343 case IPR_WHAMI:
344 *valp = env->ipr[IPR_WHAMI];
345 break;
346 default:
347 /* Invalid */
348 ret = -1;
349 break;
352 return ret;
355 int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
357 uint64_t hwpcb, tmp64;
358 uint8_t tmp8;
359 int ret = 0;
361 hwpcb = env->ipr[IPR_PCBB];
362 switch (iprn) {
363 case IPR_ASN:
364 /* Read-only */
365 ret = -1;
366 break;
367 case IPR_ASTEN:
368 tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
369 *oldvalp = tmp8;
370 tmp8 &= val & 0xF;
371 tmp8 |= (val >> 4) & 0xF;
372 env->ipr[IPR_ASTEN] &= ~0xF;
373 env->ipr[IPR_ASTEN] |= tmp8;
374 ret = 1;
375 break;
376 case IPR_ASTSR:
377 tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
378 *oldvalp = tmp8;
379 tmp8 &= val & 0xF;
380 tmp8 |= (val >> 4) & 0xF;
381 env->ipr[IPR_ASTSR] &= ~0xF;
382 env->ipr[IPR_ASTSR] |= tmp8;
383 ret = 1;
384 case IPR_DATFX:
385 env->ipr[IPR_DATFX] &= ~0x1;
386 env->ipr[IPR_DATFX] |= val & 1;
387 tmp64 = ldq_raw(hwpcb + 56);
388 tmp64 &= ~0x8000000000000000ULL;
389 tmp64 |= (val & 1) << 63;
390 stq_raw(hwpcb + 56, tmp64);
391 break;
392 case IPR_ESP:
393 if (env->features & FEATURE_SPS)
394 env->ipr[IPR_ESP] = val;
395 else
396 stq_raw(hwpcb + 8, val);
397 break;
398 case IPR_FEN:
399 env->ipr[IPR_FEN] = val & 1;
400 tmp64 = ldq_raw(hwpcb + 56);
401 tmp64 &= ~1;
402 tmp64 |= val & 1;
403 stq_raw(hwpcb + 56, tmp64);
404 break;
405 case IPR_IPIR:
406 /* XXX: TODO: Send IRQ to CPU #ir[16] */
407 break;
408 case IPR_IPL:
409 *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
410 env->ipr[IPR_IPL] &= ~0x1F;
411 env->ipr[IPR_IPL] |= val & 0x1F;
412 /* XXX: may issue an interrupt or ASR _now_ */
413 ret = 1;
414 break;
415 case IPR_KSP:
416 if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
417 ret = -1;
418 } else {
419 if (env->features & FEATURE_SPS)
420 env->ipr[IPR_KSP] = val;
421 else
422 stq_raw(hwpcb + 0, val);
424 break;
425 case IPR_MCES:
426 env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
427 env->ipr[IPR_MCES] |= val & 0x18;
428 break;
429 case IPR_PERFMON:
430 /* Implementation specific */
431 *oldvalp = 0;
432 ret = 1;
433 break;
434 case IPR_PCBB:
435 /* Read-only */
436 ret = -1;
437 break;
438 case IPR_PRBR:
439 env->ipr[IPR_PRBR] = val;
440 break;
441 case IPR_PTBR:
442 /* Read-only */
443 ret = -1;
444 break;
445 case IPR_SCBB:
446 env->ipr[IPR_SCBB] = (uint32_t)val;
447 break;
448 case IPR_SIRR:
449 if (val & 0xF) {
450 env->ipr[IPR_SISR] |= 1 << (val & 0xF);
451 /* XXX: request a software interrupt _now_ */
453 break;
454 case IPR_SISR:
455 /* Read-only */
456 ret = -1;
457 break;
458 case IPR_SSP:
459 if (env->features & FEATURE_SPS)
460 env->ipr[IPR_SSP] = val;
461 else
462 stq_raw(hwpcb + 16, val);
463 break;
464 case IPR_SYSPTBR:
465 if (env->features & FEATURE_VIRBND)
466 env->ipr[IPR_SYSPTBR] = val;
467 else
468 ret = -1;
469 break;
470 case IPR_TBCHK:
471 /* Read-only */
472 ret = -1;
473 break;
474 case IPR_TBIA:
475 tlb_flush(env, 1);
476 break;
477 case IPR_TBIAP:
478 tlb_flush(env, 1);
479 break;
480 case IPR_TBIS:
481 tlb_flush_page(env, val);
482 break;
483 case IPR_TBISD:
484 tlb_flush_page(env, val);
485 break;
486 case IPR_TBISI:
487 tlb_flush_page(env, val);
488 break;
489 case IPR_USP:
490 if (env->features & FEATURE_SPS)
491 env->ipr[IPR_USP] = val;
492 else
493 stq_raw(hwpcb + 24, val);
494 break;
495 case IPR_VIRBND:
496 if (env->features & FEATURE_VIRBND)
497 env->ipr[IPR_VIRBND] = val;
498 else
499 ret = -1;
500 break;
501 case IPR_VPTB:
502 env->ipr[IPR_VPTB] = val;
503 break;
504 case IPR_WHAMI:
505 /* Read-only */
506 ret = -1;
507 break;
508 default:
509 /* Invalid */
510 ret = -1;
511 break;
514 return ret;
517 void do_interrupt (CPUState *env)
519 int excp;
521 env->ipr[IPR_EXC_ADDR] = env->pc | 1;
522 excp = env->exception_index;
523 env->exception_index = -1;
524 env->error_code = 0;
525 /* XXX: disable interrupts and memory mapping */
526 if (env->ipr[IPR_PAL_BASE] != -1ULL) {
527 /* We use native PALcode */
528 env->pc = env->ipr[IPR_PAL_BASE] + excp;
529 } else {
530 /* We use emulated PALcode */
531 call_pal(env);
532 /* Emulate REI */
533 env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
534 env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
535 /* XXX: re-enable interrupts and memory mapping */
538 #endif
540 void cpu_dump_state (CPUState *env, FILE *f,
541 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
542 int flags)
544 static const char *linux_reg_names[] = {
545 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
546 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
547 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
548 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
550 int i;
552 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
553 env->pc, env->ps);
554 for (i = 0; i < 31; i++) {
555 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
556 linux_reg_names[i], env->ir[i]);
557 if ((i % 3) == 2)
558 cpu_fprintf(f, "\n");
560 cpu_fprintf(f, "\n");
561 for (i = 0; i < 31; i++) {
562 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
563 *((uint64_t *)(&env->fir[i])));
564 if ((i % 3) == 2)
565 cpu_fprintf(f, "\n");
567 cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock);