;********************************************************
; Module Math16
; Auth Chuck McManis (http://www.mcmanis.com/chuck) 2001
; Updated by Alain Bizot 2007
;********************************************************
; 
; This include file provides some macros for dealing with
; 16 bit quantities. It assumes a little endian format
; where the least significant byte is lower in address than
; the most significant byte.
;********************************************************
;_REG_A, _REG_B pseudo "registers" for 16 BIT operations
;
; 16 bit move from SRC to DST
;
MOV16   MACRO   SRC, DST
        MOVF    SRC,W
        MOVWF   DST
        MOVF    SRC+1,W
        MOVWF   DST+1
        ENDM
;
; 16 bit unsigned compare, returns Z and C set appropriately
; Compares the registers "CMP_A" and "CMP_B"
; Flag states and what they mean:
;
;       Z true - X & Y are equal	C=1	Z=1
;       C true - X > Y			C=1	Z=0
;       C false - X < Y			C=0	Z=0
;        
CMP16   MACRO   X, Y
        MOV16   X, _REG_A
        SUB16   _REG_A,Y
        MOVF    _REG_A,W
        IORWF   _REG_A+1,W
        ENDM
;
; Initialize a 16 bit value
;
INIT16  MACRO   VAR, CONST
        MOVLW   low (CONST)
        MOVWF   (VAR)
        MOVLW   high (CONST)
        MOVWF   (VAR)+1
        ENDM        
;
; Initialize a 16 bit value to zero
;
CLR16   MACRO   VAR
        CLRF    VAR
        CLRF    VAR+1
        ENDM      
;
; Macro to do a logical shift right on a 16 bit value
; (0 is shifted into the MSB)
;
LSR16   MACRO   VAR16
        BCF     STATUS, C       ; Clear carry
        RRF     (VAR16)+1,F     ; Rotate high byte right
        RRF     (VAR16),F       ; Rotate low byte right
       ENDM
; logical shift left
LSL16   MACRO   VAR16
        BCF     STATUS, C       ; Clear carry
        RLF     (VAR16),F       ; Rotate low byte left
        RLF     (VAR16)+1,F     ; Rotate upper byte left
        ENDM                       
;
; 16 bit unsigned subtraction with carry out.
; Word format is little endian (LSB at lower address)
; Operation is DST = DST - SRC
;
; (This from the "tips and tricks" seminar handout)
;
; DST is replaced, SRC is preserved, Carry is set correctly
;
;
SUB16   MACRO   DST, SRC
        MOVF    (SRC),W         ; Get low byte of subtrahend
        SUBWF   (DST),F         ; Subtract DST(low) - SRC(low)
        MOVF    (SRC)+1,W       ; Now get high byte of subtrahend
        BTFSS   STATUS,C        ; If there was a borrow, rather than
        INCF    (SRC)+1,W       ; decrement high byte of dst we inc src
        SUBWF   (DST)+1,F       ; Subtract the high byte and we're done
        ENDM
        
SUBI16  MACRO   DST, SB
        MOVLW   LOW (SB)
        SUBWF   (DST), F
        MOVLW   HIGH (SB)
        BTFSS   STATUS, C
        MOVLW   (HIGH (SB))+1
        SUBWF   (DST)+1,F
        ENDM
;
; 16 bit unsigned addition with carry out.
; Operation: DST = DST + SRC                       
;
; DST is replaced, SRC is preserved, Carry is set correctly
;
ADD16   MACRO   DST,SRC 
        MOVF    (SRC),W         ; Get low byte
        ADDWF   (DST),F         ; Add to destination
        MOVF    (SRC)+1,W       ; Get high byte
        BTFSC   STATUS,C        ; Check for carry
        INCF    (SRC)+1,W       ; Add one for carry
        ADDWF   (DST)+1,F       ; Add high byte into DST
        ENDM
;
; 16 bit Add Immediate
; Operation: DST = DST + Constant
;
; DST is updated, carry is set correctly.
;
ADDI16  MACRO   DST,AD
        MOVLW   LOW (AD)
        ADDWF   DST,F
        MOVLW   HIGH (AD)
        BTFSC   STATUS,C
        MOVLW   (HIGH (AD)) + 1
        ADDWF   (DST)+1,F
        ENDM
;
; Negate 16 bit value
; Find two's complement value of a 16 bit number
;
NEG16   MACRO   DST
        COMF    (DST)
        COMF    (DST)+1
        INC16   DST
        ENDM
;
; Increment 16 bit value, sets Z on exit.
;
; Operation: DST++
;
INC16   MACRO   DST        
        INCFSZ  (DST),W         ; Add one to low byte
        DECF    (DST)+1,F       ; No carry (negates next step)
        INCF    (DST)+1,F       ; Add one to high byte
        MOVWF   (DST)           ; Store updated low byte back.
        IORWF   (DST)+1,W       ; Set Z flag
        ENDM
;
; Decrement 16 bit value, sets Z on exit
;        
; Operation: DST--
;
DEC16   MACRO   DST
        DECF    (DST),F         ; Decrement low byte
        INCFSZ  (DST),W         ; Check for underflow
        INCF    (DST)+1,F       ; Update
        DECF    (DST)+1,F       ; Fixup
        MOVF    (DST),W
        IORWF   (DST)+1,W       ; Set Z bit
        ENDM

; end of My_Math
