?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

; *********************************************************************
; *
; *      Big Integer Assembly Helpers
; *  Library for Microchip TCP/IP Stack
; *       - Accelerates processing for BigInt functions
; *
; *********************************************************************
; * FileName:        BigInt_helper.asm
; * Dependencies:    None
; * Processor:       PIC18
; * Compiler:        Microchip C18 v3.30 or higher
; * Company:         Microchip Technology, Inc.
; *
; * Software License Agreement
; *
; * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
; * reserved.
; *
; * Microchip licenses to you the right to use, modify, copy, and
; * distribute:
; * (i)  the Software when embedded on a Microchip microcontroller or
; *      digital signal controller product ("Device") which is
; *      integrated into Licensee's product; or
; * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
; *             ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
; *             used in conjunction with a Microchip ethernet controller for
; *             the sole purpose of interfacing with the ethernet controller.
; *
; * You should refer to the license agreement accompanying this
; * Software for additional information regarding your rights and
; * obligations.
; *
; * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
; * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
; * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
; * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
; * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
; * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
; * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
; * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
; * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
; * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
; * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
; *
; *
; * Author               Date           Comment
; *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; * Elliott Wood             06/20/07   Original
; * Howard Schlunder     11/15/07       Converted to little endian
; ********************************************************************/
 
BIGINT_VARS             udata
        global _iA
        global _iB
        global _iBr             ;  when B is a ROM pointer
        global _iR
        global _xA
        global _xB
        global _xBr             ;  when B is a ROM pointer
        global _wC
_iA                     res     2       ;*_iA, starting pointer for A (low address)
_xA                     res     2       ;*_xA, end pointer for A (high address)
_iB                     res 2   ;*_iB, starting pointer for B (low address)
_xB                     res     2       ;*_xB, end pointer for B (high address)
_iBr            res     3       ;*_iBr, starting pointer for B in ROM (low address)
_xBr            res     3       ;*_xBr, end pointer for B in ROM (high address)
_iR                     res     2       ;*_iR, starting pointer for multiplication Result (low address)
_wC                     res 1   ;Value of C for _masBI (scalar) and _mul (temp storage)

CarryByte       res 1   ;Value of carry for _mul and _sqr (scalar)
CarryH          res 1   ;High value of carry for _sqr (scalar)

BIGINT_CODE             code

#include p18cxxx.inc
#include P18MACRO.INC


;***************************************************************************
; Function:     void _addBI()
;
; PreCondition: _iA and _iB are loaded with the LSB of each BigInt
;                               _xA and _xB are loaded with the MSB of each BigInt
;                               A.size >= B.magnitude
;                               A and B must both be 2048 bits or less (256 bytes)
;
; Input:                A and B, the BigInts to add
;
; Output:               A = A + B
;
; Side Effects: None
;
; Stack Req:    2 bytes
;
; Overview:     Quickly performs the bulk addition of two BigInts
;***************************************************************************
        GLOBAL  _addBI
_addBI:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _xA                                     ;select the assembly pointer bank
        movff   _iA+0x0,FSR0L           ;Put iA in FSR0
        movff   _iA+0x1,FSR0H
        movff   _iB+0x0,FSR2L           ;Put iB in FSR2
        movff   _iB+0x1,FSR2H
        
        ; Predecrement A and B pointers
        movf    POSTDEC0, W
        movf    POSTDEC2, W

        ; Calculate how many adds are needed divided by 8, store count in 
        ; PRODH
        ; Note: This assumes there are no more than 256 adds to do
        decf    _iB+0x0, W
        subwf   _xB+0x0, W
        andlw   0xF8
        movwf   PRODH
        swapf   PRODH, F
        rlncf   PRODH, F
        
        incf    PRODH, F                ; Preincrement so we can start the loop with a decrement
        clrf    PRODL                   ; Start out with no carry
        bra             aTest8Add

        ; Add 8 bytes of B into A at a time.  Doing it in such large 
        ; chunks saves loop and branch overhead
aDo8Add:
        rrcf    PRODL, F                ; Load carry in value
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        movf    PREINC2, W
        addwfc  PREINC0, F
        rlcf    PRODL, F                ; Save carry out value
aTest8Add:      
        decf    PRODH, F
        bnz             aDo8Add


        rrcf    PRODL, F                ; Load carry in value
        bra             aTestResidualAdd


        ; Add up to 7 bytes of B into A, one byte at a time.
