News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

A question on FPU

Started by clamicun, February 08, 2016, 08:32:53 AM

Previous topic - Next topic

clamicun

Hi HSE,

" fn crt_sprintf, addr endvalue, "%lf", FPU_calc..."

ok. but as I said...
Seeing it is good, but I nedd it for further use.
Thank you

clamicun

jj,

"I took a look. Resembles my Float2Asc routine - 500+ lines of scarcely commented code ::)"

That is what I meant ..
I do not understand it entirely (lots of code for little output).

Let esi=Str$("%4f",FPU_calc)
If esi is a string...
well I find out

...

HSE

Quote from: clamicun on February 09, 2016, 02:02:55 AM
but I need the "endvalue".

Have you tested the function in your code?
Equations in Assembly: SmplMath

jj2007

Quote from: clamicun on February 09, 2016, 05:51:14 AMLet esi=Str$("%4f",FPU_calc)
If esi is a string...

In C/C++ and assembler, a string is technically speaking a pointer to an area of memory that is delimited by a zero byte (or word in case of Unicode). You can use a register like esi, edi, ebx and ecx if you want smaller code, but Let my$=Str$(123) is valid as well, if my$ has been declared either in the .data? section or via SetGlobals.

On a very technical note,
Let my$="Hello"
Let my$=my$+" world"
is possible in MasmBasic. When my$ is assigned in the second line, the old my$ gets HeapFree'd after the new one was created. The same applies to esi, edi, ebx and ecx, but attention: If they pointed to something else before the first assignment, the heap might not agree with what you were doing. No such risk for a global variable like my$, of course, and no problem for arrays like x$(0). If you really want to use registers, the correct way is as follows:
xor esi, esi   ; make sure it doesn't point to the heap
Let esi="Hello"
Let esi=esi+" world"
PrintLine esi  ; do something useful
Clr$ esi   ; release the memory (->HeapFree)

clamicun

"Problem" resolved

MasmBasics...
fstp FPU_calculation
Let esi=Str$("%4f",FPU_calculation)
INVOKE lstrcpy,offset where_it_should_be,esi  ;for further use

Relatively small code  - using MasmBasics  "str$ MACRO" 

Nothing against the code of "RuiLoureiro" ,but...

as always - Thanks a lot jj
Mic

P.S.
One of these days I am going to understand "MasmBasics"




raymond

clamicum

QuoteINVOKE crt_atof,offset startvalue
INVOKE crt_atof,offset value1
fadd st(0),st(1)                 ; add ST(0)+ST(1)

I don't know how the crt_atof works but I would suspect that it converts the input string
- with a clean FPU after saving all current FPU registers,
- saving its converted result in local memory,
- restoring the saved FPU registers,
- and finally loading the saved result onto the FPU.

The detail for which I have no information is if it blindly frees the st(7) register (which could still contain valuable data) before loading the saved result on the FPU. If not, you would have been lucky that your test included no more than 8 input strings; otherwise, your final output value would have been TRASH.

Maybe you should have a look at the FPU tutorial at http://www.ray.masmcode.com/fpu.html, which you can read on-line or download its content.
Trying to program the FPU without sufficient knowledge of its various pitfalls can only lead to a lot of frustration.

You also seemed curious about how the Convert8DR (or Float2Asc) routines worked. I don't know how those arrive at the intended result but, if you have the MASM32 package, the source code for the FpuFLtoA function from the fpulib library is well commented. Although it contains almost 500 lines, the first 195 lines are the overhead to verify the source and validity of the input. You can then easily follow the logic used for the conversion and eventual display according to user preferences.
Whenever you assume something, you risk being wrong half the time.
https://masm32.com/masmcode/rayfil/index.html

jj2007

Quote from: raymond on February 09, 2016, 10:03:07 AMThe detail for which I have no information is if it blindly frees the st(7) register (which could still contain valuable data) before loading the saved result on the FPU. If not, you would have been lucky that your test included no more than 8 input strings; otherwise, your final output value would have been TRASH.

That is indeed a problem with this code:
Quote from: clamicun on February 08, 2016, 08:32:53 AMINVOKE crt_atof,offset startvalue
INVOKE crt_atof,offset value1
fadd st(0),st(1)                 ; add ST(0)+ST(1)

INVOKE crt_atof,offset value2
fadd st(0),st(1)                

INVOKE crt_atof,offset value3
fadd st(0),st(1)             

INVOKE crt_atof,offset value4
fadd st(0),st(1)   
             
INVOKE crt_atof,offset value5
fadd st(0),st(1)

fstp FPU_calc         ;Store real number and pop ST(0)

There are three important mnemonics related to adding ST0 and ST1:
  fadd st(0), st(1)   ; adds st1 to st0, st1 remains valid   
  faddp st(1), st(0)   ; adds st1 to st0, st1 becomes empty
  fadd         ; identical to faddp st(1), st(0)

The version you used does not empty ST(1). So when you call crt_atof eight times, the FPU is full, and that will produce a bad result. You need to use the simple fadd instead. The best option: launch Olly and have a look.

@Ray: If the FPU is full, crt_atof produces a NAN. At least one ffree ST(7) is needed.
In contrast, MovVal ST(0), Chr$("123.456") will handle the ffree, but ST 5..7 will be trashed (which could be a problem under completely unrealistic assumptions; and before you kill me for that: a simple MsgBox also trashes two FPU regs, while many API calls trash several xmm regs without asking you for your permission 8))

clamicun

Maybe you should have a look at the FPU tutorial at http://www.ray.masmcode.com/fpu.html...
That is where learned the bit I know.

I do use  the proc 5 times (maximum) - there are 5 vars "value" only
and everytime the proc starts with

FINIT  ; It is good programming practice to take the precaution of initializing FPU before starting any computation
FFREE st(0)

Is that ok. ?

jj2007

Quote from: clamicun on February 09, 2016, 11:24:19 AMFINIT  ; It is good programming practice to take the precaution of initializing FPU before starting any computation
FFREE st(0)

Is that ok. ?

MB's Init does the finit once (it is a slow instruction). It does not hurt to do it again, but avoid using finit in a tight loop.
Re ffree st(0): Read Ray's tute, the "revolver" part. What you really need is to free the last register, i.e. ffree st(7), in order to allow st(0) to load a new value. Example, assuming a "full" fpu:
FpuFill  ; for testing, fill the FPU with 1001 ... 1008
ffree st(7)  ; discard the last value
fldz  ; load zero
ffree st(7)  ; discard the last value
fldpi  ; load PI
ffree st(7)  ; discard the last value
fld1  ; load 1
You have now
ST(0)=1
ST(1)=PI
ST(2)=0

Really, the best idea is to launch Olly and watch what happens. MB has the FpuFill macro, can be very handy for testing.

raymond

QuoteFINIT  ; It is good programming practice to take the precaution of initializing FPU before starting any computation
FFREE st(0)

Is that ok. ?

For the first line comment, the answer may be yes or no according to the description of the FINIT instruction in the tutorial.

As for the second line, also from the tutorial (Chap, 1),

QuoteWhen the FPU is initialized, all the compartments are empty

It is thus useless to free "any" FPU register immediately following the finit instruction. The result of the FFREE instruction is to empty the specified register.
Whenever you assume something, you risk being wrong half the time.
https://masm32.com/masmcode/rayfil/index.html

dedndave

to execute FINIT prior to any calculation is craziness
FINIT is quite slow - i generally execute it once at the beginning of a program
then, i take care to keep track of register usage

MichaelW

Quote from: raymond on February 09, 2016, 10:03:07 AM
I don't know how the crt_atof works...

The older Microsoft PSDKs, this one , for example, included a large part of the source for the CRTL, and if I remember correctly, this included the source for the atof function and a "worker" function that it calls to do the actual conversion.
Well Microsoft, here's another nice mess you've gotten us into.

RuiLoureiro

