;*************************************************************************** ; ; 16-bit Arithmetic Routines V1.01 ; ================================= ; ; written by Peter Luethi, 2010/05/03, Switzerland ; http://www.electronic-engineering.ch ; last update: 2010/05/14 ; ; This code and accompanying files may be distributed freely and ; modified, provided this header with my name and this notice remain ; intact. Ownership rights remain with me. ; You may not sell this software without my approval. ; ; This software comes with no guarantee or warranty except for my ; good intentions. By using this code you agree to indemnify me from ; any liability that might arise from its use. ; ; ; SPECIFICATIONS ; ============== ; Processor: any 8-bit Microchip PIC controller ; ; ; DESCRIPTION ; =========== ; Provides basic 16-bit arithmetic routines: ; CLR16 DST ; INIT16 DST, VAL ; MOV16 DST, SRC ; MOVI16 DST, SRC ; NEG16 DST ; INC16 DST ; DEC16 DST ; LSR16 DST ; LSL16 DST ; SUB16 DST, SUB (handles carry bit correctly) ; SUBI16 DST, SUB (handles carry bit correctly) ; ADD16 DST, SRC ; ADDI16 DST, SRC ; CMP16 X, Y (handles zero and carry bits correctly) ; CMPI16 X, Y (handles zero and carry bits correctly) ; TSTF16 X (handles zero bit correctly) ; ; ; DECLARATIONS needed in MAIN PROGRAM ; =================================== ; - ; ; ; LIMITATIONS ; =========== ; Only for little-endian systems, i.e, &HI = &LO+1 ; Thus ensure, high byte is located directly above low byte, e.g. ; LO_val equ BASE+0x0 ; HI_val equ BASE+0x1 ; ; ; REQUIRED MEMORY ; =============== ; - ; ; ; CREDITS ; ======= ; Chuck McManis (http://www.mcmanis.com/chuck) ; for his 16 bit arithmetic routines (16bits.inc) at ; http://www.mcmanis.com/chuck/Robotics/pic_index.html ; ; ; HISTORY ; ======= ; 2010/05/03 1.00 Initial release based on code of Chuck McManis ; 2010/05/14 1.01 Added tstf16, similar to 8-bit variant tstf ; ;*************************************************************************** #DEFINE M_16BIT_ID dummy ;***** INCLUDE FILES ***** ;***** CONSTANT DECLARATION ***** ;***** REGISTER DECLARATION ***** ;***** MACROS ***** ; 16 bit clear (set to zero) CLR16 macro DST clrf DST clrf DST+1 endm ; 16 bit initialize INIT16 macro DST, VAL IF (VAL == 0) CLR16 DST ; use clr macro ELSE movlw low VAL movwf DST movlw high VAL movwf DST+1 ENDIF endm ; 16 bit move from SRC to DST ; DST <- SRC MOV16 macro DST, SRC movfw SRC movwf DST movfw SRC+1 movwf DST+1 endm MOVI16 macro DST, SRC INIT16 DST, SRC endm ; negate 16 bit value (two's complement) NEG16 macro DST comf DST,f ; complement of low byte comf DST+1,f ; complement of high byte INC16 DST endm ; increment 16 bit value, including proper zero flag handling INC16 macro DST incfsz DST,w ; increment low byte decf DST+1,f ; no carry (negates next step in case of no carry) incf DST+1,f ; increment high byte movwf DST ; store updated low byte iorwf DST+1,w ; update zero flag accordingly endm ; decrement 16 bit value, including proper zero flag handling DEC16 macro DST decf DST,f ; decrement low byte incfsz DST,w ; check for underflow incf DST+1,f ; adjust (negates next step in case of no carry) decf DST+1,f ; update movfw DST iorwf DST+1,w ; update zero flag accordingly endm ; 16 bit logical shift right LSR16 macro DST bcf STATUS,C ; clear carry rrf DST+1,f ; rotate right high byte rrf DST,f ; rotate right low byte endm ; 16 bit logical shift left LSL16 macro DST bcf STATUS,C ; clear carry rlf DST,f ; rotate left low byte rlf DST+1,f ; rotate left high byte endm ; 16 bit unsigned subtraction ; DST = DST - SUB ; DST is replaced, SUB is preserved, carry bit is set correctly ; X = X - Y: C = 1: X >= Y ; C = 0: X < Y SUB16 macro DST, SUB ; DST & SUB are 16 bit register locations movfw SUB ; get low byte of subtrahend subwf DST,f ; compute low byte (result = f - w) movfw SUB+1 ; get high byte of subtrahend skpc ; if carry, result is zero or positive incfsz SUB+1,w ; if no carry, increment high byte of subtrahend subwf DST+1,f ; compute high byte (result = f - w) endm ; Note: carry bit is only handled if SUB > 0 SUBI16 macro DST, SUB ; DST is 16 bit register location, SUB is literal IF (SUB > 0) movlw low SUB ; get low byte of subtrahend subwf DST,f ; compute low byte (result = f - w) movlw high SUB ; get high byte of subtrahend skpc ; if carry, result is zero or positive movlw (high SUB)+1 ; if no carry, increment high byte of subtrahend subwf DST+1,f ; compute high byte (result = f - w) ENDIF endm ; 16 bit unsigned addition ; DST = DST + SRC ; DST is replaced, SRC is preserved, carry bit is set correctly ADD16 macro DST, SRC movfw SRC ; get low byte addwf DST,f ; compute low byte (result = f + w) movfw SRC+1 ; get high byte addcf SRC+1,w ; add carry, if existing addwf DST+1,f ; compute high byte (result = f + w) endm ; Note: carry bit is only handled if SRC > 0 ADDI16 macro DST, SRC IF (SRC > 0) movlw low SRC ; get low byte addwf DST,f ; compute low byte (result = f + w) movlw high SRC ; get high byte skpnc movlw (high SRC) + 1 ; get high byte + 1 addwf DST+1,f ; compute high byte (result = f + w) ENDIF endm ; compare two 16-bit values, including proper flag handling ; cmp(X,Y): Z = 1: X == Y ; C = 1: X >= Y ; C = 0: X < Y CMP16 macro X, Y local _CMP_DONE movfw Y+1 ; get high byte subwf X+1,w ; compare high bytes bnz _CMP_DONE ; if not zero, we're done movfw Y ; get low byte subwf X,w ; compare low byte _CMP_DONE ; flags are now all set correctly (C & Z) endm CMPI16 macro X, Y local _CMP_DONE movlw high Y ; get high byte subwf X+1,w ; compare high bytes bnz _CMP_DONE ; if not zero, we're done movlw low Y ; get low byte subwf X,w ; compare low byte _CMP_DONE ; flags are now all set correctly (C & Z) endm ; test contents of 16-bit registers, similar to 8-bit variant tstf ; tstf16 X: Z = 1: X == 0 TSTF16 macro X local _CMP_DONE tstf X+1 ; check high byte bnz _CMP_DONE ; if not zero, we're already done tstf X ; check low byte _CMP_DONE ; zero flag is set correctly (Z) endm