aDoResidualAdd:
        movf    PREINC2, W
        addwfc  PREINC0, F

aTestResidualAdd:
        movf    FSR2L, W
        xorwf   _xB+0x0, W
        bnz             aDoResidualAdd

        ; Carry forward the carry out (in A) if needed
        bnc             aDone

aDoFinalCarry:
        movf    FSR0L, W
        xorwf   _xA+0x0, W
        bz              aDone
        incf    PREINC0, F
        bc              aDoFinalCarry

aDone:
        Stk2PopToReg    FSR2L           ;restore FSR2 from stack
        return


;***************************************************************************
; Function:     void _addBIROM()
;
; PreCondition: _iA and _iBr are loaded with the LSB of each BigInt
;                               _xA and _xBr are loaded with the MSB of each BigInt
;                               A.size >= B.magnitude
;                               A and B must both be 2048 bits or less (256 bytes)
;
; Input:                A: a BigInt in RAM
;                               B: a BigInt in ROM
;
; Output:               A = A + B
;
; Side Effects: Overwrites TBLPTRU:TBLPTRH:TBLPTRL registers
;
; Stack Req:    0 bytes
;
; Overview:     Quickly performs the bulk addition of two BigInts
;***************************************************************************
        GLOBAL  _addBIROM
_addBIROM:
        banksel _xA                                     ;Select the assembly pointer bank
        movff   _iA+0x0,FSR0L           ;Put iA in FSR0
        movff   _iA+0x1,FSR0H
        movff   _iBr+0x0,TBLPTRL        ;Put iB in TBLPTR
        movff   _iBr+0x1,TBLPTRH
        movff   _iBr+0x2,TBLPTRU                
        
        ; Predecrement A and B pointers
        movf    POSTDEC0, W
        tblrd*- 

        ; Calculate how many adds are needed divided by 8, store count in 
        ; PRODH
        ; Note: This assumes there are no more than 256 adds to do
        decf    _iBr+0x0, W
        subwf   _xBr+0x0, W
        andlw   0xF8
        movwf   PRODH
        swapf   PRODH, F
        rlncf   PRODH, F
        
        incf    PRODH, F                ; Preincrement so we can start the loop with a decrement
        clrf    PRODL                   ; Start out with no carry
        bra             aRTest8Add

        ; Add 8 bytes of B into A at a time.  Doing it in such large 
        ; chunks saves loop and branch overhead
aRDo8Add:
        rrcf    PRODL, F                ; Load carry in value
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F
        rlcf    PRODL, F                ; Save carry out value
aRTest8Add:     
        decf    PRODH, F
        bnz             aRDo8Add


        rrcf    PRODL, F                ; Load carry in value
        bra             aRTestResidualAdd


        ; Add up to 7 bytes of B into A, one byte at a time.
aRDoResidualAdd:
        tblrd+*
        movf    TABLAT, W
        addwfc  PREINC0, F

aRTestResidualAdd:
        movf    TBLPTRL, W
        xorwf   _xBr+0x0, W
        bnz             aRDoResidualAdd

        ; Carry forward the carry out (in A) if needed
        bnc             aRDone

aRDoFinalCarry:
        movf    FSR0L, W
        xorwf   _xA+0x0, W
        bz              aRDone
        incf    PREINC0, F
        bc              aRDoFinalCarry

aRDone:
        return


;***************************************************************************
; Function:     void _subBI()
;
; PreCondition: _iA and _iB are loaded with the LSB of each BigInt
;                               _xA and _xB are loaded with the MSB of each BigInt
;                               A.size >= B.magnitude
;                               A and B must both be 2048 bits or less (256 bytes)
;
; Input:                A and B, the BigInts to subtract
;
; Output:               A = A - B
;
; Side Effects: None
;
; Stack Req:    2 bytes
;
; Overview:     Quickly performs the bulk subtraction of two BigInts
;***************************************************************************
        GLOBAL  _subBI
_subBI:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _xA                                     ;select the assembly pointer bank
        movff   _iA+0x0,FSR0L           ;Put iA in FSR0
        movff   _iA+0x1,FSR0H
        movff   _iB+0x0,FSR2L           ;Put iB in FSR2
        movff   _iB+0x1,FSR2H
        
        ; Predecrement A and B pointers
        movf    POSTDEC0, W
        movf    POSTDEC2, W

        ; Calculate how many subtracts are needed divided by 8, store 
        ; count in PRODH
        ; Note: This assumes there are no more than 256 subtracts to do
        decf    _iB+0x0, W
        subwf   _xB+0x0, W
        andlw   0xF8
        movwf   PRODH
        swapf   PRODH, F
        rlncf   PRODH, F
        
        incf    PRODH, F                ; Preincrement so we can start the loop with a decrement
        setf    PRODL                   ; Start out with no borrow
        bra             sTest8Subtract

        ; Add 8 bytes of B into A at a time.  Doing it in such large 
        ; chunks saves loop and branch overhead
sDo8Subtract:
        rrcf    PRODL, F                ; Load borrow in value
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        movf    PREINC2, W
        subwfb  PREINC0, F
        rlcf    PRODL, F                ; Save borrow out value
sTest8Subtract: 
        decf    PRODH, F
        bnz             sDo8Subtract


        rrcf    PRODL, F                ; Load borrow in value
        bra             sTestResidualSubtract


        ; Subtract up to 7 bytes of B from A, one byte at a time.
sDoResidualSubtract:
        movf    PREINC2, W
        subwfb  PREINC0, F

sTestResidualSubtract:
        movf    FSR2L, W
        xorwf   _xB+0x0, W
        bnz             sDoResidualSubtract

        ; Carry forward the borrow out (in A) if needed
        bc              sDone

sDoFinalCarry:
        movf    FSR0L, W
        xorwf   _xA+0x0, W
        bz              sDone
        decf    PREINC0, F
        bnc             sDoFinalCarry

sDone:
        Stk2PopToReg    FSR2L           ;restore FSR2 from stack
        return


;***************************************************************************
; Function:     void _subBIROM()
;
; PreCondition: _iA and _iBr are loaded with the LSB of each BigInt
;                               _xA and _xBr are loaded with the MSB of each BigInt
;                               A.size >= B.magnitude
;                               A and B must both be 2048 bits or less (256 bytes)
;
; Input:                A: a BigInt in RAM
;                               B: a BigInt in ROM
;
; Output:               A = A - B
;
; Side Effects: Overwrites TBLPTRU:TBLPTRH:TBLPTRL registers
;
; Stack Req:    None
;
; Overview:     Quickly performs the bulk subtraction of two BigInts
;***************************************************************************
        GLOBAL  _subBIROM
_subBIROM:
        banksel _xA                                     ;Select the assembly pointer bank
        movff   _iA+0x0,FSR0L           ;Put iA in FSR0
        movff   _iA+0x1,FSR0H
        movff   _iBr+0x0,TBLPTRL        ;Put iB in TBLPTR
        movff   _iBr+0x1,TBLPTRH
        movff   _iBr+0x2,TBLPTRU                
        
        ; Predecrement A and B pointers
        movf    POSTDEC0, W
        tblrd*- 

        ; Calculate how many adds are needed divided by 8, store count in 
        ; PRODH
        ; Note: This assumes there are no more than 256 adds to do
        decf    _iBr+0x0, W
        subwf   _xBr+0x0, W
        andlw   0xF8
        movwf   PRODH
        swapf   PRODH, F
        rlncf   PRODH, F
        
        incf    PRODH, F                ; Preincrement so we can start the loop with a decrement
        setf    PRODL                   ; Start out with no borrow
        bra             sRTest8Subtract

        ; Subtract 8 bytes of B from A at a time.  Doing it in such large 
        ; chunks saves loop and branch overhead
sRDo8Subtract:
        rrcf    PRODL, F                ; Load borrow in value
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F
        rlcf    PRODL, F                ; Save borrow out value
sRTest8Subtract:        
        decf    PRODH, F
        bnz             sRDo8Subtract


        rrcf    PRODL, F                ; Load borrow in value
        bra             sRTestResidualSubtract


        ; Subtract up to 7 bytes of B from A, one byte at a time.
sRDoResidualSubtract:
        tblrd+*
        movf    TABLAT, W
        subwfb  PREINC0, F

sRTestResidualSubtract:
        movf    TBLPTRL, W
        xorwf   _xBr+0x0, W
        bnz             sRDoResidualSubtract

        ; Carry forward the borrow out (in A) if needed
        bc              sRDone

sRDoFinalCarry:
        movf    FSR0L, W
        xorwf   _xA+0x0, W
        bz              sRDone
        incf    PREINC0, F
        bnc             sRDoFinalCarry

sRDone:
        return


;***************************************************************************
; Function:     void _zeroBI()
;
; PreCondition: _iA is loaded with the LSB of the BigInt
;                               _xA is loaded with the MSB the BigInt
;
; Input:                A: a BigInt
;
; Output:               A = 0
;
; Side Effects: None
;
; Stack Req:    None
;
; Overview:     Sets all bytes from _iA to _xA to zero
;***************************************************************************
        GLOBAL  _zeroBI
_zeroBI:
        banksel _xA                                     ;select the assembly pointer bank
        movff   _iA+0x0,FSR0L           ;Put iA-1 in FSR0
        movff   _iA+0x1,FSR0H
        movf    POSTDEC0, W
        
zLoop:
        clrf    PREINC0                         ;set byte to zero
        movf    FSR0L,W                         ;check if A is at MSB
        xorwf   _xA+0x0,W                       ;test low byte first
        bnz             zLoop                           ;add to A, and continue
        movf    FSR0H,W                         ;check high byte
        xorwf   _xA+0x1,W                       ;
        bnz             zLoop                           ;if A is not at MSB, we're not done
        
        return


;***************************************************************************
; Function:     void _msbBI()
;
; PreCondition: _iA is loaded with the address of the LSB of the BigInt buffer
;                               _xA is loaded with the address of the right most byte of the BigInt buffer
;
; Input:                None
;
; Output:               _xA is now pointing to the MSB of the BigInt
;
; Side Effects: None
;
; Overview:     Finds the MSB (first non-zero word) of the BigInt, starting 
;                               from the right-most word and testing to the left.  This 
;                               function will stop if _iA is reached.
;***************************************************************************
        GLOBAL  _msbBI
_msbBI:
        banksel _xA                                     ; Select the correct bank
        movff   _xA+0x0,FSR0L           ; Put xA in FSR0
        movff   _xA+0x1,FSR0H

msbLoop:
        movf    FSR0L, W
        subwf   _iA+0x0, W
        bz              msbFound
        movf    POSTDEC0, W                     ; load the next value
        bz              msbLoop                         ; if value isn't zero, this is the MSB
        
        movf    PREINC0, W                      ; Correct the pointer's last decrement
        
        ; Copy FSR0 back to _xA and return
msbFound:
        movff   FSR0L,_xA+0x0           ; Move FSR0 back to iA
        movff   FSR0H,_xA+0x1           
        return


;***************************************************************************
; Function:     void _mulBI()
;
; PreCondition: _iA and _iB are loaded with the LSB of each BigInt
;                               _xA and _xB are loaded with the MSB of each BigInt
;                               _iR is the LSB of the accumulator BigInt
;                               _iR is zeroed, and has enough space
;                               A and B must both by 2048 bits or less (256 bytes max)
;
; Input:                A and B, the BigInts to multiply
;
; Output:               R = A * B
;
; Side Effects: None
;
; Stack Req:    2 bytes
;
; Overview:     Performs the bulk multiplication of two BigInts
;***************************************************************************
        GLOBAL  _mulBI
_mulBI:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _xA                                     ;select the assembly pointer bank

        ; Predecrement B and R pointers
        clrf    WREG
        decf    _iB+0x0, F
        subwfb  _iB+0x1, F
        decf    _iR+0x0, F
        subwfb  _iR+0x1, F

mLoadB:
        ; Load B pointer to FSR2 and increment B pointer
        ; Increment iR to match the new starting position
        ; Fetch new B value
        movff   _iB+0x0, FSR2L
        movff   _iB+0x1, FSR2H  
        clrf    WREG
mLoadBAgain:
        incf    _iB+0x0, F
        addwfc  _iB+0x1, F
        incf    _iR+0x0, F
        addwfc  _iR+0x1, F
        movf    PREINC2, W
        bz              mLoadBAgain                     ; No need to multiply this byte if it is zero
        movwf   _wC

        ; Restore iA start pointer in FSR0
        movff   _iA+0x0, FSR0L
        movff   _iA+0x1, FSR0H

        ; Store new iR start pointer in FSR2
        movff   _iR+0x0, FSR2L
        movff   _iR+0x1, FSR2H

        ; Clear carry byte
        clrf    CarryByte

mLoopA:
        movf    CarryByte, W            ;load carry byte
        addwf   INDF2, F                        ;add to accumulator
        clrf    CarryByte                       ;clear carry byte
        rlcf    CarryByte, F            ;if a carry occurred, save to CarryByte
        movf    _wC, W                          ;load wC
        mulwf   POSTINC0                        ;calculate wC * A[iA++]
        movf    PRODL,W                         ;load low result byte
        addwf   POSTINC2, F                     ;add to accumulator, and move ptr
        movf    PRODH,W                         ;load high result byte
        addwfc  CarryByte, F            ;add to carry byte, along with
                                                                ;  any carry from previous addition

        ; See if A loop is done
        decf    FSR0L, W
        xorwf   _xA+0x0, W
        bnz             mLoopA

        ; If A loop is done, finish out the carrying
        movff   CarryByte, INDF2                ;save carry byte (always adding to zero)

        ; See if B loop is done
        movf    _xB+0x0, W
        xorwf   _iB+0x0, W
        bnz             mLoadB

mDone:
        Stk2PopToReg    FSR2L           ;restore old FSR2
        return
        

;***************************************************************************
; Function:     void _mulBIROM()
;
; PreCondition: _iA and _iBr are loaded with the LSB of each BigInt
;                               _xA and _xBr are loaded with the MSB of each BigInt
;                               _iR is the LSB of the accumulator BigInt
;                               _iR is zeroed, and has enough space
;
; Input:                A: BigInt in RAM
;                               B: BigInt in ROM
;
; Output:               R = A * B
;
; Side Effects: Overwrites TBLPTRU:TBLPTRH:TBLPTRL
;
; Stack Req:    2 bytes
;
; Overview:     Performs the bulk multiplication of two BigInts
;***************************************************************************
        GLOBAL  _mulBIROM
_mulBIROM:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _xA                                     ;select the assembly pointer bank

        ; Predecrement B and R pointers
        movff   _iBr+0x0, TBLPTRL
        movff   _iBr+0x1, TBLPTRH
        movff   _iBr+0x2, TBLPTRU
        tblrd*-
        clrf    WREG
        decf    _iR+0x0, F
        subwfb  _iR+0x1, F

mRLoadB:
        ; Increment iR to match the new starting position
        ; Fetch new B value
        clrf    WREG
mRLoadBAgain:
        incf    _iR+0x0, F
        addwfc  _iR+0x1, F
        tblrd+*
        movf    TABLAT, W
        bz              mRLoadBAgain                    ; No need to multiply this byte if it is zero
        movwf   _wC

        ; Restore iA start pointer in FSR0
        movff   _iA+0x0, FSR0L
        movff   _iA+0x1, FSR0H

        ; Store new iR start pointer in FSR2
        movff   _iR+0x0, FSR2L
        movff   _iR+0x1, FSR2H

        ; Clear carry byte
        clrf    CarryByte

mRLoopA:
        movf    CarryByte, W            ;load carry byte
        addwf   INDF2, F                        ;add to accumulator
        clrf    CarryByte                       ;clear carry byte
        rlcf    CarryByte, F            ;if a carry occurred, save to CarryByte
        movf    _wC, W                          ;load wC
        mulwf   POSTINC0                        ;calculate wC * A[iA++]
        movf    PRODL,W                         ;load low result byte
        addwf   POSTINC2, F                     ;add to accumulator, and move ptr
        movf    PRODH,W                         ;load high result byte
        addwfc  CarryByte, F            ;add to carry byte, along with
                                                                ;  any carry from previous addition

        ; See if A loop is done
        decf    FSR0L, W
        xorwf   _xA+0x0, W
        bnz             mRLoopA

        ; If A loop is done, finish out the carrying
        movff   CarryByte, INDF2                ;save carry byte (always adding to zero)

        ; See if B loop is done
        movf    _xBr+0x0, W
        xorwf   TBLPTRL, W
        bnz             mRLoadB

mRDone:
        Stk2PopToReg    FSR2L           ;restore old FSR2
        return


;***************************************************************************
; Function:     void _sqrBI()
;
; PreCondition: _iA is loaded with the LSB of the BigInt
;                               _xA is loaded with the MSB of the BigInt
;                               _iR is the LSB of the accumulator BigInt
;                               _iR is zeroed, and has enough space
;
; Input:                A: Source BigInt to square
;                               R: Output location
;
; Output:               R = A * A
;
; Side Effects: None
;
; Stack Req:    6 bytes
;
; Overview:     Performs the bulk multiplication of two BigInts
;***************************************************************************
        GLOBAL  _sqrBI
_sqrBI:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _iA                                     ;select the assembly pointer bank

        ;decement iA (to set up for termination case)
        clrf    WREG                            ;load zero to W
        decf    _iA,F                           ;decrement iA
        subwfb  _iA+0x1,F                       ;borrow if needed

        ;set up for outer loop over all values of A
        Stk2PushFromReg _iR                     ;save initial iR to stack
        Stk2PushFromReg _iA                     ;save initial iA to stack

qOuterLoop:
        Stk2PopToReg    FSR0L           ;pop next iA from stack
        Stk2PopToReg    FSR2L           ;pop next iR from stack

        ;check if outer loop is done
        movf    FSR0L,W                         ;check if low byte of A ptr
        xorwf   _xA+0x0,W                       ;  equals low byte of stop ptr
        bnz             qNextOut                        ;if not, work on next byte of A
        movf    FSR0H,W                         ;check if high byte of A ptr
        xorwf   _xA+0x1,W                       ;  equals high byte of stop ptr
        bz              qDone                           ;if so, terminate

qNextOut:
        ;save next value of iR
        movf    PREINC2,W                       ;decrement iR twice for next value
        movf    PREINC2,W
        Stk2PushFromReg FSR2L           ;save next value of iR to stack
        movf    POSTDEC2,W                      ;restore iR value
        movf    POSTDEC2,W

        ;save next value of iA
        movf    PREINC0,W                       ;decrement iA for next value
        Stk2PushFromReg FSR0L           ;save next value of iA to stack

        ;load wC with value of A[iA--]
        ;check wC==0, if so then we can skip this byte
        movf    POSTDEC0,W                      ;restore iA and copy value
        bz              qOuterLoop                      ;if B==0, continue to next byte
        movwf   _wC                                     ;  into temporary byte
        
        ;set up for inner loop over all remaining values in A
        clrf    CarryByte                       ;clear carry bytes
        clrf    CarryH

        ;first result only gets accumulated once
        mulwf   PREINC0                         ;square first byte (W = B above)
        movf    PRODL,W                         ;load PRODL
        addwf   POSTINC2,F                      ;accumulate
        movf    PRODH,W                         ;load PRODH
        addwfc  CarryByte,F                     ;save carry byte (with prev carry)

qInnerLoop:
        ;if A isn't complete, keep looping
        movf    FSR0L,W                         ;check if low byte of A ptr
        xorwf   _xA+0x0,W                       ;  equals low byte of stop ptr
        bnz             qInnerByte                      ;if not, continue looping
        movf    FSR0H,W                         ;check if high byte of A ptr
        xorwf   _xA+0x1,W                       ;  equals high byte of stop ptr
        bz              qInnerDone                      ;if not, continue looping

qInnerByte:
        ;all future bytes get accumulated twice
        movf    CarryByte,W                     ;load carry byte
        addwf   INDF2,F                         ;add to accumulator
        movff   CarryH,CarryByte        ;move high carry byte down
        clrf    CarryH
        btfsc   STATUS,C                        ;if a carry occurred
        incf    CarryByte,F                     ;  add 1 to the carry byte
        movf    _wC,W                           ;load B
        mulwf   PREINC0                         ;calculate B * A[iA--]
        bcf             STATUS,C                        ;multiply product by 2
        rlcf    PRODL,F                         
        rlcf    PRODH,F
        btfsc   STATUS,C                        ;if a carry occurrs
        incf    CarryH,F                        ;  save 1 to the CarryH byte
        movf    PRODL,W                         ;load low result byte
        addwf   POSTINC2,F                      ;add to accumulator, and move ptr
        movf    PRODH,W                         ;load high result byte
        addwfc  CarryByte,F                     ;add to carry byte, along with
                                                                ;  any carry from previous addition
        btfsc   STATUS,C                        ;if a carry occurrs
        incf    CarryH,F                        ;  save 1 to the CarryH byte
        bra             qInnerLoop
        

qInnerDone
        ;A is complete, finish out the carrying
        movf    CarryByte,W                     ;accumulate the carry bytes
        addwf   POSTINC2,F
        movf    CarryH,W
        addwfc  INDF2
        bra             qOuterLoop

qDone:
        ;movff  FSR2L,_iR+0x0
        ;movff  FSR2H,_iR+0x1
        Stk2PopToReg    FSR2L           ;restore old FSR2
        return


