
;   RA0  ...  -> 74HC595 SCK
;   RA1  ...  NC (but pulsed after RCK)
;   RA2  ...  <- S402
;   RA3  ...  <- S401
;   RA4  ...  -> LED via 10K
;
;   RB0  ...  <- SP233ACT R1 OUT (INT)
;   RB1  ...  -> 74HC595 RCK
;   RB2  ...  -> SP233ACT T1 IN
;   RB3  ...  -> 74HC595 SER
;   RB4  ...  -> AD9830A A0
;   RB5  ...  -> AD9830A A1
;   RB6  ...  -> AD9830A A2
;   RB7  ...  -> AD9830A !WR
;
; CLKIN  ...  <- 74AC161
; CLKOUT ...  NC

; serial commands:
;
; S<CR>				STATUS 
;	R=50255055.359452Hz F=2ABB504C6D286400
;	OK
;
; F=XXXXXXXXYYYYYYYY<CR>	FREQxREG (set divider)
;	OK
;
; G=XXXX<CR>			PHASE (set phase register)
;	OK
;
; R=XXXXXXXXYYYYYY<CR>		RUBIDIUM (set calibrated freq)
;	OK
;	
; E<CR>				EEPROM (save settings)
;	OK

    processor 16F84A
    #include <P16F84A.INC>
    __config _CP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ; 0x3FF2
;   __idlocs 0xFF, 0xFF, 0xFF, 0xFF

;   EEPROM-Data
    Org 0x2100
    ; Frequency R=
    DE 0x50, 0x25, 0x50, 0x55, 0x35, 0x94, 0x52         ;  P%PU5.R
    ; Divider F=
    DE 0x2A, 0xBB, 0x50, 0x4C, 0x6D, 0x28, 0x64, 0x00   ;  *.PLm(d.

    ; unused
    DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF   ;  ........
    DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF   ;  ........
    DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF   ;  ........
    DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF   ;  ........
    DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF   ;  ........
    DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF   ;  ........
    DE 0xFF

; RAM-Variable
LRAM_0x0C equ 0x0C	; serial input? output?
LRAM_0x0D equ 0x0D	; outer loop counter

;   0x0E seems unused

LRAM_0x0F equ 0x0F	; loop counter

LRAM_0x10 equ 0x10	; flagword
			;   fw:0 output R=.. F=..
			;   fw:1 load FREQxREG(s)
			;   fw:2 branch on jumptable
			;   fw:3 update eeprom
			;   fw:4 output 'OK'
			;   fw:5 low/high nibble

LRAM_0x11 equ 0x11	; jump table index

LRAM_0x12 equ 0x12	; temp byte buffer

LRAM_0x13 equ 0x13	; temp buffer (32bit)
LRAM_0x14 equ 0x14
LRAM_0x15 equ 0x15
LRAM_0x16 equ 0x16

;   0x17 (18 bytes read from eeprom)
;   0x17-0x1A	R=XXXXXXXXxxxxxx
;   0x1B-0x1D	R=xxxxxxxxXXXXXX

;   0x1E-0x21	F=XXXXXXXXxxxxxxxx
LRAM_0x1E equ 0x1E	; F (MSB)
LRAM_0x1F equ 0x1F	; F
LRAM_0x20 equ 0x20	; F
LRAM_0x21 equ 0x21	; F (LSB)

;   0x22-0x25	F=xxxxxxxxXXXXXXXX

;   0x26-0x28	G=XXXXXX
LRAM_0x26 equ 0x26	; Phase (MSB)
LRAM_0x27 equ 0x27	; Phase (LSB)

; Program

    Org 0x0000

;   Reset-Vector
    GOTO LADR_0x000A
    ADDLW 0xFF           ;   b'11111111'  d'255'
    ADDLW 0xFF           ;   b'11111111'  d'255'
    ADDLW 0xFF           ;   b'11111111'  d'255'

;   Interrupt-Vector
    BCF STATUS,RP0       ; Bank 0
    BTFSC INTCON,INTF	 ; skip if no external IRQ on RB0
    CALL LADR_0x010A	 ; handle external IRQ

    MOVLW 0x10           ;   b'00010000'  d'016'
    MOVWF INTCON	 ; enable external IRQ
    RETFIE

;   main()
LADR_0x000A	
    MOVLW 0x10           ;   b'00010000'  d'016'
    MOVWF INTCON	 ; enable external IRQ

    BSF STATUS,RP0       ; Bank 1

    MOVLW 0x01           ;   b'00000001'  d'001'
    MOVWF TRISB          ; RB0 input

    MOVLW 0x00           ;   b'00000000'  d'000'
    MOVWF OPTION_REG     
    BCF OPTION_REG,6	 ; RB0/INT on falling edge

    BCF STATUS,RP0       ; Bank 0

    MOVLW 0x84           ;   b'10000100'  d'132'
    MOVWF PORTB          ; RB2, RB7 high

    BSF STATUS,RP0       ; Bank 1

    MOVLW 0x0C           ;   b'00001100'  d'012'
    MOVWF TRISA		 ; RA2, RA3 inputs

    BCF STATUS,RP0       ; Bank 0

    MOVLW 0x10           ;   b'00010000'  d'016'
    MOVWF PORTA          ; RA4 high

    CLRF LRAM_0x11	 ; command = 0 ?
    CLRF LRAM_0x10	 ; clear flagword
    CALL LADR_0x017B	 ; copy eeprom to buffer

    BSF INTCON,INTE	 ; enable interrupt
    BSF INTCON,GIE	 ; global IRQ enable

    MOVLW 0x1F           ;   b'00011111'  d'031'
    MOVWF LRAM_0x13	 ; loop counter

;   delay loop
LADR_0x0022
    CALL LADR_0x003B	 ; long delay
    DECFSZ LRAM_0x13,F
    GOTO LADR_0x0022	 ; repeat 31 x

    CALL LADR_0x011A	 ; load FREQxREG(s)
    CALL LADR_0x003B	 ; long delay
    CALL LADR_0x011A	 ; load FREQxREG(s)

;   main loop
LADR_0x0028
    BTFSC LRAM_0x10,2	 ; skip if fw:2 == 0
    CALL LADR_0x0055	 ; branch on LRAM_0x11 (jump table)

    BTFSC LRAM_0x10,4	 ; skip if fw:4 == 0
    CALL LADR_0x00D1	 ; output 'OK'

    BTFSC LRAM_0x10,0	 ; skip if fw:0 == 0
    CALL LADR_0x00D9	 ; output 'R=XXXXX.XXXHz F=YYYYYYY'

    BTFSC LRAM_0x10,1	 ; skip if fw:1 == 0
    CALL LADR_0x011A	 ; load FREQxREG(s)

    BTFSC LRAM_0x10,3	 ; skip if fw:3 == 0
    CALL LADR_0x018B	 ; copy buffer to eeprom

    BSF PORTA,4          ; enable RA4 (led)
    CALL LADR_0x0040	 ; action()
    CALL LADR_0x003B	 ; long delay
    CALL LADR_0x003B	 ; long delay

    BCF PORTA,4          ; disable RA4 (led)
    CALL LADR_0x0040	 ; action()
    CALL LADR_0x003B	 ; long delay
    CALL LADR_0x003B	 ; long delay

    GOTO LADR_0x0028	 ; loop forever


;   long delay (loop counter)
LADR_0x003B
    MOVLW 0xFF           ;   b'11111111'  d'255'
    CALL LADR_0x00CD	 ; delay loop
    DECFSZ LRAM_0x0F,F	 ; decrement loop counter
    GOTO LADR_0x003B	 ; loop until zero
    RETURN

;   action() i.e. check for buttons
LADR_0x0040
    BTFSC PORTA,2        ; skip if RA2 off
    GOTO LADR_0x0048	 ; branch on RA2 high 

    BTFSS PORTA,3        ; skip if RA3 on
    GOTO LADR_0x0050	 ; branch on RA3 low 

    MOVLW 0x22           ;   b'00100010'  d'034'  """
    MOVWF FSR
    CALL LADR_0x013E	 ; action on RA2 low
    GOTO LADR_0x004D

LADR_0x0048
    BTFSC PORTA,3        ; skip if RA3 off
    GOTO LADR_0x0054	 ; branch on RA3 high

    MOVLW 0x22           ;   b'00100010'  d'034'  """
    MOVWF FSR
    CALL LADR_0x0148	 ; action on RA3 low

LADR_0x004D
    CALL LADR_0x018B	 ; copy buffer to eeprom
    BCF LRAM_0x10,4
    CALL LADR_0x011A	 ; load FREQxREG(s)

LADR_0x0050
    BTFSS PORTA,2        ; skip if RA2 on
    GOTO LADR_0x0050	 ; wait for RA2 high

LADR_0x0052
    BTFSS PORTA,3        ; skip if RA3 on
    GOTO LADR_0x0052	 ; wait for RA3 high

LADR_0x0054		 ; nothing pressed
    RETURN


;   parser state table
LADR_0x0055
    MOVF LRAM_0x11,W	 ; jump table index (state)
    ADDWF PCL,F          ; jump table
    GOTO LADR_0x005C	 ; 0 (command F,R,G,S,E)
    GOTO LADR_0x007B	 ; 1 (assignment '=')
    GOTO LADR_0x0082	 ; 2 (nibble/enter)
    GOTO LADR_0x0099	 ; 3 (expect enter, output status)
    GOTO LADR_0x009E	 ; 4 (expect enter, write eeprom)


;   parse commands (F,R,G,S,E)
LADR_0x005C
    BCF LRAM_0x0C,5	 ; make all upper case

    MOVLW 0x1E           ;   b'00011110'  d'030'
    MOVWF FSR

    MOVLW 0x46           ;   b'01000110'  d'070'  "F"
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    GOTO LADR_0x007F	 ; exit on 'F'

    MOVLW 0x17           ;   b'00010111'  d'023'
    MOVWF FSR

    MOVLW 0x52           ;   b'01010010'  d'082'  "R"
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    GOTO LADR_0x007F	 ; exit on 'R'

    MOVLW 0x26           ;   b'00100110'  d'038'  "&"
    MOVWF FSR

    MOVLW 0x47           ;   b'01000111'  d'071'  "G"
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    GOTO LADR_0x007F	 ; exit on 'G'

    MOVLW 0x03           ;   b'00000011'  d'003'
    MOVWF LRAM_0x11	 ; jump index = 3

    MOVLW 0x53           ;   b'01010011'  d'083'  "S"
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    GOTO LADR_0x00A3	 ; exit keypress on 'S'

    MOVLW 0x45           ;   b'01000101'  d'069'  "E"
    SUBWF LRAM_0x0C,W
    BTFSS STATUS,Z	 ; skip if equal
    GOTO LADR_0x00A2	 ; exit (reset state)

    INCF LRAM_0x11,F	 ; jump index = 4
    GOTO LADR_0x00A3	 ; exit keypress

;   parse assignment (=)
LADR_0x007B
    MOVLW 0x3D           ;   b'00111101'  d'061'  "="
    SUBWF LRAM_0x0C,W
    BTFSS STATUS,Z	 ; skip if equal
    GOTO LADR_0x00A2	 ; exit (reset state)

;   advance to next state
LADR_0x007F
    INCF LRAM_0x11,F	 ; jump index ++ 
    BCF LRAM_0x10,5	 ; fw:5 = 0
    GOTO LADR_0x00A3	 ; exit keypress

;   parse enter/nibble 
LADR_0x0082
    MOVLW 0x0D           ;   b'00001101'  d'013'
    SUBWF LRAM_0x0C,W
    BTFSS STATUS,Z	 ; skip if equal
    GOTO LADR_0x0089	 ; parse nibble

    BSF LRAM_0x10,4	 ; fw:4 = 1
    BSF LRAM_0x10,1	 ; fw:1 = 1
    GOTO LADR_0x00A2	 ; exit (reset state)

;   parse nibble
LADR_0x0089
    MOVLW 0x2E           ;   b'00101110'  d'046'  "."
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    GOTO LADR_0x00A3	 ; exit keypress

    MOVF LRAM_0x0C,W
    CALL LADR_0x00AE	 ; convert hex to nibble

    BTFSS LRAM_0x10,5	 ; skip if fw:5 == 1
    GOTO LADR_0x0096	 ; handle high nibble

    SWAPF INDF,F	 ; move high nibble up
    IORWF INDF,F	 ; combine with low nibble
    INCF FSR,F
    BCF LRAM_0x10,5	 ; fw:5 = 0
    GOTO LADR_0x00A3	 ; exit keypress

LADR_0x0096
    MOVWF INDF		 ; save high nibble
    BSF LRAM_0x10,5	 ; fw:5 = 1
    GOTO LADR_0x00A3	 ; exit keypress

;   expect enter, output status
LADR_0x0099
    MOVLW 0x0D           ;   b'00001101'  d'013'
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    BSF LRAM_0x10,0	 ; fw:0 = 1
    GOTO LADR_0x00A2

;   expect enter, write eeprom
LADR_0x009E
    MOVLW 0x0D           ;   b'00001101'  d'013'
    SUBWF LRAM_0x0C,W
    BTFSC STATUS,Z	 ; skip if not equal
    BSF LRAM_0x10,3	 ; fw:3 = 1

;   reset state and exit
LADR_0x00A2
    CLRF LRAM_0x11	 ; reset to initial state

;   exit keypress
LADR_0x00A3
    BCF LRAM_0x10,2	 ; fw:2 = 0
    CLRF LRAM_0x0C	 ; clear keycode
    RETURN

;   convert nibble (in W) to hex
LADR_0x00A6
    ANDLW 0x0F           ;   b'00001111'  d'015'
    MOVWF LRAM_0x12
    SUBLW 0x09           ;   b'00001001'  d'009'
    MOVLW 0x30           ;   b'00110000'  d'048'  "0"
    BTFSS STATUS,C
    MOVLW 0x37           ;   b'00110111'  d'055'  "7"
    ADDWF LRAM_0x12,W
    RETURN

;   convert hex (in W) to nibble
LADR_0x00AE
    MOVWF LRAM_0x12
    MOVLW 0x30           ;   b'00110000'  d'048'  "0"

    BTFSS LRAM_0x12,6	 ; skip if not (@,A-z,{,|,},~,DEL)
    GOTO LADR_0x00B4	 ; no conversion

    BCF LRAM_0x12,5	 ; make upper case
    MOVLW 0x37           ;   b'00110111'  d'055'  "7"

LADR_0x00B4
    SUBWF LRAM_0x12,W	 ; convert to nibble
    RETURN


;   output byte to serial
LADR_0x00B6		
    MOVWF LRAM_0x0C
    MOVLW 0x08           ;   b'00001000'  d'008'
    MOVWF LRAM_0x0F	 ; loop counter = 8
    BCF PORTB,2          ; clear RB2 (TX)
    CALL LADR_0x00C7	 ; delay_0x45

LADR_0x00BB
    BCF STATUS,C
    RRF LRAM_0x0C,F
    BTFSC STATUS,C
    BSF PORTB,2          ; put data on RB2 (TX)
    BTFSS STATUS,C
    BCF PORTB,2          ; 
    CALL LADR_0x00C9	 ; delay_0x40
    DECFSZ LRAM_0x0F,F	 ; decrement loop counter
    GOTO LADR_0x00BB	 ; loop until zero

    BSF PORTB,2          ; set RB2 (TX)
    CALL LADR_0x00C7	 ; delay_0x45
    RETURN

;   delay_0x45
LADR_0x00C7
    MOVLW 0x45           ;   b'01000101'  d'069'  "E"
    GOTO LADR_0x00CD

;   delay_0x40
LADR_0x00C9
    MOVLW 0x40           ;   b'01000000'  d'064'  "@"
    GOTO LADR_0x00CD

;   delay_0x21
LADR_0x00CB
    MOVLW 0x21           ;   b'00100001'  d'033'  "!"
    GOTO LADR_0x00CD

;   delay loop
LADR_0x00CD	
    MOVWF LRAM_0x0D	 ; outer loop counter

LADR_0x00CE
    DECFSZ LRAM_0x0D,F
    GOTO LADR_0x00CE	 ; loop until zero
    RETLW 0x00           ;   b'00000000'  d'000'

LADR_0x00D1		 ; output 'OK'
    MOVLW 0x4F           ;   b'01001111'  d'079'  "O"
    CALL LADR_0x00B6
    MOVLW 0x4B           ;   b'01001011'  d'075'  "K"
    CALL LADR_0x00B6
    MOVLW 0x0D           ;   b'00001101'  d'013'
    CALL LADR_0x00B6
    BCF LRAM_0x10,4	 ; fw:4 = 0
    RETURN

LADR_0x00D9		 ; output 'R=XXXXX.XXXHz F=YYYYYYY'
    MOVLW 0x52           ;   b'01010010'  d'082'  "R"
    CALL LADR_0x00B6
    MOVLW 0x3D           ;   b'00111101'  d'061'  "="
    CALL LADR_0x00B6
    MOVLW 0x17           ;   b'00010111'  d'023'
    MOVWF FSR

LADR_0x00DF
    SWAPF INDF,W
    CALL LADR_0x00A6	 ; convert nibble to hex
    CALL LADR_0x00B6
    MOVF INDF,W
    CALL LADR_0x00A6	 ; convert nibble to hex
    CALL LADR_0x00B6
    INCF FSR,F
    MOVLW 0x1B           ;   b'00011011'  d'027'
    SUBWF FSR,W
    BTFSS STATUS,Z
    GOTO LADR_0x00EC	 ; skip unless '.' required

    MOVLW 0x2E           ;   b'00101110'  d'046'  "."
    CALL LADR_0x00B6

LADR_0x00EC
    MOVLW 0x1E           ;   b'00011110'  d'030'
    SUBWF FSR,W
    BTFSS STATUS,Z
    GOTO LADR_0x00DF	 ; loop until done

    MOVLW 0x48           ;   b'01001000'  d'072'  "H"
    CALL LADR_0x00B6
    MOVLW 0x7A           ;   b'01111010'  d'122'  "z"
    CALL LADR_0x00B6
    MOVLW 0x20           ;   b'00100000'  d'032'  " "
    CALL LADR_0x00B6
    MOVLW 0x46           ;   b'01000110'  d'070'  "F"
    CALL LADR_0x00B6
    MOVLW 0x3D           ;   b'00111101'  d'061'  "="
    CALL LADR_0x00B6

LADR_0x00FA
    SWAPF INDF,W
    CALL LADR_0x00A6	 ; convert nibble to hex
    CALL LADR_0x00B6
    MOVF INDF,W
    CALL LADR_0x00A6	 ; convert nibble to hex
    CALL LADR_0x00B6
    INCF FSR,F
    MOVLW 0x26           ;   b'00100110'  d'038'  "&"
    SUBWF FSR,W
    BTFSS STATUS,Z
    GOTO LADR_0x00FA	 ; loop until done

    MOVLW 0x0D           ;   b'00001101'  d'013'
    CALL LADR_0x00B6
    BCF LRAM_0x10,0	 ; fw:0 = 0
    BSF LRAM_0x10,4	 ; fw:4 = 1
    RETURN

;   Interrupt Handler
LADR_0x010A
    MOVLW 0x08           ;   b'00001000'  d'008'
    MOVWF LRAM_0x0F	 ; loop counter = 8
    CLRF LRAM_0x0C
    BCF INTCON,INTE	 ; disable interrupts
    CALL LADR_0x00C7	 ; delay_0x45

LADR_0x010F
    BCF STATUS,C
    RRF LRAM_0x0C,F	 ; shift right
    CALL LADR_0x00CB	 ; delay_0x21

    BTFSC PORTB,0        ; skip if RB0 (RX) = low
    BSF LRAM_0x0C,7	 ; set msb
    CALL LADR_0x00CB	 ; delay_0x21

    DECFSZ LRAM_0x0F,F	 ; decrement loop counter
    GOTO LADR_0x010F	 ; loop until zero
    CALL LADR_0x0055	 ; branch on LRAM_0x11 (jump table)

    BSF INTCON,INTE	 ; reenable interrupts
    RETURN



;   load FREQxREG(s)
LADR_0x011A
    MOVF LRAM_0x1E,W
    MOVWF LRAM_0x13	 ; copy LRAM_0x1E -> LRAM_0x13

    MOVF LRAM_0x1F,W
    MOVWF LRAM_0x14	 ; copy LRAM_0x1F -> LRAM_0x14

    MOVF LRAM_0x20,W
    MOVWF LRAM_0x15	 ; copy LRAM_0x20 -> LRAM_0x15

    MOVF LRAM_0x21,W
    MOVWF LRAM_0x16	 ; copy LRAM_0x21 -> LRAM_0x16

    MOVLW 0x13           ;   b'00010011'  d'019'
    MOVWF FSR		 

    MOVLW 0x84           ;   b'10000100'  d'132'
    MOVWF PORTB          ; RB2, RB7 = high

    CALL LADR_0x0152	 ; load FREQxREG (x = 0)

    BSF PORTB,5          ; switch on RB5

    CALL LADR_0x013E	 ; 

    MOVLW 0x13           ;   b'00010011'  d'019'
    MOVWF FSR

    MOVLW 0x1E           ;   b'00011110'  d'030'
    MOVWF FSR

    CALL LADR_0x0152	 ; load FREQxREG (x = 1)

    CLRW		 ; clear shift registers
    CALL LADR_0x016D	 ; output W
    CLRW
    CALL LADR_0x016D	 ; output W
    CALL LADR_0x015C	 ; pulse RB1 (RCK)

    BCF PORTB,5          ; switch off RB5
    BSF PORTB,6          ; switch on RB6

    CALL LADR_0x0161	 ; pulse RB7 (!WR)

    MOVF LRAM_0x26,W	 ; load PHASEx REG (msb)
    CALL LADR_0x016D	 ; output W

    MOVF LRAM_0x27,W	 ; load PHASEx REG (lsb)
    CALL LADR_0x016D	 ; output W

    CALL LADR_0x015C	 ; pulse RB1 (RCK)
    CALL LADR_0x0166	 ; pulse RA1
    BCF LRAM_0x10,1	 ; fw:1 = 0
    RETURN


LADR_0x013E
    MOVLW 0x04           ;   b'00000100'  d'004'
    MOVWF LRAM_0x0F	 ; loop counter = 4
    BSF STATUS,C
    MOVLW 0x01           ;   b'00000001'  d'001'

LADR_0x0142
    DECF FSR,F
    BTFSC STATUS,C
    ADDWF INDF,F
    DECFSZ LRAM_0x0F,F	 ; decrement loop counter
    GOTO LADR_0x0142	 ; loop until zero
    RETURN


LADR_0x0148
    MOVLW 0x04           ;   b'00000100'  d'004'
    MOVWF LRAM_0x0F	 ; loop counter = 4
    BCF STATUS,C
    MOVLW 0x01           ;   b'00000001'  d'001'

LADR_0x014C
    DECF FSR,F
    BTFSS STATUS,C
    SUBWF INDF,F
    DECFSZ LRAM_0x0F,F	 ; decrement loop counter
    GOTO LADR_0x014C	 ; loop until zero
    RETURN


;   load FREQxREG AD9830
LADR_0x0152
    BSF PORTB,4          ; switch on RB4
    CALL LADR_0x0157	 ; load and write AD9830 (MSB)
    BCF PORTB,4          ; switch off RB4
    CALL LADR_0x0157	 ; load and write AD9830 (LSB)
    RETURN

;   load shift registers and write to AD9830
LADR_0x0157
    CALL LADR_0x016B	 ; output byte
    CALL LADR_0x016B	 ; output byte
    CALL LADR_0x015C	 ; pulse RB1 (RCK)
    CALL LADR_0x0161	 ; pulse RB7 (!WR)
    RETURN

;   pulse RB1 ( HL )
LADR_0x015C
    BSF PORTB,1          ; switch on RB1 (high)
    NOP
    NOP
    BCF PORTB,1          ; switch off RB1 (low)
    RETURN

;   pulse RB7 ( LH )
LADR_0x0161
    BCF PORTB,7          ; switch off RB7 (low)
    NOP
    NOP
    BSF PORTB,7          ; switch on RB7 (high)
    RETURN

;   pulse RA1 ( HL )
LADR_0x0166
    BSF PORTA,1          ; switch on RA1 (high)
    NOP
    NOP
    BCF PORTA,1          ; switch off RA1 (low)
    RETURN

;   load byte from *FSR++
LADR_0x016B
    MOVF INDF,W
    INCF FSR,F

;   output W(byte) via RB3(data)/RA0(clock)
LADR_0x016D
    MOVWF LRAM_0x12
    MOVLW 0x08           ;   b'00001000'  d'008'
    MOVWF LRAM_0x0F	 ; loop counter = 8

LADR_0x0170
    RLF LRAM_0x12,F

    BCF PORTB,3          ; data on RB3
    BTFSC STATUS,C
    BSF PORTB,3          ; 
    NOP

    BSF PORTA,0          ; pulse RA0
    NOP
    BCF PORTA,0          ; ( HL )

    DECFSZ LRAM_0x0F,F	 ; decrement loop counter
    GOTO LADR_0x0170	 ; loop until zero
    RETURN


;   copy eeprom to 0x17 - 0x28
LADR_0x017B
    MOVLW 0x17           ;   b'00010111'  d'023'
    MOVWF FSR
    CLRF EEADR           ; eprom base

LADR_0x017E		 ; 
    BSF STATUS,RP0       ; Bank 1
    BSF EECON1,0         ; RD (read)
    BCF STATUS,RP0       ; Bank 0
    NOP
    MOVF EEDATA,W        ; read data from eeprom
    MOVWF INDF		 ; write to buffer
    INCF EEADR,F         ; increment eeprom addr
    INCF FSR,F		 ; increment buffer addr
    MOVLW 0x12           ;   b'00010010'  d'018'
    SUBWF EEADR,W
    BTFSS STATUS,Z	 ; skip if (eeadr == 0x12)
    GOTO LADR_0x017E	 ; loop until done
    RETURN


;   copy 0x17 - 0x28 to eeprom
LADR_0x018B
    MOVLW 0x17           ;   b'00010111'  d'023'
    MOVWF FSR

    BCF INTCON,GIE	 ; disable IRQ
    CLRF EEADR           ; eeprom base

LADR_0x018F		 ;
    BSF STATUS,RP0       ; Bank 1
    BSF EECON1,0         ; RD (read)
    BCF STATUS,RP0       ; Bank 0
    NOP
    MOVF EEDATA,W        ; read data from eeprom
    SUBWF INDF,W	 ; compare with buffer
    BTFSC STATUS,Z	 ; skip if different
    GOTO LADR_0x01A6	 ; avoid update

    MOVF INDF,W		 ; read from buffer
    MOVWF EEDATA         ; write to eeprom

    BSF STATUS,RP0       ; Bank 1
    BSF EECON1,2         ; set WREN (write enable)
    MOVLW 0x55           ; Magic Write Sequence
    MOVWF EECON2         ;
    MOVLW 0xAA           ;
    MOVWF EECON2         ;
    BSF EECON1,1         ; set WR (write)

LADR_0x01A0		 ; wait for eeprom write done
    NOP
    BTFSS EECON1,4       ; skip if EEIF is set
    GOTO LADR_0x01A0	 ; loop until done

    BCF EECON1,2         ; clear WREN 
    BCF EECON1,4         ; clear EEIF
    BCF STATUS,RP0       ; Bank 0

LADR_0x01A6
    INCF EEADR,F         ; increment eeprom addr
    INCF FSR,F		 ; increment buffer addr
    MOVLW 0x12           ;   b'00010010'  d'018'
    SUBWF EEADR,W        ; 
    BTFSS STATUS,Z	 ; skip if (eeadr == 0x12)
    GOTO LADR_0x018F	 ; loop until done

    BSF INTCON,GIE	 ; reenable IRQ
    BCF LRAM_0x10,3	 ; fw:3 = 0
    BSF LRAM_0x10,4	 ; fw:4 = 1
    RETURN

    End
