|
|
1.1 root 1: /* $Id: m6888x.c,v 1.3 2005/03/23 11:51:17 fredette Exp $ */
2:
3: /* ic/m68k/m6888x.c - m68k floating-point implementation */
4:
5: /*
6: * Copyright (c) 2004 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: m6888x.c,v 1.3 2005/03/23 11:51:17 fredette Exp $");
38:
39: /* includes: */
40: #include "m68k-impl.h"
41:
42: /* macros: */
43:
44: /* m6888x FPCR bits: */
45: #define TME_M6888X_FPCR_RND_MASK (0x00000030)
46: #define TME_M6888X_FPCR_RND_RN (0x00000000)
47: #define TME_M6888X_FPCR_RND_RZ (0x00000010)
48: #define TME_M6888X_FPCR_RND_RM (0x00000020)
49: #define TME_M6888X_FPCR_RND_RP (0x00000030)
50: #define TME_M6888X_FPCR_PREC_MASK (0x000000c0)
51: #define TME_M6888X_FPCR_PREC_X (0x00000000)
52: #define TME_M6888X_FPCR_PREC_S (0x00000040)
53: #define TME_M6888X_FPCR_PREC_D (0x00000080)
54: #define TME_M6888X_FPCR_PREC_UNDEF (0x000000c0)
55: #define TME_M6888X_FPCR_ENABLE_INEX1 TME_BIT(8)
56: #define TME_M6888X_FPCR_ENABLE_INEX2 TME_BIT(9)
57: #define TME_M6888X_FPCR_ENABLE_DZ TME_BIT(10)
58: #define TME_M6888X_FPCR_ENABLE_UNFL TME_BIT(11)
59: #define TME_M6888X_FPCR_ENABLE_OVFL TME_BIT(12)
60: #define TME_M6888X_FPCR_ENABLE_OPERR TME_BIT(13)
61: #define TME_M6888X_FPCR_ENABLE_SNAN TME_BIT(14)
62: #define TME_M6888X_FPCR_ENABLE_BSUN TME_BIT(15)
63:
64: /* m6888x FPSR bits: */
65: #define TME_M6888X_FPSR_AEXC_INEX TME_BIT(3)
66: #define TME_M6888X_FPSR_AEXC_DZ TME_BIT(4)
67: #define TME_M6888X_FPSR_AEXC_UNFL TME_BIT(5)
68: #define TME_M6888X_FPSR_AEXC_OVFL TME_BIT(6)
69: #define TME_M6888X_FPSR_AEXC_IOP TME_BIT(7)
70: #define TME_M6888X_FPSR_EXC_INEX1 TME_M6888X_FPCR_ENABLE_INEX1
71: #define TME_M6888X_FPSR_EXC_INEX2 TME_M6888X_FPCR_ENABLE_INEX2
72: #define TME_M6888X_FPSR_EXC_DZ TME_M6888X_FPCR_ENABLE_DZ
73: #define TME_M6888X_FPSR_EXC_UNFL TME_M6888X_FPCR_ENABLE_UNFL
74: #define TME_M6888X_FPSR_EXC_OVFL TME_M6888X_FPCR_ENABLE_OVFL
75: #define TME_M6888X_FPSR_EXC_OPERR TME_M6888X_FPCR_ENABLE_OPERR
76: #define TME_M6888X_FPSR_EXC_SNAN TME_M6888X_FPCR_ENABLE_SNAN
77: #define TME_M6888X_FPSR_EXC_BSUN TME_M6888X_FPCR_ENABLE_BSUN
78: #define TME_M6888X_FPSR_QUOTIENT (0x00ff0000)
79: #define TME_M6888X_FPSR_CC_NAN TME_BIT(24)
80: #define TME_M6888X_FPSR_CC_I TME_BIT(25)
81: #define TME_M6888X_FPSR_CC_Z TME_BIT(26)
82: #define TME_M6888X_FPSR_CC_N TME_BIT(27)
83:
84: /* m6888x exceptions: */
85: #define TME_M6888X_VECTOR_BSUN (0x30)
86: #define TME_M6888X_VECTOR_INEX (0x31)
87: #define TME_M6888X_VECTOR_DZ (0x32)
88: #define TME_M6888X_VECTOR_UNFL (0x33)
89: #define TME_M6888X_VECTOR_OPERR (0x34)
90: #define TME_M6888X_VECTOR_OVFL (0x35)
91: #define TME_M6888X_VECTOR_SNAN (0x36)
92:
93: /* m6888x frame versions: */
94: #define TME_M6888X_FRAME_VERSION_NULL (0x00)
95: #define TME_M6888X_FRAME_VERSION_IDLE_M68881 (0x1f)
96: #define TME_M6888X_FRAME_VERSION_IDLE_M68882 (0x21)
97: #define TME_M6888X_FRAME_VERSION_IDLE_M68040 (0x23)
98:
99: /* m6888x frame sizes: */
100: #define TME_M6888X_FRAME_SIZE_NULL (0x00)
101: #define TME_M6888X_FRAME_SIZE_IDLE_M68881 (0x18)
102: #define TME_M6888X_FRAME_SIZE_IDLE_M68882 (0x38)
103: #define TME_M6888X_FRAME_SIZE_IDLE_M68040 (0x00)
104:
105: /* bits in a packed decimal real: */
106: #define TME_M6888X_PACKEDDEC_SM TME_BIT(31)
107: #define TME_M6888X_PACKEDDEC_SE TME_BIT(30)
108: #define TME_M6888X_PACKEDDEC_YY (TME_BIT(29) | TME_BIT(28))
109:
110: /* rounding precisions: */
111: #define TME_M6888X_ROUNDING_PRECISION_CTL (0)
112: #define TME_M6888X_ROUNDING_PRECISION_SINGLE (32)
113: #define TME_M6888X_ROUNDING_PRECISION_DOUBLE (64)
114: #define TME_M6888X_ROUNDING_PRECISION_EXTENDED80 (80)
115:
116: /* operation types: */
117: #define TME_M6888X_OPTYPE_MONADIC (0)
118: #define TME_M6888X_OPTYPE_DYADIC_SRC_DST (1)
119: #define TME_M6888X_OPTYPE_DYADIC_DST_SRC (2)
120:
121: /* special opmodes: */
122: #define TME_M6888X_FPGEN_OPMODE_FCMP (0x38)
123: #define TME_M6888X_FPGEN_OPMODE_FTST (0x3a)
124: #define TME_M6888X_FPGEN_OPMODE_OTHER (0xff)
125:
126: /* this causes an exception if there is no FPU, or if it isn't enabled: */
127: #define TME_M68K_INSN_FPU \
128: do { \
129: if (!ic->tme_m68k_fpu_enabled) { \
130: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL); \
131: } \
132: } while (/* CONSTCOND */ 0)
133:
134: /* these declare an m68k FPgen function: */
135: #define TME_M6888X_FPGEN_DECL(name) \
136: static void name _TME_P((struct tme_m68k *, const struct tme_float *, struct tme_float *))
137: #ifdef __STDC__
138: #define TME_M6888X_FPGEN(name) \
139: static void name(struct tme_m68k *ic, const struct tme_float *src, struct tme_float *dst)
140: #else /* !__STDC__ */
141: #define TME_M6888X_FPGEN(name) \
142: static void name(ic, src, dst) \
143: struct tme_m68k *ic; \
144: const struct tme_float *src; \
145: struct tme_float *dst;
146: #endif /* !__STDC__ */
147:
148: /* this gets the offset of a function in the IEEE 754 operations structure: */
149: #define TME_M6888X_IEEE754_OP(func) ((unsigned long) ((char *) &((struct tme_ieee754_ops *) 0)->func))
150:
151: /* these invoke an IEEE 754 operation: */
152: #define _TME_M6888X_IEEE754_OP(func, x) \
153: do { \
154: if ((func) == NULL) { \
155: if (ic->tme_m68k_fpu_incomplete_abort) { \
156: abort(); \
157: } \
158: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL); \
159: } \
160: (*(func)) x; \
161: } while (/* CONSTCOND */ 0)
162: #define TME_M6888X_IEEE754_OP_MONADIC(func, src, dst) \
163: _TME_M6888X_IEEE754_OP(ic->tme_m68k_fpu_ieee754_ops->func, (&ic->tme_m68k_fpu_ieee754_ctl, src, dst))
164: #define TME_M6888X_IEEE754_OP_DYADIC(func, src0, src1, dst) \
165: _TME_M6888X_IEEE754_OP(ic->tme_m68k_fpu_ieee754_ops->func, (&ic->tme_m68k_fpu_ieee754_ctl, src0, src1, dst))
166: #define TME_M6888X_IEEE754_OP_FUNC(ops_offset) \
167: (*((void **) (((char *) ic->tme_m68k_fpu_ieee754_ops) + (ops_offset))))
168: #define TME_M6888X_IEEE754_OP_RUN(ops_offset, t, x) \
169: _TME_M6888X_IEEE754_OP(((void (*) _TME_P(t)) TME_M6888X_IEEE754_OP_FUNC(ops_offset)), x)
170:
171: /* this gets the Nth raw unsigned 32-bit word from an EA operand: */
172: #define TME_M6888X_EA_OP32(n) (((const tme_uint32_t *) _op1)[(n)])
173:
174: /* this gets the Nth raw digit from a packed decimal operand: */
175: #define TME_M6888X_PD_DIGIT(n) ((TME_M6888X_EA_OP32((n) / 8) >> (4 * ((n) % 8))) & 0xf)
176:
177: /* types: */
178:
179: /* the FPgen opmode table: */
180: struct tme_m6888x_fpgen {
181:
182: /* any m6888x-specific function. this is normally NULL: */
183: void (*tme_m6888x_fpgen_func) _TME_P((struct tme_m68k *,
184: const struct tme_float *,
185: struct tme_float *));
186:
187: /* unless there is an m6888x-specific function, this is the offset
188: in the IEEE 754 operations struct of the function: */
189: unsigned long tme_m6888x_fpgen_func_ops_offset;
190:
191: /* the FPU types that have this function: */
192: tme_uint8_t tme_m6888x_fpgen_fpu_types;
193:
194: /* the operation type: */
195: tme_uint8_t tme_m6888x_fpgen_optype;
196:
197: /* the rounding mode used by the function: */
198: tme_uint8_t tme_m6888x_fpgen_rounding_mode;
199:
200: /* the rounding precision used by the function: */
201: tme_uint8_t tme_m6888x_fpgen_rounding_precision;
202: };
203:
204: /* an m6888x frame: */
205: struct tme_m6888x_frame {
206:
207: /* the frame version: */
208: tme_uint8_t tme_m6888x_frame_version;
209:
210: /* the frame size: */
211: tme_uint8_t tme_m6888x_frame_size;
212:
213: /* reserved: */
214: tme_uint16_t tme_m6888x_frame_reserved2;
215:
216: /* the command/condition register for an IDLE frame: */
217: tme_uint16_t tme_m6888x_frame_ccr;
218:
219: /* reserved: */
220: tme_uint16_t tme_m6888x_frame_reserved6;
221:
222: /* additional words: */
223: tme_uint32_t tme_m6888x_frame_words[(TME_M6888X_FRAME_SIZE_IDLE_M68882 / sizeof(tme_uint32_t)) - 1];
224: };
225:
226: /* prototypes: */
227: TME_M6888X_FPGEN_DECL(_tme_m6888x_fmovecr);
228: TME_M6888X_FPGEN_DECL(_tme_m6888x_fsincos);
229: TME_M6888X_FPGEN_DECL(_tme_m6888x_ftst);
230: TME_M6888X_FPGEN_DECL(_tme_m6888x_ftwotox);
231: TME_M6888X_FPGEN_DECL(_tme_m6888x_ftentox);
232: TME_M6888X_FPGEN_DECL(_tme_m6888x_flog2);
233: TME_M6888X_FPGEN_DECL(_tme_m6888x_fmod);
234: TME_M6888X_FPGEN_DECL(_tme_m6888x_frem);
235: TME_M6888X_FPGEN_DECL(_tme_m6888x_fsgldiv);
236: TME_M6888X_FPGEN_DECL(_tme_m6888x_fsglmul);
237:
238: /* globals: */
239:
240: /* special fpgen structures: */
241: static const struct tme_m6888x_fpgen _tme_m6888x_fpgen_fmovecr = {
242: _tme_m6888x_fmovecr,
243: 0,
244: TME_M68K_FPU_ANY,
245: TME_M6888X_OPTYPE_MONADIC,
246: TME_FLOAT_ROUND_NULL,
247: TME_M6888X_ROUNDING_PRECISION_CTL
248: };
249: static const struct tme_m6888x_fpgen _tme_m6888x_fpgen_fmove_rm = {
250: NULL,
251: 0,
252: TME_M68K_FPU_ANY,
253: TME_M6888X_OPTYPE_MONADIC,
254: TME_FLOAT_ROUND_NULL,
255: TME_M6888X_ROUNDING_PRECISION_CTL
256: };
257:
258: /* include the automatically generated code: */
259: #include "m6888x-auto.c"
260:
261: /* this resets the FPU: */
262: void
263: tme_m68k_fpu_reset(struct tme_m68k *ic)
264: {
265: unsigned int fp_i;
266:
267: /* put nonsignaling NaNs in the floating-point data registers: */
268: for (fp_i = 0;
269: fp_i < (sizeof(ic->tme_m68k_fpu_fpreg) / sizeof(ic->tme_m68k_fpu_fpreg[0]));
270: fp_i++) {
271: ic->tme_m68k_fpu_fpreg[fp_i].tme_float_format = TME_FLOAT_FORMAT_IEEE754_EXTENDED80;
272: ic->tme_m68k_fpu_fpreg[fp_i].tme_float_value_ieee754_extended80 = ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_default_nan_extended80;
273: }
274:
275: /* put zeroes in the floating-point control register, status
276: register, and instruction address register: */
277: ic->tme_m68k_fpu_fpcr = 0;
278: ic->tme_m68k_fpu_fpsr = 0;
279: ic->tme_m68k_fpu_fpiar = 0;
280: }
281:
282: /* this handles an exception: */
283: static void
284: _tme_m6888x_exception(struct tme_m68k *ic, tme_uint32_t exceptions)
285: {
286: tme_uint8_t vector;
287:
288: /* update the EXC byte in the FPSR: */
289: ic->tme_m68k_fpu_fpsr |= exceptions;
290:
291: /* update the AEXC byte in the FPSR: */
292: if (exceptions & (TME_M6888X_FPSR_EXC_SNAN | TME_M6888X_FPSR_EXC_OPERR | TME_M6888X_FPSR_EXC_BSUN)) {
293: ic->tme_m68k_fpu_fpsr |= TME_M6888X_FPSR_AEXC_IOP;
294: }
295: if (exceptions & TME_M6888X_FPSR_EXC_OVFL) {
296: ic->tme_m68k_fpu_fpsr |= TME_M6888X_FPSR_AEXC_OVFL;
297: }
298: if (exceptions & (TME_M6888X_FPSR_EXC_UNFL | TME_M6888X_FPSR_EXC_INEX2)) {
299: ic->tme_m68k_fpu_fpsr |= TME_M6888X_FPSR_AEXC_UNFL;
300: }
301: if (exceptions & TME_M6888X_FPSR_EXC_DZ) {
302: ic->tme_m68k_fpu_fpsr |= TME_M6888X_FPSR_AEXC_DZ;
303: }
304: if (exceptions & (TME_M6888X_FPSR_EXC_INEX1 | TME_M6888X_FPSR_EXC_INEX2 | TME_M6888X_FPSR_EXC_OVFL)) {
305: ic->tme_m68k_fpu_fpsr |= TME_M6888X_FPSR_AEXC_INEX;
306: }
307:
308: /* if any of the new exceptions are unmasked, take the exception: */
309: if ((ic->tme_m68k_fpu_fpcr & exceptions)) {
310:
311: /* because it's possible for an instruction to cause multiple
312: exceptions, the exceptions are prioritized: */
313: /* XXX FIXME - when the predecrement or postincrement addressing
314: modes are used, are the address registers updated before or
315: after any exceptions are generated? */
316: if (exceptions & TME_M6888X_FPSR_EXC_BSUN) {
317: vector = TME_M6888X_VECTOR_BSUN;
318: }
319: else if (exceptions & TME_M6888X_FPSR_EXC_SNAN) {
320: vector = TME_M6888X_VECTOR_SNAN;
321: }
322: else if (exceptions & TME_M6888X_FPSR_EXC_OPERR) {
323: vector = TME_M6888X_VECTOR_OPERR;
324: }
325: else if (exceptions & TME_M6888X_FPSR_EXC_OVFL) {
326: vector = TME_M6888X_VECTOR_OVFL;
327: }
328: else if (exceptions & TME_M6888X_FPSR_EXC_UNFL) {
329: vector = TME_M6888X_VECTOR_UNFL;
330: }
331: else if (exceptions & TME_M6888X_FPSR_EXC_DZ) {
332: vector = TME_M6888X_VECTOR_DZ;
333: }
334: else {
335: assert (exceptions & (TME_M6888X_FPSR_EXC_INEX2 | TME_M6888X_FPSR_EXC_INEX1));
336: vector = TME_M6888X_VECTOR_INEX;
337: }
338:
339: /* unlock any lock: */
340: if (ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock != NULL) {
341: (*ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock)();
342: ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock = NULL;
343: }
344:
345: /* take the exception: */
346: /* XXX FIXME - we signal all m6888x exceptions as cp
347: Postinstruction exceptions. exceptions generated by a cpGEN
348: instruction are probably supposed to be cp Preinstruction
349: exceptions, signaled at the time of the next cpGEN instruction: */
350: ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;
351: ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;
352: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(vector));
353: }
354: }
355:
356: /* the IEEE 754 exception handler: */
357: static void
358: _tme_m6888x_exception_ieee754(struct tme_ieee754_ctl *ctl, tme_int8_t exceptions_ieee754)
359: {
360: tme_uint32_t exceptions_m6888x;
361:
362: /* map the exceptions: */
363: exceptions_m6888x = 0;
364: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_GENERIC) {
365: exceptions_m6888x |= TME_M6888X_FPSR_EXC_OPERR;
366: }
367: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_INVALID) {
368: exceptions_m6888x |= TME_M6888X_FPSR_EXC_OPERR;
369: }
370: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_DIVBYZERO) {
371: exceptions_m6888x |= TME_M6888X_FPSR_EXC_DZ;
372: }
373: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_OVERFLOW) {
374: exceptions_m6888x |= TME_M6888X_FPSR_EXC_OVFL;
375: }
376: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_UNDERFLOW) {
377: exceptions_m6888x |= TME_M6888X_FPSR_EXC_UNFL;
378: }
379: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_INEXACT) {
380: exceptions_m6888x |= TME_M6888X_FPSR_EXC_INEX2;
381: }
382: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_OVERFLOW_INT) {
383: exceptions_m6888x |= TME_M6888X_FPSR_EXC_OVFL;
384: }
385: /* XXX FIXME - do denormals count as INEX2? */
386: if (exceptions_ieee754 & TME_FLOAT_EXCEPTION_DENORMAL) {
387: exceptions_m6888x |= TME_M6888X_FPSR_EXC_INEX2;
388: }
389:
390: _tme_m6888x_exception((struct tme_m68k *) ctl->tme_ieee754_ctl_private, exceptions_m6888x);
391: }
392:
393: /* signaling NaN tests: */
394: #define _TME_M6888X_IS_SNAN(a) (((a)->tme_float_ieee754_extended80_significand.tme_value64_uint32_hi & TME_BIT(30)) == 0)
395: static tme_int8_t
396: _tme_m6888x_is_snan_extended80(struct tme_float_ieee754_extended80 *value)
397: {
398: return (_TME_M6888X_IS_SNAN(value));
399: }
400:
401: /* NaN propagation: */
402: static void
403: _tme_m6888x_nan_from_nans_extended80(struct tme_ieee754_ctl *ctl,
404: const struct tme_float_ieee754_extended80 *a,
405: const struct tme_float_ieee754_extended80 *b,
406: struct tme_float_ieee754_extended80 *z)
407: {
408: struct tme_m68k *ic;
409: int a_is_snan;
410: int b_is_snan;
411:
412: /* recover the m68k: */
413: ic = ctl->tme_ieee754_ctl_private;
414:
415: /* see if any of the NaNs are signaling NaNs: */
416: a_is_snan = _TME_M6888X_IS_SNAN(a);
417: b_is_snan = _TME_M6888X_IS_SNAN(b);
418:
419: /* if either operand is a signaling NaN: */
420: if (a_is_snan || b_is_snan) {
421:
422: /* signal the signaling NaN: */
423: _tme_m6888x_exception(ic, TME_M6888X_FPSR_EXC_SNAN);
424: }
425:
426: /* if a and b are different NaNs: */
427: if ((a->tme_float_ieee754_extended80_sexp
428: != b->tme_float_ieee754_extended80_sexp)
429: || (a->tme_float_ieee754_extended80_significand.tme_value64_uint32_hi
430: != b->tme_float_ieee754_extended80_significand.tme_value64_uint32_hi)
431: || (a->tme_float_ieee754_extended80_significand.tme_value64_uint32_lo
432: != b->tme_float_ieee754_extended80_significand.tme_value64_uint32_lo)) {
433:
434: /* we need to return the NaN that is the destination operand: */
435: switch (_tme_m6888x_fpgen_opmode_table[TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 7)].tme_m6888x_fpgen_optype) {
436: default:
437: case TME_M6888X_OPTYPE_MONADIC: assert(FALSE);
438: case TME_M6888X_OPTYPE_DYADIC_SRC_DST: a = b; break;
439: case TME_M6888X_OPTYPE_DYADIC_DST_SRC: break;
440: }
441: }
442:
443: /* return a as the NaN, but make sure it's nonsignaling: */
444: *z = *a;
445: z->tme_float_ieee754_extended80_significand.tme_value64_uint32_hi |= TME_BIT(30);
446: }
447:
448: /* this prepares to run an fpgen instruction: */
449: static void inline
450: _tme_m6888x_fpgen_enter(struct tme_m68k *ic, const struct tme_m6888x_fpgen *fpgen)
451: {
452: tme_int8_t rounding_mode;
453: tme_int8_t rounding_precision;
454:
455: /* set the rounding mode: */
456: rounding_mode = fpgen->tme_m6888x_fpgen_rounding_mode;
457: if (__tme_predict_true(rounding_mode == TME_FLOAT_ROUND_NULL)) {
458: switch (ic->tme_m68k_fpu_fpcr & TME_M6888X_FPCR_RND_MASK) {
459: default: assert(FALSE);
460: case TME_M6888X_FPCR_RND_RN: rounding_mode = TME_FLOAT_ROUND_NEAREST_EVEN; break;
461: case TME_M6888X_FPCR_RND_RZ: rounding_mode = TME_FLOAT_ROUND_TO_ZERO; break;
462: case TME_M6888X_FPCR_RND_RM: rounding_mode = TME_FLOAT_ROUND_DOWN; break;
463: case TME_M6888X_FPCR_RND_RP: rounding_mode = TME_FLOAT_ROUND_UP; break;
464: }
465: }
466: ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_rounding_mode = rounding_mode;
467:
468: /* set the rounding precision: */
469: rounding_precision = fpgen->tme_m6888x_fpgen_rounding_precision;
470: if (__tme_predict_true(rounding_precision == TME_M6888X_ROUNDING_PRECISION_CTL)) {
471: switch (ic->tme_m68k_fpu_fpcr & TME_M6888X_FPCR_PREC_MASK) {
472: default: assert(FALSE); /* FALLTHROUGH */
473: case TME_M6888X_FPCR_PREC_UNDEF: /* FALLTHROUGH */
474: case TME_M6888X_FPCR_PREC_X: rounding_precision = TME_M6888X_ROUNDING_PRECISION_EXTENDED80; break;
475: case TME_M6888X_FPCR_PREC_S: rounding_precision = TME_M6888X_ROUNDING_PRECISION_SINGLE; break;
476: case TME_M6888X_FPCR_PREC_D: rounding_precision = TME_M6888X_ROUNDING_PRECISION_DOUBLE; break;
477: }
478: }
479: ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_extended80_rounding_precision = rounding_precision;
480:
481: /* clear the exception status byte in the FPSR: */
482: ic->tme_m68k_fpu_fpsr
483: &= ~(TME_M6888X_FPSR_EXC_INEX1
484: | TME_M6888X_FPSR_EXC_INEX2
485: | TME_M6888X_FPSR_EXC_DZ
486: | TME_M6888X_FPSR_EXC_UNFL
487: | TME_M6888X_FPSR_EXC_OVFL
488: | TME_M6888X_FPSR_EXC_OPERR
489: | TME_M6888X_FPSR_EXC_SNAN
490: | TME_M6888X_FPSR_EXC_BSUN);
491:
492: /* set the FPIAR: */
493: ic->tme_m68k_fpu_fpiar = ic->tme_m68k_ireg_pc;
494: }
495:
496: /* this sets the floating-point condition codes: */
497: static void inline
498: _tme_m6888x_fpcc(struct tme_m68k *ic, const struct tme_float *dst, unsigned int dst_formats)
499: {
500: tme_uint32_t fpcc;
501:
502: /* start with no floating-point condition codes: */
503: fpcc = 0;
504:
505: /* set N: */
506: if (tme_float_is_negative(dst, dst_formats)) {
507: fpcc |= TME_M6888X_FPSR_CC_N;
508: }
509:
510: /* set NAN or I or Z: */
511: if (tme_float_is_nan(dst, dst_formats)) {
512: fpcc |= TME_M6888X_FPSR_CC_NAN;
513: }
514: else if (tme_float_is_inf(dst, dst_formats)) {
515: fpcc |= TME_M6888X_FPSR_CC_I;
516: }
517: else if (tme_float_is_zero(dst, dst_formats)) {
518: fpcc |= TME_M6888X_FPSR_CC_Z;
519: }
520:
521: /* set the floating-point condition codes: */
522: ic->tme_m68k_fpu_fpsr
523: = ((ic->tme_m68k_fpu_fpsr
524: & ~(TME_M6888X_FPSR_CC_N
525: | TME_M6888X_FPSR_CC_NAN
526: | TME_M6888X_FPSR_CC_I
527: | TME_M6888X_FPSR_CC_Z))
528: | fpcc);
529: }
530:
531: TME_M68K_INSN(tme_m68k_fpgen)
532: {
533: struct tme_ieee754_ctl *ieee754_ctl;
534: tme_uint16_t command;
535: tme_uint16_t opmode;
536: const struct tme_m6888x_fpgen *fpgen;
537: unsigned int src_ea;
538: const struct tme_float *src;
539: struct tme_float *dst;
540: struct tme_float src_buffer;
541: struct tme_float dst_buffer;
542: struct tme_float conv_buffer;
543: union tme_value64 value64_buffer;
544: struct tme_float_ieee754_extended80 extended80_buffer;
545: unsigned int ea_mode;
546: unsigned int ea_reg;
547: unsigned int ea_size;
548: unsigned int src_specifier;
549: unsigned int digit_i;
550: tme_int32_t packed_value_int32;
551: struct tme_float packed_value_float;
552: tme_int32_t exponent;
553:
554: /* get the IEEE 754 ctl: */
555: ieee754_ctl = &ic->tme_m68k_fpu_ieee754_ctl;
556:
557: /* this is an FPU instruction: */
558: TME_M68K_INSN_FPU;
559:
560: /* get the coprocessor-dependent command word: */
561: command = TME_M68K_INSN_SPECOP;
562:
563: /* if this is an FMOVECR instruction
564: (command word pattern 0101 11dd dooo oooo): */
565: if ((command & 0xfc00) == 0x5c00
566: && TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 6) == 0) {
567:
568: /* use the FMOVECR opmode and FPgen structure: */
569: opmode = TME_M6888X_FPGEN_OPMODE_OTHER;
570: fpgen = &_tme_m6888x_fpgen_fmovecr;
571:
572: /* the source operand does not use the EA: */
573: src_ea = FALSE;
574: }
575:
576: /* otherwise, this is a generic FPgen instruction: */
577: else {
578:
579: /* get the opmode: */
580: opmode = TME_FIELD_EXTRACTU(command, 0, 7);
581:
582: /* decode this instruction: */
583: fpgen = &_tme_m6888x_fpgen_opmode_table[opmode];
584:
585: /* the source operand uses the EA if this is an EA-to-register
586: operation: */
587: src_ea = (command & TME_BIT(14)) != 0;
588: }
589:
590: /* catch illegal instructions: */
591: switch (fpgen->tme_m6888x_fpgen_fpu_types) {
592:
593: case TME_M68K_FPU_M6888X:
594: /* instructions not supported in hardware by the m68040 are caught
595: later: */
596: case TME_M68K_FPU_ANY:
597: break;
598:
599: case TME_M68K_FPU_M68040:
600: if (ic->tme_m68k_fpu_type == TME_M68K_FPU_M68040) {
601: break;
602: }
603: /* FALLTHROUGH */
604: case TME_M68K_FPU_NONE:
605: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
606: break;
607: default:
608: abort();
609: }
610:
611: /* get the source specifier: */
612: src_specifier = TME_FIELD_EXTRACTU(command, 10, 3);
613:
614: /* if the source operand uses the EA: */
615: if (src_ea) {
616:
617: /* get the EA mode and register fields: */
618: ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);
619: ea_reg = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
620:
621: /* if this is a data register direct EA: */
622: if (ea_mode == 0) {
623:
624: /* dispatch on the source specifier, since we need to
625: sign-extend a byte or word to long, and we need to check that
626: only a byte, word, long, or single precision source is
627: specified: */
628: switch (src_specifier) {
629: case TME_M6888X_TYPE_LONG:
630: case TME_M6888X_TYPE_SINGLE:
631: break;
632: case TME_M6888X_TYPE_WORD:
633: TME_M68K_INSN_OP1(tme_int32_t) = TME_EXT_S16_S32((tme_int16_t) TME_M68K_INSN_OP1(tme_int32_t));
634: break;
635: case TME_M6888X_TYPE_BYTE:
636: TME_M68K_INSN_OP1(tme_int32_t) = TME_EXT_S8_S32((tme_int8_t) TME_M68K_INSN_OP1(tme_int32_t));
637: break;
638: default:
639: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
640: break;
641: }
642: }
643:
644: /* otherwise, if this is an address register direct EA: */
645: else if (ea_mode == 1) {
646: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
647: }
648:
649: /* otherwise, if this is an immediate EA: */
650: else if (ea_mode == 7
651: && ea_reg == 4) {
652:
653: /* _op1 already points to the operand as one or more 32-bit
654: words: */
655: }
656:
657: /* otherwise, this is a memory EA: */
658: else {
659:
660: /* this instruction can fault: */
661: TME_M68K_INSN_CANFAULT;
662:
663: /* adjust ea_reg to reference the address register: */
664: ea_reg += TME_M68K_IREG_A0;
665:
666: /* dispatch on the source specifier to size the operand: */
667: switch (src_specifier) {
668: case TME_M6888X_TYPE_LONG:
669: case TME_M6888X_TYPE_SINGLE:
670: ea_size = TME_M68K_SIZE_32;
671: break;
672:
673: case TME_M6888X_TYPE_PACKEDDEC:
674: case TME_M6888X_TYPE_EXTENDED80:
675: ea_size = TME_M68K_SIZE_96;
676: break;
677:
678: case TME_M6888X_TYPE_WORD:
679: ea_size = TME_M68K_SIZE_16;
680: break;
681:
682: case TME_M6888X_TYPE_DOUBLE:
683: ea_size = TME_M68K_SIZE_64;
684: break;
685:
686: case TME_M6888X_TYPE_BYTE:
687: ea_size = TME_M68K_SIZE_8;
688: break;
689:
690: default:
691: abort();
692: }
693:
694: /* for the effective address predecrement and postincrement
695: modes, we require that these size macros correspond exactly
696: to the number of bytes: */
697: #if TME_M68K_SIZE_8 != 1
698: #error "TME_M68K_SIZE_8 must be 1"
699: #endif
700: #if TME_M68K_SIZE_16 != 2
701: #error "TME_M68K_SIZE_16 must be 2"
702: #endif
703: #if TME_M68K_SIZE_32 != 4
704: #error "TME_M68K_SIZE_32 must be 4"
705: #endif
706: #if TME_M68K_SIZE_64 != 8
707: #error "TME_M68K_SIZE_64 must be 8"
708: #endif
709: #if TME_M68K_SIZE_96 != 12
710: #error "TME_M68K_SIZE_96 must be 12"
711: #endif
712: #define TME_M68K_AREG_INCREMENT(areg, size) \
713: ((size) + (((size) == TME_M68K_SIZE_8 && (areg) == TME_M68K_IREG_A7) ? 1 : 0))
714:
715: /* address register indirect postincrement: */
716: if (ea_mode == 3) {
717: /* if we are not restarting, set the effective address: */
718: if (!TME_M68K_SEQUENCE_RESTARTING) {
719: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(ea_reg);
720: ic->tme_m68k_ireg_uint32(ea_reg) += TME_M68K_AREG_INCREMENT(ea_reg, ea_size);
721: }
722: }
723:
724: /* address register indirect predecrement: */
725: else if (ea_mode == 4) {
726: /* if we are not restarting, set the effective address: */
727: if (!TME_M68K_SEQUENCE_RESTARTING) {
728: ic->tme_m68k_ireg_uint32(ea_reg) -= TME_M68K_AREG_INCREMENT(ea_reg, ea_size);
729: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(ea_reg);
730: }
731: }
732:
733: /* dispatch on the operand size to read in the operand as one or
734: more 32-bit words. we will read up to three 32-bit words
735: into memx, memy, and memz, and we require that those
736: registers be contiguous in memory in that order: */
737: assert (((&ic->tme_m68k_ireg_memx32 + 1) == &ic->tme_m68k_ireg_memy32)
738: && ((&ic->tme_m68k_ireg_memy32 + 1) == &ic->tme_m68k_ireg_memz32));
739: _op1 = &ic->tme_m68k_ireg_memx32;
740:
741: switch (ea_size) {
742:
743: /* this can only happen when the source operand is a byte. we
744: sign-extend the byte to a long: */
745: case TME_M68K_SIZE_8:
746: tme_m68k_read_memx8(ic);
747: assert (!TME_M68K_SEQUENCE_RESTARTING);
748: ic->tme_m68k_ireg_memx32 = TME_EXT_S8_S32((tme_int8_t) ic->tme_m68k_ireg_memx8);
749: break;
750:
751: /* this can only happen when the source operand is a word. we
752: sign-extend the word to a long: */
753: case TME_M68K_SIZE_16:
754: tme_m68k_read_memx16(ic);
755: assert (!TME_M68K_SEQUENCE_RESTARTING);
756: ic->tme_m68k_ireg_memx32 = TME_EXT_S16_S32((tme_int16_t) ic->tme_m68k_ireg_memx16);
757: break;
758:
759: /* everything else is one or more 32-bit words: */
760: default:
761:
762: /* read the first 32 bits into the memx register: */
763: tme_m68k_read_memx32(ic);
764: if (ea_size == TME_M68K_SIZE_32) {
765: break;
766: }
767:
768: /* read the second 32 bits into the memy register: */
769: if (!TME_M68K_SEQUENCE_RESTARTING) {
770: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
771: }
772: tme_m68k_read_mem32(ic, TME_M68K_IREG_MEMY32);
773: if (ea_size == TME_M68K_SIZE_64) {
774: break;
775: }
776:
777: /* read the third 32 bits into the memz register: */
778: if (!TME_M68K_SEQUENCE_RESTARTING) {
779: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
780: }
781: tme_m68k_read_mem32(ic, TME_M68K_IREG_MEMZ32);
782: break;
783: }
784: }
785:
786: /* convert the operand from one or more raw 32-bit words into the
787: internal extended precision format: */
788: switch (src_specifier) {
789:
790: /* convert a 32-bit integral value. all of these integral types
791: have already been converted into 32-bit signed integers: */
792: case TME_M6888X_TYPE_BYTE:
793: case TME_M6888X_TYPE_WORD:
794: case TME_M6888X_TYPE_LONG:
795: tme_ieee754_extended80_from_int32(TME_M68K_INSN_OP1(tme_int32_t), &src_buffer);
796: break;
797:
798: /* convert a single-precision value: */
799: case TME_M6888X_TYPE_SINGLE:
800: tme_ieee754_single_value_set(&conv_buffer, TME_M6888X_EA_OP32(0));
801: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_from_single,
802: &conv_buffer,
803: &src_buffer);
804: break;
805:
806: /* convert a double-precision value: */
807: case TME_M6888X_TYPE_DOUBLE:
808: /* NB that TME_M6888X_EA_OP32(0) is always the most significant
809: 32 bits of the double, regardless of the endianness of the
810: host. this is how both the executer fetches an immediate
811: double, and how the memory code above reads a double: */
812: value64_buffer.tme_value64_uint32_hi = TME_M6888X_EA_OP32(0);
813: value64_buffer.tme_value64_uint32_lo = TME_M6888X_EA_OP32(1);
814: tme_ieee754_double_value_set(&conv_buffer, value64_buffer);
815: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_from_double,
816: &conv_buffer,
817: &src_buffer);
818: break;
819:
820: /* assign an extended-precision value: */
821: case TME_M6888X_TYPE_EXTENDED80:
822: /* NB that TME_M6888X_EA_OP32(0) is always the most significant
823: 32 bits of the extended80, regardless of the endianness of
824: the host. this is how both the executer fetches an immediate
825: extended80, and how the memory code above reads a extended80: */
826: extended80_buffer.tme_float_ieee754_extended80_sexp = TME_M6888X_EA_OP32(0) >> 16;
827: extended80_buffer.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi = TME_M6888X_EA_OP32(1);
828: extended80_buffer.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = TME_M6888X_EA_OP32(2);
829: tme_ieee754_extended80_value_set(&src_buffer, extended80_buffer);
830: break;
831:
832: case TME_M6888X_TYPE_PACKEDDEC:
833:
834: /* if this value's SE and YY bits are all set, and the exponent
835: is 0xFFF, the value is either an infinity or a NaN: */
836: if ((TME_M6888X_EA_OP32(0)
837: & (TME_M6888X_PACKEDDEC_SE
838: | TME_M6888X_PACKEDDEC_YY))
839: == (TME_M6888X_PACKEDDEC_SE
840: | TME_M6888X_PACKEDDEC_YY)
841: && TME_M6888X_PD_DIGIT(22) == 0xf
842: && TME_M6888X_PD_DIGIT(21) == 0xf
843: && TME_M6888X_PD_DIGIT(20) == 0xf) {
844:
845: /* "A packed decimal real data format with the SE and both Y
846: bits set, an exponent of $FFF and a nonzero 16-bit [sic]
847: decimal fraction is a NAN. When the FPU uses this format,
848: the fraction of the NAN is moved bit- by-bit into the
849: extended-precision mantissa of a floating-point data
850: register."
851:
852: moving the fraction bit-by-bit works for the infinities,
853: too, since both the packed decimal and the extended
854: precision infinities have all-bits-zero fractions: */
855: extended80_buffer.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi = TME_M6888X_EA_OP32(1);
856: extended80_buffer.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = TME_M6888X_EA_OP32(2);
857:
858: /* "The exponent of the register is set to signify a NAN,
859: and no conversion occurs. The MSB of the most
860: significant digit in the decimal fraction (the MSB of
861: digit 15) is a don't care, as in extended-precision NANs,
862: and the MSB of minus one of digit 15 is the SNAN bit. If
863: the NAN bit is a zero, then it is an SNAN."
864:
865: the biased exponent for NaNs and infinities is the same,
866: and the sign bit is a don't care for a NaN: */
867: extended80_buffer.tme_float_ieee754_extended80_sexp
868: = (0x7fff
869: | (TME_M6888X_EA_OP32(0) & TME_M6888X_PACKEDDEC_SM
870: ? 0x8000
871: : 0));
872:
873: /* finally create the source operand: */
874: tme_ieee754_extended80_value_set(&src_buffer, extended80_buffer);
875: }
876:
877: /* otherwise, this should be an in-range value: */
878: else {
879:
880: /* "The FPU does not detect non-decimal digits in the exponent,
881: integer, or fraction digits of an in-range packed decimal real data
882: format. These non-decimal digits are converted to binary in the
883: same manner as decimal digits; however, the result is probably
884: useless although it is repeatable." */
885:
886: /* convert the significand: */
887: tme_ieee754_extended80_from_int32(TME_M6888X_PD_DIGIT(16), &src_buffer);
888: tme_ieee754_extended80_from_int32(100000000, &conv_buffer);
889: packed_value_int32 = 0;
890: digit_i = 15;
891: do {
892: packed_value_int32 = (packed_value_int32 * 10) + TME_M6888X_PD_DIGIT(digit_i);
893: if ((digit_i % 8) == 0) {
894: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_mul,
895: &src_buffer,
896: &conv_buffer,
897: &src_buffer);
898: tme_ieee754_extended80_from_int32(packed_value_int32, &packed_value_float);
899: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_add,
900: &src_buffer,
901: &packed_value_float,
902: &src_buffer);
903: packed_value_int32 = 0;
904: }
905: } while (digit_i-- > 0);
906: if (TME_M6888X_EA_OP32(0) & TME_M6888X_PACKEDDEC_SM) {
907: tme_ieee754_extended80_from_int32(-1, &conv_buffer);
908: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_mul,
909: &src_buffer,
910: &conv_buffer,
911: &src_buffer);
912: }
913:
914: /* convert the exponent: */
915: exponent = 0;
916: digit_i = 22;
917: do {
918: exponent = (exponent * 10) + TME_M6888X_PD_DIGIT(digit_i);
919: } while (digit_i-- > 21);
920: if (TME_M6888X_EA_OP32(0) & TME_M6888X_PACKEDDEC_SE) {
921: exponent = -exponent;
922: }
923:
924: /* adjust the exponent, since we ignored the implicit decimal
925: point when converting the significand: */
926: exponent -= 16;
927:
928: /* scale the significand: */
929: tme_ieee754_extended80_from_int32(exponent, &conv_buffer);
930: tme_ieee754_extended80_radix10_scale(&ic->tme_m68k_fpu_ieee754_ctl, &src_buffer, &conv_buffer, &src_buffer);
931: }
932: break;
933:
934: default:
935: abort();
936: }
937:
938: /* the source operand is in the buffer: */
939: src = &src_buffer;
940: }
941:
942: /* otherwise, the source operand is in a register: */
943: else {
944: src = &ic->tme_m68k_fpu_fpreg[src_specifier];
945: }
946:
947: /* XXX FIXME - a check for operand types not implemented on the
948: m68040 would go here: */
949:
950: /* do the common fpgen setup: */
951: _tme_m6888x_fpgen_enter(ic, fpgen);
952:
953: /* get the destination operand: */
954: dst = &ic->tme_m68k_fpu_fpreg[TME_FIELD_EXTRACTU(command, 7, 3)];
955:
956: /* dispatch on the opmode to handle any special cases: */
957: switch (opmode) {
958:
959: /* these instructions don't modify the destination register: */
960: case TME_M6888X_FPGEN_OPMODE_FCMP:
961: case TME_M6888X_FPGEN_OPMODE_FTST:
962: dst_buffer = *dst;
963: dst = &dst_buffer;
964: break;
965:
966: default:
967: break;
968: }
969:
970: /* if this instruction is m6888x specific: */
971: if (fpgen->tme_m6888x_fpgen_func != NULL) {
972:
973: /* run the function: */
974: (*fpgen->tme_m6888x_fpgen_func)(ic, src, dst);
975: }
976:
977: /* otherwise, this instruction has an IEEE 754 operation: */
978: else {
979:
980: /* run the function: */
981: switch (fpgen->tme_m6888x_fpgen_optype) {
982: default: assert(FALSE);
983: case TME_M6888X_OPTYPE_MONADIC:
984: TME_M6888X_IEEE754_OP_RUN(fpgen->tme_m6888x_fpgen_func_ops_offset, (struct tme_ieee754_ctl *, const struct tme_float *, struct tme_float *), (&ic->tme_m68k_fpu_ieee754_ctl, src, dst));
985: break;
986: case TME_M6888X_OPTYPE_DYADIC_SRC_DST:
987: TME_M6888X_IEEE754_OP_RUN(fpgen->tme_m6888x_fpgen_func_ops_offset, (struct tme_ieee754_ctl *, const struct tme_float *, const struct tme_float *, struct tme_float *), (&ic->tme_m68k_fpu_ieee754_ctl, src, dst, dst));
988: break;
989: case TME_M6888X_OPTYPE_DYADIC_DST_SRC:
990: TME_M6888X_IEEE754_OP_RUN(fpgen->tme_m6888x_fpgen_func_ops_offset, (struct tme_ieee754_ctl *, const struct tme_float *, const struct tme_float *, struct tme_float *), (&ic->tme_m68k_fpu_ieee754_ctl, dst, src, dst));
991: break;
992: }
993: }
994:
995: /* set the floating-point condition codes: */
996: _tme_m6888x_fpcc(ic, dst, TME_FLOAT_FORMAT_IEEE754_EXTENDED80 | TME_FLOAT_FORMAT_IEEE754_EXTENDED80_BUILTIN);
997:
998: #undef TME_M68K_AREG_INCREMENT
999: }
1000:
1001: TME_M6888X_FPGEN(_tme_m6888x_fsincos)
1002: {
1003: /* "If FPs and FPc are specified to be the same register, the cosine
1004: result is first loaded into the register and then is overwritten
1005: with the sine result." */
1006: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_cos,
1007: src,
1008: &ic->tme_m68k_fpu_fpreg[TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3)]);
1009: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_sin,
1010: src,
1011: dst);
1012: }
1013:
1014: TME_M6888X_FPGEN(_tme_m6888x_ftst)
1015: {
1016: *dst = *src;
1017: }
1018:
1019: TME_M6888X_FPGEN(_tme_m6888x_ftwotox)
1020: {
1021: struct tme_float two;
1022:
1023: tme_ieee754_extended80_value_set_constant(&two, &tme_ieee754_extended80_constant_2e2ex[0]);
1024: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_pow,
1025: src,
1026: &two,
1027: dst);
1028: }
1029:
1030: TME_M6888X_FPGEN(_tme_m6888x_ftentox)
1031: {
1032: struct tme_float ten;
1033:
1034: tme_ieee754_extended80_value_set_constant(&ten, &tme_ieee754_extended80_constant_10e2ex[0]);
1035: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_pow,
1036: src,
1037: &ten,
1038: dst);
1039: }
1040:
1041: TME_M6888X_FPGEN(_tme_m6888x_flog2)
1042: {
1043: struct tme_float log_two;
1044:
1045: /* 2^log2(x) = e^log(x) */
1046: /* log(2^log2(x)) = log(e^log(x)) */
1047: /* log2(x) * log(2) = log(x) * log(e) */
1048: /* log2(x) = log(x) / log(2) */
1049:
1050: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_log,
1051: src,
1052: dst);
1053: tme_ieee754_extended80_value_set_constant(&log_two, &tme_ieee754_extended80_constant_ln_2);
1054: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_div,
1055: dst,
1056: &log_two,
1057: dst);
1058: }
1059:
1060: /* this internal function handles fmod and frem: */
1061: static void
1062: _tme_m6888x_fmodrem(struct tme_m68k *ic, const struct tme_float *src, struct tme_float *dst, int rounding)
1063: {
1064: struct tme_float quotient;
1065: struct tme_float quotient_divisor;
1066: tme_int32_t quotient_byte;
1067: struct tme_float two_hundred_fifty_six;
1068:
1069: /* check for a NaN operand: */
1070: if (__tme_predict_false(tme_ieee754_extended80_check_nan_dyadic(&ic->tme_m68k_fpu_ieee754_ctl, src, dst, dst))) {
1071: return;
1072: }
1073:
1074: /* if the source operand is zero, or if the destination operand is infinity: */
1075: if (tme_ieee754_extended80_is_zero(src)
1076: || tme_ieee754_extended80_is_inf(dst)) {
1077:
1078: /* return a NaN: */
1079: dst->tme_float_format = TME_FLOAT_FORMAT_IEEE754_EXTENDED80;
1080: dst->tme_float_value_ieee754_extended80 = ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_default_nan_extended80;
1081: return;
1082: }
1083:
1084: /* do the division. the quotient must not be a NaN: */
1085: ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_rounding_mode = rounding;
1086: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_div, dst, src, "ient);
1087: assert (!tme_ieee754_extended80_is_nan("ient));
1088:
1089: /* round the quotient to an integer: */
1090: /* XXX FIXME we assume that the rounding mode is the same as the division: */
1091: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_rint, "ient, "ient);
1092:
1093: /* get the remainder: */
1094: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_mul, src, "ient, "ient_divisor);
1095: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_sub, dst, "ient_divisor, dst);
1096:
1097: /* get the quotient's least significant eight bits, eventually
1098: truncating them to seven: */
1099: tme_ieee754_extended80_from_int32(256, &two_hundred_fifty_six);
1100: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_rem, "ient, &two_hundred_fifty_six, "ient);
1101: quotient_byte = tme_ieee754_extended80_value_builtin_get("ient);
1102: if (quotient_byte >= 0) {
1103: quotient_byte &= 0x7f;
1104: }
1105: else {
1106: quotient_byte = ((-quotient_byte) & 0x7f) | 0x80;
1107: }
1108:
1109: /* update the quotient byte in the FPSR: */
1110: TME_FIELD_MASK_DEPOSITU(ic->tme_m68k_fpu_fpsr, TME_M6888X_FPSR_QUOTIENT, ((tme_uint32_t) quotient_byte));
1111: }
1112:
1113: TME_M6888X_FPGEN(_tme_m6888x_fmod)
1114: {
1115: _tme_m6888x_fmodrem(ic, src, dst, TME_FLOAT_ROUND_TO_ZERO);
1116: }
1117:
1118: TME_M6888X_FPGEN(_tme_m6888x_frem)
1119: {
1120: _tme_m6888x_fmodrem(ic, src, dst, TME_FLOAT_ROUND_NEAREST_EVEN);
1121: }
1122:
1123: TME_M6888X_FPGEN(_tme_m6888x_fsgldiv)
1124: {
1125: struct tme_float src_trunc, dst_trunc;
1126: struct tme_float_ieee754_extended80 src_buffer, dst_buffer;
1127:
1128: /* check for a NaN operand: */
1129: if (__tme_predict_false(tme_ieee754_extended80_check_nan_dyadic(&ic->tme_m68k_fpu_ieee754_ctl, src, dst, dst))) {
1130: return;
1131: }
1132:
1133: /* if the source and destination operands are both zero or both
1134: infinity: */
1135: if ((tme_ieee754_extended80_is_zero(src)
1136: && tme_ieee754_extended80_is_zero(dst))
1137: || (tme_ieee754_extended80_is_inf(src)
1138: && tme_ieee754_extended80_is_inf(dst))) {
1139:
1140: /* return a NaN: */
1141: dst->tme_float_format = TME_FLOAT_FORMAT_IEEE754_EXTENDED80;
1142: dst->tme_float_value_ieee754_extended80 = ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_default_nan_extended80;
1143:
1144: /* set OPERR: */
1145: _tme_m6888x_exception(ic, TME_M6888X_FPSR_EXC_OPERR);
1146: return;
1147: }
1148:
1149: /* truncate the significands of the source and destination to no
1150: more than 24 bits to the right of the point. 24 becomes 25
1151: because the extended80 format includes the explicit integer bit: */
1152: tme_ieee754_extended80_value_set(&src_trunc, *tme_ieee754_extended80_value_get(src, &src_buffer));
1153: src_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi &= 0xffff8000;
1154: src_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = 0x00000000;
1155: tme_ieee754_extended80_value_set(&dst_trunc, *tme_ieee754_extended80_value_get(dst, &dst_buffer));
1156: dst_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi &= 0xffff8000;
1157: dst_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = 0x00000000;
1158:
1159: /* do the division: */
1160: ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_extended80_rounding_precision = 32;
1161: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_div, &dst_trunc, &src_trunc, dst);
1162: }
1163:
1164: TME_M6888X_FPGEN(_tme_m6888x_fsglmul)
1165: {
1166: struct tme_float src_trunc, dst_trunc;
1167: struct tme_float_ieee754_extended80 src_buffer, dst_buffer;
1168:
1169: /* check for a NaN operand: */
1170: if (__tme_predict_false(tme_ieee754_extended80_check_nan_dyadic(&ic->tme_m68k_fpu_ieee754_ctl, src, dst, dst))) {
1171: return;
1172: }
1173:
1174: /* if the source is a zero and the destination is a NaN, or vice
1175: versa: */
1176: if ((tme_ieee754_extended80_is_zero(src)
1177: && tme_ieee754_extended80_is_inf(dst))
1178: || (tme_ieee754_extended80_is_inf(src)
1179: && tme_ieee754_extended80_is_zero(dst))) {
1180:
1181: /* return a NaN: */
1182: dst->tme_float_format = TME_FLOAT_FORMAT_IEEE754_EXTENDED80;
1183: dst->tme_float_value_ieee754_extended80 = ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_default_nan_extended80;
1184:
1185: /* if the destination is a zero, set OPERR: */
1186: if (tme_ieee754_extended80_is_zero(dst)) {
1187: _tme_m6888x_exception(ic, TME_M6888X_FPSR_EXC_OPERR);
1188: }
1189: return;
1190: }
1191:
1192: /* truncate the significands of the source and destination to no
1193: more than 24 bits to the right of the point. 24 becomes 25
1194: because the extended80 format includes the explicit integer bit: */
1195: tme_ieee754_extended80_value_set(&src_trunc, *tme_ieee754_extended80_value_get(src, &src_buffer));
1196: src_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi &= 0xffff8000;
1197: src_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = 0x00000000;
1198: tme_ieee754_extended80_value_set(&dst_trunc, *tme_ieee754_extended80_value_get(dst, &dst_buffer));
1199: dst_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi &= 0xffff8000;
1200: dst_trunc.tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = 0x00000000;
1201:
1202: /* do the multiplication: */
1203: ic->tme_m68k_fpu_ieee754_ctl.tme_ieee754_ctl_extended80_rounding_precision = 32;
1204: TME_M6888X_IEEE754_OP_DYADIC(tme_ieee754_ops_extended80_mul, &src_trunc, &dst_trunc, dst);
1205: }
1206:
1207: TME_M6888X_FPGEN(_tme_m6888x_fmovecr)
1208: {
1209: const struct tme_ieee754_extended80_constant *constant;
1210: tme_uint16_t offset;
1211:
1212: offset = TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 7);
1213:
1214: /* the binary powers of 10 offsets: */
1215: if (offset >= 0x33
1216: && offset <= 0x3f) {
1217: constant = &tme_ieee754_extended80_constant_10e2ex[offset - 0x33];
1218: }
1219:
1220: /* anything else: */
1221: else {
1222: switch (offset) {
1223: case 0x00: constant = &tme_ieee754_extended80_constant_pi; break;
1224: case 0x0b: constant = &tme_ieee754_extended80_constant_log10_2; break;
1225: case 0x0c: constant = &tme_ieee754_extended80_constant_e; break;
1226: case 0x0d: constant = &tme_ieee754_extended80_constant_log2_e; break;
1227: case 0x0e: constant = &tme_ieee754_extended80_constant_log10_e; break;
1228: default:
1229: case 0x0f: constant = &tme_ieee754_extended80_constant_zero; break;
1230: case 0x30: constant = &tme_ieee754_extended80_constant_ln_2; break;
1231: case 0x31: constant = &tme_ieee754_extended80_constant_ln_10; break;
1232: case 0x32: constant = &tme_ieee754_extended80_constant_one; break;
1233: }
1234: }
1235:
1236: /* return the result: */
1237: tme_ieee754_extended80_value_set_constant(dst, constant);
1238: }
1239:
1240: /* this can fault: */
1241: TME_M68K_INSN(tme_m68k_fmove_rm)
1242: {
1243: unsigned int ea_mode;
1244: unsigned int ea_reg;
1245: unsigned int ea_size;
1246: unsigned int destination_format;
1247: const struct tme_float *src;
1248: struct tme_float src_buffer;
1249: const struct tme_float *dst;
1250: struct tme_float dst_buffer;
1251: unsigned int dst_formats;
1252: int src_is_nan;
1253: tme_int32_t value_int32_raw;
1254: tme_int32_t value_int32;
1255: tme_uint32_t single_buffer;
1256: const union tme_value64 *value64;
1257: union tme_value64 value64_buffer;
1258: const struct tme_float_ieee754_extended80 *extended80;
1259: struct tme_float_ieee754_extended80 extended80_buffer;
1260:
1261: /* get the EA mode and register fields: */
1262: ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);
1263: ea_reg = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
1264:
1265: /* get the destination format: */
1266: destination_format = TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 10, 3);
1267:
1268: /* if this is an address register direct EA, or this is a data
1269: register direct EA and the destination format isn't byte, word,
1270: long, or single, this is an illegal instruction: */
1271: if (ea_mode == 1
1272: || (ea_mode == 0
1273: && destination_format != TME_M6888X_TYPE_BYTE
1274: && destination_format != TME_M6888X_TYPE_WORD
1275: && destination_format != TME_M6888X_TYPE_LONG
1276: && destination_format != TME_M6888X_TYPE_SINGLE)) {
1277: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1278: }
1279:
1280: /* for the effective address predecrement and postincrement modes,
1281: and for the integer conversions, we require that these size
1282: macros correspond exactly to the number of bytes: */
1283: #if TME_M68K_SIZE_8 != 1
1284: #error "TME_M68K_SIZE_8 must be 1"
1285: #endif
1286: #if TME_M68K_SIZE_16 != 2
1287: #error "TME_M68K_SIZE_16 must be 2"
1288: #endif
1289: #if TME_M68K_SIZE_32 != 4
1290: #error "TME_M68K_SIZE_32 must be 4"
1291: #endif
1292: #if TME_M68K_SIZE_64 != 8
1293: #error "TME_M68K_SIZE_64 must be 8"
1294: #endif
1295: #if TME_M68K_SIZE_96 != 12
1296: #error "TME_M68K_SIZE_96 must be 12"
1297: #endif
1298: #define TME_M68K_AREG_INCREMENT(areg, size) \
1299: ((size) + (((size) == TME_M68K_SIZE_8 && (areg) == TME_M68K_IREG_A7) ? 1 : 0))
1300:
1301: /* dispatch on the destination format to get the size of the destination: */
1302: switch (destination_format) {
1303: case TME_M6888X_TYPE_BYTE: ea_size = TME_M68K_SIZE_8; break;
1304: case TME_M6888X_TYPE_WORD: ea_size = TME_M68K_SIZE_16; break;
1305: case TME_M6888X_TYPE_LONG: /* FALLTHROUGH */
1306: case TME_M6888X_TYPE_SINGLE: ea_size = TME_M68K_SIZE_32; break;
1307: case TME_M6888X_TYPE_DOUBLE: ea_size = TME_M68K_SIZE_64; break;
1308: default: assert(FALSE);
1309: case TME_M6888X_TYPE_PACKEDDEC: /* FALLTHROUGH */
1310: case TME_M6888X_TYPE_PACKEDDEC_DK: /* FALLTHROUGH */
1311: case TME_M6888X_TYPE_EXTENDED80: ea_size = TME_M68K_SIZE_96; break;
1312: }
1313:
1314: /* if we're not restarting: */
1315: if (!TME_M68K_SEQUENCE_RESTARTING) {
1316:
1317: /* do the common fpgen setup: */
1318: _tme_m6888x_fpgen_enter(ic, &_tme_m6888x_fpgen_fmove_rm);
1319:
1320: /* get the source register: */
1321: src = &ic->tme_m68k_fpu_fpreg[TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 7, 3)];
1322:
1323: /* check for a NaN operand: */
1324: src_is_nan = tme_ieee754_extended80_check_nan_monadic(&ic->tme_m68k_fpu_ieee754_ctl, src, &src_buffer);
1325: if (src_is_nan) {
1326: src = &src_buffer;
1327: }
1328:
1329: /* assume that the source is the destination: */
1330: dst = src;
1331: dst_formats = TME_FLOAT_FORMAT_IEEE754_EXTENDED80 | TME_FLOAT_FORMAT_IEEE754_EXTENDED80_BUILTIN;
1332:
1333: /* dispatch on the destination format: */
1334: switch (destination_format) {
1335:
1336: case TME_M6888X_TYPE_BYTE:
1337: case TME_M6888X_TYPE_WORD:
1338: case TME_M6888X_TYPE_LONG:
1339: if (src_is_nan) {
1340: /* XXX how is a NaN converted into an integer? */
1341: value_int32 = -1;
1342: _tme_m6888x_exception(ic, TME_M6888X_FPSR_EXC_OPERR);
1343: }
1344: else {
1345: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_extended80_to_int32, src, &value_int32_raw);
1346: value_int32 = TME_MIN(value_int32_raw, (2147483647 / (1L << (8 * (TME_M68K_SIZE_32 - ea_size)))));
1347: value_int32 = TME_MAX(value_int32, ((-1073741824 * 2) / (1L << (8 * (TME_M68K_SIZE_32 - ea_size)))));
1348: if (tme_ieee754_extended80_is_inf(src)
1349: || value_int32 != value_int32_raw) {
1350: _tme_m6888x_exception(ic, TME_M6888X_FPSR_EXC_OPERR);
1351: }
1352: }
1353: ic->tme_m68k_ireg_memx32 = value_int32;
1354: break;
1355:
1356: case TME_M6888X_TYPE_SINGLE:
1357: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_single_from_extended80, src, &dst_buffer);
1358: ic->tme_m68k_ireg_memx32 = *tme_ieee754_single_value_get(&dst_buffer, &single_buffer);
1359: dst = &dst_buffer;
1360: dst_formats = TME_FLOAT_FORMAT_IEEE754_SINGLE | TME_FLOAT_FORMAT_IEEE754_SINGLE_BUILTIN;
1361: break;
1362:
1363: case TME_M6888X_TYPE_DOUBLE:
1364: TME_M6888X_IEEE754_OP_MONADIC(tme_ieee754_ops_double_from_extended80, src, &dst_buffer);
1365: value64 = tme_ieee754_double_value_get(&dst_buffer, &value64_buffer);
1366: ic->tme_m68k_ireg_memx32 = value64->tme_value64_uint32_hi;
1367: ic->tme_m68k_ireg_memy32 = value64->tme_value64_uint32_lo;
1368: dst = &dst_buffer;
1369: dst_formats = TME_FLOAT_FORMAT_IEEE754_DOUBLE | TME_FLOAT_FORMAT_IEEE754_DOUBLE_BUILTIN;
1370: break;
1371:
1372: case TME_M6888X_TYPE_EXTENDED80:
1373: extended80 = tme_ieee754_extended80_value_get(src, &extended80_buffer);
1374: ic->tme_m68k_ireg_memx32 = extended80->tme_float_ieee754_extended80_sexp << 16;
1375: ic->tme_m68k_ireg_memy32 = extended80->tme_float_ieee754_extended80_significand.tme_value64_uint32_hi;
1376: ic->tme_m68k_ireg_memz32 = extended80->tme_float_ieee754_extended80_significand.tme_value64_uint32_lo;
1377: break;
1378:
1379: default:
1380: assert(FALSE);
1381: /* FALLTHROUGH */
1382:
1383: case TME_M6888X_TYPE_PACKEDDEC:
1384: case TME_M6888X_TYPE_PACKEDDEC_DK:
1385:
1386: /* we punt on the packed-decimal format for now: */
1387: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1388: break;
1389: }
1390:
1391: /* set the floating-point condition codes: */
1392: _tme_m6888x_fpcc(ic, dst, dst_formats);
1393: }
1394:
1395: /* if this is a data register direct EA: */
1396: if (ea_mode == 0) {
1397:
1398: switch (ea_size) {
1399: case TME_M68K_SIZE_8:
1400: ic->tme_m68k_ireg_uint8(ea_reg << 2) = ic->tme_m68k_ireg_memx32;
1401: break;
1402:
1403: case TME_M68K_SIZE_16:
1404: ic->tme_m68k_ireg_uint8(ea_reg << 1) = ic->tme_m68k_ireg_memx32;
1405: break;
1406:
1407: default:
1408: assert (FALSE);
1409: /* FALLTHROUGH */
1410:
1411: case TME_M68K_SIZE_32:
1412: ic->tme_m68k_ireg_uint32(ea_reg) = ic->tme_m68k_ireg_memx32;
1413: break;
1414: }
1415: }
1416:
1417: /* otherwise, this is a memory EA: */
1418: else {
1419:
1420: /* this instruction can fault: */
1421: TME_M68K_INSN_CANFAULT;
1422:
1423: /* adjust ea_reg to reference the address register: */
1424: ea_reg += TME_M68K_IREG_A0;
1425:
1426: /* address register indirect postincrement: */
1427: if (ea_mode == 3) {
1428: /* if we are not restarting, set the effective address: */
1429: if (!TME_M68K_SEQUENCE_RESTARTING) {
1430: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(ea_reg);
1431: ic->tme_m68k_ireg_uint32(ea_reg) += TME_M68K_AREG_INCREMENT(ea_reg, ea_size);
1432: }
1433: }
1434:
1435: /* address register indirect predecrement: */
1436: else if (ea_mode == 4) {
1437: /* if we are not restarting, set the effective address: */
1438: if (!TME_M68K_SEQUENCE_RESTARTING) {
1439: ic->tme_m68k_ireg_uint32(ea_reg) -= TME_M68K_AREG_INCREMENT(ea_reg, ea_size);
1440: ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(ea_reg);
1441: }
1442: }
1443:
1444: /* dispatch on the operand size to write in the destination as one
1445: or more 32-bit words. we will write up to three 32-bit words
1446: into memx, memy, and memz, and we require that those registers
1447: be contiguous in memory in that order: */
1448: assert (((&ic->tme_m68k_ireg_memx32 + 1) == &ic->tme_m68k_ireg_memy32)
1449: && ((&ic->tme_m68k_ireg_memy32 + 1) == &ic->tme_m68k_ireg_memz32));
1450: _op1 = &ic->tme_m68k_ireg_memx32;
1451:
1452: switch (ea_size) {
1453:
1454: /* this can only happen when the source operand is a byte: */
1455: case TME_M68K_SIZE_8:
1456: tme_m68k_write_memx8(ic);
1457: assert (!TME_M68K_SEQUENCE_RESTARTING);
1458: break;
1459:
1460: /* this can only happen when the source operand is a word: */
1461: case TME_M68K_SIZE_16:
1462: tme_m68k_write_memx16(ic);
1463: assert (!TME_M68K_SEQUENCE_RESTARTING);
1464: break;
1465:
1466: /* everything else is one or more 32-bit words: */
1467: default:
1468:
1469: /* write the first 32 bits from the memx register: */
1470: tme_m68k_write_memx32(ic);
1471: if (ea_size == TME_M68K_SIZE_32) {
1472: break;
1473: }
1474:
1475: /* write the second 32 bits from the memy register: */
1476: if (!TME_M68K_SEQUENCE_RESTARTING) {
1477: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1478: }
1479: tme_m68k_write_mem32(ic, TME_M68K_IREG_MEMY32);
1480: if (ea_size == TME_M68K_SIZE_64) {
1481: break;
1482: }
1483:
1484: /* write the third 32 bits from the memz register: */
1485: if (!TME_M68K_SEQUENCE_RESTARTING) {
1486: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1487: }
1488: tme_m68k_write_mem32(ic, TME_M68K_IREG_MEMZ32);
1489: break;
1490: }
1491: }
1492:
1493: TME_M68K_INSN_OK;
1494:
1495: #undef TME_M68K_AREG_INCREMENT
1496: }
1497:
1498: /* this can fault: */
1499: TME_M68K_INSN(tme_m68k_fmovem)
1500: {
1501: unsigned int ea_mode;
1502: unsigned int ea_reg;
1503: unsigned int register_to_memory;
1504: tme_uint16_t mask;
1505: unsigned int bit;
1506: unsigned int first_register;
1507: struct tme_float *fpreg;
1508: const struct tme_float_ieee754_extended80 *extended80;
1509: struct tme_float_ieee754_extended80 extended80_buffer;
1510:
1511: TME_M68K_INSN_FPU;
1512:
1513: /* get the EA mode and register fields: */
1514: ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);
1515: ea_reg = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
1516:
1517: /* get the register-to-memory flag: */
1518: register_to_memory = (TME_M68K_INSN_SPECOP & TME_BIT(13)) != 0;
1519:
1520: /* immediate EAs must have already been caught as illegal instructions: */
1521: assert (!(ea_mode == 7 && ea_reg == 4));
1522:
1523: /* if this is a data register direct EA or an address register
1524: direct EA, or if this is a predecrement EA and this is a
1525: memory-to-register operation, or if this is a postincrement EA
1526: and this is a register-to-memory operation, this is an illegal
1527: instruction: */
1528: if (ea_mode == 0
1529: || ea_mode == 1
1530: || (ea_mode == 4
1531: && !register_to_memory)
1532: || (ea_mode == 3
1533: && register_to_memory)) {
1534: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1535: }
1536:
1537: /* get the register list: */
1538: mask = TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 8);
1539:
1540: /* if the register list is dynamic: */
1541: if (TME_M68K_INSN_SPECOP & TME_BIT(11)) {
1542:
1543: /* the mask field is supposed to contain only a data register
1544: number: */
1545: if (mask & 0x8f) {
1546: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1547: }
1548:
1549: /* get the dynamic register list: */
1550: mask = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(mask, 4, 3));
1551: }
1552:
1553: /* get the FP register corresponding to bit 7 in the mask: */
1554: if (TME_M68K_INSN_SPECOP & TME_BIT(12)) {
1555: first_register = 0;
1556: }
1557: else {
1558:
1559: /* this must be a predecrement EA: */
1560: if (ea_mode != 4) {
1561: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1562: }
1563:
1564: first_register = 7;
1565: }
1566:
1567: /* if the mask is empty, return now: */
1568: if (mask == 0) {
1569: TME_M68K_INSN_OK;
1570: }
1571:
1572: /* this instruction can fault: */
1573: TME_M68K_INSN_CANFAULT;
1574:
1575: /* we require that TME_M68K_SIZE_96 be 12: */
1576: #if TME_M68K_SIZE_96 != 12
1577: #error "TME_M68K_SIZE_96 must be 12"
1578: #endif
1579:
1580: /* loop over the bits in the mask: */
1581: for (bit = 0; bit < 8; bit++, mask <<= 1) {
1582:
1583: /* skip this register if its bit isn't set in the mask: */
1584: if (!(mask & 0x80)) {
1585: continue;
1586: }
1587:
1588: /* get this register: */
1589: fpreg = &ic->tme_m68k_fpu_fpreg[bit ^ first_register];
1590:
1591: /* if this is a register-to-memory operation: */
1592: if (register_to_memory) {
1593:
1594: /* if this is a predecrement EA, and we're not restarting,
1595: predecrement the EA: */
1596: if (!TME_M68K_SEQUENCE_RESTARTING
1597: && ea_mode == 4) {
1598: ic->_tme_m68k_ea_address = (ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ea_reg) -= TME_M68K_SIZE_96);
1599: }
1600:
1601: /* write out the register: */
1602: extended80 = tme_ieee754_extended80_value_get(fpreg, &extended80_buffer);
1603: if (!TME_M68K_SEQUENCE_RESTARTING) {
1604: ic->tme_m68k_ireg_memx32 = extended80->tme_float_ieee754_extended80_sexp << 16;
1605: }
1606: tme_m68k_write_memx32(ic);
1607: if (!TME_M68K_SEQUENCE_RESTARTING) {
1608: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1609: ic->tme_m68k_ireg_memx32 = extended80->tme_float_ieee754_extended80_significand.tme_value64_uint32_hi;
1610: }
1611: tme_m68k_write_memx32(ic);
1612: if (!TME_M68K_SEQUENCE_RESTARTING) {
1613: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1614: ic->tme_m68k_ireg_memx32 = extended80->tme_float_ieee754_extended80_significand.tme_value64_uint32_lo;
1615: }
1616: tme_m68k_write_memx32(ic);
1617: }
1618:
1619: /* otherwise, this is a memory-to-register operation: */
1620: else {
1621:
1622: /* read in this register: */
1623: tme_m68k_read_memx32(ic);
1624: if (!TME_M68K_SEQUENCE_RESTARTING) {
1625: fpreg->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_sexp = (ic->tme_m68k_ireg_memx32 >> 16);
1626: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1627: }
1628: tme_m68k_read_memx32(ic);
1629: if (!TME_M68K_SEQUENCE_RESTARTING) {
1630: fpreg->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi = ic->tme_m68k_ireg_memx32;
1631: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1632: }
1633: tme_m68k_read_memx32(ic);
1634: if (!TME_M68K_SEQUENCE_RESTARTING) {
1635: fpreg->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = ic->tme_m68k_ireg_memx32;
1636: ic->_tme_m68k_ea_address += TME_M68K_SIZE_32;
1637: fpreg->tme_float_format = TME_FLOAT_FORMAT_IEEE754_EXTENDED80;
1638: }
1639: }
1640: }
1641:
1642: /* if this is the postincrement addressing mode: */
1643: if (ea_mode == 3) {
1644:
1645: /* update the address register: */
1646: assert (!TME_M68K_SEQUENCE_RESTARTING);
1647: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ea_reg) = ic->_tme_m68k_ea_address;
1648: }
1649:
1650: TME_M68K_INSN_OK;
1651: }
1652:
1653: /* this can fault: */
1654: TME_M68K_INSN(tme_m68k_fmovemctl)
1655: {
1656: tme_uint16_t mask;
1657: unsigned int ea_mode;
1658: unsigned int ea_reg;
1659: unsigned int register_to_memory;
1660: unsigned int bit;
1661: tme_uint32_t *value;
1662:
1663: TME_M68K_INSN_FPU;
1664:
1665: /* get the register mask: */
1666: mask = TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 10, 3);
1667:
1668: /* get the EA mode and register fields: */
1669: ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);
1670: ea_reg = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
1671:
1672: /* get the register-to-memory flag: */
1673: register_to_memory = (TME_M68K_INSN_SPECOP & TME_BIT(13)) != 0;
1674:
1675: /* if no registers have been selected, or if this is a data register
1676: direct EA and multiple registers have been selected, or if this
1677: is an address register direct EA and the floating point
1678: instruction address register is not the single register selected,
1679: this is an illegal instruction: */
1680: if (mask == 0
1681: || (ea_mode == 0
1682: && ((mask & (mask - 1)) != 0))
1683: || (ea_mode == 1
1684: && mask != 1)) {
1685: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1686: }
1687:
1688: /* if this isn't a data register direct EA or an address register
1689: direct EA, this instruction can fault: */
1690: if (ea_mode != 0
1691: && ea_mode != 1) {
1692: TME_M68K_INSN_CANFAULT;
1693: }
1694:
1695: /* if we're not restarting, and this is the predecrement addressing mode: */
1696: if (!TME_M68K_SEQUENCE_RESTARTING
1697: && ea_mode == 4) {
1698:
1699: /* update the effective address: */
1700: for (; mask != 0; ic->_tme_m68k_ea_address -= sizeof(tme_uint32_t), mask &= (mask - 1));
1701:
1702: /* update the address register: */
1703: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ea_reg) = ic->_tme_m68k_ea_address;
1704: }
1705:
1706: /* get the register mask: */
1707: mask = TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 10, 3);
1708:
1709: /* loop over the register mask bits: */
1710: for (bit = 3; bit-- > 0; ) {
1711:
1712: /* ignore this register if its bit isn't set: */
1713: if (!(mask & (1 << bit))) {
1714: continue;
1715: }
1716:
1717: /* get a pointer to this register's value: */
1718: value = (bit == 2
1719: ? &ic->tme_m68k_fpu_fpcr
1720: : bit == 1
1721: ? &ic->tme_m68k_fpu_fpsr
1722: : &ic->tme_m68k_fpu_fpiar);
1723:
1724: /* transfer this register's value: */
1725:
1726: /* if this is a data register direct EA: */
1727: if (ea_mode == 0) {
1728: if (register_to_memory) {
1729: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0 + ea_reg) = *value;
1730: }
1731: else {
1732: *value = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0 + ea_reg);
1733: }
1734: }
1735:
1736: /* if this is an address register direct EA: */
1737: else if (ea_mode == 1) {
1738: if (register_to_memory) {
1739: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ea_reg) = *value;
1740: }
1741: else {
1742: *value = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ea_reg);
1743: }
1744: }
1745:
1746: /* otherwise, this is a memory EA: */
1747: else {
1748: if (register_to_memory) {
1749: if (!TME_M68K_SEQUENCE_RESTARTING) {
1750: ic->tme_m68k_ireg_memx32 = *value;
1751: }
1752: tme_m68k_write_memx32(ic);
1753: if (!TME_M68K_SEQUENCE_RESTARTING) {
1754: ic->_tme_m68k_ea_address += sizeof(tme_uint32_t);
1755: }
1756: }
1757: else {
1758: tme_m68k_read_memx32(ic);
1759: if (!TME_M68K_SEQUENCE_RESTARTING) {
1760: *value = ic->tme_m68k_ireg_memx32;
1761: ic->_tme_m68k_ea_address += sizeof(tme_uint32_t);
1762: }
1763: }
1764: }
1765: }
1766:
1767: /* if this is the postincrement addressing mode: */
1768: if (ea_mode == 3) {
1769:
1770: /* update the address register: */
1771: assert (!TME_M68K_SEQUENCE_RESTARTING);
1772: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ea_reg) = ic->_tme_m68k_ea_address;
1773: }
1774:
1775: TME_M68K_INSN_OK;
1776: }
1777:
1778: /* this evaluates a floating-point predicate: */
1779: static int
1780: _tme_m6888x_predicate_true(struct tme_m68k *ic, tme_uint16_t predicate)
1781: {
1782: unsigned int cc_nan;
1783: unsigned int cc_i;
1784: unsigned int cc_z;
1785: unsigned int cc_n;
1786:
1787: /* get the condition codes: */
1788: cc_nan = (ic->tme_m68k_fpu_fpsr & TME_M6888X_FPSR_CC_NAN) != 0;
1789: cc_i = (ic->tme_m68k_fpu_fpsr & TME_M6888X_FPSR_CC_I) != 0;
1790: cc_z = (ic->tme_m68k_fpu_fpsr & TME_M6888X_FPSR_CC_Z) != 0;
1791: cc_n = (ic->tme_m68k_fpu_fpsr & TME_M6888X_FPSR_CC_N) != 0;
1792:
1793: /* if this predicate is greater than 0x1f, this is an illegal instruction: */
1794: if (predicate > 0x1f) {
1795: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_ILL);
1796: }
1797:
1798: /* if this predicate sets BSUN when NaN is set: */
1799: if (predicate > 0x0f) {
1800:
1801: /* if NaN is set, set BSUN: */
1802: if (cc_nan) {
1803: _tme_m6888x_exception(ic, TME_M6888X_FPSR_EXC_BSUN);
1804: }
1805:
1806: /* adjust predicate to be its non-BSUN-setting version: */
1807: predicate -= 0x10;
1808: }
1809:
1810: /* dispatch on the predicate: */
1811: switch (predicate) {
1812: default: assert(FALSE);
1813: case 0x00: predicate = FALSE; break; /* F, SF */
1814: case 0x01: predicate = cc_z; break; /* EQ, SEQ */
1815: case 0x02: predicate = !(cc_nan || cc_z || cc_n); break; /* OGT, GT */
1816: case 0x03: predicate = cc_z || !(cc_nan || cc_n); break; /* OGE, GE */
1817: case 0x04: predicate = cc_n && !(cc_nan || cc_z); break; /* OLT, LT */
1818: case 0x05: predicate = cc_z || (cc_n && !cc_nan); break; /* OLE, LE */
1819: case 0x06: predicate = !(cc_nan || cc_z); break; /* OGL, GL */
1820: case 0x07: predicate = !cc_nan; break; /* OR, GLE */
1821: case 0x08: predicate = cc_nan; break; /* UN, NGLE */
1822: case 0x09: predicate = (cc_nan || cc_z); break; /* UEQ, NGL */
1823: case 0x0a: predicate = cc_nan || !(cc_n || cc_z); break; /* UGT, NLE */
1824: case 0x0b: predicate = cc_nan || cc_z || !cc_n; break; /* UGE, NLT */
1825: case 0x0c: predicate = cc_nan || (cc_n && !cc_z); break; /* ULT, NGE */
1826: case 0x0d: predicate = (cc_nan || cc_z || cc_n); break; /* ULE, NGT */
1827: case 0x0e: predicate = !cc_z; break; /* NE, SNE */
1828: case 0x0f: predicate = FALSE; break; /* T, ST */
1829: }
1830:
1831: return (predicate);
1832: }
1833:
1834: /* this cannot fault: */
1835: TME_M68K_INSN(tme_m68k_fdbcc)
1836: {
1837: TME_M68K_INSN_FPU;
1838:
1839: if (_tme_m6888x_predicate_true(ic, TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 6))) {
1840: if (--TME_M68K_INSN_OP0(tme_int16_t) != -1) {
1841: TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_pc
1842: + 4
1843: + TME_EXT_S16_U32(TME_M68K_INSN_OP1(tme_int16_t)));
1844: }
1845: }
1846: TME_M68K_INSN_OK;
1847: }
1848:
1849: /* this cannot fault: */
1850: TME_M68K_INSN(tme_m68k_ftrapcc)
1851: {
1852: TME_M68K_INSN_FPU;
1853: if (_tme_m6888x_predicate_true(ic, TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 6))) {
1854: ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;
1855: ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;
1856: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_TRAP));
1857: }
1858: TME_M68K_INSN_OK;
1859: }
1860:
1861: /* this cannot fault: */
1862: TME_M68K_INSN(tme_m68k_fscc)
1863: {
1864: TME_M68K_INSN_FPU;
1865: TME_M68K_INSN_OP1(tme_uint8_t) =
1866: (_tme_m6888x_predicate_true(ic, TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 6))
1867: ? 0xff
1868: : 0x00);
1869: TME_M68K_INSN_OK;
1870: }
1871:
1872: /* this cannot fault: */
1873: TME_M68K_INSN(tme_m68k_fbcc)
1874: {
1875: TME_M68K_INSN_FPU;
1876:
1877: if (_tme_m6888x_predicate_true(ic, TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 6))) {
1878: TME_M68K_INSN_BRANCH(ic->tme_m68k_ireg_pc
1879: + sizeof(tme_uint16_t)
1880: + TME_M68K_INSN_OP0(tme_uint32_t));
1881: }
1882: TME_M68K_INSN_OK;
1883: }
1884:
1885: /* this can fault: */
1886: TME_M68K_INSN(tme_m68k_fsave)
1887: {
1888: struct tme_m6888x_frame frame;
1889: tme_uint32_t frame_size;
1890:
1891: TME_M68K_INSN_FPU;
1892: TME_M68K_INSN_PRIV;
1893: TME_M68K_INSN_CANFAULT;
1894:
1895: /* zero the frame: */
1896: memset(&frame, 0, sizeof(frame));
1897:
1898: /* dispatch on the FPU type: */
1899: switch (ic->tme_m68k_fpu_type) {
1900: default: assert (FALSE);
1901: case TME_M68K_FPU_M68881:
1902: frame.tme_m6888x_frame_version = TME_M6888X_FRAME_VERSION_IDLE_M68881;
1903: frame.tme_m6888x_frame_size = TME_M6888X_FRAME_SIZE_IDLE_M68881;
1904: break;
1905: case TME_M68K_FPU_M68882:
1906: frame.tme_m6888x_frame_version = TME_M6888X_FRAME_VERSION_IDLE_M68882;
1907: frame.tme_m6888x_frame_size = TME_M6888X_FRAME_SIZE_IDLE_M68882;
1908: break;
1909: case TME_M68K_FPU_M68040:
1910: frame.tme_m6888x_frame_version = TME_M6888X_FRAME_VERSION_IDLE_M68040;
1911: frame.tme_m6888x_frame_size = TME_M6888X_FRAME_SIZE_IDLE_M68040;
1912: break;
1913: }
1914:
1915: /* if this is the m68881 or m68882: */
1916: if (ic->tme_m68k_fpu_type & TME_M68K_FPU_M6888X) {
1917:
1918: /* fill in a minimal BIU flags field: */
1919: frame.tme_m6888x_frame_words[frame.tme_m6888x_frame_size / sizeof(tme_uint32_t)] = tme_htobe_u32(0x70000000);
1920: }
1921:
1922: /* get the total size of the frame: */
1923: frame_size
1924: = (sizeof(frame.tme_m6888x_frame_version)
1925: + sizeof(frame.tme_m6888x_frame_size)
1926: + sizeof(frame.tme_m6888x_frame_reserved2)
1927: + frame.tme_m6888x_frame_size);
1928:
1929: /* if we're not restarting, and this is the predecrement addressing
1930: mode, update the effective address and the address register: */
1931: if (!TME_M68K_SEQUENCE_RESTARTING
1932: && TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3) == 4) {
1933: ic->_tme_m68k_ea_address -= frame_size;
1934: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0
1935: + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))
1936: = ic->_tme_m68k_ea_address;
1937: }
1938:
1939: /* write out the saved frame: */
1940: tme_m68k_write_mem(ic, (tme_uint8_t *) &frame, frame_size);
1941: }
1942:
1943: /* this can fault: */
1944: TME_M68K_INSN(tme_m68k_frestore)
1945: {
1946: tme_uint8_t frame_version;
1947: tme_uint8_t frame_size;
1948: int format_error;
1949:
1950: TME_M68K_INSN_FPU;
1951: TME_M68K_INSN_PRIV;
1952: TME_M68K_INSN_CANFAULT;
1953:
1954: /* read in the format word: */
1955: tme_m68k_read_memx32(ic);
1956: frame_version = (ic->tme_m68k_ireg_memx32 >> 24) & 0xff;
1957: frame_size = (ic->tme_m68k_ireg_memx32 >> 16) & 0xff;
1958:
1959: /* determine if we have a format error: */
1960: if (frame_version == TME_M6888X_FRAME_VERSION_NULL) {
1961: format_error = (frame_size != TME_M6888X_FRAME_SIZE_NULL);
1962: }
1963: else {
1964: switch (ic->tme_m68k_fpu_type) {
1965: default: assert (FALSE);
1966: case TME_M68K_FPU_M68881:
1967: format_error = (frame_version != TME_M6888X_FRAME_VERSION_IDLE_M68881
1968: || frame_size != TME_M6888X_FRAME_SIZE_IDLE_M68881);
1969: break;
1970: case TME_M68K_FPU_M68882:
1971: format_error = (frame_version != TME_M6888X_FRAME_VERSION_IDLE_M68882
1972: || frame_size != TME_M6888X_FRAME_SIZE_IDLE_M68882);
1973: break;
1974: case TME_M68K_FPU_M68040:
1975: format_error = (frame_version != TME_M6888X_FRAME_VERSION_IDLE_M68040
1976: || frame_size != TME_M6888X_FRAME_SIZE_IDLE_M68040);
1977: break;
1978: }
1979: }
1980:
1981: /* if we have a format error: */
1982: if (format_error) {
1983: TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_FORMAT));
1984: }
1985:
1986: /* XXX FIXME - we don't bother reading in the rest of the frame.
1987: this gives an incomplete emulation: */
1988:
1989: /* if this is the postincrement addressing mode, update the address
1990: register: */
1991: if (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3) == 3) {
1992: ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0
1993: + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))
1994: += (sizeof(ic->tme_m68k_ireg_memx32)
1995: + frame_size);
1996: }
1997:
1998: /* if this was a NULL frame, reset the FPU: */
1999: if (frame_version == TME_M6888X_FRAME_VERSION_NULL) {
2000: tme_m68k_fpu_reset(ic);
2001: }
2002: }
2003:
2004: /* this checks for an FPU argument: */
2005: int
2006: tme_m68k_fpu_new(struct tme_m68k *ic, const char * const *args, int *_arg_i, int *_usage, char **_output)
2007: {
2008: int arg_i;
2009: int fpu_type;
2010: const char *compliance;
2011: int complete;
2012: unsigned int opmode_i;
2013: struct tme_ieee754_ctl *ctl;
2014:
2015: /* get the argument index: */
2016: arg_i = *_arg_i;
2017:
2018: /* if this is not an FPU type, this is not an m6888x argument: */
2019: if (!TME_ARG_IS(args[arg_i + 0], "fpu-type")) {
2020: return (FALSE);
2021: }
2022:
2023: /* you can't specify more than one FPU type: */
2024: if (ic->tme_m68k_fpu_type != TME_M68K_FPU_NONE) {
2025: tme_output_append_error(_output,
2026: "%s fpu-type %s",
2027: _("multiple"),
2028: _("unexpected"));
2029: *_usage = TRUE;
2030: return (TRUE);
2031: }
2032:
2033: /* get the FPU type: */
2034: if (args[arg_i + 1] == NULL) {
2035: *_usage = TRUE;
2036: return (TRUE);
2037: }
2038: if (TME_ARG_IS(args[arg_i + 1], "m68881")) {
2039: fpu_type = TME_M68K_FPU_M68881;
2040: }
2041: else if (TME_ARG_IS(args[arg_i + 1], "m68882")) {
2042: fpu_type = TME_M68K_FPU_M68882;
2043: }
2044: else if (TME_ARG_IS(args[arg_i + 1], "m68040")) {
2045: fpu_type = TME_M68K_FPU_M68040;
2046: }
2047: else {
2048: tme_output_append_error(_output,
2049: "%s fpu-type %s",
2050: _("bad"),
2051: args[arg_i + 1]);
2052: *_usage = TRUE;
2053: return (TRUE);
2054: }
2055: ic->tme_m68k_fpu_type = fpu_type;
2056: arg_i += 2;
2057:
2058: /* the next argument must be a compliance level: */
2059: compliance = args[arg_i + 1];
2060: if (!TME_ARG_IS(args[arg_i + 0], "fpu-compliance")
2061: || compliance == NULL) {
2062: *_usage = TRUE;
2063: return (TRUE);
2064: }
2065: ic->tme_m68k_fpu_ieee754_ops = tme_ieee754_ops_lookup(compliance);
2066: if (ic->tme_m68k_fpu_ieee754_ops == NULL) {
2067: tme_output_append_error(_output,
2068: "%s fpu-compliance %s",
2069: _("bad"),
2070: compliance);
2071: *_usage = TRUE;
2072: return (TRUE);
2073: }
2074: arg_i += 2;
2075:
2076: /* see if the operations for this compliance level are complete: */
2077: complete = TRUE;
2078: for (opmode_i = 0;
2079: opmode_i < (sizeof(_tme_m6888x_fpgen_opmode_table) / sizeof(_tme_m6888x_fpgen_opmode_table[0]));
2080: opmode_i++) {
2081: if (_tme_m6888x_fpgen_opmode_table[opmode_i].tme_m6888x_fpgen_func_ops_offset != 0
2082: && TME_M6888X_IEEE754_OP_FUNC(_tme_m6888x_fpgen_opmode_table[opmode_i].tme_m6888x_fpgen_func_ops_offset) == NULL) {
2083: complete = FALSE;
2084: break;
2085: }
2086: }
2087:
2088: /* if the next argument is an incomplete disposition: */
2089: if (TME_ARG_IS(args[arg_i + 0], "fpu-incomplete")) {
2090:
2091: if (TME_ARG_IS(args[arg_i + 1], "abort")) {
2092: ic->tme_m68k_fpu_incomplete_abort = TRUE;
2093: }
2094: else if (TME_ARG_IS(args[arg_i + 1], "line-f")) {
2095: ic->tme_m68k_fpu_incomplete_abort = FALSE;
2096: }
2097: else {
2098: tme_output_append_error(_output,
2099: "%s fpu-incomplete %s",
2100: _("bad"),
2101: args[arg_i + 1]);
2102: *_usage = TRUE;
2103: return (TRUE);
2104: }
2105: arg_i += 2;
2106: }
2107:
2108: /* otherwise, no incomplete disposition is given. if this
2109: compliance is incomplete: */
2110: else if (!complete) {
2111: tme_output_append_error(_output,
2112: "%s %s %s fpu-incomplete",
2113: _("compliance"),
2114: compliance,
2115: _("is incomplete, needs"));
2116: *_usage = TRUE;
2117: return (TRUE);
2118: }
2119:
2120: /* initialize the IEEE 754 control: */
2121: ctl = &ic->tme_m68k_fpu_ieee754_ctl;
2122:
2123: /* a private data structure: */
2124: ctl->tme_ieee754_ctl_private = ic;
2125:
2126: /* the underflow tininess-detection mode: */
2127: /* XXX FIXME - is this right for the m6888x? */
2128: ctl->tme_ieee754_ctl_detect_tininess = TME_IEEE754_CTL_DETECT_TININESS_BEFORE_ROUNDING;
2129:
2130: /* the exception function: */
2131: ctl->tme_ieee754_ctl_exception = _tme_m6888x_exception_ieee754;
2132:
2133: /* we don't check whether or not a value is a NaN when converting it
2134: from one precision to another: */
2135: ctl->tme_ieee754_ctl_check_snan_on_conversion = FALSE;
2136:
2137: /* the default generated NaN patterns: */
2138: ctl->tme_ieee754_ctl_default_nan_single = 0x7fffffff;
2139: ctl->tme_ieee754_ctl_default_nan_double.tme_value64_uint32_hi = 0x7fffffff;
2140: ctl->tme_ieee754_ctl_default_nan_double.tme_value64_uint32_lo = 0xffffffff;
2141: ctl->tme_ieee754_ctl_default_nan_extended80.tme_float_ieee754_extended80_sexp = 0x7fff;
2142: ctl->tme_ieee754_ctl_default_nan_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi = 0xffffffff;
2143: ctl->tme_ieee754_ctl_default_nan_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo = 0xffffffff;
2144:
2145: /* NaN tests: */
2146: ctl->tme_ieee754_ctl_is_snan_extended80 = _tme_m6888x_is_snan_extended80;
2147:
2148: /* NaN canonicalization: */
2149: ctl->tme_ieee754_ctl_nan_single_to_common = tme_ieee754_default_nan_single_to_common;
2150: ctl->tme_ieee754_ctl_nan_common_to_single = tme_ieee754_default_nan_common_to_single;
2151: ctl->tme_ieee754_ctl_nan_double_to_common = tme_ieee754_default_nan_double_to_common;
2152: ctl->tme_ieee754_ctl_nan_common_to_double = tme_ieee754_default_nan_common_to_double;
2153: ctl->tme_ieee754_ctl_nan_extended80_to_common = tme_ieee754_default_nan_extended80_to_common;
2154: ctl->tme_ieee754_ctl_nan_common_to_extended80 = tme_ieee754_default_nan_common_to_extended80;
2155:
2156: /* NaN propagation: */
2157: ctl->tme_ieee754_ctl_nan_from_nans_extended80 = _tme_m6888x_nan_from_nans_extended80;
2158:
2159: /* done: */
2160: *_arg_i = arg_i;
2161: return (TRUE);
2162: }
2163:
2164: /* this returns the FPU usage: */
2165: void
2166: tme_m68k_fpu_usage(char **_output)
2167: {
2168: tme_output_append_error(_output,
2169: "[ fpu-type { m68881 | m68882 | m68040 } fpu-compliance %s [ fpu-incomplete { abort | line-f } ] ]",
2170: tme_ieee754_compliance_options);
2171: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.