;TIDE823.ASM 31MAR00 - JOHN BECKER - EPE CANUTE TIDE PREDICTOR

;PIC16F877, 3.2768MHz, WDT OFF, POR ON, WRITTEN IN TASM

;Config register bits (PIC Toolkit Mk2 defaults):
; CP1 CP0 DBG NIL WRT CPD LVP BOR CP1 CP0 POR WDT OS1 OS0
;  1   1   1   1   1   1   0   0   1   1   0   0   0   1
;N.B. Logic 1/0 do NOT necessarily mean that the function is On/Off
;respectively - refer to PIC '87 data sheet.

#DEFINE PAGE0   BCF $03,5
#DEFINE PAGE1   BSF $03,5
                          
INDF:    .EQU $00  ;page 0, 1, 2, 3
TMR0:    .EQU $01  ;page 0, 2
OPTION:  .EQU $01  ;page 1, 3
PCL:     .EQU $02  ;page 0, 1, 2, 3
STATUS:  .EQU $03  ;page 0, 1, 2, 3
FSR:     .EQU $04  ;page 0, 1, 2, 3

PORTA:   .EQU $05  ;page 0
TRISA:   .EQU $05  ;page 1
PORTB:   .EQU $06  ;page 0, 2
TRISB:   .EQU $06  ;page 1, 3
PORTC:   .EQU $07  ;page 0
TRISC:   .EQU $07  ;page 1
PORTD:   .EQU $08  ;page 0
TRISD:   .EQU $08  ;page 1
PORTE:   .EQU $09  ;page 0
TRISE:   .EQU $09  ;page 1

SWPORT:  .EQU 5    ;port on which switches are connected 7=PORTC, 5=PORTA

PCLATH:  .EQU $0A  ;page 0, 1, 2, 3
INTCON:  .EQU $0B  ;page 0, 1, 2, 3

PIR1:    .EQU $0C  ;page 0
PIE1:    .EQU $0C  ;page 1
EEDATA:  .EQU $0C  ;page 2
EECON1:  .EQU $0C  ;page 3
         
PIR2:    .EQU $0D  ;page 0
PIE2:    .EQU $0D  ;page 1
EEADR:   .EQU $0D  ;page 2
EECON2:  .EQU $0D  ;page 3

TMR1L:   .EQU $0E  ;page 0
PCON:    .EQU $0E  ;page 1
EEDATH:  .EQU $0E  ;page 2

TMR1H:   .EQU $0F  ;page 0
EEADRH:  .EQU $0F  ;page 2

T1CON :  .EQU $10  ;page 0

TMR2:    .EQU $11  ;page 0
SSPCON2: .EQU $11  ;page 1

T2CON:   .EQU $12  ;page 0
PR2:     .EQU $12  ;page 1

SSPBUF:  .EQU $13  ;page 0
SSPADD:  .EQU $13  ;page 1

SSPCON:  .EQU $14  ;page 0
SSPSTAT: .EQU $14  ;page 1

RCSTA:   .EQU $18  ;page 0
TXSTA:   .EQU $18  ;page 1

TXREG:   .EQU $19  ;page 0
SPBRG:   .EQU $19  ;page 1

RCREG:   .EQU $1A  ;page 0
CCPR2L:  .EQU $1B  ;page 0
CCPR2H:  .EQU $1C  ;page 0
CCP2CON: .EQU $1D  ;page 0

ADRESH:  .EQU $1E  ;page 0
ADRESL:  .EQU $1E  ;page 1

ADCON0:  .EQU $1F  ;page 0
ADCON1:  .EQU $1F  ;page 1

LOOPA:  .EQU $20        ;loop counter
LOOPB:  .EQU $21        ;loop counter

CLKCNT: .EQU $22        ;pre-counter for CLOCK
CLKSEC: .EQU $23        ;CLOCK main counter - secs

;***** $24 TO $37 SET WITH VARIABLES FROM EEPROM DATA ON START-UP ***

CLKMIN: .EQU $24        ;CLOCK - mins
CLKHRS: .EQU $25        ;CLOCK - hours
CLKDAY: .EQU $26        ;day of month
MONTH:  .EQU $27        ;month of year
YEAR:   .EQU $28        ;year
WKDAY:  .EQU $29        ;day of week
CLKAD0: .EQU $2A        ;clock rate adjustment LSB
CLKAD1: .EQU $2B        ;clock rate adjustment NSB
CLKAD2: .EQU $2C        ;clock rate adjustment MSB
TIDEAD: .EQU $2D        ;tide adjustment byte

MOONA0: .EQU $2E        ;moon angle A decimal LSB
MOONA1: .EQU $2F        ;moon angle A decimal MSB
MOONA2: .EQU $30        ;moon angle A LSB
MOONA3: .EQU $31        ;moon angle A MSB

MOONB0: .EQU $32        ;moon angle B decimal LSB
MOONB1: .EQU $33        ;moon angle B decimal MSB
MOONB2: .EQU $34        ;moon angle B LSB
MOONB3: .EQU $35        ;moon angle B MSB

DAYA0:  .EQU $36        ;day angle decimal LSB
DAYA1:  .EQU $37        ;day angle decimal MSB
DAYA2:  .EQU $38        ;day angle main byte

;********* END OF EEPROM SET VARIABLES ****

