]> git.proxmox.com Git - qemu.git/blob - target-alpha/helper.c
target-alpha: Use non-inverted arguments to gen_{f}cmov.
[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 void do_interrupt (CPUState *env)
177 {
178 env->exception_index = -1;
179 }
180
181 #else
182
183 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
184 {
185 return -1;
186 }
187
188 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
189 int mmu_idx, int is_softmmu)
190 {
191 uint32_t opc;
192
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;
206 }
207 env->ipr[IPR_MM_STAT] = opc;
208 }
209
210 return 1;
211 }
212
213 int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
214 {
215 uint64_t hwpcb;
216 int ret = 0;
217
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);
260 }
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;
306 }
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;
350 }
351
352 return ret;
353 }
354
355 int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
356 {
357 uint64_t hwpcb, tmp64;
358 uint8_t tmp8;
359 int ret = 0;
360
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);
423 }
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_ */
452 }
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 case IPR_TBCHK:
470 /* Read-only */
471 ret = -1;
472 break;
473 case IPR_TBIA:
474 tlb_flush(env, 1);
475 break;
476 case IPR_TBIAP:
477 tlb_flush(env, 1);
478 break;
479 case IPR_TBIS:
480 tlb_flush_page(env, val);
481 break;
482 case IPR_TBISD:
483 tlb_flush_page(env, val);
484 break;
485 case IPR_TBISI:
486 tlb_flush_page(env, val);
487 break;
488 case IPR_USP:
489 if (env->features & FEATURE_SPS)
490 env->ipr[IPR_USP] = val;
491 else
492 stq_raw(hwpcb + 24, val);
493 break;
494 case IPR_VIRBND:
495 if (env->features & FEATURE_VIRBND)
496 env->ipr[IPR_VIRBND] = val;
497 else
498 ret = -1;
499 break;
500 case IPR_VPTB:
501 env->ipr[IPR_VPTB] = val;
502 break;
503 case IPR_WHAMI:
504 /* Read-only */
505 ret = -1;
506 break;
507 default:
508 /* Invalid */
509 ret = -1;
510 break;
511 }
512
513 return ret;
514 }
515
516 void do_interrupt (CPUState *env)
517 {
518 int excp;
519
520 env->ipr[IPR_EXC_ADDR] = env->pc | 1;
521 excp = env->exception_index;
522 env->exception_index = -1;
523 env->error_code = 0;
524 /* XXX: disable interrupts and memory mapping */
525 if (env->ipr[IPR_PAL_BASE] != -1ULL) {
526 /* We use native PALcode */
527 env->pc = env->ipr[IPR_PAL_BASE] + excp;
528 } else {
529 /* We use emulated PALcode */
530 call_pal(env);
531 /* Emulate REI */
532 env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
533 env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
534 /* XXX: re-enable interrupts and memory mapping */
535 }
536 }
537 #endif
538
539 void cpu_dump_state (CPUState *env, FILE *f,
540 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
541 int flags)
542 {
543 static const char *linux_reg_names[] = {
544 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
545 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
546 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
547 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
548 };
549 int i;
550
551 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
552 env->pc, env->ps);
553 for (i = 0; i < 31; i++) {
554 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
555 linux_reg_names[i], env->ir[i]);
556 if ((i % 3) == 2)
557 cpu_fprintf(f, "\n");
558 }
559 cpu_fprintf(f, "\n");
560 for (i = 0; i < 31; i++) {
561 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
562 *((uint64_t *)(&env->fir[i])));
563 if ((i % 3) == 2)
564 cpu_fprintf(f, "\n");
565 }
566 cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock);
567 }