]>
Commit | Line | Data |
---|---|---|
4c9649a9 JM |
1 | /* |
2 | * Alpha emulation cpu micro-operations 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 | |
17 | * License along with this library; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | #include "exec.h" | |
603fccce | 22 | #include "host-utils.h" |
4c9649a9 JM |
23 | #include "softfloat.h" |
24 | ||
25 | #include "op_helper.h" | |
26 | ||
27 | #define MEMSUFFIX _raw | |
28 | #include "op_helper_mem.h" | |
29 | ||
30 | #if !defined(CONFIG_USER_ONLY) | |
b1806c9e | 31 | #define MEMSUFFIX _kernel |
4c9649a9 JM |
32 | #include "op_helper_mem.h" |
33 | ||
b1806c9e JM |
34 | #define MEMSUFFIX _executive |
35 | #include "op_helper_mem.h" | |
36 | ||
37 | #define MEMSUFFIX _supervisor | |
38 | #include "op_helper_mem.h" | |
39 | ||
40 | #define MEMSUFFIX _user | |
4c9649a9 JM |
41 | #include "op_helper_mem.h" |
42 | ||
b1806c9e | 43 | /* This is used for pal modes */ |
4c9649a9 JM |
44 | #define MEMSUFFIX _data |
45 | #include "op_helper_mem.h" | |
46 | #endif | |
47 | ||
48 | void helper_tb_flush (void) | |
49 | { | |
50 | tlb_flush(env, 1); | |
51 | } | |
52 | ||
53 | void cpu_dump_EA (target_ulong EA); | |
54 | void helper_print_mem_EA (target_ulong EA) | |
55 | { | |
56 | cpu_dump_EA(EA); | |
57 | } | |
58 | ||
59 | /*****************************************************************************/ | |
60 | /* Exceptions processing helpers */ | |
61 | void helper_excp (uint32_t excp, uint32_t error) | |
62 | { | |
63 | env->exception_index = excp; | |
64 | env->error_code = error; | |
65 | cpu_loop_exit(); | |
66 | } | |
67 | ||
68 | void helper_amask (void) | |
69 | { | |
70 | switch (env->implver) { | |
71 | case IMPLVER_2106x: | |
72 | /* EV4, EV45, LCA, LCA45 & EV5 */ | |
73 | break; | |
74 | case IMPLVER_21164: | |
75 | case IMPLVER_21264: | |
76 | case IMPLVER_21364: | |
77 | T0 &= ~env->amask; | |
78 | break; | |
79 | } | |
80 | } | |
81 | ||
82 | void helper_load_pcc (void) | |
83 | { | |
84 | /* XXX: TODO */ | |
85 | T0 = 0; | |
86 | } | |
87 | ||
88 | void helper_load_implver (void) | |
89 | { | |
90 | T0 = env->implver; | |
91 | } | |
92 | ||
93 | void helper_load_fpcr (void) | |
94 | { | |
95 | T0 = 0; | |
96 | #ifdef CONFIG_SOFTFLOAT | |
97 | T0 |= env->fp_status.float_exception_flags << 52; | |
98 | if (env->fp_status.float_exception_flags) | |
99 | T0 |= 1ULL << 63; | |
100 | env->ipr[IPR_EXC_SUM] &= ~0x3E: | |
101 | env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1; | |
102 | #endif | |
103 | switch (env->fp_status.float_rounding_mode) { | |
104 | case float_round_nearest_even: | |
105 | T0 |= 2ULL << 58; | |
106 | break; | |
107 | case float_round_down: | |
108 | T0 |= 1ULL << 58; | |
109 | break; | |
110 | case float_round_up: | |
111 | T0 |= 3ULL << 58; | |
112 | break; | |
113 | case float_round_to_zero: | |
114 | break; | |
115 | } | |
116 | } | |
117 | ||
118 | void helper_store_fpcr (void) | |
119 | { | |
120 | #ifdef CONFIG_SOFTFLOAT | |
121 | set_float_exception_flags((T0 >> 52) & 0x3F, &FP_STATUS); | |
122 | #endif | |
123 | switch ((T0 >> 58) & 3) { | |
124 | case 0: | |
125 | set_float_rounding_mode(float_round_to_zero, &FP_STATUS); | |
126 | break; | |
127 | case 1: | |
128 | set_float_rounding_mode(float_round_down, &FP_STATUS); | |
129 | break; | |
130 | case 2: | |
131 | set_float_rounding_mode(float_round_nearest_even, &FP_STATUS); | |
132 | break; | |
133 | case 3: | |
134 | set_float_rounding_mode(float_round_up, &FP_STATUS); | |
135 | break; | |
136 | } | |
137 | } | |
138 | ||
139 | void helper_load_irf (void) | |
140 | { | |
141 | /* XXX: TODO */ | |
142 | T0 = 0; | |
143 | } | |
144 | ||
145 | void helper_set_irf (void) | |
146 | { | |
147 | /* XXX: TODO */ | |
148 | } | |
149 | ||
150 | void helper_clear_irf (void) | |
151 | { | |
152 | /* XXX: TODO */ | |
153 | } | |
154 | ||
155 | void helper_addqv (void) | |
156 | { | |
157 | T2 = T0; | |
158 | T0 += T1; | |
159 | if (unlikely((T2 ^ T1 ^ (-1ULL)) & (T2 ^ T0) & (1ULL << 63))) { | |
160 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); | |
161 | } | |
162 | } | |
163 | ||
164 | void helper_addlv (void) | |
165 | { | |
166 | T2 = T0; | |
167 | T0 = (uint32_t)(T0 + T1); | |
168 | if (unlikely((T2 ^ T1 ^ (-1UL)) & (T2 ^ T0) & (1UL << 31))) { | |
169 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); | |
170 | } | |
171 | } | |
172 | ||
173 | void helper_subqv (void) | |
174 | { | |
175 | T2 = T0; | |
176 | T0 -= T1; | |
177 | if (unlikely(((~T2) ^ T0 ^ (-1ULL)) & ((~T2) ^ T1) & (1ULL << 63))) { | |
178 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); | |
179 | } | |
180 | } | |
181 | ||
182 | void helper_sublv (void) | |
183 | { | |
184 | T2 = T0; | |
185 | T0 = (uint32_t)(T0 - T1); | |
186 | if (unlikely(((~T2) ^ T0 ^ (-1UL)) & ((~T2) ^ T1) & (1UL << 31))) { | |
187 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); | |
188 | } | |
189 | } | |
190 | ||
191 | void helper_mullv (void) | |
192 | { | |
193 | int64_t res = (int64_t)T0 * (int64_t)T1; | |
194 | ||
195 | if (unlikely((int32_t)res != res)) { | |
196 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); | |
197 | } | |
198 | T0 = (int64_t)((int32_t)res); | |
199 | } | |
200 | ||
201 | void helper_mulqv () | |
202 | { | |
e14fe0a9 JM |
203 | uint64_t tl, th; |
204 | ||
205 | muls64(&tl, &th, T0, T1); | |
206 | /* If th != 0 && th != -1, then we had an overflow */ | |
207 | if (unlikely((th + 1) > 1)) { | |
4c9649a9 JM |
208 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); |
209 | } | |
e14fe0a9 | 210 | T0 = tl; |
4c9649a9 JM |
211 | } |
212 | ||
213 | void helper_ctpop (void) | |
214 | { | |
603fccce | 215 | T0 = ctpop64(T0); |
4c9649a9 JM |
216 | } |
217 | ||
218 | void helper_ctlz (void) | |
219 | { | |
603fccce | 220 | T0 = clz64(T0); |
4c9649a9 JM |
221 | } |
222 | ||
223 | void helper_cttz (void) | |
224 | { | |
603fccce | 225 | T0 = ctz64(T0); |
4c9649a9 JM |
226 | } |
227 | ||
f071b4d3 | 228 | static always_inline uint64_t byte_zap (uint64_t op, uint8_t mskb) |
4c9649a9 JM |
229 | { |
230 | uint64_t mask; | |
231 | ||
232 | mask = 0; | |
233 | mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL; | |
234 | mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL; | |
235 | mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL; | |
236 | mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL; | |
237 | mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL; | |
238 | mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL; | |
239 | mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL; | |
240 | mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL; | |
241 | ||
242 | return op & ~mask; | |
243 | } | |
244 | ||
245 | void helper_mskbl (void) | |
246 | { | |
247 | T0 = byte_zap(T0, 0x01 << (T1 & 7)); | |
248 | } | |
249 | ||
250 | void helper_extbl (void) | |
251 | { | |
252 | T0 >>= (T1 & 7) * 8; | |
253 | T0 = byte_zap(T0, 0xFE); | |
254 | } | |
255 | ||
256 | void helper_insbl (void) | |
257 | { | |
258 | T0 <<= (T1 & 7) * 8; | |
259 | T0 = byte_zap(T0, ~(0x01 << (T1 & 7))); | |
260 | } | |
261 | ||
262 | void helper_mskwl (void) | |
263 | { | |
264 | T0 = byte_zap(T0, 0x03 << (T1 & 7)); | |
265 | } | |
266 | ||
267 | void helper_extwl (void) | |
268 | { | |
269 | T0 >>= (T1 & 7) * 8; | |
270 | T0 = byte_zap(T0, 0xFC); | |
271 | } | |
272 | ||
273 | void helper_inswl (void) | |
274 | { | |
275 | T0 <<= (T1 & 7) * 8; | |
276 | T0 = byte_zap(T0, ~(0x03 << (T1 & 7))); | |
277 | } | |
278 | ||
279 | void helper_mskll (void) | |
280 | { | |
281 | T0 = byte_zap(T0, 0x0F << (T1 & 7)); | |
282 | } | |
283 | ||
284 | void helper_extll (void) | |
285 | { | |
286 | T0 >>= (T1 & 7) * 8; | |
287 | T0 = byte_zap(T0, 0xF0); | |
288 | } | |
289 | ||
290 | void helper_insll (void) | |
291 | { | |
292 | T0 <<= (T1 & 7) * 8; | |
293 | T0 = byte_zap(T0, ~(0x0F << (T1 & 7))); | |
294 | } | |
295 | ||
296 | void helper_zap (void) | |
297 | { | |
298 | T0 = byte_zap(T0, T1); | |
299 | } | |
300 | ||
301 | void helper_zapnot (void) | |
302 | { | |
303 | T0 = byte_zap(T0, ~T1); | |
304 | } | |
305 | ||
306 | void helper_mskql (void) | |
307 | { | |
308 | T0 = byte_zap(T0, 0xFF << (T1 & 7)); | |
309 | } | |
310 | ||
311 | void helper_extql (void) | |
312 | { | |
313 | T0 >>= (T1 & 7) * 8; | |
314 | T0 = byte_zap(T0, 0x00); | |
315 | } | |
316 | ||
317 | void helper_insql (void) | |
318 | { | |
319 | T0 <<= (T1 & 7) * 8; | |
320 | T0 = byte_zap(T0, ~(0xFF << (T1 & 7))); | |
321 | } | |
322 | ||
323 | void helper_mskwh (void) | |
324 | { | |
325 | T0 = byte_zap(T0, (0x03 << (T1 & 7)) >> 8); | |
326 | } | |
327 | ||
328 | void helper_inswh (void) | |
329 | { | |
330 | T0 >>= 64 - ((T1 & 7) * 8); | |
331 | T0 = byte_zap(T0, ~((0x03 << (T1 & 7)) >> 8)); | |
332 | } | |
333 | ||
334 | void helper_extwh (void) | |
335 | { | |
336 | T0 <<= 64 - ((T1 & 7) * 8); | |
337 | T0 = byte_zap(T0, ~0x07); | |
338 | } | |
339 | ||
340 | void helper_msklh (void) | |
341 | { | |
342 | T0 = byte_zap(T0, (0x0F << (T1 & 7)) >> 8); | |
343 | } | |
344 | ||
345 | void helper_inslh (void) | |
346 | { | |
347 | T0 >>= 64 - ((T1 & 7) * 8); | |
348 | T0 = byte_zap(T0, ~((0x0F << (T1 & 7)) >> 8)); | |
349 | } | |
350 | ||
351 | void helper_extlh (void) | |
352 | { | |
353 | T0 <<= 64 - ((T1 & 7) * 8); | |
354 | T0 = byte_zap(T0, ~0x0F); | |
355 | } | |
356 | ||
357 | void helper_mskqh (void) | |
358 | { | |
359 | T0 = byte_zap(T0, (0xFF << (T1 & 7)) >> 8); | |
360 | } | |
361 | ||
362 | void helper_insqh (void) | |
363 | { | |
364 | T0 >>= 64 - ((T1 & 7) * 8); | |
365 | T0 = byte_zap(T0, ~((0xFF << (T1 & 7)) >> 8)); | |
366 | } | |
367 | ||
368 | void helper_extqh (void) | |
369 | { | |
370 | T0 <<= 64 - ((T1 & 7) * 8); | |
371 | T0 = byte_zap(T0, 0x00); | |
372 | } | |
373 | ||
374 | void helper_cmpbge (void) | |
375 | { | |
376 | uint8_t opa, opb, res; | |
377 | int i; | |
378 | ||
379 | res = 0; | |
380 | for (i = 0; i < 7; i++) { | |
381 | opa = T0 >> (i * 8); | |
382 | opb = T1 >> (i * 8); | |
383 | if (opa >= opb) | |
384 | res |= 1 << i; | |
385 | } | |
386 | T0 = res; | |
387 | } | |
388 | ||
389 | void helper_cmov_fir (int freg) | |
390 | { | |
391 | if (FT0 != 0) | |
392 | env->fir[freg] = FT1; | |
393 | } | |
394 | ||
395 | void helper_sqrts (void) | |
396 | { | |
397 | FT0 = float32_sqrt(FT0, &FP_STATUS); | |
398 | } | |
399 | ||
400 | void helper_cpys (void) | |
401 | { | |
402 | union { | |
403 | double d; | |
404 | uint64_t i; | |
405 | } p, q, r; | |
406 | ||
407 | p.d = FT0; | |
408 | q.d = FT1; | |
409 | r.i = p.i & 0x8000000000000000ULL; | |
410 | r.i |= q.i & ~0x8000000000000000ULL; | |
411 | FT0 = r.d; | |
412 | } | |
413 | ||
414 | void helper_cpysn (void) | |
415 | { | |
416 | union { | |
417 | double d; | |
418 | uint64_t i; | |
419 | } p, q, r; | |
420 | ||
421 | p.d = FT0; | |
422 | q.d = FT1; | |
423 | r.i = (~p.i) & 0x8000000000000000ULL; | |
424 | r.i |= q.i & ~0x8000000000000000ULL; | |
425 | FT0 = r.d; | |
426 | } | |
427 | ||
428 | void helper_cpyse (void) | |
429 | { | |
430 | union { | |
431 | double d; | |
432 | uint64_t i; | |
433 | } p, q, r; | |
434 | ||
435 | p.d = FT0; | |
436 | q.d = FT1; | |
437 | r.i = p.i & 0xFFF0000000000000ULL; | |
438 | r.i |= q.i & ~0xFFF0000000000000ULL; | |
439 | FT0 = r.d; | |
440 | } | |
441 | ||
442 | void helper_itofs (void) | |
443 | { | |
444 | union { | |
445 | double d; | |
446 | uint64_t i; | |
447 | } p; | |
448 | ||
449 | p.d = FT0; | |
450 | FT0 = int64_to_float32(p.i, &FP_STATUS); | |
451 | } | |
452 | ||
453 | void helper_ftois (void) | |
454 | { | |
455 | union { | |
456 | double d; | |
457 | uint64_t i; | |
458 | } p; | |
459 | ||
460 | p.i = float32_to_int64(FT0, &FP_STATUS); | |
461 | FT0 = p.d; | |
462 | } | |
463 | ||
464 | void helper_sqrtt (void) | |
465 | { | |
466 | FT0 = float64_sqrt(FT0, &FP_STATUS); | |
467 | } | |
468 | ||
469 | void helper_cmptun (void) | |
470 | { | |
471 | union { | |
472 | double d; | |
473 | uint64_t i; | |
474 | } p; | |
475 | ||
476 | p.i = 0; | |
477 | if (float64_is_nan(FT0) || float64_is_nan(FT1)) | |
478 | p.i = 0x4000000000000000ULL; | |
479 | FT0 = p.d; | |
480 | } | |
481 | ||
482 | void helper_cmpteq (void) | |
483 | { | |
484 | union { | |
485 | double d; | |
486 | uint64_t i; | |
487 | } p; | |
488 | ||
489 | p.i = 0; | |
490 | if (float64_eq(FT0, FT1, &FP_STATUS)) | |
491 | p.i = 0x4000000000000000ULL; | |
492 | FT0 = p.d; | |
493 | } | |
494 | ||
495 | void helper_cmptle (void) | |
496 | { | |
497 | union { | |
498 | double d; | |
499 | uint64_t i; | |
500 | } p; | |
501 | ||
502 | p.i = 0; | |
503 | if (float64_le(FT0, FT1, &FP_STATUS)) | |
504 | p.i = 0x4000000000000000ULL; | |
505 | FT0 = p.d; | |
506 | } | |
507 | ||
508 | void helper_cmptlt (void) | |
509 | { | |
510 | union { | |
511 | double d; | |
512 | uint64_t i; | |
513 | } p; | |
514 | ||
515 | p.i = 0; | |
516 | if (float64_lt(FT0, FT1, &FP_STATUS)) | |
517 | p.i = 0x4000000000000000ULL; | |
518 | FT0 = p.d; | |
519 | } | |
520 | ||
521 | void helper_itoft (void) | |
522 | { | |
523 | union { | |
524 | double d; | |
525 | uint64_t i; | |
526 | } p; | |
527 | ||
528 | p.d = FT0; | |
529 | FT0 = int64_to_float64(p.i, &FP_STATUS); | |
530 | } | |
531 | ||
532 | void helper_ftoit (void) | |
533 | { | |
534 | union { | |
535 | double d; | |
536 | uint64_t i; | |
537 | } p; | |
538 | ||
539 | p.i = float64_to_int64(FT0, &FP_STATUS); | |
540 | FT0 = p.d; | |
541 | } | |
542 | ||
f071b4d3 | 543 | static always_inline int vaxf_is_valid (float ff) |
4c9649a9 JM |
544 | { |
545 | union { | |
546 | float f; | |
547 | uint32_t i; | |
548 | } p; | |
549 | uint32_t exp, mant; | |
550 | ||
551 | p.f = ff; | |
552 | exp = (p.i >> 23) & 0xFF; | |
553 | mant = p.i & 0x007FFFFF; | |
554 | if (exp == 0 && ((p.i & 0x80000000) || mant != 0)) { | |
555 | /* Reserved operands / Dirty zero */ | |
556 | return 0; | |
557 | } | |
558 | ||
559 | return 1; | |
560 | } | |
561 | ||
f071b4d3 | 562 | static always_inline float vaxf_to_ieee32 (float ff) |
4c9649a9 JM |
563 | { |
564 | union { | |
565 | float f; | |
566 | uint32_t i; | |
567 | } p; | |
568 | uint32_t exp; | |
569 | ||
570 | p.f = ff; | |
571 | exp = (p.i >> 23) & 0xFF; | |
572 | if (exp < 3) { | |
573 | /* Underflow */ | |
574 | p.f = 0.0; | |
575 | } else { | |
576 | p.f *= 0.25; | |
577 | } | |
578 | ||
579 | return p.f; | |
580 | } | |
581 | ||
f071b4d3 | 582 | static always_inline float ieee32_to_vaxf (float fi) |
4c9649a9 JM |
583 | { |
584 | union { | |
585 | float f; | |
586 | uint32_t i; | |
587 | } p; | |
588 | uint32_t exp, mant; | |
589 | ||
590 | p.f = fi; | |
591 | exp = (p.i >> 23) & 0xFF; | |
592 | mant = p.i & 0x007FFFFF; | |
593 | if (exp == 255) { | |
594 | /* NaN or infinity */ | |
595 | p.i = 1; | |
596 | } else if (exp == 0) { | |
597 | if (mant == 0) { | |
598 | /* Zero */ | |
599 | p.i = 0; | |
600 | } else { | |
601 | /* Denormalized */ | |
602 | p.f *= 2.0; | |
603 | } | |
604 | } else { | |
605 | if (exp >= 253) { | |
606 | /* Overflow */ | |
607 | p.i = 1; | |
608 | } else { | |
609 | p.f *= 4.0; | |
610 | } | |
611 | } | |
612 | ||
613 | return p.f; | |
614 | } | |
615 | ||
616 | void helper_addf (void) | |
617 | { | |
618 | float ft0, ft1, ft2; | |
619 | ||
620 | if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { | |
621 | /* XXX: TODO */ | |
622 | } | |
623 | ft0 = vaxf_to_ieee32(FT0); | |
624 | ft1 = vaxf_to_ieee32(FT1); | |
625 | ft2 = float32_add(ft0, ft1, &FP_STATUS); | |
626 | FT0 = ieee32_to_vaxf(ft2); | |
627 | } | |
628 | ||
629 | void helper_subf (void) | |
630 | { | |
631 | float ft0, ft1, ft2; | |
632 | ||
633 | if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { | |
634 | /* XXX: TODO */ | |
635 | } | |
636 | ft0 = vaxf_to_ieee32(FT0); | |
637 | ft1 = vaxf_to_ieee32(FT1); | |
638 | ft2 = float32_sub(ft0, ft1, &FP_STATUS); | |
639 | FT0 = ieee32_to_vaxf(ft2); | |
640 | } | |
641 | ||
642 | void helper_mulf (void) | |
643 | { | |
644 | float ft0, ft1, ft2; | |
645 | ||
646 | if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { | |
647 | /* XXX: TODO */ | |
648 | } | |
649 | ft0 = vaxf_to_ieee32(FT0); | |
650 | ft1 = vaxf_to_ieee32(FT1); | |
651 | ft2 = float32_mul(ft0, ft1, &FP_STATUS); | |
652 | FT0 = ieee32_to_vaxf(ft2); | |
653 | } | |
654 | ||
655 | void helper_divf (void) | |
656 | { | |
657 | float ft0, ft1, ft2; | |
658 | ||
659 | if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { | |
660 | /* XXX: TODO */ | |
661 | } | |
662 | ft0 = vaxf_to_ieee32(FT0); | |
663 | ft1 = vaxf_to_ieee32(FT1); | |
664 | ft2 = float32_div(ft0, ft1, &FP_STATUS); | |
665 | FT0 = ieee32_to_vaxf(ft2); | |
666 | } | |
667 | ||
668 | void helper_sqrtf (void) | |
669 | { | |
670 | float ft0, ft1; | |
671 | ||
672 | if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { | |
673 | /* XXX: TODO */ | |
674 | } | |
675 | ft0 = vaxf_to_ieee32(FT0); | |
676 | ft1 = float32_sqrt(ft0, &FP_STATUS); | |
677 | FT0 = ieee32_to_vaxf(ft1); | |
678 | } | |
679 | ||
680 | void helper_itoff (void) | |
681 | { | |
682 | /* XXX: TODO */ | |
683 | } | |
684 | ||
f071b4d3 | 685 | static always_inline int vaxg_is_valid (double ff) |
4c9649a9 JM |
686 | { |
687 | union { | |
688 | double f; | |
689 | uint64_t i; | |
690 | } p; | |
691 | uint64_t exp, mant; | |
692 | ||
693 | p.f = ff; | |
694 | exp = (p.i >> 52) & 0x7FF; | |
695 | mant = p.i & 0x000FFFFFFFFFFFFFULL; | |
696 | if (exp == 0 && ((p.i & 0x8000000000000000ULL) || mant != 0)) { | |
697 | /* Reserved operands / Dirty zero */ | |
698 | return 0; | |
699 | } | |
700 | ||
701 | return 1; | |
702 | } | |
703 | ||
f071b4d3 | 704 | static always_inline double vaxg_to_ieee64 (double fg) |
4c9649a9 JM |
705 | { |
706 | union { | |
707 | double f; | |
708 | uint64_t i; | |
709 | } p; | |
710 | uint32_t exp; | |
711 | ||
712 | p.f = fg; | |
713 | exp = (p.i >> 52) & 0x7FF; | |
714 | if (exp < 3) { | |
715 | /* Underflow */ | |
716 | p.f = 0.0; | |
717 | } else { | |
718 | p.f *= 0.25; | |
719 | } | |
720 | ||
721 | return p.f; | |
722 | } | |
723 | ||
f071b4d3 | 724 | static always_inline double ieee64_to_vaxg (double fi) |
4c9649a9 JM |
725 | { |
726 | union { | |
727 | double f; | |
728 | uint64_t i; | |
729 | } p; | |
730 | uint64_t mant; | |
731 | uint32_t exp; | |
732 | ||
733 | p.f = fi; | |
734 | exp = (p.i >> 52) & 0x7FF; | |
735 | mant = p.i & 0x000FFFFFFFFFFFFFULL; | |
736 | if (exp == 255) { | |
737 | /* NaN or infinity */ | |
738 | p.i = 1; /* VAX dirty zero */ | |
739 | } else if (exp == 0) { | |
740 | if (mant == 0) { | |
741 | /* Zero */ | |
742 | p.i = 0; | |
743 | } else { | |
744 | /* Denormalized */ | |
745 | p.f *= 2.0; | |
746 | } | |
747 | } else { | |
748 | if (exp >= 2045) { | |
749 | /* Overflow */ | |
750 | p.i = 1; /* VAX dirty zero */ | |
751 | } else { | |
752 | p.f *= 4.0; | |
753 | } | |
754 | } | |
755 | ||
756 | return p.f; | |
757 | } | |
758 | ||
759 | void helper_addg (void) | |
760 | { | |
761 | double ft0, ft1, ft2; | |
762 | ||
763 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
764 | /* XXX: TODO */ | |
765 | } | |
766 | ft0 = vaxg_to_ieee64(FT0); | |
767 | ft1 = vaxg_to_ieee64(FT1); | |
768 | ft2 = float64_add(ft0, ft1, &FP_STATUS); | |
769 | FT0 = ieee64_to_vaxg(ft2); | |
770 | } | |
771 | ||
772 | void helper_subg (void) | |
773 | { | |
774 | double ft0, ft1, ft2; | |
775 | ||
776 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
777 | /* XXX: TODO */ | |
778 | } | |
779 | ft0 = vaxg_to_ieee64(FT0); | |
780 | ft1 = vaxg_to_ieee64(FT1); | |
781 | ft2 = float64_sub(ft0, ft1, &FP_STATUS); | |
782 | FT0 = ieee64_to_vaxg(ft2); | |
783 | } | |
784 | ||
785 | void helper_mulg (void) | |
786 | { | |
787 | double ft0, ft1, ft2; | |
788 | ||
789 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
790 | /* XXX: TODO */ | |
791 | } | |
792 | ft0 = vaxg_to_ieee64(FT0); | |
793 | ft1 = vaxg_to_ieee64(FT1); | |
794 | ft2 = float64_mul(ft0, ft1, &FP_STATUS); | |
795 | FT0 = ieee64_to_vaxg(ft2); | |
796 | } | |
797 | ||
798 | void helper_divg (void) | |
799 | { | |
800 | double ft0, ft1, ft2; | |
801 | ||
802 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
803 | /* XXX: TODO */ | |
804 | } | |
805 | ft0 = vaxg_to_ieee64(FT0); | |
806 | ft1 = vaxg_to_ieee64(FT1); | |
807 | ft2 = float64_div(ft0, ft1, &FP_STATUS); | |
808 | FT0 = ieee64_to_vaxg(ft2); | |
809 | } | |
810 | ||
811 | void helper_sqrtg (void) | |
812 | { | |
813 | double ft0, ft1; | |
814 | ||
815 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
816 | /* XXX: TODO */ | |
817 | } | |
818 | ft0 = vaxg_to_ieee64(FT0); | |
819 | ft1 = float64_sqrt(ft0, &FP_STATUS); | |
820 | FT0 = ieee64_to_vaxg(ft1); | |
821 | } | |
822 | ||
823 | void helper_cmpgeq (void) | |
824 | { | |
825 | union { | |
826 | double d; | |
827 | uint64_t u; | |
828 | } p; | |
829 | double ft0, ft1; | |
830 | ||
831 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
832 | /* XXX: TODO */ | |
833 | } | |
834 | ft0 = vaxg_to_ieee64(FT0); | |
835 | ft1 = vaxg_to_ieee64(FT1); | |
836 | p.u = 0; | |
837 | if (float64_eq(ft0, ft1, &FP_STATUS)) | |
838 | p.u = 0x4000000000000000ULL; | |
839 | FT0 = p.d; | |
840 | } | |
841 | ||
842 | void helper_cmpglt (void) | |
843 | { | |
844 | union { | |
845 | double d; | |
846 | uint64_t u; | |
847 | } p; | |
848 | double ft0, ft1; | |
849 | ||
850 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
851 | /* XXX: TODO */ | |
852 | } | |
853 | ft0 = vaxg_to_ieee64(FT0); | |
854 | ft1 = vaxg_to_ieee64(FT1); | |
855 | p.u = 0; | |
856 | if (float64_lt(ft0, ft1, &FP_STATUS)) | |
857 | p.u = 0x4000000000000000ULL; | |
858 | FT0 = p.d; | |
859 | } | |
860 | ||
861 | void helper_cmpgle (void) | |
862 | { | |
863 | union { | |
864 | double d; | |
865 | uint64_t u; | |
866 | } p; | |
867 | double ft0, ft1; | |
868 | ||
869 | if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { | |
870 | /* XXX: TODO */ | |
871 | } | |
872 | ft0 = vaxg_to_ieee64(FT0); | |
873 | ft1 = vaxg_to_ieee64(FT1); | |
874 | p.u = 0; | |
875 | if (float64_le(ft0, ft1, &FP_STATUS)) | |
876 | p.u = 0x4000000000000000ULL; | |
877 | FT0 = p.d; | |
878 | } | |
879 | ||
880 | void helper_cvtqs (void) | |
881 | { | |
882 | union { | |
883 | double d; | |
884 | uint64_t u; | |
885 | } p; | |
886 | ||
887 | p.d = FT0; | |
888 | FT0 = (float)p.u; | |
889 | } | |
890 | ||
891 | void helper_cvttq (void) | |
892 | { | |
893 | union { | |
894 | double d; | |
895 | uint64_t u; | |
896 | } p; | |
897 | ||
898 | p.u = FT0; | |
899 | FT0 = p.d; | |
900 | } | |
901 | ||
902 | void helper_cvtqt (void) | |
903 | { | |
904 | union { | |
905 | double d; | |
906 | uint64_t u; | |
907 | } p; | |
908 | ||
909 | p.d = FT0; | |
910 | FT0 = p.u; | |
911 | } | |
912 | ||
913 | void helper_cvtqf (void) | |
914 | { | |
915 | union { | |
916 | double d; | |
917 | uint64_t u; | |
918 | } p; | |
919 | ||
920 | p.d = FT0; | |
921 | FT0 = ieee32_to_vaxf(p.u); | |
922 | } | |
923 | ||
924 | void helper_cvtgf (void) | |
925 | { | |
926 | double ft0; | |
927 | ||
928 | ft0 = vaxg_to_ieee64(FT0); | |
929 | FT0 = ieee32_to_vaxf(ft0); | |
930 | } | |
931 | ||
932 | void helper_cvtgd (void) | |
933 | { | |
934 | /* XXX: TODO */ | |
935 | } | |
936 | ||
937 | void helper_cvtgq (void) | |
938 | { | |
939 | union { | |
940 | double d; | |
941 | uint64_t u; | |
942 | } p; | |
943 | ||
944 | p.u = vaxg_to_ieee64(FT0); | |
945 | FT0 = p.d; | |
946 | } | |
947 | ||
948 | void helper_cvtqg (void) | |
949 | { | |
950 | union { | |
951 | double d; | |
952 | uint64_t u; | |
953 | } p; | |
954 | ||
955 | p.d = FT0; | |
956 | FT0 = ieee64_to_vaxg(p.u); | |
957 | } | |
958 | ||
959 | void helper_cvtdg (void) | |
960 | { | |
961 | /* XXX: TODO */ | |
962 | } | |
963 | ||
964 | void helper_cvtlq (void) | |
965 | { | |
966 | union { | |
967 | double d; | |
968 | uint64_t u; | |
969 | } p, q; | |
970 | ||
971 | p.d = FT0; | |
972 | q.u = (p.u >> 29) & 0x3FFFFFFF; | |
973 | q.u |= (p.u >> 32); | |
974 | q.u = (int64_t)((int32_t)q.u); | |
975 | FT0 = q.d; | |
976 | } | |
977 | ||
f071b4d3 | 978 | static always_inline void __helper_cvtql (int s, int v) |
4c9649a9 JM |
979 | { |
980 | union { | |
981 | double d; | |
982 | uint64_t u; | |
983 | } p, q; | |
984 | ||
985 | p.d = FT0; | |
986 | q.u = ((uint64_t)(p.u & 0xC0000000)) << 32; | |
987 | q.u |= ((uint64_t)(p.u & 0x7FFFFFFF)) << 29; | |
988 | FT0 = q.d; | |
989 | if (v && (int64_t)((int32_t)p.u) != (int64_t)p.u) { | |
990 | helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); | |
991 | } | |
992 | if (s) { | |
993 | /* TODO */ | |
994 | } | |
995 | } | |
996 | ||
997 | void helper_cvtql (void) | |
998 | { | |
999 | __helper_cvtql(0, 0); | |
1000 | } | |
1001 | ||
1002 | void helper_cvtqlv (void) | |
1003 | { | |
1004 | __helper_cvtql(0, 1); | |
1005 | } | |
1006 | ||
1007 | void helper_cvtqlsv (void) | |
1008 | { | |
1009 | __helper_cvtql(1, 1); | |
1010 | } | |
1011 | ||
1012 | void helper_cmpfeq (void) | |
1013 | { | |
1014 | if (float64_eq(FT0, FT1, &FP_STATUS)) | |
1015 | T0 = 1; | |
1016 | else | |
1017 | T0 = 0; | |
1018 | } | |
1019 | ||
1020 | void helper_cmpfne (void) | |
1021 | { | |
1022 | if (float64_eq(FT0, FT1, &FP_STATUS)) | |
1023 | T0 = 0; | |
1024 | else | |
1025 | T0 = 1; | |
1026 | } | |
1027 | ||
1028 | void helper_cmpflt (void) | |
1029 | { | |
1030 | if (float64_lt(FT0, FT1, &FP_STATUS)) | |
1031 | T0 = 1; | |
1032 | else | |
1033 | T0 = 0; | |
1034 | } | |
1035 | ||
1036 | void helper_cmpfle (void) | |
1037 | { | |
1038 | if (float64_lt(FT0, FT1, &FP_STATUS)) | |
1039 | T0 = 1; | |
1040 | else | |
1041 | T0 = 0; | |
1042 | } | |
1043 | ||
1044 | void helper_cmpfgt (void) | |
1045 | { | |
1046 | if (float64_le(FT0, FT1, &FP_STATUS)) | |
1047 | T0 = 0; | |
1048 | else | |
1049 | T0 = 1; | |
1050 | } | |
1051 | ||
1052 | void helper_cmpfge (void) | |
1053 | { | |
1054 | if (float64_lt(FT0, FT1, &FP_STATUS)) | |
1055 | T0 = 0; | |
1056 | else | |
1057 | T0 = 1; | |
1058 | } | |
1059 | ||
1060 | #if !defined (CONFIG_USER_ONLY) | |
1061 | void helper_mfpr (int iprn) | |
1062 | { | |
1063 | uint64_t val; | |
1064 | ||
1065 | if (cpu_alpha_mfpr(env, iprn, &val) == 0) | |
1066 | T0 = val; | |
1067 | } | |
1068 | ||
1069 | void helper_mtpr (int iprn) | |
1070 | { | |
1071 | cpu_alpha_mtpr(env, iprn, T0, NULL); | |
1072 | } | |
1073 | #endif | |
1074 | ||
2d8ee4e7 BS |
1075 | #if defined(HOST_SPARC) || defined(HOST_SPARC64) |
1076 | void helper_reset_FT0 (void) | |
1077 | { | |
1078 | FT0 = 0; | |
1079 | } | |
1080 | ||
1081 | void helper_reset_FT1 (void) | |
1082 | { | |
1083 | FT1 = 0; | |
1084 | } | |
1085 | ||
1086 | void helper_reset_FT2 (void) | |
1087 | { | |
1088 | FT2 = 0; | |
1089 | } | |
1090 | #endif | |
1091 | ||
4c9649a9 JM |
1092 | /*****************************************************************************/ |
1093 | /* Softmmu support */ | |
1094 | #if !defined (CONFIG_USER_ONLY) | |
1095 | ||
4c9649a9 JM |
1096 | /* XXX: the two following helpers are pure hacks. |
1097 | * Hopefully, we emulate the PALcode, then we should never see | |
1098 | * HW_LD / HW_ST instructions. | |
1099 | */ | |
1100 | void helper_ld_phys_to_virt (void) | |
1101 | { | |
1102 | uint64_t tlb_addr, physaddr; | |
6ebbf390 | 1103 | int index, mmu_idx; |
4c9649a9 JM |
1104 | void *retaddr; |
1105 | ||
6ebbf390 | 1106 | mmu_idx = cpu_mmu_index(env); |
4c9649a9 JM |
1107 | index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
1108 | redo: | |
6ebbf390 | 1109 | tlb_addr = env->tlb_table[mmu_idx][index].addr_read; |
4c9649a9 JM |
1110 | if ((T0 & TARGET_PAGE_MASK) == |
1111 | (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { | |
6ebbf390 | 1112 | physaddr = T0 + env->tlb_table[mmu_idx][index].addend; |
4c9649a9 JM |
1113 | } else { |
1114 | /* the page is not in the TLB : fill it */ | |
1115 | retaddr = GETPC(); | |
6ebbf390 | 1116 | tlb_fill(T0, 0, mmu_idx, retaddr); |
4c9649a9 JM |
1117 | goto redo; |
1118 | } | |
1119 | T0 = physaddr; | |
1120 | } | |
1121 | ||
1122 | void helper_st_phys_to_virt (void) | |
1123 | { | |
1124 | uint64_t tlb_addr, physaddr; | |
6ebbf390 | 1125 | int index, mmu_idx; |
4c9649a9 JM |
1126 | void *retaddr; |
1127 | ||
6ebbf390 | 1128 | mmu_idx = cpu_mmu_index(env); |
4c9649a9 JM |
1129 | index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
1130 | redo: | |
6ebbf390 | 1131 | tlb_addr = env->tlb_table[mmu_idx][index].addr_write; |
4c9649a9 JM |
1132 | if ((T0 & TARGET_PAGE_MASK) == |
1133 | (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { | |
6ebbf390 | 1134 | physaddr = T0 + env->tlb_table[mmu_idx][index].addend; |
4c9649a9 JM |
1135 | } else { |
1136 | /* the page is not in the TLB : fill it */ | |
1137 | retaddr = GETPC(); | |
6ebbf390 | 1138 | tlb_fill(T0, 1, mmu_idx, retaddr); |
4c9649a9 JM |
1139 | goto redo; |
1140 | } | |
1141 | T0 = physaddr; | |
1142 | } | |
1143 | ||
1144 | #define MMUSUFFIX _mmu | |
1145 | ||
1146 | #define SHIFT 0 | |
1147 | #include "softmmu_template.h" | |
1148 | ||
1149 | #define SHIFT 1 | |
1150 | #include "softmmu_template.h" | |
1151 | ||
1152 | #define SHIFT 2 | |
1153 | #include "softmmu_template.h" | |
1154 | ||
1155 | #define SHIFT 3 | |
1156 | #include "softmmu_template.h" | |
1157 | ||
1158 | /* try to fill the TLB and return an exception if error. If retaddr is | |
1159 | NULL, it means that the function was called in C code (i.e. not | |
1160 | from generated code or from helper.c) */ | |
1161 | /* XXX: fix it to restore all registers */ | |
6ebbf390 | 1162 | void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
4c9649a9 JM |
1163 | { |
1164 | TranslationBlock *tb; | |
1165 | CPUState *saved_env; | |
44f8625d | 1166 | unsigned long pc; |
4c9649a9 JM |
1167 | int ret; |
1168 | ||
1169 | /* XXX: hack to restore env in all cases, even if not called from | |
1170 | generated code */ | |
1171 | saved_env = env; | |
1172 | env = cpu_single_env; | |
6ebbf390 | 1173 | ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); |
4c9649a9 JM |
1174 | if (!likely(ret == 0)) { |
1175 | if (likely(retaddr)) { | |
1176 | /* now we have a real cpu fault */ | |
44f8625d | 1177 | pc = (unsigned long)retaddr; |
4c9649a9 JM |
1178 | tb = tb_find_pc(pc); |
1179 | if (likely(tb)) { | |
1180 | /* the PC is inside the translated code. It means that we have | |
1181 | a virtual CPU fault */ | |
1182 | cpu_restore_state(tb, env, pc, NULL); | |
1183 | } | |
1184 | } | |
1185 | /* Exception index and error code are already set */ | |
1186 | cpu_loop_exit(); | |
1187 | } | |
1188 | env = saved_env; | |
1189 | } | |
1190 | ||
1191 | #endif |