res_func.s
上传用户:baixin
上传日期:2008-03-13
资源大小:4795k
文件大小:54k
开发平台:

MultiPlatform

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