fpa11_cpdt.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. NetWinder Floating Point Emulator
  3. (c) Rebel.com, 1998-1999
  4. (c) Philip Blundell, 1998, 2001
  5. Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include <linux/config.h>
  19. #include "fpa11.h"
  20. #include "softfloat.h"
  21. #include "fpopcode.h"
  22. #include "fpmodule.h"
  23. #include "fpmodule.inl"
  24. #include <asm/uaccess.h>
  25. static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
  26. {
  27. FPA11 *fpa11 = GET_FPA11();
  28. fpa11->fType[Fn] = typeSingle;
  29. get_user(fpa11->fpreg[Fn].fSingle, pMem);
  30. }
  31. static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
  32. {
  33. FPA11 *fpa11 = GET_FPA11();
  34. unsigned int *p;
  35. p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
  36. fpa11->fType[Fn] = typeDouble;
  37. #ifdef __ARMEB__
  38. get_user(p[0], &pMem[0]); /* sign & exponent */
  39. get_user(p[1], &pMem[1]);
  40. #else
  41. get_user(p[0], &pMem[1]);
  42. get_user(p[1], &pMem[0]); /* sign & exponent */
  43. #endif
  44. }
  45. #ifdef CONFIG_FPE_NWFPE_XP
  46. static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
  47. {
  48. FPA11 *fpa11 = GET_FPA11();
  49. unsigned int *p;
  50. p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
  51. fpa11->fType[Fn] = typeExtended;
  52. get_user(p[0], &pMem[0]); /* sign & exponent */
  53. get_user(p[1], &pMem[2]); /* ls bits */
  54. get_user(p[2], &pMem[1]); /* ms bits */
  55. }
  56. #endif
  57. static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
  58. {
  59. FPA11 *fpa11 = GET_FPA11();
  60. register unsigned int *p;
  61. unsigned long x;
  62. p = (unsigned int *) &(fpa11->fpreg[Fn]);
  63. get_user(x, &pMem[0]);
  64. fpa11->fType[Fn] = (x >> 14) & 0x00000003;
  65. switch (fpa11->fType[Fn]) {
  66. case typeSingle:
  67. case typeDouble:
  68. {
  69. get_user(p[0], &pMem[2]); /* Single */
  70. get_user(p[1], &pMem[1]); /* double msw */
  71. p[2] = 0; /* empty */
  72. }
  73. break;
  74. #ifdef CONFIG_FPE_NWFPE_XP
  75. case typeExtended:
  76. {
  77. get_user(p[1], &pMem[2]);
  78. get_user(p[2], &pMem[1]); /* msw */
  79. p[0] = (x & 0x80003fff);
  80. }
  81. break;
  82. #endif
  83. }
  84. }
  85. static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
  86. {
  87. FPA11 *fpa11 = GET_FPA11();
  88. union {
  89. float32 f;
  90. unsigned int i[1];
  91. } val;
  92. switch (fpa11->fType[Fn]) {
  93. case typeDouble:
  94. val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
  95. break;
  96. #ifdef CONFIG_FPE_NWFPE_XP
  97. case typeExtended:
  98. val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
  99. break;
  100. #endif
  101. default:
  102. val.f = fpa11->fpreg[Fn].fSingle;
  103. }
  104. put_user(val.i[0], pMem);
  105. }
  106. static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
  107. {
  108. FPA11 *fpa11 = GET_FPA11();
  109. union {
  110. float64 f;
  111. unsigned int i[2];
  112. } val;
  113. switch (fpa11->fType[Fn]) {
  114. case typeSingle:
  115. val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
  116. break;
  117. #ifdef CONFIG_FPE_NWFPE_XP
  118. case typeExtended:
  119. val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
  120. break;
  121. #endif
  122. default:
  123. val.f = fpa11->fpreg[Fn].fDouble;
  124. }
  125. #ifdef __ARMEB__
  126. put_user(val.i[0], &pMem[0]); /* msw */
  127. put_user(val.i[1], &pMem[1]); /* lsw */
  128. #else
  129. put_user(val.i[1], &pMem[0]); /* msw */
  130. put_user(val.i[0], &pMem[1]); /* lsw */
  131. #endif
  132. }
  133. #ifdef CONFIG_FPE_NWFPE_XP
  134. static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
  135. {
  136. FPA11 *fpa11 = GET_FPA11();
  137. union {
  138. floatx80 f;
  139. unsigned int i[3];
  140. } val;
  141. switch (fpa11->fType[Fn]) {
  142. case typeSingle:
  143. val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
  144. break;
  145. case typeDouble:
  146. val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
  147. break;
  148. default:
  149. val.f = fpa11->fpreg[Fn].fExtended;
  150. }
  151. put_user(val.i[0], &pMem[0]); /* sign & exp */
  152. put_user(val.i[1], &pMem[2]);
  153. put_user(val.i[2], &pMem[1]); /* msw */
  154. }
  155. #endif
  156. static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
  157. {
  158. FPA11 *fpa11 = GET_FPA11();
  159. register unsigned int nType, *p;
  160. p = (unsigned int *) &(fpa11->fpreg[Fn]);
  161. nType = fpa11->fType[Fn];
  162. switch (nType) {
  163. case typeSingle:
  164. case typeDouble:
  165. {
  166. put_user(p[0], &pMem[2]); /* single */
  167. put_user(p[1], &pMem[1]); /* double msw */
  168. put_user(nType << 14, &pMem[0]);
  169. }
  170. break;
  171. #ifdef CONFIG_FPE_NWFPE_XP
  172. case typeExtended:
  173. {
  174. put_user(p[2], &pMem[1]); /* msw */
  175. put_user(p[1], &pMem[2]);
  176. put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
  177. }
  178. break;
  179. #endif
  180. }
  181. }
  182. unsigned int PerformLDF(const unsigned int opcode)
  183. {
  184. unsigned int __user *pBase, *pAddress, *pFinal;
  185. unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
  186. pBase = (unsigned int __user *) readRegister(getRn(opcode));
  187. if (REG_PC == getRn(opcode)) {
  188. pBase += 2;
  189. write_back = 0;
  190. }
  191. pFinal = pBase;
  192. if (BIT_UP_SET(opcode))
  193. pFinal += getOffset(opcode);
  194. else
  195. pFinal -= getOffset(opcode);
  196. if (PREINDEXED(opcode))
  197. pAddress = pFinal;
  198. else
  199. pAddress = pBase;
  200. switch (opcode & MASK_TRANSFER_LENGTH) {
  201. case TRANSFER_SINGLE:
  202. loadSingle(getFd(opcode), pAddress);
  203. break;
  204. case TRANSFER_DOUBLE:
  205. loadDouble(getFd(opcode), pAddress);
  206. break;
  207. #ifdef CONFIG_FPE_NWFPE_XP
  208. case TRANSFER_EXTENDED:
  209. loadExtended(getFd(opcode), pAddress);
  210. break;
  211. #endif
  212. default:
  213. nRc = 0;
  214. }
  215. if (write_back)
  216. writeRegister(getRn(opcode), (unsigned long) pFinal);
  217. return nRc;
  218. }
  219. unsigned int PerformSTF(const unsigned int opcode)
  220. {
  221. unsigned int __user *pBase, *pAddress, *pFinal;
  222. unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
  223. struct roundingData roundData;
  224. roundData.mode = SetRoundingMode(opcode);
  225. roundData.precision = SetRoundingPrecision(opcode);
  226. roundData.exception = 0;
  227. pBase = (unsigned int __user *) readRegister(getRn(opcode));
  228. if (REG_PC == getRn(opcode)) {
  229. pBase += 2;
  230. write_back = 0;
  231. }
  232. pFinal = pBase;
  233. if (BIT_UP_SET(opcode))
  234. pFinal += getOffset(opcode);
  235. else
  236. pFinal -= getOffset(opcode);
  237. if (PREINDEXED(opcode))
  238. pAddress = pFinal;
  239. else
  240. pAddress = pBase;
  241. switch (opcode & MASK_TRANSFER_LENGTH) {
  242. case TRANSFER_SINGLE:
  243. storeSingle(&roundData, getFd(opcode), pAddress);
  244. break;
  245. case TRANSFER_DOUBLE:
  246. storeDouble(&roundData, getFd(opcode), pAddress);
  247. break;
  248. #ifdef CONFIG_FPE_NWFPE_XP
  249. case TRANSFER_EXTENDED:
  250. storeExtended(getFd(opcode), pAddress);
  251. break;
  252. #endif
  253. default:
  254. nRc = 0;
  255. }
  256. if (roundData.exception)
  257. float_raise(roundData.exception);
  258. if (write_back)
  259. writeRegister(getRn(opcode), (unsigned long) pFinal);
  260. return nRc;
  261. }
  262. unsigned int PerformLFM(const unsigned int opcode)
  263. {
  264. unsigned int __user *pBase, *pAddress, *pFinal;
  265. unsigned int i, Fd, write_back = WRITE_BACK(opcode);
  266. pBase = (unsigned int __user *) readRegister(getRn(opcode));
  267. if (REG_PC == getRn(opcode)) {
  268. pBase += 2;
  269. write_back = 0;
  270. }
  271. pFinal = pBase;
  272. if (BIT_UP_SET(opcode))
  273. pFinal += getOffset(opcode);
  274. else
  275. pFinal -= getOffset(opcode);
  276. if (PREINDEXED(opcode))
  277. pAddress = pFinal;
  278. else
  279. pAddress = pBase;
  280. Fd = getFd(opcode);
  281. for (i = getRegisterCount(opcode); i > 0; i--) {
  282. loadMultiple(Fd, pAddress);
  283. pAddress += 3;
  284. Fd++;
  285. if (Fd == 8)
  286. Fd = 0;
  287. }
  288. if (write_back)
  289. writeRegister(getRn(opcode), (unsigned long) pFinal);
  290. return 1;
  291. }
  292. unsigned int PerformSFM(const unsigned int opcode)
  293. {
  294. unsigned int __user *pBase, *pAddress, *pFinal;
  295. unsigned int i, Fd, write_back = WRITE_BACK(opcode);
  296. pBase = (unsigned int __user *) readRegister(getRn(opcode));
  297. if (REG_PC == getRn(opcode)) {
  298. pBase += 2;
  299. write_back = 0;
  300. }
  301. pFinal = pBase;
  302. if (BIT_UP_SET(opcode))
  303. pFinal += getOffset(opcode);
  304. else
  305. pFinal -= getOffset(opcode);
  306. if (PREINDEXED(opcode))
  307. pAddress = pFinal;
  308. else
  309. pAddress = pBase;
  310. Fd = getFd(opcode);
  311. for (i = getRegisterCount(opcode); i > 0; i--) {
  312. storeMultiple(Fd, pAddress);
  313. pAddress += 3;
  314. Fd++;
  315. if (Fd == 8)
  316. Fd = 0;
  317. }
  318. if (write_back)
  319. writeRegister(getRn(opcode), (unsigned long) pFinal);
  320. return 1;
  321. }
  322. unsigned int EmulateCPDT(const unsigned int opcode)
  323. {
  324. unsigned int nRc = 0;
  325. if (LDF_OP(opcode)) {
  326. nRc = PerformLDF(opcode);
  327. } else if (LFM_OP(opcode)) {
  328. nRc = PerformLFM(opcode);
  329. } else if (STF_OP(opcode)) {
  330. nRc = PerformSTF(opcode);
  331. } else if (SFM_OP(opcode)) {
  332. nRc = PerformSFM(opcode);
  333. } else {
  334. nRc = 0;
  335. }
  336. return nRc;
  337. }