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