round.S 16 KB

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