|
|
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.