l_round.s
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:17k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* l_round.s - Motorola 68040 FP rounding routines (LIB) */
  2. /* Copyright 1991-1993 Wind River Systems, Inc. */
  3. .data
  4. .globl _copyright_wind_river
  5. .long _copyright_wind_river
  6. /*
  7. modification history
  8. --------------------
  9. 01f,21jul93,kdl  added .text (SPR #2372).
  10. 01e,23aug92,jcf  changed bxxx to jxx.
  11. 01d,26may92,rrr  the tree shuffle
  12. 01c,01jan92,jcf reversed order of cmp <reg>,<reg>
  13. 01b,17dec91,kdl put in changes from Motorola v3.4 (from FPSP 2.1):
  14. add check for negative loop count in __l_dnrm_lp.
  15. 01a,31jul91,kdl from Motorola FPSP v2.0.
  16. */
  17. /*
  18. DESCRIPTION
  19. roundsa 3.2 2/18/91
  20. handle rounding and normalization tasks
  21. Copyright (C) Motorola, Inc. 1990
  22. All Rights Reserved
  23. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
  24. The copyright notice above does not evidence any
  25. actual or intended publication of such source code.
  26. ROUND idnt    2,1 Motorola 040 Floating Point Software Package
  27. section 8
  28. NOMANUAL
  29. */
  30. #include "fpsp040L.h"
  31. |
  32. | __l_round --- round result according to precision/mode
  33. |
  34. | a0 points to the input operand in the internal extended format
  35. | d1(high word) contains rounding precision:
  36. | ext = 0x0000xxxx
  37. | sgl = 0x0001xxxx
  38. | dbl = 0x0002xxxx
  39. | d1(low word) contains rounding mode:
  40. | RN  = $xxxx0000
  41. | RZ  = $xxxx0001
  42. | RM  = $xxxx0010
  43. | RP  = $xxxx0011
  44. | d0{31:29} contains the g,r,s bits (extended)
  45. |
  46. | On return the value pointed to by a0 is correctly rounded,
  47. | a0 is preserved and the g-r-s bits in d0 are cleared.
  48. | The result is not typed - the tag field is invalid.  The
  49. | result is still in the internal extended format.
  50. |
  51. | The INEX bit of USER_FPSR will be set if the rounded result was
  52. | inexact (i.e. if any of the g-r-s bits were set).
  53. |
  54. .text
  55. .globl __l_round
  56. __l_round:
  57. | If g=r=s=0 then result is exact and round is done, else set
  58. | the inex flag in status reg and continue.
  59. |
  60. bsrl ext_grs | this subroutine looks at the
  61. | | rounding precision and sets
  62. | | the appropriate g-r-s bits.
  63. tstl d0 | if grs are zero, go force
  64. jne  rnd_cont | lower bits to zero for size
  65. swap d1 | set up d1:w for round prec.
  66. jra  truncate
  67. rnd_cont:
  68. |
  69. | Use rounding mode as an index into a jump table for these modes.
  70. |
  71. orl #inx2a_mask,a6@(USER_FPSR) | set inex2/ainex
  72. lea mode_tab,a1
  73. movel a1@(d1:w:4),a1
  74. jmp a1@
  75. |
  76. | Jump table indexed by rounding mode in d1:w.  All following assumes
  77. | grs != 0.
  78. |
  79. mode_tab:
  80. .long rnd_near
  81. .long rnd_zero
  82. .long rnd_mnus
  83. .long rnd_plus
  84. |
  85. | ROUND PLUS INFINITY
  86. |
  87. | If sign of fp number = 0 (positive), then add 1 to l.
  88. |
  89. rnd_plus:
  90. swap  d1 | set up d1 for round prec.
  91. tstb a0@(LOCAL_SGN) | check for sign
  92. jmi  truncate | if positive then truncate
  93. movel #0xffffffff,d0 /* | force g,r,s to be all f's */
  94. lea add_to_l,a1
  95. movel a1@(d1:w:4),a1
  96. jmp a1@
  97. |
  98. | ROUND MINUS INFINITY
  99. |
  100. | If sign of fp number = 1 (negative), then add 1 to l.
  101. |
  102. rnd_mnus:
  103. swap  d1 | set up d1 for round prec.
  104. tstb a0@(LOCAL_SGN) | check for sign
  105. jpl  truncate | if negative then truncate
  106. movel #0xffffffff,d0 /* | force g,r,s to be all f's */
  107. lea add_to_l,a1
  108. movel a1@(d1:w:4),a1
  109. jmp a1@
  110. |
  111. | ROUND ZERO
  112. |
  113. | Always truncate.
  114. rnd_zero:
  115. swap  d1 | set up d1 for round prec.
  116. jra  truncate
  117. |
  118. |
  119. | ROUND NEAREST
  120. |
  121. | If (g=1), then add 1 to l and if (r=s=0), then clear l
  122. | Note that this will round to even in case of a tie.
  123. |
  124. rnd_near:
  125. swap  d1 | set up d1 for round prec.
  126. asll #1,d0 | shift g-bit to c-bit
  127. jcc  truncate | if (g=1) then
  128. lea add_to_l,a1
  129. movel a1@(d1:w:4),a1
  130. jmp a1@
  131. |
  132. | ext_grs --- extract guard, round and sticky bits
  133. |
  134. | Input: d1 = PREC:ROUND
  135. | Output:   d0{31:29}= guard, round, sticky
  136. |
  137. | The ext_grs extract the guard/round/sticky bits according to the
  138. | selected rounding precision. It is called by the round subroutine
  139. | only.  All registers except d0 are kept intact. d0 becomes an
  140. | updated guard,round,sticky in d0{31:29}
  141. |
  142. | Notes: the ext_grs uses the round PREC, and therefore has to swap d1
  143. |  prior to usage, and needs to restore d1 to original.
  144. |
  145. ext_grs:
  146. swap d1 | have d1:w point to round precision
  147. cmpiw #0,d1
  148. jne  sgl_or_dbl
  149. jra  end_ext_grs
  150. sgl_or_dbl:
  151. moveml d2/d3,a7@- | make some temp registers
  152. cmpiw #1,d1
  153. jne  grs_dbl
  154. grs_sgl:
  155. bfextu a0@(LOCAL_HI){#24:#2},d3 | sgl prec. g-r are 2 bits right
  156. movel #30,d2 | of the sgl prec. limits
  157. lsll d2,d3 | shift g-r bits to MSB of d3
  158. movel a0@(LOCAL_HI),d2 | get word 2 for s-bit test
  159. andil #0x0000003f,d2 | s bit is the or of all other
  160. jne  st_stky | bits to the right of g-r
  161. tstl a0@(LOCAL_LO) | test lower mantissa
  162. jne  st_stky | if any are set, set sticky
  163. tstl d0 | test original g,r,s
  164. jne  st_stky | if any are set, set sticky
  165. jra  end_sd | if words 3 and 4 are clr, exit
  166. grs_dbl:
  167. bfextu a0@(LOCAL_LO){#21:#2},d3 | dbl-prec. g-r are 2 bits right
  168. movel #30,d2 | of the dbl prec. limits
  169. lsll d2,d3 | shift g-r bits to MSB of d3
  170. movel a0@(LOCAL_LO),d2 | get lower mantissa  for s-bit test
  171. andil #0x000001ff,d2 | s bit is the or-ing of all
  172. jne  st_stky | other bits to the right of g-r
  173. tstl d0 | test word original g,r,s
  174. jne  st_stky | if any are set, set sticky
  175. jra  end_sd | if clear, exit
  176. st_stky:
  177. bset #rnd_stky_bit,d3
  178. end_sd:
  179. movel d3,d0 | return grs to d0
  180. moveml a7@+,d2/d3 | restore scratch registers
  181. end_ext_grs:
  182. swap d1 | restore d1 to original
  183. rts
  184. |*******************  Local Equates
  185. #define ad_1_sgl  0x00000100 /* constant to add 1 to l-bit in sgl prec */
  186. #define ad_1_dbl  0x00000800 /* constant to add 1 to l-bit in dbl prec */
  187. |Jump table for adding 1 to the l-bit indexed by rnd prec
  188. add_to_l:
  189. .long add_ext
  190. .long add_sgl
  191. .long add_dbl
  192. .long add_dbl
  193. |
  194. | ADD SINGLE
  195. |
  196. add_sgl:
  197. addl #ad_1_sgl,a0@(LOCAL_HI)
  198. jcc  scc_clr | no mantissa overflow
  199. roxrw  a0@(LOCAL_HI) | shift v-bit back in
  200. roxrw  a0@(LOCAL_HI+2) | shift v-bit back in
  201. addw #0x1,a0@(LOCAL_EX) | and incr exponent
  202. scc_clr:
  203. tstl d0 | test for rs = 0
  204. jne  sgl_done
  205. andiw  #0xfe00,a0@(LOCAL_HI+2) | clear the l-bit
  206. sgl_done:
  207. andil #0xffffff00,a0@(LOCAL_HI) | truncate bits beyond sgl limit
  208. clrl a0@(LOCAL_LO) | clear d2
  209. rts
  210. |
  211. | ADD EXTENDED
  212. |
  213. add_ext:
  214. addql  #1,a0@(LOCAL_LO) | add 1 to l-bit
  215. jcc  xcc_clr | test for carry out
  216. addql  #1,a0@(LOCAL_HI) | propogate carry
  217. jcc  xcc_clr
  218. roxrw  a0@(LOCAL_HI) | mant is 0 so restore v-bit
  219. roxrw  a0@(LOCAL_HI+2) | mant is 0 so restore v-bit
  220. roxrw a0@(LOCAL_LO)
  221. roxrw a0@(LOCAL_LO+2)
  222. addw #0x1,a0@(LOCAL_EX) | and inc exp
  223. xcc_clr:
  224. tstl d0 | test rs = 0
  225. jne  add_ext_done
  226. andib #0xfe,a0@(LOCAL_LO+3) | clear the l bit
  227. add_ext_done:
  228. rts
  229. |
  230. | ADD DOUBLE
  231. |
  232. add_dbl:
  233. addl #ad_1_dbl,a0@(LOCAL_LO)
  234. jcc  dcc_clr
  235. addql #1,a0@(LOCAL_HI) | propogate carry
  236. jcc  dcc_clr
  237. roxrw a0@(LOCAL_HI) | mant is 0 so restore v-bit
  238. roxrw a0@(LOCAL_HI+2) | mant is 0 so restore v-bit
  239. roxrw a0@(LOCAL_LO)
  240. roxrw a0@(LOCAL_LO+2)
  241. addw #0x1,a0@(LOCAL_EX) | incr exponent
  242. dcc_clr:
  243. tstl d0 | test for rs = 0
  244. jne  dbl_done
  245. andiw #0xf000,a0@(LOCAL_LO+2) | clear the l-bit
  246. dbl_done:
  247. andil #0xfffff800,a0@(LOCAL_LO) | truncate bits beyond dbl limit
  248. rts
  249. error:
  250. rts
  251. |
  252. | Truncate all other bits
  253. |
  254. trunct:
  255. .long end_rnd
  256. .long sgl_done
  257. .long dbl_done
  258. .long dbl_done
  259. truncate:
  260. lea trunct,a1
  261. movel a1@(d1:w:4),a1
  262. jmp a1@
  263. end_rnd:
  264. rts
  265. |
  266. | NORMALIZE
  267. |
  268. | These routines (nrm_zero # __l_nrm_set) normalize the unnorm.  This
  269. | is done by shifting the mantissa left while decrementing the
  270. | exponent.
  271. |
  272. | NRM_SET shifts and decrements until there is a 1 set in the integer
  273. | bit of the mantissa (msb in d1).
  274. |
  275. | NRM_ZERO shifts and decrements until there is a 1 set in the integer
  276. | bit of the mantissa (msb in d1) unless this would mean the exponent
  277. | would go less than 0.  In that case the number becomes a denorm - the
  278. | exponent d0@ is set to 0 and the mantissa (d1 # d2) is not
  279. | normalized.
  280. |
  281. | Note that both routines have been optimized (for the worst case) and
  282. | therefore do not have the easy to follow decrement/shift loop.
  283. |
  284. | NRM_ZERO
  285. |
  286. | Distance to first 1 bit in mantissa = X
  287. | Distance to 0 from exponent = Y
  288. | If X < Y
  289. | Then
  290. |   __l_nrm_set
  291. | Else
  292. |   shift mantissa by Y
  293. |   set exponent = 0
  294. |
  295. |input:
  296. | FP_SCR1 = exponent, ms mantissa part, ls mantissa part
  297. |output:
  298. | L_SCR1{4} = fpte15 or ete15 bit
  299. |
  300. .globl __l_nrm_zero
  301. __l_nrm_zero:
  302. movew a0@(LOCAL_EX),d0
  303. cmpw   #64,d0          | see if exp > 64
  304. jmi  d0_less
  305. bsrl __l_nrm_set /* | exp > 64 so exp won't exceed 0  */
  306. rts
  307. d0_less:
  308. moveml d2/d3/d5/d6,a7@-
  309. movel a0@(LOCAL_HI),d1
  310. movel a0@(LOCAL_LO),d2
  311. bfffo d1{#0:#32},d3 | get the distance to the first 1
  312. | | in ms mant
  313. jeq  ms_clr | branch if no bits were set
  314. cmpw d3,d0 | of X>Y
  315. jmi  greater | then exp will go past 0 (neg) if
  316. | | it is just shifted
  317. bsrl __l_nrm_set /* | else exp won't go past 0 */
  318. moveml a7@+,d2/d3/d5/d6
  319. rts
  320. greater:
  321. movel d2,d6 | save ls mant in d6
  322. lsll d0,d2 | shift ls mant by count
  323. lsll d0,d1 | shift ms mant by count
  324. movel #32,d5
  325. subl d0,d5 | make op a denorm by shifting bits
  326. lsrl d5,d6 | by the number in the exp, then
  327. | | set exp = 0.
  328. orl d6,d1 | shift the ls mant bits into the ms mant
  329. movel #0,d0 | same as if decremented exp to 0
  330. | | while shifting
  331. movew d0,a0@(LOCAL_EX)
  332. movel d1,a0@(LOCAL_HI)
  333. movel d2,a0@(LOCAL_LO)
  334. moveml a7@+,d2/d3/d5/d6
  335. rts
  336. ms_clr:
  337. bfffo d2{#0:#32},d3 | check if any bits set in ls mant
  338. jeq  all_clr | branch if none set
  339. addw #32,d3
  340. cmpw d3,d0 | if X>Y
  341. jmi  greater | then branch
  342. bsrl __l_nrm_set /* | else exp won't go past 0 */
  343. moveml a7@+,d2/d3/d5/d6
  344. rts
  345. all_clr:
  346. movew #0,a0@(LOCAL_EX) | no mantissa bits set. Set exp = 0.
  347. moveml a7@+,d2/d3/d5/d6
  348. rts
  349. |
  350. | NRM_SET
  351. |
  352. .globl __l_nrm_set
  353. __l_nrm_set:
  354. movel d7,a7@-
  355. bfffo a0@(LOCAL_HI){#0:#32},d7 | find first 1 in ms mant to d7)
  356. jeq  lower /* | branch if ms mant is all 0's */
  357. movel d6,a7@-
  358. subw d7,a0@(LOCAL_EX) | sub exponent by count
  359. movel a0@(LOCAL_HI),d0 | d0 has ms mant
  360. movel a0@(LOCAL_LO),d1  | d1 has ls mant
  361. lsll d7,d0 | shift first 1 to j bit position
  362. movel d1,d6 | copy ls mant into d6
  363. lsll d7,d6 | shift ls mant by count
  364. movel d6,a0@(LOCAL_LO) | store ls mant into memory
  365. moveql #32,d6
  366. subl d7,d6 | continue shift
  367. lsrl d6,d1 | shift off all bits but those that will
  368. | | be shifted into ms mant
  369. orl d1,d0 | shift the ls mant bits into ms mant
  370. movel d0,a0@(LOCAL_HI) | store ms mant into memory
  371. moveml a7@+,d7/d6 | restore registers
  372. rts
  373. |
  374. | We get here if ms mant was = 0, and we assume ls mant has bits
  375. | set (otherwise this would have been tagged a zero not a denorm).
  376. |
  377. lower:
  378. movew a0@(LOCAL_EX),d0 | d0 has exponent
  379. movel a0@(LOCAL_LO),d1 | d1 has ls mant
  380. subw #32,d0 | account for ms mant being all zeros
  381. bfffo d1{#0:#32},d7 | find first 1 in ls mant to d7)
  382. subw d7,d0 | subtract shift count from exp
  383. lsll d7,d1 | shift 1st 1 to integer bit in ms mant
  384. movew d0,a0@(LOCAL_EX) | store ms mant
  385. movel d1,a0@(LOCAL_HI) | store exp
  386. clrl a0@(LOCAL_LO) | clear ls mant
  387. movel a7@+,d7
  388. rts
  389. |
  390. | __l_denorm --- denormalize an intermediate result
  391. |
  392. | Used by underflow.
  393. |
  394. | Input:
  395. | a0  points to the operand to be denormalized
  396. |  (in the internal extended format)
  397. |
  398. | d0:   rounding precision
  399. | Output:
  400. | a0  points to the denormalized result
  401. |  (in the internal extended format)
  402. |
  403. | d0  is guard,round,sticky
  404. |
  405. | d0 comes into this routine with the rounding precision. It
  406. | is then loaded with the denormalized exponent threshold for the
  407. | rounding precision.
  408. |
  409. .globl __l_denorm
  410. __l_denorm:
  411. btst #6,a0@(LOCAL_EX) | check for exponents between 0x7fff-0x4000
  412. jeq  no_sgn_ext
  413. bset #7,a0@(LOCAL_EX) | sign extend if it is so
  414. no_sgn_ext:
  415. cmpib #0,d0 | if 0 then extended precision
  416. jne  not_ext | else branch
  417. clrl d1 | load d1 with ext threshold
  418. clrl d0 | clear the sticky flag
  419. bsrl __l_dnrm_lp | denormalize the number
  420. tstb d1 | check for inex
  421. jeq  no_inex | if clr, no inex
  422. jra  dnrm_inex | if set, set inex
  423. not_ext:
  424. cmpil #1,d0 | if 1 then single precision
  425. jeq  load_sgl | else must be 2, double prec
  426. load_dbl:
  427. movew #dbl_thresh,d1 | put copy of threshold in d1
  428. movel d1,d0 | copy d1 into d0
  429. subw a0@(LOCAL_EX),d0 | diff = threshold - exp
  430. cmpw #67,d0 | if diff > 67 (mant + grs bits)
  431. jpl  chk_stky | then branch (all bits would be
  432. | |  shifted off in __l_denorm routine)
  433. clrl d0 | else clear the sticky flag
  434. bsrl __l_dnrm_lp | denormalize the number
  435. tstb d1 | check flag
  436. jeq  no_inex | if clr, no inex
  437. jra  dnrm_inex | if set, set inex
  438. load_sgl:
  439. movew #sgl_thresh,d1 | put copy of threshold in d1
  440. movel d1,d0 | copy d1 into d0
  441. subw a0@(LOCAL_EX),d0 | diff = threshold - exp
  442. cmpw #67,d0 | if diff > 67 (mant + grs bits)
  443. jpl  chk_stky | then branch (all bits would be
  444. | |  shifted off in __l_denorm routine)
  445. clrl d0 | else clear the sticky flag
  446. bsrl __l_dnrm_lp | denormalize the number
  447. tstb d1 | check flag
  448. jeq  no_inex | if clr, no inex
  449. jra  dnrm_inex | if set, set inex
  450. chk_stky:
  451. tstl a0@(LOCAL_HI) | check for any bits set
  452. jne  set_stky
  453. tstl a0@(LOCAL_LO) | check for any bits set
  454. jne  set_stky
  455. jra  clr_mant
  456. set_stky:
  457. orl #inx2a_mask,a6@(USER_FPSR) | set inex2/ainex
  458. movel #0x20000000,d0 | set sticky bit in return value
  459. clr_mant:
  460. movew d1,a0@(LOCAL_EX) | load exp with threshold
  461. movel #0,a0@(LOCAL_HI)  | set d1 = 0 (ms mantissa)
  462. movel #0,a0@(LOCAL_LO) | set d2 = 0 (ms mantissa)
  463. rts
  464. dnrm_inex:
  465. orl #inx2a_mask,a6@(USER_FPSR) | set inex2/ainex
  466. no_inex:
  467. rts
  468. |
  469. | __l_dnrm_lp --- normalize exponent/mantissa to specified threshhold
  470. |
  471. | Input:
  472. | a0 points to the operand to be denormalized
  473. | d0{31:29}  initial guard,round,sticky
  474. | d1{15:0} denormalization threshold
  475. | Output:
  476. | a0 points to the denormalized operand
  477. | d0{31:29} final guard,round,sticky
  478. | d1b inexact flag:  all ones means inexact result
  479. |
  480. | The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2
  481. | so that bfext can be used to extract the new low part of the mantissa.
  482. | Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there
  483. | is no LOCAL_GRS scratch word following it on the fsave frame.
  484. |
  485. .globl __l_dnrm_lp
  486. __l_dnrm_lp:
  487. movel d2,a7@- | save d2 for temp use
  488. movel a7@+,d2 | restore d2
  489. movel a0@(LOCAL_LO),a6@(FP_SCR2+LOCAL_LO)
  490. movel d0,a6@(FP_SCR2+LOCAL_GRS)
  491. movel d1,d0 | copy the denorm threshold
  492. subw a0@(LOCAL_EX),d1 | d1 = threshold - uns exponent
  493. jle  no_lp | d1 <= 0
  494. cmpw #32,d1
  495. jlt  case_1 | 0 = d1 < 32
  496. cmpw #64,d1
  497. jlt  case_2 | 32 <= d1 < 64
  498. jra  case_3 | d1 >= 64
  499. |
  500. | No normalization necessary
  501. |
  502. no_lp:
  503. clrb d1 | set no inex2 reported
  504. movel a6@(FP_SCR2+LOCAL_GRS),d0 | restore original g,r,s
  505. rts
  506. |
  507. | case (0<d1<32)
  508. |
  509. case_1:
  510. movel d2,a7@-
  511. movew d0,a0@(LOCAL_EX) | exponent = denorm threshold
  512. movel #32,d0
  513. subw d1,d0 | d0 = 32 - d1
  514. bfextu a0@(LOCAL_EX){d0:#32},d2
  515. bfextu d2{d1:d0},d2 | d2 = new LOCAL_HI
  516. bfextu a0@(LOCAL_HI){d0:#32},d1 | d1 = new LOCAL_LO
  517. bfextu a6@(FP_SCR2+LOCAL_LO){d0:#32},d0 | d0 = new G,R,S
  518. movel d2,a0@(LOCAL_HI) | store new LOCAL_HI
  519. movel d1,a0@(LOCAL_LO) | store new LOCAL_LO
  520. clrb d1
  521. bftst d0{#2:#30}
  522. jeq  c1nstky
  523. bset #rnd_stky_bit,d0
  524. st d1
  525. c1nstky:
  526. movel a6@(FP_SCR2+LOCAL_GRS),d2 | restore original g,r,s
  527. andil #0xe0000000,d2 | clear all but G,R,S
  528. tstl d2 | test if original G,R,S are clear
  529. jeq  grs_clear
  530. orl #0x20000000,d0 | set sticky bit in d0
  531. grs_clear:
  532. andil #0xe0000000,d0 | clear all but G,R,S
  533. movel a7@+,d2
  534. rts
  535. |
  536. | case (32<=d1<64)
  537. |
  538. case_2:
  539. movel d2,a7@-
  540. movew d0,a0@(LOCAL_EX) | unsigned exponent = threshold
  541. subw #32,d1 | d1 now between 0 and 32
  542. movel #32,d0
  543. subw d1,d0 | d0 = 32 - d1
  544. bfextu a0@(LOCAL_EX){d0:#32},d2
  545. bfextu d2{d1:d0},d2 | d2 = new LOCAL_LO
  546. bfextu a0@(LOCAL_HI){d0:#32},d1 | d1 = new G,R,S
  547. bftst d1{#2:#30}
  548. jne  c2_sstky | jra  if sticky bit to be set
  549. bftst a6@(FP_SCR2+LOCAL_LO){d0:#32}
  550. jne  c2_sstky | jra  if sticky bit to be set
  551. movel d1,d0
  552. clrb d1
  553. jra  end_c2
  554. c2_sstky:
  555. movel d1,d0
  556. bset #rnd_stky_bit,d0
  557. st d1
  558. end_c2:
  559. clrl a0@(LOCAL_HI) | store LOCAL_HI = 0
  560. movel d2,a0@(LOCAL_LO) | store LOCAL_LO
  561. movel a6@(FP_SCR2+LOCAL_GRS),d2 | restore original g,r,s
  562. andil #0xe0000000,d2 | clear all but G,R,S
  563. tstl d2 | test if original G,R,S are clear
  564. jeq  clear_grs
  565. orl #0x20000000,d0 | set sticky bit in d0
  566. clear_grs:
  567. andil #0xe0000000,d0 | get rid of all but G,R,S
  568. movel a7@+,d2
  569. rts
  570. |
  571. | d1 >= 64 Force the exponent to be the denorm threshold with the
  572. | correct sign.
  573. |
  574. case_3:
  575. movew d0,a0@(LOCAL_EX)
  576. tstw a0@(LOCAL_SGN)
  577. jge  c3con
  578. c3neg:
  579. orl #0x80000000,a0@(LOCAL_EX)
  580. c3con:
  581. cmpw #64,d1
  582. jeq  sixty_four
  583. cmpw #65,d1
  584. jeq  sixty_five
  585. |
  586. | Shift value is out of range.  Set d1 for inex2 flag and
  587. | return a zero with the given threshold.
  588. |
  589. clrl a0@(LOCAL_HI)
  590. clrl a0@(LOCAL_LO)
  591. movel #0x20000000,d0
  592. st d1
  593. rts
  594. sixty_four:
  595. movel a0@(LOCAL_HI),d0
  596. bfextu d0{#2:#30},d1
  597. andil #0xc0000000,d0
  598. jra  c3com
  599. sixty_five:
  600. movel a0@(LOCAL_HI),d0
  601. bfextu d0{#1:#31},d1
  602. andil #0x80000000,d0
  603. lsrl #1,d0 | shift high bit into R bit
  604. c3com:
  605. tstl d1
  606. jne  c3ssticky
  607. tstl a0@(LOCAL_LO)
  608. jne  c3ssticky
  609. tstb a6@(FP_SCR2+LOCAL_GRS)
  610. jne  c3ssticky
  611. clrb d1
  612. jra  c3end
  613. c3ssticky:
  614. bset #rnd_stky_bit,d0
  615. st d1
  616. c3end:
  617. clrl a0@(LOCAL_HI)
  618. clrl a0@(LOCAL_LO)
  619. rts
  620. | end