PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/arch/m68k/fpsp040/res_func.S

https://bitbucket.org/cresqo/cm7-p500-kernel
Assembly | 2039 lines | 1992 code | 47 blank | 0 comment | 88 complexity | 8f26ed07756beff64862aec3c994aab5 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1. |
  2. | res_func.sa 3.9 7/29/91
  3. |
  4. | Normalizes denormalized numbers if necessary and updates the
  5. | stack frame. The function is then restored back into the
  6. | machine and the 040 completes the operation. This routine
  7. | is only used by the unsupported data type/format handler.
  8. | (Exception vector 55).
  9. |
  10. | For packed move out (fmove.p fpm,<ea>) the operation is
  11. | completed here; data is packed and moved to user memory.
  12. | The stack is restored to the 040 only in the case of a
  13. | reportable exception in the conversion.
  14. |
  15. |
  16. | Copyright (C) Motorola, Inc. 1990
  17. | All Rights Reserved
  18. |
  19. | For details on the license for this file, please see the
  20. | file, README, in this same directory.
  21. RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package
  22. |section 8
  23. #include "fpsp.h"
  24. sp_bnds: .short 0x3f81,0x407e
  25. .short 0x3f6a,0x0000
  26. dp_bnds: .short 0x3c01,0x43fe
  27. .short 0x3bcd,0x0000
  28. |xref mem_write
  29. |xref bindec
  30. |xref get_fline
  31. |xref round
  32. |xref denorm
  33. |xref dest_ext
  34. |xref dest_dbl
  35. |xref dest_sgl
  36. |xref unf_sub
  37. |xref nrm_set
  38. |xref dnrm_lp
  39. |xref ovf_res
  40. |xref reg_dest
  41. |xref t_ovfl
  42. |xref t_unfl
  43. .global res_func
  44. .global p_move
  45. res_func:
  46. clrb DNRM_FLG(%a6)
  47. clrb RES_FLG(%a6)
  48. clrb CU_ONLY(%a6)
  49. tstb DY_MO_FLG(%a6)
  50. beqs monadic
  51. dyadic:
  52. btstb #7,DTAG(%a6) |if dop = norm=000, zero=001,
  53. | ;inf=010 or nan=011
  54. beqs monadic |then branch
  55. | ;else denorm
  56. | HANDLE DESTINATION DENORM HERE
  57. | ;set dtag to norm
  58. | ;write the tag & fpte15 to the fstack
  59. leal FPTEMP(%a6),%a0
  60. bclrb #sign_bit,LOCAL_EX(%a0)
  61. sne LOCAL_SGN(%a0)
  62. bsr nrm_set |normalize number (exp will go negative)
  63. bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
  64. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  65. beqs dpos
  66. bsetb #sign_bit,LOCAL_EX(%a0)
  67. dpos:
  68. bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
  69. bsetb #4,DTAG(%a6) |set FPTE15
  70. orb #0x0f,DNRM_FLG(%a6)
  71. monadic:
  72. leal ETEMP(%a6),%a0
  73. btstb #direction_bit,CMDREG1B(%a6) |check direction
  74. bne opclass3 |it is a mv out
  75. |
  76. | At this point, only opclass 0 and 2 possible
  77. |
  78. btstb #7,STAG(%a6) |if sop = norm=000, zero=001,
  79. | ;inf=010 or nan=011
  80. bne mon_dnrm |else denorm
  81. tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
  82. bne normal |require normalization of denorm
  83. | At this point:
  84. | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
  85. | fmove = $00 fsmove = $40 fdmove = $44
  86. | fsqrt = $05* fssqrt = $41 fdsqrt = $45
  87. | (*fsqrt reencoded to $05)
  88. |
  89. movew CMDREG1B(%a6),%d0 |get command register
  90. andil #0x7f,%d0 |strip to only command word
  91. |
  92. | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
  93. | fdsqrt are possible.
  94. | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
  95. | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
  96. |
  97. btstl #0,%d0
  98. bne normal |weed out fsqrt instructions
  99. |
  100. | cu_norm handles fmove in instructions with normalized inputs.
  101. | The routine round is used to correctly round the input for the
  102. | destination precision and mode.
  103. |
  104. cu_norm:
  105. st CU_ONLY(%a6) |set cu-only inst flag
  106. movew CMDREG1B(%a6),%d0
  107. andib #0x3b,%d0 |isolate bits to select inst
  108. tstb %d0
  109. beql cu_nmove |if zero, it is an fmove
  110. cmpib #0x18,%d0
  111. beql cu_nabs |if $18, it is fabs
  112. cmpib #0x1a,%d0
  113. beql cu_nneg |if $1a, it is fneg
  114. |
  115. | Inst is ftst. Check the source operand and set the cc's accordingly.
  116. | No write is done, so simply rts.
  117. |
  118. cu_ntst:
  119. movew LOCAL_EX(%a0),%d0
  120. bclrl #15,%d0
  121. sne LOCAL_SGN(%a0)
  122. beqs cu_ntpo
  123. orl #neg_mask,USER_FPSR(%a6) |set N
  124. cu_ntpo:
  125. cmpiw #0x7fff,%d0 |test for inf/nan
  126. bnes cu_ntcz
  127. tstl LOCAL_HI(%a0)
  128. bnes cu_ntn
  129. tstl LOCAL_LO(%a0)
  130. bnes cu_ntn
  131. orl #inf_mask,USER_FPSR(%a6)
  132. rts
  133. cu_ntn:
  134. orl #nan_mask,USER_FPSR(%a6)
  135. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  136. | ;snan handler
  137. rts
  138. cu_ntcz:
  139. tstl LOCAL_HI(%a0)
  140. bnel cu_ntsx
  141. tstl LOCAL_LO(%a0)
  142. bnel cu_ntsx
  143. orl #z_mask,USER_FPSR(%a6)
  144. cu_ntsx:
  145. rts
  146. |
  147. | Inst is fabs. Execute the absolute value function on the input.
  148. | Branch to the fmove code. If the operand is NaN, do nothing.
  149. |
  150. cu_nabs:
  151. moveb STAG(%a6),%d0
  152. btstl #5,%d0 |test for NaN or zero
  153. bne wr_etemp |if either, simply write it
  154. bclrb #7,LOCAL_EX(%a0) |do abs
  155. bras cu_nmove |fmove code will finish
  156. |
  157. | Inst is fneg. Execute the negate value function on the input.
  158. | Fall though to the fmove code. If the operand is NaN, do nothing.
  159. |
  160. cu_nneg:
  161. moveb STAG(%a6),%d0
  162. btstl #5,%d0 |test for NaN or zero
  163. bne wr_etemp |if either, simply write it
  164. bchgb #7,LOCAL_EX(%a0) |do neg
  165. |
  166. | Inst is fmove. This code also handles all result writes.
  167. | If bit 2 is set, round is forced to double. If it is clear,
  168. | and bit 6 is set, round is forced to single. If both are clear,
  169. | the round precision is found in the fpcr. If the rounding precision
  170. | is double or single, round the result before the write.
  171. |
  172. cu_nmove:
  173. moveb STAG(%a6),%d0
  174. andib #0xe0,%d0 |isolate stag bits
  175. bne wr_etemp |if not norm, simply write it
  176. btstb #2,CMDREG1B+1(%a6) |check for rd
  177. bne cu_nmrd
  178. btstb #6,CMDREG1B+1(%a6) |check for rs
  179. bne cu_nmrs
  180. |
  181. | The move or operation is not with forced precision. Test for
  182. | nan or inf as the input; if so, simply write it to FPn. Use the
  183. | FPCR_MODE byte to get rounding on norms and zeros.
  184. |
  185. cu_nmnr:
  186. bfextu FPCR_MODE(%a6){#0:#2},%d0
  187. tstb %d0 |check for extended
  188. beq cu_wrexn |if so, just write result
  189. cmpib #1,%d0 |check for single
  190. beq cu_nmrs |fall through to double
  191. |
  192. | The move is fdmove or round precision is double.
  193. |
  194. cu_nmrd:
  195. movel #2,%d0 |set up the size for denorm
  196. movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold
  197. andw #0x7fff,%d1
  198. cmpw #0x3c01,%d1
  199. bls cu_nunfl
  200. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  201. orl #0x00020000,%d1 |or in rprec (double)
  202. clrl %d0 |clear g,r,s for round
  203. bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format
  204. sne LOCAL_SGN(%a0)
  205. bsrl round
  206. bfclr LOCAL_SGN(%a0){#0:#8}
  207. beqs cu_nmrdc
  208. bsetb #sign_bit,LOCAL_EX(%a0)
  209. cu_nmrdc:
  210. movew LOCAL_EX(%a0),%d1 |check for overflow
  211. andw #0x7fff,%d1
  212. cmpw #0x43ff,%d1
  213. bge cu_novfl |take care of overflow case
  214. bra cu_wrexn
  215. |
  216. | The move is fsmove or round precision is single.
  217. |
  218. cu_nmrs:
  219. movel #1,%d0
  220. movew LOCAL_EX(%a0),%d1
  221. andw #0x7fff,%d1
  222. cmpw #0x3f81,%d1
  223. bls cu_nunfl
  224. bfextu FPCR_MODE(%a6){#2:#2},%d1
  225. orl #0x00010000,%d1
  226. clrl %d0
  227. bclrb #sign_bit,LOCAL_EX(%a0)
  228. sne LOCAL_SGN(%a0)
  229. bsrl round
  230. bfclr LOCAL_SGN(%a0){#0:#8}
  231. beqs cu_nmrsc
  232. bsetb #sign_bit,LOCAL_EX(%a0)
  233. cu_nmrsc:
  234. movew LOCAL_EX(%a0),%d1
  235. andw #0x7FFF,%d1
  236. cmpw #0x407f,%d1
  237. blt cu_wrexn
  238. |
  239. | The operand is above precision boundaries. Use t_ovfl to
  240. | generate the correct value.
  241. |
  242. cu_novfl:
  243. bsr t_ovfl
  244. bra cu_wrexn
  245. |
  246. | The operand is below precision boundaries. Use denorm to
  247. | generate the correct value.
  248. |
  249. cu_nunfl:
  250. bclrb #sign_bit,LOCAL_EX(%a0)
  251. sne LOCAL_SGN(%a0)
  252. bsr denorm
  253. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  254. beqs cu_nucont
  255. bsetb #sign_bit,LOCAL_EX(%a0)
  256. cu_nucont:
  257. bfextu FPCR_MODE(%a6){#2:#2},%d1
  258. btstb #2,CMDREG1B+1(%a6) |check for rd
  259. bne inst_d
  260. btstb #6,CMDREG1B+1(%a6) |check for rs
  261. bne inst_s
  262. swap %d1
  263. moveb FPCR_MODE(%a6),%d1
  264. lsrb #6,%d1
  265. swap %d1
  266. bra inst_sd
  267. inst_d:
  268. orl #0x00020000,%d1
  269. bra inst_sd
  270. inst_s:
  271. orl #0x00010000,%d1
  272. inst_sd:
  273. bclrb #sign_bit,LOCAL_EX(%a0)
  274. sne LOCAL_SGN(%a0)
  275. bsrl round
  276. bfclr LOCAL_SGN(%a0){#0:#8}
  277. beqs cu_nuflp
  278. bsetb #sign_bit,LOCAL_EX(%a0)
  279. cu_nuflp:
  280. btstb #inex2_bit,FPSR_EXCEPT(%a6)
  281. beqs cu_nuninx
  282. orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
  283. cu_nuninx:
  284. tstl LOCAL_HI(%a0) |test for zero
  285. bnes cu_nunzro
  286. tstl LOCAL_LO(%a0)
  287. bnes cu_nunzro
  288. |
  289. | The mantissa is zero from the denorm loop. Check sign and rmode
  290. | to see if rounding should have occurred which would leave the lsb.
  291. |
  292. movel USER_FPCR(%a6),%d0
  293. andil #0x30,%d0 |isolate rmode
  294. cmpil #0x20,%d0
  295. blts cu_nzro
  296. bnes cu_nrp
  297. cu_nrm:
  298. tstw LOCAL_EX(%a0) |if positive, set lsb
  299. bges cu_nzro
  300. btstb #7,FPCR_MODE(%a6) |check for double
  301. beqs cu_nincs
  302. bras cu_nincd
  303. cu_nrp:
  304. tstw LOCAL_EX(%a0) |if positive, set lsb
  305. blts cu_nzro
  306. btstb #7,FPCR_MODE(%a6) |check for double
  307. beqs cu_nincs
  308. cu_nincd:
  309. orl #0x800,LOCAL_LO(%a0) |inc for double
  310. bra cu_nunzro
  311. cu_nincs:
  312. orl #0x100,LOCAL_HI(%a0) |inc for single
  313. bra cu_nunzro
  314. cu_nzro:
  315. orl #z_mask,USER_FPSR(%a6)
  316. moveb STAG(%a6),%d0
  317. andib #0xe0,%d0
  318. cmpib #0x40,%d0 |check if input was tagged zero
  319. beqs cu_numv
  320. cu_nunzro:
  321. orl #unfl_mask,USER_FPSR(%a6) |set unfl
  322. cu_numv:
  323. movel (%a0),ETEMP(%a6)
  324. movel 4(%a0),ETEMP_HI(%a6)
  325. movel 8(%a0),ETEMP_LO(%a6)
  326. |
  327. | Write the result to memory, setting the fpsr cc bits. NaN and Inf
  328. | bypass cu_wrexn.
  329. |
  330. cu_wrexn:
  331. tstw LOCAL_EX(%a0) |test for zero
  332. beqs cu_wrzero
  333. cmpw #0x8000,LOCAL_EX(%a0) |test for zero
  334. bnes cu_wreon
  335. cu_wrzero:
  336. orl #z_mask,USER_FPSR(%a6) |set Z bit
  337. cu_wreon:
  338. tstw LOCAL_EX(%a0)
  339. bpl wr_etemp
  340. orl #neg_mask,USER_FPSR(%a6)
  341. bra wr_etemp
  342. |
  343. | HANDLE SOURCE DENORM HERE
  344. |
  345. | ;clear denorm stag to norm
  346. | ;write the new tag & ete15 to the fstack
  347. mon_dnrm:
  348. |
  349. | At this point, check for the cases in which normalizing the
  350. | denorm produces incorrect results.
  351. |
  352. tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
  353. bnes nrm_src |require normalization of denorm
  354. | At this point:
  355. | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
  356. | fmove = $00 fsmove = $40 fdmove = $44
  357. | fsqrt = $05* fssqrt = $41 fdsqrt = $45
  358. | (*fsqrt reencoded to $05)
  359. |
  360. movew CMDREG1B(%a6),%d0 |get command register
  361. andil #0x7f,%d0 |strip to only command word
  362. |
  363. | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
  364. | fdsqrt are possible.
  365. | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
  366. | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
  367. |
  368. btstl #0,%d0
  369. bnes nrm_src |weed out fsqrt instructions
  370. st CU_ONLY(%a6) |set cu-only inst flag
  371. bra cu_dnrm |fmove, fabs, fneg, ftst
  372. | ;cases go to cu_dnrm
  373. nrm_src:
  374. bclrb #sign_bit,LOCAL_EX(%a0)
  375. sne LOCAL_SGN(%a0)
  376. bsr nrm_set |normalize number (exponent will go
  377. | ; negative)
  378. bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
  379. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  380. beqs spos
  381. bsetb #sign_bit,LOCAL_EX(%a0)
  382. spos:
  383. bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
  384. bsetb #4,STAG(%a6) |set ETE15
  385. orb #0xf0,DNRM_FLG(%a6)
  386. normal:
  387. tstb DNRM_FLG(%a6) |check if any of the ops were denorms
  388. bne ck_wrap |if so, check if it is a potential
  389. | ;wrap-around case
  390. fix_stk:
  391. moveb #0xfe,CU_SAVEPC(%a6)
  392. bclrb #E1,E_BYTE(%a6)
  393. clrw NMNEXC(%a6)
  394. st RES_FLG(%a6) |indicate that a restore is needed
  395. rts
  396. |
  397. | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
  398. | ftst) completely in software without an frestore to the 040.
  399. |
  400. cu_dnrm:
  401. st CU_ONLY(%a6)
  402. movew CMDREG1B(%a6),%d0
  403. andib #0x3b,%d0 |isolate bits to select inst
  404. tstb %d0
  405. beql cu_dmove |if zero, it is an fmove
  406. cmpib #0x18,%d0
  407. beql cu_dabs |if $18, it is fabs
  408. cmpib #0x1a,%d0
  409. beql cu_dneg |if $1a, it is fneg
  410. |
  411. | Inst is ftst. Check the source operand and set the cc's accordingly.
  412. | No write is done, so simply rts.
  413. |
  414. cu_dtst:
  415. movew LOCAL_EX(%a0),%d0
  416. bclrl #15,%d0
  417. sne LOCAL_SGN(%a0)
  418. beqs cu_dtpo
  419. orl #neg_mask,USER_FPSR(%a6) |set N
  420. cu_dtpo:
  421. cmpiw #0x7fff,%d0 |test for inf/nan
  422. bnes cu_dtcz
  423. tstl LOCAL_HI(%a0)
  424. bnes cu_dtn
  425. tstl LOCAL_LO(%a0)
  426. bnes cu_dtn
  427. orl #inf_mask,USER_FPSR(%a6)
  428. rts
  429. cu_dtn:
  430. orl #nan_mask,USER_FPSR(%a6)
  431. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  432. | ;snan handler
  433. rts
  434. cu_dtcz:
  435. tstl LOCAL_HI(%a0)
  436. bnel cu_dtsx
  437. tstl LOCAL_LO(%a0)
  438. bnel cu_dtsx
  439. orl #z_mask,USER_FPSR(%a6)
  440. cu_dtsx:
  441. rts
  442. |
  443. | Inst is fabs. Execute the absolute value function on the input.
  444. | Branch to the fmove code.
  445. |
  446. cu_dabs:
  447. bclrb #7,LOCAL_EX(%a0) |do abs
  448. bras cu_dmove |fmove code will finish
  449. |
  450. | Inst is fneg. Execute the negate value function on the input.
  451. | Fall though to the fmove code.
  452. |
  453. cu_dneg:
  454. bchgb #7,LOCAL_EX(%a0) |do neg
  455. |
  456. | Inst is fmove. This code also handles all result writes.
  457. | If bit 2 is set, round is forced to double. If it is clear,
  458. | and bit 6 is set, round is forced to single. If both are clear,
  459. | the round precision is found in the fpcr. If the rounding precision
  460. | is double or single, the result is zero, and the mode is checked
  461. | to determine if the lsb of the result should be set.
  462. |
  463. cu_dmove:
  464. btstb #2,CMDREG1B+1(%a6) |check for rd
  465. bne cu_dmrd
  466. btstb #6,CMDREG1B+1(%a6) |check for rs
  467. bne cu_dmrs
  468. |
  469. | The move or operation is not with forced precision. Use the
  470. | FPCR_MODE byte to get rounding.
  471. |
  472. cu_dmnr:
  473. bfextu FPCR_MODE(%a6){#0:#2},%d0
  474. tstb %d0 |check for extended
  475. beq cu_wrexd |if so, just write result
  476. cmpib #1,%d0 |check for single
  477. beq cu_dmrs |fall through to double
  478. |
  479. | The move is fdmove or round precision is double. Result is zero.
  480. | Check rmode for rp or rm and set lsb accordingly.
  481. |
  482. cu_dmrd:
  483. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  484. tstw LOCAL_EX(%a0) |check sign
  485. blts cu_dmdn
  486. cmpib #3,%d1 |check for rp
  487. bne cu_dpd |load double pos zero
  488. bra cu_dpdr |load double pos zero w/lsb
  489. cu_dmdn:
  490. cmpib #2,%d1 |check for rm
  491. bne cu_dnd |load double neg zero
  492. bra cu_dndr |load double neg zero w/lsb
  493. |
  494. | The move is fsmove or round precision is single. Result is zero.
  495. | Check for rp or rm and set lsb accordingly.
  496. |
  497. cu_dmrs:
  498. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  499. tstw LOCAL_EX(%a0) |check sign
  500. blts cu_dmsn
  501. cmpib #3,%d1 |check for rp
  502. bne cu_spd |load single pos zero
  503. bra cu_spdr |load single pos zero w/lsb
  504. cu_dmsn:
  505. cmpib #2,%d1 |check for rm
  506. bne cu_snd |load single neg zero
  507. bra cu_sndr |load single neg zero w/lsb
  508. |
  509. | The precision is extended, so the result in etemp is correct.
  510. | Simply set unfl (not inex2 or aunfl) and write the result to
  511. | the correct fp register.
  512. cu_wrexd:
  513. orl #unfl_mask,USER_FPSR(%a6)
  514. tstw LOCAL_EX(%a0)
  515. beq wr_etemp
  516. orl #neg_mask,USER_FPSR(%a6)
  517. bra wr_etemp
  518. |
  519. | These routines write +/- zero in double format. The routines
  520. | cu_dpdr and cu_dndr set the double lsb.
  521. |
  522. cu_dpd:
  523. movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
  524. clrl LOCAL_HI(%a0)
  525. clrl LOCAL_LO(%a0)
  526. orl #z_mask,USER_FPSR(%a6)
  527. orl #unfinx_mask,USER_FPSR(%a6)
  528. bra wr_etemp
  529. cu_dpdr:
  530. movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
  531. clrl LOCAL_HI(%a0)
  532. movel #0x800,LOCAL_LO(%a0) |with lsb set
  533. orl #unfinx_mask,USER_FPSR(%a6)
  534. bra wr_etemp
  535. cu_dnd:
  536. movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
  537. clrl LOCAL_HI(%a0)
  538. clrl LOCAL_LO(%a0)
  539. orl #z_mask,USER_FPSR(%a6)
  540. orl #neg_mask,USER_FPSR(%a6)
  541. orl #unfinx_mask,USER_FPSR(%a6)
  542. bra wr_etemp
  543. cu_dndr:
  544. movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
  545. clrl LOCAL_HI(%a0)
  546. movel #0x800,LOCAL_LO(%a0) |with lsb set
  547. orl #neg_mask,USER_FPSR(%a6)
  548. orl #unfinx_mask,USER_FPSR(%a6)
  549. bra wr_etemp
  550. |
  551. | These routines write +/- zero in single format. The routines
  552. | cu_dpdr and cu_dndr set the single lsb.
  553. |
  554. cu_spd:
  555. movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
  556. clrl LOCAL_HI(%a0)
  557. clrl LOCAL_LO(%a0)
  558. orl #z_mask,USER_FPSR(%a6)
  559. orl #unfinx_mask,USER_FPSR(%a6)
  560. bra wr_etemp
  561. cu_spdr:
  562. movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
  563. movel #0x100,LOCAL_HI(%a0) |with lsb set
  564. clrl LOCAL_LO(%a0)
  565. orl #unfinx_mask,USER_FPSR(%a6)
  566. bra wr_etemp
  567. cu_snd:
  568. movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
  569. clrl LOCAL_HI(%a0)
  570. clrl LOCAL_LO(%a0)
  571. orl #z_mask,USER_FPSR(%a6)
  572. orl #neg_mask,USER_FPSR(%a6)
  573. orl #unfinx_mask,USER_FPSR(%a6)
  574. bra wr_etemp
  575. cu_sndr:
  576. movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
  577. movel #0x100,LOCAL_HI(%a0) |with lsb set
  578. clrl LOCAL_LO(%a0)
  579. orl #neg_mask,USER_FPSR(%a6)
  580. orl #unfinx_mask,USER_FPSR(%a6)
  581. bra wr_etemp
  582. |
  583. | This code checks for 16-bit overflow conditions on dyadic
  584. | operations which are not restorable into the floating-point
  585. | unit and must be completed in software. Basically, this
  586. | condition exists with a very large norm and a denorm. One
  587. | of the operands must be denormalized to enter this code.
  588. |
  589. | Flags used:
  590. | DY_MO_FLG contains 0 for monadic op, $ff for dyadic
  591. | DNRM_FLG contains $00 for neither op denormalized
  592. | $0f for the destination op denormalized
  593. | $f0 for the source op denormalized
  594. | $ff for both ops denormalized
  595. |
  596. | The wrap-around condition occurs for add, sub, div, and cmp
  597. | when
  598. |
  599. | abs(dest_exp - src_exp) >= $8000
  600. |
  601. | and for mul when
  602. |
  603. | (dest_exp + src_exp) < $0
  604. |
  605. | we must process the operation here if this case is true.
  606. |
  607. | The rts following the frcfpn routine is the exit from res_func
  608. | for this condition. The restore flag (RES_FLG) is left clear.
  609. | No frestore is done unless an exception is to be reported.
  610. |
  611. | For fadd:
  612. | if(sign_of(dest) != sign_of(src))
  613. | replace exponent of src with $3fff (keep sign)
  614. | use fpu to perform dest+new_src (user's rmode and X)
  615. | clr sticky
  616. | else
  617. | set sticky
  618. | call round with user's precision and mode
  619. | move result to fpn and wbtemp
  620. |
  621. | For fsub:
  622. | if(sign_of(dest) == sign_of(src))
  623. | replace exponent of src with $3fff (keep sign)
  624. | use fpu to perform dest+new_src (user's rmode and X)
  625. | clr sticky
  626. | else
  627. | set sticky
  628. | call round with user's precision and mode
  629. | move result to fpn and wbtemp
  630. |
  631. | For fdiv/fsgldiv:
  632. | if(both operands are denorm)
  633. | restore_to_fpu;
  634. | if(dest is norm)
  635. | force_ovf;
  636. | else(dest is denorm)
  637. | force_unf:
  638. |
  639. | For fcmp:
  640. | if(dest is norm)
  641. | N = sign_of(dest);
  642. | else(dest is denorm)
  643. | N = sign_of(src);
  644. |
  645. | For fmul:
  646. | if(both operands are denorm)
  647. | force_unf;
  648. | if((dest_exp + src_exp) < 0)
  649. | force_unf:
  650. | else
  651. | restore_to_fpu;
  652. |
  653. | local equates:
  654. .set addcode,0x22
  655. .set subcode,0x28
  656. .set mulcode,0x23
  657. .set divcode,0x20
  658. .set cmpcode,0x38
  659. ck_wrap:
  660. | tstb DY_MO_FLG(%a6) ;check for fsqrt
  661. beq fix_stk |if zero, it is fsqrt
  662. movew CMDREG1B(%a6),%d0
  663. andiw #0x3b,%d0 |strip to command bits
  664. cmpiw #addcode,%d0
  665. beq wrap_add
  666. cmpiw #subcode,%d0
  667. beq wrap_sub
  668. cmpiw #mulcode,%d0
  669. beq wrap_mul
  670. cmpiw #cmpcode,%d0
  671. beq wrap_cmp
  672. |
  673. | Inst is fdiv.
  674. |
  675. wrap_div:
  676. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  677. beq fix_stk |restore to fpu
  678. |
  679. | One of the ops is denormalized. Test for wrap condition
  680. | and force the result.
  681. |
  682. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  683. bnes div_srcd
  684. div_destd:
  685. bsrl ckinf_ns
  686. bne fix_stk
  687. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  688. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  689. subl %d1,%d0 |subtract dest from src
  690. cmpl #0x7fff,%d0
  691. blt fix_stk |if less, not wrap case
  692. clrb WBTEMP_SGN(%a6)
  693. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  694. movew FPTEMP_EX(%a6),%d1
  695. eorw %d1,%d0
  696. andiw #0x8000,%d0
  697. beq force_unf
  698. st WBTEMP_SGN(%a6)
  699. bra force_unf
  700. ckinf_ns:
  701. moveb STAG(%a6),%d0 |check source tag for inf or nan
  702. bra ck_in_com
  703. ckinf_nd:
  704. moveb DTAG(%a6),%d0 |check destination tag for inf or nan
  705. ck_in_com:
  706. andib #0x60,%d0 |isolate tag bits
  707. cmpb #0x40,%d0 |is it inf?
  708. beq nan_or_inf |not wrap case
  709. cmpb #0x60,%d0 |is it nan?
  710. beq nan_or_inf |yes, not wrap case?
  711. cmpb #0x20,%d0 |is it a zero?
  712. beq nan_or_inf |yes
  713. clrl %d0
  714. rts |then ; it is either a zero of norm,
  715. | ;check wrap case
  716. nan_or_inf:
  717. moveql #-1,%d0
  718. rts
  719. div_srcd:
  720. bsrl ckinf_nd
  721. bne fix_stk
  722. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  723. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  724. subl %d1,%d0 |subtract src from dest
  725. cmpl #0x8000,%d0
  726. blt fix_stk |if less, not wrap case
  727. clrb WBTEMP_SGN(%a6)
  728. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  729. movew FPTEMP_EX(%a6),%d1
  730. eorw %d1,%d0
  731. andiw #0x8000,%d0
  732. beqs force_ovf
  733. st WBTEMP_SGN(%a6)
  734. |
  735. | This code handles the case of the instruction resulting in
  736. | an overflow condition.
  737. |
  738. force_ovf:
  739. bclrb #E1,E_BYTE(%a6)
  740. orl #ovfl_inx_mask,USER_FPSR(%a6)
  741. clrw NMNEXC(%a6)
  742. leal WBTEMP(%a6),%a0 |point a0 to memory location
  743. movew CMDREG1B(%a6),%d0
  744. btstl #6,%d0 |test for forced precision
  745. beqs frcovf_fpcr
  746. btstl #2,%d0 |check for double
  747. bnes frcovf_dbl
  748. movel #0x1,%d0 |inst is forced single
  749. bras frcovf_rnd
  750. frcovf_dbl:
  751. movel #0x2,%d0 |inst is forced double
  752. bras frcovf_rnd
  753. frcovf_fpcr:
  754. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  755. frcovf_rnd:
  756. | The 881/882 does not set inex2 for the following case, so the
  757. | line is commented out to be compatible with 881/882
  758. | tst.b %d0
  759. | beq.b frcovf_x
  760. | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
  761. |frcovf_x:
  762. bsrl ovf_res |get correct result based on
  763. | ;round precision/mode. This
  764. | ;sets FPSR_CC correctly
  765. | ;returns in external format
  766. bfclr WBTEMP_SGN(%a6){#0:#8}
  767. beq frcfpn
  768. bsetb #sign_bit,WBTEMP_EX(%a6)
  769. bra frcfpn
  770. |
  771. | Inst is fadd.
  772. |
  773. wrap_add:
  774. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  775. beq fix_stk |restore to fpu
  776. |
  777. | One of the ops is denormalized. Test for wrap condition
  778. | and complete the instruction.
  779. |
  780. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  781. bnes add_srcd
  782. add_destd:
  783. bsrl ckinf_ns
  784. bne fix_stk
  785. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  786. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  787. subl %d1,%d0 |subtract dest from src
  788. cmpl #0x8000,%d0
  789. blt fix_stk |if less, not wrap case
  790. bra add_wrap
  791. add_srcd:
  792. bsrl ckinf_nd
  793. bne fix_stk
  794. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  795. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  796. subl %d1,%d0 |subtract src from dest
  797. cmpl #0x8000,%d0
  798. blt fix_stk |if less, not wrap case
  799. |
  800. | Check the signs of the operands. If they are unlike, the fpu
  801. | can be used to add the norm and 1.0 with the sign of the
  802. | denorm and it will correctly generate the result in extended
  803. | precision. We can then call round with no sticky and the result
  804. | will be correct for the user's rounding mode and precision. If
  805. | the signs are the same, we call round with the sticky bit set
  806. | and the result will be correct for the user's rounding mode and
  807. | precision.
  808. |
  809. add_wrap:
  810. movew ETEMP_EX(%a6),%d0
  811. movew FPTEMP_EX(%a6),%d1
  812. eorw %d1,%d0
  813. andiw #0x8000,%d0
  814. beq add_same
  815. |
  816. | The signs are unlike.
  817. |
  818. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  819. bnes add_u_srcd
  820. movew FPTEMP_EX(%a6),%d0
  821. andiw #0x8000,%d0
  822. orw #0x3fff,%d0 |force the exponent to +/- 1
  823. movew %d0,FPTEMP_EX(%a6) |in the denorm
  824. movel USER_FPCR(%a6),%d0
  825. andil #0x30,%d0
  826. fmovel %d0,%fpcr |set up users rmode and X
  827. fmovex ETEMP(%a6),%fp0
  828. faddx FPTEMP(%a6),%fp0
  829. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  830. fmovel %fpsr,%d1
  831. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  832. fmovex %fp0,WBTEMP(%a6) |write result to memory
  833. lsrl #4,%d0 |put rmode in lower 2 bits
  834. movel USER_FPCR(%a6),%d1
  835. andil #0xc0,%d1
  836. lsrl #6,%d1 |put precision in upper word
  837. swap %d1
  838. orl %d0,%d1 |set up for round call
  839. clrl %d0 |force sticky to zero
  840. bclrb #sign_bit,WBTEMP_EX(%a6)
  841. sne WBTEMP_SGN(%a6)
  842. bsrl round |round result to users rmode & prec
  843. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  844. beq frcfpnr
  845. bsetb #sign_bit,WBTEMP_EX(%a6)
  846. bra frcfpnr
  847. add_u_srcd:
  848. movew ETEMP_EX(%a6),%d0
  849. andiw #0x8000,%d0
  850. orw #0x3fff,%d0 |force the exponent to +/- 1
  851. movew %d0,ETEMP_EX(%a6) |in the denorm
  852. movel USER_FPCR(%a6),%d0
  853. andil #0x30,%d0
  854. fmovel %d0,%fpcr |set up users rmode and X
  855. fmovex ETEMP(%a6),%fp0
  856. faddx FPTEMP(%a6),%fp0
  857. fmovel %fpsr,%d1
  858. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  859. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  860. fmovex %fp0,WBTEMP(%a6) |write result to memory
  861. lsrl #4,%d0 |put rmode in lower 2 bits
  862. movel USER_FPCR(%a6),%d1
  863. andil #0xc0,%d1
  864. lsrl #6,%d1 |put precision in upper word
  865. swap %d1
  866. orl %d0,%d1 |set up for round call
  867. clrl %d0 |force sticky to zero
  868. bclrb #sign_bit,WBTEMP_EX(%a6)
  869. sne WBTEMP_SGN(%a6) |use internal format for round
  870. bsrl round |round result to users rmode & prec
  871. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  872. beq frcfpnr
  873. bsetb #sign_bit,WBTEMP_EX(%a6)
  874. bra frcfpnr
  875. |
  876. | Signs are alike:
  877. |
  878. add_same:
  879. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  880. bnes add_s_srcd
  881. add_s_destd:
  882. leal ETEMP(%a6),%a0
  883. movel USER_FPCR(%a6),%d0
  884. andil #0x30,%d0
  885. lsrl #4,%d0 |put rmode in lower 2 bits
  886. movel USER_FPCR(%a6),%d1
  887. andil #0xc0,%d1
  888. lsrl #6,%d1 |put precision in upper word
  889. swap %d1
  890. orl %d0,%d1 |set up for round call
  891. movel #0x20000000,%d0 |set sticky for round
  892. bclrb #sign_bit,ETEMP_EX(%a6)
  893. sne ETEMP_SGN(%a6)
  894. bsrl round |round result to users rmode & prec
  895. bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  896. beqs add_s_dclr
  897. bsetb #sign_bit,ETEMP_EX(%a6)
  898. add_s_dclr:
  899. leal WBTEMP(%a6),%a0
  900. movel ETEMP(%a6),(%a0) |write result to wbtemp
  901. movel ETEMP_HI(%a6),4(%a0)
  902. movel ETEMP_LO(%a6),8(%a0)
  903. tstw ETEMP_EX(%a6)
  904. bgt add_ckovf
  905. orl #neg_mask,USER_FPSR(%a6)
  906. bra add_ckovf
  907. add_s_srcd:
  908. leal FPTEMP(%a6),%a0
  909. movel USER_FPCR(%a6),%d0
  910. andil #0x30,%d0
  911. lsrl #4,%d0 |put rmode in lower 2 bits
  912. movel USER_FPCR(%a6),%d1
  913. andil #0xc0,%d1
  914. lsrl #6,%d1 |put precision in upper word
  915. swap %d1
  916. orl %d0,%d1 |set up for round call
  917. movel #0x20000000,%d0 |set sticky for round
  918. bclrb #sign_bit,FPTEMP_EX(%a6)
  919. sne FPTEMP_SGN(%a6)
  920. bsrl round |round result to users rmode & prec
  921. bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  922. beqs add_s_sclr
  923. bsetb #sign_bit,FPTEMP_EX(%a6)
  924. add_s_sclr:
  925. leal WBTEMP(%a6),%a0
  926. movel FPTEMP(%a6),(%a0) |write result to wbtemp
  927. movel FPTEMP_HI(%a6),4(%a0)
  928. movel FPTEMP_LO(%a6),8(%a0)
  929. tstw FPTEMP_EX(%a6)
  930. bgt add_ckovf
  931. orl #neg_mask,USER_FPSR(%a6)
  932. add_ckovf:
  933. movew WBTEMP_EX(%a6),%d0
  934. andiw #0x7fff,%d0
  935. cmpiw #0x7fff,%d0
  936. bne frcfpnr
  937. |
  938. | The result has overflowed to $7fff exponent. Set I, ovfl,
  939. | and aovfl, and clr the mantissa (incorrectly set by the
  940. | round routine.)
  941. |
  942. orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
  943. clrl 4(%a0)
  944. bra frcfpnr
  945. |
  946. | Inst is fsub.
  947. |
  948. wrap_sub:
  949. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  950. beq fix_stk |restore to fpu
  951. |
  952. | One of the ops is denormalized. Test for wrap condition
  953. | and complete the instruction.
  954. |
  955. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  956. bnes sub_srcd
  957. sub_destd:
  958. bsrl ckinf_ns
  959. bne fix_stk
  960. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  961. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  962. subl %d1,%d0 |subtract src from dest
  963. cmpl #0x8000,%d0
  964. blt fix_stk |if less, not wrap case
  965. bra sub_wrap
  966. sub_srcd:
  967. bsrl ckinf_nd
  968. bne fix_stk
  969. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  970. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  971. subl %d1,%d0 |subtract dest from src
  972. cmpl #0x8000,%d0
  973. blt fix_stk |if less, not wrap case
  974. |
  975. | Check the signs of the operands. If they are alike, the fpu
  976. | can be used to subtract from the norm 1.0 with the sign of the
  977. | denorm and it will correctly generate the result in extended
  978. | precision. We can then call round with no sticky and the result
  979. | will be correct for the user's rounding mode and precision. If
  980. | the signs are unlike, we call round with the sticky bit set
  981. | and the result will be correct for the user's rounding mode and
  982. | precision.
  983. |
  984. sub_wrap:
  985. movew ETEMP_EX(%a6),%d0
  986. movew FPTEMP_EX(%a6),%d1
  987. eorw %d1,%d0
  988. andiw #0x8000,%d0
  989. bne sub_diff
  990. |
  991. | The signs are alike.
  992. |
  993. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  994. bnes sub_u_srcd
  995. movew FPTEMP_EX(%a6),%d0
  996. andiw #0x8000,%d0
  997. orw #0x3fff,%d0 |force the exponent to +/- 1
  998. movew %d0,FPTEMP_EX(%a6) |in the denorm
  999. movel USER_FPCR(%a6),%d0
  1000. andil #0x30,%d0
  1001. fmovel %d0,%fpcr |set up users rmode and X
  1002. fmovex FPTEMP(%a6),%fp0
  1003. fsubx ETEMP(%a6),%fp0
  1004. fmovel %fpsr,%d1
  1005. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  1006. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  1007. fmovex %fp0,WBTEMP(%a6) |write result to memory
  1008. lsrl #4,%d0 |put rmode in lower 2 bits
  1009. movel USER_FPCR(%a6),%d1
  1010. andil #0xc0,%d1
  1011. lsrl #6,%d1 |put precision in upper word
  1012. swap %d1
  1013. orl %d0,%d1 |set up for round call
  1014. clrl %d0 |force sticky to zero
  1015. bclrb #sign_bit,WBTEMP_EX(%a6)
  1016. sne WBTEMP_SGN(%a6)
  1017. bsrl round |round result to users rmode & prec
  1018. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1019. beq frcfpnr
  1020. bsetb #sign_bit,WBTEMP_EX(%a6)
  1021. bra frcfpnr
  1022. sub_u_srcd:
  1023. movew ETEMP_EX(%a6),%d0
  1024. andiw #0x8000,%d0
  1025. orw #0x3fff,%d0 |force the exponent to +/- 1
  1026. movew %d0,ETEMP_EX(%a6) |in the denorm
  1027. movel USER_FPCR(%a6),%d0
  1028. andil #0x30,%d0
  1029. fmovel %d0,%fpcr |set up users rmode and X
  1030. fmovex FPTEMP(%a6),%fp0
  1031. fsubx ETEMP(%a6),%fp0
  1032. fmovel %fpsr,%d1
  1033. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  1034. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  1035. fmovex %fp0,WBTEMP(%a6) |write result to memory
  1036. lsrl #4,%d0 |put rmode in lower 2 bits
  1037. movel USER_FPCR(%a6),%d1
  1038. andil #0xc0,%d1
  1039. lsrl #6,%d1 |put precision in upper word
  1040. swap %d1
  1041. orl %d0,%d1 |set up for round call
  1042. clrl %d0 |force sticky to zero
  1043. bclrb #sign_bit,WBTEMP_EX(%a6)
  1044. sne WBTEMP_SGN(%a6)
  1045. bsrl round |round result to users rmode & prec
  1046. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1047. beq frcfpnr
  1048. bsetb #sign_bit,WBTEMP_EX(%a6)
  1049. bra frcfpnr
  1050. |
  1051. | Signs are unlike:
  1052. |
  1053. sub_diff:
  1054. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  1055. bnes sub_s_srcd
  1056. sub_s_destd:
  1057. leal ETEMP(%a6),%a0
  1058. movel USER_FPCR(%a6),%d0
  1059. andil #0x30,%d0
  1060. lsrl #4,%d0 |put rmode in lower 2 bits
  1061. movel USER_FPCR(%a6),%d1
  1062. andil #0xc0,%d1
  1063. lsrl #6,%d1 |put precision in upper word
  1064. swap %d1
  1065. orl %d0,%d1 |set up for round call
  1066. movel #0x20000000,%d0 |set sticky for round
  1067. |
  1068. | Since the dest is the denorm, the sign is the opposite of the
  1069. | norm sign.
  1070. |
  1071. eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result
  1072. tstw ETEMP_EX(%a6)
  1073. bgts sub_s_dwr
  1074. orl #neg_mask,USER_FPSR(%a6)
  1075. sub_s_dwr:
  1076. bclrb #sign_bit,ETEMP_EX(%a6)
  1077. sne ETEMP_SGN(%a6)
  1078. bsrl round |round result to users rmode & prec
  1079. bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1080. beqs sub_s_dclr
  1081. bsetb #sign_bit,ETEMP_EX(%a6)
  1082. sub_s_dclr:
  1083. leal WBTEMP(%a6),%a0
  1084. movel ETEMP(%a6),(%a0) |write result to wbtemp
  1085. movel ETEMP_HI(%a6),4(%a0)
  1086. movel ETEMP_LO(%a6),8(%a0)
  1087. bra sub_ckovf
  1088. sub_s_srcd:
  1089. leal FPTEMP(%a6),%a0
  1090. movel USER_FPCR(%a6),%d0
  1091. andil #0x30,%d0
  1092. lsrl #4,%d0 |put rmode in lower 2 bits
  1093. movel USER_FPCR(%a6),%d1
  1094. andil #0xc0,%d1
  1095. lsrl #6,%d1 |put precision in upper word
  1096. swap %d1
  1097. orl %d0,%d1 |set up for round call
  1098. movel #0x20000000,%d0 |set sticky for round
  1099. bclrb #sign_bit,FPTEMP_EX(%a6)
  1100. sne FPTEMP_SGN(%a6)
  1101. bsrl round |round result to users rmode & prec
  1102. bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1103. beqs sub_s_sclr
  1104. bsetb #sign_bit,FPTEMP_EX(%a6)
  1105. sub_s_sclr:
  1106. leal WBTEMP(%a6),%a0
  1107. movel FPTEMP(%a6),(%a0) |write result to wbtemp
  1108. movel FPTEMP_HI(%a6),4(%a0)
  1109. movel FPTEMP_LO(%a6),8(%a0)
  1110. tstw FPTEMP_EX(%a6)
  1111. bgt sub_ckovf
  1112. orl #neg_mask,USER_FPSR(%a6)
  1113. sub_ckovf:
  1114. movew WBTEMP_EX(%a6),%d0
  1115. andiw #0x7fff,%d0
  1116. cmpiw #0x7fff,%d0
  1117. bne frcfpnr
  1118. |
  1119. | The result has overflowed to $7fff exponent. Set I, ovfl,
  1120. | and aovfl, and clr the mantissa (incorrectly set by the
  1121. | round routine.)
  1122. |
  1123. orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
  1124. clrl 4(%a0)
  1125. bra frcfpnr
  1126. |
  1127. | Inst is fcmp.
  1128. |
  1129. wrap_cmp:
  1130. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  1131. beq fix_stk |restore to fpu
  1132. |
  1133. | One of the ops is denormalized. Test for wrap condition
  1134. | and complete the instruction.
  1135. |
  1136. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  1137. bnes cmp_srcd
  1138. cmp_destd:
  1139. bsrl ckinf_ns
  1140. bne fix_stk
  1141. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  1142. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  1143. subl %d1,%d0 |subtract dest from src
  1144. cmpl #0x8000,%d0
  1145. blt fix_stk |if less, not wrap case
  1146. tstw ETEMP_EX(%a6) |set N to ~sign_of(src)
  1147. bge cmp_setn
  1148. rts
  1149. cmp_srcd:
  1150. bsrl ckinf_nd
  1151. bne fix_stk
  1152. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  1153. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  1154. subl %d1,%d0 |subtract src from dest
  1155. cmpl #0x8000,%d0
  1156. blt fix_stk |if less, not wrap case
  1157. tstw FPTEMP_EX(%a6) |set N to sign_of(dest)
  1158. blt cmp_setn
  1159. rts
  1160. cmp_setn:
  1161. orl #neg_mask,USER_FPSR(%a6)
  1162. rts
  1163. |
  1164. | Inst is fmul.
  1165. |
  1166. wrap_mul:
  1167. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  1168. beq force_unf |force an underflow (really!)
  1169. |
  1170. | One of the ops is denormalized. Test for wrap condition
  1171. | and complete the instruction.
  1172. |
  1173. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  1174. bnes mul_srcd
  1175. mul_destd:
  1176. bsrl ckinf_ns
  1177. bne fix_stk
  1178. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  1179. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  1180. addl %d1,%d0 |subtract dest from src
  1181. bgt fix_stk
  1182. bra force_unf
  1183. mul_srcd:
  1184. bsrl ckinf_nd
  1185. bne fix_stk
  1186. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  1187. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  1188. addl %d1,%d0 |subtract src from dest
  1189. bgt fix_stk
  1190. |
  1191. | This code handles the case of the instruction resulting in
  1192. | an underflow condition.
  1193. |
  1194. force_unf:
  1195. bclrb #E1,E_BYTE(%a6)
  1196. orl #unfinx_mask,USER_FPSR(%a6)
  1197. clrw NMNEXC(%a6)
  1198. clrb WBTEMP_SGN(%a6)
  1199. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  1200. movew FPTEMP_EX(%a6),%d1
  1201. eorw %d1,%d0
  1202. andiw #0x8000,%d0
  1203. beqs frcunfcont
  1204. st WBTEMP_SGN(%a6)
  1205. frcunfcont:
  1206. lea WBTEMP(%a6),%a0 |point a0 to memory location
  1207. movew CMDREG1B(%a6),%d0
  1208. btstl #6,%d0 |test for forced precision
  1209. beqs frcunf_fpcr
  1210. btstl #2,%d0 |check for double
  1211. bnes frcunf_dbl
  1212. movel #0x1,%d0 |inst is forced single
  1213. bras frcunf_rnd
  1214. frcunf_dbl:
  1215. movel #0x2,%d0 |inst is forced double
  1216. bras frcunf_rnd
  1217. frcunf_fpcr:
  1218. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  1219. frcunf_rnd:
  1220. bsrl unf_sub |get correct result based on
  1221. | ;round precision/mode. This
  1222. | ;sets FPSR_CC correctly
  1223. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1224. beqs frcfpn
  1225. bsetb #sign_bit,WBTEMP_EX(%a6)
  1226. bra frcfpn
  1227. |
  1228. | Write the result to the user's fpn. All results must be HUGE to be
  1229. | written; otherwise the results would have overflowed or underflowed.
  1230. | If the rounding precision is single or double, the ovf_res routine
  1231. | is needed to correctly supply the max value.
  1232. |
  1233. frcfpnr:
  1234. movew CMDREG1B(%a6),%d0
  1235. btstl #6,%d0 |test for forced precision
  1236. beqs frcfpn_fpcr
  1237. btstl #2,%d0 |check for double
  1238. bnes frcfpn_dbl
  1239. movel #0x1,%d0 |inst is forced single
  1240. bras frcfpn_rnd
  1241. frcfpn_dbl:
  1242. movel #0x2,%d0 |inst is forced double
  1243. bras frcfpn_rnd
  1244. frcfpn_fpcr:
  1245. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  1246. tstb %d0
  1247. beqs frcfpn |if extended, write what you got
  1248. frcfpn_rnd:
  1249. bclrb #sign_bit,WBTEMP_EX(%a6)
  1250. sne WBTEMP_SGN(%a6)
  1251. bsrl ovf_res |get correct result based on
  1252. | ;round precision/mode. This
  1253. | ;sets FPSR_CC correctly
  1254. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1255. beqs frcfpn_clr
  1256. bsetb #sign_bit,WBTEMP_EX(%a6)
  1257. frcfpn_clr:
  1258. orl #ovfinx_mask,USER_FPSR(%a6)
  1259. |
  1260. | Perform the write.
  1261. |
  1262. frcfpn:
  1263. bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
  1264. cmpib #3,%d0
  1265. bles frc0123 |check if dest is fp0-fp3
  1266. movel #7,%d1
  1267. subl %d0,%d1
  1268. clrl %d0
  1269. bsetl %d1,%d0
  1270. fmovemx WBTEMP(%a6),%d0
  1271. rts
  1272. frc0123:
  1273. cmpib #0,%d0
  1274. beqs frc0_dst
  1275. cmpib #1,%d0
  1276. beqs frc1_dst
  1277. cmpib #2,%d0
  1278. beqs frc2_dst
  1279. frc3_dst:
  1280. movel WBTEMP_EX(%a6),USER_FP3(%a6)
  1281. movel WBTEMP_HI(%a6),USER_FP3+4(%a6)
  1282. movel WBTEMP_LO(%a6),USER_FP3+8(%a6)
  1283. rts
  1284. frc2_dst:
  1285. movel WBTEMP_EX(%a6),USER_FP2(%a6)
  1286. movel WBTEMP_HI(%a6),USER_FP2+4(%a6)
  1287. movel WBTEMP_LO(%a6),USER_FP2+8(%a6)
  1288. rts
  1289. frc1_dst:
  1290. movel WBTEMP_EX(%a6),USER_FP1(%a6)
  1291. movel WBTEMP_HI(%a6),USER_FP1+4(%a6)
  1292. movel WBTEMP_LO(%a6),USER_FP1+8(%a6)
  1293. rts
  1294. frc0_dst:
  1295. movel WBTEMP_EX(%a6),USER_FP0(%a6)
  1296. movel WBTEMP_HI(%a6),USER_FP0+4(%a6)
  1297. movel WBTEMP_LO(%a6),USER_FP0+8(%a6)
  1298. rts
  1299. |
  1300. | Write etemp to fpn.
  1301. | A check is made on enabled and signalled snan exceptions,
  1302. | and the destination is not overwritten if this condition exists.
  1303. | This code is designed to make fmoveins of unsupported data types
  1304. | faster.
  1305. |
  1306. wr_etemp:
  1307. btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and
  1308. beqs fmoveinc |enabled, force restore
  1309. btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
  1310. beqs fmoveinc |the dest
  1311. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  1312. | ;snan handler
  1313. tstb ETEMP(%a6) |check for negative
  1314. blts snan_neg
  1315. rts
  1316. snan_neg:
  1317. orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N
  1318. rts
  1319. fmoveinc:
  1320. clrw NMNEXC(%a6)
  1321. bclrb #E1,E_BYTE(%a6)
  1322. moveb STAG(%a6),%d0 |check if stag is inf
  1323. andib #0xe0,%d0
  1324. cmpib #0x40,%d0
  1325. bnes fminc_cnan
  1326. orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
  1327. tstw LOCAL_EX(%a0) |check sign
  1328. bges fminc_con
  1329. orl #neg_mask,USER_FPSR(%a6)
  1330. bra fminc_con
  1331. fminc_cnan:
  1332. cmpib #0x60,%d0 |check if stag is NaN
  1333. bnes fminc_czero
  1334. orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
  1335. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  1336. | ;snan handler
  1337. tstw LOCAL_EX(%a0) |check sign
  1338. bges fminc_con
  1339. orl #neg_mask,USER_FPSR(%a6)
  1340. bra fminc_con
  1341. fminc_czero:
  1342. cmpib #0x20,%d0 |check if zero
  1343. bnes fminc_con
  1344. orl #z_mask,USER_FPSR(%a6) |if zero, set Z
  1345. tstw LOCAL_EX(%a0) |check sign
  1346. bges fminc_con
  1347. orl #neg_mask,USER_FPSR(%a6)
  1348. fminc_con:
  1349. bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
  1350. cmpib #3,%d0
  1351. bles fp0123 |check if dest is fp0-fp3
  1352. movel #7,%d1
  1353. subl %d0,%d1
  1354. clrl %d0
  1355. bsetl %d1,%d0
  1356. fmovemx ETEMP(%a6),%d0
  1357. rts
  1358. fp0123:
  1359. cmpib #0,%d0
  1360. beqs fp0_dst
  1361. cmpib #1,%d0
  1362. beqs fp1_dst
  1363. cmpib #2,%d0
  1364. beqs fp2_dst
  1365. fp3_dst:
  1366. movel ETEMP_EX(%a6),USER_FP3(%a6)
  1367. movel ETEMP_HI(%a6),USER_FP3+4(%a6)
  1368. movel ETEMP_LO(%a6),USER_FP3+8(%a6)
  1369. rts
  1370. fp2_dst:
  1371. movel ETEMP_EX(%a6),USER_FP2(%a6)
  1372. movel ETEMP_HI(%a6),USER_FP2+4(%a6)
  1373. movel ETEMP_LO(%a6),USER_FP2+8(%a6)
  1374. rts
  1375. fp1_dst:
  1376. movel ETEMP_EX(%a6),USER_FP1(%a6)
  1377. movel ETEMP_HI(%a6),USER_FP1+4(%a6)
  1378. movel ETEMP_LO(%a6),USER_FP1+8(%a6)
  1379. rts
  1380. fp0_dst:
  1381. movel ETEMP_EX(%a6),USER_FP0(%a6)
  1382. movel ETEMP_HI(%a6),USER_FP0+4(%a6)
  1383. movel ETEMP_LO(%a6),USER_FP0+8(%a6)
  1384. rts
  1385. opclass3:
  1386. st CU_ONLY(%a6)
  1387. movew CMDREG1B(%a6),%d0 |check if packed moveout
  1388. andiw #0x0c00,%d0 |isolate last 2 bits of size field
  1389. cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed
  1390. beq pack_out |else it is norm or denorm
  1391. bra mv_out
  1392. |
  1393. | MOVE OUT
  1394. |
  1395. mv_tbl:
  1396. .long li
  1397. .long sgp
  1398. .long xp
  1399. .long mvout_end |should never be taken
  1400. .long wi
  1401. .long dp
  1402. .long bi
  1403. .long mvout_end |should never be taken
  1404. mv_out:
  1405. bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1
  1406. leal mv_tbl,%a0
  1407. movel %a0@(%d1:l:4),%a0
  1408. jmp (%a0)
  1409. |
  1410. | This exit is for move-out to memory. The aunfl bit is
  1411. | set if the result is inex and unfl is signalled.
  1412. |
  1413. mvout_end:
  1414. btstb #inex2_bit,FPSR_EXCEPT(%a6)
  1415. beqs no_aufl
  1416. btstb #unfl_bit,FPSR_EXCEPT(%a6)
  1417. beqs no_aufl
  1418. bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
  1419. no_aufl:
  1420. clrw NMNEXC(%a6)
  1421. bclrb #E1,E_BYTE(%a6)
  1422. fmovel #0,%FPSR |clear any cc bits from res_func
  1423. |
  1424. | Return ETEMP to extended format from internal extended format so
  1425. | that gen_except will have a correctly signed value for ovfl/unfl
  1426. | handlers.
  1427. |
  1428. bfclr ETEMP_SGN(%a6){#0:#8}
  1429. beqs mvout_con
  1430. bsetb #sign_bit,ETEMP_EX(%a6)
  1431. mvout_con:
  1432. rts
  1433. |
  1434. | This exit is for move-out to int register. The aunfl bit is
  1435. | not set in any case for this move.
  1436. |
  1437. mvouti_end:
  1438. clrw NMNEXC(%a6)
  1439. bclrb #E1,E_BYTE(%a6)
  1440. fmovel #0,%FPSR |clear any cc bits from res_func
  1441. |
  1442. | Return ETEMP to extended format from internal extended format so
  1443. | that gen_except will have a correctly signed value for ovfl/unfl
  1444. | handlers.
  1445. |
  1446. bfclr ETEMP_SGN(%a6){#0:#8}
  1447. beqs mvouti_con
  1448. bsetb #sign_bit,ETEMP_EX(%a6)
  1449. mvouti_con:
  1450. rts
  1451. |
  1452. | li is used to handle a long integer source specifier
  1453. |
  1454. li:
  1455. moveql #4,%d0 |set byte count
  1456. btstb #7,STAG(%a6) |check for extended denorm
  1457. bne int_dnrm |if so, branch
  1458. fmovemx ETEMP(%a6),%fp0-%fp0
  1459. fcmpd #0x41dfffffffc00000,%fp0
  1460. | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
  1461. fbge lo_plrg
  1462. fcmpd #0xc1e0000000000000,%fp0
  1463. | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
  1464. fble lo_nlrg
  1465. |
  1466. | at this point, the answer is between the largest pos and neg values
  1467. |
  1468. movel USER_FPCR(%a6),%d1 |use user's rounding mode
  1469. andil #0x30,%d1
  1470. fmovel %d1,%fpcr
  1471. fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion
  1472. fmovel %fpsr,%d1
  1473. orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
  1474. bra int_wrt
  1475. lo_plrg:
  1476. movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int
  1477. fbeq int_wrt |exact answer
  1478. fcmpd #0x41dfffffffe00000,%fp0
  1479. | 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
  1480. fbge int_operr |set operr
  1481. bra int_inx |set inexact
  1482. lo_nlrg:
  1483. movel #0x80000000,L_SCR1(%a6)
  1484. fbeq int_wrt |exact answer
  1485. fcmpd #0xc1e0000000100000,%fp0
  1486. | c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
  1487. fblt int_operr |set operr
  1488. bra int_inx |set inexact
  1489. |
  1490. | wi is used to handle a word integer source specifier
  1491. |
  1492. wi:
  1493. moveql #2,%d0 |set byte count
  1494. btstb #7,STAG(%a6) |check for extended denorm
  1495. bne int_dnrm |branch if so
  1496. fmovemx ETEMP(%a6),%fp0-%fp0
  1497. fcmps #0x46fffe00,%fp0
  1498. | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
  1499. fbge wo_plrg
  1500. fcmps #0xc7000000,%fp0
  1501. | c7000000 in sgl prec = c00e00008000000000000000 in ext prec
  1502. fble wo_nlrg
  1503. |
  1504. | at this point, the answer is between the largest pos and neg values
  1505. |
  1506. movel USER_FPCR(%a6),%d1 |use user's rounding mode
  1507. andil #0x30,%d1
  1508. fmovel %d1,%fpcr
  1509. fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion
  1510. fmovel %fpsr,%d1
  1511. orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
  1512. bra int_wrt
  1513. wo_plrg:
  1514. movew #0x7fff,L_SCR1(%a6) |answer is largest positive int
  1515. fbeq int_wrt |exact answer
  1516. fcmps #0x46ffff00,%fp0
  1517. | 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
  1518. fbge int_operr |set operr
  1519. bra int_inx |set inexact
  1520. wo_nlrg:
  1521. movew #0x8000,L_SCR1(%a6)
  1522. fbeq int_wrt |exact answer
  1523. fcmps #0xc7000080,%fp0
  1524. | c7000080 in sgl prec = c00e00008000800000000000 in ext prec
  1525. fblt int_operr |set operr
  1526. bra int_inx |set inexact
  1527. |
  1528. | bi is used to handle a byte integer source specifier
  1529. |
  1530. bi:
  1531. moveql #1,%d0 |set byte count
  1532. btstb #7,STAG(%a6) |check for extended denorm
  1533. bne int_dnrm |branch if so
  1534. fmovemx ETEMP(%a6),%fp0-%fp0
  1535. fcmps #0x42fe0000,%fp0
  1536. | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
  1537. fbge by_plrg
  1538. fcmps #0xc3000000,%fp0
  1539. | c3000000 in sgl prec = c00600008000000000000000 in ext prec
  1540. fble by_nlrg
  1541. |
  1542. | at this point, the answer is between the largest pos and neg values
  1543. |
  1544. movel USER_FPCR(%a6),%d1 |use user's rounding mode
  1545. andil #0x30,%d1
  1546. fmovel %d1,%fpcr
  1547. fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion
  1548. fmovel %fpsr,%d1
  1549. orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
  1550. bra int_wrt
  1551. by_plrg:
  1552. moveb #0x7f,L_SCR1(%a6) |answer is largest positive int
  1553. fbeq int_wrt |exact answer
  1554. fcmps #0x42ff0000,%fp0
  1555. | 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
  1556. fbge int_operr |set operr
  1557. bra int_inx |set inexact
  1558. by_nlrg:
  1559. moveb #0x80,L_SCR1(%a6)
  1560. fbeq int_wrt |exact answer
  1561. fcmps #0xc3008000,%fp0
  1562. | c3008000 in sgl prec = c00600008080000000000000 in ext prec
  1563. fblt int_operr |set operr
  1564. bra int_inx |set inexact
  1565. |
  1566. | Common integer routines
  1567. |
  1568. | int_drnrm---account for possible nonzero result for round up with positive
  1569. | operand and round down for negative answer. In the first case (result = 1)
  1570. | byte-width (store in d0) of result must be honored. In the second case,
  1571. | -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
  1572. int_dnrm:
  1573. movel #0,L_SCR1(%a6) | initialize result to 0
  1574. bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode
  1575. cmpb #2,%d1
  1576. bmis int_inx | if RN or RZ, done
  1577. bnes int_rp | if RP, continue below
  1578. tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative
  1579. bpls int_inx | otherwise result is 0
  1580. movel #-1,L_SCR1(%a6)
  1581. bras int_inx
  1582. int_rp:
  1583. tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if
  1584. | ; source is greater than 0
  1585. bmis int_inx | otherwise, result is 0
  1586. lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1
  1587. addal %d0,%a1 | offset by destination width -1
  1588. subal #1,%a1
  1589. bsetb #0,(%a1) | set low bit at a1 address
  1590. int_inx:
  1591. oril #inx2a_mask,USER_FPSR(%a6)
  1592. bras int_wrt
  1593. int_operr:
  1594. fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended
  1595. | ;precision source that needs to be
  1596. | ;converted to integer this is required
  1597. | ;if the operr exception is enabled.
  1598. | ;set operr/aiop (no inex2 on int ovfl)
  1599. oril #opaop_mask,USER_FPSR(%a6)
  1600. | ;fall through to perform int_wrt
  1601. int_wrt:
  1602. movel EXC_EA(%a6),%a1 |load destination address
  1603. tstl %a1 |check to see if it is a dest register
  1604. beqs wrt_dn |write data register
  1605. lea L_SCR1(%a6),%a0 |point to supervisor source address
  1606. bsrl mem_write
  1607. bra mvouti_end
  1608. wrt_dn:
  1609. movel %d0,-(%sp) |d0 currently contains the size to write
  1610. bsrl get_fline |get_fline returns Dn in d0
  1611. andiw #0x7,%d0 |isolate register
  1612. movel (%sp)+,%d1 |get size
  1613. cmpil #4,%d1 |most frequent case
  1614. beqs sz_long
  1615. cmpil #2,%d1
  1616. bnes sz_con
  1617. orl #8,%d0 |add 'word' size to register#
  1618. bras sz_con
  1619. sz_long:
  1620. orl #0x10,%d0 |add 'long' size to register#
  1621. sz_con:
  1622. movel %d0,%d1 |reg_dest expects size:reg in d1
  1623. bsrl reg_dest |load proper data register
  1624. bra mvouti_end
  1625. xp:
  1626. lea ETEMP(%a6),%a0
  1627. bclrb #sign_bit,LOCAL_EX(%a0)
  1628. sne LOCAL_SGN(%a0)
  1629. btstb #7,STAG(%a6) |check for extended denorm
  1630. bne xdnrm
  1631. clrl %d0
  1632. bras do_fp |do normal case
  1633. sgp:
  1634. lea ETEMP(%a6),%a0
  1635. bclrb #sign_bit,LOCAL_EX(%a0)
  1636. sne LOCAL_SGN(%a0)
  1637. btstb #7,STAG(%a6) |check for extended denorm
  1638. bne sp_catas |branch if so
  1639. movew LOCAL_EX(%a0),%d0
  1640. lea sp_bnds,%a1
  1641. cmpw (%a1),%d0
  1642. blt sp_under
  1643. cmpw 2(%a1),%d0
  1644. bgt sp_over
  1645. movel #1,%d0 |set destination format to single
  1646. bras do_fp |do normal case
  1647. dp:
  1648. lea ETEMP(%a6),%a0
  1649. bclrb #sign_bit,LOCAL_EX(%a0)
  1650. sne LOCAL_SGN(%a0)
  1651. btstb #7,STAG(%a6) |check for extended denorm
  1652. bne dp_catas |branch if so
  1653. movew LOCAL_EX(%a0),%d0
  1654. lea dp_bnds,%a1
  1655. cmpw (%a1),%d0
  1656. blt dp_under
  1657. cmpw 2(%a1),%d0
  1658. bgt dp_over
  1659. movel #2,%d0 |set destination format to double
  1660. | ;fall through to do_fp
  1661. |
  1662. do_fp:
  1663. bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1
  1664. swap %d0 |rnd prec in upper word
  1665. addl %d0,%d1 |d1 has PREC/MODE info
  1666. clrl %d0 |clear g,r,s
  1667. bsrl round |round
  1668. movel %a0,%a1
  1669. movel EXC_EA(%a6),%a0
  1670. bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format
  1671. | ;at this point only the dest
  1672. | ;formats sgl, dbl, ext are
  1673. | ;possible
  1674. cmpb #2,%d1
  1675. bgts ddbl |double=5, extended=2, single=1
  1676. bnes dsgl
  1677. | ;fall through to dext
  1678. dext:
  1679. bsrl dest_ext
  1680. bra mvout_end
  1681. dsgl:
  1682. bsrl dest_sgl
  1683. bra mvout_end
  1684. ddbl:
  1685. bsrl dest_dbl
  1686. bra mvout_end
  1687. |
  1688. | Handle possible denorm or catastrophic underflow cases here
  1689. |
  1690. xdnrm:
  1691. bsr set_xop |initialize WBTEMP
  1692. bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
  1693. movel %a0,%a1
  1694. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1695. bsrl dest_ext |store to memory
  1696. bsetb #unfl_bit,FPSR_EXCEPT(%a6)
  1697. bra mvout_end
  1698. sp_under:
  1699. bsetb #etemp15_bit,STAG(%a6)
  1700. cmpw 4(%a1),%d0
  1701. blts sp_catas |catastrophic underflow case
  1702. movel #1,%d0 |load in round precision
  1703. movel #sgl_thresh,%d1 |load in single denorm threshold
  1704. bsrl dpspdnrm |expects d1 to have the proper
  1705. | ;denorm threshold
  1706. bsrl dest_sgl |stores value to destination
  1707. bsetb #unfl_bit,FPSR_EXCEPT(%a6)
  1708. bra mvout_end |exit
  1709. dp_under:
  1710. bsetb #etemp15_bit,STAG(%a6)
  1711. cmpw 4(%a1),%d0
  1712. blts dp_catas |catastrophic underflow case
  1713. movel #dbl_thresh,%d1 |load in double precision threshold
  1714. movel #2,%d0
  1715. bsrl dpspdnrm |expects d1 to have proper
  1716. | ;denorm threshold
  1717. | ;expects d0 to have round precision
  1718. bsrl dest_dbl |store value to destination
  1719. bsetb #unfl_bit,FPSR_EXCEPT(%a6)
  1720. bra mvout_end |exit
  1721. |
  1722. | Handle catastrophic underflow cases here
  1723. |
  1724. sp_catas:
  1725. | Temp fix for z bit set in unf_sub
  1726. movel USER_FPSR(%a6),-(%a7)
  1727. movel #1,%d0 |set round precision to sgl
  1728. bsrl unf_sub |a0 points to result
  1729. movel (%a7)+,USER_FPSR(%a6)
  1730. movel #1,%d0
  1731. subw %d0,LOCAL_EX(%a0) |account for difference between
  1732. | ;denorm/norm bias
  1733. movel %a0,%a1 |a1 has the operand input
  1734. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1735. bsrl dest_sgl |store the result
  1736. oril #unfinx_mask,USER_FPSR(%a6)
  1737. bra mvout_end
  1738. dp_catas:
  1739. | Temp fix for z bit set in unf_sub
  1740. movel USER_FPSR(%a6),-(%a7)
  1741. movel #2,%d0 |set round precision to dbl
  1742. bsrl unf_sub |a0 points to result
  1743. movel (%a7)+,USER_FPSR(%a6)
  1744. movel #1,%d0
  1745. subw %d0,LOCAL_EX(%a0) |account for difference between
  1746. | ;denorm/norm bias
  1747. movel %a0,%a1 |a1 has the operand input
  1748. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1749. bsrl dest_dbl |store the result
  1750. oril #unfinx_mask,USER_FPSR(%a6)
  1751. bra mvout_end
  1752. |
  1753. | Handle catastrophic overflow cases here
  1754. |
  1755. sp_over:
  1756. | Temp fix for z bit set in unf_sub
  1757. movel USER_FPSR(%a6),-(%a7)
  1758. movel #1,%d0
  1759. leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
  1760. movel ETEMP_EX(%a6),(%a0)
  1761. movel ETEMP_HI(%a6),4(%a0)
  1762. movel ETEMP_LO(%a6),8(%a0)
  1763. bsrl ovf_res
  1764. movel (%a7)+,USER_FPSR(%a6)
  1765. movel %a0,%a1
  1766. movel EXC_EA(%a6),%a0
  1767. bsrl dest_sgl
  1768. orl #ovfinx_mask,USER_FPSR(%a6)
  1769. bra mvout_end
  1770. dp_over:
  1771. | Temp fix for z bit set in ovf_res
  1772. movel USER_FPSR(%a6),-(%a7)
  1773. movel #2,%d0
  1774. leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
  1775. movel ETEMP_EX(%a6),(%a0)
  1776. movel ETEMP_HI(%a6),4(%a0)
  1777. movel ETEMP_LO(%a6),8(%a0)
  1778. bsrl ovf_res
  1779. movel (%a7)+,USER_FPSR(%a6)
  1780. movel %a0,%a1
  1781. movel EXC_EA(%a6),%a0
  1782. bsrl dest_dbl
  1783. orl #ovfinx_mask,USER_FPSR(%a6)
  1784. bra mvout_end
  1785. |
  1786. | DPSPDNRM
  1787. |
  1788. | This subroutine takes an extended normalized number and denormalizes
  1789. | it to the given round precision. This subroutine also decrements
  1790. | the input operand's exponent by 1 to account for the fact that
  1791. | dest_sgl or dest_dbl expects a normalized number's bias.
  1792. |
  1793. | Input: a0 points to a normalized number in internal extended format
  1794. | d0 is the round precision (=1 for sgl; =2 for dbl)
  1795. | d1 is the single precision or double precision
  1796. | denorm threshold
  1797. |
  1798. | Output: (In the format for dest_sgl or dest_dbl)
  1799. | a0 points to the destination
  1800. | a1 points to the operand
  1801. |
  1802. | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
  1803. |
  1804. dpspdnrm:
  1805. movel %d0,-(%a7) |save round precision
  1806. clrl %d0 |clear initial g,r,s
  1807. bsrl dnrm_lp |careful with d0, it's needed by round
  1808. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
  1809. swap %d1
  1810. movew 2(%a7),%d1 |set rounding precision
  1811. swap %d1 |at this point d1 has PREC/MODE info
  1812. bsrl round |round result, sets the inex bit in
  1813. | ;USER_FPSR if needed
  1814. movew #1,%d0
  1815. subw %d0,LOCAL_EX(%a0) |account for difference in denorm
  1816. | ;vs norm bias
  1817. movel %a0,%a1 |a1 has the operand input
  1818. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1819. addw #4,%a7 |pop stack
  1820. rts
  1821. |
  1822. | SET_XOP initialized WBTEMP with the value pointed to by a0
  1823. | input: a0 points to input operand in the internal extended format
  1824. |
  1825. set_xop:
  1826. movel LOCAL_EX(%a0),WBTEMP_EX(%a6)
  1827. movel LOCAL_HI(%a0),WBTEMP_HI(%a6)
  1828. movel LOCAL_LO(%a0),WBTEMP_LO(%a6)
  1829. bfclr WBTEMP_SGN(%a6){#0:#8}
  1830. beqs sxop
  1831. bsetb #sign_bit,WBTEMP_EX(%a6)
  1832. sxop:
  1833. bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit
  1834. rts
  1835. |
  1836. | P_MOVE
  1837. |
  1838. p_movet:
  1839. .long p_move
  1840. .long p_movez
  1841. .long p_movei
  1842. .long p_moven
  1843. .long p_move
  1844. p_regd:
  1845. .long p_dyd0
  1846. .long p_dyd1
  1847. .long p_dyd2
  1848. .long p_dyd3
  1849. .long p_dyd4
  1850. .long p_dyd5
  1851. .long p_dyd6
  1852. .long p_dyd7
  1853. pack_out:
  1854. leal p_movet,%a0 |load jmp table address
  1855. movew STAG(%a6),%d0 |get source tag
  1856. bfextu %d0{#16:#3},%d0 |isolate source bits
  1857. movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag
  1858. jmp (%a0) |go to the routine
  1859. p_write:
  1860. movel #0x0c,%d0 |get byte count
  1861. movel EXC_EA(%a6),%a1 |get the destination address
  1862. bsr mem_write |write the user's destination
  1863. moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
  1864. |
  1865. | Also note that the dtag must be set to norm here - this is because
  1866. | the 040 uses the dtag to execute the correct microcode.
  1867. |
  1868. bfclr DTAG(%a6){#0:#3} |set dtag to norm
  1869. rts
  1870. | Notes on handling of special case (zero, inf, and nan) inputs:
  1871. | 1. Operr is not signalled if the k-factor is greater than 18.
  1872. | 2. Per the manual, status bits are not set.
  1873. |
  1874. p_move:
  1875. movew CMDREG1B(%a6),%d0
  1876. btstl #kfact_bit,%d0 |test for dynamic k-factor
  1877. beqs statick |if clear, k-factor is static
  1878. dynamick:
  1879. bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor
  1880. lea p_regd,%a0
  1881. movel %a0@(%d0:l:4),%a0
  1882. jmp (%a0)
  1883. statick:
  1884. andiw #0x007f,%d0 |get k-factor
  1885. bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec
  1886. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1887. bsrl bindec |perform the convert; data at a6
  1888. leal FP_SCR1(%a6),%a0 |load a0 with result address
  1889. bral p_write
  1890. p_movez:
  1891. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1892. clrw 2(%a0) |clear lower word of exp
  1893. clrl 4(%a0) |load second lword of ZERO
  1894. clrl 8(%a0) |load third lword of ZERO
  1895. bra p_write |go write results
  1896. p_movei:
  1897. fmovel #0,%FPSR |clear aiop
  1898. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1899. clrw 2(%a0) |clear lower word of exp
  1900. bra p_write |go write the result
  1901. p_moven:
  1902. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1903. clrw 2(%a0) |clear lower word of exp
  1904. bra p_write |go write the result
  1905. |
  1906. | Routines to read the dynamic k-factor from Dn.
  1907. |
  1908. p_dyd0:
  1909. movel USER_D0(%a6),%d0
  1910. bras statick
  1911. p_dyd1:
  1912. movel USER_D1(%a6),%d0
  1913. bras statick
  1914. p_dyd2:
  1915. movel %d2,%d0
  1916. bras statick
  1917. p_dyd3:
  1918. movel %d3,%d0
  1919. bras statick
  1920. p_dyd4:
  1921. movel %d4,%d0
  1922. bras statick
  1923. p_dyd5:
  1924. movel %d5,%d0
  1925. bras statick
  1926. p_dyd6:
  1927. movel %d6,%d0
  1928. bra statick
  1929. p_dyd7:
  1930. movel %d7,%d0
  1931. bra statick
  1932. |end