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

VxWorks

开发平台:

C/C++

  1. /* decbin.s - Motorola 68040 FP BCD/binary 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  added modification history; general cleanup.
  13. 01a,15aug91,kdl  original version, from Motorola FPSP v2.0.
  14. */
  15. /*
  16. DESCRIPTION
  17. __x_decbinsa 3.3 12/19/90
  18. Description: Converts normalized packed bcd value pointed to by
  19. register A6 to extended-precision value in FP0.
  20. Input: Normalized packed bcd value in a6@(ETEMP).
  21. Output: Exact floating-point representation of the packed bcd value.
  22. Saves and Modifies: D2-D5
  23. Speed: The program __x_decbin takes ??? cycles to execute.
  24. Object Size:
  25. External Reference(s): None.
  26. Algorithm:
  27. Expected is a normal bcd (i.e. non-exceptional|  all inf, zero,
  28. and NaN operands are dispatched without entering this routine)
  29. value in 68881/882 format at location A6@(ETEMP).
  30. A1. Convert the bcd exponent to binary by successive adds and muls.
  31. Set the sign according to SE. Subtract 16 to compensate
  32. for the mantissa which is to be interpreted as 17 integer
  33. digits, rather than 1 integer and 16 fraction digits.
  34. Note: this operation can never overflow.
  35. A2. Convert the bcd mantissa to binary by successive
  36. adds and muls in FP0. Set the sign according to SM.
  37. The mantissa digits will be converted with the decimal point
  38. assumed following the least-significant digit.
  39. Note: this operation can never overflow.
  40. A3. Count the number of leading/trailing zeros in the
  41. bcd string.  If SE is positive, count the leading zeros|
  42. if negative, count the trailing zeros.  Set the adjusted
  43. exponent equal to the exponent from A1 and the zero count
  44. added if SM = 1 and subtracted if SM = 0.  Scale the
  45. mantissa the equivalent of forcing in the bcd value:
  46. SM = 0 a non-zero digit in the integer position
  47. SM = 1 a non-zero digit in Mant0, lsd of the fraction
  48. this will insure that any value, regardless of its
  49. representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted
  50. consistently.
  51. A4. Calculate the factor 10^exp in FP1 using a table of
  52. 10^(2^n) values.  To reduce the error in forming factors
  53. greater than 10^27, a directed rounding scheme is used with
  54. tables rounded to RN, RM, and RP, according to the table
  55. in the comments of the __x_pwrten section.
  56. A5. Form the final binary number by scaling the mantissa by
  57. the exponent factor.  This is done by multiplying the
  58. mantissa in FP0 by the factor in FP1 if the adjusted
  59. exponent sign is positive, and dividing FP0 by FP1 if
  60. it is negative.
  61. Clean up and return.  Check if the final mul or div resulted
  62. in an inex2 exception.  If so, set inex1 in the fpsr and
  63. check if the inex1 exception is enabled.  If so, set d7 upper
  64. .word to 0x0100.  This will signal unimpsa that an enabled inex1
  65. exception occured.  Unimp will fix the stack.
  66. Copyright (C) Motorola, Inc. 1990
  67. All Rights Reserved
  68. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
  69. The copyright notice above does not evidence any
  70. actual or intended publication of such source code.
  71. DECBIN    idnt    2,1 Motorola 040 Floating Point Software Package
  72. section 8
  73. NOMANUAL
  74. */
  75. #include "fpsp040E.h"
  76. |
  77. | __x_PTENRN, __x_PTENRM, and __x_PTENRP are arrays of powers of 10 rounded
  78. | to nearest, minus, and plus, respectively.  The tables include
  79. | 10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}.  No rounding
  80. | is required until the power is greater than 27, however, all
  81. | tables include the first 5 for ease of indexing.
  82. |
  83. | xref __x_PTENRN
  84. | xref __x_PTENRM
  85. | xref __x_PTENRP
  86. RTABLE: .byte 0,0,0,0
  87. .byte 2,3,2,3
  88. .byte 2,3,3,2
  89. .byte 3,2,2,3
  90. .globl __x_decbin
  91. .globl __x_calc_e
  92. .globl __x_pwrten
  93. .globl __x_calc_m
  94. .globl __x_norm
  95. .globl __x_ap_st_z
  96. .globl __x_ap_st_n
  97. |
  98. #define FNIBS 7
  99. #define FSTRT 0
  100. |
  101. #define ESTRT 4
  102. #define EDIGITS  2
  103. |
  104. | Constants in single precision
  105. FZERO:  .long 0x00000000
  106. FONE:  .long 0x3F800000
  107. FTEN:  .long 0x41200000
  108. #define TEN 10
  109. |
  110. .text
  111. __x_decbin:
  112. fmovel #0,fpcr | clr real fpcr
  113. moveml d2-d5,a7@-
  114. |
  115. | Calculate exponent:
  116. |  1. Copy bcd value in memory for use as a working copy.
  117. |  2. Calculate absolute value of exponent in d1 by mul and add.
  118. |  3. Correct for exponent sign.
  119. |  4. Subtract 16 to compensate for interpreting the mant as all integer digits.
  120. |     (i.e., all digits assumed left of the decimal point.)
  121. |
  122. | Register usage:
  123. |
  124. |  __x_calc_e:
  125. | (*)  d0: temp digit storage
  126. | (*)  d1: accumulator for binary exponent
  127. | (*)  d2: digit count
  128. | (*)  d3: offset pointer
  129. | ( )  d4: first word of bcd
  130. | ( )  a0: pointer to working bcd value
  131. | ( )  a6: pointer to original bcd value
  132. | (*)  FP_SCR1: working copy of original bcd value
  133. | (*)  L_SCR1: copy of original exponent word
  134. |
  135. __x_calc_e:
  136. movel #EDIGITS,d2 | # of nibbles (digits) in fraction part
  137. movel #ESTRT,d3 | counter to pick up digits
  138. lea a6@(FP_SCR1),a0 | load tmp bcd storage address
  139. movel a6@(ETEMP),a0@ | save input bcd value
  140. movel a6@(ETEMP_HI),a0@(4) | save words 2 and 3
  141. movel a6@(ETEMP_LO),a0@(8) | and work with these
  142. movel a0@,d4 | get first word of bcd
  143. clrl d1 | zero d1 for accumulator
  144. e_gd:
  145. mulul #TEN,d1 | mul partial product by one digit place
  146. bfextu d4{d3:#4},d0 | get the digit and zero extend into d0
  147. addl d0,d1 | d1 = d1 + d0
  148. addqb #4,d3 | advance d3 to the next digit
  149. dbf d2,e_gd | if we have used all 3 digits, exit loop
  150. btst #30,d4 | get SE
  151. jeq  e_pos /* | don't negate if pos */
  152. negl d1 | negate before subtracting
  153. e_pos:
  154. subl #16,d1 | sub to compensate for shift of mant
  155. jge  e_save | if still pos, do not neg
  156. negl d1 | now negative, make pos and set SE
  157. orl #0x40000000,d4 | set SE in d4,
  158. orl #0x40000000,a0@ | and in working bcd
  159. e_save:
  160. movel d1,a6@(L_SCR1) | save exp in memory
  161. |
  162. |
  163. | Calculate mantissa:
  164. |  1. Calculate absolute value of mantissa in fp0 by mul and add.
  165. |  2. Correct for mantissa sign.
  166. |     (i.e., all digits assumed left of the decimal point.)
  167. |
  168. | Register usage:
  169. |
  170. |  __x_calc_m:
  171. | (*)  d0: temp digit storage
  172. | (*)  d1: lword counter
  173. | (*)  d2: digit count
  174. | (*)  d3: offset pointer
  175. | ( )  d4: words 2 and 3 of bcd
  176. | ( )  a0: pointer to working bcd value
  177. | ( )  a6: pointer to original bcd value
  178. | (*) fp0: mantissa accumulator
  179. | ( )  FP_SCR1: working copy of original bcd value
  180. | ( )  L_SCR1: copy of original exponent word
  181. |
  182. __x_calc_m:
  183. moveql #1,d1 | word counter, init to 1
  184. fmoves FZERO,fp0 | accumulator
  185. |
  186. |
  187. |  Since the packed number has a long word between the first # second parts,
  188. |  get the integer digit then skip down # get the rest of the
  189. |  mantissa.  We will unroll the loop once.
  190. |
  191. bfextu a0@{#28:#4},d0 | integer part is ls digit in long word
  192. faddb d0,fp0 | add digit to sum in fp0
  193. |
  194. |
  195. |  Get the rest of the mantissa.
  196. |
  197. loadlw:
  198. movel a0@(d1:l:4),d4 | load mantissa lonqword into d4
  199. movel #FSTRT,d3 | counter to pick up digits
  200. movel #FNIBS,d2 | reset number of digits per a0 ptr
  201. md2b:
  202. fmuls FTEN,fp0 | fp0 = fp0 * 10
  203. bfextu d4{d3:#4},d0 | get the digit and zero extend
  204. faddb d0,fp0 | fp0 = fp0 + digit
  205. |
  206. |
  207. |  If all the digits (8) in that long word have been converted (d2=0),
  208. |  then inc d1 (=2) to point to the next long word and reset d3 to 0
  209. |  to initialize the digit offset, and set d2 to 7 for the digit count|
  210. |  else continue with this long word.
  211. |
  212. addqb #4,d3 | advance d3 to the next digit
  213. dbf d2,md2b | check for last digit in this lw
  214. nextlw:
  215. addql #1,d1 | inc lw pointer in mantissa
  216. cmpl #2,d1 | test for last lw
  217. jle  loadlw | if not, get last one
  218. |
  219. |  Check the sign of the mant and make the value in fp0 the same sign.
  220. |
  221. m_sign:
  222. btst #31,a0@ | test sign of the mantissa
  223. jeq  __x_ap_st_z | if clear, go to append/strip zeros
  224. fnegx fp0 | if set, negate fp0
  225. |
  226. | Append/strip zeros:
  227. |
  228. |  For adjusted exponents which have an absolute value greater than 27*,
  229. |  this routine calculates the amount needed to normalize the mantissa
  230. |  for the adjusted exponent.  That number is subtracted from the exp
  231. |  if the exp was positive, and added if it was negative.  The purpose
  232. |  of this is to reduce the value of the exponent and the possibility
  233. |  of error in calculation of __x_pwrten.
  234. |
  235. |  1. Branch on the sign of the adjusted exponent.
  236. |  2p.(positive exp)
  237. |   2. Check M16 and the digits in lwords 2 and 3 in decending order.
  238. |   3. Add one for each zero encountered until a non-zero digit.
  239. |   4. Subtract the count from the exp.
  240. |   5. Check if the exp has crossed zero in #3 above|  make the exp abs
  241. |    and set SE.
  242. | 6. Multiply the mantissa by 10**count.
  243. |  2n.(negative exp)
  244. |   2. Check the digits in lwords 3 and 2 in decending order.
  245. |   3. Add one for each zero encountered until a non-zero digit.
  246. |   4. Add the count to the exp.
  247. |   5. Check if the exp has crossed zero in #3 above|  clear SE.
  248. |   6. Divide the mantissa by 10**count.
  249. |
  250. |  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
  251. |   any adjustment due to append/strip zeros will drive the resultane
  252. |   exponent towards zero.  Since all __x_pwrten constants with a power
  253. |   of 27 or less are exact, there is no need to use this routine to
  254. |   attempt to lessen the resultant exponent.
  255. |
  256. | Register usage:
  257. |
  258. |  __x_ap_st_z:
  259. | (*)  d0: temp digit storage
  260. | (*)  d1: zero count
  261. | (*)  d2: digit count
  262. | (*)  d3: offset pointer
  263. | ( )  d4: first word of bcd
  264. | (*)  d5: lword counter
  265. | ( )  a0: pointer to working bcd value
  266. | ( )  FP_SCR1: working copy of original bcd value
  267. | ( )  L_SCR1: copy of original exponent word
  268. |
  269. |
  270. | First check the absolute value of the exponent to see if this
  271. | routine is necessary.  If so, then check the sign of the exponent
  272. | and do append (+) or strip (-) zeros accordingly.
  273. | This section handles a positive adjusted exponent.
  274. |
  275. __x_ap_st_z:
  276. movel a6@(L_SCR1),d1 | load expA for range test
  277. cmpl #27,d1 | test is with 27
  278. jle  __x_pwrten | if abs(expA) <28, skip ap/st zeros
  279. btst #30,a0@ | check sign of exp
  280. jne  __x_ap_st_n | if neg, go to neg side
  281. clrl d1 | zero count reg
  282. movel a0@,d4 | load lword 1 to d4
  283. bfextu d4{#28:#4},d0 | get M16 in d0
  284. jne  ap_p_fx | if M16 is non-zero, go fix exp
  285. addql #1,d1 | inc zero count
  286. moveql #1,d5 | init lword counter
  287. movel a0@(d5:l:4),d4 | get lword 2 to d4
  288. jne  ap_p_cl | if lw 2 is zero, skip it
  289. addql #8,d1 | and inc count by 8
  290. addql #1,d5 | inc lword counter
  291. movel a0@(d5:l:4),d4 | get lword 3 to d4
  292. ap_p_cl:
  293. clrl d3 | init offset reg
  294. moveql #7,d2 | init digit counter
  295. ap_p_gd:
  296. bfextu d4{d3:#4},d0 | get digit
  297. jne  ap_p_fx | if non-zero, go to fix exp
  298. addql #4,d3 | point to next digit
  299. addql #1,d1 | inc digit counter
  300. dbf d2,ap_p_gd | get next digit
  301. ap_p_fx:
  302. movel d1,d0 | copy counter to d2
  303. movel a6@(L_SCR1),d1 | get adjusted exp from memory
  304. subl d0,d1 | subtract count from exp
  305. jge  ap_p_fm | if still pos, go to __x_pwrten
  306. negl d1 | now its neg|  get abs
  307. movel a0@,d4 | load lword 1 to d4
  308. orl #0x40000000,d4 |  and set SE in d4
  309. orl #0x40000000,a0@ |  and in memory
  310. |
  311. | Calculate the mantissa multiplier to compensate for the striping of
  312. | zeros from the mantissa.
  313. |
  314. ap_p_fm:
  315. movel #__x_PTENRN,a1 | get address of power-of-ten table
  316. clrl d3 | init table index
  317. fmoves FONE,fp1 | init fp1 to 1
  318. moveql #3,d2 | init d2 to count bits in counter
  319. ap_p_el:
  320. asrl #1,d0 | shift lsb into carry
  321. jcc  ap_p_en | if 1, mul fp1 by __x_pwrten factor
  322. fmulx a1@(d3),fp1 | mul by 10**(d3_bit_no)
  323. ap_p_en:
  324. addl #12,d3 | inc d3 to next rtable entry
  325. tstl d0 | check if d0 is zero
  326. jne  ap_p_el | if not, get next bit
  327. fmulx fp1,fp0 | mul mantissa by 10**(no_bits_shifted)
  328. jra  __x_pwrten | go calc __x_pwrten
  329. |
  330. | This section handles a negative adjusted exponent.
  331. |
  332. __x_ap_st_n:
  333. clrl d1 | clr counter
  334. moveql #2,d5 | set up d5 to point to lword 3
  335. movel a0@(d5:l:4),d4 | get lword 3
  336. jne  ap_n_cl | if not zero, check digits
  337. subl #1,d5 | dec d5 to point to lword 2
  338. addql #8,d1 | inc counter by 8
  339. movel a0@(d5:l:4),d4 | get lword 2
  340. ap_n_cl:
  341. movel #28,d3 | point to last digit
  342. moveql #7,d2 | init digit counter
  343. ap_n_gd:
  344. bfextu d4{d3:#4},d0 | get digit
  345. jne  ap_n_fx | if non-zero, go to exp fix
  346. subql #4,d3 | point to previous digit
  347. addql #1,d1 | inc digit counter
  348. dbf d2,ap_n_gd | get next digit
  349. ap_n_fx:
  350. movel d1,d0 | copy counter to d0
  351. movel a6@(L_SCR1),d1 | get adjusted exp from memory
  352. subl d0,d1 | subtract count from exp
  353. jgt  ap_n_fm | if still pos, go fix mantissa
  354. negl d1 | take abs of exp and clr SE
  355. movel a0@,d4 | load lword 1 to d4
  356. andl #0xbfffffff,d4 |  and clr SE in d4
  357. andl #0xbfffffff,a0@ |  and in memory
  358. |
  359. | Calculate the mantissa multiplier to compensate for the appending of
  360. | zeros to the mantissa.
  361. |
  362. ap_n_fm:
  363. movel #__x_PTENRN,a1 | get address of power-of-ten table
  364. clrl d3 | init table index
  365. fmoves FONE,fp1 | init fp1 to 1
  366. moveql #3,d2 | init d2 to count bits in counter
  367. ap_n_el:
  368. asrl #1,d0 | shift lsb into carry
  369. jcc  ap_n_en | if 1, mul fp1 by __x_pwrten factor
  370. fmulx a1@(d3),fp1 | mul by 10**(d3_bit_no)
  371. ap_n_en:
  372. addl #12,d3 | inc d3 to next rtable entry
  373. tstl d0 | check if d0 is zero
  374. jne  ap_n_el | if not, get next bit
  375. fdivx fp1,fp0 | div mantissa by 10**(no_bits_shifted)
  376. |
  377. |
  378. | Calculate power-of-ten factor from adjusted and shifted exponent.
  379. |
  380. | Register usage:
  381. |
  382. |  __x_pwrten:
  383. | (*)  d0: temp
  384. | ( )  d1: exponent
  385. | (*)  d2: {FPCR[6:5],SM,SE} as index in RTABLE|  temp
  386. | (*)  d3: fpcr work copy
  387. | ( )  d4: first word of bcd
  388. | (*)  a1: RTABLE pointer
  389. |  calc_p:
  390. | (*)  d0: temp
  391. | ( )  d1: exponent
  392. | (*)  d3: PWRTxx table index
  393. | ( )  a0: pointer to working copy of bcd
  394. | (*)  a1: PWRTxx pointer
  395. | (*) fp1: power-of-ten accumulator
  396. |
  397. | Pwrten calculates the exponent factor in the selected rounding mode
  398. | according to the following table:
  399. |
  400. | Sign of Mant  Sign of Exp  Rounding Mode  PWRTEN Rounding Mode
  401. |
  402. | ANY   ANY RN RN
  403. |
  404. |  +    + RP RP
  405. |  -    + RP RM
  406. |  +    - RP RM
  407. |  -    - RP RP
  408. |
  409. |  +    + RM RM
  410. |  -    + RM RP
  411. |  +    - RM RP
  412. |  -    - RM RM
  413. |
  414. |  +    + RZ RM
  415. |  -    + RZ RM
  416. |  +    - RZ RP
  417. |  -    - RZ RP
  418. |
  419. |
  420. __x_pwrten:
  421. movel a6@(USER_FPCR),d3 /* | get user's fpcr */
  422. bfextu d3{#26:#2},d2 | isolate rounding mode bits
  423. movel a0@,d4 | reload 1st bcd word to d4
  424. asll #2,d2 | format d2 to be
  425. bfextu d4{#0:#2},d0 |  {FPCR[6],fpcr[5],SM,SE}
  426. addl d0,d2 | in d2 as index into RTABLE
  427. lea RTABLE,a1 | load rtable base
  428. moveb a1@(d2),d0 | load new rounding bits from table
  429. clrl d3 | clear d3 to force no exc and extended
  430. bfins d0,d3{#26:#2} | stuff new rounding bits in fpcr
  431. fmovel d3,fpcr | write new fpcr
  432. asrl #1,d0 | write correct PTENxx table
  433. jcc  not_rp | to a1
  434. lea __x_PTENRP,a1 | it is RP
  435. jra  calc_p | go to init section
  436. not_rp:
  437. asrl #1,d0 | keep checking
  438. jcc  not_rm
  439. lea __x_PTENRM,a1 | it is RM
  440. jra  calc_p | go to init section
  441. not_rm:
  442. lea __x_PTENRN,a1 | it is RN
  443. calc_p:
  444. movel d1,d0 | copy exp to d0| use d0
  445. jpl  no_neg | if exp is negative,
  446. negl d0 | invert it
  447. orl #0x40000000,a0@ | and set SE bit
  448. no_neg:
  449. clrl d3 | table index
  450. fmoves FONE,fp1 | init fp1 to 1
  451. e_loop:
  452. asrl #1,d0 | shift next bit into carry
  453. jcc  e_next | if zero, skip the mul
  454. fmulx a1@(d3),fp1 | mul by 10**(d3_bit_no)
  455. e_next:
  456. addl #12,d3 | inc d3 to next rtable entry
  457. tstl d0 | check if d0 is zero
  458. jne  e_loop | not zero, continue shifting
  459. |
  460. |
  461. |  Check the sign of the adjusted exp and make the value in fp0 the
  462. |  same sign. If the exp was pos then multiply fp1*fp0|
  463. |  else divide fp0/fp1.
  464. |
  465. | Register Usage:
  466. |  __x_norm:
  467. | ( )  a0: pointer to working bcd value
  468. | (*) fp0: mantissa accumulator
  469. | ( ) fp1: scaling factor - 10**(abs(exp))
  470. |
  471. __x_norm:
  472. btst #30,a0@ | test the sign of the exponent
  473. jeq  mul | if clear, go to multiply
  474. div:
  475. fdivx fp1,fp0 | exp is negative, so divide mant by exp
  476. jra  end_dec
  477. mul:
  478. fmulx fp1,fp0 | exp is positive, so multiply by exp
  479. |
  480. |
  481. | Clean up and return with result in fp0.
  482. |
  483. | If the final mul/div in __x_decbin incurred an inex exception,
  484. | it will be inex2, but will be reported as inex1 by __x_get_op.
  485. |
  486. end_dec:
  487. fmovel FPSR,d0 | get status register
  488. bclr #__x_inex2_bit+8,d0 | test for inex2 and clear it
  489. fmovel d0,FPSR | return status reg w/o inex2
  490. jeq  no_exc | skip this if no exc
  491. orl #inx1a_mask,a6@(USER_FPSR) | set inex1/ainex
  492. no_exc:
  493. moveml a7@+,d2-d5
  494. rts
  495. | end