Shop OBEX P1 Docs P2 Docs Learn Events
ASM 32bit divide help! — Parallax Forums

ASM 32bit divide help!

JavalinJavalin Posts: 892
edited 2010-06-28 19:30 in Propeller 1
So I want to divide·long (32bit)·numbers, i.e. 30_000_000 / 4000, or 757_002 / 80, etc so I wrote this as a quick divide routine:

asmLongDivide           ' takes X / Y = R
                        mov     r,#0
:loop                   cmpsub  x, y            wc
        if_c            add     r,#1                         
        if_c            jmp     #:loop
asmLongDivide_ret       ret

It appears to work in my test case (110 / 10 = 11) - but when I start using it for real math it seems to "glitch" - i.e. suddenly from data where I should get 2,300 I get lumps of 4,700 or whatever.· I've confirmed its this code, if I let SPIN do the math it works perfectly.

Any ideas?· Its so simple I can't see how it can't not work.

Interestingly de-siliva's example has the WZ specified - but can't see how that would work either, as you'd want to still sub if X=Y?
asmLongDivide           ' takes X / Y = R
                        mov     r,#0
:loop                   cmpsub  x, y            wc, wz
        if_c            add     r,#1                         
        if_c_and_nz     jmp     #:loop
asmLongDivide_ret       ret

Cheers,

James

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2010-06-27 08:44
    Javalin said...
    It appears to work in my test case (110 / 10 = 11) - but when I start using it for real math it seems to "glitch" - i.e. suddenly from data where I should get 2,300 I get lumps of 4,700 or whatever. I've confirmed its this code, if I let SPIN do the math it works perfectly.

    ... example has the WZ specified - but can't see how that would work either, as you'd want to still sub if X=Y?
    Works for me (your example that is). What numbers did you try and how did you call your routine?

    As for wz, if x == y you have C (and Z) set and the sub is done already. Not looking at Z makes you go around the loop one more time for nothing (x < y || x == 0). Call it an early exit if you want.
  • JavalinJavalin Posts: 892
    edited 2010-06-27 08:48
    Hiya

    Its called like this:
                            mov     x, rawvalue                                     ' convert to MS (X / 80_000)
                            mov     y, eighty_thousand
                            call    #asmLongDivide
                            mov     pulseMS, r
    

    for example.

    >Works for me (your example that is).
    hmmmm.· Interesting.··OK will have to dig yet more.

    Cheers!

    James
  • BRBR Posts: 92
    edited 2010-06-27 13:38
    Javalin,

    Are you trying to divide signed integers with that routine?
  • JavalinJavalin Posts: 892
    edited 2010-06-27 14:04
    Nope - should be positive integer only.

    James
  • JavalinJavalin Posts: 892
    edited 2010-06-27 14:45
    ok, so i've done some more testing and its not that code.· Putting a loop of the range of values into the code instead of picking up from hardware proved the math.· Doh, but thanks for the code verification!

    I am sampling the pulse length of a pin in ASM - high-low-high time like this:

    readPulseLength         waitpeq RPMPULSEPIN,RPMPULSEPIN              ' Wait until pin goes HIGH
                            mov     starttime,cnt                        '
                            waitpeq zero,RPMPULSEPIN                     ' Wait until pin goes LOW
                            waitpeq RPMPULSEPIN,RPMPULSEPIN              ' Wait until pin goes HIGH                        
                            mov     stoptime,cnt                         '
                            sub     stoptime,starttime                   '
                            mov     rawvalue, stoptime                   ' leave the value in rawvalue                              
    readPulseLength_ret     ret
    

    the problem seems to be when the pulse length is ~ 2ms then the rawvalue times jump arround.· I know that that spin executes instructions at ~50us so I would imagine that ASM can see a 2ms pulse without breaking sweat!

    I thought about using the counters, but then I still have to waitpeq/waitpne for signal edges, so why would that improve the timing? (apart from avoiding cnt roleover issues)

    Am I making a mistake here?· Is there a better way to do this, preferably non-blocking so I can include other functions in the cog too?

    Thanks again,

    James

    Post Edited (Javalin) : 6/27/2010 2:50:52 PM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2010-06-27 23:58
    Javalin said...
    the problem seems to be when the pulse length is ~ 2ms then the rawvalue times jump arround. I know that that spin executes instructions at ~50us so I would imagine that ASM can see a 2ms pulse without breaking sweat!
    You can measure quite a lot with that piece of code [noparse]:)[/noparse] Imagine a 2ms pulse width but the low part is only e.g. 25% of that (.5ms). So depending on when your code is called you will get results ranging from 2ms (best case) downto .5ms (worst case). So I'd suggest catching two edges (LH) instead of level and edge.
  • JavalinJavalin Posts: 892
    edited 2010-06-28 07:56
    Hiya

    Ah, I gettit. I'll check it out.

    thanks,

    James
  • JavalinJavalin Posts: 892
    edited 2010-06-28 19:30
    Ah.· Got it.· One line sorted it.
    readPulseLength         [i]waitpeq zero,RPMPULSEPIN[/i]                      ' Wait until pin goes LOW
                            waitpeq RPMPULSEPIN,RPMPULSEPIN               ' Wait until pin goes HIGH
                            mov     starttime,cnt                         '
                            waitpeq zero,RPMPULSEPIN                      ' Wait until pin goes LOW
                            waitpeq RPMPULSEPIN,RPMPULSEPIN               ' Wait until pin goes HIGH                        
                            mov     stoptime,cnt                          '
                            sub     stoptime,starttime                    '
                            mov     rawvalue, stoptime                    ' leave the value in rawvalue                              
    readPulseLength_ret     ret
    

    Now it waits for a complete cycle and is still accurate.

    Cheers all,

    James

    Post Edited (Javalin) : 6/28/2010 7:36:09 PM GMT
Sign In or Register to comment.