DIFF0:  .EQU $39        ;tide diff in mins LSB {is the diff between latest
DIFF1:  .EQU $3A        ;tide diff in mins MSB {high tide and the next

TIDEUP: .EQU $3B        ;tide graph direction flag

NXTHI0: .EQU $3C        ;high tide count store LSB
NXTHI1: .EQU $3D        ;high tide count store MSB
NXTLO0: .EQU $3E        ;low tide count store LSB
NXTLO1: .EQU $3F        ;low tide count store MSB
TIDE0:  .EQU $40        ;tide graph counter LSB
TIDE1:  .EQU $41        ;tide graph counter MSB

STORE0: .EQU $42        ;general store 0
STORE1: .EQU $43        ;general store 1
STORE2: .EQU $44        ;general store 2

ADLIN0: .EQU $45        ;sum of MOONA + MOONB LSB {ADLIN is val from which
ADLIN1: .EQU $46        ;sum of MOONA + MOONB NSB {next high tide is
ADLIN2: .EQU $47        ;sum of MOONA + MOONB MSB {calculated

SWITCH: .EQU $48        ;switch store
ANSA0:  .EQU $49        ;multiplying store LSB
ANSA1:  .EQU $4A        ;multiplying store NSB
ANSA2:  .EQU $4B        ;multiplying store NSB
ANSA3:  .EQU $4C        ;multiplying store MSB
MULTX0: .EQU $4D        ;multiplier for multi routine LSB
MULTX1: .EQU $4E        ;multiplier for multi routine MSB

RSLINE: .EQU $4F        ;LCD control line

spareA: .EQU $50        ;
spareB: .EQU $51        ;
spareC: .EQU $52        ;
spareD: .EQU $53        ;
spareE: .EQU $54        ;
spareF: .EQU $55        ;
spareG: .EQU $56        ;
spareH: .EQU $57        ;
spareI: .EQU $58        ;
sparej: .EQU $59        ;
BYTE4:  .EQU $5A        ;used as overflow for DADD routine
LIMIT:  .EQU $5B        ;limit of value for changing routines
EVENT:  .EQU $5C        ;switch mode counter
CALC0:  .EQU $5D        ;flag for calculation occuring (=1)
SECAD0: .EQU $5E        ;counter for clock secs fractions LSB
SECAD1: .EQU $5F        ;counter for clock secs fractions NSB
SECAD2: .EQU $60        ;counter for clock secs fractions MSB
BCDVAL: .EQU $61        ;BCD of binary value, and other uses
STORE5: .EQU $62        ;general store 5
STORE6: .EQU $63        ;general store 6
CELL0:  .EQU $65        ;location of highlight cell during change
CALCDY: .EQU $66        ;days store for use in calculation
CALCMN: .EQU $67        ;month store for use in calculation
CALCYR: .EQU $68        ;year store for use in calculation
NOWLO0  .EQU $69        ;current low tide time LSB
NOWLO1  .EQU $6A        ;current low tide time MSB
NOWHI0  .EQU $6B        ;current high tide time LSB
NOWHI1  .EQU $6C        ;current high tide time MSB
FLASH:  .EQU $6D        ;flash '*' flag for changes routines
TIME:   .EQU $6E        ;flag for showing calendar during graph
VFAST:  .EQU $6F        ;flag for putting routine into high speed
                        ;(author's use only)

W:      .EQU 0
F:      .EQU 1

C:      .EQU 0
DC:     .EQU 1
Z:      .EQU 2

RD:     .EQU 0  ;EECON1 reg eeprom read enable flag
WR:     .EQU 1  ;EECON1 reg eeprom write initiate flag
WREN:   .EQU 2  ;EECON1 reg eeprom write enable flag

RP0:    .EQU 5           ;STATUS reg
RP1:    .EQU 6           ;STATUS reg
EEPGD:  .EQU 7           ;EECON1 reg 
GIE:    .EQU 7           ;INTCON reg
EEIF:   .EQU 4           ;PIR2 reg 


        .ORG $0004      ;Interrupt vector address
        GOTO START      ;Jump to interrupt routine on interrupt
        .ORG $0005      ;Start of program memory
        GOTO START

SINE:   addwf PCL,F     ; convert angle to sine
        retlw 0         ; 0
        retlw 2         ; 1
        retlw 3         ; 2
        retlw 5         ; 3
        retlw 7         ; 4
        retlw 9         ; 5
        retlw 10        ; 6
        retlw 12        ; 7
        retlw 14        ; 8
        retlw 16        ; 9
        retlw 17        ; 10
        retlw 19        ; 11
        retlw 21        ; 12
        retlw 22        ; 13
        retlw 24        ; 14
        retlw 26        ; 15
        retlw 28        ; 16
        retlw 29        ; 17
        retlw 31        ; 18
        retlw 33        ; 19

        retlw 34        ; 20
        retlw 36        ; 21
        retlw 37        ; 22
        retlw 39        ; 23
        retlw 41        ; 24
        retlw 42        ; 25
        retlw 44        ; 26
        retlw 45        ; 27
        retlw 47        ; 28
        retlw 48        ; 29

        retlw 50        ; 30
        retlw 52        ; 31
        retlw 53        ; 32
        retlw 54        ; 33
        retlw 56        ; 34
        retlw 57        ; 35
        retlw 59        ; 36
        retlw 60        ; 37
        retlw 62        ; 38
        retlw 63        ; 39

        retlw 64        ; 40
        retlw 66        ; 41
        retlw 67        ; 42
        retlw 68        ; 43
        retlw 69        ; 44
        retlw 71        ; 45
        retlw 72        ; 46
        retlw 73        ; 47
        retlw 74        ; 48
        retlw 75        ; 49

        retlw 77        ; 50
        retlw 78        ; 51
        retlw 79        ; 52
        retlw 80        ; 53
        retlw 81        ; 54
        retlw 82        ; 55
        retlw 83        ; 56
        retlw 84        ; 57
        retlw 85        ; 58
        retlw 86        ; 59

        retlw 87        ; 60
        retlw 87        ; 61
        retlw 88        ; 62
        retlw 89        ; 63
        retlw 90        ; 64
        retlw 91        ; 65
        retlw 91        ; 66
        retlw 92        ; 67
        retlw 93        ; 68
        retlw 93        ; 69

        retlw 94        ; 70
        retlw 95        ; 71
        retlw 95        ; 72
        retlw 96        ; 73
        retlw 96        ; 74
        retlw 97        ; 75
        retlw 97        ; 76
        retlw 97        ; 77
        retlw 98        ; 78
        retlw 98        ; 79

        retlw 98        ; 80
        retlw 99        ; 81
        retlw 99        ; 82
        retlw 99        ; 83
        retlw 99        ; 84
        retlw 100       ; 85
        retlw 100       ; 86
        retlw 100       ; 87
        retlw 100       ; 88
        retlw 100       ; 89
        retlw 100       ; 90
        retlw 100       ; 91
 
CHKVAL: ADDWF PCL,F     ;checks vals for exceeding max allowed
        retlw %01011001 ;59 secs max
        retlw %01011001 ;59 mins max
        retlw %00100011 ;23 hours max
        goto CHKVL2     ;days in month
        retlw %00001100 ;12 months in year max (binary, not BCD)
        retlw %10011001 ;99 years in century max
        retlw %11111111 ;max limit for century count (FF)
CHKVL2: movf MONTH,W    ;get days in month
        btfsc CALC0,0   ;is calculation in progress?
        movf CALCMN,W   ;yes

MONTH4: ADDWF PCL,F     ;month length in days in BCD
        retlw %00110001 ;0. XXX 31
        retlw %00110001 ;1. JAN 31
        goto FEB        ;2. FEB 28/29
        retlw %00110001 ;3. MAR 31
        retlw %00110000 ;4. APR 30
        retlw %00110001 ;5. MAY 31
        retlw %00110000 ;6. JUN 30
        retlw %00110001 ;7. JUL 31
        retlw %00110001 ;8. AUG 31
        retlw %00110000 ;9. SEP 30
        retlw %00110001 ;10. OCT 31
        retlw %00110000 ;11. NOV 30
        retlw %00110001 ;12. DEC 31

FEB:    movf YEAR,W
        btfsc CALC0,0   ;is calculation in progress?
        movf CALCYR,W   ;yes
        call BCDBIN
        andlw %00000011
        btfss STATUS,Z  ;is year a multiple of 4?
        retlw %00101000 ;no, FEB = 28
        retlw %00101001 ;yes, FEB = 29


TABLCD: addwf PCL,F     ;LCD initialisation table
        retlw %00110011 ;initialise lcd - first byte
        retlw %00110011 ;2nd byte (repeat of first)
        retlw %00110010 ;set for 4-bit operation
        retlw %00101100 ;set for 2 lines
        retlw %00000110 ;set entry mode to increment each address
        retlw %00001100 ;set display on, cursor off, blink off
        retlw %00000001 ;clear display
        retlw %00000010 ;return home, cursor & RAM to zero
                        ;end initialisation table

CHANGE: ADDWF PCL,F     ;order for changing values
        return          ;0
        goto ALTYRS     ;1 correct years
        goto ALTMNT     ;2 correct month
        goto ALTDAY     ;3 correct days
        goto ALTWKD     ;4 correct weekday
        goto ALTMIN     ;5 correct minutes
        goto ALTHRS     ;6 correct hours
        goto ALTTID     ;7 correct tide factor
        goto ALTTIM     ;8 correct clock timing accuracy factor

CELL:   movf EVENT,W
        ADDWF PCL,F     ;asterisk position for changing values
        retlw 1         ;0
        retlw 15        ;1
        retlw 12        ;2
        retlw 10        ;3
        retlw 7         ;4
        retlw 4         ;5
        retlw 1         ;6
        retlw 11        ;7
        retlw 10        ;8

HIGH:   ADDWF PCL,F     ;NEXT HIGH tide message for changing values
        retlw 'N'       ;0
        retlw 'E'       ;1
        retlw 'X'       ;2
        retlw 'T'       ;3
        retlw ' '       ;4
        retlw 'H'       ;5
        retlw '-'       ;6
        retlw 'T'       ;7
        retlw 'I'       ;8
        retlw 'D'       ;9
        retlw 'E'       ;10
        retlw ' '       ;10

FAST:   ADDWF PCL,F     ;FAST/SLOW message for clock accuracy adjust
        retlw 'F'       ;0
        retlw 'A'       ;1
        retlw 'S'       ;2
        retlw 'T'       ;3
        retlw '/'       ;4
        retlw 'S'       ;5
        retlw 'L'       ;6
        retlw 'O'       ;7
        retlw 'W'       ;8

CALC:   ADDWF PCL,F     ;CALCULATE message for end of all changes
        retlw 'R'       ;0
        retlw 'E'       ;1
        retlw '-'       ;2
        retlw 'C'       ;3
        retlw 'A'       ;4
        retlw 'L'       ;5
        retlw 'C'       ;6
        retlw 'U'       ;7
        retlw 'L'       ;8
        retlw 'A'       ;9
        retlw 'T'       ;10
        retlw 'E'       ;11

SETTIM: ADDWF PCL,F     ;SET TIME message for changes
        retlw 'S'       ;0
        retlw 'E'       ;1
        retlw 'T'       ;2
        retlw ' '       ;3
        retlw 'Y'       ;4
        retlw 'O'       ;5
        retlw 'U'       ;6
        retlw 'R'       ;7
        retlw ' '       ;3
        retlw 'D'       ;4
        retlw 'A'       ;5
        retlw 'T'       ;6
        retlw 'E'       ;7

ALLDUN: ADDWF PCL,F     ;ALL DONE message for changes
        retlw 'A'       ;0
        retlw 'L'       ;1
        retlw 'L'       ;2
        retlw ' '       ;3
        retlw 'D'       ;4
        retlw 'O'       ;5
        retlw 'N'       ;6
        retlw 'E'       ;7

;.............

START:  clrf PORTA
        clrf PORTB
        clrf PORTC

        clrf VFAST      ;flag for high speed calc - author's use only
;        movlw 1
;        movwf VFAST

        bcf STATUS,RP1  ; clear PAGE2/3 bit
        bsf STATUS,RP0  ; set PAGE1 bit
        movlw %00111111 ;all PORTA as input
        movwf TRISA
        clrf TRISB
        movlw %10000111
        movwf TRISC     ;PORTC 3,4,5,6 as output, 0,1,2,7 as input
        movlw %00000111 ; all-digital I/O code
        movwf ADCON1
;        movlw %00000000 ;set timer ratio 1:1   - pull ups on
        movlw %00000101 ;set timer ratio 1:64 (1/50th sec) - pull ups on
        movwf OPTION
        bcf STATUS,RP0  ; reset to PAGE0

        btfss VFAST,0   ;is VFAST flag set?
        goto SETUP      ;no
        bsf STATUS,RP0  ;yes, set PAGE1 bit
        movlw %00000001 ;set timer ratio 1:1   - pull ups on
        movwf OPTION
        bcf STATUS,RP0  ; reset to PAGE0

SETUP:  call PAUSIT     ;delay

LCDSET: clrf LOOPB      ;clr LCD set-up loop
        clrf RSLINE     ;clear RS line for instruction send
LCDST2: movf LOOPB,W    ;get table address
        call TABLCD     ;get set-up instruction
        call LCDLIN     ;perform it
        incf LOOPB,F    ;inc loop
        btfss LOOPB,3   ;has last LCD set-up instruction now been done?
        goto LCDST2     ;no
        call PAUSIT     ;delay

        call CHARCT     ;setup LCD for bargraph characters

        btfsc SWPORT,0  ;is RESET called?
        call RESET      ;yes

        movlw 21
        movwf LOOPA
        clrf LOOPB
        movlw CLKMIN
        movwf FSR
PRIME:  movf LOOPB,W    ;get primary data from EEPROM
        call PRMGET
        movwf INDF
        incf FSR,F
        incf LOOPB,F
        decfsz LOOPA,F
        goto PRIME

        call CLKSH3
        clrf CALC0
        movlw 1
        movwf EVENT

        call CLRLN1
        call CLRLN2

        movlw 0
        call LCDPX2
        clrf LOOPB
SETIT:  movf LOOPB,W
        call SETTIM     ;show SET YOUR DATE message
        call LCDOUT
        incf LOOPB,F
        movf LOOPB,W
        xorlw 13
        btfss STATUS,Z
        goto SETIT

        call CELL
        movwf CELL0
        call LCDPX2
        movlw '*'
        call LCDOUT

        clrf SECAD0
        clrf SECAD1
        clrf SECAD2
        clrf CLKSEC
        clrf TIME
        clrf FLASH

        clrf CLKSEC
        movlw 25
        movwf CLKCNT

        btfsc VFAST,0
        clrf EVENT

        call SETBAUD
;...............

INTRPT: btfss INTCON,2  ;has a timer time-out been detected?
        goto INTRPT     ;no
        bcf INTCON,2    ;yes
        call CLKSYS
        goto INTRPT

;.....................

GRAPH:  btfsc VFAST,0    ;is VFAST flag set?
        goto GF0         ;yes
        movf EVENT,W     ;is EVENT > 0
        btfss STATUS,Z
        return           ;yes

        movf CLKSEC,W     ;are secs = 0?
        btfss STATUS,Z
        return            ;no

CHKHI:  movf CLKHRS,W     ;are HRS = high tide hours?
        xorwf NXTHI1,W
        btfss STATUS,Z
        goto CHKLO
        movf CLKMIN,W     ;are MINS = high tide mins?
        xorwf NXTHI0,W
        btfss STATUS,Z
        goto CHKLO
        clrf TIDEUP
        goto GF0

CHKLO:  movf CLKHRS,W     ;are HRS = high tide hours?
        xorwf NXTLO1,W
        btfss STATUS,Z
        goto GF3          ;no
        movf CLKMIN,W     ;yes, are MINS = high tide mins?
        xorwf NXTLO0,W
        btfss STATUS,Z
        goto GF3          ;no
        bsf TIDEUP,0      ;yes
        movlw 15
        call LCDPX1
        movlw '>'
        call LCDOUT
        movlw 12           ;show time of next high tide
        call LCDPX2
        movf NXTHI1,W
        movwf NOWHI1
        call LCDHEX
        movf NXTHI0,W
        movwf NOWHI0
        call LCDHEX
        goto GF3

GF0:    call DAYA         ;add to dayangle
        call MOONA        ;add to moonangleA
        call MOONB        ;add to moonangleB
        call DAYB         ;convert dayangle to hours/mins
        call DAYC         ;get next high/low tide times
        clrf TIDEUP       ;set tide direction flag for down
        btfss VFAST,0
        call FIXFAX

        movlw 0
        call LCDPX2       ;show time of next low tide
        movf NXTLO1,W
        movwf NOWLO1
        call LCDHEX
        movf NXTLO0,W
        movwf NOWLO0
        call LCDHEX
        movlw 15
        call LCDPX1
        movlw '<'
        call LCDOUT

GF3:    btfsc VFAST,0     ;is VFAST flag set?
        return            ;yes

GRFSHW: btfss TIDEUP,0    ;is tide direction up?
        goto GF3A         ;no, dec graph
        incfsz TIDE0,F    ;yes, inc graph
        goto GF3AB
        incf TIDE1,F

GF3AB:  btfss TIDE1,0     ;is TIDE1 = 1? (i.e. is TIDE > $1BC - LCD max)
        goto GF3B         ;no
        movlw $BC         ;yes, is TIDE0 > $BC?
        subwf TIDE0,W
        btfss STATUS,C
        goto GF3B         ;no
        movlw $BC         ;yes, keep it at $BC
        movwf TIDE0
        goto GF3B

GF3A:   movlw 1
        subwf TIDE0,F
        btfsc STATUS,C
        goto GF3B
        movf TIDE1,F       ;if TIDE1 is 0 then keep TIDE0/1 at 0
        btfss STATUS,Z
        goto GF3C
        clrf TIDE0
        goto GF3B
GF3C:   decf TIDE1,F

GF3B:   movf TIDE1,W
        movwf STORE1
        movf TIDE0,W
        movwf STORE0
        clrf ANSA1

GF4:    incf ANSA1,F    ;get tide segments value (divide by 30)
        movlw 30
        subwf STORE0,F
        btfsc STATUS,C
        goto GF4
        movlw 1
        subwf STORE1,F
        btfsc STATUS,C
        goto GF4

        decf ANSA1,F
        movlw 30
        addwf STORE0,F   ;remainder

        clrf ANSA0
        movf STORE0,F
        btfsc STATUS,Z
        goto GF10

GF7:    incf ANSA0,F    ;get tide pixel value (divide by 6)
        movlw 6
        subwf STORE0,F
        btfsc STATUS,C
        goto GF7
        decf ANSA0,F

        movf ANSA0,W    ;is sub-div answer > 4?
        addlw 251
        btfss STATUS,C
        goto GF10       ;no
        movlw 255       ;yes so set char to full black
        movwf ANSA0

GF10:   movlw 0
        call LCDPX1
        movf ANSA1,W    ;is graph answer = 0?
        btfsc STATUS,Z
        goto GF13       ;yes
        movf ANSA1,W    ;is graph answer > 15?
        andlw %11110000
        btfsc STATUS,Z
        goto GF11       ;no
        movlw 15
        movwf ANSA1     ;yes, limit it to 15

GF11:   movf ANSA1,W
        movwf LOOPB

GF12:   movlw 255
        call LCDOUT
        decfsz LOOPB,F
        goto GF12

GF13:   movf ANSA0,W     ;show sub-section of bargraph
        call LCDOUT
        movlw ' '
        call LCDOUT
        movlw 15
        call LCDPX1
        movlw '>'
        btfss TIDEUP,0
        movlw '<'
        call LCDOUT

        btfsc TIME,0
        goto CLKSH3

        return

;.....................

DAYA:   movlw DAYA0
        movwf FSR
        movlw $86       ;DAY A step LSB (decimal place)
        call DADD0

DA1:    movlw DAYA1
        movwf FSR
        movlw $7C       ;DAY A step NSB (decimal place)
        call DADD1

DA2:    movlw DAYA2
        movwf FSR
        movlw $84       ;DAY A step MSB
        call DADD2
        return

;............

DAYB:   movf DAYA2,W    ;divide day angle by 256 * 256
        addwf TIDEAD,W  ;add tide adjustment factor *31MAR00
        movwf STORE0
        clrf STORE1
DB1:    clrf STORE2
        movlw $A0       ;multiply by 1440 ($5A0)
        movwf MULTX0
        movlw 5
        movwf MULTX1
        call MLTPLY

        movf ANSA2,W
        movwf ADLIN1
        movf ANSA1,W
        movwf ADLIN0

        movlw $E9       ;reset standard tide diff of 745 mins ($2E9)
        movwf DIFF0     ;DIFF is time diff between previous high tide & next
        movlw 2         ;it is added to during ADLIN calcs
        movwf DIFF1
        return

DAYC:   call MA3
        call MB3

        movf ADLIN1,W     ;get next high tide hours value 
        movwf STORE1
        movf ADLIN0,W
        movwf STORE0
        call GETHRS       ;divide by 60 to get hours + mins

        movf STORE2,W
        call BINBCD
        movf BCDVAL,W
        movwf NXTHI1

        movf STORE0,W
        call BINBCD
        movf BCDVAL,W
        movwf NXTHI0

        btfss VFAST,0       ;is VFAST set? (routine for author only)
        goto DAYC1          ;no

        movlw 0             ;zero to PC (needed for reasons unknown)
        call SENDPC
        movf NXTHI1,W       ;send high tide time to PC
        call SENDPC
        movf NXTHI0,W
        call SENDPC

DAYC1:  movf EVENT,W
        btfsc STATUS,Z
        goto DA15

        movlw 12
        call LCDPX2
        movf NXTHI1,W
        call LCDHEX
        movf NXTHI0,W
        call LCDHEX

DA15:   movf ADLIN1,W    ;get next low tide by subtracting half of DIFF
        movwf STORE1     ;from 30 mins + ADLIN (which holds next high)
        movf ADLIN0,W
        movwf STORE0

        movlw 30         ;add 30 to value of ADLIN
        addwf STORE0,F
        btfsc STATUS,C
        incf STORE1,F

        movf DIFF1,W     ;get DIFF val & divide by 2
        movwf ANSA1
        movf DIFF0,W
        movwf ANSA0
        bcf STATUS,C
        rrf ANSA1,F
        rrf ANSA0,F

        movf ANSA0,W      ;sub ANSA0 from STORE0
        subwf STORE0,F
        btfsc STATUS,C    ;is there a borrow?
        goto DA16         ;no
        movlw 1           ;yes, so subtract 1 from STORE1
        subwf STORE1,F
        btfsc STATUS,C    ;is there a borrow?
        goto DA16         ;no

        movlw $A0         ;yes, so add 1440
        addwf STORE0,F
        movf STATUS,W
        andlw 1
        addlw 5
        addwf STORE1,F

DA16:   movf ANSA1,W      ;subtract ANSA1 from STORE1
        subwf STORE1,F
        btfsc STATUS,C    ;is there a borrow?
        goto DA17         ;no

        movlw $A0         ;yes, so add 1440
        addwf STORE0,F
        movf STATUS,W
        andlw 1
        addlw 5
        addwf STORE1,F
DA17:
        call GETHRS      ;divide by 60 to get hours + mins

        movf STORE2,W
        call BINBCD
        movf BCDVAL,W
        movwf NXTLO1

        movf STORE0,W
        call BINBCD
        movf BCDVAL,W
        movwf NXTLO0
        return

;....................

MOONA:  movlw MOONA0
        movwf FSR
        movlw $38       ;moon A step LSB (decimal place)
        call ADD0

MA1:    movlw MOONA1
        movwf FSR
        movlw $9E       ;moon A step NSB (decimal place)
        call ADD1

MA2:    movlw MOONA2
        movwf FSR
        movlw $0C       ;moon A step MSB
        call ADD2
        return

MA3:    movlw MOONA2    ;set address of MOONA2
        movwf FSR       ;set BYTE2
        call GETSIN
        movf STORE1,W
        call SINE
        movwf STORE0

MA4:    clrf STORE1
        clrf STORE2
        movlw 158       ;multiply sine answer by 158
        movwf MULTX0
        clrf MULTX1
        call MLTPLY
        movlw MOONA3
        movwf FSR
        goto MT5

;.........

MOONB:  movlw MOONB0
        movwf FSR
        movlw $EC       ;moon B step LSB (decimal place)
        call ADD0

MB1:    movlw MOONB1
        movwf FSR
        movlw $CC       ;moon B step NSB (decimal place)
        call ADD1

MB2:    movlw MOONB2
        movwf FSR
        movlw $06       ;moon B step MSB
        call ADD2
        return

MB3:    movlw MOONB2    ;set address of MOONB2
        movwf FSR       ;set BYTE2
        call GETSIN
        movf STORE1,W
        call SINE
        movwf STORE0

MB4:    clrf STORE1
        clrf STORE2
        movlw 97        ;multiply sine answer by 97
        movwf MULTX0
        clrf MULTX1
        call MLTPLY
        movlw MOONB3
        movwf FSR

MT5:    btfsc INDF,0
        goto MT8          ;bit 0=1 (angle >= 180) so add ANSA1 to ADLIN
        movf ANSA1,W      ;bit 0=0 (angle <180), so sub ANSA1 from ADLIN
        subwf ADLIN0,F
        btfsc STATUS,C    ;is there a borrow?
        goto MT9          ;no
        movlw 1           ;yes, so subtract 1 from ADLIN1
        subwf ADLIN1,F
        btfsc STATUS,C    ;is there a borrow?
        goto MT9          ;no

        movlw $A0         ;yes, so add 1440
        addwf ADLIN0,F
        movf STATUS,W
        andlw 1
        addlw 5
        addwf ADLIN1,F
        goto MT9

MT8:    movf ANSA1,W
        addwf ADLIN0,F
        movf STATUS,W
        andlw 1
        addwf ADLIN1,F

MT9:    btfsc INDF,0
        goto MT18         ;bit 0=1 (angle >= 180) so add ANSA1 to DIFF
        movf ANSA1,W      ;bit 0=0 (angle <180), so sub ANSA1 from DIFF
        subwf DIFF0,F
        btfsc STATUS,C    ;is there a borrow?
        goto MT19         ;no
        movlw 1           ;yes, so subtract 1 from DIFF1
        subwf DIFF1,F
        goto MT19

MT18:   movf ANSA1,W
        addwf DIFF0,F
        movf STATUS,W
        andlw 1
        addwf DIFF1,F
MT19:   return

;..................

MLTPLY: clrf ANSA0
        clrf ANSA1
        clrf ANSA2
        clrf ANSA3
        movlw 16
        movwf LOOPA
MLT1:   btfss MULTX0,0
        goto MLT2
        movf STORE0,W
        addwf ANSA0,F
        movf STATUS,W
        andlw 1
        addwf ANSA1,F
        movf STATUS,W
        andlw 1
        addwf ANSA2,F
        movf STATUS,W
        andlw 1
        addwf ANSA3,F

        movf STORE1,W
        addwf ANSA1,F
        movf STATUS,W
        andlw 1
        addwf ANSA2,F
        movf STATUS,W
        andlw 1
        addwf ANSA3,F

        movf STORE2,W
        addwf ANSA2,F
        movf STATUS,W
        andlw 1
        addwf ANSA3,F

MLT2:   bcf STATUS,C
        rlf STORE0,F
        rlf STORE1,F
        rlf STORE2,F
        bcf STATUS,C
        rrf MULTX1,F
        rrf MULTX0,F
        decfsz LOOPA,F
        goto MLT1
        return

;.................

DADD0:  addwf INDF,F    ;BYTE0  normal adding routine
        incf FSR,F      ;BYTE1
        movf STATUS,W
        andlw 1
DADD1:  addwf INDF,F    ;BYTE1
        incf FSR,F      ;BYTE2
        movf STATUS,W
        andlw 1
DADD2:  addwf INDF,F    ;BYTE2
        movf STATUS,W
        andlw 1
        addwf BYTE4,F
        return

;................

ADD0:   addwf INDF,F    ;BYTE0   adding routine for 360 degrees
        incf FSR,F      ;BYTE1
        movf STATUS,W
        andlw 1
ADD1:   addwf INDF,F    ;BYTE1
        incf FSR,F      ;BYTE2
        movf STATUS,W
        andlw 1
ADD2:   addwf INDF,F    ;BYTE2
        movlw 76        ;is BYTE2 >= 180?
        addwf INDF,W
        btfss STATUS,C
        goto ADD3       ;no
        movwf INDF
        incf FSR,F      ;BYTE3
        incf INDF,F     ;BYTE3
        btfsc INDF,1    ;is BYTE3 bit 1 set?
        clrf INDF       ;yes, so clear BYTE3
ADD3:   return

;.............

GETSIN: movf INDF,W     ;BYTE2 ;is angle >= 90?
        movwf STORE1
        addlw 166
        btfss STATUS,C
        goto GS2        ;no
        sublw 90        ;yes, now subtract answer from 90
        movwf STORE1    ;and store new value
GS2:    return

;.............

PAUSIT: movlw 16        ; wait approx 1/5 sec
        movwf LOOPA          
        clrf INTCON
PAUSE:  btfss INTCON,2  ; has a timer time-out been detected?
        goto PAUSE      ; no
        bcf INTCON,2    ; yes
        decfsz LOOPA,F  ; dec loop, is it zero?
        goto PAUSE      ; no
        return          ; yes

;........................................................

LCDPX1: iorlw %10000000
        goto LCDLIN
LCDPX2: iorlw %11000000

LCDLIN: BCF RSLINE,4          ;clear RS flag - sets LCD command/line

LCDOUT: MOVWF STORE1          ;temp store data for LCD
        MOVLW 60              ;set min time between sending full bytes to LCD
        MOVWF LOOPA
DELAY:  DECFSZ LOOPA,F
        GOTO DELAY            
        CALL SENDIT           ;send MSB
        CALL SENDIT           ;send LSB
        BSF RSLINE,4          ;set RS flag (default is flag set)
        return

SENDIT: SWAPF STORE1,F        ;get and send data nibble
        MOVF STORE1,W         
        ANDLW 15              
        IORWF RSLINE,W        ;OR the RS bit
        MOVWF PORTB           ;output the byte
        BSF PORTB,5           ;set E high
        nop
        nop
        BCF PORTB,5           ;set E low
        nop
        MOVLW 60
        MOVWF LOOPA
DELAYX: DECFSZ LOOPA,F
        GOTO DELAYX            
        RETURN

LCDHEX: movwf STORE2    ;split & format decimal byte as HEX for LCD
        swapf STORE2,W  ;get tens nibble
        andlw 15
        movwf STORE1
        addlw 6
        btfss STATUS,DC
        goto HEX2
        movf STORE1,W
        addlw 55        ;set as alpha
        goto HEX3
HEX2:   movf STORE1,W
        iorlw 48        ;set as numeral
HEX3:   call LCDOUT     ;send it
        movf STORE2,W   ;get units
        andlw 15
        movwf STORE1
        addlw 6
        btfss STATUS,DC
        goto HEX4
        movf STORE1,W
        addlw 55        ;set as alpha
        goto HEX5
HEX4:   movf STORE1,W
        iorlw 48        ;set as numeral
HEX5:   call LCDOUT
        return

;.....................

CHARCT: movlw %01000000 ;set address for CG RAM write
        call LCDLIN
        movlw %00010000
        movwf ANSA0
        clrf ANSA1

CHAR1:  movf ANSA0,W
        iorwf ANSA1,F
        movlw 8
        movwf LOOPB
CHAR2:  movf ANSA1,W
        call LCDOUT
        decfsz LOOPB,F
        goto CHAR2
        bcf STATUS,C
        rrf ANSA0,F
        btfss STATUS,C
        goto CHAR1
        return

;............

CLKSYS: btfss VFAST,0   ;is VFAST flag set?
        goto CLKS2      ;no
        call GRAPH
        return          ;yes

CLKS2:  call MODE
        call TIMEON
        decfsz CLKCNT,F ;no, increment system clock counter. Is it = 0?
        return          ;no

CLKADD: movlw 25        ;reset start value of CLKCNT
        movwf CLKCNT

        incf FLASH,F
        bcf FLASH,1

        movf EVENT,F
        btfsc STATUS,Z
        goto INCSEC
        movf CELL0,W
        call LCDPX2
        movlw '*'
        btfss FLASH,0
        movlw ' '
        call LCDOUT
        movf EVENT,W
        goto CHANGE     ;routing table

INCSEC: movlw 2
        btfss TIME,0
        movlw 7
        call LCDPX2
        movlw ':'
        btfss FLASH,0
        movlw ' '
        call LCDOUT

        clrf BYTE4
        movlw SECAD0
        movwf FSR
        movf CLKAD0,W   ;secs add step LSB (decimal place)
        call DADD0
        movlw SECAD1
        movwf FSR
        movf CLKAD1,W   ;secs add step NSB (decimal place)
        call DADD1
        movlw SECAD2
        movwf FSR
        movf CLKAD2,W   ;secs add step MSB (decimal place)
        call DADD2
        movf BYTE4,W    ;is there an overflow i.e. has 1 sec been counted?
        btfsc STATUS,Z
        return          ;no


        call GRAPH      ;yes

;        goto ADDMIN     ;.....temp - author's use only

ADDSEC: incf CLKSEC,F     ;inc secs {all units in BCD except WKDAY & MONTH}
        movlw 6
        addwf CLKSEC,W    ;if 6 is added is there a digit carry?
        btfss STATUS,DC
        goto CLKSHW       ;no
        movwf CLKSEC      ;yes
        movlw %01100000
        xorwf CLKSEC,W    ;is count = 60?
        btfss STATUS,Z
        goto CLKSHW       ;no
        clrf CLKSEC       ;yes

ADDMIN: incf CLKMIN,F     ;inc mins
        movlw 6
        addwf CLKMIN,W    ;if 6 is added is there a digit carry?
        btfss STATUS,DC
        goto CLKSHW       ;no
        movwf CLKMIN      ;yes
        movlw %01100000
        xorwf CLKMIN,W    ;is count = 60?
        btfss STATUS,Z
        goto CLKSHW       ;no
        clrf CLKMIN       ;yes

ADDHRS: incf CLKHRS,F     ;inc hours
        movlw 6
        addwf CLKHRS,W    ;if 6 is added is there a digit carry?
        btfsc STATUS,DC
        movwf CLKHRS      ;yes
        movlw %00100100
        xorwf CLKHRS,W    ;is HRS = 24?
        btfss STATUS,Z
        goto CLKSHW       ;no
        clrf CLKHRS       ;yes

ADDWK:  incf WKDAY,F
        movlw 7
        xorwf WKDAY,W
        btfsc STATUS,Z
        clrf WKDAY

ADDDAY: incf CLKDAY,F     ;inc days
        movlw 6
        addwf CLKDAY,W    ;if 6 is added is there a digit carry?
        btfsc STATUS,DC
        movwf CLKDAY      ;yes
        movf MONTH,W      ;get days in month
        call MONTH4
        movwf STORE1
        movf CLKDAY,W     ;are days <= max?
        subwf STORE1,W
        btfsc STATUS,C
        goto CLKSHW       ;no
        movlw 1
        movwf CLKDAY      ;yes

ADDMON: incf MONTH,F
        movlw 13
        xorwf MONTH,W
        btfss STATUS,Z
        goto CLKSHW
        movlw 1
        movwf MONTH

ADDYRS: incf YEAR,F       ;inc years
        movlw 6
        addwf YEAR,W      ;if 6 is added is there a digit carry?
        btfss STATUS,DC
        goto CLKSHW       ;no
        movwf YEAR        ;yes
        movlw %10100000
        xorwf YEAR,W      ;is count = 100?
        btfsc STATUS,Z
        clrf YEAR         ;yes

CLKSHW: bcf RSLINE,7      ;temp RB7 flag for sending to CPU for timing calc
        btfsc CLKSEC,0
        bsf RSLINE,7
        movf EVENT,W
        btfss STATUS,Z
        goto CLKSH3
        btfsc TIME,0    ;is calendar being shown?
        return          ;yes

        movlw 5
        call LCDPX2
CLKSH2: movf CLKHRS,W   ;get hrs
        call LCDHEX
        movlw ':'       ;insert colon
        btfss FLASH,0   ;alternate colon symbol each half-sec
        movlw ' '
        call LCDOUT
        movf CLKMIN,W   ;get mins
        call LCDHEX
        return

CLKSH3: movlw 0
        btfsc TIME,0
        goto CLKSH4
        call LCDPX1
        goto CLKSH5
CLKSH4: movlw 0
        call LCDPX2

CLKSH5: call CLKSH2
        movlw ' '
        call LCDOUT
        call SHWDAY     ;show day of week
        movlw ' '
        call LCDOUT

        movf CLKDAY,W   ;get day of month
        call LCDHEX
        call SHWMNT     ;show month

        movf YEAR,W     ;get year
        call LCDHEX
        return

;.............

BCDBIN: movwf LOOPA     ;convert BCD into binary
        andlw 15
        movwf STORE5
        swapf LOOPA,W
        andlw 15
        btfsc STATUS,Z
        goto BCDBN3
        movwf LOOPA
BCDBN2: movlw 10
        addwf STORE5,F
        decfsz LOOPA,F
        goto BCDBN2
BCDBN3: movf STORE5,W
        return

;................

BINBCD: movwf LOOPA
        clrf BCDVAL     ;convert binary to BCD value
        movf LOOPA,W
        btfsc STATUS,Z
        goto BCD3
BCD2:   incf BCDVAL,F
        movlw 6
        addwf BCDVAL,W
        btfsc STATUS,DC
        movwf BCDVAL
        decfsz LOOPA,F
        goto BCD2
BCD3:   return

;...............

GETHRS: clrf STORE2
GTHRS2: incf STORE2,F    ;get hours value (divide by 60)
        movlw 60
        subwf STORE0,F
        btfsc STATUS,C
        goto GTHRS2
        movlw 1
        subwf STORE1,F
        btfsc STATUS,C
        goto GTHRS2
        decf STORE2,F
        movlw 60
        addwf STORE0,F
        movlw 24
        xorwf STORE2,W
        btfsc STATUS,Z
        clrf STORE2
        return

;...............

;WRITE DATA TO EEPROM ROUTINE modified for PIC16F87x devices
;according to data sheet DS30292A page 43

                        ;This routine is entered with W holding
                        ;the eeprom byte address at which data
                        ;is to be stored. The data to be stored
                        ;is held in STORE1.
SETPRM: bsf STATUS,RP1  ;set for Page 2
        bcf STATUS,RP0
        movwf EEADR     ;copy W into EEADR to set eeprom address
        bcf STATUS,RP1  ;set for Page 0
        movf STORE1,W   ;get data value from STORE1 and hold in W
        bsf STATUS,RP1  ;set for Page 2
        movwf EEDATA    ;copy W into eeprom data byte register
        bsf STATUS,RP0  ;set for page 3
        bcf EECON1,EEPGD ;point to Data memory
        bsf EECON1,WREN ;enable write flag

MANUAL: movlw $55       ;these lines cause the action required by
        movwf EECON2    ;by the eeprom to store the data in EEDATA
        movlw $AA       ;at the address held by EEADR.
        movwf EECON2
        bsf EECON1,WR   ;set the ``perform write'' flag
        bcf STATUS,RP1  ;set for Page 0
        bcf STATUS,RP0

CHKWRT: btfss PIR2,EEIF ;wait until bit 4 of PIR2 is set
        goto CHKWRT
        bcf PIR2,EEIF   ;clear bit 4 of PIR2
        return

;..............

INCPRM: movwf STORE1    ;used for consecutive writes to EEPROM
        movf LOOPB,W
        incf LOOPB,F
        goto SETPRM

;..........

;READ DATA FROM EEPROM ROUTINE modified for PIC16F87x devices
;according to data sheet DS30292A page 43

                        ;This routine is entered with W holding
                        ;the eeprom byte address to be read.
PRMGET: bsf STATUS,RP1  ;set for Page 2
        bcf STATUS,RP0
        movwf EEADR     ;copy W into EEADR to set eeprom address
        bsf STATUS,RP0  ;set for Page 3
        bcf EECON1,EEPGD ;point to data memory
        bsf EECON1,RD   ;enable read flag
        bcf STATUS,RP0  ;set for Page 2 
        movf EEDATA,W   ;read eeprom data now in EEDATA into W
        bcf STATUS,RP1  ;set for Page 0
        return

;.................

TIMEON: movf EVENT,F
        btfss STATUS,Z
        return
        btfsc SWPORT,1
        goto TSTPR2
        bcf SWITCH,1
        return

TSTPR2: btfsc SWITCH,1
        return
        bsf SWITCH,1
        call CLRLN2
        incf TIME,F
        bcf TIME,1
        bsf FLASH,0
        btfsc TIME,0
        goto CLKSH3

TIMON2: movlw 0
        call LCDPX2
        movf NOWLO1,W
        xorlw 255
        btfss STATUS,Z
        goto TIMON3

        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        goto TIMON4

TIMON3: movf NOWLO1,W
        call LCDHEX
        movf NOWLO0,W
        call LCDHEX

TIMON4: movlw ' '
        call LCDOUT
        call CLKSH2
        movlw 12
        call LCDPX2
        movf NOWHI1,W
        xorlw 255
        btfss STATUS,Z
        goto TIMON5

        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        return

TIMON5: movf NOWHI1,W
        call LCDHEX
        movf NOWHI0,W
        call LCDHEX
        return

MODE:   btfsc SWPORT,0
        goto TSTPRV
        bcf SWITCH,0
        return

TSTPRV: btfsc SWITCH,0
        return
        bsf SWITCH,0
        goto EVENT1

EVENT1: call CLRLN2
        bcf FLASH,0
        incf EVENT,F
        movf EVENT,W
        addlw 247       ;is value >8?
        btfss STATUS,C
        goto EVENTB     ;no
        clrf EVENT      ;yes
        call CALCTD     ;calculate new high/low tides

        movlw 0         ;show ALL DONE message
        call LCDPX2
        clrf LOOPB
DONE:   movf LOOPB,W
        call ALLDUN
        call LCDOUT
        incf LOOPB,F
        movf LOOPB,W
        xorlw 8
        btfss STATUS,Z
        goto DONE
        movlw 2
        call LCDPX1
        movlw ':'
        call LCDOUT

WAIT1:  btfsc SWPORT,0
        goto WAIT1
        clrf CALC0      ;clear calculation in progress flag
        call CLRLN1
        call CLRLN2
        clrf CLKSEC
        movlw 25
        movwf CLKCNT

        movlw 0           ;show current high and low tide times
        call LCDPX2
        btfss TIDEUP,0
        goto DUN2
DUN1:   movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw 255
        movwf NOWLO1
        movwf NOWLO0

        movlw 12
        call LCDPX2
        movf NXTHI1,W
        movwf NOWHI1
        call LCDHEX
        movf NXTHI0,W
        movwf NOWHI0
        call LCDHEX
        goto DUN3

DUN2:   movf NXTLO1,W
        movwf NOWLO1
        call LCDHEX
        movf NXTLO0,W
        movwf NOWLO0
        call LCDHEX
        movlw 12
        call LCDPX2
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw '?'
        call LCDOUT
        movlw 255
        movwf NOWHI1
        movwf NOWHI0

DUN3:   call GRFSHW
        bsf FLASH,0
        movlw 5
        call LCDPX2
        call CLKSH2
        return

EVENTB: call CELL
        movwf CELL0
        call LCDPX2

        movf EVENT,W
        xorlw 7
        btfsc STATUS,Z
        goto EVENT7        ;amend tide time mode

        movf EVENT,W
        xorlw 8
        btfsc STATUS,Z
        goto EVENT8        ;adjust real-time clock timing accuracy mode
        goto EVENTC

EVENT7: call CALCRF        ;amend tide time mode
        movlw 0
        call LCDPX2
        clrf LOOPB
EV7A:   movf LOOPB,W
        call HIGH
        call LCDOUT
        incf LOOPB,F
        movf LOOPB,W
        xorlw 12
        btfss STATUS,Z
        goto EV7A
        movlw 12           ;show time of next high tide
        call LCDPX2
        movf NXTHI1,W
        call LCDHEX
        movf NXTHI0,W
        call LCDHEX
        goto EVENTC

EVENT8: movlw 0            ;adjust real-time clock timing accuracy mode
        call LCDPX2
        clrf LOOPB
EV8A:   movf LOOPB,W
        call FAST
        call LCDOUT
        incf LOOPB,F
        movf LOOPB,W
        xorlw 9
        btfss STATUS,Z
        goto EV8A
        call SHWALT
EVENTC: return

;..............

ALTMIN: movlw CLKMIN    ;correct minutes
        movwf FSR
        movlw %01011001 ;limiting value
        call INCIT
        call CLKSH3
        return

ALTHRS: movlw CLKHRS    ;correct hours
        movwf FSR
        movlw %00100011 ;limiting value
        call INCIT
        call CLKSH3
        return

ALTDAY: movf MONTH,W    ;correct days
        call MONTH4     ;get limiting value
        movwf LIMIT
        btfss SWPORT,2  ;is dec needed?
        goto ALD4       ;no
        movlw 1         ;yes
        subwf CLKDAY,F
        btfsc STATUS,Z
        goto ALD3
        btfsc STATUS,DC
        goto ALD5
        movlw 6
        subwf CLKDAY,W
        movwf CLKDAY
        goto ALD5
ALD3:   movf LIMIT,W
        movwf CLKDAY
        goto ALD5

ALD4:   btfss SWPORT,1
        goto ALD5
        incf CLKDAY,F
        movf CLKDAY,W
        addlw 6
        btfsc STATUS,DC
        movwf CLKDAY
        movf CLKDAY,W
        subwf LIMIT,W
        btfsc STATUS,C
        goto ALD5
        movlw 1
        movwf CLKDAY
ALD5:   call CLKSH3
        return

ALTMNT: btfss SWPORT,1     ;correct month
        goto ALTMN2
        incf MONTH,F
        movf MONTH,W
        addlw 243
        btfss STATUS,C
        goto ALTMN3
        movlw 1
        movwf MONTH
        goto ALTMN3

ALTMN2: btfss SWPORT,2
        goto ALTMN3
        decfsz MONTH,F
        goto ALTMN3
        movlw 12
        movwf MONTH
ALTMN3: call CLKSH3
        return

ALTYRS: movlw YEAR      ;correct years
        movwf FSR
        movlw %10011001 ;limiting value
        call INCIT
        call CLKSH3
        return

ALTWKD: movlw WKDAY     ;correct weekday
        movwf FSR
        movlw 6         ;limiting value
        call INCIT
        call CLKSH3
        return

ALTTIM: call CLKSH3
        movlw CLKAD0    ;correct real-time timing factor
        movwf FSR
        btfss SWPORT,1
        goto ALT2
        movlw 1
        call DADD0
        goto SHWALT
ALT2:   btfss SWPORT,2
        goto ALT3
        movlw 1
        subwf INDF,F
        btfsc STATUS,C
        goto SHWALT
        incf FSR,F
        movlw 1
        subwf INDF,F
        btfsc STATUS,C
        goto SHWALT
        incf FSR,F
        decf INDF,F
        goto SHWALT
ALT3:   return

;............

ALTTID: btfss SWPORT,1    ;correct tide adjust factor
        goto ALTD2
        incf TIDEAD,F
        goto ALTD3
ALTD2:  btfss SWPORT,2
        goto ALTD3
        decf TIDEAD,F
ALTD3:  call DAYB
        call DAYC
        movlw 12
        call LCDPX2
        movf NXTHI1,W
        call LCDHEX
        movf NXTHI0,W
        call LCDHEX
        call CLKSH3
        return

;................

SHWALT: movlw 11           ;show real-time clock adjustment factor
        call LCDPX2
        btfss CLKAD1,7
        goto FASTER

SLOWER  movlw '-'
        call LCDOUT
        movf CLKAD1,W
        movwf ANSA1
        movf CLKAD0,W
        movwf ANSA0
        comf ANSA0,F
        incf ANSA0,F
        btfsc STATUS,Z
        incf ANSA1,F
        comf ANSA1,F
        movf ANSA1,W
        call LCDHEX
        movf ANSA0,W
        call LCDHEX
        return

FASTER: movlw '+'
        call LCDOUT
        movf CLKAD1,W
        call LCDHEX
        movf CLKAD0,W
        call LCDHEX
        return

INCIT:  movwf LIMIT         ;increment routine used during some corrections
        btfss SWPORT,1
        goto DECIT
        incf INDF,F
        movf INDF,W
        addlw 6
        btfsc STATUS,DC
        movwf INDF
        movf INDF,W
        subwf LIMIT,W
        btfsc STATUS,C
        goto INCIT2
        clrf INDF
INCIT2: return

DECIT:  btfss SWPORT,2      ;decrement routine used during some corrections
        goto DEC4
        movlw 1
        subwf INDF,F
        btfss STATUS,C
        goto DEC3
        btfsc STATUS,DC
        goto DEC4
        movlw 6
        subwf INDF,W
        movwf INDF
        goto DEC4
DEC3:   movf LIMIT,W
        movwf INDF
DEC4:   return

SHWDAY: bcf STATUS,C    ;get weekday, multiply by 2
        rlf WKDAY,W
        addlw 68        ;add eeprom displacement
        movwf STORE2
        call PRMGET
        call LCDOUT
        incf STORE2,F
        movf STORE2,W
        call PRMGET
        call LCDOUT
        return

SHWMNT: bcf STATUS,C    ;get month, multiply by 3
        rlf MONTH,W
        addwf MONTH,W
        addlw 29        ;add eeprom displacement
SHWMT2: movwf STORE2
        call PRMGET
        call LCDOUT
        incf STORE2,F
        movf STORE2,W
        call PRMGET
        call LCDOUT
        incf STORE2,W
        call PRMGET
        call LCDOUT
        return

;.............

CALCRF: movlw 0         ;calculate tides for amended date/time
        call LCDPX2

        movlw $53        ;new routine 31MAR00
        movwf MOONA0
        movlw $E5
        movwf MOONA1
        movlw 176
        movwf MOONA2
        movlw 0
        movwf MOONA3

        movlw $53
        movwf MOONB0
        movlw $57
        movwf MOONB1
        movlw 69
        movwf MOONB2
        movlw 1
        movwf MOONB3

        movlw $DF
        movwf DAYA0
        movlw $A6
        movwf DAYA1
        movlw 5
        movwf DAYA2     ;end new routine

        clrf LOOPB
CALCR2: movf LOOPB,W
        call CALC       ;show CALCULATE message
        call LCDOUT
        incf LOOPB,F
        movf LOOPB,W
        xorlw 12
        btfss STATUS,Z
        goto CALCR2

        movlw 3         ;get max day limit for month
        call CHKVAL
        movwf STORE0

        movf CLKDAY,W   ;correct day of month if set for greater than max
        subwf STORE0,W
        btfsc STATUS,C
        goto CALCR4
        movf STORE0,W
        movwf CLKDAY
CALCR4: movlw 9
        call LCDPX1
        movf CLKDAY,W
        call LCDHEX

CALCR3: movlw 1
        movwf CALCDY    ;day
        movwf CALCMN    ;month
        clrf CALCYR     ;year
        bsf CALC0,0     ;set calculation in progress flag

CALC2:  movf YEAR,W     ;inc moon/day angles until year count = true year
        xorwf CALCYR,W  ;NB all calcs start off from moon/day angles
        btfsc STATUS,Z  ;in respect of tides for Plymouth UK 01JAN2000
        goto CALC3
        call CALCIT
        goto CALC2

CALC3:  movf MONTH,W    ;inc moon/day angles until month count = true month
        xorwf CALCMN,W
        btfsc STATUS,Z
        goto CALC4
        call CALCIT
        goto CALC3

CALC4:  movf CLKDAY,W   ;inc moon/day angles until day count = true day
        xorwf CALCDY,W
        btfsc STATUS,Z
        goto CALCA
        call CALCIT
        goto CALC4
CALCA:  call DAYB       ;convert day angle to time
        call DAYC       ;get next high/low tide times

        call CALCC      ;check that clktime is sensible for high tide
        return

;................

CALCC:  movf CLKHRS,W     ;check that clktime is sensible for high tide
        subwf NXTHI1,W    ;is CLKHRS > high tide hour?
        btfss STATUS,C
        goto CALCAB       ;yes; so increment moon/day angles once

        movf CLKHRS,W     ;is CLKHRS = high tide hour?
        xorwf NXTHI1,W
        btfss STATUS,Z
        goto CALCB        ;no

        movf CLKMIN,W     ;yes, is CLKMIN > high
        subwf NXTHI0,W    ;
        btfsc STATUS,C
        goto CALCB        ;no

CALCAB: call DAYA         ;add to dayangle
        call MOONA        ;add to moonangleA
        call MOONB        ;add to moonangleB
        call DAYB         ;convert day angle to time
        call DAYC         ;get next high/low tide times
CALCB:  return

;.........

CALCIT: clrf BYTE4        ;moon/dayangle inc for date/time adjust routine
        call MOONA
        call MOONB
        call DAYA
        btfss BYTE4,0
        return

        incf CALCDY,F     ;inc units - all in BCD
        movlw 6
        addwf CALCDY,W    ;if 6 is added is there a digit carry?
        btfsc STATUS,DC
        movwf CALCDY      ;yes
        movlw 3
        call CHKVAL
        movwf STORE2
        movf CALCDY,W
        subwf STORE2,F    ;is CALCDY > than allowed?
        btfsc STATUS,C
        return            ;no
        movlw 1           ;yes, reset CALCDY to 1
        movwf CALCDY
        incf CALCMN,F
        movlw 13
        xorwf CALCMN,W
        btfss STATUS,Z
        return
        movlw 1
        movwf CALCMN
        incf CALCYR,F
        movlw 6
        addwf CALCYR,W    ;if 6 is added is there a digit carry?
        btfss STATUS,DC
        return            ;no
        movwf CALCYR      ;yes
        movlw %10100000   ;is CALCYR = 100 (decimal)
        xorwf CALCYR,W
        btfsc STATUS,Z
        clrf CALCYR       ;yes
        return

;...............

CLRLN1: movlw 0           ;clear LCD line 1
        call LCDPX1
        goto CLRLIN
CLRLN2: movlw 0           ;clear LCD line 2
        call LCDPX2
CLRLIN: movlw 16
        movwf LOOPB
CLRA:   movlw ' '
        call LCDOUT
        decfsz LOOPB,F
        goto CLRA
        return

;**************

SETBAUD:  PAGE1               ;this is for author's use only
          movlw 21            ;BRG for 9600baud from 3.2768MHz, brgh=1
          movwf SPBRG
          movlw %00000100     ;set sync=0, brgh=1
          movwf TXSTA
          movlw %10000111     ;set output reg (RC6 is the pin)
          movwf TRISC
          bcf PIE1,4          ;clear interrupt bit (bit TXIE)
          PAGE0
          movlw %10000000     ;set SPEN Bit of RCSTA reg
          movwf RCSTA
          PAGE1
          bsf TXSTA,5         ;enable transmission (bit TXEN)
          PAGE0
          nop
          nop
          movlw 0             ;zero to PC
          call SENDPC
          return

;*************** OUTPUT TO PC SERIAL PORT for author's use only

SENDPC:   btfss PIR1,4  ;wait for TXIF bit 4 to go high (showing TXREG empty)
          goto SENDPC
          nop
          movwf TXREG   ;put val (held in W) in TXREG ready for transmission
          return

;**************

        ;calc if tide is rising for falling following date/time adjustment
CALCTD: movf CLKHRS,W   ;get clock time in BCD hours
        call BCDBIN     ;convert to binary
        movf STORE5,W   ;get binary value
        movwf STORE0
        clrf STORE1
        clrf STORE2
        movlw 60
        movwf MULTX0    ;multiply it by 60
        clrf MULTX1
        call MLTPLY
        movf CLKMIN,W   ;get clock time in BCD mins
        call BCDBIN     ;convert to binary
        movf STORE5,W   ;get multiplied mins
        addwf ANSA0,F   ;add to binary mins
        btfsc STATUS,C
        incf ANSA1,F
        movf ANSA0,W    ;store total mins in CALC (as general store)
        movwf CALCDY
        movf ANSA1,W
        movwf CALCMN

GETLO:  movf NXTLO1,W   ;get next low tide BCD hours
        call BCDBIN     ;convert to binary
        movf STORE5,W   ;get binary value of BCD store
        movwf STORE0    
        clrf STORE1
        clrf STORE2
        movlw 60
        movwf MULTX0    ;convert to mins
        clrf MULTX1
        call MLTPLY
        movf NXTLO0,W   ;get next low tide BCD mins
        call BCDBIN     ;convert to binary
        movf STORE5,W   ;get binary value of BCD store
        addwf ANSA0,F   ;add to the multiplied mins value
        btfsc STATUS,C
        incf ANSA1,F

FALL1:  clrf BYTE4        ;check if tide is falling
        movf CALCDY,W     ;subtract LSB clock time from low tide time
        subwf ANSA0,F
        btfsc STATUS,C    ;is there a borrow?
        goto FALL2        ;no
        movlw 1
        subwf ANSA1,F
        btfsc STATUS,C    ;is there a borrow?
        goto FALL2        ;no
        bsf BYTE4,0       ;yes, set overflow flag

FALL2:  movf CALCMN,W     ;subtract MSB clock time from low tide time
        subwf ANSA1,F
        btfss STATUS,C    ;is there a borrow?
        bsf BYTE4,0       ;yes, set overflow flag

        btfsc BYTE4,0     ;is overflow flag clear?
        goto RISE1        ;no, it's set, so clock hours > low tide hours

FALL3:  movlw $BC         ;is answer > $1BC?
        movwf STORE0
        movlw 1
        movwf STORE1

        clrf BYTE4
        movf ANSA0,W      ;subtract ANSA LSB from $1BC
        subwf STORE0,F
        btfsc STATUS,C    ;is there a borrow?
        goto FALL4        ;no
        movlw 1           ;yes
        subwf STORE1,F
        btfss STATUS,C    ;is there a borrow?
        bsf BYTE4,0       ;yes

FALL4:  movf ANSA1,W      ;subtract ANSA MSB from $1BC
        subwf STORE1,F
        btfss STATUS,C    ;is there a borrow?
        bsf BYTE4,0       ;yes
        btfsc BYTE4,0     ;is there an overflow?
        goto RISE1        ;yes

        movf ANSA0,W
        movwf TIDE0
        movf ANSA1,W
        movwf TIDE1

        clrf TIDEUP     ;yes, clk hrs < lo tide hrs & tide is falling
        goto CTD8

RISE1:  movf NXTHI1,W   ;get next high tide BCD hours
        call BCDBIN     ;convert to binary
        movf STORE5,W   ;get binary value of BCD store
        movwf STORE0    
        clrf STORE1
        clrf STORE2
        movlw 60
        movwf MULTX0    ;convert to mins
        clrf MULTX1
        call MLTPLY
        movf NXTHI0,W   ;get next high tide BCD mins
        call BCDBIN     ;convert to binary
        movf STORE5,W   ;get binary value of BCD store
        addwf ANSA0,F   ;add to the multiplied mins value
        btfsc STATUS,C
        incf ANSA1,F

RISE2:  clrf BYTE4
        movf CALCDY,W     ;subtract LSB clock time from high tide time
        subwf ANSA0,F
        btfsc STATUS,C    ;is there a borrow?
        goto RISE3        ;no
        movlw 1           ;yes
        subwf ANSA1,F
        btfss STATUS,C    ;is there a borrow?
        bsf BYTE4,0       ;yes

RISE3:  movf CALCMN,W     ;subtract MSB clock time from high tide time
        subwf ANSA1,F
        btfss STATUS,C    ;is there a borrow?
        bsf BYTE4,0       ;yes
        btfss BYTE4,0     ;is there an overflow?
        goto RISE4
        movlw $A0         ;yes, so add 1440
        addwf ANSA0,F
        movf STATUS,W
        andlw 1
        addlw 5
        addwf ANSA1,F

RISE4:  bsf TIDEUP,0      ;tide is rising
        movlw $BC         ;subtract diff from 444
        movwf TIDE0       ;(15 LCD cells * 30 - 6 = 444)
        movlw 1
        movwf TIDE1

        movf ANSA0,W      ;subtract diff from 444, to become TIDE
        subwf TIDE0,F
        btfss STATUS,C    ;is there a borrow?
        decf TIDE1,F      ;yes
CDT7A:  movf ANSA1,W
        subwf TIDE1,F
        movf TIDE1,W
        andlw %11111110
        btfsc STATUS,Z    ;is there a borrow?
        goto CTD8         ;no
        clrf TIDE1        ;yes, so set tide to minimum of 1
        movlw 1
        movwf TIDE0
CTD8:   call FIXFAX
        return

;..............

FIXFAX: clrf LOOPB        ;stores time & calender data in EEPROM
        movlw CLKMIN      ;plus tide adjustment factor
        movwf FSR
FIXFX2: movf INDF,W
        movwf STORE1
        movf LOOPB,W
        call SETPRM
        incf LOOPB,F
        incf FSR,F
        movf LOOPB,W
        xorlw 10
        btfss STATUS,Z
        goto FIXFX2
        return

SETFAX: clrf LOOPB        ;sets full variable data into EEPROM
        movlw CLKMIN
        movwf FSR
SETFX2: movf INDF,W
        movwf STORE1
        movf LOOPB,W
        call SETPRM
        incf LOOPB,F
        incf FSR,F
        movf LOOPB,W
        xorlw 21
        btfss STATUS,Z
        goto SETFX2
        return

RESET:  clrf CLKMIN
        clrf CLKHRS
        movlw 1
        movwf CLKDAY
        movwf MONTH
        clrf YEAR
        movlw 5
        movwf WKDAY

        movlw 0
        movwf CLKAD0
        movwf CLKAD1
        movlw $80
        movwf CLKAD2

        clrf TIDEAD

        movlw $53
        movwf MOONA0
        movlw $E5
        movwf MOONA1
        movlw 176
        movwf MOONA2
        movlw 0
        movwf MOONA3

        movlw $53
        movwf MOONB0
        movlw $57
        movwf MOONB1
        movlw 69
        movwf MOONB2
        movlw 1
        movwf MOONB3

        movlw $DF
        movwf DAYA0
        movlw $A6
        movwf DAYA1
        movlw 5
        movwf DAYA2
        call SETFAX

        movlw 32
        movwf LOOPB
        movlw 'J'
        call INCPRM
        movlw 'A'
        call INCPRM
        movlw 'N'
        call INCPRM
        movlw 'F'
        call INCPRM
        movlw 'E'
        call INCPRM
        movlw 'B'
        call INCPRM
        movlw 'M'
        call INCPRM
        movlw 'A'
        call INCPRM
        movlw 'R'
        call INCPRM
        movlw 'A'
        call INCPRM
        movlw 'P'
        call INCPRM
        movlw 'R'
        call INCPRM
        movlw 'M'
        call INCPRM
        movlw 'A'
        call INCPRM
        movlw 'Y'
        call INCPRM
        movlw 'J'
        call INCPRM
        movlw 'U'
        call INCPRM
        movlw 'N'
        call INCPRM

        movlw 'J'
        call INCPRM
        movlw 'U'
        call INCPRM
        movlw 'L'
        call INCPRM
        movlw 'A'
        call INCPRM
        movlw 'U'
        call INCPRM
        movlw 'G'
        call INCPRM
        movlw 'S'
        call INCPRM
        movlw 'E'
        call INCPRM
        movlw 'P'
        call INCPRM
        movlw 'O'
        call INCPRM
        movlw 'C'
        call INCPRM
        movlw 'T'
        call INCPRM
        movlw 'N'
        call INCPRM
        movlw 'O'
        call INCPRM
        movlw 'V'
        call INCPRM
        movlw 'D'
        call INCPRM
        movlw 'E'
        call INCPRM
        movlw 'C'
        call INCPRM

        movlw 'M'
        call INCPRM
        movlw 'O'
        call INCPRM
        movlw 'T'
        call INCPRM
        movlw 'U'
        call INCPRM
        movlw 'W'
        call INCPRM
        movlw 'E'
        call INCPRM
        movlw 'T'
        call INCPRM
        movlw 'H'
        call INCPRM
        movlw 'F'
        call INCPRM
        movlw 'R'
        call INCPRM
        movlw 'S'
        call INCPRM
        movlw 'A'
        call INCPRM
        movlw 'S'
        call INCPRM
        movlw 'U'
        call INCPRM

        movlw 0
        call LCDPX1
        movlw 'E'
        call LCDOUT
        movlw 'P'
        call LCDOUT
        movlw 'E'
        call LCDOUT
        movlw ' '
        call LCDOUT
        movlw 'T'
        call LCDOUT
        movlw 'I'
        call LCDOUT
        movlw 'D'
        call LCDOUT
        movlw 'E'
        call LCDOUT
        movlw ' '
        call LCDOUT
        movlw 'M'
        call LCDOUT
        movlw 'A'
        call LCDOUT
        movlw 'C'
        call LCDOUT
        movlw 'H'
        call LCDOUT
        movlw 'I'
        call LCDOUT
        movlw 'N'
        call LCDOUT
        movlw 'E'
        call LCDOUT

        movlw 0
        call LCDPX2
        movlw 'R'
        call LCDOUT
        movlw 'E'
        call LCDOUT
        movlw 'S'
        call LCDOUT
        movlw 'E'
        call LCDOUT
        movlw 'T'
        call LCDOUT
        movlw ' '
        call LCDOUT
        movlw 'O'
        call LCDOUT
        movlw 'K'
        call LCDOUT

WAITR:  btfsc SWPORT,0
        goto WAITR
        return

        .END            ;Final command
