flat assembler
Message board for the users of flat assembler.

Index > DOS > Working with FPU insturctions

Author
Thread Post new topic Reply to topic
wyvern



Joined: 08 Dec 2011
Posts: 27
wyvern 02 Mar 2013, 01:19
Hi all the forum.

Im learning to work with the FPU on a 16 bit enviroment, im using DOSBOX and currently the TASM assembler because i have a lot of source examples made in TASM, but mi intentions are to continue with FASM.

I have some trouble with a square root computation, for example the next code works fine. I can load any real value declared in de data section and then operate with it.

Code:
    ...
    finit
    fld dword [value]        ;load real value into st0
    fsqrt                         ;compute square root of st0 and store in st0
    fst dword [res]           ;store st0 in result
    ...
    


But now i want to declare a procedure to receive a memory addres where is a dword (float) value:
Code:
            mov ax, value
            push ax
            call sqrt

sqrt:      push     bp           
             mov      bp, sp
                      
             finit        
    
             fld       dword ptr [bp+2]      ;this is wrong
             fsqrt                   
             
             ;... etc           

             ffree     

             mov      sp, bp            
             pop       bp                                   
             ret      

value dd 5.5           
    

But i dont know how to load the value on FPU from the parameter addres in bp+2. i tryied to load the dword on a local var [bp - 2], and then to use fld from there but is a lot of work and i dont see it worth while.

Moreover, if i want to return the result in AX, this must be the address of some buffer declared in heap i guess... i cant see another way.

Any suggestions about this?.

Thanks.

_________________
Thanks
Post 02 Mar 2013, 01:19
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1660
Location: Toronto, Canada
AsmGuru62 02 Mar 2013, 13:42
You can pass two parameters:
1. Address of location, where the result is stored
2. Address of location (or locations), where the input is stored

So, in your function you deal with addresses as parameters.
I tried a small COM project for this:

MAIN.ASM:
Code:
; ---------------------------------------------------------------------------
; FILE: DosComTemplate.Asm
; DATE: March 2, 2013
; ---------------------------------------------------------------------------

    org 100h
    use16

    ; {INSMODDEF} Module Definitions will be inserted here

    ;
    ; MS-DOS Program Entry Point
    ;

    ;
    ; Parameters are pushed in opposite order
    ; (you probably need a macro to make it shorter)
    ;
    mov       ax, divisor
    push      ax
    mov       ax, m2
    push      ax
    mov       ax, m1
    push      ax
    mov       ax, result
    push      ax
    call      Module1_PerformMulDiv  ; (result, m1, m2, divisor)
    ;
    ; Just to check result in debugger
    ;
    fld       [result]
    fstp      st0       ; Throw it out
    ;
    ; Quit to MS-DOS
    ;
    int       20h

    include 'Module1.Asm'
    ; {INSMODIMPL} Module Implementations will be inserted here

    ;
    ; Some DOUBLEs...
    ;
    align 8
    m1       dq 43.9548
    m2       dq 79064.03262
    divisor  dq 6534.77544
    result   dq 0.0
    


MODULE1.ASM:
Code:
; ---------------------------------------------------------------------------
; FILE: Module1.Asm
; DATE: March 2, 2013
; ---------------------------------------------------------------------------
align 32
Module1_PerformMulDiv:
; ---------------------------------------------------------------------------
; INPUT (stdcall addresses of DOUBLE values):
;   RESULT, MUL1, MUL2, DIVISOR
; OUTPUT:
;   Expression (MUL1*MUL2)/DIVISOR will be stored at address in RESULT
; ---------------------------------------------------------------------------
    push      bp
    mov       bp, sp
    push      bx
    ;
    ; BP+4  -> RESULT
    ; BP+6  -> MUL1
    ; BP+8  -> MUL2
    ; BP+10 -> DIVISOR
    ;
    mov       bx, [bp + 6]
    fld       qword [bx]

    mov       bx, [bp + 8]
    fmul      qword [bx]

    mov       bx, [bp + 10]
    fdiv      qword [bx]

    mov       bx, [bp + 4]
    fstp      qword [bx]

    pop       bx bp
    ret       4*2      ; Restore stack for 4 16-bit parameters
    

For an EXE file and FAR pointers you will have to do some adjustments.

I must add that the convention for a function returning a single float point value
is to return it in ST0 register of the FPU. So, you can use it instead of storing it at some address.
Same can be said for an input parameters to a function --- they also can be passed in registers.
Post 02 Mar 2013, 13:42
View user's profile Send private message Send e-mail Reply with quote
SeproMan



Joined: 11 Oct 2009
Posts: 70
Location: Belgium
SeproMan 02 Mar 2013, 13:48
wyvern,

The dword at [bp+2] is not what you need!
You should move the word at [bp+4] in an address register (BX, SI, or DI).
Note that if you preserve this register also, you must use [bp+6] instead!

Why not return the result at the same place you found the input?

_________________
Real Address Mode.
Post 02 Mar 2013, 13:48
View user's profile Send private message Reply with quote
wyvern



Joined: 08 Dec 2011
Posts: 27
wyvern 02 Mar 2013, 19:30
AsmGuru62, SeproMan:

Thank very much you for your help, now i realize i was close to the solution (sorry for the "[bp+2]", i mean [bp+4]).

And about "calling conventions", if return value must be in ST0, what happen if i want to return two or more values. For example, suppose i have a function that evaluates a 2ยบ polinomyal and i want to return two roots... i could use st0 and st1?, or would be better to receive two memory buffers from the caller to store the two results there?. I just want to know wich is the most "correct" or convenient way to do it.

Thanks
Post 02 Mar 2013, 19:30
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1660
Location: Toronto, Canada
AsmGuru62 03 Mar 2013, 19:07
I would use ST0 and ST1.
The calling conventions are for interfacing your function with HLL.
Lets say that your function will be called by C/C++ -- in this case you need to follow the convention.
Otherwise, if function used only in your own ASM code, then you can
do whatever produces smaller code -- I think ST0,ST1 combination will
produce shorter code.
Post 03 Mar 2013, 19:07
View user's profile Send private message Send e-mail Reply with quote
wyvern



Joined: 08 Dec 2011
Posts: 27
wyvern 03 Mar 2013, 19:12
AsmGuru62, im more interested to write code that can be easily used from anywhere (or at least not just from my own code). In this case, what would be the better aproach?

Thanks.
Post 03 Mar 2013, 19:12
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1660
Location: Toronto, Canada
AsmGuru62 04 Mar 2013, 18:01
Post 04 Mar 2013, 18:01
View user's profile Send private message Send e-mail Reply with quote
wyvern



Joined: 08 Dec 2011
Posts: 27
wyvern 04 Mar 2013, 22:40
Excelent info, thanks for the link.
Post 04 Mar 2013, 22:40
View user's profile Send private message Reply with quote
ACP



Joined: 23 Sep 2006
Posts: 204
ACP 04 Mar 2013, 23:39
wyvern wrote:
Im learning to work with the FPU on a 16 bit enviroment, im using DOSBOX and currently the TASM assembler because i have a lot of source examples made in TASM, but mi intentions are to continue with FASM.


Please note that TASM (I'm assuming you are using 5.x) is adding WAIT/FWAIT instruction before any FPU instruction unless you specify CPU type to be 486 or higher (if I remember correctly). If 486 CPU has been selected TASM skips it just like FASM does. So if you "port" code generated by TASM to FASM you have to remember about it.

Just my 2 cents...
Post 04 Mar 2013, 23:39
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.