PageRenderTime 66ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/fpp.cpp

https://github.com/tonioni/WinUAE
C++ | 3867 lines | 3364 code | 297 blank | 206 comment | 896 complexity | 8b97bf37fc65b41cc57ff494a216ed2e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * UAE - The Un*x Amiga Emulator
  3. *
  4. * MC68881/68882/68040/68060 FPU emulation
  5. *
  6. * Copyright 1996 Herman ten Brugge
  7. * Modified 2005 Peter Keunecke
  8. * 68040+ exceptions and more by Toni Wilen
  9. */
  10. #define __USE_ISOC9X /* We might be able to pick up a NaN */
  11. #define FPU_TEST 0
  12. #define FPU_LOG 0
  13. #include <math.h>
  14. #include <float.h>
  15. #include <fenv.h>
  16. #include "sysconfig.h"
  17. #include "sysdeps.h"
  18. #include "options.h"
  19. #include "memory.h"
  20. #include "uae/attributes.h"
  21. #include "uae/vm.h"
  22. #include "custom.h"
  23. #include "events.h"
  24. #include "newcpu.h"
  25. #include "fpp.h"
  26. #include "savestate.h"
  27. #include "cpu_prefetch.h"
  28. #include "cpummu.h"
  29. #include "cpummu030.h"
  30. #include "debug.h"
  31. #ifndef CPU_TESTER
  32. #define SUPPORT_MMU 1
  33. #else
  34. #define SUPPORT_MMU 0
  35. extern void cputester_fault(void);
  36. #endif
  37. #include "softfloat/softfloat.h"
  38. // global variable for JIT FPU
  39. #ifdef USE_LONG_DOUBLE
  40. bool use_long_double = true;
  41. #else
  42. bool use_long_double = false;
  43. #endif
  44. static bool support_exceptions;
  45. static bool support_denormals;
  46. static uae_u32 fpcr_mask, fpsr_mask;
  47. FPP_PRINT fpp_print;
  48. FPP_IS fpp_unset_snan;
  49. FPP_IS fpp_is_init;
  50. FPP_IS fpp_is_snan;
  51. FPP_IS fpp_is_nan;
  52. FPP_IS fpp_is_infinity;
  53. FPP_IS fpp_is_zero;
  54. FPP_IS fpp_is_neg;
  55. FPP_IS fpp_is_denormal;
  56. FPP_IS fpp_is_unnormal;
  57. FPP_A fpp_fix_infinity;
  58. FPP_GET_STATUS fpp_get_status;
  59. FPP_CLEAR_STATUS fpp_clear_status;
  60. FPP_SET_MODE fpp_set_mode;
  61. FPP_SUPPORT_FLAGS fpp_get_support_flags;
  62. FPP_FROM_NATIVE fpp_from_native;
  63. FPP_TO_NATIVE fpp_to_native;
  64. FPP_TO_INT fpp_to_int;
  65. FPP_FROM_INT fpp_from_int;
  66. FPP_PACK fpp_to_pack;
  67. FPP_PACK fpp_from_pack;
  68. FPP_TO_SINGLE fpp_to_single;
  69. FPP_FROM_SINGLE fpp_from_single;
  70. FPP_TO_DOUBLE fpp_to_double;
  71. FPP_FROM_DOUBLE fpp_from_double;
  72. FPP_TO_EXTEN fpp_to_exten;
  73. FPP_FROM_EXTEN fpp_from_exten;
  74. FPP_TO_EXTEN fpp_to_exten_fmovem;
  75. FPP_FROM_EXTEN fpp_from_exten_fmovem;
  76. FPP_A fpp_normalize;
  77. FPP_DENORMALIZE fpp_denormalize;
  78. FPP_A fpp_get_internal_overflow;
  79. FPP_A fpp_get_internal_underflow;
  80. FPP_A fpp_get_internal_round_all;
  81. FPP_A fpp_get_internal_round;
  82. FPP_A fpp_get_internal_round_exten;
  83. FPP_A fpp_get_internal;
  84. FPP_GET32 fpp_get_internal_grs;
  85. FPP_A fpp_round_single;
  86. FPP_A fpp_round_double;
  87. FPP_A fpp_round32;
  88. FPP_A fpp_round64;
  89. FPP_AB fpp_int;
  90. FPP_AB fpp_sinh;
  91. FPP_AB fpp_intrz;
  92. FPP_ABP fpp_sqrt;
  93. FPP_AB fpp_lognp1;
  94. FPP_AB fpp_etoxm1;
  95. FPP_AB fpp_tanh;
  96. FPP_AB fpp_atan;
  97. FPP_AB fpp_atanh;
  98. FPP_AB fpp_sin;
  99. FPP_AB fpp_asin;
  100. FPP_AB fpp_tan;
  101. FPP_AB fpp_etox;
  102. FPP_AB fpp_twotox;
  103. FPP_AB fpp_tentox;
  104. FPP_AB fpp_logn;
  105. FPP_AB fpp_log10;
  106. FPP_AB fpp_log2;
  107. FPP_ABP fpp_abs;
  108. FPP_AB fpp_cosh;
  109. FPP_ABP fpp_neg;
  110. FPP_AB fpp_acos;
  111. FPP_AB fpp_cos;
  112. FPP_ABC fpp_sincos;
  113. FPP_AB fpp_getexp;
  114. FPP_AB fpp_getman;
  115. FPP_ABP fpp_div;
  116. FPP_ABQS fpp_mod;
  117. FPP_ABP fpp_add;
  118. FPP_ABP fpp_mul;
  119. FPP_ABQS fpp_rem;
  120. FPP_AB fpp_scale;
  121. FPP_ABP fpp_sub;
  122. FPP_AB fpp_sgldiv;
  123. FPP_AB fpp_sglmul;
  124. FPP_AB fpp_cmp;
  125. FPP_AB fpp_tst;
  126. FPP_ABP fpp_move;
  127. #define DEBUG_FPP 0
  128. #define EXCEPTION_FPP 0
  129. STATIC_INLINE int isinrom (void)
  130. {
  131. return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
  132. }
  133. static bool jit_fpu(void)
  134. {
  135. return currprefs.cachesize && currprefs.compfpu;
  136. }
  137. static int warned = 100;
  138. struct fpp_cr_entry {
  139. uae_u32 val[3];
  140. uae_u8 inexact;
  141. uae_s8 rndoff[4];
  142. };
  143. static const struct fpp_cr_entry fpp_cr[22] = {
  144. { {0x40000000, 0xc90fdaa2, 0x2168c235}, 1, {0,-1,-1, 0} }, // 0 = pi
  145. { {0x3ffd0000, 0x9a209a84, 0xfbcff798}, 1, {0, 0, 0, 1} }, // 1 = log10(2)
  146. { {0x40000000, 0xadf85458, 0xa2bb4a9a}, 1, {0, 0, 0, 1} }, // 2 = e
  147. { {0x3fff0000, 0xb8aa3b29, 0x5c17f0bc}, 1, {0,-1,-1, 0} }, // 3 = log2(e)
  148. { {0x3ffd0000, 0xde5bd8a9, 0x37287195}, 0, {0, 0, 0, 0} }, // 4 = log10(e)
  149. { {0x00000000, 0x00000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 5 = 0.0
  150. { {0x3ffe0000, 0xb17217f7, 0xd1cf79ac}, 1, {0,-1,-1, 0} }, // 6 = ln(2)
  151. { {0x40000000, 0x935d8ddd, 0xaaa8ac17}, 1, {0,-1,-1, 0} }, // 7 = ln(10)
  152. { {0x3fff0000, 0x80000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 8 = 1e0
  153. { {0x40020000, 0xa0000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 9 = 1e1
  154. { {0x40050000, 0xc8000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 10 = 1e2
  155. { {0x400c0000, 0x9c400000, 0x00000000}, 0, {0, 0, 0, 0} }, // 11 = 1e4
  156. { {0x40190000, 0xbebc2000, 0x00000000}, 0, {0, 0, 0, 0} }, // 12 = 1e8
  157. { {0x40340000, 0x8e1bc9bf, 0x04000000}, 0, {0, 0, 0, 0} }, // 13 = 1e16
  158. { {0x40690000, 0x9dc5ada8, 0x2b70b59e}, 1, {0,-1,-1, 0} }, // 14 = 1e32
  159. { {0x40d30000, 0xc2781f49, 0xffcfa6d5}, 1, {0, 0, 0, 1} }, // 15 = 1e64
  160. { {0x41a80000, 0x93ba47c9, 0x80e98ce0}, 1, {0,-1,-1, 0} }, // 16 = 1e128
  161. { {0x43510000, 0xaa7eebfb, 0x9df9de8e}, 1, {0,-1,-1, 0} }, // 17 = 1e256
  162. { {0x46a30000, 0xe319a0ae, 0xa60e91c7}, 1, {0,-1,-1, 0} }, // 18 = 1e512
  163. { {0x4d480000, 0xc9767586, 0x81750c17}, 1, {0, 0, 0, 1} }, // 19 = 1e1024
  164. { {0x5a920000, 0x9e8b3b5d, 0xc53d5de5}, 1, {0,-1,-1, 0} }, // 20 = 1e2048
  165. { {0x75250000, 0xc4605202, 0x8a20979b}, 1, {0,-1,-1, 0} } // 21 = 1e4094
  166. };
  167. #define FPP_CR_PI 0
  168. #define FPP_CR_LOG10_2 1
  169. #define FPP_CR_E 2
  170. #define FPP_CR_LOG2_E 3
  171. #define FPP_CR_LOG10_E 4
  172. #define FPP_CR_ZERO 5
  173. #define FPP_CR_LN_2 6
  174. #define FPP_CR_LN_10 7
  175. #define FPP_CR_1E0 8
  176. #define FPP_CR_1E1 9
  177. #define FPP_CR_1E2 10
  178. #define FPP_CR_1E4 11
  179. #define FPP_CR_1E8 12
  180. #define FPP_CR_1E16 13
  181. #define FPP_CR_1E32 14
  182. #define FPP_CR_1E64 15
  183. #define FPP_CR_1E128 16
  184. #define FPP_CR_1E256 17
  185. #define FPP_CR_1E512 18
  186. #define FPP_CR_1E1024 19
  187. #define FPP_CR_1E2048 20
  188. #define FPP_CR_1E4096 21
  189. struct fpp_cr_entry_undef {
  190. uae_u32 val[3];
  191. };
  192. #define FPP_CR_NUM_SPECIAL_UNDEFINED 10
  193. // 68881 and 68882 have identical undefined fields
  194. static const struct fpp_cr_entry_undef fpp_cr_undef[] = {
  195. { {0x40000000, 0x00000000, 0x00000000} },
  196. { {0x40010000, 0xfe000682, 0x00000000} },
  197. { {0x40010000, 0xffc00503, 0x80000000} },
  198. { {0x20000000, 0x7fffffff, 0x00000000} },
  199. { {0x00000000, 0xffffffff, 0xffffffff} },
  200. { {0x3c000000, 0xffffffff, 0xfffff800} },
  201. { {0x3f800000, 0xffffff00, 0x00000000} },
  202. { {0x00010000, 0xf65d8d9c, 0x00000000} },
  203. { {0x7fff0000, 0x001e0000, 0x00000000} },
  204. { {0x43ff0000, 0x000e0000, 0x00000000} },
  205. { {0x407f0000, 0x00060000, 0x00000000} }
  206. };
  207. uae_u32 xhex_nan[] ={0x7fff0000, 0xffffffff, 0xffffffff};
  208. static bool fpu_mmu_fixup;
  209. /* Floating Point Control Register (FPCR)
  210. *
  211. * Exception Enable Byte
  212. * x--- ---- ---- ---- bit 15: BSUN (branch/set on unordered)
  213. * -x-- ---- ---- ---- bit 14: SNAN (signaling not a number)
  214. * --x- ---- ---- ---- bit 13: OPERR (operand error)
  215. * ---x ---- ---- ---- bit 12: OVFL (overflow)
  216. * ---- x--- ---- ---- bit 11: UNFL (underflow)
  217. * ---- -x-- ---- ---- bit 10: DZ (divide by zero)
  218. * ---- --x- ---- ---- bit 9: INEX 2 (inexact operation)
  219. * ---- ---x ---- ---- bit 8: INEX 1 (inexact decimal input)
  220. *
  221. * Mode Control Byte
  222. * ---- ---- xx-- ---- bits 7 and 6: PREC (rounding precision)
  223. * ---- ---- --xx ---- bits 5 and 4: RND (rounding mode)
  224. * ---- ---- ---- xxxx bits 3 to 0: all 0
  225. */
  226. #define FPCR_PREC 0x00C0
  227. #define FPCR_RND 0x0030
  228. /* Floating Point Status Register (FPSR)
  229. *
  230. * Condition Code Byte
  231. * xxxx ---- ---- ---- ---- ---- ---- ---- bits 31 to 28: all 0
  232. * ---- x--- ---- ---- ---- ---- ---- ---- bit 27: N (negative)
  233. * ---- -x-- ---- ---- ---- ---- ---- ---- bit 26: Z (zero)
  234. * ---- --x- ---- ---- ---- ---- ---- ---- bit 25: I (infinity)
  235. * ---- ---x ---- ---- ---- ---- ---- ---- bit 24: NAN (not a number or unordered)
  236. *
  237. * Quotient Byte (set and reset only by FMOD and FREM)
  238. * ---- ---- x--- ---- ---- ---- ---- ---- bit 23: sign of quotient
  239. * ---- ---- -xxx xxxx ---- ---- ---- ---- bits 22 to 16: 7 least significant bits of quotient
  240. *
  241. * Exception Status Byte
  242. * ---- ---- ---- ---- x--- ---- ---- ---- bit 15: BSUN (branch/set on unordered)
  243. * ---- ---- ---- ---- -x-- ---- ---- ---- bit 14: SNAN (signaling not a number)
  244. * ---- ---- ---- ---- --x- ---- ---- ---- bit 13: OPERR (operand error)
  245. * ---- ---- ---- ---- ---x ---- ---- ---- bit 12: OVFL (overflow)
  246. * ---- ---- ---- ---- ---- x--- ---- ---- bit 11: UNFL (underflow)
  247. * ---- ---- ---- ---- ---- -x-- ---- ---- bit 10: DZ (divide by zero)
  248. * ---- ---- ---- ---- ---- --x- ---- ---- bit 9: INEX 2 (inexact operation)
  249. * ---- ---- ---- ---- ---- ---x ---- ---- bit 8: INEX 1 (inexact decimal input)
  250. *
  251. * Accrued Exception Byte
  252. * ---- ---- ---- ---- ---- ---- x--- ---- bit 7: IOP (invalid operation)
  253. * ---- ---- ---- ---- ---- ---- -x-- ---- bit 6: OVFL (overflow)
  254. * ---- ---- ---- ---- ---- ---- --x- ---- bit 5: UNFL (underflow)
  255. * ---- ---- ---- ---- ---- ---- ---x ---- bit 4: DZ (divide by zero)
  256. * ---- ---- ---- ---- ---- ---- ---- x--- bit 3: INEX (inexact)
  257. * ---- ---- ---- ---- ---- ---- ---- -xxx bits 2 to 0: all 0
  258. */
  259. #define FPSR_ZEROBITS 0xF0000007
  260. #define FPSR_CC_N 0x08000000
  261. #define FPSR_CC_Z 0x04000000
  262. #define FPSR_CC_I 0x02000000
  263. #define FPSR_CC_NAN 0x01000000
  264. #define FPSR_QUOT_SIGN 0x00800000
  265. #define FPSR_QUOT_LSB 0x007F0000
  266. #define FPSR_AE_IOP 0x00000080
  267. #define FPSR_AE_OVFL 0x00000040
  268. #define FPSR_AE_UNFL 0x00000020
  269. #define FPSR_AE_DZ 0x00000010
  270. #define FPSR_AE_INEX 0x00000008
  271. static struct {
  272. // 6888x and 68060
  273. uae_u32 ccr;
  274. uae_u32 eo[3];
  275. // 68060
  276. uae_u32 v;
  277. // 68040
  278. uae_u32 fpiarcu;
  279. uae_u32 cmdreg3b;
  280. uae_u32 cmdreg1b;
  281. uae_u32 stag, dtag;
  282. uae_u32 e1, e3, t;
  283. uae_u32 fpt[3];
  284. uae_u32 et[3];
  285. uae_u32 wbt[3];
  286. uae_u32 grs;
  287. uae_u32 wbte15;
  288. uae_u32 wbtm66;
  289. } fsave_data;
  290. static void reset_fsave_data(void)
  291. {
  292. int i;
  293. for (i = 0; i < 3; i++) {
  294. fsave_data.eo[i] = 0;
  295. fsave_data.fpt[i] = 0;
  296. fsave_data.et[i] = 0;
  297. fsave_data.wbt[i] = 0;
  298. }
  299. fsave_data.ccr = 0;
  300. fsave_data.v = 0;
  301. fsave_data.fpiarcu = 0;
  302. fsave_data.cmdreg1b = 0;
  303. fsave_data.cmdreg3b = 0;
  304. fsave_data.stag = 0;
  305. fsave_data.dtag = 0;
  306. fsave_data.e1 = 0;
  307. fsave_data.e3 = 0;
  308. fsave_data.t = 0;
  309. fsave_data.wbte15 = 0;
  310. fsave_data.wbtm66 = 0;
  311. fsave_data.grs = 0;
  312. }
  313. static uae_u32 get_ftag(fpdata *src, int size)
  314. {
  315. fpp_is_init(src);
  316. if (fpp_is_zero(src)) {
  317. return 1; // ZERO
  318. } else if (fpp_is_unnormal(src) || fpp_is_denormal(src)) {
  319. if (size == 1 || size == 5)
  320. return 5; // Single/double DENORMAL
  321. return 4; // Extended DENORMAL or UNNORMAL
  322. } else if (fpp_is_nan(src)) {
  323. return 3; // NAN
  324. } else if (fpp_is_infinity(src)) {
  325. return 2; // INF
  326. }
  327. return 0; // NORMAL
  328. }
  329. STATIC_INLINE bool fp_is_dyadic(uae_u16 extra)
  330. {
  331. return ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38);
  332. }
  333. static bool fp_exception_pending(bool pre)
  334. {
  335. // first check for pending arithmetic exceptions
  336. if (support_exceptions && !jit_fpu()) {
  337. if (regs.fp_exp_pend) {
  338. if (warned > 0) {
  339. write_log (_T("FPU ARITHMETIC EXCEPTION (%d) PC=%08x\n"), regs.fp_exp_pend, regs.instruction_pc);
  340. }
  341. regs.fpu_exp_pre = pre;
  342. Exception(regs.fp_exp_pend);
  343. if (currprefs.fpu_model != 68882)
  344. regs.fp_exp_pend = 0;
  345. return true;
  346. }
  347. }
  348. // no arithmetic exceptions pending, check for unimplemented datatype
  349. if (regs.fp_unimp_pend) {
  350. if (warned > 0) {
  351. write_log (_T("FPU unimplemented datatype exception (%s) PC=%08x\n"), pre ? _T("pre") : _T("mid/post"), regs.instruction_pc);
  352. }
  353. if (currprefs.cpu_model == 68060 && fpu_mmu_fixup) {
  354. m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
  355. mmufixup[0].reg = -1;
  356. }
  357. regs.fpu_exp_pre = pre;
  358. Exception(55);
  359. regs.fp_unimp_pend = 0;
  360. return true;
  361. }
  362. return false;
  363. }
  364. static void fp_unimp_instruction_exception_pending(void)
  365. {
  366. if (regs.fp_unimp_ins) {
  367. if (warned > 0) {
  368. write_log (_T("FPU UNIMPLEMENTED INSTRUCTION/FPU DISABLED EXCEPTION PC=%08x\n"), M68K_GETPC);
  369. }
  370. if (currprefs.cpu_model == 68060 && fpu_mmu_fixup) {
  371. m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
  372. mmufixup[0].reg = -1;
  373. }
  374. regs.fpu_exp_pre = true;
  375. Exception(11);
  376. regs.fp_unimp_ins = false;
  377. regs.fp_unimp_pend = 0;
  378. }
  379. }
  380. void fpsr_set_exception(uae_u32 exception)
  381. {
  382. regs.fpsr |= exception;
  383. }
  384. static uae_u32 fpsr_get_vector(uae_u32 exception)
  385. {
  386. static const int vtable[8] = { 49, 49, 50, 51, 53, 52, 54, 48 };
  387. int i;
  388. exception >>= 8;
  389. for (i = 7; i >= 0; i--) {
  390. if (exception & (1 << i)) {
  391. return vtable[i];
  392. }
  393. }
  394. return 0;
  395. }
  396. static bool fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea, bool easet, uaecptr oldpc)
  397. {
  398. if (!support_exceptions || jit_fpu())
  399. return false;
  400. uae_u32 exception;
  401. // Any exception status bit and matching exception enable bits set?
  402. exception = regs.fpsr & regs.fpcr & 0xff00;
  403. // Add 68040/68060 nonmaskable exceptions. Only if no unimplemented instruction emulation.
  404. if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  405. exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL | mask);
  406. }
  407. if (exception) {
  408. regs.fp_exp_pend = fpsr_get_vector(exception);
  409. bool nonmaskable = (regs.fp_exp_pend != fpsr_get_vector(regs.fpsr & regs.fpcr));
  410. if (warned > 0) {
  411. write_log(_T("FPU %s arithmetic exception pending: FPSR: %08x, FPCR: %04x (vector: %d) PC=%08x!\n"),
  412. nonmaskable ? _T("nonmaskable") : _T(""), regs.fpsr, regs.fpcr, regs.fp_exp_pend, regs.instruction_pc);
  413. #if EXCEPTION_FPP == 0
  414. warned--;
  415. #endif
  416. }
  417. if (!support_exceptions || jit_fpu()) {
  418. // log message and exit
  419. regs.fp_exp_pend = 0;
  420. return false;
  421. }
  422. regs.fp_opword = opcode;
  423. regs.fp_ea = ea;
  424. regs.fp_ea_set = easet;
  425. if (oldpc != 0xffffffff) {
  426. regs.fpiar = oldpc;
  427. }
  428. // data for FSAVE stack frame
  429. fpdata eo;
  430. uae_u32 opclass = (extra >> 13) & 7;
  431. reset_fsave_data();
  432. if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) {
  433. // fsave data for 68881 and 68882
  434. if (opclass == 3) { // 011
  435. fsave_data.ccr = ((uae_u32)extra << 16) | extra;
  436. } else { // 000 or 010
  437. fsave_data.ccr = ((uae_u32)(opcode | 0x0080) << 16) | extra;
  438. }
  439. if (regs.fp_exp_pend == 54 || regs.fp_exp_pend == 52 || regs.fp_exp_pend == 50) { // SNAN, OPERR, DZ
  440. fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
  441. if (regs.fp_exp_pend == 52 && opclass == 3) { // OPERR from move to integer or packed
  442. fsave_data.eo[0] &= 0x4fff0000;
  443. fsave_data.eo[1] = fsave_data.eo[2] = 0;
  444. }
  445. } else if (regs.fp_exp_pend == 53) { // OVFL
  446. fpp_get_internal_overflow(&eo);
  447. fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
  448. } else if (regs.fp_exp_pend == 51) { // UNFL
  449. fpp_get_internal_underflow(&eo);
  450. fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
  451. } // else INEX1, INEX2: do nothing
  452. } else if (currprefs.cpu_model == 68060) {
  453. // fsave data for 68060
  454. regs.fpu_exp_state = 2; // 68060 EXCP frame
  455. fsave_data.v = regs.fp_exp_pend & 7;
  456. fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
  457. } else {
  458. // fsave data for 68040
  459. regs.fpu_exp_state = 1; // 68040 UNIMP frame
  460. uae_u32 reg = (extra >> 7) & 7;
  461. int size = (extra >> 10) & 7;
  462. fsave_data.fpiarcu = regs.fpiar;
  463. if (regs.fp_exp_pend == 54) { // SNAN (undocumented)
  464. fsave_data.wbte15 = 1;
  465. fsave_data.grs = 7;
  466. } else {
  467. fsave_data.grs = 1;
  468. }
  469. if (opclass == 3) { // OPCLASS 011
  470. fsave_data.cmdreg1b = extra;
  471. fsave_data.e1 = 1;
  472. fsave_data.t = 1;
  473. fsave_data.wbte15 = (regs.fp_exp_pend == 51 || regs.fp_exp_pend == 54) ? 1 : 0; // UNFL, SNAN
  474. fpp_is_init(src);
  475. if (fpp_is_snan(src)) {
  476. fpp_unset_snan(src);
  477. }
  478. fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
  479. fsave_data.stag = get_ftag(src, -1);
  480. } else { // OPCLASS 000 and 010
  481. fsave_data.cmdreg1b = extra;
  482. fsave_data.e1 = 1;
  483. fsave_data.wbte15 = (regs.fp_exp_pend == 54) ? 1 : 0; // SNAN (undocumented)
  484. if (regs.fp_exp_pend == 51 || regs.fp_exp_pend == 53 || regs.fp_exp_pend == 49) { // UNFL, OVFL, INEX
  485. if ((extra & 0x30) == 0x20 || (extra & 0x3f) == 0x04) { // FADD, FSUB, FMUL, FDIV, FSQRT
  486. regs.fpu_exp_state = 2; // 68040 BUSY frame
  487. fsave_data.e3 = 1;
  488. fsave_data.e1 = 0;
  489. fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038)>>1) | ((extra & 0x004)<<3);
  490. if (regs.fp_exp_pend == 51) { // UNFL
  491. fpp_get_internal(&eo);
  492. } else { // OVFL, INEX
  493. fpp_get_internal_round(&eo);
  494. }
  495. fsave_data.grs = fpp_get_internal_grs();
  496. fpp_from_exten_fmovem(&eo, &fsave_data.wbt[0], &fsave_data.wbt[1], &fsave_data.wbt[2]);
  497. fsave_data.wbte15 = (regs.fp_exp_pend == 51) ? 1 : 0; // UNFL
  498. // src and dst is stored (undocumented)
  499. fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
  500. fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
  501. if (fp_is_dyadic(extra)) {
  502. fpp_from_exten_fmovem(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
  503. fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
  504. }
  505. } else { // FMOVE to register, FABS, FNEG
  506. fpp_get_internal_round_exten(&eo);
  507. fsave_data.grs = fpp_get_internal_grs();
  508. fpp_from_exten_fmovem(&eo, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
  509. fpp_get_internal_round_all(&eo); // weird
  510. fpp_from_exten_fmovem(&eo, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); // undocumented
  511. fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
  512. }
  513. } else { // SNAN, OPERR, DZ
  514. fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
  515. fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
  516. if (fp_is_dyadic(extra)) {
  517. fpp_from_exten_fmovem(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
  518. fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
  519. }
  520. }
  521. }
  522. }
  523. return nonmaskable;
  524. }
  525. return false;
  526. }
  527. // Flag that is always set immediately.
  528. static void fpsr_set_result_always(fpdata *result)
  529. {
  530. #ifdef JIT
  531. regs.fp_result = *result;
  532. #endif
  533. regs.fpsr &= 0x00fffff8; // clear cc
  534. fpp_is_init(result);
  535. if (fpp_is_neg(result)) {
  536. regs.fpsr |= FPSR_CC_N;
  537. }
  538. }
  539. // Flags that are set if instruction didn't generate exception.
  540. static void fpsr_set_result(fpdata *result)
  541. {
  542. // condition code byte
  543. if (fpp_is_nan(result)) {
  544. regs.fpsr |= FPSR_CC_NAN;
  545. } else if (fpp_is_zero(result)) {
  546. regs.fpsr |= FPSR_CC_Z;
  547. } else if (fpp_is_infinity(result)) {
  548. regs.fpsr |= FPSR_CC_I;
  549. }
  550. }
  551. static void fpsr_clear_status(void)
  552. {
  553. // clear exception status byte only
  554. regs.fpsr &= 0x0fff00f8;
  555. // clear external status
  556. fpp_clear_status();
  557. }
  558. static void updateaccrued(void)
  559. {
  560. // update accrued exception byte
  561. if (regs.fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR))
  562. regs.fpsr |= FPSR_AE_IOP; // IOP = BSUN || SNAN || OPERR
  563. if ((regs.fpsr & FPSR_UNFL) && (regs.fpsr & FPSR_INEX2))
  564. regs.fpsr |= FPSR_AE_UNFL; // UNFL = UNFL && INEX2
  565. if (regs.fpsr & FPSR_DZ)
  566. regs.fpsr |= FPSR_AE_DZ; // DZ = DZ
  567. }
  568. static uae_u32 fpsr_make_status(void)
  569. {
  570. uae_u32 exception;
  571. // get external status
  572. fpp_get_status(&regs.fpsr);
  573. if (regs.fpsr & FPSR_OVFL)
  574. regs.fpsr |= FPSR_AE_OVFL; // OVFL = OVFL
  575. if (regs.fpsr & (FPSR_OVFL | FPSR_INEX2 | FPSR_INEX1))
  576. regs.fpsr |= FPSR_AE_INEX; // INEX = INEX1 || INEX2 || OVFL
  577. if (!support_exceptions || jit_fpu()) {
  578. updateaccrued();
  579. return 0;
  580. }
  581. // return exceptions that interrupt calculation
  582. exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ);
  583. updateaccrued();
  584. if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  585. exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL);
  586. }
  587. return exception;
  588. }
  589. static int fpsr_set_bsun(void)
  590. {
  591. regs.fpsr |= FPSR_BSUN;
  592. regs.fpsr |= FPSR_AE_IOP;
  593. if (regs.fpcr & FPSR_BSUN) {
  594. write_log (_T("FPU exception: BSUN! (FPSR: %08x, FPCR: %08x)\n"), regs.fpsr, regs.fpcr);
  595. if (support_exceptions && !jit_fpu()) {
  596. regs.fp_exp_pend = fpsr_get_vector(FPSR_BSUN);
  597. fp_exception_pending(true);
  598. return 1;
  599. }
  600. }
  601. return 0;
  602. }
  603. static void fpsr_set_quotient(uae_u64 quot, uae_u8 sign)
  604. {
  605. regs.fpsr &= 0x0f00fff8;
  606. regs.fpsr |= (quot << 16) & FPSR_QUOT_LSB;
  607. regs.fpsr |= sign ? FPSR_QUOT_SIGN : 0;
  608. }
  609. static void fpsr_get_quotient(uae_u64 *quot, uae_u8 *sign)
  610. {
  611. *quot = (regs.fpsr & FPSR_QUOT_LSB) >> 16;
  612. *sign = (regs.fpsr & FPSR_QUOT_SIGN) ? 1 : 0;
  613. }
  614. uae_u32 fpp_get_fpsr (void)
  615. {
  616. #ifdef JIT
  617. if (currprefs.cachesize && currprefs.compfpu) {
  618. regs.fpsr &= 0x00fffff8; // clear cc
  619. fpp_is_init(&regs.fp_result);
  620. if (fpp_is_nan(&regs.fp_result)) {
  621. regs.fpsr |= FPSR_CC_NAN;
  622. } else if (fpp_is_zero(&regs.fp_result)) {
  623. regs.fpsr |= FPSR_CC_Z;
  624. } else if (fpp_is_infinity(&regs.fp_result)) {
  625. regs.fpsr |= FPSR_CC_I;
  626. }
  627. if (fpp_is_neg(&regs.fp_result))
  628. regs.fpsr |= FPSR_CC_N;
  629. }
  630. #endif
  631. return regs.fpsr & fpsr_mask;
  632. }
  633. uae_u32 fpp_get_fpcr(void)
  634. {
  635. return regs.fpcr & fpcr_mask;
  636. }
  637. void fpp_set_fpcr (uae_u32 val)
  638. {
  639. fpp_set_mode(val);
  640. regs.fpcr = val & fpcr_mask;
  641. }
  642. static void fpnan (fpdata *fpd)
  643. {
  644. fpp_to_exten(fpd, xhex_nan[0], xhex_nan[1], xhex_nan[2]);
  645. }
  646. static void fpclear (fpdata *fpd)
  647. {
  648. fpp_from_int(fpd, 0);
  649. }
  650. static void fpset (fpdata *fpd, uae_s32 val)
  651. {
  652. fpp_from_int(fpd, val);
  653. }
  654. void fpp_set_fpsr (uae_u32 val)
  655. {
  656. regs.fpsr = val & fpsr_mask;
  657. #ifdef JIT
  658. // check comment in fpp_cond
  659. if (currprefs.cachesize && currprefs.compfpu) {
  660. if (val & 0x01000000)
  661. fpnan(&regs.fp_result);
  662. else if (val & 0x04000000)
  663. fpset(&regs.fp_result, 0);
  664. else if (val & 0x08000000)
  665. fpset(&regs.fp_result, -1);
  666. else
  667. fpset(&regs.fp_result, 1);
  668. }
  669. #endif
  670. }
  671. static void maybe_set_fpiar(uaecptr oldpc)
  672. {
  673. // if any exception (except BSUN) is enabled: update FPIAR
  674. // 68040 or 68060: always update FPIAR
  675. if ((regs.fpcr & 0x00007f00) || currprefs.fpu_model == 68040 || currprefs.fpu_model == 68060) {
  676. regs.fpiar = oldpc;
  677. }
  678. }
  679. void fpp_set_fpiar(uae_u32 val)
  680. {
  681. regs.fpiar = val;
  682. }
  683. uae_u32 fpp_get_fpiar(void)
  684. {
  685. return regs.fpiar;
  686. }
  687. bool fpu_get_constant(fpdata *fpd, int cr)
  688. {
  689. uae_u32 f[3] = { 0, 0, 0 };
  690. int entry = 0;
  691. bool round = true;
  692. int mode = (regs.fpcr >> 4) & 3;
  693. int prec = (regs.fpcr >> 6) & 3;
  694. switch (cr)
  695. {
  696. case 0x00: // pi
  697. entry = FPP_CR_PI;
  698. break;
  699. case 0x0b: // log10(2)
  700. entry = FPP_CR_LOG10_2;
  701. break;
  702. case 0x0c: // e
  703. entry = FPP_CR_E;
  704. break;
  705. case 0x0d: // log2(e)
  706. entry = FPP_CR_LOG2_E;
  707. break;
  708. case 0x0e: // log10(e)
  709. entry = FPP_CR_LOG10_E;
  710. break;
  711. case 0x0f: // 0.0
  712. entry = FPP_CR_ZERO;
  713. break;
  714. case 0x30: // ln(2)
  715. entry = FPP_CR_LN_2;
  716. break;
  717. case 0x31: // ln(10)
  718. entry = FPP_CR_LN_10;
  719. break;
  720. case 0x32: // 1e0
  721. entry = FPP_CR_1E0;
  722. break;
  723. case 0x33: // 1e1
  724. entry = FPP_CR_1E1;
  725. break;
  726. case 0x34: // 1e2
  727. entry = FPP_CR_1E2;
  728. break;
  729. case 0x35: // 1e4
  730. entry = FPP_CR_1E4;
  731. break;
  732. case 0x36: // 1e8
  733. entry = FPP_CR_1E8;
  734. break;
  735. case 0x37: // 1e16
  736. entry = FPP_CR_1E16;
  737. break;
  738. case 0x38: // 1e32
  739. entry = FPP_CR_1E32;
  740. break;
  741. case 0x39: // 1e64
  742. entry = FPP_CR_1E64;
  743. break;
  744. case 0x3a: // 1e128
  745. entry = FPP_CR_1E128;
  746. break;
  747. case 0x3b: // 1e256
  748. entry = FPP_CR_1E256;
  749. break;
  750. case 0x3c: // 1e512
  751. entry = FPP_CR_1E512;
  752. break;
  753. case 0x3d: // 1e1024
  754. entry = FPP_CR_1E1024;
  755. break;
  756. case 0x3e: // 1e2048
  757. entry = FPP_CR_1E2048;
  758. break;
  759. case 0x3f: // 1e4096
  760. entry = FPP_CR_1E4096;
  761. break;
  762. default: // undefined
  763. {
  764. bool check_f1_adjust = false;
  765. int f1_adjust = 0;
  766. uae_u32 sr = 0;
  767. if (cr > FPP_CR_NUM_SPECIAL_UNDEFINED) {
  768. cr = 0; // Most undefined fields contain this
  769. }
  770. f[0] = fpp_cr_undef[cr].val[0];
  771. f[1] = fpp_cr_undef[cr].val[1];
  772. f[2] = fpp_cr_undef[cr].val[2];
  773. // Rounding mode and precision works very strangely here..
  774. switch (cr)
  775. {
  776. case 1:
  777. check_f1_adjust = true;
  778. break;
  779. case 2:
  780. if (prec == 1 && mode == 3)
  781. f1_adjust = -1;
  782. break;
  783. case 3:
  784. if (prec == 1 && (mode == 0 || mode == 3))
  785. sr |= FPSR_CC_I;
  786. else
  787. sr |= FPSR_CC_NAN;
  788. break;
  789. case 7:
  790. sr |= FPSR_CC_NAN;
  791. check_f1_adjust = true;
  792. break;
  793. }
  794. if (check_f1_adjust) {
  795. if (prec == 1) {
  796. if (mode == 0) {
  797. f1_adjust = -1;
  798. } else if (mode == 1 || mode == 2) {
  799. f1_adjust = 1;
  800. }
  801. }
  802. }
  803. fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
  804. if (prec == 1)
  805. fpp_round32(fpd);
  806. if (prec >= 2)
  807. fpp_round64(fpd);
  808. if (f1_adjust) {
  809. fpp_from_exten_fmovem(fpd, &f[0], &f[1], &f[2]);
  810. f[1] += f1_adjust * 0x80;
  811. fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
  812. }
  813. fpsr_set_result_always(fpd);
  814. fpsr_set_result(fpd);
  815. regs.fpsr |= sr;
  816. return false;
  817. }
  818. }
  819. f[0] = fpp_cr[entry].val[0];
  820. f[1] = fpp_cr[entry].val[1];
  821. f[2] = fpp_cr[entry].val[2];
  822. // if constant is inexact, set inexact bit and round
  823. // note: with valid constants, LSB never wraps
  824. if (fpp_cr[entry].inexact) {
  825. fpsr_set_exception(FPSR_INEX2);
  826. f[2] += fpp_cr[entry].rndoff[mode];
  827. }
  828. fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
  829. if (prec == 1)
  830. fpp_round32(fpd);
  831. if (prec >= 2)
  832. fpp_round64(fpd);
  833. fpsr_set_result_always(fpd);
  834. fpsr_set_result(fpd);
  835. return true;
  836. }
  837. #if 0
  838. static void fpu_format_error (void)
  839. {
  840. uaecptr newpc;
  841. regs.t0 = regs.t1 = 0;
  842. MakeSR ();
  843. if (!regs.s) {
  844. regs.usp = m68k_areg (regs, 7);
  845. m68k_areg (regs, 7) = regs.isp;
  846. }
  847. regs.s = 1;
  848. m68k_areg (regs, 7) -= 2;
  849. x_cp_put_long (m68k_areg (regs, 7), 0x0000 + 14 * 4);
  850. m68k_areg (regs, 7) -= 4;
  851. x_cp_put_long (m68k_areg (regs, 7), m68k_getpc ());
  852. m68k_areg (regs, 7) -= 2;
  853. x_cp_put_long (m68k_areg (regs, 7), regs.sr);
  854. newpc = x_cp_get_long (regs.vbr + 14 * 4);
  855. m68k_setpc (newpc);
  856. #ifdef JIT
  857. set_special (SPCFLAG_END_COMPILE);
  858. #endif
  859. regs.fp_exception = true;
  860. }
  861. #endif
  862. static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, bool easet, uaecptr oldpc, fpdata *src, int reg, int size)
  863. {
  864. if ((extra & 0x7f) == 4) // FSQRT 4->5
  865. extra |= 1;
  866. // data for fsave stack frame
  867. regs.fpu_exp_state = 1; // 68060 IDLE frame, 68040 UNIMP frame
  868. regs.fpiar = oldpc;
  869. if (currprefs.cpu_model == 68060) {
  870. // fsave data for 68060
  871. reset_fsave_data();
  872. } else if(currprefs.cpu_model == 68040) {
  873. // fsave data for 68040
  874. fsave_data.fpiarcu = regs.fpiar;
  875. if (regs.fp_unimp_pend == 0) { // else data has been saved by fp_unimp_datatype
  876. reset_fsave_data();
  877. fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038) >> 1) | ((extra & 0x004) << 3);
  878. fsave_data.cmdreg1b = extra;
  879. fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
  880. fsave_data.stag = get_ftag(src, size);
  881. if (reg >= 0) {
  882. fpp_from_exten_fmovem(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
  883. fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
  884. }
  885. }
  886. }
  887. if (warned > 0) {
  888. write_log (_T("FPU unimplemented instruction: OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
  889. opcode, extra, fsave_data.et[0],fsave_data.et[1],fsave_data.et[2], ea, oldpc);
  890. #if EXCEPTION_FPP == 0
  891. warned--;
  892. #endif
  893. }
  894. regs.fp_ea = ea;
  895. regs.fp_ea_set = easet;
  896. regs.fp_unimp_ins = true;
  897. fp_unimp_instruction_exception_pending();
  898. regs.fp_exception = true;
  899. }
  900. static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, bool easet, uaecptr oldpc, fpdata *src, uae_u32 *packed, bool predenormal)
  901. {
  902. uae_u32 reg = (extra >> 7) & 7;
  903. uae_u32 size = (extra >> 10) & 7;
  904. uae_u32 opclass = (extra >> 13) & 7;
  905. regs.fp_opword = opcode;
  906. regs.fp_ea = ea;
  907. regs.fp_ea_set = easet;
  908. regs.fp_unimp_pend = packed ? 2 : (predenormal ? 3 : 1);
  909. regs.fpiar = oldpc;
  910. if((extra & 0x7f) == 4) // FSQRT 4->5
  911. extra |= 1;
  912. // data for fsave stack frame
  913. reset_fsave_data();
  914. regs.fpu_exp_state = 2; // 68060 EXCP frame, 68040 BUSY frame
  915. if (currprefs.cpu_model == 68060) {
  916. // fsave data for 68060
  917. if (packed) {
  918. regs.fpu_exp_state = 1; // 68060 IDLE frame
  919. } else {
  920. fsave_data.v = 7; // vector & 0x7
  921. fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
  922. }
  923. } else if (currprefs.cpu_model == 68040) {
  924. // fsave data for 68040
  925. fsave_data.cmdreg1b = extra;
  926. fsave_data.fpiarcu = regs.fpiar;
  927. if (packed) {
  928. fsave_data.e1 = 1; // used to distinguish packed operands
  929. }
  930. if (opclass == 3) { // OPCLASS 011
  931. fsave_data.t = 1;
  932. fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
  933. fsave_data.stag = get_ftag(src, -1);
  934. fpp_from_exten_fmovem(src, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); // undocumented
  935. fsave_data.dtag = get_ftag(src, -1); // undocumented
  936. } else { // OPCLASS 000 and 010
  937. if (packed) {
  938. fsave_data.fpt[2] = packed[0]; // yes, this is correct.
  939. fsave_data.fpt[1] = packed[1]; // undocumented
  940. fsave_data.et[1] = packed[1];
  941. fsave_data.et[2] = packed[2];
  942. fsave_data.stag = 7; // undocumented
  943. } else {
  944. fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
  945. fsave_data.stag = get_ftag(src, (opclass == 0) ? 0xffffffff : size);
  946. if (fsave_data.stag == 5) {
  947. fsave_data.et[0] = (size == 1) ? 0x3f800000 : 0x3c000000; // exponent for denormalized single and double
  948. }
  949. if (fp_is_dyadic(extra)) {
  950. fpp_from_exten_fmovem(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
  951. fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
  952. }
  953. }
  954. }
  955. }
  956. if (warned > 0) {
  957. write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
  958. packed ? _T("packed") : _T("denormal"), opcode, extra,
  959. packed ? fsave_data.fpt[2] : fsave_data.et[0], fsave_data.et[1], fsave_data.et[2], ea, oldpc);
  960. #if EXCEPTION_FPP == 0
  961. warned--;
  962. #endif
  963. }
  964. regs.fp_exception = true;
  965. }
  966. static void fpu_op_illg(uae_u16 opcode, uae_u32 ea, bool easet, uaecptr oldpc)
  967. {
  968. if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
  969. || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
  970. regs.fp_unimp_ins = true;
  971. regs.fp_ea = ea;
  972. regs.fp_ea_set = easet;
  973. regs.fpiar = oldpc;
  974. fp_unimp_instruction_exception_pending();
  975. return;
  976. }
  977. regs.fp_exception = true;
  978. m68k_setpc (oldpc);
  979. op_illg(opcode);
  980. }
  981. static void fpu_noinst(uae_u16 opcode, uaecptr pc)
  982. {
  983. #if EXCEPTION_FPP
  984. write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
  985. #endif
  986. regs.fp_exception = true;
  987. m68k_setpc(pc);
  988. op_illg(opcode);
  989. }
  990. static bool if_no_fpu(void)
  991. {
  992. return (regs.pcr & 2) || currprefs.fpu_model <= 0;
  993. }
  994. static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc)
  995. {
  996. if (if_no_fpu()) {
  997. #if EXCEPTION_FPP
  998. write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
  999. #endif
  1000. if (fpu_mmu_fixup) {
  1001. m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
  1002. mmufixup[0].reg = -1;
  1003. }
  1004. fpu_op_illg(opcode, ea, easet, oldpc);
  1005. return true;
  1006. }
  1007. return false;
  1008. }
  1009. static bool fault_if_nonexisting_opmode(uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
  1010. {
  1011. uae_u16 v = extra & 0x7f;
  1012. // if non-existing FPU instruction (opmode): exit immediately and generate normal frame 0 exception 11.
  1013. if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) {
  1014. if (currprefs.fpu_no_unimplemented) {
  1015. if (v >= 0x40) {
  1016. fpu_noinst(opcode, oldpc);
  1017. return true;
  1018. }
  1019. return false;
  1020. }
  1021. // 6888x undocumented but existing opmodes
  1022. switch (v)
  1023. {
  1024. case 0x05:
  1025. case 0x07:
  1026. case 0x0b:
  1027. case 0x13:
  1028. case 0x17:
  1029. case 0x1b:
  1030. case 0x29:
  1031. case 0x2a:
  1032. case 0x2b:
  1033. case 0x2c:
  1034. case 0x2d:
  1035. case 0x2e:
  1036. case 0x2f:
  1037. case 0x39:
  1038. case 0x3b:
  1039. case 0x3c:
  1040. case 0x3d:
  1041. case 0x3e:
  1042. case 0x3f:
  1043. return false;
  1044. }
  1045. }
  1046. switch (v)
  1047. {
  1048. case 0x05:
  1049. case 0x07:
  1050. case 0x0b:
  1051. case 0x13:
  1052. case 0x17:
  1053. case 0x1b:
  1054. case 0x29:
  1055. case 0x2a:
  1056. case 0x2b:
  1057. case 0x2c:
  1058. case 0x2d:
  1059. case 0x2e:
  1060. case 0x2f:
  1061. case 0x39:
  1062. case 0x3b:
  1063. case 0x3c:
  1064. case 0x3d:
  1065. case 0x3e:
  1066. case 0x3f:
  1067. case 0x42:
  1068. case 0x43:
  1069. case 0x46:
  1070. case 0x47:
  1071. case 0x48:
  1072. case 0x49:
  1073. case 0x4a:
  1074. case 0x4b:
  1075. case 0x4c:
  1076. case 0x4d:
  1077. case 0x4e:
  1078. case 0x4f:
  1079. case 0x50:
  1080. case 0x51:
  1081. case 0x52:
  1082. case 0x53:
  1083. case 0x54:
  1084. case 0x55:
  1085. case 0x56:
  1086. case 0x57:
  1087. case 0x59:
  1088. case 0x5b:
  1089. case 0x5d:
  1090. case 0x5f:
  1091. case 0x61:
  1092. case 0x65:
  1093. case 0x69:
  1094. case 0x6a:
  1095. case 0x6b:
  1096. case 0x6d:
  1097. case 0x6e:
  1098. case 0x6f:
  1099. case 0x70:
  1100. case 0x71:
  1101. case 0x72:
  1102. case 0x73:
  1103. case 0x74:
  1104. case 0x75:
  1105. case 0x76:
  1106. case 0x77:
  1107. fpu_noinst(opcode, oldpc);
  1108. return true;
  1109. case 0x78:
  1110. case 0x79:
  1111. case 0x7a:
  1112. case 0x7b:
  1113. case 0x7c:
  1114. case 0x7d:
  1115. case 0x7e:
  1116. case 0x7f:
  1117. // Unexpected, isn't it?!
  1118. Exception(4);
  1119. return true;
  1120. break;
  1121. }
  1122. return false;
  1123. }
  1124. static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src, int reg)
  1125. {
  1126. if (fault_if_no_fpu (opcode, extra, ea, easet, oldpc))
  1127. return true;
  1128. if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  1129. if ((extra & (0x8000 | 0x2000)) != 0)
  1130. return false;
  1131. if ((extra & 0xfc00) == 0x5c00) {
  1132. // FMOVECR
  1133. fp_unimp_instruction(opcode, extra, ea, easet, oldpc, src, reg, -1);
  1134. return true;
  1135. }
  1136. uae_u16 v = extra & 0x7f;
  1137. /* >=0x040 are 68040/68060 only variants. 6888x = F-line exception. */
  1138. switch (v)
  1139. {
  1140. case 0x00: /* FMOVE */
  1141. case 0x04: /* FSQRT */
  1142. case 0x18: /* FABS */
  1143. case 0x1a: /* FNEG */
  1144. case 0x20: /* FDIV */
  1145. case 0x22: /* FADD */
  1146. case 0x23: /* FMUL */
  1147. case 0x24: /* FSGLDIV */
  1148. case 0x27: /* FSGLMUL */
  1149. case 0x28: /* FSUB */
  1150. case 0x38: /* FCMP */
  1151. case 0x3a: /* FTST */
  1152. case 0x40: /* FSMOVE */
  1153. case 0x41: /* FSSQRT */
  1154. case 0x44: /* FDMOVE */
  1155. case 0x45: /* FDSQRT */
  1156. case 0x58: /* FSABS */
  1157. case 0x5c: /* FDABS */
  1158. case 0x5a: /* FSNEG */
  1159. case 0x5e: /* FDNEG */
  1160. case 0x60: /* FSDIV */
  1161. case 0x62: /* FSADD */
  1162. case 0x63: /* FSMUL */
  1163. case 0x64: /* FDDIV */
  1164. case 0x66: /* FDADD */
  1165. case 0x67: /* FDMUL */
  1166. case 0x68: /* FSSUB */
  1167. case 0x6c: /* FDSUB */
  1168. return false;
  1169. case 0x01: /* FINT */
  1170. case 0x03: /* FINTRZ */
  1171. // Unimplemented only in 68040.
  1172. if(currprefs.cpu_model != 68040) {
  1173. return false;
  1174. }
  1175. default:
  1176. fp_unimp_instruction(opcode, extra, ea, easet, oldpc, src, reg, -1);
  1177. return true;
  1178. }
  1179. }
  1180. return false;
  1181. }
  1182. static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
  1183. {
  1184. if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) && currprefs.fpu_no_unimplemented) {
  1185. uae_u16 v = extra & 0x7f;
  1186. switch(v)
  1187. {
  1188. case 0x00: /* FMOVE */
  1189. case 0x01: /* FINT */
  1190. case 0x02: /* FSINH */
  1191. case 0x03: /* FINTRZ */
  1192. case 0x04: /* FSQRT */
  1193. case 0x06: /* FLOGNP1 */
  1194. case 0x08: /* FETOXM1 */
  1195. case 0x09: /* FTANH */
  1196. case 0x0a: /* FATAN */
  1197. case 0x0c: /* FASIN */
  1198. case 0x0d: /* FATANH */
  1199. case 0x0e: /* FSIN */
  1200. case 0x0f: /* FTAN */
  1201. case 0x10: /* FETOX */
  1202. case 0x11: /* FTWOTOX */
  1203. case 0x12: /* FTENTOX */
  1204. case 0x14: /* FLOGN */
  1205. case 0x15: /* FLOG10 */
  1206. case 0x16: /* FLOG2 */
  1207. case 0x18: /* FABS */
  1208. case 0x19: /* FCOSH */
  1209. case 0x1a: /* FNEG */
  1210. case 0x1c: /* FACOS */
  1211. case 0x1d: /* FCOS */
  1212. case 0x1e: /* FGETEXP */
  1213. case 0x1f: /* FGETMAN */
  1214. case 0x20: /* FDIV */
  1215. case 0x21: /* FMOD */
  1216. case 0x22: /* FADD */
  1217. case 0x23: /* FMUL */
  1218. case 0x24: /* FSGLDIV */
  1219. case 0x25: /* FREM */
  1220. case 0x26: /* FSCALE */
  1221. case 0x27: /* FSGLMUL */
  1222. case 0x28: /* FSUB */
  1223. case 0x30: /* FSINCOS */
  1224. case 0x31: /* FSINCOS */
  1225. case 0x32: /* FSINCOS */
  1226. case 0x33: /* FSINCOS */
  1227. case 0x34: /* FSINCOS */
  1228. case 0x35: /* FSINCOS */
  1229. case 0x36: /* FSINCOS */
  1230. case 0x37: /* FSINCOS */
  1231. case 0x38: /* FCMP */
  1232. case 0x3a: /* FTST */
  1233. // 6888x invalid opmodes execute existing FPU instruction.
  1234. // Only opmodes 0x40-0x7f generate F-line exception.
  1235. case 0x05:
  1236. case 0x07:
  1237. case 0x0b:
  1238. case 0x13:
  1239. case 0x17:
  1240. case 0x1b:
  1241. case 0x29:
  1242. case 0x2a:
  1243. case 0x2b:
  1244. case 0x2c:
  1245. case 0x2d:
  1246. case 0x2e:
  1247. case 0x2f:
  1248. case 0x39:
  1249. case 0x3b:
  1250. case 0x3c:
  1251. case 0x3d:
  1252. case 0x3e:
  1253. case 0x3f:
  1254. return false;
  1255. default:
  1256. fpu_noinst (opcode, oldpc);
  1257. return true;
  1258. }
  1259. }
  1260. return false;
  1261. }
  1262. static bool fault_if_60 (void)
  1263. {
  1264. if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  1265. Exception(60);
  1266. return true;
  1267. }
  1268. return false;
  1269. }
  1270. static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc)
  1271. {
  1272. if (fault_if_no_fpu (opcode, extra, ea, easet, oldpc))
  1273. return true;
  1274. if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  1275. // 68060 FTRAPcc, FDBcc and FScc are not implemented.
  1276. regs.fp_unimp_ins = true;
  1277. regs.fp_ea = ea;
  1278. regs.fp_ea_set = easet;
  1279. regs.fpiar = oldpc;
  1280. fp_unimp_instruction_exception_pending();
  1281. return true;
  1282. }
  1283. return false;
  1284. }
  1285. static bool fault_if_no_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
  1286. {
  1287. if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) {
  1288. #if EXCEPTION_FPP
  1289. write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
  1290. #endif
  1291. m68k_setpc (oldpc);
  1292. regs.fp_exception = true;
  1293. op_illg (opcode);
  1294. return true;
  1295. }
  1296. return false;
  1297. }
  1298. static int get_fpu_version (int model)
  1299. {
  1300. int v = 0;
  1301. switch (model)
  1302. {
  1303. case 68881:
  1304. case 68882:
  1305. v = 0x1f;
  1306. break;
  1307. case 68040:
  1308. if (currprefs.fpu_revision == 0x40)
  1309. v = 0x40;
  1310. else
  1311. v = 0x41;
  1312. break;
  1313. }
  1314. return v;
  1315. }
  1316. static void fpu_null (void)
  1317. {
  1318. regs.fpu_state = 0;
  1319. regs.fpu_exp_state = 0;
  1320. regs.fpcr = 0;
  1321. regs.fpsr = 0;
  1322. regs.fpiar = 0;
  1323. for (int i = 0; i < 8; i++)
  1324. fpnan (&regs.fp[i]);
  1325. }
  1326. // 68040/060 does not support denormals
  1327. static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src)
  1328. {
  1329. if (!support_denormals)
  1330. return false;
  1331. fpp_is_init(src);
  1332. if (fpp_is_unnormal(src) || fpp_is_denormal(src)) {
  1333. if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  1334. if (fpp_is_zero(src)) {
  1335. fpp_normalize(src); // 68040/060 can only fix unnormal zeros
  1336. } else {
  1337. fp_unimp_datatype(opcode, extra, ea, easet, oldpc, src, NULL, true);
  1338. return true;
  1339. }
  1340. } else {
  1341. fpp_normalize(src);
  1342. }
  1343. }
  1344. return false;
  1345. }
  1346. static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *dst, fpdata *src)
  1347. {
  1348. if (!support_denormals)
  1349. return false;
  1350. fpp_is_init(dst);
  1351. if (fpp_is_unnormal(dst) || fpp_is_denormal(dst)) {
  1352. if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  1353. if (fpp_is_zero(dst)) {
  1354. fpp_normalize(dst); // 68040/060 can only fix unnormal zeros
  1355. } else {
  1356. fp_unimp_datatype(opcode, extra, ea, easet, oldpc, src, NULL, false);
  1357. return true;
  1358. }
  1359. } else {
  1360. fpp_normalize(dst);
  1361. }
  1362. }
  1363. return false;
  1364. }
  1365. // 68040/060 does not support packed decimal format
  1366. static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src, uae_u32 *packed)
  1367. {
  1368. if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
  1369. fp_unimp_datatype(opcode, extra, ea, easet, oldpc, src, packed, false);
  1370. return true;
  1371. }
  1372. return false;
  1373. }
  1374. // 68040 does not support move to integer format
  1375. static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src)
  1376. {
  1377. if (currprefs.cpu_model == 68040 && currprefs.fpu_model && currprefs.fpu_mode > 0) {
  1378. fpsr_make_status();
  1379. if (regs.fpsr & (FPSR_SNAN | FPSR_OPERR)) {
  1380. fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea, easet, oldpc);
  1381. fp_exception_pending(false); // post
  1382. return true;
  1383. }
  1384. }
  1385. return false;
  1386. }
  1387. static int get_fp_value(uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp, bool *adsetp)
  1388. {
  1389. int size, mode, reg;
  1390. uae_u32 ad = 0;
  1391. bool adset = false;
  1392. static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
  1393. static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
  1394. uae_u32 exts[3];
  1395. int doext = 0;
  1396. if (!(extra & 0x4000)) {
  1397. // FPx to FPx
  1398. if (fault_if_no_fpu (opcode, extra, 0, false, oldpc))
  1399. return -1;
  1400. *src = regs.fp[(extra >> 10) & 7];
  1401. normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, src);
  1402. return 1;
  1403. }
  1404. mode = (opcode >> 3) & 7;
  1405. reg = opcode & 7;
  1406. size = (extra >> 10) & 7;
  1407. switch (mode) {
  1408. case 0: // Dn
  1409. if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, false, oldpc))
  1410. return -1;
  1411. switch (size)
  1412. {
  1413. case 6: // B
  1414. fpset(src, (uae_s8) m68k_dreg (regs, reg));
  1415. break;
  1416. case 4: // W
  1417. fpset(src, (uae_s16) m68k_dreg (regs, reg));
  1418. break;
  1419. case 0: // L
  1420. fpset(src, (uae_s32) m68k_dreg (regs, reg));
  1421. break;
  1422. case 1: // S
  1423. fpp_to_single (src, m68k_dreg (regs, reg));
  1424. normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, src);
  1425. break;
  1426. case 3: // P
  1427. if (currprefs.cpu_model == 68060) {
  1428. uae_u32 wrd[3];
  1429. if (fault_if_no_packed_support(opcode, extra, 0, false, oldpc, NULL, wrd))
  1430. return 1;
  1431. }
  1432. return 0;
  1433. default:
  1434. if (currprefs.cpu_model >= 68040) {
  1435. if (fault_if_unimplemented_680x0(opcode, extra, ad, adset, oldpc, src, reg))
  1436. return -1;
  1437. regs.fpiar = oldpc;
  1438. }
  1439. return 0;
  1440. }
  1441. return 1;
  1442. case 1: // An
  1443. if (currprefs.cpu_model >= 68040) {
  1444. if (fault_if_unimplemented_680x0(opcode, extra, ad, adset, oldpc, src, reg))
  1445. return -1;
  1446. }
  1447. return 0;
  1448. case 2: // (An)
  1449. ad = m68k_areg (regs, reg);
  1450. adset = true;
  1451. break;
  1452. case 3: // (An)+
  1453. // Also needed by fault_if_no_fpu
  1454. mmufixup[0].reg = reg;
  1455. mmufixup[0].value = m68k_areg (regs, reg);
  1456. fpu_mmu_fixup = true;
  1457. ad = m68k_areg (regs, reg);
  1458. adset = true;
  1459. m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
  1460. break;
  1461. case 4: // -(An)
  1462. // Also needed by fault_if_no_fpu
  1463. mmufixup[0].reg = reg;
  1464. mmufixup[0].value = m68k_areg (regs, reg);
  1465. fpu_mmu_fixup = true;
  1466. m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
  1467. ad = m68k_areg (regs, reg);
  1468. adset = true;
  1469. // 68060 no fpu -(an): EA points to -4, not -12 if extended precision
  1470. // or unsupported packed datatype.
  1471. if (currprefs.cpu_model == 68060 && ((if_no_fpu() && sz1[size] == 12) || size == 3)) {
  1472. ad += 8;
  1473. }
  1474. break;
  1475. case 5: // (d16,An)
  1476. ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
  1477. adset = true;
  1478. break;
  1479. case 6: // (d8,An,Xn)+
  1480. ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
  1481. adset = true;
  1482. break;
  1483. case 7:
  1484. switch (reg)
  1485. {
  1486. case 0: // (xxx).W
  1487. ad = (uae_s32) (uae_s16) x_cp_next_iword ();
  1488. adset = true;
  1489. break;
  1490. case 1: // (xxx).L
  1491. ad = x_cp_next_ilong ();
  1492. adset = true;
  1493. break;
  1494. case 2: // (d16,PC)
  1495. ad = m68k_getpc ();
  1496. ad += (uae_s32) (uae_s16) x_cp_next_iword ();
  1497. adset = true;
  1498. break;
  1499. case 3: // (d8,PC,Xn)+
  1500. ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
  1501. adset = true;
  1502. break;
  1503. case 4: // #imm
  1504. doext = 1;
  1505. switch (size)
  1506. {
  1507. case 0: // L
  1508. case 1: // S
  1509. exts[0] = x_cp_next_ilong ();
  1510. break;
  1511. case 2: // X
  1512. case 3: // P
  1513. // 68060 and immediate X or P: unimplemented effective address
  1514. if (fault_if_60())
  1515. return -1;
  1516. exts[0] = x_cp_next_ilong ();
  1517. exts[1] = x_cp_next_ilong ();
  1518. exts[2] = x_cp_next_ilong ();
  1519. break;
  1520. case 4: // W
  1521. exts[0] = x_cp_next_iword ();
  1522. break;
  1523. case 5: // D
  1524. exts[0] = x_cp_next_ilong ();
  1525. exts[1] = x_cp_next_ilong ();
  1526. break;
  1527. case 6: // B
  1528. exts[0] = x_cp_next_iword ();
  1529. break;
  1530. }
  1531. break;
  1532. default:
  1533. return 0;
  1534. }
  1535. }
  1536. if (fault_if_no_fpu (opcode, extra, ad, adset, oldpc))
  1537. return -1;
  1538. *adp = ad;
  1539. *adsetp = adset;
  1540. uae_u32 adold = ad;
  1541. if (currprefs.fpu_model == 68060) {
  1542. // Skip if 68040 because FSAVE frame can store both src and dst
  1543. if (fault_if_unimplemented_680x0(opcode, extra, ad, adset, oldpc, src, -1)) {
  1544. return -1;
  1545. }
  1546. }
  1547. switch (size)
  1548. {
  1549. case 0: // L
  1550. fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad)));
  1551. break;
  1552. case 1: // S
  1553. fpp_to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
  1554. normalize_or_fault_if_no_denormal_support(opcode, extra, adold, adset, oldpc, src);
  1555. break;
  1556. case 2: // X
  1557. {
  1558. uae_u32 wrd1, wrd2, wrd3;
  1559. wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
  1560. ad += 4;
  1561. wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
  1562. ad += 4;
  1563. wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
  1564. fpp_to_exten (src, wrd1, wrd2, wrd3);
  1565. normalize_or_fault_if_no_denormal_support(opcode, extra, adold, adset, oldpc, src);
  1566. }
  1567. break;
  1568. case 3: // P
  1569. {
  1570. uae_u32 wrd[3];
  1571. if (currprefs.cpu_model == 68060) {
  1572. if (fault_if_no_packed_support (opcode, extra, adold, adset, oldpc, NULL, wrd))
  1573. return 1;
  1574. }
  1575. wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
  1576. ad += 4;
  1577. wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
  1578. ad += 4;
  1579. wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
  1580. if (fault_if_no_packed_support (opcode, extra, adold, adset, oldpc, NULL, wrd))
  1581. return 1;
  1582. fpp_to_pack (src, wrd, 0);
  1583. fpp_normalize(src);
  1584. return 1;
  1585. }
  1586. break;
  1587. case 4: // W
  1588. fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad)));
  1589. break;
  1590. case 5: // D
  1591. {
  1592. uae_u32 wrd1, wrd2;
  1593. wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
  1594. ad += 4;
  1595. wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
  1596. fpp_to_double (src, wrd1, wrd2);
  1597. normalize_or_fault_if_no_denormal_support(opcode, extra, adold, adset, oldpc, src);
  1598. }
  1599. break;
  1600. case 6: // B
  1601. fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad)));
  1602. break;
  1603. default:
  1604. return 0;
  1605. }
  1606. return 1;
  1607. }
  1608. static int put_fp_value2(fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp, bool *adsetp)
  1609. {
  1610. int size, mode, reg;
  1611. uae_u32 ad = 0;
  1612. bool adset = false;
  1613. static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
  1614. static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
  1615. #if DEBUG_FPP
  1616. if (!isinrom ())
  1617. write_log (_T("PUTFP: %04X %04X\n"), opcode, extra);
  1618. #endif
  1619. #if 0
  1620. if (!(extra & 0x4000)) {
  1621. if (fault_if_no_fpu (opcode, extra, 0, oldpc))
  1622. return 1;
  1623. regs.fp[(extra >> 10) & 7] = *value;
  1624. return 1;
  1625. }
  1626. #endif
  1627. reg = opcode & 7;
  1628. mode = (opcode >> 3) & 7;
  1629. size = (extra >> 10) & 7;
  1630. switch (mode)
  1631. {
  1632. case 0: // Dn
  1633. if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, false, oldpc))
  1634. return -1;
  1635. switch (size)
  1636. {
  1637. case 6: // B
  1638. if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
  1639. return 1;
  1640. m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 0) & 0xff)
  1641. | (m68k_dreg (regs, reg) & ~0xff)));
  1642. if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
  1643. return -1;
  1644. break;
  1645. case 4: // W
  1646. if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
  1647. return 1;
  1648. m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 1) & 0xffff)
  1649. | (m68k_dreg (regs, reg) & ~0xffff)));
  1650. if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
  1651. return -1;
  1652. break;
  1653. case 0: // L
  1654. if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
  1655. return 1;
  1656. m68k_dreg (regs, reg) = (uae_u32)fpp_to_int (value, 2);
  1657. if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
  1658. return -1;
  1659. break;
  1660. case 1: // S
  1661. if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
  1662. return 1;
  1663. m68k_dreg (regs, reg) = fpp_from_single (value);
  1664. break;
  1665. case 3: // packed
  1666. case 7: // packed
  1667. {
  1668. // K-factor size and other errors are checked even if EA is illegal
  1669. if (!currprefs.fpu_no_unimplemented || currprefs.cpu_model < 68040) {
  1670. uae_u32 wrd[3];
  1671. int kfactor = size == 7 ? m68k_dreg(regs, (extra >> 4) & 7) : extra;
  1672. kfactor &= 127;
  1673. if (kfactor & 64)
  1674. kfactor |= ~63;
  1675. fpp_normalize(value);
  1676. fpp_from_pack(value, wrd, kfactor);
  1677. fpp_get_status(&regs.fpsr);
  1678. }
  1679. return -2;
  1680. }
  1681. default:
  1682. return 0;
  1683. }
  1684. return 1;
  1685. case 1: // An
  1686. return 0;
  1687. case 2: // (An)
  1688. ad = m68k_areg (regs, reg);
  1689. adset = true;
  1690. break;
  1691. case 3: // (An)+
  1692. // Also needed by fault_if_no_fpu
  1693. mmufixup[0].reg = reg;
  1694. mmufixup[0].value = m68k_areg (regs, reg);
  1695. fpu_mmu_fixup = true;
  1696. ad = m68k_areg (regs, reg);
  1697. adset = true;
  1698. m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
  1699. break;
  1700. case 4: // -(An)
  1701. // Also needed by fault_if_no_fpu
  1702. mmufixup[0].reg = reg;
  1703. mmufixup[0].value = m68k_areg (regs, reg);
  1704. fpu_mmu_fixup = true;
  1705. m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
  1706. ad = m68k_areg (regs, reg);
  1707. adset = true;
  1708. // 68060 no fpu -(an): EA points to -4, not -12 if extended precision
  1709. // or if packed datatype
  1710. if (currprefs.cpu_model == 68060 && ((if_no_fpu() && sz1[size] == 12) || size == 3 || size == 7)) {
  1711. ad += 8;
  1712. }
  1713. break;
  1714. case 5: // (d16,An)
  1715. ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
  1716. adset = true;
  1717. break;
  1718. case 6: // (d8,An,Xn)+
  1719. ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
  1720. adset = true;
  1721. break;
  1722. case 7:
  1723. switch (reg)
  1724. {
  1725. case 0: // (xxx).W
  1726. ad = (uae_s32) (uae_s16) x_cp_next_iword ();
  1727. adset = true;
  1728. break;
  1729. case 1: // (xxx).L
  1730. ad = x_cp_next_ilong ();
  1731. adset = true;
  1732. break;
  1733. // Immediate and PC-relative modes are not supported
  1734. default:
  1735. return 0;
  1736. }
  1737. }
  1738. *adp = ad;
  1739. *adsetp = adset;
  1740. if (fault_if_no_fpu (opcode, extra, ad, adset, oldpc))
  1741. return -1;
  1742. switch (size)
  1743. {
  1744. case 0

Large files files are truncated, but you can click here to view the full file