res_func.S
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:52k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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. | THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
  20. | The copyright notice above does not evidence any  
  21. | actual or intended publication of such source code.
  22. RES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
  23. |section 8
  24. .include "fpsp.h"
  25. sp_bnds: .short 0x3f81,0x407e
  26. .short 0x3f6a,0x0000
  27. dp_bnds: .short 0x3c01,0x43fe
  28. .short 0x3bcd,0x0000
  29. |xref mem_write
  30. |xref bindec
  31. |xref get_fline
  32. |xref round
  33. |xref denorm
  34. |xref dest_ext
  35. |xref dest_dbl
  36. |xref dest_sgl
  37. |xref unf_sub
  38. |xref nrm_set
  39. |xref dnrm_lp
  40. |xref ovf_res
  41. |xref reg_dest
  42. |xref t_ovfl
  43. |xref t_unfl
  44. .global res_func
  45. .global  p_move
  46. res_func:
  47. clrb DNRM_FLG(%a6)
  48. clrb RES_FLG(%a6)
  49. clrb CU_ONLY(%a6)
  50. tstb DY_MO_FLG(%a6)
  51. beqs monadic
  52. dyadic:
  53. btstb #7,DTAG(%a6) |if dop = norm=000, zero=001,
  54. | ;inf=010 or nan=011
  55. beqs monadic |then branch
  56. | ;else denorm
  57. | HANDLE DESTINATION DENORM HERE
  58. | ;set dtag to norm
  59. | ;write the tag & fpte15 to the fstack
  60. leal FPTEMP(%a6),%a0
  61. bclrb #sign_bit,LOCAL_EX(%a0)
  62. sne LOCAL_SGN(%a0)
  63. bsr nrm_set |normalize number (exp will go negative)
  64. bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
  65. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  66. beqs dpos
  67. bsetb #sign_bit,LOCAL_EX(%a0)
  68. dpos:
  69. bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
  70. bsetb #4,DTAG(%a6) |set FPTE15
  71. orb #0x0f,DNRM_FLG(%a6)
  72. monadic:
  73. leal ETEMP(%a6),%a0
  74. btstb #direction_bit,CMDREG1B(%a6) |check direction
  75. bne opclass3 |it is a mv out
  76. |
  77. | At this point, only opclass 0 and 2 possible
  78. |
  79. btstb #7,STAG(%a6) |if sop = norm=000, zero=001,
  80. | ;inf=010 or nan=011
  81. bne mon_dnrm |else denorm
  82. tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
  83. bne normal |require normalization of denorm
  84. | At this point:
  85. | monadic instructions: fabs  = $18  fneg   = $1a  ftst   = $3a
  86. | fmove = $00  fsmove = $40  fdmove = $44
  87. | fsqrt = $05* fssqrt = $41  fdsqrt = $45
  88. | (*fsqrt reencoded to $05)
  89. |
  90. movew CMDREG1B(%a6),%d0 |get command register
  91. andil #0x7f,%d0 |strip to only command word
  92. |
  93. | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 
  94. | fdsqrt are possible.
  95. | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
  96. | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
  97. |
  98. btstl #0,%d0
  99. bne normal |weed out fsqrt instructions
  100. |
  101. | cu_norm handles fmove in instructions with normalized inputs.
  102. | The routine round is used to correctly round the input for the
  103. | destination precision and mode.
  104. |
  105. cu_norm:
  106. st CU_ONLY(%a6) |set cu-only inst flag
  107. movew CMDREG1B(%a6),%d0
  108. andib #0x3b,%d0 |isolate bits to select inst
  109. tstb %d0
  110. beql cu_nmove |if zero, it is an fmove
  111. cmpib #0x18,%d0
  112. beql cu_nabs |if $18, it is fabs
  113. cmpib #0x1a,%d0
  114. beql cu_nneg |if $1a, it is fneg
  115. |
  116. | Inst is ftst.  Check the source operand and set the cc's accordingly.
  117. | No write is done, so simply rts.
  118. |
  119. cu_ntst:
  120. movew LOCAL_EX(%a0),%d0
  121. bclrl #15,%d0
  122. sne LOCAL_SGN(%a0)
  123. beqs cu_ntpo
  124. orl #neg_mask,USER_FPSR(%a6) |set N
  125. cu_ntpo:
  126. cmpiw #0x7fff,%d0 |test for inf/nan
  127. bnes cu_ntcz
  128. tstl LOCAL_HI(%a0)
  129. bnes cu_ntn
  130. tstl LOCAL_LO(%a0)
  131. bnes cu_ntn
  132. orl #inf_mask,USER_FPSR(%a6)
  133. rts
  134. cu_ntn:
  135. orl #nan_mask,USER_FPSR(%a6)
  136. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 
  137. | ;snan handler
  138. rts
  139. cu_ntcz:
  140. tstl LOCAL_HI(%a0)
  141. bnel cu_ntsx
  142. tstl LOCAL_LO(%a0)
  143. bnel cu_ntsx
  144. orl #z_mask,USER_FPSR(%a6)
  145. cu_ntsx:
  146. rts
  147. |
  148. | Inst is fabs.  Execute the absolute value function on the input.
  149. | Branch to the fmove code.  If the operand is NaN, do nothing.
  150. |
  151. cu_nabs:
  152. moveb STAG(%a6),%d0
  153. btstl #5,%d0 |test for NaN or zero
  154. bne wr_etemp |if either, simply write it
  155. bclrb #7,LOCAL_EX(%a0) |do abs
  156. bras cu_nmove |fmove code will finish
  157. |
  158. | Inst is fneg.  Execute the negate value function on the input.
  159. | Fall though to the fmove code.  If the operand is NaN, do nothing.
  160. |
  161. cu_nneg:
  162. moveb STAG(%a6),%d0
  163. btstl #5,%d0 |test for NaN or zero
  164. bne wr_etemp |if either, simply write it
  165. bchgb #7,LOCAL_EX(%a0) |do neg
  166. |
  167. | Inst is fmove.  This code also handles all result writes.
  168. | If bit 2 is set, round is forced to double.  If it is clear,
  169. | and bit 6 is set, round is forced to single.  If both are clear,
  170. | the round precision is found in the fpcr.  If the rounding precision
  171. | is double or single, round the result before the write.
  172. |
  173. cu_nmove:
  174. moveb STAG(%a6),%d0
  175. andib #0xe0,%d0 |isolate stag bits
  176. bne wr_etemp |if not norm, simply write it
  177. btstb #2,CMDREG1B+1(%a6) |check for rd
  178. bne cu_nmrd
  179. btstb #6,CMDREG1B+1(%a6) |check for rs
  180. bne cu_nmrs
  181. |
  182. | The move or operation is not with forced precision.  Test for
  183. | nan or inf as the input; if so, simply write it to FPn.  Use the
  184. | FPCR_MODE byte to get rounding on norms and zeros.
  185. |
  186. cu_nmnr:
  187. bfextu FPCR_MODE(%a6){#0:#2},%d0
  188. tstb %d0 |check for extended
  189. beq cu_wrexn |if so, just write result
  190. cmpib #1,%d0 |check for single
  191. beq cu_nmrs |fall through to double
  192. |
  193. | The move is fdmove or round precision is double.
  194. |
  195. cu_nmrd:
  196. movel #2,%d0 |set up the size for denorm
  197. movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold
  198. andw #0x7fff,%d1
  199. cmpw #0x3c01,%d1
  200. bls cu_nunfl
  201. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  202. orl #0x00020000,%d1 |or in rprec (double)
  203. clrl %d0 |clear g,r,s for round
  204. bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format
  205. sne LOCAL_SGN(%a0)
  206. bsrl round
  207. bfclr LOCAL_SGN(%a0){#0:#8}
  208. beqs cu_nmrdc
  209. bsetb #sign_bit,LOCAL_EX(%a0)
  210. cu_nmrdc:
  211. movew LOCAL_EX(%a0),%d1 |check for overflow
  212. andw #0x7fff,%d1
  213. cmpw #0x43ff,%d1
  214. bge cu_novfl |take care of overflow case
  215. bra cu_wrexn
  216. |
  217. | The move is fsmove or round precision is single.
  218. |
  219. cu_nmrs:
  220. movel #1,%d0
  221. movew LOCAL_EX(%a0),%d1
  222. andw #0x7fff,%d1
  223. cmpw #0x3f81,%d1
  224. bls cu_nunfl
  225. bfextu FPCR_MODE(%a6){#2:#2},%d1
  226. orl #0x00010000,%d1
  227. clrl %d0
  228. bclrb #sign_bit,LOCAL_EX(%a0)
  229. sne LOCAL_SGN(%a0)
  230. bsrl round
  231. bfclr LOCAL_SGN(%a0){#0:#8}
  232. beqs cu_nmrsc
  233. bsetb #sign_bit,LOCAL_EX(%a0)
  234. cu_nmrsc:
  235. movew LOCAL_EX(%a0),%d1
  236. andw #0x7FFF,%d1
  237. cmpw #0x407f,%d1
  238. blt cu_wrexn
  239. |
  240. | The operand is above precision boundaries.  Use t_ovfl to
  241. | generate the correct value.
  242. |
  243. cu_novfl:
  244. bsr t_ovfl
  245. bra cu_wrexn
  246. |
  247. | The operand is below precision boundaries.  Use denorm to
  248. | generate the correct value.
  249. |
  250. cu_nunfl:
  251. bclrb #sign_bit,LOCAL_EX(%a0)
  252. sne LOCAL_SGN(%a0)
  253. bsr denorm
  254. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  255. beqs cu_nucont
  256. bsetb #sign_bit,LOCAL_EX(%a0)
  257. cu_nucont:
  258. bfextu FPCR_MODE(%a6){#2:#2},%d1
  259. btstb #2,CMDREG1B+1(%a6) |check for rd
  260. bne inst_d
  261. btstb #6,CMDREG1B+1(%a6) |check for rs
  262. bne inst_s
  263. swap %d1
  264. moveb FPCR_MODE(%a6),%d1
  265. lsrb #6,%d1
  266. swap %d1
  267. bra inst_sd
  268. inst_d:
  269. orl #0x00020000,%d1
  270. bra inst_sd
  271. inst_s:
  272. orl #0x00010000,%d1
  273. inst_sd:
  274. bclrb #sign_bit,LOCAL_EX(%a0)
  275. sne LOCAL_SGN(%a0)
  276. bsrl round
  277. bfclr LOCAL_SGN(%a0){#0:#8}
  278. beqs cu_nuflp
  279. bsetb #sign_bit,LOCAL_EX(%a0)
  280. cu_nuflp:
  281. btstb #inex2_bit,FPSR_EXCEPT(%a6)
  282. beqs cu_nuninx
  283. orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
  284. cu_nuninx:
  285. tstl LOCAL_HI(%a0) |test for zero
  286. bnes cu_nunzro
  287. tstl LOCAL_LO(%a0)
  288. bnes cu_nunzro
  289. |
  290. | The mantissa is zero from the denorm loop.  Check sign and rmode
  291. | to see if rounding should have occurred which would leave the lsb.
  292. |
  293. movel USER_FPCR(%a6),%d0
  294. andil #0x30,%d0 |isolate rmode
  295. cmpil #0x20,%d0
  296. blts cu_nzro
  297. bnes cu_nrp
  298. cu_nrm:
  299. tstw LOCAL_EX(%a0) |if positive, set lsb
  300. bges cu_nzro
  301. btstb #7,FPCR_MODE(%a6) |check for double
  302. beqs cu_nincs
  303. bras cu_nincd
  304. cu_nrp:
  305. tstw LOCAL_EX(%a0) |if positive, set lsb
  306. blts cu_nzro
  307. btstb #7,FPCR_MODE(%a6) |check for double
  308. beqs cu_nincs
  309. cu_nincd:
  310. orl #0x800,LOCAL_LO(%a0) |inc for double
  311. bra cu_nunzro
  312. cu_nincs:
  313. orl #0x100,LOCAL_HI(%a0) |inc for single
  314. bra cu_nunzro
  315. cu_nzro:
  316. orl #z_mask,USER_FPSR(%a6)
  317. moveb STAG(%a6),%d0
  318. andib #0xe0,%d0
  319. cmpib #0x40,%d0 |check if input was tagged zero
  320. beqs cu_numv
  321. cu_nunzro:
  322. orl #unfl_mask,USER_FPSR(%a6) |set unfl
  323. cu_numv:
  324. movel (%a0),ETEMP(%a6)
  325. movel 4(%a0),ETEMP_HI(%a6)
  326. movel 8(%a0),ETEMP_LO(%a6)
  327. |
  328. | Write the result to memory, setting the fpsr cc bits.  NaN and Inf
  329. | bypass cu_wrexn.
  330. |
  331. cu_wrexn:
  332. tstw LOCAL_EX(%a0) |test for zero
  333. beqs cu_wrzero
  334. cmpw #0x8000,LOCAL_EX(%a0) |test for zero
  335. bnes cu_wreon
  336. cu_wrzero:
  337. orl #z_mask,USER_FPSR(%a6) |set Z bit
  338. cu_wreon:
  339. tstw LOCAL_EX(%a0)
  340. bpl wr_etemp
  341. orl #neg_mask,USER_FPSR(%a6)
  342. bra wr_etemp
  343. |
  344. | HANDLE SOURCE DENORM HERE
  345. |
  346. | ;clear denorm stag to norm
  347. | ;write the new tag & ete15 to the fstack
  348. mon_dnrm:
  349. |
  350. | At this point, check for the cases in which normalizing the 
  351. | denorm produces incorrect results.
  352. |
  353. tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
  354. bnes nrm_src |require normalization of denorm
  355. | At this point:
  356. | monadic instructions: fabs  = $18  fneg   = $1a  ftst   = $3a
  357. | fmove = $00  fsmove = $40  fdmove = $44
  358. | fsqrt = $05* fssqrt = $41  fdsqrt = $45
  359. | (*fsqrt reencoded to $05)
  360. |
  361. movew CMDREG1B(%a6),%d0 |get command register
  362. andil #0x7f,%d0 |strip to only command word
  363. |
  364. | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 
  365. | fdsqrt are possible.
  366. | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
  367. | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
  368. |
  369. btstl #0,%d0
  370. bnes nrm_src |weed out fsqrt instructions
  371. st CU_ONLY(%a6) |set cu-only inst flag
  372. bra cu_dnrm |fmove, fabs, fneg, ftst 
  373. | ;cases go to cu_dnrm
  374. nrm_src:
  375. bclrb #sign_bit,LOCAL_EX(%a0)
  376. sne LOCAL_SGN(%a0)
  377. bsr nrm_set |normalize number (exponent will go 
  378. | ; negative)
  379. bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
  380. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  381. beqs spos
  382. bsetb #sign_bit,LOCAL_EX(%a0)
  383. spos:
  384. bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
  385. bsetb #4,STAG(%a6) |set ETE15
  386. orb #0xf0,DNRM_FLG(%a6)
  387. normal:
  388. tstb DNRM_FLG(%a6) |check if any of the ops were denorms
  389. bne ck_wrap |if so, check if it is a potential
  390. | ;wrap-around case
  391. fix_stk:
  392. moveb #0xfe,CU_SAVEPC(%a6)
  393. bclrb #E1,E_BYTE(%a6)
  394. clrw NMNEXC(%a6)
  395. st RES_FLG(%a6) |indicate that a restore is needed
  396. rts
  397. |
  398. | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
  399. | ftst) completely in software without an frestore to the 040. 
  400. |
  401. cu_dnrm:
  402. st CU_ONLY(%a6)
  403. movew CMDREG1B(%a6),%d0
  404. andib #0x3b,%d0 |isolate bits to select inst
  405. tstb %d0
  406. beql cu_dmove |if zero, it is an fmove
  407. cmpib #0x18,%d0
  408. beql cu_dabs |if $18, it is fabs
  409. cmpib #0x1a,%d0
  410. beql cu_dneg |if $1a, it is fneg
  411. |
  412. | Inst is ftst.  Check the source operand and set the cc's accordingly.
  413. | No write is done, so simply rts.
  414. |
  415. cu_dtst:
  416. movew LOCAL_EX(%a0),%d0
  417. bclrl #15,%d0
  418. sne LOCAL_SGN(%a0)
  419. beqs cu_dtpo
  420. orl #neg_mask,USER_FPSR(%a6) |set N
  421. cu_dtpo:
  422. cmpiw #0x7fff,%d0 |test for inf/nan
  423. bnes cu_dtcz
  424. tstl LOCAL_HI(%a0)
  425. bnes cu_dtn
  426. tstl LOCAL_LO(%a0)
  427. bnes cu_dtn
  428. orl #inf_mask,USER_FPSR(%a6)
  429. rts
  430. cu_dtn:
  431. orl #nan_mask,USER_FPSR(%a6)
  432. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 
  433. | ;snan handler
  434. rts
  435. cu_dtcz:
  436. tstl LOCAL_HI(%a0)
  437. bnel cu_dtsx
  438. tstl LOCAL_LO(%a0)
  439. bnel cu_dtsx
  440. orl #z_mask,USER_FPSR(%a6)
  441. cu_dtsx:
  442. rts
  443. |
  444. | Inst is fabs.  Execute the absolute value function on the input.
  445. | Branch to the fmove code.
  446. |
  447. cu_dabs:
  448. bclrb #7,LOCAL_EX(%a0) |do abs
  449. bras cu_dmove |fmove code will finish
  450. |
  451. | Inst is fneg.  Execute the negate value function on the input.
  452. | Fall though to the fmove code.
  453. |
  454. cu_dneg:
  455. bchgb #7,LOCAL_EX(%a0) |do neg
  456. |
  457. | Inst is fmove.  This code also handles all result writes.
  458. | If bit 2 is set, round is forced to double.  If it is clear,
  459. | and bit 6 is set, round is forced to single.  If both are clear,
  460. | the round precision is found in the fpcr.  If the rounding precision
  461. | is double or single, the result is zero, and the mode is checked
  462. | to determine if the lsb of the result should be set.
  463. |
  464. cu_dmove:
  465. btstb #2,CMDREG1B+1(%a6) |check for rd
  466. bne cu_dmrd
  467. btstb #6,CMDREG1B+1(%a6) |check for rs
  468. bne cu_dmrs
  469. |
  470. | The move or operation is not with forced precision.  Use the
  471. | FPCR_MODE byte to get rounding.
  472. |
  473. cu_dmnr:
  474. bfextu FPCR_MODE(%a6){#0:#2},%d0
  475. tstb %d0 |check for extended
  476. beq cu_wrexd |if so, just write result
  477. cmpib #1,%d0 |check for single
  478. beq cu_dmrs |fall through to double
  479. |
  480. | The move is fdmove or round precision is double.  Result is zero.
  481. | Check rmode for rp or rm and set lsb accordingly.
  482. |
  483. cu_dmrd:
  484. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  485. tstw LOCAL_EX(%a0) |check sign
  486. blts cu_dmdn
  487. cmpib #3,%d1 |check for rp
  488. bne cu_dpd |load double pos zero
  489. bra cu_dpdr |load double pos zero w/lsb
  490. cu_dmdn:
  491. cmpib #2,%d1 |check for rm
  492. bne cu_dnd |load double neg zero
  493. bra cu_dndr |load double neg zero w/lsb
  494. |
  495. | The move is fsmove or round precision is single.  Result is zero.
  496. | Check for rp or rm and set lsb accordingly.
  497. |
  498. cu_dmrs:
  499. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  500. tstw LOCAL_EX(%a0) |check sign
  501. blts cu_dmsn
  502. cmpib #3,%d1 |check for rp
  503. bne cu_spd |load single pos zero
  504. bra cu_spdr |load single pos zero w/lsb
  505. cu_dmsn:
  506. cmpib #2,%d1 |check for rm
  507. bne cu_snd |load single neg zero
  508. bra cu_sndr |load single neg zero w/lsb
  509. |
  510. | The precision is extended, so the result in etemp is correct.
  511. | Simply set unfl (not inex2 or aunfl) and write the result to 
  512. | the correct fp register.
  513. cu_wrexd:
  514. orl #unfl_mask,USER_FPSR(%a6)
  515. tstw LOCAL_EX(%a0)
  516. beq wr_etemp
  517. orl #neg_mask,USER_FPSR(%a6)
  518. bra wr_etemp
  519. |
  520. | These routines write +/- zero in double format.  The routines
  521. | cu_dpdr and cu_dndr set the double lsb.
  522. |
  523. cu_dpd:
  524. movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
  525. clrl LOCAL_HI(%a0)
  526. clrl LOCAL_LO(%a0)
  527. orl #z_mask,USER_FPSR(%a6)
  528. orl #unfinx_mask,USER_FPSR(%a6)
  529. bra wr_etemp
  530. cu_dpdr:
  531. movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
  532. clrl LOCAL_HI(%a0)
  533. movel #0x800,LOCAL_LO(%a0) |with lsb set
  534. orl #unfinx_mask,USER_FPSR(%a6)
  535. bra wr_etemp
  536. cu_dnd:
  537. movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
  538. clrl LOCAL_HI(%a0)
  539. clrl LOCAL_LO(%a0)
  540. orl #z_mask,USER_FPSR(%a6)
  541. orl #neg_mask,USER_FPSR(%a6)
  542. orl #unfinx_mask,USER_FPSR(%a6)
  543. bra wr_etemp
  544. cu_dndr:
  545. movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
  546. clrl LOCAL_HI(%a0)
  547. movel #0x800,LOCAL_LO(%a0) |with lsb set
  548. orl #neg_mask,USER_FPSR(%a6)
  549. orl #unfinx_mask,USER_FPSR(%a6)
  550. bra wr_etemp
  551. |
  552. | These routines write +/- zero in single format.  The routines
  553. | cu_dpdr and cu_dndr set the single lsb.
  554. |
  555. cu_spd:
  556. movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
  557. clrl LOCAL_HI(%a0)
  558. clrl LOCAL_LO(%a0)
  559. orl #z_mask,USER_FPSR(%a6)
  560. orl #unfinx_mask,USER_FPSR(%a6)
  561. bra wr_etemp
  562. cu_spdr:
  563. movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
  564. movel #0x100,LOCAL_HI(%a0) |with lsb set
  565. clrl LOCAL_LO(%a0)
  566. orl #unfinx_mask,USER_FPSR(%a6)
  567. bra wr_etemp
  568. cu_snd:
  569. movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
  570. clrl LOCAL_HI(%a0)
  571. clrl LOCAL_LO(%a0)
  572. orl #z_mask,USER_FPSR(%a6)
  573. orl #neg_mask,USER_FPSR(%a6)
  574. orl #unfinx_mask,USER_FPSR(%a6)
  575. bra wr_etemp
  576. cu_sndr:
  577. movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
  578. movel #0x100,LOCAL_HI(%a0) |with lsb set
  579. clrl LOCAL_LO(%a0)
  580. orl #neg_mask,USER_FPSR(%a6)
  581. orl #unfinx_mask,USER_FPSR(%a6)
  582. bra wr_etemp
  583. |
  584. | This code checks for 16-bit overflow conditions on dyadic
  585. | operations which are not restorable into the floating-point
  586. | unit and must be completed in software.  Basically, this
  587. | condition exists with a very large norm and a denorm.  One
  588. | of the operands must be denormalized to enter this code.
  589. |
  590. | Flags used:
  591. | DY_MO_FLG contains 0 for monadic op, $ff for dyadic
  592. | DNRM_FLG contains $00 for neither op denormalized
  593. |                   $0f for the destination op denormalized
  594. |                   $f0 for the source op denormalized
  595. |                   $ff for both ops denormalized
  596. |
  597. | The wrap-around condition occurs for add, sub, div, and cmp
  598. | when 
  599. |
  600. | abs(dest_exp - src_exp) >= $8000
  601. |
  602. | and for mul when
  603. |
  604. | (dest_exp + src_exp) < $0
  605. |
  606. | we must process the operation here if this case is true.
  607. |
  608. | The rts following the frcfpn routine is the exit from res_func
  609. | for this condition.  The restore flag (RES_FLG) is left clear.
  610. | No frestore is done unless an exception is to be reported.
  611. |
  612. | For fadd: 
  613. | if(sign_of(dest) != sign_of(src))
  614. | replace exponent of src with $3fff (keep sign)
  615. | use fpu to perform dest+new_src (user's rmode and X)
  616. | clr sticky
  617. | else
  618. | set sticky
  619. | call round with user's precision and mode
  620. | move result to fpn and wbtemp
  621. |
  622. | For fsub:
  623. | if(sign_of(dest) == sign_of(src))
  624. | replace exponent of src with $3fff (keep sign)
  625. | use fpu to perform dest+new_src (user's rmode and X)
  626. | clr sticky
  627. | else
  628. | set sticky
  629. | call round with user's precision and mode
  630. | move result to fpn and wbtemp
  631. |
  632. | For fdiv/fsgldiv:
  633. | if(both operands are denorm)
  634. | restore_to_fpu;
  635. | if(dest is norm)
  636. | force_ovf;
  637. | else(dest is denorm)
  638. | force_unf:
  639. |
  640. | For fcmp:
  641. | if(dest is norm)
  642. | N = sign_of(dest);
  643. | else(dest is denorm)
  644. | N = sign_of(src);
  645. |
  646. | For fmul:
  647. | if(both operands are denorm)
  648. | force_unf;
  649. | if((dest_exp + src_exp) < 0)
  650. | force_unf:
  651. | else
  652. | restore_to_fpu;
  653. |
  654. | local equates:
  655. .set addcode,0x22
  656. .set subcode,0x28
  657. .set mulcode,0x23
  658. .set divcode,0x20
  659. .set cmpcode,0x38
  660. ck_wrap:
  661. | tstb DY_MO_FLG(%a6) ;check for fsqrt
  662. beq fix_stk |if zero, it is fsqrt
  663. movew CMDREG1B(%a6),%d0
  664. andiw #0x3b,%d0 |strip to command bits
  665. cmpiw #addcode,%d0
  666. beq wrap_add
  667. cmpiw #subcode,%d0
  668. beq wrap_sub
  669. cmpiw #mulcode,%d0
  670. beq wrap_mul
  671. cmpiw #cmpcode,%d0
  672. beq wrap_cmp
  673. |
  674. | Inst is fdiv.  
  675. |
  676. wrap_div:
  677. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 
  678. beq fix_stk  |restore to fpu
  679. |
  680. | One of the ops is denormalized.  Test for wrap condition
  681. | and force the result.
  682. |
  683. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  684. bnes div_srcd
  685. div_destd:
  686. bsrl ckinf_ns
  687. bne fix_stk
  688. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  689. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  690. subl %d1,%d0 |subtract dest from src
  691. cmpl #0x7fff,%d0
  692. blt fix_stk |if less, not wrap case
  693. clrb WBTEMP_SGN(%a6)
  694. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  695. movew FPTEMP_EX(%a6),%d1
  696. eorw %d1,%d0
  697. andiw #0x8000,%d0
  698. beq force_unf
  699. st WBTEMP_SGN(%a6)
  700. bra force_unf
  701. ckinf_ns:
  702. moveb STAG(%a6),%d0 |check source tag for inf or nan
  703. bra ck_in_com
  704. ckinf_nd:
  705. moveb DTAG(%a6),%d0 |check destination tag for inf or nan
  706. ck_in_com:
  707. andib #0x60,%d0 |isolate tag bits
  708. cmpb #0x40,%d0 |is it inf?
  709. beq nan_or_inf |not wrap case
  710. cmpb #0x60,%d0 |is it nan?
  711. beq nan_or_inf |yes, not wrap case?
  712. cmpb #0x20,%d0 |is it a zero?
  713. beq nan_or_inf |yes
  714. clrl %d0
  715. rts |then ; it is either a zero of norm,
  716. | ;check wrap case
  717. nan_or_inf:
  718. moveql #-1,%d0
  719. rts
  720. div_srcd:
  721. bsrl ckinf_nd
  722. bne fix_stk
  723. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  724. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  725. subl %d1,%d0 |subtract src from dest
  726. cmpl #0x8000,%d0
  727. blt fix_stk |if less, not wrap case
  728. clrb WBTEMP_SGN(%a6)
  729. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  730. movew FPTEMP_EX(%a6),%d1
  731. eorw %d1,%d0
  732. andiw #0x8000,%d0
  733. beqs force_ovf
  734. st WBTEMP_SGN(%a6)
  735. |
  736. | This code handles the case of the instruction resulting in 
  737. | an overflow condition.
  738. |
  739. force_ovf:
  740. bclrb #E1,E_BYTE(%a6)
  741. orl #ovfl_inx_mask,USER_FPSR(%a6)
  742. clrw NMNEXC(%a6)
  743. leal WBTEMP(%a6),%a0 |point a0 to memory location
  744. movew CMDREG1B(%a6),%d0
  745. btstl #6,%d0 |test for forced precision
  746. beqs frcovf_fpcr
  747. btstl #2,%d0 |check for double
  748. bnes frcovf_dbl
  749. movel #0x1,%d0 |inst is forced single
  750. bras frcovf_rnd
  751. frcovf_dbl:
  752. movel #0x2,%d0 |inst is forced double
  753. bras frcovf_rnd
  754. frcovf_fpcr:
  755. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  756. frcovf_rnd:
  757. | The 881/882 does not set inex2 for the following case, so the 
  758. | line is commented out to be compatible with 881/882
  759. | tst.b %d0
  760. | beq.b frcovf_x
  761. | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
  762. |frcovf_x:
  763. bsrl ovf_res |get correct result based on
  764. | ;round precision/mode.  This 
  765. | ;sets FPSR_CC correctly
  766. | ;returns in external format
  767. bfclr WBTEMP_SGN(%a6){#0:#8}
  768. beq frcfpn
  769. bsetb #sign_bit,WBTEMP_EX(%a6)
  770. bra frcfpn
  771. |
  772. | Inst is fadd.
  773. |
  774. wrap_add:
  775. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 
  776. beq fix_stk  |restore to fpu
  777. |
  778. | One of the ops is denormalized.  Test for wrap condition
  779. | and complete the instruction.
  780. |
  781. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  782. bnes add_srcd
  783. add_destd:
  784. bsrl ckinf_ns
  785. bne fix_stk
  786. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  787. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  788. subl %d1,%d0 |subtract dest from src
  789. cmpl #0x8000,%d0
  790. blt fix_stk |if less, not wrap case
  791. bra add_wrap
  792. add_srcd:
  793. bsrl ckinf_nd
  794. bne fix_stk
  795. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  796. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  797. subl %d1,%d0 |subtract src from dest
  798. cmpl #0x8000,%d0
  799. blt fix_stk |if less, not wrap case
  800. |
  801. | Check the signs of the operands.  If they are unlike, the fpu
  802. | can be used to add the norm and 1.0 with the sign of the
  803. | denorm and it will correctly generate the result in extended
  804. | precision.  We can then call round with no sticky and the result
  805. | will be correct for the user's rounding mode and precision.  If
  806. | the signs are the same, we call round with the sticky bit set
  807. | and the result will be correct for the user's rounding mode and
  808. | precision.
  809. |
  810. add_wrap:
  811. movew ETEMP_EX(%a6),%d0
  812. movew FPTEMP_EX(%a6),%d1
  813. eorw %d1,%d0
  814. andiw #0x8000,%d0
  815. beq add_same
  816. |
  817. | The signs are unlike.
  818. |
  819. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  820. bnes add_u_srcd
  821. movew FPTEMP_EX(%a6),%d0
  822. andiw #0x8000,%d0
  823. orw #0x3fff,%d0 |force the exponent to +/- 1
  824. movew %d0,FPTEMP_EX(%a6) |in the denorm
  825. movel USER_FPCR(%a6),%d0
  826. andil #0x30,%d0
  827. fmovel %d0,%fpcr |set up users rmode and X
  828. fmovex ETEMP(%a6),%fp0
  829. faddx FPTEMP(%a6),%fp0
  830. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  831. fmovel %fpsr,%d1
  832. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  833. fmovex %fp0,WBTEMP(%a6) |write result to memory
  834. lsrl #4,%d0 |put rmode in lower 2 bits
  835. movel USER_FPCR(%a6),%d1
  836. andil #0xc0,%d1
  837. lsrl #6,%d1 |put precision in upper word
  838. swap %d1
  839. orl %d0,%d1 |set up for round call
  840. clrl %d0 |force sticky to zero
  841. bclrb #sign_bit,WBTEMP_EX(%a6)
  842. sne WBTEMP_SGN(%a6)
  843. bsrl round |round result to users rmode & prec
  844. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  845. beq frcfpnr
  846. bsetb #sign_bit,WBTEMP_EX(%a6)
  847. bra frcfpnr
  848. add_u_srcd:
  849. movew ETEMP_EX(%a6),%d0
  850. andiw #0x8000,%d0
  851. orw #0x3fff,%d0 |force the exponent to +/- 1
  852. movew %d0,ETEMP_EX(%a6) |in the denorm
  853. movel USER_FPCR(%a6),%d0
  854. andil #0x30,%d0
  855. fmovel %d0,%fpcr |set up users rmode and X
  856. fmovex ETEMP(%a6),%fp0
  857. faddx FPTEMP(%a6),%fp0
  858. fmovel %fpsr,%d1
  859. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  860. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  861. fmovex %fp0,WBTEMP(%a6) |write result to memory
  862. lsrl #4,%d0 |put rmode in lower 2 bits
  863. movel USER_FPCR(%a6),%d1
  864. andil #0xc0,%d1
  865. lsrl #6,%d1 |put precision in upper word
  866. swap %d1
  867. orl %d0,%d1 |set up for round call
  868. clrl %d0 |force sticky to zero
  869. bclrb #sign_bit,WBTEMP_EX(%a6)
  870. sne WBTEMP_SGN(%a6) |use internal format for round
  871. bsrl round |round result to users rmode & prec
  872. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  873. beq frcfpnr
  874. bsetb #sign_bit,WBTEMP_EX(%a6)
  875. bra frcfpnr
  876. |
  877. | Signs are alike:
  878. |
  879. add_same:
  880. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  881. bnes add_s_srcd
  882. add_s_destd:
  883. leal ETEMP(%a6),%a0
  884. movel USER_FPCR(%a6),%d0
  885. andil #0x30,%d0
  886. lsrl #4,%d0 |put rmode in lower 2 bits
  887. movel USER_FPCR(%a6),%d1
  888. andil #0xc0,%d1
  889. lsrl #6,%d1 |put precision in upper word
  890. swap %d1
  891. orl %d0,%d1 |set up for round call
  892. movel #0x20000000,%d0 |set sticky for round
  893. bclrb #sign_bit,ETEMP_EX(%a6)
  894. sne ETEMP_SGN(%a6)
  895. bsrl round |round result to users rmode & prec
  896. bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  897. beqs add_s_dclr
  898. bsetb #sign_bit,ETEMP_EX(%a6)
  899. add_s_dclr:
  900. leal WBTEMP(%a6),%a0
  901. movel ETEMP(%a6),(%a0) |write result to wbtemp
  902. movel ETEMP_HI(%a6),4(%a0)
  903. movel ETEMP_LO(%a6),8(%a0)
  904. tstw ETEMP_EX(%a6)
  905. bgt add_ckovf
  906. orl #neg_mask,USER_FPSR(%a6)
  907. bra add_ckovf
  908. add_s_srcd:
  909. leal FPTEMP(%a6),%a0
  910. movel USER_FPCR(%a6),%d0
  911. andil #0x30,%d0
  912. lsrl #4,%d0 |put rmode in lower 2 bits
  913. movel USER_FPCR(%a6),%d1
  914. andil #0xc0,%d1
  915. lsrl #6,%d1 |put precision in upper word
  916. swap %d1
  917. orl %d0,%d1 |set up for round call
  918. movel #0x20000000,%d0 |set sticky for round
  919. bclrb #sign_bit,FPTEMP_EX(%a6)
  920. sne FPTEMP_SGN(%a6)
  921. bsrl round |round result to users rmode & prec
  922. bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  923. beqs add_s_sclr
  924. bsetb #sign_bit,FPTEMP_EX(%a6)
  925. add_s_sclr:
  926. leal WBTEMP(%a6),%a0
  927. movel FPTEMP(%a6),(%a0) |write result to wbtemp
  928. movel FPTEMP_HI(%a6),4(%a0)
  929. movel FPTEMP_LO(%a6),8(%a0)
  930. tstw FPTEMP_EX(%a6)
  931. bgt add_ckovf
  932. orl #neg_mask,USER_FPSR(%a6)
  933. add_ckovf:
  934. movew WBTEMP_EX(%a6),%d0
  935. andiw #0x7fff,%d0
  936. cmpiw #0x7fff,%d0
  937. bne frcfpnr
  938. |
  939. | The result has overflowed to $7fff exponent.  Set I, ovfl,
  940. | and aovfl, and clr the mantissa (incorrectly set by the
  941. | round routine.)
  942. |
  943. orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
  944. clrl 4(%a0)
  945. bra frcfpnr
  946. |
  947. | Inst is fsub.
  948. |
  949. wrap_sub:
  950. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 
  951. beq fix_stk  |restore to fpu
  952. |
  953. | One of the ops is denormalized.  Test for wrap condition
  954. | and complete the instruction.
  955. |
  956. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  957. bnes sub_srcd
  958. sub_destd:
  959. bsrl ckinf_ns
  960. bne fix_stk
  961. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  962. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  963. subl %d1,%d0 |subtract src from dest
  964. cmpl #0x8000,%d0
  965. blt fix_stk |if less, not wrap case
  966. bra sub_wrap
  967. sub_srcd:
  968. bsrl ckinf_nd
  969. bne fix_stk
  970. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  971. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  972. subl %d1,%d0 |subtract dest from src
  973. cmpl #0x8000,%d0
  974. blt fix_stk |if less, not wrap case
  975. |
  976. | Check the signs of the operands.  If they are alike, the fpu
  977. | can be used to subtract from the norm 1.0 with the sign of the
  978. | denorm and it will correctly generate the result in extended
  979. | precision.  We can then call round with no sticky and the result
  980. | will be correct for the user's rounding mode and precision.  If
  981. | the signs are unlike, we call round with the sticky bit set
  982. | and the result will be correct for the user's rounding mode and
  983. | precision.
  984. |
  985. sub_wrap:
  986. movew ETEMP_EX(%a6),%d0
  987. movew FPTEMP_EX(%a6),%d1
  988. eorw %d1,%d0
  989. andiw #0x8000,%d0
  990. bne sub_diff
  991. |
  992. | The signs are alike.
  993. |
  994. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  995. bnes sub_u_srcd
  996. movew FPTEMP_EX(%a6),%d0
  997. andiw #0x8000,%d0
  998. orw #0x3fff,%d0 |force the exponent to +/- 1
  999. movew %d0,FPTEMP_EX(%a6) |in the denorm
  1000. movel USER_FPCR(%a6),%d0
  1001. andil #0x30,%d0
  1002. fmovel %d0,%fpcr |set up users rmode and X
  1003. fmovex FPTEMP(%a6),%fp0
  1004. fsubx ETEMP(%a6),%fp0
  1005. fmovel %fpsr,%d1
  1006. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  1007. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  1008. fmovex %fp0,WBTEMP(%a6) |write result to memory
  1009. lsrl #4,%d0 |put rmode in lower 2 bits
  1010. movel USER_FPCR(%a6),%d1
  1011. andil #0xc0,%d1
  1012. lsrl #6,%d1 |put precision in upper word
  1013. swap %d1
  1014. orl %d0,%d1 |set up for round call
  1015. clrl %d0 |force sticky to zero
  1016. bclrb #sign_bit,WBTEMP_EX(%a6)
  1017. sne WBTEMP_SGN(%a6)
  1018. bsrl round |round result to users rmode & prec
  1019. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1020. beq frcfpnr
  1021. bsetb #sign_bit,WBTEMP_EX(%a6)
  1022. bra frcfpnr
  1023. sub_u_srcd:
  1024. movew ETEMP_EX(%a6),%d0
  1025. andiw #0x8000,%d0
  1026. orw #0x3fff,%d0 |force the exponent to +/- 1
  1027. movew %d0,ETEMP_EX(%a6) |in the denorm
  1028. movel USER_FPCR(%a6),%d0
  1029. andil #0x30,%d0
  1030. fmovel %d0,%fpcr |set up users rmode and X
  1031. fmovex FPTEMP(%a6),%fp0
  1032. fsubx ETEMP(%a6),%fp0
  1033. fmovel %fpsr,%d1
  1034. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  1035. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  1036. fmovex %fp0,WBTEMP(%a6) |write result to memory
  1037. lsrl #4,%d0 |put rmode in lower 2 bits
  1038. movel USER_FPCR(%a6),%d1
  1039. andil #0xc0,%d1
  1040. lsrl #6,%d1 |put precision in upper word
  1041. swap %d1
  1042. orl %d0,%d1 |set up for round call
  1043. clrl %d0 |force sticky to zero
  1044. bclrb #sign_bit,WBTEMP_EX(%a6)
  1045. sne WBTEMP_SGN(%a6)
  1046. bsrl round |round result to users rmode & prec
  1047. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1048. beq frcfpnr
  1049. bsetb #sign_bit,WBTEMP_EX(%a6)
  1050. bra frcfpnr
  1051. |
  1052. | Signs are unlike:
  1053. |
  1054. sub_diff:
  1055. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  1056. bnes sub_s_srcd
  1057. sub_s_destd:
  1058. leal ETEMP(%a6),%a0
  1059. movel USER_FPCR(%a6),%d0
  1060. andil #0x30,%d0
  1061. lsrl #4,%d0 |put rmode in lower 2 bits
  1062. movel USER_FPCR(%a6),%d1
  1063. andil #0xc0,%d1
  1064. lsrl #6,%d1 |put precision in upper word
  1065. swap %d1
  1066. orl %d0,%d1 |set up for round call
  1067. movel #0x20000000,%d0 |set sticky for round
  1068. |
  1069. | Since the dest is the denorm, the sign is the opposite of the
  1070. | norm sign.
  1071. |
  1072. eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result
  1073. tstw ETEMP_EX(%a6)
  1074. bgts sub_s_dwr
  1075. orl #neg_mask,USER_FPSR(%a6)
  1076. sub_s_dwr:
  1077. bclrb #sign_bit,ETEMP_EX(%a6)
  1078. sne ETEMP_SGN(%a6)
  1079. bsrl round |round result to users rmode & prec
  1080. bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1081. beqs sub_s_dclr
  1082. bsetb #sign_bit,ETEMP_EX(%a6)
  1083. sub_s_dclr:
  1084. leal WBTEMP(%a6),%a0
  1085. movel ETEMP(%a6),(%a0) |write result to wbtemp
  1086. movel ETEMP_HI(%a6),4(%a0)
  1087. movel ETEMP_LO(%a6),8(%a0)
  1088. bra sub_ckovf
  1089. sub_s_srcd:
  1090. leal FPTEMP(%a6),%a0
  1091. movel USER_FPCR(%a6),%d0
  1092. andil #0x30,%d0
  1093. lsrl #4,%d0 |put rmode in lower 2 bits
  1094. movel USER_FPCR(%a6),%d1
  1095. andil #0xc0,%d1
  1096. lsrl #6,%d1 |put precision in upper word
  1097. swap %d1
  1098. orl %d0,%d1 |set up for round call
  1099. movel #0x20000000,%d0 |set sticky for round
  1100. bclrb #sign_bit,FPTEMP_EX(%a6)
  1101. sne FPTEMP_SGN(%a6)
  1102. bsrl round |round result to users rmode & prec
  1103. bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1104. beqs sub_s_sclr
  1105. bsetb #sign_bit,FPTEMP_EX(%a6)
  1106. sub_s_sclr:
  1107. leal WBTEMP(%a6),%a0
  1108. movel FPTEMP(%a6),(%a0) |write result to wbtemp
  1109. movel FPTEMP_HI(%a6),4(%a0)
  1110. movel FPTEMP_LO(%a6),8(%a0)
  1111. tstw FPTEMP_EX(%a6)
  1112. bgt sub_ckovf
  1113. orl #neg_mask,USER_FPSR(%a6)
  1114. sub_ckovf:
  1115. movew WBTEMP_EX(%a6),%d0
  1116. andiw #0x7fff,%d0
  1117. cmpiw #0x7fff,%d0
  1118. bne frcfpnr
  1119. |
  1120. | The result has overflowed to $7fff exponent.  Set I, ovfl,
  1121. | and aovfl, and clr the mantissa (incorrectly set by the
  1122. | round routine.)
  1123. |
  1124. orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
  1125. clrl 4(%a0)
  1126. bra frcfpnr
  1127. |
  1128. | Inst is fcmp.
  1129. |
  1130. wrap_cmp:
  1131. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 
  1132. beq fix_stk  |restore to fpu
  1133. |
  1134. | One of the ops is denormalized.  Test for wrap condition
  1135. | and complete the instruction.
  1136. |
  1137. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  1138. bnes cmp_srcd
  1139. cmp_destd:
  1140. bsrl ckinf_ns
  1141. bne fix_stk
  1142. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  1143. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  1144. subl %d1,%d0 |subtract dest from src
  1145. cmpl #0x8000,%d0
  1146. blt fix_stk |if less, not wrap case
  1147. tstw ETEMP_EX(%a6) |set N to ~sign_of(src)
  1148. bge cmp_setn
  1149. rts
  1150. cmp_srcd:
  1151. bsrl ckinf_nd
  1152. bne fix_stk
  1153. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  1154. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  1155. subl %d1,%d0 |subtract src from dest
  1156. cmpl #0x8000,%d0
  1157. blt fix_stk |if less, not wrap case
  1158. tstw FPTEMP_EX(%a6) |set N to sign_of(dest)
  1159. blt cmp_setn
  1160. rts
  1161. cmp_setn:
  1162. orl #neg_mask,USER_FPSR(%a6)
  1163. rts
  1164. |
  1165. | Inst is fmul.
  1166. |
  1167. wrap_mul:
  1168. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 
  1169. beq force_unf |force an underflow (really!)
  1170. |
  1171. | One of the ops is denormalized.  Test for wrap condition
  1172. | and complete the instruction.
  1173. |
  1174. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  1175. bnes mul_srcd
  1176. mul_destd:
  1177. bsrl ckinf_ns
  1178. bne fix_stk
  1179. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  1180. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  1181. addl %d1,%d0 |subtract dest from src
  1182. bgt fix_stk
  1183. bra force_unf
  1184. mul_srcd:
  1185. bsrl ckinf_nd
  1186. bne fix_stk
  1187. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  1188. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  1189. addl %d1,%d0 |subtract src from dest
  1190. bgt fix_stk
  1191. |
  1192. | This code handles the case of the instruction resulting in 
  1193. | an underflow condition.
  1194. |
  1195. force_unf:
  1196. bclrb #E1,E_BYTE(%a6)
  1197. orl #unfinx_mask,USER_FPSR(%a6)
  1198. clrw NMNEXC(%a6)
  1199. clrb WBTEMP_SGN(%a6)
  1200. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  1201. movew FPTEMP_EX(%a6),%d1
  1202. eorw %d1,%d0
  1203. andiw #0x8000,%d0
  1204. beqs frcunfcont
  1205. st WBTEMP_SGN(%a6)
  1206. frcunfcont:
  1207. lea WBTEMP(%a6),%a0 |point a0 to memory location
  1208. movew CMDREG1B(%a6),%d0
  1209. btstl #6,%d0 |test for forced precision
  1210. beqs frcunf_fpcr
  1211. btstl #2,%d0 |check for double
  1212. bnes frcunf_dbl
  1213. movel #0x1,%d0 |inst is forced single
  1214. bras frcunf_rnd
  1215. frcunf_dbl:
  1216. movel #0x2,%d0 |inst is forced double
  1217. bras frcunf_rnd
  1218. frcunf_fpcr:
  1219. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  1220. frcunf_rnd:
  1221. bsrl unf_sub |get correct result based on
  1222. | ;round precision/mode.  This 
  1223. | ;sets FPSR_CC correctly
  1224. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1225. beqs frcfpn
  1226. bsetb #sign_bit,WBTEMP_EX(%a6)
  1227. bra frcfpn
  1228. |
  1229. | Write the result to the user's fpn.  All results must be HUGE to be
  1230. | written; otherwise the results would have overflowed or underflowed.
  1231. | If the rounding precision is single or double, the ovf_res routine
  1232. | is needed to correctly supply the max value.
  1233. |
  1234. frcfpnr:
  1235. movew CMDREG1B(%a6),%d0
  1236. btstl #6,%d0 |test for forced precision
  1237. beqs frcfpn_fpcr
  1238. btstl #2,%d0 |check for double
  1239. bnes frcfpn_dbl
  1240. movel #0x1,%d0 |inst is forced single
  1241. bras frcfpn_rnd
  1242. frcfpn_dbl:
  1243. movel #0x2,%d0 |inst is forced double
  1244. bras frcfpn_rnd
  1245. frcfpn_fpcr:
  1246. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  1247. tstb %d0
  1248. beqs frcfpn |if extended, write what you got
  1249. frcfpn_rnd:
  1250. bclrb #sign_bit,WBTEMP_EX(%a6)
  1251. sne WBTEMP_SGN(%a6)
  1252. bsrl ovf_res |get correct result based on
  1253. | ;round precision/mode.  This 
  1254. | ;sets FPSR_CC correctly
  1255. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1256. beqs frcfpn_clr
  1257. bsetb #sign_bit,WBTEMP_EX(%a6)
  1258. frcfpn_clr:
  1259. orl #ovfinx_mask,USER_FPSR(%a6)
  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