kvm: move kvm to use memory notifiers
[qemu/aliguori-queue.git] / target-alpha / helper.c
blobbe7d37b0d9c07cdfd4b28ad617b5f44506bcacfe
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 ret = 0;
31 int flags, mask;
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;
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;
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;
65 return ret;
68 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
70 int round_mode, mask;
72 set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status);
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;
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 default: /* this avoids a gcc (< 4.4) warning */
99 round_mode = float_round_up;
100 break;
102 set_float_rounding_mode(round_mode, &env->fp_status);
105 #if defined(CONFIG_USER_ONLY)
107 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
108 int mmu_idx, int is_softmmu)
110 if (rw == 2)
111 env->exception_index = EXCP_ITB_MISS;
112 else
113 env->exception_index = EXCP_DFAULT;
114 env->ipr[IPR_EXC_ADDR] = address;
116 return 1;
119 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
121 return addr;
124 void do_interrupt (CPUState *env)
126 env->exception_index = -1;
129 #else
131 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
133 return -1;
136 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
137 int mmu_idx, int is_softmmu)
139 uint32_t opc;
141 if (rw == 2) {
142 /* Instruction translation buffer miss */
143 env->exception_index = EXCP_ITB_MISS;
144 } else {
145 if (env->ipr[IPR_EXC_ADDR] & 1)
146 env->exception_index = EXCP_DTB_MISS_PAL;
147 else
148 env->exception_index = EXCP_DTB_MISS_NATIVE;
149 opc = (ldl_code(env->pc) >> 21) << 4;
150 if (rw) {
151 opc |= 0x9;
152 } else {
153 opc |= 0x4;
155 env->ipr[IPR_MM_STAT] = opc;
158 return 1;
161 int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
163 uint64_t hwpcb;
164 int ret = 0;
166 hwpcb = env->ipr[IPR_PCBB];
167 switch (iprn) {
168 case IPR_ASN:
169 if (env->features & FEATURE_ASN)
170 *valp = env->ipr[IPR_ASN];
171 else
172 *valp = 0;
173 break;
174 case IPR_ASTEN:
175 *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
176 break;
177 case IPR_ASTSR:
178 *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
179 break;
180 case IPR_DATFX:
181 /* Write only */
182 ret = -1;
183 break;
184 case IPR_ESP:
185 if (env->features & FEATURE_SPS)
186 *valp = env->ipr[IPR_ESP];
187 else
188 *valp = ldq_raw(hwpcb + 8);
189 break;
190 case IPR_FEN:
191 *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
192 break;
193 case IPR_IPIR:
194 /* Write-only */
195 ret = -1;
196 break;
197 case IPR_IPL:
198 *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
199 break;
200 case IPR_KSP:
201 if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
202 ret = -1;
203 } else {
204 if (env->features & FEATURE_SPS)
205 *valp = env->ipr[IPR_KSP];
206 else
207 *valp = ldq_raw(hwpcb + 0);
209 break;
210 case IPR_MCES:
211 *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
212 break;
213 case IPR_PERFMON:
214 /* Implementation specific */
215 *valp = 0;
216 break;
217 case IPR_PCBB:
218 *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
219 break;
220 case IPR_PRBR:
221 *valp = env->ipr[IPR_PRBR];
222 break;
223 case IPR_PTBR:
224 *valp = env->ipr[IPR_PTBR];
225 break;
226 case IPR_SCBB:
227 *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
228 break;
229 case IPR_SIRR:
230 /* Write-only */
231 ret = -1;
232 break;
233 case IPR_SISR:
234 *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
235 case IPR_SSP:
236 if (env->features & FEATURE_SPS)
237 *valp = env->ipr[IPR_SSP];
238 else
239 *valp = ldq_raw(hwpcb + 16);
240 break;
241 case IPR_SYSPTBR:
242 if (env->features & FEATURE_VIRBND)
243 *valp = env->ipr[IPR_SYSPTBR];
244 else
245 ret = -1;
246 break;
247 case IPR_TBCHK:
248 if ((env->features & FEATURE_TBCHK)) {
249 /* XXX: TODO */
250 *valp = 0;
251 ret = -1;
252 } else {
253 ret = -1;
255 break;
256 case IPR_TBIA:
257 /* Write-only */
258 ret = -1;
259 break;
260 case IPR_TBIAP:
261 /* Write-only */
262 ret = -1;
263 break;
264 case IPR_TBIS:
265 /* Write-only */
266 ret = -1;
267 break;
268 case IPR_TBISD:
269 /* Write-only */
270 ret = -1;
271 break;
272 case IPR_TBISI:
273 /* Write-only */
274 ret = -1;
275 break;
276 case IPR_USP:
277 if (env->features & FEATURE_SPS)
278 *valp = env->ipr[IPR_USP];
279 else
280 *valp = ldq_raw(hwpcb + 24);
281 break;
282 case IPR_VIRBND:
283 if (env->features & FEATURE_VIRBND)
284 *valp = env->ipr[IPR_VIRBND];
285 else
286 ret = -1;
287 break;
288 case IPR_VPTB:
289 *valp = env->ipr[IPR_VPTB];
290 break;
291 case IPR_WHAMI:
292 *valp = env->ipr[IPR_WHAMI];
293 break;
294 default:
295 /* Invalid */
296 ret = -1;
297 break;
300 return ret;
303 int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
305 uint64_t hwpcb, tmp64;
306 uint8_t tmp8;
307 int ret = 0;
309 hwpcb = env->ipr[IPR_PCBB];
310 switch (iprn) {
311 case IPR_ASN:
312 /* Read-only */
313 ret = -1;
314 break;
315 case IPR_ASTEN:
316 tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
317 *oldvalp = tmp8;
318 tmp8 &= val & 0xF;
319 tmp8 |= (val >> 4) & 0xF;
320 env->ipr[IPR_ASTEN] &= ~0xF;
321 env->ipr[IPR_ASTEN] |= tmp8;
322 ret = 1;
323 break;
324 case IPR_ASTSR:
325 tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
326 *oldvalp = tmp8;
327 tmp8 &= val & 0xF;
328 tmp8 |= (val >> 4) & 0xF;
329 env->ipr[IPR_ASTSR] &= ~0xF;
330 env->ipr[IPR_ASTSR] |= tmp8;
331 ret = 1;
332 case IPR_DATFX:
333 env->ipr[IPR_DATFX] &= ~0x1;
334 env->ipr[IPR_DATFX] |= val & 1;
335 tmp64 = ldq_raw(hwpcb + 56);
336 tmp64 &= ~0x8000000000000000ULL;
337 tmp64 |= (val & 1) << 63;
338 stq_raw(hwpcb + 56, tmp64);
339 break;
340 case IPR_ESP:
341 if (env->features & FEATURE_SPS)
342 env->ipr[IPR_ESP] = val;
343 else
344 stq_raw(hwpcb + 8, val);
345 break;
346 case IPR_FEN:
347 env->ipr[IPR_FEN] = val & 1;
348 tmp64 = ldq_raw(hwpcb + 56);
349 tmp64 &= ~1;
350 tmp64 |= val & 1;
351 stq_raw(hwpcb + 56, tmp64);
352 break;
353 case IPR_IPIR:
354 /* XXX: TODO: Send IRQ to CPU #ir[16] */
355 break;
356 case IPR_IPL:
357 *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
358 env->ipr[IPR_IPL] &= ~0x1F;
359 env->ipr[IPR_IPL] |= val & 0x1F;
360 /* XXX: may issue an interrupt or ASR _now_ */
361 ret = 1;
362 break;
363 case IPR_KSP:
364 if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
365 ret = -1;
366 } else {
367 if (env->features & FEATURE_SPS)
368 env->ipr[IPR_KSP] = val;
369 else
370 stq_raw(hwpcb + 0, val);
372 break;
373 case IPR_MCES:
374 env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
375 env->ipr[IPR_MCES] |= val & 0x18;
376 break;
377 case IPR_PERFMON:
378 /* Implementation specific */
379 *oldvalp = 0;
380 ret = 1;
381 break;
382 case IPR_PCBB:
383 /* Read-only */
384 ret = -1;
385 break;
386 case IPR_PRBR:
387 env->ipr[IPR_PRBR] = val;
388 break;
389 case IPR_PTBR:
390 /* Read-only */
391 ret = -1;
392 break;
393 case IPR_SCBB:
394 env->ipr[IPR_SCBB] = (uint32_t)val;
395 break;
396 case IPR_SIRR:
397 if (val & 0xF) {
398 env->ipr[IPR_SISR] |= 1 << (val & 0xF);
399 /* XXX: request a software interrupt _now_ */
401 break;
402 case IPR_SISR:
403 /* Read-only */
404 ret = -1;
405 break;
406 case IPR_SSP:
407 if (env->features & FEATURE_SPS)
408 env->ipr[IPR_SSP] = val;
409 else
410 stq_raw(hwpcb + 16, val);
411 break;
412 case IPR_SYSPTBR:
413 if (env->features & FEATURE_VIRBND)
414 env->ipr[IPR_SYSPTBR] = val;
415 else
416 ret = -1;
417 case IPR_TBCHK:
418 /* Read-only */
419 ret = -1;
420 break;
421 case IPR_TBIA:
422 tlb_flush(env, 1);
423 break;
424 case IPR_TBIAP:
425 tlb_flush(env, 1);
426 break;
427 case IPR_TBIS:
428 tlb_flush_page(env, val);
429 break;
430 case IPR_TBISD:
431 tlb_flush_page(env, val);
432 break;
433 case IPR_TBISI:
434 tlb_flush_page(env, val);
435 break;
436 case IPR_USP:
437 if (env->features & FEATURE_SPS)
438 env->ipr[IPR_USP] = val;
439 else
440 stq_raw(hwpcb + 24, val);
441 break;
442 case IPR_VIRBND:
443 if (env->features & FEATURE_VIRBND)
444 env->ipr[IPR_VIRBND] = val;
445 else
446 ret = -1;
447 break;
448 case IPR_VPTB:
449 env->ipr[IPR_VPTB] = val;
450 break;
451 case IPR_WHAMI:
452 /* Read-only */
453 ret = -1;
454 break;
455 default:
456 /* Invalid */
457 ret = -1;
458 break;
461 return ret;
464 void do_interrupt (CPUState *env)
466 int excp;
468 env->ipr[IPR_EXC_ADDR] = env->pc | 1;
469 excp = env->exception_index;
470 env->exception_index = 0;
471 env->error_code = 0;
472 /* XXX: disable interrupts and memory mapping */
473 if (env->ipr[IPR_PAL_BASE] != -1ULL) {
474 /* We use native PALcode */
475 env->pc = env->ipr[IPR_PAL_BASE] + excp;
476 } else {
477 /* We use emulated PALcode */
478 call_pal(env);
479 /* Emulate REI */
480 env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
481 env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
482 /* XXX: re-enable interrupts and memory mapping */
485 #endif
487 void cpu_dump_state (CPUState *env, FILE *f,
488 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
489 int flags)
491 static const char *linux_reg_names[] = {
492 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
493 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
494 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
495 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
497 int i;
499 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
500 env->pc, env->ps);
501 for (i = 0; i < 31; i++) {
502 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
503 linux_reg_names[i], env->ir[i]);
504 if ((i % 3) == 2)
505 cpu_fprintf(f, "\n");
507 cpu_fprintf(f, "\n");
508 for (i = 0; i < 31; i++) {
509 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
510 *((uint64_t *)(&env->fir[i])));
511 if ((i % 3) == 2)
512 cpu_fprintf(f, "\n");
514 cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock);