home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Runimage / Delphi50 / Source / Rtl / Sys / STREXT.ASM < prev    next >
Encoding:
Assembly Source File  |  1999-08-11  |  7.8 KB  |  459 lines

  1.  
  2. ; *******************************************************
  3. ; *                            *
  4. ; *     Delphi Runtime Library                          *
  5. ; *                            *
  6. ; *    Copyright (c) 1996,98 Inprise Corporation    *
  7. ; *                            *
  8. ; *******************************************************
  9.  
  10.     INCLUDE    SE.ASM
  11.  
  12.     .386
  13.     .MODEL    FLAT
  14.  
  15.     EXTRN    _Pow10:NEAR
  16.     PUBLIC    _Str0Ext, _Str1Ext, _Str2Ext
  17.  
  18.     .CODE
  19.  
  20. one    DQ    1.0
  21. ten    DQ    10.0
  22. tenE17    DQ    1E17
  23. tenE18    DQ    1E18
  24.  
  25. ;    PROCEDURE _Str0Ext( val: Extended; var s: String );
  26.  
  27. _Str0Ext PROC
  28.  
  29. ; ->    [ESP+4]    Extended value
  30. ;    EAX    Pointer to string
  31.  
  32.     MOV    ECX,EAX            ; pass string
  33.     MOV    EAX,23            ; pass default field width
  34.     OR    EDX,-1            ; pass precision -1
  35.     JMP    _Str2Ext
  36.  
  37. _Str0Ext ENDP
  38.  
  39.  
  40. ;    PROCEDURE _Str1Ext( val: Extended; width: Longint; var s: String );
  41.  
  42. _Str1Ext PROC
  43.  
  44. ; ->    [ESP+4]    Extended value
  45. ;    EAX    Field width
  46. ;    EDX    Pointer to string
  47.  
  48.     MOV    ECX,EDX
  49.     OR    EDX,-1            ; pass precision -1
  50.     JMP    _Str2Ext
  51.  
  52. _Str1Ext ENDP
  53.  
  54.  
  55. ;    PROCEDURE _Str2Ext( val: Extended; width, precision: Longint; var s: String );
  56.  
  57. _Str2Ext PROC
  58.  
  59. ; ->    [ESP+4]    Extended value
  60. ;    EAX    Width
  61. ;    EDX    Precision
  62. ;    ECX    Pointer to string
  63.  
  64. MAXDIGS    EQU    256
  65.  
  66.     FLD    tbyte ptr [ESP+4]
  67.  
  68.     PUSH    EBX
  69.     PUSH    ESI
  70.     PUSH    EDI
  71.     MOV    EBX,EAX
  72.     MOV    ESI,EDX
  73.     PUSH    ECX            ; save string pointer
  74.     SUB    ESP,MAXDIGS        ; VAR digBuf: array [0..MAXDIGS-1] of Char
  75.  
  76. ;    limit width to 255
  77.  
  78.     CMP    EBX,255            ; if width > 255 then width := 255;
  79.     JLE    @@1
  80.     MOV    EBX,255
  81. @@1:
  82.  
  83. ;    save sign bit in bit 0 of EDI, take absolute value of val, check for
  84. ;    Nan and infinity.
  85.  
  86.     FLD    ST(0)
  87.     FSTP    tbyte ptr [ESP]
  88.     XOR    EAX,EAX
  89.     MOV    AX,word ptr [ESP+8]
  90.     MOV    EDI,EAX
  91.     SHR    EDI,15
  92.     AND    AX,7FFFH
  93.     CMP    AX,7FFFH
  94.     JE    @@nanInf
  95.     FABS
  96.  
  97. ;    if precision < 0 then do scientific else do fixed;
  98.  
  99.     TEST    ESI,ESI
  100.     JGE    @@fixed
  101.  
  102. ;    the following call finds a decimal exponent and a reduced
  103. ;    mantissa such that val = mant * 10**exp
  104.  
  105.     CALL    _ScaleExt        ; val is FST(0), exp is EAX
  106.  
  107. ;    for scientific notation, we have width - 8 significant digits
  108. ;    however, we can not have less than 2 or more than 18 digits.
  109.  
  110. @@scientific:
  111.  
  112.     MOV    ESI,EBX            ; digCnt := width - 8;
  113.     SUB    ESI,8
  114.     CMP    ESI,2            ; if digCnt < 2 then digCnt := 2
  115.     JGE    @@2
  116.     MOV    ESI,2
  117.     JMP    @@3
  118. @@2:
  119.     CMP    ESI,18            ; else if digCnt > 18 then digCnt := 18;
  120.     JLE    @@3
  121.     MOV    ESI,18
  122. @@3:
  123.  
  124. ;    _EmitDigits( val, digCnt, digBuf )
  125.  
  126.     MOV    EDX,ESP            ; pass digBuf
  127.     PUSH    EAX            ; save exponent
  128.     MOV    EAX,ESI            ; pass digCnt
  129.     CALL    _EmitDigits        ; convert val to ASCII
  130.  
  131.     MOV    EDX,EDI            ; save sign in EDX
  132.     MOV    EDI,[ESP+MAXDIGS+4]    ; load result string pointer
  133.  
  134.     MOV    [EDI],BL        ; length of result string := width
  135.     INC    EDI
  136.  
  137.     MOV    AL,' '            ; prepare for leading blanks and sign
  138.  
  139.     MOV    ECX,EBX            ; blankCnt := width - digCnt - 8
  140.     SUB    ECX,ESI
  141.     SUB    ECX,8
  142.     JLE    @@4
  143.  
  144.     REP    STOSB            ; emit blankCnt blanks
  145. @@4:
  146.     SUB    [EDI-1],CL        ; if blankCnt < 0, adjust length
  147.  
  148.     TEST    DL,DL            ; emit the sign (' ' or '-')
  149.     JE    @@5
  150.     MOV    AL,'-'
  151. @@5:
  152.     STOSB
  153.  
  154.     POP    EAX
  155.  
  156.     MOV    ECX,ESI            ; emit digCnt digits
  157.  
  158.     MOV    ESI,ESP            ; point ESI to digBuf
  159.  
  160.     CMP    byte ptr [ESI],'0'
  161.     JE    @@5a            ; if rounding overflowed, adjust exponent and ESI
  162.     INC    EAX
  163.     DEC    ESI
  164. @@5a:
  165.     INC    ESI
  166.  
  167.     MOVSB                ; emit one digit
  168.     MOV    byte ptr [EDI],'.'    ; emit dot
  169.     INC    EDI            ; adjust dest pointer
  170.     DEC    ECX            ; adjust count
  171.  
  172.     REP    MOVSB
  173.  
  174.     MOV    byte ptr [EDI],'E'
  175.  
  176.     MOV    CL,'+'            ; emit sign of exponent ('+' or '-')
  177.     TEST    EAX,EAX
  178.     JGE    @@6
  179.     MOV    CL,'-'
  180.     NEG    EAX
  181. @@6:
  182.     MOV    [EDI+1],CL
  183.  
  184.     XOR    EDX,EDX            ; emit exponent
  185.     MOV    CX,10
  186.     DIV    CX
  187.     ADD    DL,'0'
  188.     MOV    [EDI+5],DL
  189.  
  190.     XOR    EDX,EDX
  191.     DIV    CX
  192.     ADD    DL,'0'
  193.     MOV    [EDI+4],DL
  194.  
  195.     XOR    EDX,EDX
  196.     DIV    CX
  197.     ADD    DL,'0'
  198.     MOV    [EDI+3],DL
  199.  
  200.     ADD    AL,'0'
  201.     MOV    [EDI+2],AL
  202.  
  203.     JMP    @@exit
  204.  
  205. @@fixed:
  206.  
  207. ;    FST(0)    = value >= 0.0
  208. ;    EBX    = width
  209. ;    ESI    = precision
  210. ;    EDI    = sign
  211.  
  212.     CMP    ESI,MAXDIGS-40        ; else if precision > MAXDIGS-40 then precision := MAXDIGS-40;
  213.     JLE    @@6a
  214.     MOV    ESI,MAXDIGS-40
  215. @@6a:
  216.     FCOM    ten
  217.     FSTSW    AX
  218.     SAHF
  219.     MOV    EAX,0
  220.     JB    @@7
  221.  
  222.     CALL    _ScaleExt        ; val is FST(0), exp is EAX
  223.  
  224.     CMP    EAX,35            ; if val is too large, use scientific
  225.     JG    @@scientific
  226.  
  227. @@7:
  228. ;    FST(0)    = scaled value, 0.0 <= value < 10.0
  229. ;    EAX    = exponent, 0 <= exponent
  230.  
  231. ;    intDigCnt := exponent + 1;
  232.  
  233.     INC    EAX
  234.  
  235. ;    _EmitDigits( value, intDigCnt + precision, digBuf );
  236.  
  237.     MOV    EDX,ESP
  238.     PUSH    EAX
  239.     ADD    EAX,ESI
  240.     CALL    _EmitDigits
  241.     POP    EAX
  242.  
  243. ;    Now we need to check whether rounding to the right number of
  244. ;    digits overflowed, and if so, adjust things accordingly
  245.  
  246.     MOV    EDX,ESI            ; put precision in EDX
  247.     MOV    ESI,ESP            ; point EDI to digBuf
  248.     CMP    byte ptr [ESI],'0'
  249.     JE    @@8
  250.     INC    EAX
  251.     DEC    ESI
  252. @@8:
  253.     INC    ESI
  254.  
  255.     MOV    ECX,EAX            ; numWidth := sign + intDigCnt;
  256.     ADD    ECX,EDI
  257.  
  258.     TEST    EDX,EDX            ; if precision > 0 then
  259.     JE    @@9
  260.     INC    ECX            ;   numWidth := numWidth + 1 + precision
  261.     ADD    ECX,EDX
  262.  
  263.     CMP    EBX,ECX            ; if width <= numWidth
  264.     JG    @@9
  265.     MOV    EBX,ECX            ;   width := numWidth
  266. @@9:
  267.     PUSH    EAX
  268.     PUSH    EDI
  269.  
  270.     MOV    EDI,[ESP+MAXDIGS+2*4]    ; point EDI to dest string
  271.  
  272.     MOV    [EDI],BL        ; store final length in dest string
  273.     INC    EDI
  274.  
  275.     SUB    EBX,ECX            ; width := width - numWidth
  276.     MOV    ECX,EBX
  277.     JLE    @@10
  278.  
  279.     MOV    AL,' '            ; emit width blanks
  280.     REP    STOSB
  281. @@10:
  282.     SUB    [EDI-1],CL        ; if blankCnt < 0, adjust length
  283.     POP    EAX
  284.     POP    ECX
  285.  
  286.     TEST    EAX,EAX
  287.     JE    @@11
  288.  
  289.     MOV    byte ptr [EDI],'-'
  290.     INC    EDI
  291.  
  292. @@11:
  293.     REP    MOVSB            ; copy intDigCnt digits
  294.  
  295.     TEST    EDX,EDX            ; if precision > 0 then
  296.     JE    @@12
  297.  
  298.     MOV    byte ptr [EDI],'.'    ;   emit '.'
  299.     INC    EDI
  300.     MOV    ECX,EDX            ;   emit precision digits
  301.     REP    MOVSB
  302.  
  303. @@12:
  304.  
  305. @@exit:
  306.     ADD    ESP,MAXDIGS
  307.     POP    ECX
  308.     POP    EDI
  309.     POP    ESI
  310.     POP    EBX
  311.     RET    12
  312.  
  313. @@nanInf:
  314. ;    here: EBX = width, ECX = string pointer, EDI = sign, [ESP] = value
  315.  
  316.     FSTP    ST(0)
  317.     CMP    [ESP+4],80000000H
  318.     MOV    ESI,offset nanStr
  319.     JNE    @@13
  320.     DEC    EDI
  321.     MOV    ESI,offset plusInfStr
  322.     JNZ    @@13
  323.     MOV    ESI,offset minInfStr
  324. @@13:
  325.     MOV    EDI,ECX
  326.     MOV    ECX,EBX
  327.     MOV    [EDI],CL
  328.     INC    EDI
  329.     SUB    CL,[ESI]
  330.     JBE    @@14
  331.     MOV    AL,' '
  332.     REP    STOSB
  333. @@14:
  334.     SUB    [EDI-1],CL
  335.     MOV    CL,[ESI]
  336.     INC    ESI
  337.     REP    MOVSB
  338.  
  339.     JMP    @@exit
  340.  
  341. nanStr        DB    3,'Nan'
  342. plusInfStr    DB    4,'+Inf'
  343. minInfStr    DB    4,'-Inf'
  344.  
  345. _Str2Ext ENDP
  346.  
  347.  
  348. _EmitDigits PROC
  349.  
  350. ; ->    FST(0)    Value, 0 <= value < 10.0
  351. ;    EAX    Count of digits to generate
  352. ;    EDX    Pointer to digit buffer
  353.  
  354.     PUSH    EDI
  355.     MOV    EDI,EDX
  356.     MOV    ECX,EAX
  357.  
  358.     SUB    ESP,10            ; VAR bcdBuf: array [0..9] of Byte
  359.     MOV    byte ptr [EDI],'0'    ; digBuf[0] := '0';
  360.     FMUL    tenE17            ; val := Round(val*1e17);
  361.     FRNDINT
  362.  
  363.     FCOM    tenE18            ; if val >= 1e18 then
  364.     FSTSW    AX
  365.     SAHF
  366.     JB    @@1
  367.  
  368.     FSUB    tenE18            ;   val := val - 1e18;
  369.     MOV    byte ptr [EDI],'1'    ;   digBuf[0] := '1';
  370. @@1:
  371.     FBSTP    [ESP]            ; store packed bcd digits in bcdBuf
  372.  
  373.     MOV    EDX,8
  374.     INC    EDI
  375.  
  376. @@2:
  377.     WAIT
  378.     MOV    AL,[ESP+EDX]        ; unpack 18 bcd digits in 9 bytes
  379.     MOV    AH,AL            ; into 9 words = 18 bytes
  380.     SHR    AL,4
  381.     AND    AH,0FH
  382.     ADD    AX,'00'
  383.     STOSW
  384.     DEC    EDX
  385.     JNS    @@2
  386.  
  387.     SUB    ECX,18            ; we need at least digCnt digits
  388.     JL    @@3            ; we have generated 18
  389.  
  390.     MOV    AL,'0'            ; if this is not enough, append zeroes
  391.     REP    STOSB
  392.     JMP    @@4            ; in this case, we don't need to round
  393.  
  394. @@3:
  395.     ADD    EDI,ECX            ; point EDI to the round digit
  396.     CMP    byte ptr [EDI],'5'
  397.     JL    @@4
  398. @@5:
  399.     DEC    EDI
  400.     INC    byte ptr [EDI]
  401.     CMP    byte ptr [EDI],'9'
  402.     JLE    @@4
  403.     MOV    byte ptr [EDI],'0'
  404.     JMP    @@5
  405.  
  406. @@4:
  407.     ADD    ESP,10
  408.     POP    EDI
  409.     RET
  410.  
  411. _EmitDigits ENDP
  412.  
  413.  
  414. _ScaleExt PROC
  415.  
  416. ; ->    FST(0)    Value
  417. ; <-    EAX    exponent (base 10)
  418. ;    FST(0)    Value / 10**eax
  419.  
  420.     PUSH    EBX
  421.     SUB    ESP,12
  422.  
  423.     XOR    EBX,EBX
  424.  
  425. @@normLoop:                ; loop necessary for denormals
  426.  
  427.     FLD    ST(0)
  428.     FSTP    tbyte ptr [ESP]
  429.     MOV    AX,[ESP+8]
  430.     TEST    AX,AX
  431.     JE    @@testZero
  432. @@cont:
  433.     SUB    AX,3FFFH
  434.     MOV    DX,4D10H    ; log10(2) * 2**16
  435.     IMUL    DX
  436.     MOVSX    EAX,DX        ; exp10 = exp2 * log10(2)
  437.     NEG    EAX
  438.     JE    @@exit
  439.     SUB    EBX,EAX
  440.     CALL    _Pow10
  441.     JMP    @@normLoop
  442.  
  443. @@exit:
  444.     ADD    ESP,12
  445.     MOV    EAX,EBX
  446.     POP    EBX
  447.     RET
  448.  
  449. @@testZero:
  450.     CMP     dword ptr [ESP+4],0
  451.     JNE    @@cont
  452.     CMP    dword ptr [ESP+0],0
  453.     JNE    @@cont
  454.     JMP    @@exit
  455.  
  456. _ScaleExt ENDP
  457.  
  458.     END
  459.