EAFixedPoint.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. ///////////////////////////////////////////////////////////////////////////////
  5. // See the header file for documentation and example usage.
  6. ///////////////////////////////////////////////////////////////////////////////
  7. #include <EAStdC/internal/Config.h>
  8. #include <EAStdC/EAFixedPoint.h>
  9. #include <EAAssert/eaassert.h>
  10. namespace EA
  11. {
  12. namespace StdC
  13. {
  14. ///////////////////////////////////////////////////////////////////////////////
  15. // SFixed16::FixedMul
  16. //
  17. // returns a*b
  18. //
  19. #ifdef FP_USE_INTEL_ASM
  20. EASTDC_API __declspec(naked)
  21. int32_t __stdcall SFixed16::FixedMul(const int32_t /*a*/, const int32_t /*b*/)
  22. {
  23. __asm{ // VC++ compiler will choke if you put ";" comments with a templated inline assembly function.
  24. mov eax, [esp+4] // Move a into eax
  25. mov ecx, [esp+8] // Move b into ecx
  26. imul ecx // Multiply by b, storing the result in edx:eax
  27. shrd eax, edx, 16 // Do shift and leave result in eax.
  28. ret 8
  29. }
  30. #ifdef EA_COMPILER_INTEL // Intel C++
  31. return 0; // Just to get the compiler to shut up.
  32. #endif
  33. }
  34. #else
  35. template<> EASTDC_API
  36. int32_t FP_PASCAL SFixed16::FixedMul(const int32_t a, const int32_t b)
  37. {
  38. const int64_t c = (int64_t)a * b;
  39. return (int32_t)(c >> 16);
  40. }
  41. #endif
  42. ///////////////////////////////////////////////////////////////////////////////
  43. // SFixed16::FixedMul
  44. //
  45. // returns a*b
  46. //
  47. #ifdef FP_USE_INTEL_ASM
  48. EASTDC_API __declspec(naked)
  49. uint32_t __stdcall UFixed16::FixedMul(const uint32_t /*a*/, const uint32_t /*b*/)
  50. {
  51. __asm{ // VC++ compiler will choke if you put ";" comments with a templated inline assembly function.
  52. mov eax, [esp+4] // Move a into eax
  53. mov ecx, [esp+8] // Move b into ecx
  54. mul ecx // Multiply by b, storing the result in edx:eax
  55. shrd eax, edx, 16 // Do shift and leave result in eax.
  56. ret 8
  57. }
  58. #ifdef EA_COMPILER_INTEL // Intel C++
  59. return 0; // Just to get the compiler to shut up.
  60. #endif
  61. }
  62. #else
  63. template<> EASTDC_API
  64. uint32_t FP_PASCAL UFixed16::FixedMul(const uint32_t a, const uint32_t b)
  65. {
  66. const uint64_t c = (uint64_t)a * b;
  67. return (uint32_t)(c >> 16);
  68. }
  69. #endif
  70. ///////////////////////////////////////////////////////////////////////////////
  71. // SFixed16::FixedDiv
  72. //
  73. // returns a/b
  74. //
  75. #ifdef FP_USE_INTEL_ASM
  76. __declspec(naked)
  77. int32_t FP_PASCAL SFixed16::FixedDiv(const int32_t /*a*/, const int32_t /*b*/)
  78. {
  79. __asm{
  80. mov eax, [esp+4] // Prepare the number for division
  81. rol eax, 16 // Put the fractional part of the number in the top half of eax, rotating the top part to the bottom part for later use
  82. movsx edx, ax // Put the integer part in edx
  83. xor ax, ax // Clear the integer part from eax
  84. mov ecx, [esp+8] // Move b into ecx
  85. idiv ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  86. ret 8
  87. }
  88. #ifdef EA_COMPILER_INTEL // Intel C++
  89. return 0; // Just to get the compiler to shut up.
  90. #endif
  91. }
  92. #else
  93. template<> EASTDC_API
  94. int32_t FP_PASCAL SFixed16::FixedDiv(const int32_t a, const int32_t b)
  95. {
  96. const int64_t c = ((uint64_t)a) << 16;
  97. return (int32_t)(c / b);
  98. }
  99. #endif
  100. ///////////////////////////////////////////////////////////////////////////////
  101. // UFixed16::FixedDiv
  102. //
  103. #ifdef FP_USE_INTEL_ASM
  104. __declspec(naked)
  105. uint32_t __stdcall UFixed16::FixedDiv(const uint32_t /*a*/, const uint32_t /*b*/)
  106. {
  107. __asm{
  108. mov eax, [esp+4] // Prepare the number for division
  109. rol eax, 16 // Put the fractional part of the number in the top half of eax, rotating the top part to the bottom part for later use
  110. movsx edx, ax // Put the integer part in edx
  111. xor ax, ax // Clear the integer part from eax
  112. mov ecx, [esp+8] // Move b into ecx
  113. div ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  114. ret 8
  115. }
  116. #ifdef EA_COMPILER_INTEL // Intel C++
  117. return 0; // Just to get the compiler to shut up.
  118. #endif
  119. }
  120. #else
  121. template<> EASTDC_API
  122. uint32_t FP_PASCAL UFixed16::FixedDiv(const uint32_t a, const uint32_t b)
  123. {
  124. const uint64_t c = ((uint64_t)a) << 16;
  125. return (uint32_t)(c / b);
  126. }
  127. #endif
  128. ///////////////////////////////////////////////////////////////////////////////
  129. // SFixed16::FixedDivSafe
  130. //
  131. // returns a/b. Checks for overflow and returns max value if so, instead of bombing.
  132. //
  133. #ifdef FP_USE_INTEL_ASM
  134. __declspec(naked)
  135. int32_t __stdcall SFixed16::FixedDivSafe(const int32_t /*a*/, const int32_t /*b*/)
  136. {
  137. __asm{
  138. mov ecx, [esp+8] // Move b into ecx.
  139. or ecx, ecx // Test to see if equal to zero.
  140. je NOT_OK // if not OK
  141. mov eax, [esp+4] // Put a into eax.
  142. xor edx, edx // Clear out edx, since we'll be shifting into it.
  143. shld edx,eax,16 // double fixed
  144. cmp edx, ecx // do a test for overflow.
  145. jge NOT_OK // If edx is greater than ecx, then we will overflow on the divide.
  146. shl eax,16 // double fixed
  147. idiv ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  148. ret 8
  149. NOT_OK:
  150. mov eax, 0x7FFFFFFF // put in max value
  151. ret 8
  152. }
  153. #ifdef EA_COMPILER_INTEL // Intel C++
  154. return 0; // Just to get the compiler to shut up.
  155. #endif
  156. }
  157. #else
  158. template<> EASTDC_API
  159. int32_t FP_PASCAL SFixed16::FixedDivSafe(const int32_t a, const int32_t b)
  160. {
  161. if(b)
  162. {
  163. const int64_t c = ((int64_t)a) << 16;
  164. return (int32_t)(c / b);
  165. }
  166. return INT32_MAX;
  167. }
  168. #endif
  169. ///////////////////////////////////////////////////////////////////////////////
  170. // UFixed16::FixedDivSafe
  171. //
  172. #ifdef FP_USE_INTEL_ASM
  173. __declspec(naked)
  174. uint32_t __stdcall UFixed16::FixedDivSafe(const uint32_t /*a*/, const uint32_t /*b*/)
  175. {
  176. __asm{
  177. mov ecx, [esp+8] // Move b into ecx.
  178. or ecx, ecx // Test to see if equal to zero.
  179. je NOT_OK // if not OK
  180. mov eax, [esp+4] // Put a into eax.
  181. xor edx, edx // Clear out edx, since we'll be shifting into it.
  182. shld edx,eax,16 // double fixed
  183. cmp edx, ecx // do a test for overflow.
  184. jae NOT_OK // If edx is greater than ecx, then we will overflow on the divide.
  185. shl eax,16 // double fixed
  186. div ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  187. ret 8 // return
  188. NOT_OK:
  189. mov eax, 0xFFFFFFFF // put in max value
  190. ret 8
  191. }
  192. #ifdef EA_COMPILER_INTEL //Intel C++
  193. return 0; //Just to get the compiler to shut up.
  194. #endif
  195. }
  196. #else
  197. template<> EASTDC_API
  198. uint32_t FP_PASCAL UFixed16::FixedDivSafe(const uint32_t a, const uint32_t b)
  199. {
  200. if(b)
  201. {
  202. const uint64_t c = ((uint64_t)a) << 16;
  203. return (uint32_t)(c / b);
  204. }
  205. return UINT32_MAX;
  206. }
  207. #endif
  208. ///////////////////////////////////////////////////////////////////////////////
  209. // SFixed16::FixedMulDiv
  210. //
  211. // returns a*b/c Faster than separate mul and div.
  212. //
  213. #ifdef FP_USE_INTEL_ASM
  214. __declspec(naked)
  215. int32_t __stdcall SFixed16::FixedMulDiv(const int32_t /*a*/, const int32_t /*b*/, const int32_t /*c*/)
  216. {
  217. __asm{
  218. mov eax, [esp+4] // First set up the multiply. Put a into eax.
  219. mov ecx, [esp+8] // Put b into ecx.
  220. imul ecx // Multiply. The result is in edx:eax.
  221. mov ecx, [esp+12] // Put the denominator into ecx.
  222. idiv ecx // Divide, leaving the result in eax and remainder in edx.
  223. ret 12
  224. }
  225. #ifdef EA_COMPILER_INTEL // Intel C++
  226. return 0; // Just to get the compiler to shut up.
  227. #endif
  228. }
  229. #else
  230. template<> EASTDC_API
  231. int32_t FP_PASCAL SFixed16::FixedMulDiv(const int32_t /*a*/, const int32_t /*b*/, const int32_t /*c*/)
  232. {
  233. // EA_ASSERT(false); // This is not yet finished.
  234. return 0;
  235. }
  236. #endif
  237. ///////////////////////////////////////////////////////////////////////////////
  238. // UFixed16::FixedMulDiv
  239. //
  240. #ifdef FP_USE_INTEL_ASM
  241. __declspec(naked)
  242. uint32_t __stdcall UFixed16::FixedMulDiv(const uint32_t /*a*/, const uint32_t /*b*/, const uint32_t /*c*/)
  243. {
  244. __asm{
  245. mov eax, [esp+4] // First set up the multiply. Put a into eax.
  246. mov ecx, [esp+8] // Put b into ecx.
  247. mul ecx // Multiply. The result is in edx:eax.
  248. mov ecx, [esp+12] // Put the denominator into ecx.
  249. div ecx // Divide, leaving the result in eax and remainder in edx.
  250. ret 12
  251. }
  252. #ifdef EA_COMPILER_INTEL //Intel C++
  253. return 0; //Just to get the compiler to shut up.
  254. #endif
  255. }
  256. #else
  257. template<> EASTDC_API
  258. uint32_t FP_PASCAL UFixed16::FixedMulDiv(const uint32_t /*a*/, const uint32_t /*b*/, const uint32_t /*c*/)
  259. {
  260. // EA_ASSERT(false); // This is not yet finished.
  261. return 0;
  262. }
  263. #endif
  264. ///////////////////////////////////////////////////////////////////////////////
  265. // SFixed16::FixedMulDivSafe
  266. //
  267. #ifdef FP_USE_INTEL_ASM
  268. __declspec(naked)
  269. int32_t __stdcall SFixed16::FixedMulDivSafe(const int32_t /*a*/, const int32_t /*b*/, const int32_t /*c*/)
  270. {
  271. __asm{
  272. mov ecx, [esp+12] // Move b into ecx.
  273. or ecx, ecx // Test to see if equal to zero.
  274. je NOT_OK // if not OK
  275. mov eax, [esp+4] //
  276. mov ebx, [esp+8] //
  277. imul ebx //
  278. cmp edx, ecx // do a test for overflow.
  279. jge NOT_OK // If edx is greater than ecx, then we will overflow on the divide.
  280. idiv ecx // Result is in eax.
  281. ret 12
  282. NOT_OK:
  283. mov eax, 0x7FFFFFFF // put in max value
  284. ret 12
  285. }
  286. #ifdef EA_COMPILER_INTEL //Intel C++
  287. return 0; //Just to get the compiler to shut up.
  288. #endif
  289. }
  290. #else
  291. template<> EASTDC_API
  292. int32_t FP_PASCAL SFixed16::FixedMulDivSafe(const int32_t /*a*/, const int32_t /*b*/, const int32_t /*c*/)
  293. {
  294. // EA_ASSERT(false); // This is not yet finished.
  295. return 0;
  296. }
  297. #endif
  298. ///////////////////////////////////////////////////////////////////////////////
  299. // UFixed16::FixedMulDivSafe
  300. //
  301. #ifdef FP_USE_INTEL_ASM
  302. __declspec(naked)
  303. uint32_t __stdcall UFixed16::FixedMulDivSafe(const uint32_t /*a*/, const uint32_t /*b*/, const uint32_t /*c*/)
  304. {
  305. __asm{
  306. mov ecx, [esp+12] // Move b into ecx.
  307. or ecx, ecx // Test to see if equal to zero.
  308. je NOT_OK // if not OK
  309. mov eax, [esp+4] //
  310. mov ebx, [esp+8] //
  311. mul ebx //
  312. cmp edx, ecx // do a test for overflow.
  313. jae NOT_OK // If edx is greater than ecx, then we will overflow on the divide.
  314. div ecx // Result is in eax.
  315. ret 12
  316. NOT_OK:
  317. mov eax, 0xFFFFFFFF // put in max value
  318. ret 12
  319. }
  320. #ifdef EA_COMPILER_INTEL //Intel C++
  321. return 0; //Just to get the compiler to shut up.
  322. #endif
  323. }
  324. #else
  325. template<> EASTDC_API
  326. uint32_t FP_PASCAL UFixed16::FixedMulDivSafe(const uint32_t /*a*/, const uint32_t /*b*/, const uint32_t /*c*/)
  327. {
  328. // EA_ASSERT(false); // This is not yet finished.
  329. return 0;
  330. }
  331. #endif
  332. ///////////////////////////////////////////////////////////////////////////////
  333. // SFixed16::FixedMod
  334. //
  335. // returns a%b
  336. //
  337. #ifdef FP_USE_INTEL_ASM
  338. __declspec(naked)
  339. int32_t __stdcall SFixed16::FixedMod(const int32_t /*a*/, const int32_t /*b*/)
  340. {
  341. __asm{
  342. mov eax, [esp+4] // Prepare the number for division
  343. rol eax, 16 // Put the fractional part of the number in the top half of eax, rotating the top part to the bottom part for later use
  344. movsx edx, ax // Put the integer part in edx
  345. xor ax, ax // Clear the integer part from eax
  346. mov ecx, [esp+8] // Move b into ecx
  347. idiv ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  348. mov eax, edx // The remainder after idiv is in edx. So we move it to eax before the return.
  349. ret 8
  350. }
  351. #ifdef EA_COMPILER_INTEL // Intel C++
  352. return 0; // Just to get the compiler to shut up.
  353. #endif
  354. }
  355. #else
  356. template<> EASTDC_API
  357. int32_t FP_PASCAL SFixed16::FixedMod(const int32_t a, const int32_t b)
  358. {
  359. const uint64_t c = ((uint64_t)a) << 16;
  360. return (int32_t)(c % b);
  361. }
  362. #endif
  363. ///////////////////////////////////////////////////////////////////////////////
  364. // UFixed16::FixedMod
  365. //
  366. #ifdef FP_USE_INTEL_ASM
  367. __declspec(naked)
  368. uint32_t __stdcall UFixed16::FixedMod(const uint32_t /*a*/, const uint32_t /*b*/)
  369. {
  370. __asm{
  371. mov eax, [esp+4] // Prepare the number for division
  372. rol eax, 16 // Put the fractional part of the number in the top half of eax, rotating the top part to the bottom part for later use
  373. movsx edx, ax // Put the integer part in edx
  374. xor ax, ax // Clear the integer part from eax
  375. mov ecx, [esp+8] // Move b into ecx
  376. div ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  377. mov eax, edx // The remainder after div is in edx. So we move it to eax before the return.
  378. ret 8
  379. }
  380. #ifdef EA_COMPILER_INTEL // Intel C++
  381. return 0; // Just to get the compiler to shut up.
  382. #endif
  383. }
  384. #else
  385. template<> EASTDC_API
  386. uint32_t FP_PASCAL UFixed16::FixedMod(const uint32_t a, const uint32_t b)
  387. {
  388. const uint64_t c = ((uint64_t)a) << 16;
  389. return (uint32_t)(c % b);
  390. }
  391. #endif
  392. ///////////////////////////////////////////////////////////////////////////////
  393. // SFixed16::FixedModSafe
  394. //
  395. // returns a%b
  396. //
  397. #ifdef FP_USE_INTEL_ASM
  398. __declspec(naked)
  399. int32_t __stdcall SFixed16::FixedModSafe(const int32_t /*a*/, const int32_t /*b*/)
  400. {
  401. __asm{
  402. mov ecx, [esp+8] // Move b into ecx
  403. or ecx, ecx // Test to see if equal to zero.
  404. je NOT_OK // if not OK
  405. mov eax, [esp+4] // Prepare the number for division
  406. rol eax, 16 // Put the fractional part of the number in the top half of eax, rotating the top part to the bottom part for later use
  407. movsx edx, ax // Put the integer part in edx
  408. xor ax, ax // Clear the integer part from eax
  409. cmp edx, ecx // do a test for overflow.
  410. jge NOT_OK // If edx is greater than ecx, then we will overflow on the divide.
  411. div ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  412. mov eax, edx // The remainder after idiv is in edx. So we move it to eax before the return.
  413. ret 8
  414. NOT_OK:
  415. mov eax, 0xFFFFFFFF // put in max value
  416. ret 8
  417. }
  418. #ifdef EA_COMPILER_INTEL // Intel C++
  419. return 0; // Just to get the compiler to shut up.
  420. #endif
  421. }
  422. #else
  423. template<> EASTDC_API
  424. int32_t FP_PASCAL SFixed16::FixedModSafe(const int32_t a, const int32_t b)
  425. {
  426. if(b)
  427. {
  428. const uint64_t c = ((uint64_t)a) << 16;
  429. return (int32_t)(c % b);
  430. }
  431. return INT32_MAX;
  432. }
  433. #endif
  434. ///////////////////////////////////////////////////////////////////////////////
  435. // UFixed16::FixedModSafe
  436. //
  437. #ifdef FP_USE_INTEL_ASM
  438. __declspec(naked)
  439. uint32_t __stdcall UFixed16::FixedModSafe(const uint32_t /*a*/, const uint32_t /*b*/)
  440. {
  441. __asm{
  442. mov ecx, [esp+8] // Move b into ecx
  443. or ecx, ecx // Test to see if equal to zero.
  444. je NOT_OK // if not OK
  445. mov eax, [esp+4] // Prepare the number for division
  446. rol eax, 16 // Put the fractional part of the number in the top half of eax, rotating the top part to the bottom part for later use
  447. movsx edx, ax // Put the integer part in edx
  448. xor ax, ax // Clear the integer part from eax
  449. cmp edx, ecx // do a test for overflow.
  450. jae NOT_OK // If edx is greater than ecx, then we will overflow on the divide.
  451. div ecx // Divide and store. Divide the signed 64 bit value in edx:eax by the 32 bit value in ecx.
  452. mov eax, edx // The remainder after div is in edx. So we move it to eax before the return.
  453. ret 8
  454. NOT_OK:
  455. mov eax, 0xFFFFFFFF // put in max value
  456. ret 8
  457. }
  458. #ifdef EA_COMPILER_INTEL // Intel C++
  459. return 0; // Just to get the compiler to shut up.
  460. #endif
  461. }
  462. #else
  463. template<> EASTDC_API
  464. uint32_t FP_PASCAL UFixed16::FixedModSafe(const uint32_t a, const uint32_t b)
  465. {
  466. if(b)
  467. {
  468. const uint64_t c = ((uint64_t)a) << 16;
  469. return (uint32_t)(c % b);
  470. }
  471. return UINT32_MAX;
  472. }
  473. #endif
  474. } // namespace StdC
  475. } // namespace EA
  476. // For unity build friendliness, undef all local #defines.
  477. #undef FP_USE_INTEL_ASM