float.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <mach.h>
  5. #define Extern extern
  6. #include "power.h"
  7. ulong setfpscr(void);
  8. void setfpcc(double);
  9. void farith(ulong);
  10. void farith2(ulong);
  11. void fariths(ulong);
  12. void fcmp(ulong);
  13. void mtfsb1(ulong);
  14. void mcrfs(ulong);
  15. void mtfsb0(ulong);
  16. void mtfsf(ulong);
  17. void mtfsfi(ulong);
  18. void mffs(ulong);
  19. void mtfsf(ulong);
  20. Inst op59[] = {
  21. [18] {fariths, "fdivs", Ifloat},
  22. [20] {fariths, "fsubs", Ifloat},
  23. [21] {fariths, "fadds", Ifloat},
  24. [22] {unimp, "fsqrts", Ifloat},
  25. [24] {unimp, "fres", Ifloat},
  26. [25] {fariths, "fmuls", Ifloat},
  27. [28] {fariths, "fmsubs", Ifloat},
  28. [29] {fariths, "fmadds", Ifloat},
  29. [30] {fariths, "fnmsubs", Ifloat},
  30. [31] {fariths, "fnmadds", Ifloat},
  31. };
  32. Inset ops59 = {op59, nelem(op59)};
  33. Inst op63a[] = {
  34. [12] {farith, "frsp", Ifloat},
  35. [14] {farith, "fctiw", Ifloat},
  36. [15] {farith, "fctiwz", Ifloat},
  37. [18] {farith, "fdiv", Ifloat},
  38. [20] {farith, "fsub", Ifloat},
  39. [21] {farith, "fadd", Ifloat},
  40. [22] {unimp, "frsqrt", Ifloat},
  41. [23] {unimp, "fsel", Ifloat},
  42. [25] {farith, "fmul", Ifloat},
  43. [26] {unimp, "frsqrte", Ifloat},
  44. [28] {farith, "fmsub", Ifloat},
  45. [29] {farith, "fmadd", Ifloat},
  46. [30] {farith, "fnmsub", Ifloat},
  47. [31] {farith, "fnmadd", Ifloat},
  48. };
  49. Inset ops63a= {op63a, nelem(op63a)};
  50. Inst op63b[] = {
  51. [0] {fcmp, "fcmpu", Ifloat},
  52. [32] {fcmp, "fcmpo", Ifloat},
  53. [38] {mtfsb1, "mtfsb1", Ifloat},
  54. [40] {farith2, "fneg", Ifloat},
  55. [64] {mcrfs, "mcrfs", Ifloat},
  56. [70] {mtfsb0, "mtfsb0", Ifloat},
  57. [72] {farith2, "fmr", Ifloat},
  58. [134] {mtfsfi, "mtfsfi", Ifloat},
  59. [136] {farith2, "fnabs", Ifloat},
  60. [264] {farith2, "fabs", Ifloat},
  61. [583] {mffs, "mffs", Ifloat},
  62. [711] {mtfsf, "mtfsf", Ifloat},
  63. };
  64. Inset ops63b = {op63b, nelem(op63b)};
  65. void
  66. fpreginit(void)
  67. {
  68. int i;
  69. /* Normally initialised by the kernel */
  70. reg.fd[27] = 4503601774854144.0;
  71. reg.fd[29] = 0.5;
  72. reg.fd[28] = 0.0;
  73. reg.fd[30] = 1.0;
  74. reg.fd[31] = 2.0;
  75. for(i = 0; i < 27; i++)
  76. reg.fd[i] = reg.fd[28];
  77. }
  78. static double
  79. v2fp(uvlong v)
  80. {
  81. FPdbleword f;
  82. f.hi = v>>32;
  83. f.lo = v;
  84. return f.x;
  85. }
  86. static uvlong
  87. fp2v(double d)
  88. {
  89. FPdbleword f;
  90. f.x = d;
  91. return ((uvlong)f.hi<<32) | f.lo;
  92. }
  93. void
  94. lfs(ulong ir)
  95. {
  96. ulong ea;
  97. int imm, ra, rd, upd;
  98. union {
  99. ulong i;
  100. float f;
  101. } u;
  102. getairr(ir);
  103. ea = imm;
  104. upd = (ir&(1L<<26))!=0;
  105. if(ra) {
  106. ea += reg.r[ra];
  107. if(upd)
  108. reg.r[ra] = ea;
  109. } else {
  110. if(upd)
  111. undef(ir);
  112. }
  113. if(trace)
  114. itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
  115. u.i = getmem_w(ea);
  116. reg.fd[rd] = u.f;
  117. }
  118. void
  119. lfsx(ulong ir)
  120. {
  121. ulong ea;
  122. int rd, ra, rb, upd;
  123. union {
  124. ulong i;
  125. float f;
  126. } u;
  127. getarrr(ir);
  128. ea = reg.r[rb];
  129. upd = ((ir>>1)&0x3FF)==567;
  130. if(ra){
  131. ea += reg.r[ra];
  132. if(upd)
  133. reg.r[ra] = ea;
  134. if(trace)
  135. itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
  136. } else {
  137. if(upd)
  138. undef(ir);
  139. if(trace)
  140. itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
  141. }
  142. u.i = getmem_w(ea);
  143. reg.fd[rd] = u.f;
  144. }
  145. void
  146. lfd(ulong ir)
  147. {
  148. ulong ea;
  149. int imm, ra, rd, upd;
  150. getairr(ir);
  151. ea = imm;
  152. upd = (ir&(1L<<26))!=0;
  153. if(ra) {
  154. ea += reg.r[ra];
  155. if(upd)
  156. reg.r[ra] = ea;
  157. } else {
  158. if(upd)
  159. undef(ir);
  160. }
  161. if(trace)
  162. itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
  163. reg.fd[rd] = v2fp(getmem_v(ea));
  164. }
  165. void
  166. lfdx(ulong ir)
  167. {
  168. ulong ea;
  169. int rd, ra, rb, upd;
  170. getarrr(ir);
  171. ea = reg.r[rb];
  172. upd = ((ir>>1)&0x3FF)==631;
  173. if(ra){
  174. ea += reg.r[ra];
  175. if(upd)
  176. reg.r[ra] = ea;
  177. if(trace)
  178. itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
  179. } else {
  180. if(upd)
  181. undef(ir);
  182. if(trace)
  183. itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
  184. }
  185. reg.fd[rd] = v2fp(getmem_v(ea));
  186. }
  187. void
  188. stfs(ulong ir)
  189. {
  190. ulong ea;
  191. int imm, ra, rd, upd;
  192. union {
  193. float f;
  194. ulong w;
  195. } u;
  196. getairr(ir);
  197. ea = imm;
  198. upd = (ir&(1L<<26))!=0;
  199. if(ra) {
  200. ea += reg.r[ra];
  201. if(upd)
  202. reg.r[ra] = ea;
  203. } else {
  204. if(upd)
  205. undef(ir);
  206. }
  207. if(trace)
  208. itrace("%s\tf%d,%ld(r%d) %lux=%g",
  209. ci->name, rd, imm, ra, ea, reg.fd[rd]);
  210. u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */
  211. putmem_w(ea, u.w);
  212. }
  213. void
  214. stfsx(ulong ir)
  215. {
  216. ulong ea;
  217. int rd, ra, rb, upd;
  218. union {
  219. float f;
  220. ulong w;
  221. } u;
  222. getarrr(ir);
  223. ea = reg.r[rb];
  224. upd = getxo(ir)==695;
  225. if(ra){
  226. ea += reg.r[ra];
  227. if(upd)
  228. reg.r[ra] = ea;
  229. if(trace)
  230. itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]);
  231. } else {
  232. if(upd)
  233. undef(ir);
  234. if(trace)
  235. itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]);
  236. }
  237. u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */
  238. putmem_w(ea, u.w);
  239. }
  240. void
  241. stfd(ulong ir)
  242. {
  243. ulong ea;
  244. int imm, ra, rd, upd;
  245. getairr(ir);
  246. ea = imm;
  247. upd = (ir&(1L<<26))!=0;
  248. if(ra) {
  249. ea += reg.r[ra];
  250. if(upd)
  251. reg.r[ra] = ea;
  252. } else {
  253. if(upd)
  254. undef(ir);
  255. }
  256. if(trace)
  257. itrace("%s\tf%d,%ld(r%d) %lux=%g",
  258. ci->name, rd, imm, ra, ea, reg.fd[rd]);
  259. putmem_v(ea, fp2v(reg.fd[rd]));
  260. }
  261. void
  262. stfdx(ulong ir)
  263. {
  264. ulong ea;
  265. int rd, ra, rb, upd;
  266. getarrr(ir);
  267. ea = reg.r[rb];
  268. upd = ((ir>>1)&0x3FF)==759;
  269. if(ra){
  270. ea += reg.r[ra];
  271. if(upd)
  272. reg.r[ra] = ea;
  273. if(trace)
  274. itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]);
  275. } else {
  276. if(upd)
  277. undef(ir);
  278. if(trace)
  279. itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]);
  280. }
  281. putmem_v(ea, fp2v(reg.fd[rd]));
  282. }
  283. void
  284. mcrfs(ulong ir)
  285. {
  286. ulong rd, ra, rb;
  287. static ulong fpscr0[] ={
  288. FPS_FX|FPS_OX,
  289. FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
  290. FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
  291. FPS_VXVC,
  292. 0,
  293. FPS_VXCVI,
  294. };
  295. getarrr(ir);
  296. if(rb || ra&3 || rd&3)
  297. undef(ir);
  298. ra >>= 2;
  299. rd >>= 2;
  300. reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr));
  301. reg.fpscr &= ~fpscr0[ra];
  302. if(trace)
  303. itrace("mcrfs\tcrf%d,crf%d\n", rd, ra);
  304. }
  305. void
  306. mffs(ulong ir)
  307. {
  308. int rd, ra, rb;
  309. FPdbleword d;
  310. getarrr(ir);
  311. if(ra || rb)
  312. undef(ir);
  313. d.hi = 0xFFF80000UL;
  314. d.lo = reg.fpscr;
  315. reg.fd[rd] = d.x;
  316. /* it's anyone's guess how CR1 should be set when ir&1 */
  317. reg.cr &= ~mkCR(1, 0xE); /* leave SO, reset others */
  318. if(trace)
  319. itrace("mffs%s\tfr%d\n", ir&1?".":"", rd);
  320. }
  321. void
  322. mtfsb1(ulong ir)
  323. {
  324. int rd, ra, rb;
  325. getarrr(ir);
  326. if(ra || rb)
  327. undef(ir);
  328. reg.fpscr |= (1L << (31-rd));
  329. /* BUG: should set summary bits */
  330. if(ir & 1)
  331. reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
  332. if(trace)
  333. itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd);
  334. }
  335. void
  336. mtfsb0(ulong ir)
  337. {
  338. int rd, ra, rb;
  339. getarrr(ir);
  340. if(ra || rb)
  341. undef(ir);
  342. reg.fpscr &= ~(1L << (31-rd));
  343. if(ir & 1)
  344. reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
  345. if(trace)
  346. itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd);
  347. }
  348. void
  349. mtfsf(ulong ir)
  350. {
  351. int fm, rb, i;
  352. FPdbleword d;
  353. ulong v;
  354. if(ir & ((1L << 25)|(1L << 16)))
  355. undef(ir);
  356. rb = (ir >> 11) & 0x1F;
  357. fm = (ir >> 17) & 0xFF;
  358. d.x = reg.fd[rb];
  359. v = d.lo;
  360. for(i=0; i<8; i++)
  361. if(fm & (1 << (7-i)))
  362. reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
  363. /* BUG: should set FEX and VX `according to the usual rule' */
  364. if(ir & 1)
  365. reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
  366. if(trace)
  367. itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb);
  368. }
  369. void
  370. mtfsfi(ulong ir)
  371. {
  372. int imm, rd;
  373. if(ir & ((0x7F << 16)|(1L << 11)))
  374. undef(ir);
  375. rd = (ir >> 23) & 0xF;
  376. imm = (ir >> 12) & 0xF;
  377. reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
  378. /* BUG: should set FEX and VX `according to the usual rule' */
  379. if(ir & 1)
  380. reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
  381. if(trace)
  382. itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm);
  383. }
  384. void
  385. fcmp(ulong ir)
  386. {
  387. int fc, rd, ra, rb;
  388. getarrr(ir);
  389. if(rd & 3)
  390. undef(ir);
  391. rd >>= 2;
  392. SET(fc);
  393. switch(getxo(ir)) {
  394. default:
  395. undef(ir);
  396. case 0:
  397. if(trace)
  398. itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb);
  399. if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {
  400. fc = CRFU;
  401. break;
  402. }
  403. if(reg.fd[ra] == reg.fd[rb]) {
  404. fc = CREQ;
  405. break;
  406. }
  407. if(reg.fd[ra] < reg.fd[rb]) {
  408. fc = CRLT;
  409. break;
  410. }
  411. if(reg.fd[ra] > reg.fd[rb]) {
  412. fc = CRGT;
  413. break;
  414. }
  415. print("qi: fcmp error\n");
  416. break;
  417. case 32:
  418. if(trace)
  419. itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb);
  420. if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { /* BUG: depends whether quiet or signalling ... */
  421. fc = CRFU;
  422. Bprint(bioout, "invalid_fp_register\n");
  423. longjmp(errjmp, 0);
  424. }
  425. if(reg.fd[ra] == reg.fd[rb]) {
  426. fc = CREQ;
  427. break;
  428. }
  429. if(reg.fd[ra] < reg.fd[rb]) {
  430. fc = CRLT;
  431. break;
  432. }
  433. if(reg.fd[ra] > reg.fd[rb]) {
  434. fc = CRGT;
  435. break;
  436. }
  437. print("qi: fcmp error\n");
  438. break;
  439. }
  440. fc >>= 28;
  441. reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
  442. reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11);
  443. /* BUG: update FX, VXSNAN, VXVC */
  444. }
  445. /*
  446. * the farith functions probably don't produce the right results
  447. * in the presence of NaNs, Infs, etc., esp. wrt exception handling,
  448. */
  449. void
  450. fariths(ulong ir)
  451. {
  452. int rd, ra, rb, rc, fmt;
  453. char *cc;
  454. ulong fpscr;
  455. fmt = 0;
  456. rc = (ir>>6)&0x1F;
  457. getarrr(ir);
  458. switch(getxo(ir)&0x1F) { /* partial XO decode */
  459. default:
  460. undef(ir);
  461. case 18:
  462. if((float)reg.fd[rb] == 0.0) {
  463. Bprint(bioout, "fp_exception ZX\n");
  464. reg.fpscr |= FPS_ZX | FPS_FX;
  465. longjmp(errjmp, 0);
  466. }
  467. reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]);
  468. break;
  469. case 20:
  470. reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]);
  471. break;
  472. case 21:
  473. reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]);
  474. break;
  475. case 25:
  476. reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]);
  477. rb = rc;
  478. break;
  479. case 28:
  480. reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
  481. fmt = 2;
  482. break;
  483. case 29:
  484. reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
  485. fmt = 2;
  486. break;
  487. case 30:
  488. reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
  489. fmt = 2;
  490. break;
  491. case 31:
  492. reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
  493. fmt = 2;
  494. break;
  495. }
  496. if(fmt==1 && ra)
  497. undef(ir);
  498. fpscr = setfpscr();
  499. setfpcc(reg.fd[rd]);
  500. cc = "";
  501. if(ir & 1) {
  502. cc = ".";
  503. reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
  504. }
  505. if(trace) {
  506. switch(fmt) {
  507. case 0:
  508. itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
  509. break;
  510. case 1:
  511. itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
  512. break;
  513. case 2:
  514. itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
  515. break;
  516. }
  517. }
  518. }
  519. void
  520. farith(ulong ir)
  521. {
  522. vlong vl;
  523. int rd, ra, rb, rc, fmt;
  524. char *cc;
  525. ulong fpscr;
  526. int nocc;
  527. double d;
  528. fmt = 0;
  529. nocc = 0;
  530. rc = (ir>>6)&0x1F;
  531. getarrr(ir);
  532. switch(getxo(ir)&0x1F) { /* partial XO decode */
  533. default:
  534. undef(ir);
  535. case 12: /* frsp */
  536. reg.fd[rd] = (float)reg.fd[rb];
  537. fmt = 1;
  538. break;
  539. case 14: /* fctiw */ /* BUG: ignores rounding mode */
  540. case 15: /* fctiwz */
  541. d = reg.fd[rb];
  542. if(d >= 0x7fffffff)
  543. vl = 0x7fffffff;
  544. else if(d < 0x80000000)
  545. vl = 0x80000000;
  546. else
  547. vl = d;
  548. reg.fd[rd] = v2fp(vl);
  549. fmt = 1;
  550. nocc = 1;
  551. break;
  552. case 18:
  553. if(reg.fd[rb] == 0.0) {
  554. Bprint(bioout, "fp_exception ZX\n");
  555. reg.fpscr |= FPS_ZX | FPS_FX;
  556. longjmp(errjmp, 0);
  557. }
  558. reg.fd[rd] = reg.fd[ra] / reg.fd[rb];
  559. break;
  560. case 20:
  561. reg.fd[rd] = reg.fd[ra] - reg.fd[rb];
  562. break;
  563. case 21:
  564. reg.fd[rd] = reg.fd[ra] + reg.fd[rb];
  565. break;
  566. case 25:
  567. reg.fd[rd] = reg.fd[ra] * reg.fd[rc];
  568. rb = rc;
  569. break;
  570. case 28:
  571. reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb];
  572. fmt = 2;
  573. break;
  574. case 29:
  575. reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb];
  576. fmt = 2;
  577. break;
  578. case 30:
  579. reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
  580. fmt = 2;
  581. break;
  582. case 31:
  583. reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
  584. fmt = 2;
  585. break;
  586. }
  587. if(fmt==1 && ra)
  588. undef(ir);
  589. fpscr = setfpscr();
  590. if(nocc == 0)
  591. setfpcc(reg.fd[rd]);
  592. cc = "";
  593. if(ir & 1) {
  594. cc = ".";
  595. reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
  596. }
  597. if(trace) {
  598. switch(fmt) {
  599. case 0:
  600. itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
  601. break;
  602. case 1:
  603. itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
  604. break;
  605. case 2:
  606. itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
  607. break;
  608. }
  609. }
  610. }
  611. void
  612. farith2(ulong ir)
  613. {
  614. int rd, ra, rb;
  615. char *cc;
  616. ulong fpscr;
  617. getarrr(ir);
  618. switch(getxo(ir)) { /* full XO decode */
  619. default:
  620. undef(ir);
  621. case 40:
  622. reg.fd[rd] = -reg.fd[rb];
  623. break;
  624. case 72:
  625. reg.fd[rd] = reg.fd[rb];
  626. break;
  627. case 136:
  628. reg.fd[rd] = -fabs(reg.fd[rb]);
  629. break;
  630. case 264:
  631. reg.fd[rd] = fabs(reg.fd[rb]);
  632. break;
  633. }
  634. if(ra)
  635. undef(ir);
  636. fpscr = setfpscr();
  637. setfpcc(reg.fd[rd]);
  638. cc = "";
  639. if(ir & 1) {
  640. cc = ".";
  641. reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
  642. }
  643. if(trace)
  644. itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
  645. }
  646. ulong
  647. setfpscr(void)
  648. {
  649. ulong fps, fpscr;
  650. fps = getfsr();
  651. fpscr = reg.fpscr;
  652. if(fps & FPAOVFL)
  653. fpscr |= FPS_OX;
  654. if(fps & FPAINEX)
  655. fpscr |= FPS_XX;
  656. if(fps & FPAUNFL)
  657. fpscr |= FPS_UX;
  658. if(fps & FPAZDIV)
  659. fpscr |= FPS_ZX;
  660. if(fpscr != reg.fpscr) {
  661. fpscr |= FPS_FX;
  662. reg.fpscr = fpscr;
  663. }
  664. return fpscr;
  665. }
  666. void
  667. setfpcc(double r)
  668. {
  669. int c;
  670. c = 0;
  671. if(r == 0)
  672. c |= 2;
  673. else if(r < 0)
  674. c |= 4;
  675. else
  676. c |= 8;
  677. if(isNaN(r))
  678. c |= 1;
  679. reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
  680. }