📄 bindec.s
字号:
/* bindec.s - Motorola 68040 FP binary/decimal conversion routines (EXC) *//* Copyright 1991-1993 Wind River Systems, Inc. */ .data .globl _copyright_wind_river .long _copyright_wind_river/*modification history--------------------01e,21jul93,kdl added .text (SPR #2372).01d,23aug92,jcf changed bxxx to jxx.01c,26may92,rrr the tree shuffle01b,10jan92,kdl general cleanup.01b,01jan92,jcf reversed order of cmp <reg>,<reg>01a,12aug91,kdl changed routine names which begin "Ax_" to aboid confusion when converting to lower case reg names.*//*DESCRIPTION __x_bindecsa 3.4 1/3/91 __x_bindec Description: Converts an input in extended precision format to bcd format. Input: a0 points to the input extended precision value value in memory| d0 contains the k-factor sign-extended to 32-bits. The input may be either normalized, unnormalized, or denormalized. Output: result in the FP_SCR1 space on the stack. Saves and Modifies: D2-D7,A2,FP2 Algorithm: A1. Set RM and size ext| Set SIGMA = sign of input. The k-factor is saved for use in d7. Clear the BINDEC_FLG for separating normalized/denormalized input. If input is unnormalized or denormalized, normalize it. A2. Set X = abs(input). A3. Compute ILOG. ILOG is the log base 10 of the input value. It is approximated by adding e + 0.f when the original value is viewed as 2^^e * 1.f in extended precision. This value is stored in d6. A4. Clr INEX bit. The operation in A3 above may have set INEX2. A5. Set ICTR = 0| ICTR is a flag used in A13. It must be set before the loop entry A6. A6. Calculate LEN. LEN is the number of digits to be displayed. The k-factor can dictate either the total number of digits, if it is a positive number, or the number of digits after the decimal point which are to be included as significant. See the 68882 manual for examples. If LEN is computed to be greater than 17, set OPERR in USER_FPSR. LEN is stored in d4. A7. Calculate SCALE. SCALE is equal to 10^ISCALE, where ISCALE is the number of decimal places needed to insure LEN integer digits in the output before conversion to bcd. LAMBDA is the sign of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using a rounding mode which is a function of the original rounding mode and the signs of ISCALE and X. A table is given in the code. A8. Clr INEX| Force RZ. The operation in A3 above may have set INEX2. RZ mode is forced for the scaling operation to insure only one rounding error. The grs bits are collected in the INEX flag for use in A10. A9. Scale X -> Y. The mantissa is scaled to the desired number of significant digits. The excess digits are collected in INEX2. A10. Or in INEX. If INEX is set, round error occured. This is compensated for by 'or-ing' in the INEX2 flag to the lsb of Y. A11. Restore original fpcr| set size ext. Perform FINT operation in the user's rounding mode. Keep the size to extended. A12. Calculate YINT = FINT(Y) according to user's rounding mode. The FPSP routine __x_sintd0 is used. The output is in fp0. A13. Check for LEN digits. If the int operation results in more than LEN digits, or less than LEN -1 digits, adjust ILOG and repeat from A6. This test occurs only on the first pass. If the result is exactly 10^LEN, decrement ILOG and divide the mantissa by 10. A14. Convert the mantissa to bcd. The __x_binstr routine is used to convert the LEN digit mantissa to bcd in memory. The input to __x_binstr is to be a fraction| i.e. (mantissa)/10^LEN and adjusted such that the decimal point is to the left of bit 63. The bcd digits are stored in the correct position in the final string area in memory. A15. Convert the exponent to bcd. As in A14 above, the exp is converted to bcd and the digits are stored in the final string. Test the length of the final exponent string. If the length is 4, set operr. A16. Write sign bits to final string. Implementation Notes: The registers are used as follows: d0: scratch| LEN input to __x_binstr d1: scratch d2: upper 32-bits of mantissa for __x_binstr d3: scratch| lower 32-bits of mantissa for __x_binstr d4: LEN d5: LAMBDA/ICTR d6: ILOG d7: k-factor a0: ptr for original operand/final result a1: scratch pointer a2: pointer to FP_X| abs(original value) in ext fp0: scratch fp1: scratch fp2: scratch F_SCR1: F_SCR2: L_SCR1: L_SCR2: Copyright (C) Motorola, Inc. 1990 All Rights Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA The copyright notice above does not evidence any actual or intended publication of such source code.BINDEC idnt 2,1 Motorola 040 Floating Point Software PackageNOMANUAL*/#include "fpsp040E.h"| section 8| Constants in extended precisionLOG2: .long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000LOG2UP1: .long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000| Constants in single precisionFONE: .long 0x3F800000,0x00000000,0x00000000,0x00000000FTWO: .long 0x40000000,0x00000000,0x00000000,0x00000000FTEN: .long 0x41200000,0x00000000,0x00000000,0x00000000F4933: .long 0x459A2800,0x00000000,0x00000000,0x00000000RBDTBL: .byte 0,0,0,0 .byte 3,3,2,2 .byte 3,2,2,3 .byte 2,3,3,2| xref __x_binstr| xref __x_sintdo| xref ptenrn,ptenrm,ptenrp .globl __x_bindec .globl __x_sc_mul .text__x_bindec: moveml d2-d7/a2,a7@- fmovemx fp0-fp2,a7@-| A1. Set RM and size ext. Set SIGMA = sign input|| The k-factor is saved for use in d7. Clear BINDEC_FLG for| separating normalized/denormalized input. If the input| is a denormalized number, set the BINDEC_FLG memory word| to signal denorm. If the input is unnormalized, normalize| the input and test for denormalized result.| fmovel #rm_mode,fpcr | set RM and ext movel a0@,a6@(L_SCR2) | save exponent for sign check movel d0,d7 | move k-factor to d7 clrb a6@(BINDEC_FLG) | clr norm/denorm flag movew a6@(STAG),d0 | get stag andiw #0xe000,d0 | isolate stag bits jeq __A2_str | if zero, input is norm|| Normalize the denorm|un_de_norm: movew a0@,d0 andiw #0x7fff,d0 | strip sign of normalized exp movel a0@(4),d1 movel a0@(8),d2__x_norm_loop: subw #1,d0 lsll #1,d2 roxll #1,d1 tstl d1 jge __x_norm_loop|| Test if the normalized input is denormalized| tstw d0 jgt pos_exp | if greater than zero, it is a norm st a6@(BINDEC_FLG) | set flag for denormpos_exp: andiw #0x7fff,d0 | strip sign of normalized exp movew d0,a0@ movel d1,a0@(4) movel d2,a0@(8)| A2. Set X = abs(input).|__A2_str: movel a0@,a6@(FP_SCR2) | move input to work space movel a0@(4),a6@(FP_SCR2+4) | move input to work space movel a0@(8),a6@(FP_SCR2+8) | move input to work space andil #0x7fffffff,a6@(FP_SCR2) | create abs(X)| A3. Compute ILOG.| ILOG is the log base 10 of the input value. It is approx-| imated by adding e + 0.f when the original value is viewed| as 2^^e * 1.f in extended precision. This value is stored| in d6.|| Register usage:| Input/Output| d0: k-factor/exponent| d2: x/x| d3: x/x| d4: x/x| d5: x/x| d6: x/ILOG| d7: k-factor/Unchanged| a0: ptr for original operand/final result| a1: x/x| a2: x/x| fp0: x/float(ILOG)| fp1: x/x| fp2: x/x| F_SCR1:x/x| F_SCR2:Abs(X)/Abs(X) with 0x3fff exponent| L_SCR1:x/x| L_SCR2:first word of X packed/Unchanged tstb a6@(BINDEC_FLG) | check for denorm jeq __A3_cont | if clr, continue with norm movel #-4933,d6 | force ILOG = -4933 jra __A4_str__A3_cont: movew a6@(FP_SCR2),d0 | move exp to d0 movew #0x3fff,a6@(FP_SCR2) | replace exponent with 0x3fff fmovex a6@(FP_SCR2),fp0 | now fp0 has 1.f subw #0x3fff,d0 | strip off bias faddw d0,fp0 | add in exp fsubs FONE,fp0 | subtract off 1.0 fbge pos_res | if pos, branch fmulx LOG2UP1,fp0 | if neg, mul by LOG2UP1 fmovel fp0,d6 | put ILOG in d6 as a lword jra __A4_str | go move out ILOGpos_res: fmulx LOG2,fp0 | if pos, mul by LOG2 fmovel fp0,d6 | put ILOG in d6 as a lword| A4. Clr INEX bit.| The operation in A3 above may have set INEX2.__A4_str: fmovel #0,FPSR | zero all of fpsr - nothing needed| A5. Set ICTR = 0|| ICTR is a flag used in A13. It must be set before the| loop entry A6. The lower word of d5 is used for ICTR. clrw d5 | clear ICTR| A6. Calculate LEN.| LEN is the number of digits to be displayed. The k-factor| can dictate either the total number of digits, if it is| a positive number, or the number of digits after the| original decimal point which are to be included as| significant. See the 68882 manual for examples.| If LEN is computed to be greater than 17, set OPERR in| USER_FPSR. LEN is stored in d4.|| Register usage:| Input/Output| d0: exponent/Unchanged| d2: x/x/scratch| d3: x/x| d4: exc picture/LEN| d5: ICTR/Unchanged| d6: ILOG/Unchanged| d7: k-factor/Unchanged| a0: ptr for original operand/final result| a1: x/x| a2: x/x| fp0: float(ILOG)/Unchanged| fp1: x/x| fp2: x/x| F_SCR1:x/x| F_SCR2:Abs(X) with 0x3fff exponent/Unchanged| L_SCR1:x/x| L_SCR2:first word of X packed/Unchanged__A6_str: tstl d7 | branch on sign of k jle k_neg | if k <= 0, LEN = ILOG + 1 - k movel d7,d4 | if k > 0, LEN = k jra len_ck | skip to LEN checkk_neg: movel d6,d4 | first load ILOG to d4 subl d7,d4 | subtract off k addql #1,d4 | add in the 1len_ck: tstl d4 | LEN check: branch on sign of LEN jle LEN_ng | if neg, set LEN = 1 cmpl #17,d4 | test if LEN > 17 jle __A7_str | if not, forget it movel #17,d4 | set max LEN = 17 tstl d7 | if negative, never set OPERR jle __A7_str | if positive, continue orl #opaop_mask,a6@(USER_FPSR) | set OPERR # AIOP in USER_FPSR jra __A7_str | finished hereLEN_ng: moveql #1,d4 | min LEN is 1| A7. Calculate SCALE.| SCALE is equal to 10^ISCALE, where ISCALE is the number| of decimal places needed to insure LEN integer digits| in the output before conversion to bcd. LAMBDA is the sign| of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using| the rounding mode as given in the following table (see| Coonen, p. 7.23 as ref.| however, the SCALE variable is| of opposite sign in __x_bindecsa from Coonen).|| Initial USE| fpcr[6:5] LAMBDA SIGN(X) fpcr[6:5]| ----------------------------------------------| RN 00 0 0 00/0 RN| RN 00 0 1 00/0 RN| RN 00 1 0 00/0 RN| RN 00 1 1 00/0 RN| RZ 01 0 0 11/3 RP| RZ 01 0 1 11/3 RP| RZ 01 1 0 10/2 RM| RZ 01 1 1 10/2 RM| RM 10 0 0 11/3 RP| RM 10 0 1 10/2 RM| RM 10 1 0 10/2 RM| RM 10 1 1 11/3 RP| RP 11 0 0 10/2 RM| RP 11 0 1 11/3 RP| RP 11 1 0 11/3 RP| RP 11 1 1 10/2 RM|| Register usage:| Input/Output| d0: exponent/scratch - final is 0| d2: x/0 or 24 for A9| d3: x/scratch - offset ptr into __x_PTENRM array| d4: LEN/Unchanged| d5: 0/ICTR:LAMBDA| d6: ILOG/ILOG or k if ((k<=0)#(ILOG<k))| d7: k-factor/Unchanged| a0: ptr for original operand/final result| a1: x/ptr to __x_PTENRM array| a2: x/x| fp0: float(ILOG)/Unchanged| fp1: x/10^ISCALE| fp2: x/x| F_SCR1:x/x| F_SCR2:Abs(X) with 0x3fff exponent/Unchanged| L_SCR1:x/x| L_SCR2:first word of X packed/Unchanged__A7_str: tstl d7 | test sign of k jgt k_pos | if pos and > 0, skip this cmpl d6,d7 | test ILOG - k jlt k_pos | if ILOG >= k, skip this movel d7,d6 | if ((k<0) # (ILOG < k)) ILOG = kk_pos: movel d6,d0 | calc ILOG + 1 - LEN in d0 addql #1,d0 | add the 1 subl d4,d0 | sub off LEN swap d5 | use upper word of d5 for LAMBDA clrw d5 | set it zero initially clrw d2 | set up d2 for very small case tstl d0 | test sign of ISCALE jge iscale | if pos, skip next inst addqw #1,d5 | if neg, set LAMBDA true cmpl #0xffffecd4,d0 | test iscale <= -4908 jgt no_inf | if false, skip rest addil #24,d0 | add in 24 to iscale movel #24,d2 | put 24 in d2 for A9no_inf: negl d0 | and take abs of ISCALEiscale: fmoves FONE,fp1 | init fp1 to 1 bfextu a6@(USER_FPCR){#26:#2},d1 | get initial rmode bits lslw #1,d1 | put them in bits 2:1 addw d5,d1 | add in LAMBDA lslw #1,d1 | put them in bits 3:1 tstl a6@(L_SCR2) | test sign of original x jge x_pos /* | if pos, don't set bit 0 */ addql #1,d1 | if neg, set bit 0x_pos: lea RBDTBL,a2 | load rbdtbl base moveb a2@(d1),d3 | load d3 with new rmode lsll #4,d3 | put bits in proper position fmovel d3,fpcr | load bits into fpu lsrl #4,d3 | put bits in proper position tstb d3 | decode new rmode for pten table jne not_rn | if zero, it is RN lea __x_PTENRN,a1 | load a1 with RN table base jra rmode | exit decodenot_rn: lsrb #1,d3 | get lsb in carry jcc not_rp | if carry clear, it is RM lea __x_PTENRP,a1 | load a1 with RP table base jra rmode | exit decodenot_rp: lea __x_PTENRM,a1 | load a1 with RM table basermode: clrl d3 | clr table indexe_loop: lsrl #1,d0 | shift next bit into carry jcc e_next | if zero, skip the mul fmulx a1@(d3),fp1 | mul by 10**(d3_bit_no)e_next: addl #12,d3 | inc d3 to next __x_pwrten table entry tstl d0 | test if ISCALE is zero jne e_loop | if not, loop| A8. Clr INEX| Force RZ.| The operation in A3 above may have set INEX2.| RZ mode is forced for the scaling operation to insure| only one rounding error. The grs bits are collected in| the INEX flag for use in A10.|| Register usage:| Input/Output fmovel #0,FPSR | clr INEX
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -