xref: /illumos-kvm-cmd/target-alpha/helper.c (revision 68396ea9)
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 
cpu_alpha_load_fpcr(CPUState * env)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 
cpu_alpha_store_fpcr(CPUState * env,uint64_t val)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 
cpu_alpha_handle_mmu_fault(CPUState * env,target_ulong address,int rw,int mmu_idx,int is_softmmu)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 
do_interrupt(CPUState * env)176 void do_interrupt (CPUState *env)
177 {
178     env->exception_index = -1;
179 }
180 
181 #else
182 
cpu_get_phys_page_debug(CPUState * env,target_ulong addr)183 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
184 {
185     return -1;
186 }
187 
cpu_alpha_handle_mmu_fault(CPUState * env,target_ulong address,int rw,int mmu_idx,int is_softmmu)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 
cpu_alpha_mfpr(CPUState * env,int iprn,uint64_t * valp)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 
cpu_alpha_mtpr(CPUState * env,int iprn,uint64_t val,uint64_t * oldvalp)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         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;
512     }
513 
514     return ret;
515 }
516 
do_interrupt(CPUState * env)517 void do_interrupt (CPUState *env)
518 {
519     int excp;
520 
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 */
536     }
537 }
538 #endif
539 
cpu_dump_state(CPUState * env,FILE * f,fprintf_function cpu_fprintf,int flags)540 void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
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 
560     cpu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
561                 env->lock_addr, env->lock_value);
562 
563     for (i = 0; i < 31; i++) {
564         cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
565                     *((uint64_t *)(&env->fir[i])));
566         if ((i % 3) == 2)
567             cpu_fprintf(f, "\n");
568     }
569     cpu_fprintf(f, "\n");
570 }
571