;***************************************************************************
; Function:     void _masBI()
;
; PreCondition: _iB is loaded with the LSB of the modulus BigInt
;                               _xB is loaded with the MSB of the modulus BigInt
;                               _wC is loaded with the 8 bit integer by which to multiply
;                               _iR is the starting LSB of the decumulator BigInt
;                               B must be 256 bytes or less
;
; Input:                B: a BigInt to multiply with wC
;                               wC: a simple scalar
;                               R: a BigInt decumulator to subtract the result from
;
; Output:               R = R - (B * wC)
;
; Side Effects: None
;
; Stack Req:    2 bytes
;
; Overview:     Performs a Multiply And Subtract function.  This is used in
;                               the modulus calculation.
;
; Note:                 As an optimization, the final borrow forward propagation 
;                               is commented out below.  This results in an a potentially 
;                               incorrect result in R, but for the BigIntMod() algorithm, 
;                               the final borrow forward propagation would be both unneeded 
;                               and unwanted.  For BigIntMod(), this underflow is repaired 
;                               by adding B back into R one or two times.
;***************************************************************************
        GLOBAL  _masBI
_masBI:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _xB                                     ;select the assembly pointer bank
        
        ; Load B pointer into FSR2 and R pointer into FSR0
        movff   _iR+0x0, FSR0L          ;load iR into FSR0
        movff   _iR+0x1, FSR0H
        movff   _iB+0x0, FSR2L          ;load iB into FSR2
        movff   _iB+0x1, FSR2H
        
        ; Predecrement B pointer
        movf    POSTDEC2, W     
        
        ; Calculate loop counters for /4 and /1
masLoop4Init:
        clrf    CarryByte
        movf    FSR2L, W
        subwf   _xB+0x0, W
        bcf             STATUS, C
        rrcf    WREG, W
        rlcf    CarryByte
        rrcf    WREG, W
        btfsc   STATUS, C
        bsf             CarryByte, 1
        movwf   CarryH

        movf    CarryH, F
        bz              masLoopInit             

        clrf    WREG

masLoop4:
        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        mulwf   PREINC2                         ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W

        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        mulwf   PREINC2                         ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W

        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        mulwf   PREINC2                         ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W
        
        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        mulwf   PREINC2                         ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W
        
        ; See if we've looped through all (B bytes)/4
        decfsz  CarryH, F
        bra             masLoop4


masLoopInit:
        movf    CarryByte, F
        bz              masFinalBorrow          

masLoop:
        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        mulwf   PREINC2                         ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W

        ; See if we've looped through all B bytes in the residual
        decfsz  CarryByte, F
        bra             masLoop

        ; If B is complete, finish out the borrow and return
masFinalBorrow:
        subwf   POSTINC0, F

        Stk2PopToReg    FSR2L           ;restore old FSR2
        return


;***************************************************************************
; Function:     void _masBIROM()
;
; PreCondition: _iBr is loaded with the LSB of the modulus BigInt
;                               _xBr is loaded with the MSB of the modulus BigInt
;                               _wC is loaded with the 8 bit integer by which to multiply
;                               _iR is the starting LSB of the decumulator BigInt
;                               Br must be 256 bytes or less
;
; Input:                Br: a BigInt in ROM to multiply with wC
;                               wC: a simple scalar
;                               R: a BigInt decumulator in RAM to subtract the result from
;
; Output:               R = R - (Br * wC)
;
; Side Effects: Overwrites TBLPTRU:TBLPTRH:TBLPTRL
;
; Stack Req:    None
;
; Overview:     Performs a Multiply And Subtract function.  This is used in
;                               the modulus calculation.
;
; Note:                 As an optimization, the final borrow forward propagation 
;                               is commented out below.  This results in an a potentially 
;                               incorrect result in R, but for the BigIntMod() algorithm, 
;                               the final borrow forward propagation would be both unneeded 
;                               and unwanted.  For BigIntMod(), this underflow is repaired 
;                               by adding B back into R one or two times.
;***************************************************************************
        GLOBAL  _masBIROM
_masBIROM:
        banksel _xB                                     ;select the assembly pointer bank
        
        ; Load B pointer into TBLPTR and R pointer into FSR0
        movff   _iR+0x0, FSR0L          ;load iR into FSR0
        movff   _iR+0x1, FSR0H
        movff   _iBr+0x0, TBLPTRL       ;load iBr into TBLPTR
        movff   _iBr+0x1, TBLPTRH
        movff   _iBr+0x2, TBLPTRU
        
        ; Predecrement Br pointer and set up carry byte
        tblrd*-

        ; Calculate loop counters for /4 and /1
