|
|
1.1 root 1: /*
2: * PowerPC emulation helpers for qemu.
3: *
4: * Copyright (c) 2003-2005 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: #include <math.h>
21: #include "exec.h"
22:
23: #define MEMSUFFIX _raw
24: #include "op_helper_mem.h"
25: #if !defined(CONFIG_USER_ONLY)
26: #define MEMSUFFIX _user
27: #include "op_helper_mem.h"
28: #define MEMSUFFIX _kernel
29: #include "op_helper_mem.h"
30: #endif
31:
32: //#define DEBUG_OP
33: //#define DEBUG_EXCEPTIONS
34: //#define FLUSH_ALL_TLBS
35:
36: #define Ts0 (long)((target_long)T0)
37: #define Ts1 (long)((target_long)T1)
38: #define Ts2 (long)((target_long)T2)
39:
40: /*****************************************************************************/
41: /* Exceptions processing helpers */
42: void cpu_loop_exit(void)
43: {
44: longjmp(env->jmp_env, 1);
45: }
46:
47: void do_raise_exception_err (uint32_t exception, int error_code)
48: {
49: #if 0
50: printf("Raise exception %3x code : %d\n", exception, error_code);
51: #endif
52: switch (exception) {
53: case EXCP_PROGRAM:
54: if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
55: return;
56: break;
57: default:
58: break;
59: }
60: env->exception_index = exception;
61: env->error_code = error_code;
62: cpu_loop_exit();
63: }
64:
65: void do_raise_exception (uint32_t exception)
66: {
67: do_raise_exception_err(exception, 0);
68: }
69:
70: /*****************************************************************************/
71: /* Fixed point operations helpers */
72: void do_addo (void)
73: {
74: T2 = T0;
75: T0 += T1;
76: if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
77: xer_ov = 0;
78: } else {
79: xer_so = 1;
80: xer_ov = 1;
81: }
82: }
83:
84: void do_addco (void)
85: {
86: T2 = T0;
87: T0 += T1;
88: if (likely(T0 >= T2)) {
89: xer_ca = 0;
90: } else {
91: xer_ca = 1;
92: }
93: if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
94: xer_ov = 0;
95: } else {
96: xer_so = 1;
97: xer_ov = 1;
98: }
99: }
100:
101: void do_adde (void)
102: {
103: T2 = T0;
104: T0 += T1 + xer_ca;
105: if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
106: xer_ca = 0;
107: } else {
108: xer_ca = 1;
109: }
110: }
111:
112: void do_addeo (void)
113: {
114: T2 = T0;
115: T0 += T1 + xer_ca;
116: if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
117: xer_ca = 0;
118: } else {
119: xer_ca = 1;
120: }
121: if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
122: xer_ov = 0;
123: } else {
124: xer_so = 1;
125: xer_ov = 1;
126: }
127: }
128:
129: void do_addmeo (void)
130: {
131: T1 = T0;
132: T0 += xer_ca + (-1);
133: if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
134: xer_ov = 0;
135: } else {
136: xer_so = 1;
137: xer_ov = 1;
138: }
139: if (likely(T1 != 0))
140: xer_ca = 1;
141: }
142:
143: void do_addzeo (void)
144: {
145: T1 = T0;
146: T0 += xer_ca;
147: if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
148: xer_ov = 0;
149: } else {
150: xer_so = 1;
151: xer_ov = 1;
152: }
153: if (likely(T0 >= T1)) {
154: xer_ca = 0;
155: } else {
156: xer_ca = 1;
157: }
158: }
159:
160: void do_divwo (void)
161: {
162: if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
163: xer_ov = 0;
164: T0 = (Ts0 / Ts1);
165: } else {
166: xer_so = 1;
167: xer_ov = 1;
168: T0 = (-1) * ((uint32_t)T0 >> 31);
169: }
170: }
171:
172: void do_divwuo (void)
173: {
174: if (likely((uint32_t)T1 != 0)) {
175: xer_ov = 0;
176: T0 = (uint32_t)T0 / (uint32_t)T1;
177: } else {
178: xer_so = 1;
179: xer_ov = 1;
180: T0 = 0;
181: }
182: }
183:
184: void do_mullwo (void)
185: {
186: int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
187:
188: if (likely((int32_t)res == res)) {
189: xer_ov = 0;
190: } else {
191: xer_ov = 1;
192: xer_so = 1;
193: }
194: T0 = (int32_t)res;
195: }
196:
197: void do_nego (void)
198: {
199: if (likely(T0 != INT32_MIN)) {
200: xer_ov = 0;
201: T0 = -Ts0;
202: } else {
203: xer_ov = 1;
204: xer_so = 1;
205: }
206: }
207:
208: void do_subfo (void)
209: {
210: T2 = T0;
211: T0 = T1 - T0;
212: if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
213: xer_ov = 0;
214: } else {
215: xer_so = 1;
216: xer_ov = 1;
217: }
218: RETURN();
219: }
220:
221: void do_subfco (void)
222: {
223: T2 = T0;
224: T0 = T1 - T0;
225: if (likely(T0 > T1)) {
226: xer_ca = 0;
227: } else {
228: xer_ca = 1;
229: }
230: if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
231: xer_ov = 0;
232: } else {
233: xer_so = 1;
234: xer_ov = 1;
235: }
236: }
237:
238: void do_subfe (void)
239: {
240: T0 = T1 + ~T0 + xer_ca;
241: if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
242: xer_ca = 0;
243: } else {
244: xer_ca = 1;
245: }
246: }
247:
248: void do_subfeo (void)
249: {
250: T2 = T0;
251: T0 = T1 + ~T0 + xer_ca;
252: if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
253: xer_ov = 0;
254: } else {
255: xer_so = 1;
256: xer_ov = 1;
257: }
258: if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
259: xer_ca = 0;
260: } else {
261: xer_ca = 1;
262: }
263: }
264:
265: void do_subfmeo (void)
266: {
267: T1 = T0;
268: T0 = ~T0 + xer_ca - 1;
269: if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
270: xer_ov = 0;
271: } else {
272: xer_so = 1;
273: xer_ov = 1;
274: }
275: if (likely(T1 != -1))
276: xer_ca = 1;
277: }
278:
279: void do_subfzeo (void)
280: {
281: T1 = T0;
282: T0 = ~T0 + xer_ca;
283: if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
284: xer_ov = 0;
285: } else {
286: xer_ov = 1;
287: xer_so = 1;
288: }
289: if (likely(T0 >= ~T1)) {
290: xer_ca = 0;
291: } else {
292: xer_ca = 1;
293: }
294: }
295:
296: /* shift right arithmetic helper */
297: void do_sraw (void)
298: {
299: int32_t ret;
300:
301: if (likely(!(T1 & 0x20UL))) {
302: if (likely(T1 != 0)) {
303: ret = (int32_t)T0 >> (T1 & 0x1fUL);
304: if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
305: xer_ca = 0;
306: } else {
307: xer_ca = 1;
308: }
309: } else {
310: ret = T0;
311: xer_ca = 0;
312: }
313: } else {
314: ret = (-1) * ((uint32_t)T0 >> 31);
315: if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
316: xer_ca = 0;
317: } else {
318: xer_ca = 1;
319: }
320: }
321: T0 = ret;
322: }
323:
324: /*****************************************************************************/
325: /* Floating point operations helpers */
326: void do_fctiw (void)
327: {
328: union {
329: double d;
330: uint64_t i;
331: } p;
332:
333: /* XXX: higher bits are not supposed to be significant.
334: * to make tests easier, return the same as a real PowerPC 750 (aka G3)
335: */
336: p.i = float64_to_int32(FT0, &env->fp_status);
337: p.i |= 0xFFF80000ULL << 32;
338: FT0 = p.d;
339: }
340:
341: void do_fctiwz (void)
342: {
343: union {
344: double d;
345: uint64_t i;
346: } p;
347:
348: /* XXX: higher bits are not supposed to be significant.
349: * to make tests easier, return the same as a real PowerPC 750 (aka G3)
350: */
351: p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
352: p.i |= 0xFFF80000ULL << 32;
353: FT0 = p.d;
354: }
355:
356: void do_fnmadd (void)
357: {
358: FT0 = float64_mul(FT0, FT1, &env->fp_status);
359: FT0 = float64_add(FT0, FT2, &env->fp_status);
360: if (likely(!isnan(FT0)))
361: FT0 = float64_chs(FT0);
362: }
363:
364: void do_fnmsub (void)
365: {
366: FT0 = float64_mul(FT0, FT1, &env->fp_status);
367: FT0 = float64_sub(FT0, FT2, &env->fp_status);
368: if (likely(!isnan(FT0)))
369: FT0 = float64_chs(FT0);
370: }
371:
372: void do_fsqrt (void)
373: {
374: FT0 = float64_sqrt(FT0, &env->fp_status);
375: }
376:
377: void do_fres (void)
378: {
379: union {
380: double d;
381: uint64_t i;
382: } p;
383:
384: if (likely(isnormal(FT0))) {
385: FT0 = (float)(1.0 / FT0);
386: } else {
387: p.d = FT0;
388: if (p.i == 0x8000000000000000ULL) {
389: p.i = 0xFFF0000000000000ULL;
390: } else if (p.i == 0x0000000000000000ULL) {
391: p.i = 0x7FF0000000000000ULL;
392: } else if (isnan(FT0)) {
393: p.i = 0x7FF8000000000000ULL;
394: } else if (FT0 < 0.0) {
395: p.i = 0x8000000000000000ULL;
396: } else {
397: p.i = 0x0000000000000000ULL;
398: }
399: FT0 = p.d;
400: }
401: }
402:
403: void do_frsqrte (void)
404: {
405: union {
406: double d;
407: uint64_t i;
408: } p;
409:
410: if (likely(isnormal(FT0) && FT0 > 0.0)) {
411: FT0 = float64_sqrt(FT0, &env->fp_status);
412: FT0 = float32_div(1.0, FT0, &env->fp_status);
413: } else {
414: p.d = FT0;
415: if (p.i == 0x8000000000000000ULL) {
416: p.i = 0xFFF0000000000000ULL;
417: } else if (p.i == 0x0000000000000000ULL) {
418: p.i = 0x7FF0000000000000ULL;
419: } else if (isnan(FT0)) {
420: if (!(p.i & 0x0008000000000000ULL))
421: p.i |= 0x000FFFFFFFFFFFFFULL;
422: } else if (FT0 < 0) {
423: p.i = 0x7FF8000000000000ULL;
424: } else {
425: p.i = 0x0000000000000000ULL;
426: }
427: FT0 = p.d;
428: }
429: }
430:
431: void do_fsel (void)
432: {
433: if (FT0 >= 0)
434: FT0 = FT1;
435: else
436: FT0 = FT2;
437: }
438:
439: void do_fcmpu (void)
440: {
441: if (likely(!isnan(FT0) && !isnan(FT1))) {
442: if (float64_lt(FT0, FT1, &env->fp_status)) {
443: T0 = 0x08UL;
444: } else if (!float64_le(FT0, FT1, &env->fp_status)) {
445: T0 = 0x04UL;
446: } else {
447: T0 = 0x02UL;
448: }
449: } else {
450: T0 = 0x01UL;
451: env->fpscr[4] |= 0x1;
452: env->fpscr[6] |= 0x1;
453: }
454: env->fpscr[3] = T0;
455: }
456:
457: void do_fcmpo (void)
458: {
459: env->fpscr[4] &= ~0x1;
460: if (likely(!isnan(FT0) && !isnan(FT1))) {
461: if (float64_lt(FT0, FT1, &env->fp_status)) {
462: T0 = 0x08UL;
463: } else if (!float64_le(FT0, FT1, &env->fp_status)) {
464: T0 = 0x04UL;
465: } else {
466: T0 = 0x02UL;
467: }
468: } else {
469: T0 = 0x01UL;
470: env->fpscr[4] |= 0x1;
471: /* I don't know how to test "quiet" nan... */
472: if (0 /* || ! quiet_nan(...) */) {
473: env->fpscr[6] |= 0x1;
474: if (!(env->fpscr[1] & 0x8))
475: env->fpscr[4] |= 0x8;
476: } else {
477: env->fpscr[4] |= 0x8;
478: }
479: }
480: env->fpscr[3] = T0;
481: }
482:
483: void do_rfi (void)
484: {
485: env->nip = env->spr[SPR_SRR0] & ~0x00000003;
486: T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
487: do_store_msr(env, T0);
488: #if defined (DEBUG_OP)
489: dump_rfi();
490: #endif
491: env->interrupt_request |= CPU_INTERRUPT_EXITTB;
492: }
493:
494: void do_tw (uint32_t cmp, int flags)
495: {
496: if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
497: (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
498: (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
499: (T0 < cmp && (flags & 0x02)) ||
500: (T0 > cmp && (flags & 0x01)))))
501: do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
502: }
503:
504: /* Instruction cache invalidation helper */
505: void do_icbi (void)
506: {
507: uint32_t tmp;
508: /* Invalidate one cache line :
509: * PowerPC specification says this is to be treated like a load
510: * (not a fetch) by the MMU. To be sure it will be so,
511: * do the load "by hand".
512: */
513: #if defined(TARGET_PPC64)
514: if (!msr_sf)
515: T0 &= 0xFFFFFFFFULL;
516: #endif
517: tmp = ldl_kernel(T0);
518: T0 &= ~(ICACHE_LINE_SIZE - 1);
519: tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
520: }
521:
522: /*****************************************************************************/
523: /* MMU related helpers */
524: /* TLB invalidation helpers */
525: void do_tlbia (void)
526: {
527: tlb_flush(env, 1);
528: }
529:
530: void do_tlbie (void)
531: {
532: #if !defined(FLUSH_ALL_TLBS)
533: tlb_flush_page(env, T0);
534: #else
535: do_tlbia();
536: #endif
537: }
538:
539: /*****************************************************************************/
540: /* Softmmu support */
541: #if !defined (CONFIG_USER_ONLY)
542:
543: #define MMUSUFFIX _mmu
544: #define GETPC() (__builtin_return_address(0))
545:
546: #define SHIFT 0
547: #include "softmmu_template.h"
548:
549: #define SHIFT 1
550: #include "softmmu_template.h"
551:
552: #define SHIFT 2
553: #include "softmmu_template.h"
554:
555: #define SHIFT 3
556: #include "softmmu_template.h"
557:
558: /* try to fill the TLB and return an exception if error. If retaddr is
559: NULL, it means that the function was called in C code (i.e. not
560: from generated code or from helper.c) */
561: /* XXX: fix it to restore all registers */
562: void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
563: {
564: TranslationBlock *tb;
565: CPUState *saved_env;
566: target_phys_addr_t pc;
567: int ret;
568:
569: /* XXX: hack to restore env in all cases, even if not called from
570: generated code */
571: saved_env = env;
572: env = cpu_single_env;
573: ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
574: if (!likely(ret == 0)) {
575: if (likely(retaddr)) {
576: /* now we have a real cpu fault */
577: pc = (target_phys_addr_t)retaddr;
578: tb = tb_find_pc(pc);
579: if (likely(tb)) {
580: /* the PC is inside the translated code. It means that we have
581: a virtual CPU fault */
582: cpu_restore_state(tb, env, pc, NULL);
583: }
584: }
585: do_raise_exception_err(env->exception_index, env->error_code);
586: }
587: env = saved_env;
588: }
589: #endif /* !CONFIG_USER_ONLY */
590:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.