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