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

VxWorks

开发平台:

C/C++

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