fpuemu.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2005-2018 Andes Technology Corporation
  3. #include <asm/bitfield.h>
  4. #include <asm/uaccess.h>
  5. #include <asm/sfp-machine.h>
  6. #include <asm/fpuemu.h>
  7. #include <asm/nds32_fpu_inst.h>
  8. #define DPFROMREG(dp, x) (dp = (void *)((unsigned long *)fpu_reg + 2*x))
  9. #ifdef __NDS32_EL__
  10. #define SPFROMREG(sp, x)\
  11. ((sp) = (void *)((unsigned long *)fpu_reg + (x^1)))
  12. #else
  13. #define SPFROMREG(sp, x) ((sp) = (void *)((unsigned long *)fpu_reg + x))
  14. #endif
  15. #define DEF3OP(name, p, f1, f2) \
  16. void fpemu_##name##p(void *ft, void *fa, void *fb) \
  17. { \
  18. f1(fa, fa, fb); \
  19. f2(ft, ft, fa); \
  20. }
  21. #define DEF3OPNEG(name, p, f1, f2, f3) \
  22. void fpemu_##name##p(void *ft, void *fa, void *fb) \
  23. { \
  24. f1(fa, fa, fb); \
  25. f2(ft, ft, fa); \
  26. f3(ft, ft); \
  27. }
  28. DEF3OP(fmadd, s, fmuls, fadds);
  29. DEF3OP(fmsub, s, fmuls, fsubs);
  30. DEF3OP(fmadd, d, fmuld, faddd);
  31. DEF3OP(fmsub, d, fmuld, fsubd);
  32. DEF3OPNEG(fnmadd, s, fmuls, fadds, fnegs);
  33. DEF3OPNEG(fnmsub, s, fmuls, fsubs, fnegs);
  34. DEF3OPNEG(fnmadd, d, fmuld, faddd, fnegd);
  35. DEF3OPNEG(fnmsub, d, fmuld, fsubd, fnegd);
  36. static const unsigned char cmptab[8] = {
  37. SF_CEQ,
  38. SF_CEQ,
  39. SF_CLT,
  40. SF_CLT,
  41. SF_CLT | SF_CEQ,
  42. SF_CLT | SF_CEQ,
  43. SF_CUN,
  44. SF_CUN
  45. };
  46. enum ARGTYPE {
  47. S1S = 1,
  48. S2S,
  49. S1D,
  50. CS,
  51. D1D,
  52. D2D,
  53. D1S,
  54. CD
  55. };
  56. union func_t {
  57. void (*t)(void *ft, void *fa, void *fb);
  58. void (*b)(void *ft, void *fa);
  59. };
  60. /*
  61. * Emulate a single FPU arithmetic instruction.
  62. */
  63. static int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn)
  64. {
  65. int rfmt; /* resulting format */
  66. union func_t func;
  67. int ftype = 0;
  68. switch (rfmt = NDS32Insn_OPCODE_COP0(insn)) {
  69. case fs1_op:{
  70. switch (NDS32Insn_OPCODE_BIT69(insn)) {
  71. case fadds_op:
  72. func.t = fadds;
  73. ftype = S2S;
  74. break;
  75. case fsubs_op:
  76. func.t = fsubs;
  77. ftype = S2S;
  78. break;
  79. case fmadds_op:
  80. func.t = fpemu_fmadds;
  81. ftype = S2S;
  82. break;
  83. case fmsubs_op:
  84. func.t = fpemu_fmsubs;
  85. ftype = S2S;
  86. break;
  87. case fnmadds_op:
  88. func.t = fpemu_fnmadds;
  89. ftype = S2S;
  90. break;
  91. case fnmsubs_op:
  92. func.t = fpemu_fnmsubs;
  93. ftype = S2S;
  94. break;
  95. case fmuls_op:
  96. func.t = fmuls;
  97. ftype = S2S;
  98. break;
  99. case fdivs_op:
  100. func.t = fdivs;
  101. ftype = S2S;
  102. break;
  103. case fs1_f2op_op:
  104. switch (NDS32Insn_OPCODE_BIT1014(insn)) {
  105. case fs2d_op:
  106. func.b = fs2d;
  107. ftype = S1D;
  108. break;
  109. case fs2si_op:
  110. func.b = fs2si;
  111. ftype = S1S;
  112. break;
  113. case fs2si_z_op:
  114. func.b = fs2si_z;
  115. ftype = S1S;
  116. break;
  117. case fs2ui_op:
  118. func.b = fs2ui;
  119. ftype = S1S;
  120. break;
  121. case fs2ui_z_op:
  122. func.b = fs2ui_z;
  123. ftype = S1S;
  124. break;
  125. case fsi2s_op:
  126. func.b = fsi2s;
  127. ftype = S1S;
  128. break;
  129. case fui2s_op:
  130. func.b = fui2s;
  131. ftype = S1S;
  132. break;
  133. case fsqrts_op:
  134. func.b = fsqrts;
  135. ftype = S1S;
  136. break;
  137. default:
  138. return SIGILL;
  139. }
  140. break;
  141. default:
  142. return SIGILL;
  143. }
  144. break;
  145. }
  146. case fs2_op:
  147. switch (NDS32Insn_OPCODE_BIT69(insn)) {
  148. case fcmpeqs_op:
  149. case fcmpeqs_e_op:
  150. case fcmplts_op:
  151. case fcmplts_e_op:
  152. case fcmples_op:
  153. case fcmples_e_op:
  154. case fcmpuns_op:
  155. case fcmpuns_e_op:
  156. ftype = CS;
  157. break;
  158. default:
  159. return SIGILL;
  160. }
  161. break;
  162. case fd1_op:{
  163. switch (NDS32Insn_OPCODE_BIT69(insn)) {
  164. case faddd_op:
  165. func.t = faddd;
  166. ftype = D2D;
  167. break;
  168. case fsubd_op:
  169. func.t = fsubd;
  170. ftype = D2D;
  171. break;
  172. case fmaddd_op:
  173. func.t = fpemu_fmaddd;
  174. ftype = D2D;
  175. break;
  176. case fmsubd_op:
  177. func.t = fpemu_fmsubd;
  178. ftype = D2D;
  179. break;
  180. case fnmaddd_op:
  181. func.t = fpemu_fnmaddd;
  182. ftype = D2D;
  183. break;
  184. case fnmsubd_op:
  185. func.t = fpemu_fnmsubd;
  186. ftype = D2D;
  187. break;
  188. case fmuld_op:
  189. func.t = fmuld;
  190. ftype = D2D;
  191. break;
  192. case fdivd_op:
  193. func.t = fdivd;
  194. ftype = D2D;
  195. break;
  196. case fd1_f2op_op:
  197. switch (NDS32Insn_OPCODE_BIT1014(insn)) {
  198. case fd2s_op:
  199. func.b = fd2s;
  200. ftype = D1S;
  201. break;
  202. case fd2si_op:
  203. func.b = fd2si;
  204. ftype = D1S;
  205. break;
  206. case fd2si_z_op:
  207. func.b = fd2si_z;
  208. ftype = D1S;
  209. break;
  210. case fd2ui_op:
  211. func.b = fd2ui;
  212. ftype = D1S;
  213. break;
  214. case fd2ui_z_op:
  215. func.b = fd2ui_z;
  216. ftype = D1S;
  217. break;
  218. case fsi2d_op:
  219. func.b = fsi2d;
  220. ftype = D1S;
  221. break;
  222. case fui2d_op:
  223. func.b = fui2d;
  224. ftype = D1S;
  225. break;
  226. case fsqrtd_op:
  227. func.b = fsqrtd;
  228. ftype = D1D;
  229. break;
  230. default:
  231. return SIGILL;
  232. }
  233. break;
  234. default:
  235. return SIGILL;
  236. }
  237. break;
  238. }
  239. case fd2_op:
  240. switch (NDS32Insn_OPCODE_BIT69(insn)) {
  241. case fcmpeqd_op:
  242. case fcmpeqd_e_op:
  243. case fcmpltd_op:
  244. case fcmpltd_e_op:
  245. case fcmpled_op:
  246. case fcmpled_e_op:
  247. case fcmpund_op:
  248. case fcmpund_e_op:
  249. ftype = CD;
  250. break;
  251. default:
  252. return SIGILL;
  253. }
  254. break;
  255. default:
  256. return SIGILL;
  257. }
  258. switch (ftype) {
  259. case S1S:{
  260. void *ft, *fa;
  261. SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  262. SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  263. func.b(ft, fa);
  264. break;
  265. }
  266. case S2S:{
  267. void *ft, *fa, *fb;
  268. SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  269. SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  270. SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
  271. func.t(ft, fa, fb);
  272. break;
  273. }
  274. case S1D:{
  275. void *ft, *fa;
  276. DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  277. SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  278. func.b(ft, fa);
  279. break;
  280. }
  281. case CS:{
  282. unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
  283. void *ft, *fa, *fb;
  284. SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  285. SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  286. SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
  287. if (cmpop < 0x8) {
  288. cmpop = cmptab[cmpop];
  289. fcmps(ft, fa, fb, cmpop);
  290. } else
  291. return SIGILL;
  292. break;
  293. }
  294. case D1D:{
  295. void *ft, *fa;
  296. DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  297. DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  298. func.b(ft, fa);
  299. break;
  300. }
  301. case D2D:{
  302. void *ft, *fa, *fb;
  303. DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  304. DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  305. DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
  306. func.t(ft, fa, fb);
  307. break;
  308. }
  309. case D1S:{
  310. void *ft, *fa;
  311. SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  312. DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  313. func.b(ft, fa);
  314. break;
  315. }
  316. case CD:{
  317. unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
  318. void *ft, *fa, *fb;
  319. SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
  320. DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
  321. DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
  322. if (cmpop < 0x8) {
  323. cmpop = cmptab[cmpop];
  324. fcmpd(ft, fa, fb, cmpop);
  325. } else
  326. return SIGILL;
  327. break;
  328. }
  329. default:
  330. return SIGILL;
  331. }
  332. /*
  333. * If an exception is required, generate a tidy SIGFPE exception.
  334. */
  335. #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
  336. if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDF_IEXE)
  337. || ((fpu_reg->fpcsr << 5) & (fpu_reg->UDF_IEX_trap))) {
  338. #else
  339. if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE) {
  340. #endif
  341. return SIGFPE;
  342. }
  343. return 0;
  344. }
  345. int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu)
  346. {
  347. unsigned long insn = 0, addr = regs->ipc;
  348. unsigned long emulpc, contpc;
  349. unsigned char *pc = (void *)&insn;
  350. char c;
  351. int i = 0, ret;
  352. for (i = 0; i < 4; i++) {
  353. if (__get_user(c, (unsigned char *)addr++))
  354. return SIGBUS;
  355. *pc++ = c;
  356. }
  357. insn = be32_to_cpu(insn);
  358. emulpc = regs->ipc;
  359. contpc = regs->ipc + 4;
  360. if (NDS32Insn_OPCODE(insn) != cop0_op)
  361. return SIGILL;
  362. switch (NDS32Insn_OPCODE_COP0(insn)) {
  363. case fs1_op:
  364. case fs2_op:
  365. case fd1_op:
  366. case fd2_op:
  367. {
  368. /* a real fpu computation instruction */
  369. ret = fpu_emu(fpu, insn);
  370. if (!ret)
  371. regs->ipc = contpc;
  372. }
  373. break;
  374. default:
  375. return SIGILL;
  376. }
  377. return ret;
  378. }