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