#27
Quote from: clamicun on February 08, 2016, 08:32:53 AM
;this does it - why ... I still am on problems with "FPU"

include \masm32\include\masm32rt.inc
include Convert8DR.inc   ;You have to download the zipFile to make it working

;=========
show_string MACRO arg1,arg2
LOCAL ws_msg
LOCAL stringlabel

.data
ws_msg    TCHAR 60 dup(?),0
stringlabel TCHAR '%s',0

.code
    pushad
    INVOKE wsprintf,addr ws_msg,addr stringlabel,reparg(arg2)
    INVOKE MessageBox,0,addr arg1,addr ws_msg,0
    popad
ENDM
;==========

.data
startvalue db "0.00",0
endvalue   db 20 dup(?),0

value1 db "1.11",0
value2 db "2.22",0
value3 db "3.33",0
value4 db "4.44",0
value5 db "5.55",0

FPU_calc    REAL8 ?
;-----------------

.code
start:

call Calculate


INVOKE ExitProcess,0

;============
Calculate proc

FINIT  ; It is good programming practice to take the precaution of initializing FPU before starting any computation
; FFREE st(0)      <<<<<<<< remove this it does nothing after finit

show_string startvalue,"start value"

INVOKE crt_atof,offset startvalue
INVOKE crt_atof,offset value1
fadd st(0),st(1)                 ; add ST(0)+ST(1)

INVOKE crt_atof,offset value2
fadd st(0),st(1)                 

INVOKE crt_atof,offset value3
fadd st(0),st(1)             

INVOKE crt_atof,offset value4
fadd st(0),st(1)   
             
INVOKE crt_atof,offset value5
fadd st(0),st(1)

fstp FPU_calc         ;Store real number and pop ST(0)

;So the result is in st(0)
;I use 'Convert8DR.inc' written by RuiLoureiro,- it works well, but I do not understand his macros... 
;Is there an "easier" way to convert the content of 'FPU_calc REAL8 ?' into a string - MasmBasics ??
 
INVOKE  ConvertReal8DR, offset FPU_calc, offset endvalue

show_string endvalue,"result add"

ret
Calculate endp
;============

end start
Hi all,
         I saw this just now. Please correct the bug that i show in red
         Good luck :t
Quote

        _finish:    mov      eax, edi
                    mov      edi, pString
                    sub      eax, edi

        _exit0:     ;mov      dword ptr [edi-4], eax            <<<<<< THIS is OK
                    mov      byte ptr [edi+eax], 0
                                             
                    xor      eax, eax
                    clc
        _exit:      mov      edx, edi
                    ;                   
                    pop      edi
                    pop      esi
                    pop      ebx
                    ret
;-----------------------------------------------------------
    _isinfinityS:   sub      edi, 1
                    cmp      byte ptr [edi], '-'
                    je       short @F
                    mov      byte ptr [edi], '+'     
            @@:     mov      dword ptr [edi+1], "IFNI"
                    mov      dword ptr [edi+5], "YTIN"
                    mov      eax, 9
                    jmp      _exit0
                   
                    ;--------------------------
                    ; value to be converted = 0
                    ;--------------------------
        _iszeroS:   sub      edi, 1
                    mov      word ptr [edi], 3020h
                    mov      eax, 2
                    jmp      _exit0
                   
                    ; --------------------
                    ; is indefinite or NAN
                    ; --------------------
        _erro1S:    mov      eax, 1
                    ; -------------------
                    ; Remove sign / space
                    ; -------------------
        _errorS:    sub      edi, 1
                    mov      dword ptr [edi+0], "ORRE"
                    mov      byte ptr [edi+4], "R"
                    ;
                    ;mov      dword ptr [edi-4], 5              <<<<<<  REMOVE THIS ALSO
                    mov      byte ptr [edi+5], 0
                    stc
                    jmp      _exit
                                       
                    ; -----------------
                    ; invalid operation
                    ; -----------------
        _erro2S:    fclex
                    mov      eax, 2
                    jmp      _errorS
ConvertReal8DR      endp