masRLoop4Init:
        clrf    CarryByte
        movf    TBLPTRL, W
        subwf   _xBr+0x0, W
        bcf             STATUS, C
        rrcf    WREG, W
        rlcf    CarryByte
        rrcf    WREG, W
        btfsc   STATUS, C
        bsf             CarryByte, 1
        movwf   CarryH

        movf    CarryH, F
        bz              masRLoopInit            

        clrf    WREG

masRLoop4:
        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        tblrd+*
        mulwf   TABLAT                          ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W

        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        tblrd+*
        mulwf   TABLAT                          ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W

        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        tblrd+*
        mulwf   TABLAT                          ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W

        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        tblrd+*
        mulwf   TABLAT                          ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W
        
        ; See if we've looped through all B bytes
        decfsz  CarryH, F
        bra             masRLoop4


masRLoopInit:
        movf    CarryByte, F
        bz              masRFinalBorrow         

masRLoop:
        subwf   INDF0, F                        ;subtract from decumulator
        movf    _wC, W                          ;load B
        tblrd+*
        mulwf   TABLAT                          ;calculate wC * B[iB--]
        btfss   STATUS, C                       ;if a borrow occurred
        incf    PRODH, F                        ;  save 1 to the carry byte
        movf    PRODL, W                        ;load low result byte
        subwf   POSTINC0, F                     ;subtract from decumulator, and move ptr
        movf    PRODH, W
        btfss   STATUS, C
        incf    PRODH, W
        
        ; See if we've looped through all B bytes in the residual
        decfsz  CarryByte, F
        bra             masRLoop

        ; If B is complete, finish out the borrow and return
masRFinalBorrow:
        subwf   POSTINC0, F

        return
        

;***************************************************************************
; Function:     void _copyBI()
;
; PreCondition: _iA and _iB are loaded with the LSB of each BigInt
;                               _xA and _xB are loaded with the MSB of each BigInt
;                               B must be 256 bytes or less
;
; Input:                A: the destination
;                               B: the source
;
; Output:               A = B
;
; Side Effects: None
;
; Stack Req:    2 bytes
;
; Overview:     Copies a value from BigInt B into BigInt A.  If A has more 
;                               bytes allocated than B, then the most significant bytes in 
;                               A are zero padded.  If A has less bytes allocated than B, 
;                               then the most significant bytes are truncated off in A.
;***************************************************************************
        GLOBAL  _copyBI
_copyBI:
    Stk2PushFromReg FSR2L               ;Save FSR2 on the stack
        banksel _xA                                     ;select the assembly pointer bank

        ;Load and predecrement iA, iB (to set up termination case)
        movff   _iA+0x0, FSR0L          ;load iA into FSR0
        movff   _iA+0x1, FSR0H
        movff   _iB+0x0, FSR2L          ;load iB into FSR2
        movff   _iB+0x1, FSR2H
        movf    POSTDEC0, W
        movf    POSTDEC2, W
        
cLoop:
        movff   PREINC2, PREINC0        ;copy B to A
        movf    FSR2L, W                        ;check if low byte of B ptr
        xorwf   _xB+0x0, W                      ;  equals low byte of stop ptr
        bz              cZeroTest                       ;if so, B is done, so clear rest of A

        movf    FSR0L, W                        ;check if low byte of A ptr
        xorwf   _xA+0x0, W                      ;  equals low byte of stop ptr
        bnz             cLoop                           ;if not, continue
        movf    FSR0H, W                        ;check if high byte of A ptr
        xorwf   _xA+0x1, W                      ;  equals high byte of stop ptr
        bnz             cLoop                           ;if so, terminate

        bra             cZeroTest

cZero:
        clrf    PREINC0                         ;set A byte to zero

cZeroTest:
        movf    FSR0L, W                        ;check if low byte of A ptr
        xorwf   _xA+0x0, W                      ;  equals low byte of stop ptr
        bnz             cZero                           ;if not, continue
        movf    FSR0H, W                        ;check if high byte of A ptr
        xorwf   _xA+0x1, W                      ;  equals high byte of stop ptr
        bnz             cZero                           ;if so, terminate

        Stk2PopToReg    FSR2L           ;restore old FSR2
        return


  end
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3