Shop OBEX P1 Docs P2 Docs Learn Events
Floating Point in Assembly (User Defined Functions) — Parallax Forums

Floating Point in Assembly (User Defined Functions)

NeucessorNeucessor Posts: 7
edited 2009-06-03 16:28 in Propeller 1
I'm using floating point since my application uses lots of math functions and multiplication between the float variables. It has been tedious converting back and forth from float to integer variables.
I have read the Floating Point Routines documentation, and clearly it states assembler code executes way faster than spin code.
I couldn't understand how to get it working, do I copy-paste the needed functions from Float32 (with its constants and variables) to my object and run the DAT in a new cog?

Can anyone show an example code showing how to create and use a (float routine) user defined function?
Thanks everyone, would be very grateful for the help.


PS: here is the link to the floating point documentation I mentioned: http://forums.parallax.com/forums/attach.aspx?a=24276

Comments

  • RossHRossH Posts: 5,512
    edited 2009-06-02 06:06
    Hi Neucessor,

    Is your program written in SPIN or PASM? If you use PASM, and you just need a few of the routines, the easiest thing is to just cut and paste the ones you need (make sure you copy all the support routines as well). If you use SPIN, then start the appropriate float32 library in a cog, and it will monitor a particular memory address for requests. From Spin you then put your request in that memory location, and this will trigger the float32 cog, which wil spit back the answer in another memory location. I think it will tell you it's done by clearing the request memory location.

    I think there's some examples that wrap all this up for you (in SPIN) in the Float 32 objects in the Object Exchange. See http://obex.parallax.com/objects/202/

    Ross.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Catalina - a FREE C compiler for the Propeller - see Catalina
  • TimmooreTimmoore Posts: 1,031
    edited 2009-06-02 06:21
    There are basically 3 versions of float32 libs
    floatmath which is a spin only version - limited set of functions and slow
    float32 which is spin/asm, with the float math done is asm. takes a cog and is a limited set of function
    float32full which is spin/asm, takes 2 cogs, more float functions which are split acros 2 cogs.

    The common way the asm versions are used is to call the spin access functions, passing parameters in/out of these functions and into asm.

    user defined functions is in the float32full version. It allows you to write a list of functions to be executed, as a table of functions, each function takes 1 parameter, the function and parameter are 1 long in the table. When you pass the table in by calling FFunc and giving the address of the function. one of the cogs then executes all the asm functions specified in the table until the end of the table. This allows you to call a set of float funtions without the overhead of all the spin access functions.

    e.g. the example is a spin defined table with 3 variables x, y you fill before calling ffunc and passing in @func1, then load x, multi x*y and store z is excuted all in asm before returning. Then you can read the value stored in z
  • NeucessorNeucessor Posts: 7
    edited 2009-06-02 07:24
    Thx for the quick replies guys.

    Aha! I missed the fact that FFunc is in the Float32Full library. I've been using Float32 all this time (since it's enough for my app).
    The app is written fully in Spin.
    Now I understand the Float library waits for the "command" variable to contain a value and then execute it. When it finishes, it is clears that var.
    But I cannot find the call to FFunc in cmdTable of both Float32Full and Float32A, where am I supposed to define FFunc (the code is fully in Spin)?


    Is it possible to edit the Float32 library and edit/add my own function? I think it's better to save a cog from not using Float32Full, since I don't need the additional functions.
    The whole idea of the user defined function is to eliminate the Spin overhead, is this right?
    In shorter words, is it okay to add a method FMyFunc (which consists of calls to existing asm methods) in Float32?
  • northcovenorthcove Posts: 49
    edited 2009-06-02 12:06
    My project also relies heavily upon the floating point functions in my Spin code.

    Can anyone explain the reasoning behind Float32 blocking the caller and passing a command for another dedicated FP cog to do the work? I don't see how this improves efficiency. It also uses a precious cog. Why not just jmp to the PASM implementation, use the stack for scratch vars, and return?
  • RossHRossH Posts: 5,512
    edited 2009-06-02 12:26
    @northcove

    If you think about it, there is no real alternative. The FP is just PASM code, and PASM has to be executed by a cog. If you are programming in SPIN then the cog executing your SPIN code is chock-full of SPIN interpreter, and has no space to hold any of the FP PASM code - so it must be executed by another cog.

    If you are programming in PASM and you have space available then you don't need to pass the request off to another cog - you copy the FP code into your cog and execute it directly. But if you don't have enough space, then again your only choice is to pass the request off to another cog to execute for you (and then pass back a result). In PASM it makes sense to go do something else while the FP code is executing. In SPIN it is probably easier to just block since you wouldn't be able to do much else while you are waiting (SPIN being much slower).

    Ross.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Catalina - a FREE C compiler for the Propeller - see Catalina
  • northcovenorthcove Posts: 49
    edited 2009-06-02 12:34
    @Ross -- thanks for answering that. Minutes after I posted my question I stumbled upon http://propeller.wikispaces.com/Method+Calls which explained the implementation and presented a few things I wasn't aware of. Very enlightening, thanks!
  • TimmooreTimmoore Posts: 1,031
    edited 2009-06-02 16:45
    Neucessor, FFunc works in the same way as other F functions, it passes a command to the cog and waits for the result. But in this case you define a line of functions to execute. The best way to look at it, is write the code in spin

    x := 2.0
    y := 3.0
    z := FMul(x,y)
    

    Then translate this into the list of functions you need. One other thing the mul in FFunc in cog 2 takes 1 paramter, and multiples by a pre-loaded parameter.
    so it translates into
    · 1. Load x·········· - loads x into an internal variable
    · 2. Mul(y)·········· - this multiples the existing loaded variable by y and stores it in the internal variable
    · 3. Store(@z)······- this saves the internal variable into z

    Then you an translate that into the table format
    DAT
    x long 2.0
    y long 3.0
    z long 0
    func1    long   JmpCmd + @func1
             long   LoadCmd + @x   'LoadCmd is load, x is address of x to get value from
             long   FMulCMd + @y   'multiple internal variable (loaded by above) by contents of Y and store internally
             long   SaveCmd + @z   ' store internal value into z
             long   0              ' tells the internal processor to stop
    

    So you dont write a MyFFunc you can use the existing FFunc, you describe what you want your function to do in terms of hte existing functions in Float32Full.
    The first line (JmpCmd), is required, it tells the asm command processor the offset to the table. Elsewhere in the table is a jmp in the table so you can have branches/condition branches etc in the table. There is extra commands for this type of use - jmp, and condition jmp routines.
    Also you need to be careful, since the asm is split between 2 cogs, FFunc is in the 2nd cog, to access functions in the first cog you need to use the SendCmd function, this sends commands to the 1st cog to execute.

    ·
  • NeucessorNeucessor Posts: 7
    edited 2009-06-03 11:33
    PUB FFunc(cmdPointer)
    
      command2 := FFuncCmd + cmdPointer
    
      repeat while command2
    
      return cmdReturn2
    


    FFunc takes a command pointer as parameter. So if I were to call func1 as shown in the example, I should call FFunc(func1), where func1 is defined in DAT block of the app's spin code.
    Is this correct?
  • TimmooreTimmoore Posts: 1,031
    edited 2009-06-03 16:28
    FFunc(@func1), you need the address of the function block
Sign In or Register to comment.