; All these utility subroutines are using stack memory 
; starting from FSR-1 downwards.
; Gaspar Sinai <gaspar@yudit.org>
; 2010-03-14
;------------------------------------------------------------------------------

#include "common.inc"

    global FromBCD
    global CalculateParityAdd
    global CalculateParity
    global GetDaysInMonthBCD

    udata

VarParity   res 1 ; Parity uses this

    code
;------------------------------------------------------------------------------
; Convert number in W from BCD.
; args 
;    W     BCD
; return   number
;------------------------------------------------------------------------------
FromBCD:
    decf    FSR,F
    movwf   INDF 
    swapf   INDF,W
    andlw   0FH
    subwf   INDF,F
    subwf   INDF,F
    subwf   INDF,F
    subwf   INDF,F
    subwf   INDF,F
    subwf   INDF,W
    incf    FSR,F
    return 


;------------------------------------------------------------------------------
; Calculate parity clean
; args 
;    W    number
; args    parity(numebr)
;------------------------------------------------------------------------------
CalculateParity:

    clrf    VarParity;  the parity 

;------------------------------------------------------------------------------
;Calculate parity by adding this parity to previous parity.
; args 
;   W:     number
; return    parity(numebr)
;------------------------------------------------------------------------------
CalculateParityAdd:

    decf    FSR,F
    movwf   INDF 

CalculateParityLoop:

    bcf     STATUS,C 
    rrf     INDF,F
    btfsc   STATUS,C
    incf    VarParity,F 

    movf    INDF,W
    btfss   STATUS,Z 
    goto    CalculateParityLoop

    incf    FSR,F
    movf    VarParity,W

    return

;------------------------------------------------------------------------------
; Get days in a month. 
; args 
;    W     MONTH (BCD)
;    FSR   YEARL (BCD)
;    FSR+1 YEARH (BCD)
;------------------------------------------------------------------------------
GetDaysInMonthBCD: 

    call    FromBCD

    decf    FSR,F       ; save W
    movwf   INDF

    addlw   -.13        ; sanity check
    btfss   STATUS,C    ; skip not borrow

    goto    GetDaysInMonthBorrow

    incf    FSR,F       ; restore stack 
    retlw   0x31        ; ERROR

GetDaysInMonthBorrow:

    movlw   high(MonthTable)
    movwf   PCLATH

    movf    INDF,W      ; load W
    incf    FSR,F       ; restore stack

    addlw   low (MonthTable)
    btfsc   STATUS,C
    incf    PCLATH,F
    movwf   PCL

MonthTable:
    retlw   0x31 ; 0 ?
    retlw   0x31 ; JAN
    goto    GetDaysInMonthFeb
    retlw   0x31 ; MAR
    retlw   0x30 ; APR
    retlw   0x31 ; MAY
    retlw   0x30 ; JUN
    retlw   0x31 ; JUL
    retlw   0x31 ; AUG
    retlw   0x30 ; SEP
    retlw   0x31 ; OCT
    retlw   0x30 ; NOV
    retlw   0x31 ; DEC

;
; args    
;    FSR   YEARL (BCD)
;    FSR+1 YEARH (BCD)
; return number of days in february (BCD)
;
GetDaysInMonthFeb:

    movf    INDF,W  ; load year BCD low
    btfsc   STATUS,Z 
    goto    GetDaysInMonthFeb100
    call    FromBCD
    andlw   3
    btfss   STATUS,Z 
    retlw   0x28    ; every year except 4 
    retlw   0x29    ; every 4 years

GetDaysInMonthFeb100:

    ; every 100 years

    incf    FSR,F 
    movf    INDF,W  ; load year BCD high
    decf    FSR,F
    call    FromBCD
    andlw   3
    btfss   STATUS,Z 
    retlw   0x28    ; every 100 years except 400
    retlw   0x29    ; every 400 years 


end
