N-Bit_MATH


Closed Thread
Results 1 to 39 of 39

Thread: N-Bit_MATH

Hybrid View

  1. #1
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Cool N-Bit_MATH

    I recently came across these great routines from Alexander Avtanski, on the PicList ...
    http://avtanski.net/projects/math/
    All credit goes to Alexander!

    Everything was there, it just needed a few tweaks to be used with PicBasic Pro.

    They're so cool ...

    8, 16, 24, 32, 64, 128-bit Integer Math or more.
    You want BIG numbers? .... you got 'em.
    N-Bit means any number of bits.

    16F, 18F ... doesn't matter (other than RAM space), and you must be using MPASM.
    <hr>
    The number of bytes used in the math depends on the PRECISION constant.
    If PRECISION = 4, then all math is done as 32-bit operations.

    So you need to have variables of the same size, which is easy to do with ...
    Code:
    PRECISION  CON 4 SYSTEM         ' 4 bytes = 32-bit
    
    SetPoint  VAR BYTE[PRECISION]
    Position  VAR BYTE[PRECISION]
    Error     VAR BYTE[PRECISION]
    Current   VAR BYTE[PRECISION]
    MyVar     VAR BYTE[PRECISION]
    Then you can do the math on those variables with ...
    Code:
    @  MATH_SUB  _SetPoint, _Position, _Error   ; subtract Position from setpoint
    Which subtracts Position from Setpoint and puts the result in Error.
    <hr>

    All I've done is put a "wrapper" around the original routines from Alexander, so they can still be used exactly like the webpage says.
    I've also added some macros to make things easier with PBP.

    Code:
    @  MATH_CLR  _Pvar               ; clear an N-Bit variable
    @  MATH_INC  _Pvar               ; increment an N-Bit variable
    @  MATH_DEC  _Pvar               ; decrement an N-Bit variable
    @  MATH_ROL  _Pvar               ; rotate LEFT
    @  MATH_ROR  _Pvar               ; rotate RIGHT
    @  MATH_CMP  _A, _B              ; Compare Pvars - result in M_EQ and M_GTE bits
    @  MATH_ADD  _A, _B, _Res        ; Res = A + B
    @  MATH_SUB  _A, _B, _Res        ; Res = A - B
    @  MATH_MUL  _A, _B, _Res        ; Res = A * B
    @  MATH_DIV  _A, _B, _Res        ; Res = A / B - Remainder in REG_Z
    At this point I'm calling them Pvar's because unlike a byte or word, they could be any length specified by the PRECISION constant.
    ALL math done with these routines are done at the PRECISION level, and all variables used with the MATH functions must be (PRECISION) bytes in length.

    Additional macros were created to allow movement of variables between bytes, words, longs and the Pvars.
    Code:
    @  MOVE?CP  Cin, _Pout           ; copy a CONSTANT to a Pvar
    @  MOVE?BP  _Bin, _Pout          ; copy a BYTE to a Pvar
    @  MOVE?WP  _Win, _Pout          ; copy a WORD to a Pvar
    @  MOVE?LP  _Lin, _Pout          ; copy a LONG to a Pvar (PBPL only)
    @  MOVE?PP  _BeerIN, _Pout       ; copy a Pvar to a Pvar
    And the inverse of those puts them back into PBP variables again.
    Code:
    @  MOVE?PB  _Pin, _Bout          ; truncate a Pvar into a BYTE var
    @  MOVE?PW  _Pin, _Wout          ; truncate a Pvar into a WORD var 
    @  MOVE?PL  _Pin, _Lout          ; truncate a Pvar into a LONG var (PBPL only)


    So let's say you were getting a 16-bit value from the QEI counter, and the upper 16-bits from a Rollover interrupt.
    You could move them all into a Pvar with two lines ...
    Code:
    RollOvers  VAR WORD                        ; QEI rollovers (from interrupt)
    
    @  MOVE?WP   POSCNTL, _Position            ; copy QEI count to Position.Word0
    @  MOVE?WW   _RollOvers, _Position + 2     ; copy rollovers to Position.Word1
    
       ;-- Calculate the Error --
    @  MATH_SUB  _SetPoint, _Position, _Error  ; Error = Setpoint - Position
    @  MOVE?PW   _Error, _pid_Error            ; copy Pvar result to a WORD variable
    This way you can do 32-bit math without PBPL. Or 64-bit if you needed.
    It's not as easy as PBPL, but can be very useful.

    Keep in mind that the math is all Software. Multiplication does not use the hardware multiplier.
    So with 18F's, MATH_MUL at 32-bits will take longer than PBPL with 32-bits.

    However, you can still use all of the math statements within PBP, and they will be faster without PBPL, or BIGGER with PBPL.



    Another recent request from someone in this forum was to have a counter that keeps track of the number of milliseconds since the power was turned on.
    That can be a pretty big number ... if it's been powered-up for a decade or two.
    No problem ...

    Code:
    '----[N-Bit Math]-----------------------------------------------------------
    PRECISION  CON 5 SYSTEM          ; 5 bytes=40-bit
    INCLUDE "N-Bit_MATH.pbp"
    
    Powered_MS   VAR BYTE[PRECISION]
    
    MS_intHandler:  ; this routine should be called every mS via a timer interrupt
      @ FSRSAVE                   ; Save FSR value before interrupt code
      @ MATH_INC  _Powered_MS     ; increment # of mS since PWR_ON
      @ FSRREST                   ; Restore FSR
    ; return from interrupt, depends on the type of interrupt.
    ; interrupt code and context saving not shown.
    That will happily count the number of milliseconds passed for over 34 years. 2<sup>^</sup>40/(1000*60*60*24*365)
    If you need it to count longer ... go with 6 byte PRECISION (8,925 years).

    <hr>
    The routines are completely ASM, and do not use any of PBP's system variables. So it's OK to use them within ASM type Interrupts if desired.
    But you'll need to save the FSR value before doing any MATH because it uses the FSR and would disrupt the flow of the Main program if not saved.

    The @ FSRSAVE and @ FSRREST can be used to make it easy.

    Note: DT_INTS already saves/restores the FSR's at the beginning/end of an interrupt, so you don't have to.
    For ASM interrupts, you will need to save it. FSR's don't matter with ON INTERRUPT.

    <hr>
    Please understand that these are "Advanced Level" math routines.
    I can not debug everyone's program that ends up not compiling because of syntax errors.

    If you truely believe that something is wrong with the routines, I would love to hear it. And I will do my best to fix it.
    If you can't get it to compile ... keep trying ... it will.

    Here's the Include File.
    Current Version = 1.4 Beta (8/4/2010); Workaround for MPASMs shift > 32-bits

    History:
    &nbsp; &nbsp; 1.3 Beta 1/7/2010 ; compatability with 16F1xxx chips (enhanced core)
    &nbsp; &nbsp; 1.2 Alpha 1/4/2010 ; adds ability to turn Case Sensitivity off in MPASM
    &nbsp; &nbsp; 1.1 Alpha 1/4/2010 ; fixes FSR conflict with DT_INTS-18
    &nbsp; &nbsp; 1.0 Alpha 1/3/2010 ; initial release
    Attached Files Attached Files
    Last edited by Darrel Taylor; - 5th August 2010 at 00:27. Reason: Version 1.4
    DT

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hopefully, more info and examples forthcoming.
    <br>

  3. #3
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    Very cool! I've got to try these out. Thanks Alexander and Darrel!

  4. #4
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,816


    Did you find this post helpful? Yes | No

    Default

    As always, a great Darrel Taylor's project!

    Thanks!

    Ioannis

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default

    Wow, this is going to be very cool Darrel!
    I know you said to keep trying if it wouldn't compile but I can't seem to get it to "go thru" when using it in the same program as DT-Ints... Boiled down example, this compiles:
    Code:
    PRECISION CON 4 SYSTEM
    INCLUDE "N-Bit_Math.pbp"
    
    Setpoint VAR BYTE[PRECISION]
    Position VAR BYTE[PRECISION]
    Error VAR BYTE[PRECISION]
    
    Start:
    Pause 10
    Goto Start
    This does not compile (or assemble):
    Code:
    PRECISION CON 4 SYSTEM
    INCLUDE "N-Bit_Math.pbp"
    INCLUDE "DT_INTS-18.pbp"             'Include the interrupt system files.
    INCLUDE "ReEnterPBP-18.pbp"
    
    ASM
    INT_LIST    macro   ;IntSource    Label   Type   ResetFlag
           INT_Handler INT2_INT,    _DoStep,   PBP,     yes                                
                endm
        INT_CREATE
    ENDASM
    
    @ INT_ENABLE INT2_INT
    
    Setpoint VAR BYTE[PRECISION]
    Position VAR BYTE[PRECISION]
    Error VAR BYTE[PRECISION]
    
    Start:
    Pause 10
    Goto Start
    
    DoStep:
    Toggle PortB.7
    @ INT_RETURN
    I get a whole bunch of Symbol not previously defined FSR0L0L and so on.

    Similarily, same code as above but simply removing the INCLUDE "N-Bit_Math.pbp"-line also compiles fine so there seems to be some incompatibillity there.I'm using 18F2431 but the device selected in MCS+ doesn't seem to matter.

    Any ideas what might be the issue?
    Thanks!
    /Henrik.

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hmmm, apparently it's laughing at my use of FSR's "FSR0L0L".

    You are correct, there is a conflict when used with DT_INTS-18.
    DT-INTS-14 is OK.

    I must find a way around it.

    Thanks Henrik.
    DT

  7. #7
    Join Date
    Oct 2004
    Posts
    46


    Did you find this post helpful? Yes | No

    Default How do you display large numbers in decimal format instead of binary?

    Not being the brightest bulb in the math department, I was trying to figure out how to display the value of 100000 in decimal format on the debug screen.

    So if I have the following loaded into a PVAR called SetPoint

    SetPoint[0] = 160
    SetPoint[1] = 134
    SetPoint[2] = 1
    SetPoint[3] = 0

    How can I display is as 100000 as opposed to:

    00000000000000011000011010100000

    Hoping someone can point me in the right direction.

    Eric




    put 100000 into a PRECISION variable. Using a calculator I found the binary equivalent of 100000 and then took each byte and calculated the decimal value of it and plugged it in as shown below. Obviously this is quite laborious

    PRECISION CON 4 SYSTEM
    include "NBit_Math.bas"
    SetPoint VAR BYTE[PRECISION]
    SetPoint[0] = 160
    SetPoint[1] = 134
    SetPoint[2] = 1
    SetPoint[3] = 0

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Much easier than using a calculator and separating the bytes.
    You can load the number you want like this ...

    Code:
    @  MOVE?CP  100000, _SetPoint
    Which puts up to a 32-bit Constant (4,294,967,295) into a PVAR.

    Displaying the big numbers is just a matter of dividing them down to useable amounts.
    For small numbers like 100,000 a single divide will do.
    Code:
    Divisor    VAR BYTE[PRECISION]
    Result     VAR BYTE[PRECISION]
    WordVar    VAR WORD
    Remainder  VAR WORD
    
    @   MOVE?CP   10000, _Divisor              ; load 10,000 into Divisor
    @   MATH_DIV  _SetPoint, _Divisor, _Result ; isolate lowest 4 digits
    @   MOVE?PW   _Result, _WordVar            ; copy Result to a PBP Word
    @   MOVE?PW   REG_Z, _Remainder            ; copy remainder to a PBP Word 
    
        IF WordVar > 0 THEN 
            LCDOUT DEC Wordvar, DEC4 Remainder
        ELSE
            LCDOUT DEC Remainder
        ENDIF
    It should work up to 655,359,999. Larger numbers will require more divisions.
    That's just off the top of my head, untested.
    Let me know if you have problems.
    Last edited by Darrel Taylor; - 14th March 2010 at 04:49. Reason: Added DEC to first LCDOUT ... removed ENDASM
    DT

  9. #9
    Join Date
    Oct 2004
    Posts
    46


    Did you find this post helpful? Yes | No

    Default Works fantastically!

    Darrel,
    Thanks so much for your help. I've got it displaying the large values perfectly.
    Eric

  10. #10


    Did you find this post helpful? Yes | No

    Default N-bit_Math strange behavior

    Hi!

    I have been away from PIC and PICbasic world over one and a half year now. However, I'm back again and run to a really strange thing. I have slightly over 28 k code where I need 36 bits for calculations, so I found that wonderful N-bit_Math (just beautiful). There is however, something strange going on.
    the code for N-bits is as suggested by Darrel. And compiles without errors and warnings, as long as .... here is the code:

    Code:
    PRECISION CON 5 SYSTEM           ' 5*8 = 40 bits, byte size for registers
    include "N-Bit_Math.pbp"
    
    define OSC 48               ' used clock frequenze
    
    SetPoint  VAR BYTE[PRECISION]
    Position  VAR BYTE[PRECISION]
    Error       VAR BYTE[PRECISION]
    Current   VAR BYTE[PRECISION]
    MyVar     VAR BYTE[PRECISION]
    by  var byte
    wo  var word
    LHi var word
    LMi var word
    LLo var word
    
    LHi = $7: LMi = $2174: LLo = $6FD9
    for by = 0 to 4
       select case by
         case 0,1 : wo = LLo
         case 2,3 : wo = LMi
         case 4   : wo = LHi
       end select
      ' SetPoint[2] = wo & $FF                                  'A
               if (by & 1) = 0 _
                 then
                   by= by  '    SetPoint[by] = wo & $FF    ' B
                 else 
                   by=by  '   SetPoint[by] = wo >> 8       ' C
               endif
    next by
    @ MATH_DIV  _SetPoint, _Position, _Error
    There are three comments (A,B and C). Depending on what combination you have will give different results for the compilation. As it is "now", SetPoint not involved, it compiles OK.

    If I enable A then there are two warnings one saying both in the .mac file and ..pbppic18.lib file that "Address exceeds maximum range for this processor".

    If I enable B and/or C without A then there is one Error (126) in pbppic18.lib saying "argument out of range (32816 not between 0-32767) and bunch of warnings, all saying "Address exceeds maximum range for this processor" in .lib and .mac files.

    If I copy that to a new file and compile it then there are no problems to compile it.

    I have been looking around the rest of the code to found something strange but can not image what it would be.

    I'm using PicBasic pro 2.50b, MPASM and target is 18F4550.

    The real question is:
    What can in a code (the rest of it), what could make the compiler to act like that. Any ideas ?
    Any suggestion what to look for? Please help....

  11. #11
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    If you un-comment B or C, then you end up with invalid statements.

    But in general, it looks like your program is larger than the chips memory.
    No way to know with only a snippet of your code.

    And, it would be easier to load the SetPoint this way ...
    Code:
    @ MOVE?CP  21746FD9h, _SetPoint
      SetPoint(4) = 7
    DT

  12. #12


    Did you find this post helpful? Yes | No

    Cool

    Quote Originally Posted by Darrel Taylor View Post
    If you un-comment B or C, then you end up with invalid statements.

    But in general, it looks like your program is larger than the chips memory.
    No way to know with only a snippet of your code.

    And, it would be easier to load the SetPoint this way ...
    Code:
    @ MOVE?CP  21746FD9h, _SetPoint
      SetPoint(4) = 7
    Thanks Darrel,

    chips memory should be 32k (18F4550) and within the IF statement only two times by = by and not any SetPoint "statements" then the compiled size is 28692 bytes. That is the strange thing here, how can one explain that?

    I tested this:
    @ MOVE?CP 21746FD9h, _SetPoint
    SetPoint(4) = 7
    no problems, once,
    BUT
    when there more than one then the problems are "familiar" from those earlier mentioned. It seems that .... only guessing, that the compiler is allergic to SetPoint
    of course not so, but again there is something here that I do not grasp...
    OR
    do I miss something from the hole picture here
    Here is the code with more @ MOVE?CPs:
    Code:
    @ MOVE?CP  21746FD9h, _SetPoint
      SetPoint(4) = 7
    @ MATH_DIV  _SetPoint, _Position, _Error  
    @ MOVE?CP  21756FD9h, _SetPoint
      SetPoint(4) = 6
    @ MATH_DIV  _SetPoint, _Position, _Error  
    @ MOVE?CP  21766FD9h, _SetPoint
      SetPoint(4) = 5
    @ MATH_DIV  _SetPoint, _Position, _Error  
    @ MOVE?CP  21776FD9h, _SetPoint
      SetPoint(4) = 4
    @ MATH_DIV  _SetPoint, _Position, _Error

  13. #13
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    There's no way for me to tell what's happening, since your snippets all compile.

    If I had your whole program, maybe I could see what's going on.
    DT

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts