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

VxWorks

开发平台:

C/C++

  1. /* bindec.s - Motorola 68040 FP binary/decimal conversion 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. 01e,21jul93,kdl  added .text (SPR #2372).
  10. 01d,23aug92,jcf  changed bxxx to jxx.
  11. 01c,26may92,rrr  the tree shuffle
  12. 01b,10jan92,kdl  general cleanup.
  13. 01b,01jan92,jcf  reversed order of cmp <reg>,<reg>
  14. 01a,12aug91,kdl  changed routine names which begin "Ax_" to aboid
  15.  confusion when converting to lower case reg names.
  16. */
  17. /*
  18. DESCRIPTION
  19. __x_bindecsa 3.4 1/3/91
  20. __x_bindec
  21. Description:
  22. Converts an input in extended precision format
  23. to bcd format.
  24. Input:
  25. a0 points to the input extended precision value
  26. value in memory|  d0 contains the k-factor sign-extended
  27. to 32-bits.  The input may be either normalized,
  28. unnormalized, or denormalized.
  29. Output: result in the FP_SCR1 space on the stack.
  30. Saves and Modifies: D2-D7,A2,FP2
  31. Algorithm:
  32. A1. Set RM and size ext|   Set SIGMA = sign of input.
  33. The k-factor is saved for use in d7. Clear the
  34. BINDEC_FLG for separating normalized/denormalized
  35. input.  If input is unnormalized or denormalized,
  36. normalize it.
  37. A2. Set X = abs(input).
  38. A3. Compute ILOG.
  39. ILOG is the log base 10 of the input value.  It is
  40. approximated by adding e + 0.f when the original
  41. value is viewed as 2^^e * 1.f in extended precision.
  42. This value is stored in d6.
  43. A4. Clr INEX bit.
  44. The operation in A3 above may have set INEX2.
  45. A5. Set ICTR = 0|
  46. ICTR is a flag used in A13.  It must be set before the
  47. loop entry A6.
  48. A6. Calculate LEN.
  49. LEN is the number of digits to be displayed.  The
  50. k-factor can dictate either the total number of digits,
  51. if it is a positive number, or the number of digits
  52. after the decimal point which are to be included as
  53. significant.  See the 68882 manual for examples.
  54. If LEN is computed to be greater than 17, set OPERR in
  55. USER_FPSR.  LEN is stored in d4.
  56. A7. Calculate SCALE.
  57. SCALE is equal to 10^ISCALE, where ISCALE is the number
  58. of decimal places needed to insure LEN integer digits
  59. in the output before conversion to bcd. LAMBDA is the
  60. sign of ISCALE, used in A9. Fp1 contains
  61. 10^^(abs(ISCALE)) using a rounding mode which is a
  62. function of the original rounding mode and the signs
  63. of ISCALE and X.  A table is given in the code.
  64. A8. Clr INEX|  Force RZ.
  65. The operation in A3 above may have set INEX2.
  66. RZ mode is forced for the scaling operation to insure
  67. only one rounding error.  The grs bits are collected in
  68. the INEX flag for use in A10.
  69. A9. Scale X -> Y.
  70. The mantissa is scaled to the desired number of
  71. significant digits.  The excess digits are collected
  72. in INEX2.
  73. A10. Or in INEX.
  74. If INEX is set, round error occured.  This is
  75. compensated for by 'or-ing' in the INEX2 flag to
  76. the lsb of Y.
  77. A11. Restore original fpcr|  set size ext.
  78. Perform FINT operation in the user's rounding mode.
  79. Keep the size to extended.
  80. A12. Calculate YINT = FINT(Y) according to user's rounding
  81. mode.  The FPSP routine __x_sintd0 is used.  The output
  82. is in fp0.
  83. A13. Check for LEN digits.
  84. If the int operation results in more than LEN digits,
  85. or less than LEN -1 digits, adjust ILOG and repeat from
  86. A6.  This test occurs only on the first pass.  If the
  87. result is exactly 10^LEN, decrement ILOG and divide
  88. the mantissa by 10.
  89. A14. Convert the mantissa to bcd.
  90. The __x_binstr routine is used to convert the LEN digit
  91. mantissa to bcd in memory.  The input to __x_binstr is
  92. to be a fraction|  i.e. (mantissa)/10^LEN and adjusted
  93. such that the decimal point is to the left of bit 63.
  94. The bcd digits are stored in the correct position in
  95. the final string area in memory.
  96. A15. Convert the exponent to bcd.
  97. As in A14 above, the exp is converted to bcd and the
  98. digits are stored in the final string.
  99. Test the length of the final exponent string.  If the
  100. length is 4, set operr.
  101. A16. Write sign bits to final string.
  102. Implementation Notes:
  103. The registers are used as follows:
  104. d0: scratch|  LEN input to __x_binstr
  105. d1: scratch
  106. d2: upper 32-bits of mantissa for __x_binstr
  107. d3: scratch| lower 32-bits of mantissa for __x_binstr
  108. d4: LEN
  109.        d5: LAMBDA/ICTR
  110. d6: ILOG
  111. d7: k-factor
  112. a0: ptr for original operand/final result
  113. a1: scratch pointer
  114. a2: pointer to FP_X|  abs(original value) in ext
  115. fp0: scratch
  116. fp1: scratch
  117. fp2: scratch
  118. F_SCR1:
  119. F_SCR2:
  120. L_SCR1:
  121. L_SCR2:
  122. Copyright (C) Motorola, Inc. 1990
  123. All Rights Reserved
  124. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
  125. The copyright notice above does not evidence any
  126. actual or intended publication of such source code.
  127. BINDEC    idnt    2,1 Motorola 040 Floating Point Software Package
  128. NOMANUAL
  129. */
  130. #include "fpsp040E.h"
  131. | section 8
  132. | Constants in extended precision
  133. LOG2:  .long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
  134. LOG2UP1: .long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
  135. | Constants in single precision
  136. FONE:  .long 0x3F800000,0x00000000,0x00000000,0x00000000
  137. FTWO: .long 0x40000000,0x00000000,0x00000000,0x00000000
  138. FTEN:  .long 0x41200000,0x00000000,0x00000000,0x00000000
  139. F4933: .long 0x459A2800,0x00000000,0x00000000,0x00000000
  140. RBDTBL:  .byte 0,0,0,0
  141. .byte 3,3,2,2
  142. .byte 3,2,2,3
  143. .byte 2,3,3,2
  144. | xref __x_binstr
  145. | xref __x_sintdo
  146. | xref ptenrn,ptenrm,ptenrp
  147. .globl __x_bindec
  148. .globl __x_sc_mul
  149. .text
  150. __x_bindec:
  151. moveml d2-d7/a2,a7@-
  152. fmovemx fp0-fp2,a7@-
  153. | A1. Set RM and size ext. Set SIGMA = sign input|
  154. |     The k-factor is saved for use in d7.  Clear BINDEC_FLG for
  155. |     separating  normalized/denormalized input.  If the input
  156. |     is a denormalized number, set the BINDEC_FLG memory word
  157. |     to signal denorm.  If the input is unnormalized, normalize
  158. |     the input and test for denormalized result.
  159. |
  160. fmovel #rm_mode,fpcr | set RM and ext
  161. movel a0@,a6@(L_SCR2) | save exponent for sign check
  162. movel d0,d7 | move k-factor to d7
  163. clrb a6@(BINDEC_FLG) | clr norm/denorm flag
  164. movew a6@(STAG),d0 | get stag
  165. andiw #0xe000,d0 | isolate stag bits
  166. jeq  __A2_str | if zero, input is norm
  167. |
  168. | Normalize the denorm
  169. |
  170. un_de_norm:
  171. movew a0@,d0
  172. andiw #0x7fff,d0 | strip sign of normalized exp
  173. movel a0@(4),d1
  174. movel a0@(8),d2
  175. __x_norm_loop:
  176. subw #1,d0
  177. lsll #1,d2
  178. roxll #1,d1
  179. tstl d1
  180. jge  __x_norm_loop
  181. |
  182. | Test if the normalized input is denormalized
  183. |
  184. tstw d0
  185. jgt  pos_exp | if greater than zero, it is a norm
  186. st a6@(BINDEC_FLG) | set flag for denorm
  187. pos_exp:
  188. andiw #0x7fff,d0 | strip sign of normalized exp
  189. movew d0,a0@
  190. movel d1,a0@(4)
  191. movel d2,a0@(8)
  192. | A2. Set X = abs(input).
  193. |
  194. __A2_str:
  195. movel a0@,a6@(FP_SCR2) |  move input to work space
  196. movel a0@(4),a6@(FP_SCR2+4) |  move input to work space
  197. movel a0@(8),a6@(FP_SCR2+8) |  move input to work space
  198. andil #0x7fffffff,a6@(FP_SCR2) | create abs(X)
  199. | A3. Compute ILOG.
  200. |     ILOG is the log base 10 of the input value.  It is approx-
  201. |     imated by adding e + 0.f when the original value is viewed
  202. |     as 2^^e * 1.f in extended precision.  This value is stored
  203. |     in d6.
  204. |
  205. | Register usage:
  206. | Input/Output
  207. | d0: k-factor/exponent
  208. | d2: x/x
  209. | d3: x/x
  210. | d4: x/x
  211. | d5: x/x
  212. | d6: x/ILOG
  213. | d7: k-factor/Unchanged
  214. | a0: ptr for original operand/final result
  215. | a1: x/x
  216. | a2: x/x
  217. | fp0: x/float(ILOG)
  218. | fp1: x/x
  219. | fp2: x/x
  220. | F_SCR1:x/x
  221. | F_SCR2:Abs(X)/Abs(X) with 0x3fff exponent
  222. | L_SCR1:x/x
  223. | L_SCR2:first word of X packed/Unchanged
  224. tstb a6@(BINDEC_FLG) | check for denorm
  225. jeq  __A3_cont | if clr, continue with norm
  226. movel #-4933,d6 | force ILOG = -4933
  227. jra  __A4_str
  228. __A3_cont:
  229. movew a6@(FP_SCR2),d0 | move exp to d0
  230. movew #0x3fff,a6@(FP_SCR2) | replace exponent with 0x3fff
  231. fmovex a6@(FP_SCR2),fp0 | now fp0 has 1.f
  232. subw #0x3fff,d0 | strip off bias
  233. faddw d0,fp0 | add in exp
  234. fsubs FONE,fp0 | subtract off 1.0
  235. fbge pos_res | if pos, branch
  236. fmulx LOG2UP1,fp0 | if neg, mul by LOG2UP1
  237. fmovel fp0,d6 | put ILOG in d6 as a lword
  238. jra  __A4_str | go move out ILOG
  239. pos_res:
  240. fmulx LOG2,fp0 | if pos, mul by LOG2
  241. fmovel fp0,d6 | put ILOG in d6 as a lword
  242. | A4. Clr INEX bit.
  243. |     The operation in A3 above may have set INEX2.
  244. __A4_str:
  245. fmovel #0,FPSR | zero all of fpsr - nothing needed
  246. | A5. Set ICTR = 0|
  247. |     ICTR is a flag used in A13.  It must be set before the
  248. |     loop entry A6. The lower word of d5 is used for ICTR.
  249. clrw d5 | clear ICTR
  250. | A6. Calculate LEN.
  251. |     LEN is the number of digits to be displayed.  The k-factor
  252. |     can dictate either the total number of digits, if it is
  253. |     a positive number, or the number of digits after the
  254. |     original decimal point which are to be included as
  255. |     significant.  See the 68882 manual for examples.
  256. |     If LEN is computed to be greater than 17, set OPERR in
  257. |     USER_FPSR.  LEN is stored in d4.
  258. |
  259. | Register usage:
  260. | Input/Output
  261. | d0: exponent/Unchanged
  262. | d2: x/x/scratch
  263. | d3: x/x
  264. | d4: exc picture/LEN
  265. | d5: ICTR/Unchanged
  266. | d6: ILOG/Unchanged
  267. | d7: k-factor/Unchanged
  268. | a0: ptr for original operand/final result
  269. | a1: x/x
  270. | a2: x/x
  271. | fp0: float(ILOG)/Unchanged
  272. | fp1: x/x
  273. | fp2: x/x
  274. | F_SCR1:x/x
  275. | F_SCR2:Abs(X) with 0x3fff exponent/Unchanged
  276. | L_SCR1:x/x
  277. | L_SCR2:first word of X packed/Unchanged
  278. __A6_str:
  279. tstl d7 | branch on sign of k
  280. jle  k_neg | if k <= 0, LEN = ILOG + 1 - k
  281. movel d7,d4 | if k > 0, LEN = k
  282. jra  len_ck | skip to LEN check
  283. k_neg:
  284. movel d6,d4 | first load ILOG to d4
  285. subl d7,d4 | subtract off k
  286. addql #1,d4 | add in the 1
  287. len_ck:
  288. tstl d4 | LEN check: branch on sign of LEN
  289. jle  LEN_ng | if neg, set LEN = 1
  290. cmpl #17,d4 | test if LEN > 17
  291. jle  __A7_str | if not, forget it
  292. movel #17,d4 | set max LEN = 17
  293. tstl d7 | if negative, never set OPERR
  294. jle  __A7_str | if positive, continue
  295. orl #opaop_mask,a6@(USER_FPSR) | set OPERR # AIOP in USER_FPSR
  296. jra  __A7_str | finished here
  297. LEN_ng:
  298. moveql #1,d4 | min LEN is 1
  299. | A7. Calculate SCALE.
  300. |     SCALE is equal to 10^ISCALE, where ISCALE is the number
  301. |     of decimal places needed to insure LEN integer digits
  302. |     in the output before conversion to bcd. LAMBDA is the sign
  303. |     of ISCALE, used in A9.  Fp1 contains 10^^(abs(ISCALE)) using
  304. |     the rounding mode as given in the following table (see
  305. |     Coonen, p. 7.23 as ref.|  however, the SCALE variable is
  306. |     of opposite sign in __x_bindecsa from Coonen).
  307. |
  308. | Initial USE
  309. | fpcr[6:5] LAMBDA SIGN(X) fpcr[6:5]
  310. | ----------------------------------------------
  311. |  RN 00    0    0 00/0 RN
  312. |  RN 00    0    1 00/0 RN
  313. |  RN 00    1    0 00/0 RN
  314. |  RN 00    1    1 00/0 RN
  315. |  RZ 01    0    0 11/3 RP
  316. |  RZ 01    0    1 11/3 RP
  317. |  RZ 01    1    0 10/2 RM
  318. |  RZ 01    1    1 10/2 RM
  319. |  RM 10    0    0 11/3 RP
  320. |  RM 10    0    1 10/2 RM
  321. |  RM 10    1    0 10/2 RM
  322. |  RM 10    1    1 11/3 RP
  323. |  RP 11    0    0 10/2 RM
  324. |  RP 11    0    1 11/3 RP
  325. |  RP 11    1    0 11/3 RP
  326. |  RP 11    1    1 10/2 RM
  327. |
  328. | Register usage:
  329. | Input/Output
  330. | d0: exponent/scratch - final is 0
  331. | d2: x/0 or 24 for A9
  332. | d3: x/scratch - offset ptr into __x_PTENRM array
  333. | d4: LEN/Unchanged
  334. | d5: 0/ICTR:LAMBDA
  335. | d6: ILOG/ILOG or k if ((k<=0)#(ILOG<k))
  336. | d7: k-factor/Unchanged
  337. | a0: ptr for original operand/final result
  338. | a1: x/ptr to __x_PTENRM array
  339. | a2: x/x
  340. | fp0: float(ILOG)/Unchanged
  341. | fp1: x/10^ISCALE
  342. | fp2: x/x
  343. | F_SCR1:x/x
  344. | F_SCR2:Abs(X) with 0x3fff exponent/Unchanged
  345. | L_SCR1:x/x
  346. | L_SCR2:first word of X packed/Unchanged
  347. __A7_str:
  348. tstl d7 | test sign of k
  349. jgt  k_pos | if pos and > 0, skip this
  350. cmpl d6,d7 | test ILOG - k
  351. jlt  k_pos | if ILOG >= k, skip this
  352. movel d7,d6 | if ((k<0) # (ILOG < k)) ILOG = k
  353. k_pos:
  354. movel d6,d0 | calc ILOG + 1 - LEN in d0
  355. addql #1,d0 | add the 1
  356. subl d4,d0 | sub off LEN
  357. swap d5 | use upper word of d5 for LAMBDA
  358. clrw d5 | set it zero initially
  359. clrw d2 | set up d2 for very small case
  360. tstl d0 | test sign of ISCALE
  361. jge  iscale | if pos, skip next inst
  362. addqw #1,d5 | if neg, set LAMBDA true
  363. cmpl #0xffffecd4,d0 | test iscale <= -4908
  364. jgt  no_inf | if false, skip rest
  365. addil #24,d0 | add in 24 to iscale
  366. movel #24,d2 | put 24 in d2 for A9
  367. no_inf:
  368. negl d0 | and take abs of ISCALE
  369. iscale:
  370. fmoves FONE,fp1 | init fp1 to 1
  371. bfextu a6@(USER_FPCR){#26:#2},d1 | get initial rmode bits
  372. lslw #1,d1 | put them in bits 2:1
  373. addw d5,d1 | add in LAMBDA
  374. lslw #1,d1 | put them in bits 3:1
  375. tstl a6@(L_SCR2) | test sign of original x
  376. jge  x_pos /* | if pos, don't set bit 0 */
  377. addql #1,d1 | if neg, set bit 0
  378. x_pos:
  379. lea RBDTBL,a2 | load rbdtbl base
  380. moveb a2@(d1),d3 | load d3 with new rmode
  381. lsll #4,d3 | put bits in proper position
  382. fmovel d3,fpcr | load bits into fpu
  383. lsrl #4,d3 | put bits in proper position
  384. tstb d3 | decode new rmode for pten table
  385. jne  not_rn | if zero, it is RN
  386. lea __x_PTENRN,a1 | load a1 with RN table base
  387. jra  rmode | exit decode
  388. not_rn:
  389. lsrb #1,d3 | get lsb in carry
  390. jcc  not_rp | if carry clear, it is RM
  391. lea __x_PTENRP,a1 | load a1 with RP table base
  392. jra  rmode | exit decode
  393. not_rp:
  394. lea __x_PTENRM,a1 | load a1 with RM table base
  395. rmode:
  396. clrl d3 | clr table index
  397. e_loop:
  398. lsrl #1,d0 | shift next bit into carry
  399. jcc  e_next | if zero, skip the mul
  400. fmulx a1@(d3),fp1 | mul by 10**(d3_bit_no)
  401. e_next:
  402. addl #12,d3 | inc d3 to next __x_pwrten table entry
  403. tstl d0 | test if ISCALE is zero
  404. jne  e_loop | if not, loop
  405. | A8. Clr INEX|  Force RZ.
  406. |     The operation in A3 above may have set INEX2.
  407. |     RZ mode is forced for the scaling operation to insure
  408. |     only one rounding error.  The grs bits are collected in
  409. |     the INEX flag for use in A10.
  410. |
  411. | Register usage:
  412. | Input/Output
  413. fmovel #0,FPSR | clr INEX
  414. fmovel #rz_mode,fpcr | set RZ rounding mode
  415. | A9. Scale X -> Y.
  416. |     The mantissa is scaled to the desired number of significant
  417. |     digits.  The excess digits are collected in INEX2. If mul,
  418. |     Check d2 for excess 10 exponential value.  If not zero,
  419. |     the iscale value would have caused the __x_pwrten calculation
  420. |     to overflow.  Only a negative iscale can cause this, so
  421. |     multiply by d2@(10^), which is now only allowed to be 24,
  422. |     with a multiply by 10^8 and 10^16, which is exact since
  423. |     10^24 is exact.  If the input was denormalized, we must
  424. |     create a busy stack frame with the mul command and the
  425. |     two operands, and allow the fpu to complete the multiply.
  426. |
  427. | Register usage:
  428. | Input/Output
  429. | d0: fpcr with RZ mode/Unchanged
  430. | d2: 0 or 24/unchanged
  431. | d3: x/x
  432. | d4: LEN/Unchanged
  433. | d5: ICTR:LAMBDA
  434. | d6: ILOG/Unchanged
  435. | d7: k-factor/Unchanged
  436. | a0: ptr for original operand/final result
  437. | a1: ptr to __x_PTENRM array/Unchanged
  438. | a2: x/x
  439. | fp0: float(ILOG)/X adjusted for SCALE (Y)
  440. | fp1: 10^ISCALE/Unchanged
  441. | fp2: x/x
  442. | F_SCR1:x/x
  443. | F_SCR2:Abs(X) with 0x3fff exponent/Unchanged
  444. | L_SCR1:x/x
  445. | L_SCR2:first word of X packed/Unchanged
  446. A9_str:
  447. fmovex a0@,fp0 | load X from memory
  448. fabsx fp0 | use abs(X)
  449. tstw d5 | LAMBDA is in lower word of d5
  450. jne  __x_sc_mul | if neg (LAMBDA = 0), scale by mul
  451. fdivx fp1,fp0 | calculate X / SCALE -> Y to fp0
  452. jra  __A10_st | branch to A10
  453. __x_sc_mul:
  454. tstb a6@(BINDEC_FLG) | check for denorm
  455. jeq  A9_norm | if norm, continue with mul
  456. fmovemx fp1-fp1,a7@- | load ETEMP with 10^ISCALE
  457. movel a0@(8),a7@- | load FPTEMP with input arg
  458. movel a0@(4),a7@-
  459. movel a0@,a7@-
  460. movel #18,d3 | load count for busy stack
  461. A9_loop:
  462. clrl a7@- | clear lword on stack
  463. dbf d3,A9_loop
  464. moveb a6@(VER_TMP),a7@  | write current version number
  465. moveb #BUSY_SIZE-4,a7@(1)  | write current busy size
  466. moveb #0x10,a7@(0x44) | set fcefpte[15] bit
  467. movew #0x0023,a7@(0x40) | load cmdreg1b with mul command
  468. moveb #0xfe,a7@(0x8) | load all 1s to cu savepc
  469. frestore a7@+ | restore frame to fpu for completion
  470. fmulx a1@(36),fp0 | multiply fp0 by 10^8
  471. fmulx a1@(48),fp0 | multiply fp0 by 10^16
  472. jra  __A10_st
  473. A9_norm:
  474. tstw d2 | test for small exp case
  475. jeq  A9_con | if zero, continue as normal
  476. fmulx a1@(36),fp0 | multiply fp0 by 10^8
  477. fmulx a1@(48),fp0 | multiply fp0 by 10^16
  478. A9_con:
  479. fmulx fp1,fp0 | calculate X * SCALE -> Y to fp0
  480. | A10. Or in INEX.
  481. |      If INEX is set, round error occured.  This is compensated
  482. /* |      for by 'or-ing' in the INEX2 flag to the lsb of Y. */
  483. |
  484. | Register usage:
  485. | Input/Output
  486. | d0: fpcr with RZ mode/FPSR with INEX2 isolated
  487. | d2: x/x
  488. | d3: x/x
  489. | d4: LEN/Unchanged
  490. | d5: ICTR:LAMBDA
  491. | d6: ILOG/Unchanged
  492. | d7: k-factor/Unchanged
  493. | a0: ptr for original operand/final result
  494. | a1: ptr to PTENxx array/Unchanged
  495. | a2: x/ptr to a6@(FP_SCR2)
  496. | fp0: Y/Y with lsb adjusted
  497. | fp1: 10^ISCALE/Unchanged
  498. | fp2: x/x
  499. __A10_st:
  500. fmovel FPSR,d0 | get FPSR
  501. fmovex fp0,a6@(FP_SCR2) | move Y to memory
  502. lea a6@(FP_SCR2),a2 | load a2 with ptr to FP_SCR2
  503. btst #9,d0 | check if INEX2 set
  504. jeq  __A11_st | if clear, skip rest
  505. oril #1,a2@(8) | or in 1 to lsb of mantissa
  506. fmovex a6@(FP_SCR2),fp0 | write adjusted Y back to fpu
  507. | A11. Restore original fpcr|  set size ext.
  508. /* |      Perform FINT operation in the user's rounding mode.  Keep */
  509. |      the size to extended.  The __x_sintdo entry point in the __x_sint
  510. |      routine expects the fpcr value to be in USER_FPCR for
  511. |      mode and precision.  The original fpcr is saved in L_SCR1.
  512. __A11_st:
  513. movel a6@(USER_FPCR),a6@(L_SCR1) | save it for later
  514. andil #0x00000030,a6@(USER_FPCR) | set size to ext,
  515. | | block exceptions
  516. /* | A12. Calculate YINT = FINT(Y) according to user's rounding mode. */
  517. |      The FPSP routine __x_sintd0 is used.  The output is in fp0.
  518. |
  519. | Register usage:
  520. | Input/Output
  521. | d0: FPSR with AINEX cleared/fpcr with size set to ext
  522. | d2: x/x/scratch
  523. | d3: x/x
  524. | d4: LEN/Unchanged
  525. | d5: ICTR:LAMBDA/Unchanged
  526. | d6: ILOG/Unchanged
  527. | d7: k-factor/Unchanged
  528. | a0: ptr for original operand/src ptr for __x_sintdo
  529. | a1: ptr to PTENxx array/Unchanged
  530. | a2: ptr to a6@(FP_SCR2)/Unchanged
  531. | a6: temp pointer to a6@(FP_SCR2) - orig value saved and restored
  532. | fp0: Y/YINT
  533. | fp1: 10^ISCALE/Unchanged
  534. | fp2: x/x
  535. | F_SCR1:x/x
  536. | F_SCR2:Y adjusted for inex/Y with original exponent
  537. | L_SCR1:x/original USER_FPCR
  538. | L_SCR2:first word of X packed/Unchanged
  539. __A12_st:
  540. moveml d0-d1/a0-a1,a7@- | save regs used by __x_sintd0
  541. movel a6@(L_SCR1),a7@-
  542. movel a6@(L_SCR2),a7@-
  543. lea a6@(FP_SCR2),a0 | a0 is ptr to a6@(F_SCR2)
  544. fmovex fp0,a0@ | move Y to memory at a6@(FP_SCR2)
  545. tstl a6@(L_SCR2) | test sign of original operand
  546. jge  do_fint | if pos, use Y
  547. orl #0x80000000,a0@ | if neg, use -Y
  548. do_fint:
  549. movel a6@(USER_FPSR),a7@-
  550. bsrl __x_sintdo | sint routine returns int in fp0
  551. moveb a7@,a6@(USER_FPSR)
  552. addl #4,a7
  553. movel a7@+,a6@(L_SCR2)
  554. movel a7@+,a6@(L_SCR1)
  555. moveml a7@+,d0-d1/a0-a1 | restore regs used by __x_sint
  556. movel a6@(L_SCR2),a6@(FP_SCR2) | restore original exponent
  557. movel a6@(L_SCR1),a6@(USER_FPCR) /* | restore user's fpcr */
  558. | A13. Check for LEN digits.
  559. |      If the int operation results in more than LEN digits,
  560. |      or less than LEN -1 digits, adjust ILOG and repeat from
  561. |      A6.  This test occurs only on the first pass.  If the
  562. |      result is exactly 10^LEN, decrement ILOG and divide
  563. |      the mantissa by 10.  The calculation of 10^LEN cannot
  564. |      be inexact, since all powers of ten upto 10^27 are exact
  565. |      in extended precision, so the use of a previous power-of-ten
  566. |      table will introduce no error.
  567. |
  568. |
  569. | Register usage:
  570. | Input/Output
  571. | d0: fpcr with size set to ext/scratch final = 0
  572. | d2: x/x
  573. | d3: x/scratch final = x
  574. | d4: LEN/LEN adjusted
  575. | d5: ICTR:LAMBDA/LAMBDA:ICTR
  576. | d6: ILOG/ILOG adjusted
  577. | d7: k-factor/Unchanged
  578. | a0: pointer into memory for packed bcd string formation
  579. | a1: ptr to PTENxx array/Unchanged
  580. | a2: ptr to a6@(FP_SCR2)/Unchanged
  581. | fp0: int portion of Y/abs(YINT) adjusted
  582. | fp1: 10^ISCALE/Unchanged
  583. | fp2: x/10^LEN
  584. | F_SCR1:x/x
  585. | F_SCR2:Y with original exponent/Unchanged
  586. | L_SCR1:original USER_FPCR/Unchanged
  587. | L_SCR2:first word of X packed/Unchanged
  588. __A13_st:
  589. swap d5 | put ICTR in lower word of d5
  590. tstw d5 | check if ICTR = 0
  591. jne  not_zr | if non-zero, go to second test
  592. |
  593. | Compute 10^(LEN-1)
  594. |
  595. fmoves FONE,fp2 | init fp2 to 1.0
  596. movel d4,d0 | put LEN in d0
  597. subql #1,d0 | d0 = LEN -1
  598. clrl d3 | clr table index
  599. l_loop:
  600. lsrl #1,d0 | shift next bit into carry
  601. jcc  l_next | if zero, skip the mul
  602. fmulx a1@(d3),fp2 | mul by 10**(d3_bit_no)
  603. l_next:
  604. addl #12,d3 | inc d3 to next __x_pwrten table entry
  605. tstl d0 | test if LEN is zero
  606. jne  l_loop | if not, loop
  607. |
  608. | 10^LEN-1 is computed for this test and A14.  If the input was
  609. | denormalized, check only the case in which YINT > 10^LEN.
  610. |
  611. tstb a6@(BINDEC_FLG) | check if input was norm
  612. jeq  __A13_con | if norm, continue with checking
  613. fabsx fp0 | take abs of YINT
  614. jra  test_2
  615. |
  616. | Compare abs(YINT) to 10^(LEN-1) and 10^LEN
  617. |
  618. __A13_con:
  619. fabsx fp0 | take abs of YINT
  620. fcmpx fp2,fp0 | compare abs(YINT) with 10^(LEN-1)
  621. fbge test_2 | if greater, do next test
  622. subql #1,d6 | subtract 1 from ILOG
  623. movew #1,d5 | set ICTR
  624. fmovel #rm_mode,fpcr | set rmode to RM
  625. fmuls FTEN,fp2 | compute 10^LEN
  626. jra  __A6_str | return to a6 and recompute YINT
  627. test_2:
  628. fmuls FTEN,fp2 | compute 10^LEN
  629. fcmpx fp2,fp0 | compare abs(YINT) with 10^LEN
  630. fblt __A14_st | if less, all is ok, go to A14
  631. fbgt fix_ex | if greater, fix and redo
  632. fdivs FTEN,fp0 | if equal, divide by 10
  633. addql #1,d6 |  and inc ILOG
  634. jra  __A14_st |  and continue elsewhere
  635. fix_ex:
  636. addql #1,d6 | increment ILOG by 1
  637. movew #1,d5 | set ICTR
  638. fmovel #rm_mode,fpcr | set rmode to RM
  639. jra  __A6_str | return to a6 and recompute YINT
  640. |
  641. | Since ICTR <> 0, we have already been through one adjustment,
  642. /* | and shouldn't have another|  this is to check if abs(YINT) = 10^LEN */
  643. | 10^LEN is again computed using whatever table is in a1 since the
  644. | value calculated cannot be inexact.
  645. |
  646. not_zr:
  647. fmoves FONE,fp2 | init fp2 to 1.0
  648. movel d4,d0 | put LEN in d0
  649. clrl d3 | clr table index
  650. z_loop:
  651. lsrl #1,d0 | shift next bit into carry
  652. jcc  z_next | if zero, skip the mul
  653. fmulx a1@(d3),fp2 | mul by 10**(d3_bit_no)
  654. z_next:
  655. addl #12,d3 | inc d3 to next __x_pwrten table entry
  656. tstl d0 | test if LEN is zero
  657. jne  z_loop | if not, loop
  658. fabsx fp0 | get abs(YINT)
  659. fcmpx fp2,fp0 | check if abs(YINT) = 10^LEN
  660. fbne __A14_st | if not, skip this
  661. fdivs FTEN,fp0 | divide abs(YINT) by 10
  662. addql #1,d6 | and inc ILOG by 1
  663. addql #1,d4 |  and inc LEN
  664. fmuls FTEN,fp2 |  if LEN++, the get 10^^LEN
  665. | A14. Convert the mantissa to bcd.
  666. |      The __x_binstr routine is used to convert the LEN digit
  667. |      mantissa to bcd in memory.  The input to __x_binstr is
  668. |      to be a fraction|  i.e. (mantissa)/10^LEN and adjusted
  669. |      such that the decimal point is to the left of bit 63.
  670. |      The bcd digits are stored in the correct position in
  671. |      the final string area in memory.
  672. |
  673. |
  674. | Register usage:
  675. | Input/Output
  676. | d0: x/LEN call to __x_binstr - final is 0
  677. | d1: x/0
  678. | d2: x/ms 32-bits of mant of abs(YINT)
  679. | d3: x/ls 32-bits of mant of abs(YINT)
  680. | d4: LEN/Unchanged
  681. | d5: ICTR:LAMBDA/LAMBDA:ICTR
  682. | d6: ILOG
  683. | d7: k-factor/Unchanged
  684. | a0: pointer into memory for packed bcd string formation
  685. |     /ptr to first mantissa byte in result string
  686. | a1: ptr to PTENxx array/Unchanged
  687. | a2: ptr to a6@(FP_SCR2)/Unchanged
  688. | fp0: int portion of Y/abs(YINT) adjusted
  689. | fp1: 10^ISCALE/Unchanged
  690. | fp2: 10^LEN/Unchanged
  691. | F_SCR1:x/Work area for final result
  692. | F_SCR2:Y with original exponent/Unchanged
  693. | L_SCR1:original USER_FPCR/Unchanged
  694. | L_SCR2:first word of X packed/Unchanged
  695. __A14_st:
  696. fmovel #rz_mode,fpcr | force rz for conversion
  697. fdivx fp2,fp0 | divide abs(YINT) by 10^LEN
  698. lea a6@(FP_SCR1),a0
  699. fmovex fp0,a0@ | move abs(YINT)/10^LEN to memory
  700. movel a0@(4),d2 | move 2nd word of FP_RES to d2
  701. movel a0@(8),d3 | move 3rd word of FP_RES to d3
  702. clrl a0@(4) | zero word 2 of FP_RES
  703. clrl a0@(8) | zero word 3 of FP_RES
  704. movel a0@,d0 | move exponent to d0
  705. swap d0 | put exponent in lower word
  706. jeq  no_sft /* | if zero, don't shift */
  707. subil #0x3ffd,d0 | sub bias less 2 to make fract
  708. tstl d0 | check if > 1
  709. jgt  no_sft /* | if so, don't shift */
  710. negl d0 | make exp positive
  711. m_loop:
  712. lsrl #1,d2 | shift d2:d3 right, add 0s
  713. roxrl #1,d3 | the number of places
  714. dbf d0,m_loop | given in d0
  715. no_sft:
  716. tstl d2 | check for mantissa of zero
  717. jne  no_zr | if not, go on
  718. tstl d3 | continue zero check
  719. jeq  zer_m | if zero, go directly to __x_binstr
  720. no_zr:
  721. clrl d1 | put zero in d1 for addx
  722. addil #0x00000080,d3 | inc at bit 7
  723. addxl d1,d2 | continue inc
  724. andil #0xffffff80,d3 | strip off lsb not used by 882
  725. zer_m:
  726. movel d4,d0 | put LEN in d0 for __x_binstr call
  727. addql #3,a0 | a0 points to M16 byte in result
  728. bsrl __x_binstr | call __x_binstr to convert mant
  729. | A15. Convert the exponent to bcd.
  730. |      As in A14 above, the exp is converted to bcd and the
  731. |      digits are stored in the final string.
  732. |
  733. |      Digits are stored in a6@(L_SCR1) on return from BINDEC as:
  734. |
  735. |    32               16 15                0
  736. | -----------------------------------------
  737. |   |  0 | e3 | e2 | e1 | e4 |  X |  X |  X |
  738. | -----------------------------------------
  739. |
  740. | And are moved into their proper places in FP_SCR1.  If digit e4
  741. | is non-zero, OPERR is signaled.  In all cases, all 4 digits are
  742. | written as specified in the 881/882 manual for packed decimal.
  743. |
  744. | Register usage:
  745. | Input/Output
  746. | d0: x/LEN call to __x_binstr - final is 0
  747. | d1: x/scratch (0)| shift count for final exponent packing
  748. | d2: x/ms 32-bits of exp fraction/scratch
  749. | d3: x/ls 32-bits of exp fraction
  750. | d4: LEN/Unchanged
  751. | d5: ICTR:LAMBDA/LAMBDA:ICTR
  752. | d6: ILOG
  753. | d7: k-factor/Unchanged
  754. | a0: ptr to result string/ptr to a6@(L_SCR1)
  755. | a1: ptr to PTENxx array/Unchanged
  756. | a2: ptr to a6@(FP_SCR2)/Unchanged
  757. | fp0: abs(YINT) adjusted/float(ILOG)
  758. | fp1: 10^ISCALE/Unchanged
  759. | fp2: 10^LEN/Unchanged
  760. | F_SCR1:Work area for final result/BCD result
  761. | F_SCR2:Y with original exponent/ILOG/10^4
  762. | L_SCR1:original USER_FPCR/Exponent digits on return from __x_binstr
  763. | L_SCR2:first word of X packed/Unchanged
  764. __A15_st:
  765. tstb a6@(BINDEC_FLG) | check for denorm
  766. jeq  not_denorm
  767. ftstx fp0 | test for zero
  768. fbeq den_zero | if zero, use k-factor or 4933
  769. fmovel d6,fp0 | float ILOG
  770. fabsx fp0 | get abs of ILOG
  771. jra  convrt
  772. den_zero:
  773. tstl d7 | check sign of the k-factor
  774. jlt  use_ilog | if negative, use ILOG
  775. fmoves F4933,fp0 | force exponent to 4933
  776. jra  convrt | do it
  777. use_ilog:
  778. fmovel d6,fp0 | float ILOG
  779. fabsx fp0 | get abs of ILOG
  780. jra  convrt
  781. not_denorm:
  782. ftstx fp0 | test for zero
  783. fbne not_zero | if zero, force exponent
  784. fmoves FONE,fp0 | force exponent to 1
  785. jra  convrt | do it
  786. not_zero:
  787. fmovel d6,fp0 | float ILOG
  788. fabsx fp0 | get abs of ILOG
  789. convrt:
  790. fdivx a1@(24),fp0 | compute ILOG/10^4
  791. fmovex fp0,a6@(FP_SCR2) | store fp0 in memory
  792. movel a2@(4),d2 | move word 2 to d2
  793. movel a2@(8),d3 | move word 3 to d3
  794. movew a2@,d0 | move exp to d0
  795. jeq  x_loop_fin | if zero, skip the shift
  796. subiw #0x3ffd,d0 | subtract off bias
  797. negw d0 | make exp positive
  798. x_loop:
  799. lsrl #1,d2 | shift d2:d3 right
  800. roxrl #1,d3 | the number of places
  801. dbf d0,x_loop | given in d0
  802. x_loop_fin:
  803. clrl d1 | put zero in d1 for addx
  804. addil #0x00000080,d3 | inc at bit 6
  805. addxl d1,d2 | continue inc
  806. andil #0xffffff80,d3 | strip off lsb not used by 882
  807. movel #4,d0 | put 4 in d0 for __x_binstr call
  808. lea a6@(L_SCR1),a0 | a0 is ptr to L_SCR1 for exp digits
  809. bsrl __x_binstr | call __x_binstr to convert exp
  810. movel a6@(L_SCR1),d0 | load L_SCR1 lword to d0
  811. movel #12,d1 | use d1 for shift count
  812. lsrl d1,d0 | shift d0 right by 12
  813. bfins d0,a6@(FP_SCR1){#4:#12} | put e3:e2:e1 in FP_SCR1
  814. lsrl d1,d0 | shift d0 right by 12
  815. bfins d0,a6@(FP_SCR1){#16:#4} | put e4 in FP_SCR1
  816. tstb d0 | check if e4 is zero
  817. jeq  __A16_st | if zero, skip rest
  818. orl #opaop_mask,a6@(USER_FPSR) | set OPERR # AIOP in USER_FPSR
  819. | A16. Write sign bits to final string.
  820. |    Sigma is bit 31 of initial value|  RHO is bit 31 of d6 (ILOG).
  821. |
  822. | Register usage:
  823. | Input/Output
  824. | d0: x/scratch - final is x
  825. | d2: x/x
  826. | d3: x/x
  827. | d4: LEN/Unchanged
  828. | d5: ICTR:LAMBDA/LAMBDA:ICTR
  829. | d6: ILOG/ILOG adjusted
  830. | d7: k-factor/Unchanged
  831. | a0: ptr to a6@(L_SCR1)/Unchanged
  832. | a1: ptr to PTENxx array/Unchanged
  833. | a2: ptr to a6@(FP_SCR2)/Unchanged
  834. | fp0: float(ILOG)/Unchanged
  835. | fp1: 10^ISCALE/Unchanged
  836. | fp2: 10^LEN/Unchanged
  837. | F_SCR1:BCD result with correct signs
  838. | F_SCR2:ILOG/10^4
  839. | L_SCR1:Exponent digits on return from __x_binstr
  840. | L_SCR2:first word of X packed/Unchanged
  841. __A16_st:
  842. clrl d0 | clr d0 for collection of signs
  843. andib #0x0f,a6@(FP_SCR1) | clear first nibble of FP_SCR1
  844. tstl a6@(L_SCR2) | check sign of original mantissa
  845. jge  mant_p /* | if pos, don't set SM */
  846. moveql #2,d0 | move 2 in to d0 for SM
  847. mant_p:
  848. tstl d6 | check sign of ILOG
  849. jge  wr_sgn /* | if pos, don't set SE */
  850. addql #1,d0 | set bit 0 in d0 for SE
  851. wr_sgn:
  852. bfins d0,a6@(FP_SCR1){#0:#2} | insert SM and SE into FP_SCR1
  853. | Clean up and restore all registers used.
  854. fmovel #0,FPSR | clear possible inex2/ainex bits
  855. fmovemx a7@+,fp0-fp2
  856. moveml a7@+,d2-d7/a2
  857. rts
  858. | end