|
|
1.1 root 1: /*
2: * m68k micro operations
3: *
4: * Copyright (c) 2006 CodeSourcery
5: * Written by Paul Brook
6: *
7: * This library is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU Lesser General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This library is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * General Public License for more details.
16: *
17: * You should have received a copy of the GNU Lesser General Public
18: * License along with this library; if not, write to the Free Software
19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20: */
21:
22: #include "exec.h"
23: #include "m68k-qreg.h"
24:
25: #ifndef offsetof
26: #define offsetof(type, field) ((size_t) &((type *)0)->field)
27: #endif
28:
29: static long qreg_offsets[] = {
30: #define DEFO32(name, offset) offsetof(CPUState, offset),
31: #define DEFR(name, reg, mode) -1,
32: #define DEFF64(name, offset) offsetof(CPUState, offset),
33: 0,
34: #include "qregs.def"
35: };
36:
37: #define CPU_FP_STATUS env->fp_status
38:
39: #define RAISE_EXCEPTION(n) do { \
40: env->exception_index = n; \
41: cpu_loop_exit(); \
42: } while(0)
43:
44: #define get_op helper_get_op
45: #define set_op helper_set_op
46: #define get_opf64 helper_get_opf64
47: #define set_opf64 helper_set_opf64
48: uint32_t
49: get_op(int qreg)
50: {
51: if (qreg == QREG_T0) {
52: return T0;
53: } else if (qreg < TARGET_NUM_QREGS) {
54: return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
55: } else {
56: return env->qregs[qreg - TARGET_NUM_QREGS];
57: }
58: }
59:
60: void set_op(int qreg, uint32_t val)
61: {
62: if (qreg == QREG_T0) {
63: T0 = val;
64: } else if (qreg < TARGET_NUM_QREGS) {
65: *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
66: } else {
67: env->qregs[qreg - TARGET_NUM_QREGS] = val;
68: }
69: }
70:
71: float64 get_opf64(int qreg)
72: {
73: if (qreg < TARGET_NUM_QREGS) {
74: return *(float64 *)(((long)env) + qreg_offsets[qreg]);
75: } else {
76: return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS];
77: }
78: }
79:
80: void set_opf64(int qreg, float64 val)
81: {
82: if (qreg < TARGET_NUM_QREGS) {
83: *(float64 *)(((long)env) + qreg_offsets[qreg]) = val;
84: } else {
85: *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val;
86: }
87: }
88:
89: #define OP(name) void OPPROTO op_##name (void)
90:
91: OP(mov32)
92: {
93: set_op(PARAM1, get_op(PARAM2));
94: FORCE_RET();
95: }
96:
97: OP(mov32_im)
98: {
99: set_op(PARAM1, PARAM2);
100: FORCE_RET();
101: }
102:
103: OP(movf64)
104: {
105: set_opf64(PARAM1, get_opf64(PARAM2));
106: FORCE_RET();
107: }
108:
109: OP(zerof64)
110: {
111: set_opf64(PARAM1, 0);
112: FORCE_RET();
113: }
114:
115: OP(add32)
116: {
117: uint32_t op2 = get_op(PARAM2);
118: uint32_t op3 = get_op(PARAM3);
119: set_op(PARAM1, op2 + op3);
120: FORCE_RET();
121: }
122:
123: OP(sub32)
124: {
125: uint32_t op2 = get_op(PARAM2);
126: uint32_t op3 = get_op(PARAM3);
127: set_op(PARAM1, op2 - op3);
128: FORCE_RET();
129: }
130:
131: OP(mul32)
132: {
133: uint32_t op2 = get_op(PARAM2);
134: uint32_t op3 = get_op(PARAM3);
135: set_op(PARAM1, op2 * op3);
136: FORCE_RET();
137: }
138:
139: OP(not32)
140: {
141: uint32_t arg = get_op(PARAM2);
142: set_op(PARAM1, ~arg);
143: FORCE_RET();
144: }
145:
146: OP(neg32)
147: {
148: uint32_t arg = get_op(PARAM2);
149: set_op(PARAM1, -arg);
150: FORCE_RET();
151: }
152:
153: OP(bswap32)
154: {
155: uint32_t arg = get_op(PARAM2);
156: arg = (arg >> 24) | (arg << 24)
157: | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000);
158: set_op(PARAM1, arg);
159: FORCE_RET();
160: }
161:
162: OP(btest)
163: {
164: uint32_t op1 = get_op(PARAM1);
165: uint32_t op2 = get_op(PARAM2);
166: if (op1 & op2)
167: env->cc_dest &= ~CCF_Z;
168: else
169: env->cc_dest |= CCF_Z;
170: FORCE_RET();
171: }
172:
173: OP(addx_cc)
174: {
175: uint32_t op1 = get_op(PARAM1);
176: uint32_t op2 = get_op(PARAM2);
177: uint32_t res;
178: if (env->cc_x) {
179: env->cc_x = (op1 <= op2);
180: env->cc_op = CC_OP_SUBX;
181: res = op1 - (op2 + 1);
182: } else {
183: env->cc_x = (op1 < op2);
184: env->cc_op = CC_OP_SUB;
185: res = op1 - op2;
186: }
187: set_op(PARAM1, res);
188: FORCE_RET();
189: }
190:
191: OP(subx_cc)
192: {
193: uint32_t op1 = get_op(PARAM1);
194: uint32_t op2 = get_op(PARAM2);
195: uint32_t res;
196: if (env->cc_x) {
197: res = op1 + op2 + 1;
198: env->cc_x = (res <= op2);
199: env->cc_op = CC_OP_ADDX;
200: } else {
201: res = op1 + op2;
202: env->cc_x = (res < op2);
203: env->cc_op = CC_OP_ADD;
204: }
205: set_op(PARAM1, res);
206: FORCE_RET();
207: }
208:
209: /* Logic ops. */
210:
211: OP(and32)
212: {
213: uint32_t op2 = get_op(PARAM2);
214: uint32_t op3 = get_op(PARAM3);
215: set_op(PARAM1, op2 & op3);
216: FORCE_RET();
217: }
218:
219: OP(or32)
220: {
221: uint32_t op2 = get_op(PARAM2);
222: uint32_t op3 = get_op(PARAM3);
223: set_op(PARAM1, op2 | op3);
224: FORCE_RET();
225: }
226:
227: OP(xor32)
228: {
229: uint32_t op2 = get_op(PARAM2);
230: uint32_t op3 = get_op(PARAM3);
231: set_op(PARAM1, op2 ^ op3);
232: FORCE_RET();
233: }
234:
235: /* Shifts. */
236: OP(shl32)
237: {
238: uint32_t op2 = get_op(PARAM2);
239: uint32_t op3 = get_op(PARAM3);
240: uint32_t result;
241: result = op2 << op3;
242: set_op(PARAM1, result);
243: FORCE_RET();
244: }
245:
246: OP(shl_cc)
247: {
248: uint32_t op1 = get_op(PARAM1);
249: uint32_t op2 = get_op(PARAM2);
250: uint32_t result;
251: result = op1 << op2;
252: set_op(PARAM1, result);
253: env->cc_x = (op1 << (op2 - 1)) & 1;
254: FORCE_RET();
255: }
256:
257: OP(shr32)
258: {
259: uint32_t op2 = get_op(PARAM2);
260: uint32_t op3 = get_op(PARAM3);
261: uint32_t result;
262: result = op2 >> op3;
263: set_op(PARAM1, result);
264: FORCE_RET();
265: }
266:
267: OP(shr_cc)
268: {
269: uint32_t op1 = get_op(PARAM1);
270: uint32_t op2 = get_op(PARAM2);
271: uint32_t result;
272: result = op1 >> op2;
273: set_op(PARAM1, result);
274: env->cc_x = (op1 >> (op2 - 1)) & 1;
275: FORCE_RET();
276: }
277:
278: OP(sar_cc)
279: {
280: int32_t op1 = get_op(PARAM1);
281: uint32_t op2 = get_op(PARAM2);
282: uint32_t result;
283: result = op1 >> op2;
284: set_op(PARAM1, result);
285: env->cc_x = (op1 >> (op2 - 1)) & 1;
286: FORCE_RET();
287: }
288:
289: /* Value extend. */
290:
291: OP(ext8u32)
292: {
293: uint32_t op2 = get_op(PARAM2);
294: set_op(PARAM1, (uint8_t)op2);
295: FORCE_RET();
296: }
297:
298: OP(ext8s32)
299: {
300: uint32_t op2 = get_op(PARAM2);
301: set_op(PARAM1, (int8_t)op2);
302: FORCE_RET();
303: }
304:
305: OP(ext16u32)
306: {
307: uint32_t op2 = get_op(PARAM2);
308: set_op(PARAM1, (uint16_t)op2);
309: FORCE_RET();
310: }
311:
312: OP(ext16s32)
313: {
314: uint32_t op2 = get_op(PARAM2);
315: set_op(PARAM1, (int16_t)op2);
316: FORCE_RET();
317: }
318:
319: /* Load/store ops. */
320: OP(ld8u32)
321: {
322: uint32_t addr = get_op(PARAM2);
323: set_op(PARAM1, ldub(addr));
324: FORCE_RET();
325: }
326:
327: OP(ld8s32)
328: {
329: uint32_t addr = get_op(PARAM2);
330: set_op(PARAM1, ldsb(addr));
331: FORCE_RET();
332: }
333:
334: OP(ld16u32)
335: {
336: uint32_t addr = get_op(PARAM2);
337: set_op(PARAM1, lduw(addr));
338: FORCE_RET();
339: }
340:
341: OP(ld16s32)
342: {
343: uint32_t addr = get_op(PARAM2);
344: set_op(PARAM1, ldsw(addr));
345: FORCE_RET();
346: }
347:
348: OP(ld32)
349: {
350: uint32_t addr = get_op(PARAM2);
351: set_op(PARAM1, ldl(addr));
352: FORCE_RET();
353: }
354:
355: OP(st8)
356: {
357: uint32_t addr = get_op(PARAM1);
358: stb(addr, get_op(PARAM2));
359: FORCE_RET();
360: }
361:
362: OP(st16)
363: {
364: uint32_t addr = get_op(PARAM1);
365: stw(addr, get_op(PARAM2));
366: FORCE_RET();
367: }
368:
369: OP(st32)
370: {
371: uint32_t addr = get_op(PARAM1);
372: stl(addr, get_op(PARAM2));
373: FORCE_RET();
374: }
375:
376: OP(ldf64)
377: {
378: uint32_t addr = get_op(PARAM2);
379: set_opf64(PARAM1, ldfq(addr));
380: FORCE_RET();
381: }
382:
383: OP(stf64)
384: {
385: uint32_t addr = get_op(PARAM1);
386: stfq(addr, get_opf64(PARAM2));
387: FORCE_RET();
388: }
389:
390: OP(flush_flags)
391: {
392: int cc_op = PARAM1;
393: if (cc_op == CC_OP_DYNAMIC)
394: cc_op = env->cc_op;
395: cpu_m68k_flush_flags(env, cc_op);
396: FORCE_RET();
397: }
398:
399: OP(divu)
400: {
401: uint32_t num;
402: uint32_t den;
403: uint32_t quot;
404: uint32_t rem;
405: uint32_t flags;
406:
407: num = env->div1;
408: den = env->div2;
409: /* ??? This needs to make sure the throwing location is accurate. */
410: if (den == 0)
411: RAISE_EXCEPTION(EXCP_DIV0);
412: quot = num / den;
413: rem = num % den;
414: flags = 0;
415: /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses
416: the address of a symbol, and gcc knows symbols can't have address
417: zero. */
418: if (PARAM1 == 2 && quot > 0xffff)
419: flags |= CCF_V;
420: if (quot == 0)
421: flags |= CCF_Z;
422: else if ((int32_t)quot < 0)
423: flags |= CCF_N;
424: env->div1 = quot;
425: env->div2 = rem;
426: env->cc_dest = flags;
427: FORCE_RET();
428: }
429:
430: OP(divs)
431: {
432: int32_t num;
433: int32_t den;
434: int32_t quot;
435: int32_t rem;
436: int32_t flags;
437:
438: num = env->div1;
439: den = env->div2;
440: if (den == 0)
441: RAISE_EXCEPTION(EXCP_DIV0);
442: quot = num / den;
443: rem = num % den;
444: flags = 0;
445: if (PARAM1 == 2 && quot != (int16_t)quot)
446: flags |= CCF_V;
447: if (quot == 0)
448: flags |= CCF_Z;
449: else if (quot < 0)
450: flags |= CCF_N;
451: env->div1 = quot;
452: env->div2 = rem;
453: env->cc_dest = flags;
454: FORCE_RET();
455: }
456:
457: OP(raise_exception)
458: {
459: RAISE_EXCEPTION(PARAM1);
460: FORCE_RET();
461: }
462:
463: /* Floating point comparison sets flags differently to other instructions. */
464:
465: OP(sub_cmpf64)
466: {
467: float64 src0;
468: float64 src1;
469: src0 = get_opf64(PARAM2);
470: src1 = get_opf64(PARAM3);
471: set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
472: FORCE_RET();
473: }
474:
475: OP(update_xflag_tst)
476: {
477: uint32_t op1 = get_op(PARAM1);
478: env->cc_x = op1;
479: FORCE_RET();
480: }
481:
482: OP(update_xflag_lt)
483: {
484: uint32_t op1 = get_op(PARAM1);
485: uint32_t op2 = get_op(PARAM2);
486: env->cc_x = (op1 < op2);
487: FORCE_RET();
488: }
489:
490: OP(get_xflag)
491: {
492: set_op(PARAM1, env->cc_x);
493: FORCE_RET();
494: }
495:
496: OP(logic_cc)
497: {
498: uint32_t op1 = get_op(PARAM1);
499: env->cc_dest = op1;
500: FORCE_RET();
501: }
502:
503: OP(update_cc_add)
504: {
505: uint32_t op1 = get_op(PARAM1);
506: uint32_t op2 = get_op(PARAM2);
507: env->cc_dest = op1;
508: env->cc_src = op2;
509: FORCE_RET();
510: }
511:
512: OP(fp_result)
513: {
514: env->fp_result = get_opf64(PARAM1);
515: FORCE_RET();
516: }
517:
518: OP(jmp)
519: {
520: GOTO_LABEL_PARAM(1);
521: }
522:
523: /* These ops involve a function call, which probably requires a stack frame
524: and breaks things on some hosts. */
525: OP(jmp_z32)
526: {
527: uint32_t arg = get_op(PARAM1);
528: if (arg == 0)
529: GOTO_LABEL_PARAM(2);
530: FORCE_RET();
531: }
532:
533: OP(jmp_nz32)
534: {
535: uint32_t arg = get_op(PARAM1);
536: if (arg != 0)
537: GOTO_LABEL_PARAM(2);
538: FORCE_RET();
539: }
540:
541: OP(jmp_s32)
542: {
543: int32_t arg = get_op(PARAM1);
544: if (arg < 0)
545: GOTO_LABEL_PARAM(2);
546: FORCE_RET();
547: }
548:
549: OP(jmp_ns32)
550: {
551: int32_t arg = get_op(PARAM1);
552: if (arg >= 0)
553: GOTO_LABEL_PARAM(2);
554: FORCE_RET();
555: }
556:
557: void OPPROTO op_goto_tb0(void)
558: {
559: GOTO_TB(op_goto_tb0, PARAM1, 0);
560: }
561:
562: void OPPROTO op_goto_tb1(void)
563: {
564: GOTO_TB(op_goto_tb1, PARAM1, 1);
565: }
566:
567: OP(exit_tb)
568: {
569: EXIT_TB();
570: }
571:
572:
573: /* Floating point. */
574: OP(f64_to_i32)
575: {
576: set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
577: FORCE_RET();
578: }
579:
580: OP(f64_to_f32)
581: {
582: union {
583: float32 f;
584: uint32_t i;
585: } u;
586: u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
587: set_op(PARAM1, u.i);
588: FORCE_RET();
589: }
590:
591: OP(i32_to_f64)
592: {
593: set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
594: FORCE_RET();
595: }
596:
597: OP(f32_to_f64)
598: {
599: union {
600: float32 f;
601: uint32_t i;
602: } u;
603: u.i = get_op(PARAM2);
604: set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
605: FORCE_RET();
606: }
607:
608: OP(absf64)
609: {
610: float64 op0 = get_opf64(PARAM2);
611: set_opf64(PARAM1, float64_abs(op0));
612: FORCE_RET();
613: }
614:
615: OP(chsf64)
616: {
617: float64 op0 = get_opf64(PARAM2);
618: set_opf64(PARAM1, float64_chs(op0));
619: FORCE_RET();
620: }
621:
622: OP(sqrtf64)
623: {
624: float64 op0 = get_opf64(PARAM2);
625: set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
626: FORCE_RET();
627: }
628:
629: OP(addf64)
630: {
631: float64 op0 = get_opf64(PARAM2);
632: float64 op1 = get_opf64(PARAM3);
633: set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
634: FORCE_RET();
635: }
636:
637: OP(subf64)
638: {
639: float64 op0 = get_opf64(PARAM2);
640: float64 op1 = get_opf64(PARAM3);
641: set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
642: FORCE_RET();
643: }
644:
645: OP(mulf64)
646: {
647: float64 op0 = get_opf64(PARAM2);
648: float64 op1 = get_opf64(PARAM3);
649: set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
650: FORCE_RET();
651: }
652:
653: OP(divf64)
654: {
655: float64 op0 = get_opf64(PARAM2);
656: float64 op1 = get_opf64(PARAM3);
657: set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
658: FORCE_RET();
659: }
660:
661: OP(iround_f64)
662: {
663: float64 op0 = get_opf64(PARAM2);
664: set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
665: FORCE_RET();
666: }
667:
668: OP(itrunc_f64)
669: {
670: float64 op0 = get_opf64(PARAM2);
671: set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
672: FORCE_RET();
673: }
674:
675: OP(compare_quietf64)
676: {
677: float64 op0 = get_opf64(PARAM2);
678: float64 op1 = get_opf64(PARAM3);
679: set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
680: FORCE_RET();
681: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.