home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1997 April
/
Chip_1997-04_cd.bin
/
prezent
/
cb
/
data.z
/
STREXT.ASM
< prev
next >
Wrap
Assembly Source File
|
1997-01-16
|
8KB
|
453 lines
; *******************************************************
; * *
; * Delphi Runtime Library *
; * *
; * Copyright (c) 1996 Borland International *
; * *
; *******************************************************
INCLUDE SE.ASM
.386
.MODEL FLAT
EXTRN _Pow10:NEAR
PUBLIC _Str0Ext, _Str1Ext, _Str2Ext
.CODE
one DQ 1.0
ten DQ 10.0
tenE17 DQ 1E17
tenE18 DQ 1E18
; PROCEDURE _Str0Ext( val: Extended; var s: String );
_Str0Ext PROC
; -> [ESP+4] Extended value
; EAX Pointer to string
MOV ECX,EAX ; pass string
MOV EAX,23 ; pass default field width
OR EDX,-1 ; pass precision -1
JMP _Str2Ext
_Str0Ext ENDP
; PROCEDURE _Str1Ext( val: Extended; width: Longint; var s: String );
_Str1Ext PROC
; -> [ESP+4] Extended value
; EAX Field width
; EDX Pointer to string
MOV ECX,EDX
OR EDX,-1 ; pass precision -1
JMP _Str2Ext
_Str1Ext ENDP
; PROCEDURE _Str2Ext( val: Extended; width, precision: Longint; var s: String );
_Str2Ext PROC
; -> [ESP+4] Extended value
; EAX Width
; EDX Precision
; ECX Pointer to string
FLD tbyte ptr [ESP+4]
PUSH EBX
PUSH ESI
PUSH EDI
MOV EBX,EAX
MOV ESI,EDX
PUSH ECX ; save string pointer
SUB ESP,40 ; VAR digBuf: array [0..39] of Char
; limit width to 255
CMP EBX,255 ; if width > 255 then width := 255;
JLE @@1
MOV EBX,255
@@1:
; save sign bit in bit 0 of EDI, take absolute value of val, check for
; Nan and infinity.
FLD ST(0)
FSTP tbyte ptr [ESP]
XOR EAX,EAX
MOV AX,word ptr [ESP+8]
MOV EDI,EAX
SHR EDI,15
AND AX,7FFFH
CMP AX,7FFFH
JE @@nanInf
FABS
; if precision < 0 then do scientific else do fixed;
TEST ESI,ESI
JGE @@fixed
; the following call finds a decimal exponent and a reduced
; mantissa such that val = mant * 10**exp
CALL _ScaleExt ; val is FST(0), exp is EAX
; for scientific notation, we have width - 8 significant digits
; however, we can not have less than 2 or more than 18 digits.
@@scientific:
MOV ESI,EBX ; digCnt := width - 8;
SUB ESI,8
CMP ESI,2 ; if digCnt < 2 then digCnt := 2
JGE @@2
MOV ESI,2
JMP @@3
@@2:
CMP ESI,18 ; else if digCnt > 18 then digCnt := 18;
JLE @@3
MOV ESI,18
@@3:
; _EmitDigits( val, digCnt, digBuf )
MOV EDX,ESP ; pass digBuf
PUSH EAX ; save exponent
MOV EAX,ESI ; pass digCnt
CALL _EmitDigits ; convert val to ASCII
MOV EDX,EDI ; save sign in EDX
MOV EDI,[ESP+40+4] ; load result string pointer
MOV [EDI],BL ; length of result string := width
INC EDI
MOV AL,' ' ; prepare for leading blanks and sign
MOV ECX,EBX ; blankCnt := width - digCnt - 8
SUB ECX,ESI
SUB ECX,8
JLE @@4
REP STOSB ; emit blankCnt blanks
@@4:
SUB [EDI-1],CL ; if blankCnt < 0, adjust length
TEST DL,DL ; emit the sign (' ' or '-')
JE @@5
MOV AL,'-'
@@5:
STOSB
POP EAX
MOV ECX,ESI ; emit digCnt digits
MOV ESI,ESP ; point ESI to digBuf
CMP byte ptr [ESI],'0'
JE @@5a ; if rounding overflowed, adjust exponent and ESI
INC EAX
DEC ESI
@@5a:
INC ESI
MOVSB ; emit one digit
MOV byte ptr [EDI],'.' ; emit dot
INC EDI ; adjust dest pointer
DEC ECX ; adjust count
REP MOVSB
MOV byte ptr [EDI],'E'
MOV CL,'+' ; emit sign of exponent ('+' or '-')
TEST EAX,EAX
JGE @@6
MOV CL,'-'
NEG EAX
@@6:
MOV [EDI+1],CL
XOR EDX,EDX ; emit exponent
MOV CX,10
DIV CX
ADD DL,'0'
MOV [EDI+5],DL
XOR EDX,EDX
DIV CX
ADD DL,'0'
MOV [EDI+4],DL
XOR EDX,EDX
DIV CX
ADD DL,'0'
MOV [EDI+3],DL
ADD AL,'0'
MOV [EDI+2],AL
JMP @@exit
@@fixed:
; FST(0) = value >= 0.0
; EBX = width
; ESI = precision
; EDI = sign
FCOM ten
FSTSW AX
SAHF
MOV EAX,0
JB @@7
CALL _ScaleExt ; val is FST(0), exp is EAX
CMP EAX,35 ; if val is too large, use scientific
JG @@scientific
@@7:
; FST(0) = scaled value, 0.0 <= value < 10.0
; EAX = exponent, 0 <= exponent
; intDigCnt := exponent + 1;
INC EAX
; _EmitDigits( value, intDigCnt + precision, digBuf );
MOV EDX,ESP
PUSH EAX
ADD EAX,ESI
CALL _EmitDigits
POP EAX
; Now we need to check whether rounding to the right number of
; digits overflowed, and if so, adjust things accordingly
MOV EDX,ESI ; put precision in EDX
MOV ESI,ESP ; point EDI to digBuf
CMP byte ptr [ESI],'0'
JE @@8
INC EAX
DEC ESI
@@8:
INC ESI
MOV ECX,EAX ; numWidth := sign + intDigCnt;
ADD ECX,EDI
TEST EDX,EDX ; if precision > 0 then
JE @@9
INC ECX ; numWidth := numWidth + 1 + precision
ADD ECX,EDX
CMP EBX,ECX ; if width <= numWidth
JG @@9
MOV EBX,ECX ; width := numWidth
@@9:
PUSH EAX
PUSH EDI
MOV EDI,[ESP+40+2*4] ; point EDI to dest string
MOV [EDI],BL ; store final length in dest string
INC EDI
SUB EBX,ECX ; width := width - numWidth
MOV ECX,EBX
JLE @@10
MOV AL,' ' ; emit width blanks
REP STOSB
@@10:
SUB [EDI-1],CL ; if blankCnt < 0, adjust length
POP EAX
POP ECX
TEST EAX,EAX
JE @@11
MOV byte ptr [EDI],'-'
INC EDI
@@11:
REP MOVSB ; copy intDigCnt digits
TEST EDX,EDX ; if precision > 0 then
JE @@12
MOV byte ptr [EDI],'.' ; emit '.'
INC EDI
MOV ECX,EDX ; emit precision digits
REP MOVSB
@@12:
@@exit:
ADD ESP,40
POP ECX
POP EDI
POP ESI
POP EBX
RET 12
@@nanInf:
; here: EBX = width, ECX = string pointer, EDI = sign, [ESP] = value
FSTP ST(0)
CMP [ESP+4],80000000H
MOV ESI,offset nanStr
JNE @@13
DEC EDI
MOV ESI,offset plusInfStr
JNZ @@13
MOV ESI,offset minInfStr
@@13:
MOV EDI,ECX
MOV ECX,EBX
MOV [EDI],CL
INC EDI
SUB CL,[ESI]
JBE @@14
MOV AL,' '
REP STOSB
@@14:
SUB [EDI-1],CL
MOV CL,[ESI]
INC ESI
REP MOVSB
JMP @@exit
nanStr DB 3,'Nan'
plusInfStr DB 4,'+Inf'
minInfStr DB 4,'-Inf'
_Str2Ext ENDP
_EmitDigits PROC
; -> FST(0) Value, 0 <= value < 10.0
; EAX Count of digits to generate
; EDX Pointer to digit buffer
PUSH EDI
MOV EDI,EDX
MOV ECX,EAX
SUB ESP,10 ; VAR bcdBuf: array [0..9] of Byte
MOV byte ptr [EDI],'0' ; digBuf[0] := '0';
FMUL tenE17 ; val := Round(val*1e17);
FRNDINT
FCOM tenE18 ; if val >= 1e18 then
FSTSW AX
SAHF
JB @@1
FSUB tenE18 ; val := val - 1e18;
MOV byte ptr [EDI],'1' ; digBuf[0] := '1';
@@1:
FBSTP [ESP] ; store packed bcd digits in bcdBuf
MOV EDX,8
INC EDI
@@2:
WAIT
MOV AL,[ESP+EDX] ; unpack 18 bcd digits in 9 bytes
MOV AH,AL ; into 9 words = 18 bytes
SHR AL,4
AND AH,0FH
ADD AX,'00'
STOSW
DEC EDX
JNS @@2
SUB ECX,18 ; we need at least digCnt digits
JL @@3 ; we have generated 18
MOV AL,'0' ; if this is not enough, append zeroes
REP STOSB
JMP @@4 ; in this case, we don't need to round
@@3:
ADD EDI,ECX ; point EDI to the round digit
CMP byte ptr [EDI],'5'
JL @@4
@@5:
DEC EDI
INC byte ptr [EDI]
CMP byte ptr [EDI],'9'
JLE @@4
MOV byte ptr [EDI],'0'
JMP @@5
@@4:
ADD ESP,10
POP EDI
RET
_EmitDigits ENDP
_ScaleExt PROC
; -> FST(0) Value
; <- EAX exponent (base 10)
; FST(0) Value / 10**eax
PUSH EBX
SUB ESP,12
XOR EBX,EBX
@@normLoop: ; loop necessary for denormals
FLD ST(0)
FSTP tbyte ptr [ESP]
MOV AX,[ESP+8]
TEST AX,AX
JE @@testZero
@@cont:
SUB AX,3FFFH
MOV DX,4D10H ; log10(2) * 2**16
IMUL DX
MOVSX EAX,DX ; exp10 = exp2 * log10(2)
NEG EAX
JE @@exit
SUB EBX,EAX
CALL _Pow10
JMP @@normLoop
@@exit:
ADD ESP,12
MOV EAX,EBX
POP EBX
RET
@@testZero:
CMP dword ptr [ESP+4],0
JNE @@cont
CMP dword ptr [ESP+0],0
JNE @@cont
JMP @@exit
_ScaleExt ENDP
END