
; 32 LED Knight Rider


; CPU configuration
; 	
	list P=16F84
	#include "p16f84.inc"
	__config _RC_OSC & _WDT_OFF & _PWRTE_ON

; Define variables at memory locations
; EEPROM DATA


EEPROM1		equ	H'00'	; non-volatile storage for LEDs pattern
EEPROM2		equ	H'01'	; cyclic change of pattern each power up

; RAM

W_TMP		equ	H'0C'	; temporary store for w in interrupt
STATUS_TMP	equ	H'0D'	; temporary store of status in interrupt  
FLAG_1		equ	H'0E'	; EEPROM write repeat flag
TEMP_1		equ	H'0F'	; temp store
TEMP_2		equ	H'10'	; w store in EWRITE subroutine
VALUE_1		equ	H'11'	; delay value in DELY subroutine
VALUE_2		equ	H'12'	; delay value in DELY subroutine

PATTERN		equ	H'13'	; LED pattern or sequence number 
MULTI_P		equ	H'14'	; multiplex number 
 			
PATT_P		equ	H'16'	; pattern position

COLUMN0		equ	H'17'	; column 0 LEDs
COLUMN1		equ	H'18'	; column 1 LEDs
COLUMN2		equ	H'19'	; column 2 LEDs
COLUMN3		equ	H'1A'	; column 3 LEDs
DELVAL		equ	H'1B'	; multiplex count
TEMP_3		equ	H'1C'	; Pattern temporary store
FLAG_S		equ	H'1D'	; switch flag
TEMP_4		equ	H'1E'	; random counter store
TEMP_5		equ	H'1F'	; random counter store
TEMP_6		equ	H'20'	; counter

BARGB0		equ	H'21'	; random number generator
BARGB1		equ	H'22'	; random number generator
BARGB2		equ	H'23'	; random number generator
AARGB0		equ	H'24'	; random number gen
AARGB1		equ	H'25'	; random number gen
AARGB2		equ	H'26'	; random number gen
AARGB3		equ	H'27'	; random number gen
AARGB4		equ	H'28'	; random number gen
AARGB5		equ	H'29'	; random number gen
AARGB6		equ	H'2A'	; random number gen
RANDB0		equ	H'2B'	; random number seed
RANDB1		equ	H'2C'	; random number seed
RANDB2		equ	H'2D'	; random number seed
RANDB3		equ	H'2E'	; random number seed
TEMPB0		equ	H'2F'	; random gen temp files
TEMPB1		equ	H'30'	; random gen temp files
TEMPB2		equ	H'31'	; random gen temp files
TEMPB3		equ	H'32'	; random gen temp files
LOOPCOUNT	equ	H'33'	; loop counter in random gen

CYCLIC		equ	H'34'	; cyclic pattern number
REP_T		equ	H'35'	; repeat sequence

; preprogram EEPROM DATA (00-3F from 2100-213F)
	
	ORG     2100		; start at 00
	
	DE	D'00'		; first pattern sequence
	DE	D'00'		; cyclic pattern 0 first

; define reset and interrupt vector start addresses

	org	0	  	; start at address 0000h
	goto	MAIN		; normal service routines from Reset vector
	org     4		; interrupt vector 0004h, start interrupt routine here
	goto	INTRUPT

; place lookup table here to ensure it does not cross a 256 byte boundary

; LED chaser sequence codes

CHASE	addwf	PCL,f		; add value to program counter
	retlw	B'11111111'	; 0
	retlw	B'11111110'	; 1
	retlw	B'11111100'	; 2
	retlw	B'11111101'
	retlw	B'11111001'
	retlw	B'11111011'
	retlw	B'11110011'
	retlw	B'11110111'
	retlw	B'11100111'
	retlw	B'11101111'
	retlw	B'11001111'
	retlw	B'11011111'
	retlw	B'10011111'
	retlw	B'10111111'
	retlw	B'00111111'
	retlw	B'01111111'	; 15
	retlw	B'11111111'	; 16

; start interrupt by saving w and status registers before altered by interrupt routine

INTRUPT movwf	W_TMP		; w to w_tmp storage
	swapf	STATUS,w	; status to w
	movwf	STATUS_TMP	; status in status_tmp  
	bcf	STATUS,RP0	; select memory bank 0

; check interrupt	
		
	btfsc	INTCON,T0IF	; TMRO overflow interrupt flag then goto counter
	goto	N_LEDS		; TMRO overflow so drive next LEDs
	goto	RECLAIM		; end of interrupt reclaim w and status


N_LEDS	movlw	D'50'		; freq is XMHz/4/2 divided by (255- value in 'w' register) 
	addwf	TMR0,f		; add to timer register and takes 2 cycles to start counting
	bcf	INTCON,T0IF	; clear TMRO interrupt flag
	
; multiplex display

	btfsc	FLAG_S,0	; is switch flag set
	goto	DEC_VAL		; LEDs off till new sequence starts

	movf	MULTI_P,w	; look at multiplex position (0 to 3)
	btfsc	STATUS,z	; if zero goto LED_0 
	goto	LED_0		; send RA0 output low
	movlw	0x01		; place a 1 in w register
	xorwf	MULTI_P,w	; compare with 1
	btfsc	STATUS,z	; if zero then goto LED_1
	goto	LED_1		; send RA1 low
	movlw	0x02		; 2 in w register
	xorwf	MULTI_P,w	; compare with 2
	btfsc	STATUS,z	; if zero then goto LED_2
	goto	LED_2		; send RA2 low

; column 3
	
LED_3	clrf	MULTI_P		; clear multiplex position ready for 0
	movlw	0xFF		; all 1's
	movwf	PORTB		; set high for LEDs off
	bsf	PORTA,0		; RA0 high
	bsf	PORTA,1		; RA1 high
	bsf	PORTA,2		; RA2 high
	bcf	PORTA,3		; RA3 low
	
	movf	COLUMN3,w	; column 3 LED codes
	movwf	PORTB		; drive LEDs
	goto	RECLAIM

; column 2

LED_2	incf	MULTI_P,f	; set multiplex position ready for 3
	movlw	0xFF		; all 1's
	movwf	PORTB		; set high for LEDs off
	bsf	PORTA,0		; RA0 high
	bsf	PORTA,1		; RA1 high
	bsf	PORTA,3		; RA3 high
	bcf	PORTA,2		; RA2 low

	movf	COLUMN2,w	; column 2 LED codes
	movwf	PORTB		; drive LEDs
	goto	RECLAIM

; column 1

LED_1	incf	MULTI_P,f	; set multiplex position ready for 2
	movlw	0xFF		; all 1's
	movwf	PORTB		; set high for LEDs off
	bsf	PORTA,0		; RA0 high
	bsf	PORTA,3		; RA3 high
	bsf	PORTA,2		; RA2 high
	bcf	PORTA,1		; RA1 low

	movf	COLUMN1,w	; column 1 LED codes
	movwf	PORTB		; drive LEDs
	goto	RECLAIM

; column 0

LED_0	incf	MULTI_P,f	; set multiplex position ready for 1
	movlw	0xFF		; all 1's
	movwf	PORTB		; set high for LEDs off
	bsf	PORTA,3		; RA0 high
	bsf	PORTA,1		; RA1 high
	bsf	PORTA,2		; RA2 high
	bcf	PORTA,0		; RA0 low

	movf	COLUMN0,w	; column 0 LED codes
	movwf	PORTB		; drive LEDs
	
; decrease Delval to zero 
; sets flash rate for pattern acknowledge LED on RA4

DEC_VAL	movf	DELVAL,w	; time delay
	btfss	STATUS,z	; check if zero
	decf	DELVAL,f	; decrease

; end of interrupt reclaim w and status 

RECLAIM	swapf	STATUS_TMP,w	; status temp storage to w
	movwf	STATUS		; w to status register
	swapf	W_TMP,f		; swap upper and lower 4-bits in w_tmp
	swapf   W_TMP,w		; swap bits and into w register
	retfie			; return from interrupt

;********************************************************************************************** 
  
; RESET		
; Set ports A & B

MAIN	movlw	0xFF
	movwf	COLUMN0		; column LEDs off
	movwf	COLUMN1
	movwf	COLUMN2
	movwf	COLUMN3
	movlw	0x27		; random seed value
	movwf	RANDB0
	movlw	0xF1
	movwf	RANDB1
	movlw	0x20		; random seed value
	movwf	RANDB2
	movlw	0x49
	movwf	RANDB2
	clrf	FLAG_S		; switch flag
	clrf	MULTI_P		; clear multiplex position
	clrf	PATT_P		; clear pattern position
	bsf	STATUS,RP0	; select memory bank 1
	movlw	B'00000000'	; (RB0 - RB7 outputs)
	movwf	TRISB		; port B data direction register
	movlw	B'00000000'	; 
	movwf	OPTION_REG	; TMRO prescaler is 2, PORTB pullups enabled
	movlw   B'00000000'	; (1's are inputs, 0's are outputs) RA0-RA4 outputs 
	movwf   TRISA		; A port data direction register
	bcf	STATUS,RP0	; select memory bank 0
	movlw	B'11111111'	; 1 for LEDs display off
	movwf	PORTB		; portB outputs high
	movlw	B'00011111'	; all high (RA4 open drain so high impedance)
	movwf	PORTA		; portA values set
	

; recall stored values

	movlw	EEPROM1		; pattern
	call 	EEREAD
	movwf	PATTERN		; pattern number

	movlw	EEPROM2		; cyclic pattern
	call	EEREAD
	movwf	CYCLIC
	incf	CYCLIC,f	
	movf	CYCLIC,w	
	sublw	0x03		; check with 4-sequences (0-3)
	btfss	STATUS,c
	clrf	CYCLIC		; clear if > 4
 	movlw	EEPROM2		; storage of CYCLIC
	movwf	EEADR
	movf	CYCLIC,w	; 
	call	EWRITE		; to EEPROM 

; interrupt enable 

	bsf	INTCON,T0IE	; set interrupt enable for TMR0 
	bsf	INTCON,GIE	; set global interrupt enable for above

; ....................................................................

; LED sequences
; LEDs are positioned from left to right as shown below column orders are 0,3,2,1
; Left Column 0; RB7,6,5,4,3,2,1,0. Left centre Column 3; RB0,1,2,3,4,5,6,7.
; Right centre Column 2; RB7,6,5,4,3,2,1,0. Right Column 1; RB0,1,2,3,4,5,6,7. 

SEQU	bcf	FLAG_S,0	; reset switch flag
	movlw	0xFF		; start with all LEDs off
	movwf	COLUMN0		; column LEDs off
	movwf	COLUMN1
	movwf	COLUMN2
	movwf	COLUMN3

	movlw	D'0'		; 0 for pattern 1
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 1
	goto	PATT_1

	movlw	D'1'		; 1 for pattern 2
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 2
	goto	PATT_2

	movlw	D'2'		; 2 for pattern 3
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 3
	goto	PATT_3

	movlw	D'3'		; 3 for pattern 4
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 4
	goto	PATT_4

	movlw	D'4'		; 4 for pattern 5
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 5
	goto	PATT_5

	movlw	D'5'		; 5 for pattern 6
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 6
	goto	PATT_6

	movlw	D'6'		; 6 for pattern 7
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 7
	goto	PATT_7

	movlw	D'7'		; 7 for pattern 8
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 8
	goto	PATT_8

	movlw	D'8'		; 8 for pattern 9
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 9
	goto	PATT_9

	movlw	D'9'		; 9 for pattern 10
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 10
	goto	PATT_10

	movlw	D'10'		; 10 for pattern 11
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 11
	goto	PATT_11

	movlw	D'11'		; 11 for pattern 12
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 12
	goto	PATT_12

	movlw	D'12'		; 12 for pattern 13
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 13
	goto	PATT_13

	movlw	D'13'		; 13 for pattern 14
	xorwf	PATTERN,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 14
	goto	PATT_14

; pattern 1 sequence (scans LEDs from left to right and then right to left)
; start by lighting middle LEDs 

PATT_1	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	ONE_1		; pattern 1 subroutine
	goto	PATT_1		; repeat
ONE_1	bcf	COLUMN3,7	; start of pattern 1
	bcf	COLUMN2,7
	call	DELAY		; time between each LED sequence
	bsf	COLUMN2,7
	movlw	D'15'		
	movwf	PATT_P		; pattern position
	movlw	COLUMN3
	call	DECRMNT		; decrement PATT_P
	bcf	COLUMN0,0	; LED on
	call 	DELAY
	bsf	COLUMN3,0	; column3 LED off
	movlw	COLUMN0
	call	INCRMNT		; increment PATT_P
; far left end so add extra delay
	call 	DELAY
	decf	PATT_P,f
	movlw	COLUMN0
	call	DECRMNT		; decrement PATT_P
	bcf	COLUMN3,0	; LED on
	call	DELAY
	bsf	COLUMN0,0	; column LED off
	movlw	COLUMN3
	call	INCRMNT		; increment PATT_P
	bcf	COLUMN2,7	; LED on
	call	DELAY
	bsf	COLUMN3,7	; LED off
	decf	PATT_P,f
	movlw	COLUMN2
	call	DECRMNT		; decrement PATT_P
	bcf	COLUMN1,0	; LED on
	call	DELAY
	bsf	COLUMN2,0	; column LED off
	movlw	COLUMN1
	call	INCRMNT		; increment PATT_P
; far right LED so add extra delay
	call 	DELAY
	decf	PATT_P,f
	movlw	COLUMN1
	call	DECRMNT		; decrement PATT_P
	bcf	COLUMN2,0	; LED on
	call	DELAY
	bsf	COLUMN1,0	; column LED off
	movlw	COLUMN2
	call	INCRMNT		; increment PATT_P
	return			; pattern return

; Pattern 2
; lights middle LEDs first then sequentially moves outward as a mirror image from the center.
; lights then sequentially move toward centre again

PATT_2	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	IN_OUT		; in to out pattern
	call	OUT_IN		; out to in pattern
	call	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	goto	PATT_2

; pattern 3 lights as an outward pattern from centre then back to centre	

PATT_3	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	IN_OUT
	bsf	COLUMN0,7	; switch off end LEDs
	bsf	COLUMN1,7
	goto	PATT_3

; pattern 4 lights as an inward pattern from out to centre

PATT_4	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call 	OUT_IN
	call	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	bsf	COLUMN3,7	; switch off inside LEDs
	bsf	COLUMN2,7
	goto 	PATT_4

IN_OUT	movlw	D'15'		
	movwf	PATT_P		; pattern position
	movlw	COLUMN2
	call	DEC_2		; decrement PATT_P
	bcf	COLUMN0,0	; LED on
	bcf	COLUMN1,0
	call 	DELAY
	bsf	COLUMN3,0	; column3 LED off
	bsf	COLUMN2,0
	movlw	COLUMN0
	call	INC_2		; increment PATT_P
	call 	DELAY
	return

; far left and right end so add extra delay

OUT_IN	movlw	D'15'		; out to in pattern
	movwf	PATT_P
	movlw	COLUMN0
	call	DEC_2		; decrement PATT_P
	bcf	COLUMN3,0	; LED on
	bcf	COLUMN2,0
	call	DELAY
	bsf	COLUMN0,0	; column LED off
	bsf	COLUMN1,0
	movlw	COLUMN2
	call	INC_2		; increment PATT_P
	return

; Pattern 5
; cyclic use of patterns 1-4
	
PATT_5	movlw	D'0'		; 0 for pattern 1
	xorwf	CYCLIC,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 1
	goto	CPATT_1

	movlw	D'1'		; 1 for pattern 2
	xorwf	CYCLIC,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 2
	goto	CPATT_2

	movlw	D'2'		; 2 for pattern 3
	xorwf	CYCLIC,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 3
	goto	CPATT_3

	movlw	D'3'		; 3 for pattern 4
	xorwf	CYCLIC,w	; patterns
	btfsc	STATUS,z	; if zero then pattern 4
	goto	CPATT_4

CPATT_1	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	ONE_1
	goto	CPATT_1
CPATT_2	call	IN_OUT		; in to out pattern
	call	OUT_IN		; out to in pattern
	call	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	goto	CPATT_2
CPATT_3	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	IN_OUT
	bsf	COLUMN0,7	; switch off end LEDs
	bsf	COLUMN1,7
	goto	CPATT_3
CPATT_4	call 	OUT_IN
	call	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	bsf	COLUMN3,7	; switch off inside LEDs
	bsf	COLUMN2,7
	goto 	CPATT_4

; Pattern 6 repeat of patterns 1-4 in sequence

PATT_6	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	movlw	D'8'		; pattern repeat
	movwf	REP_T
RPT0	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	ONE_1
	decfsz	REP_T,f
	goto	RPT0
	movlw	0x10
	movwf	REP_T
RPT1	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	IN_OUT		; in to out pattern
	call	OUT_IN		; out to in pattern
	call	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	decfsz	REP_T,f
	goto	RPT1
	movlw	0x10
	movwf	REP_T
RPT2	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	IN_OUT
	bsf	COLUMN0,7	; switch off end LEDs
	bsf	COLUMN1,7
	decfsz	REP_T,f
	goto	RPT2
	movlw	0x10
	movwf	REP_T
RPT3	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call 	OUT_IN
	call	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	bsf	COLUMN3,7	; switch off inside LEDs
	bsf	COLUMN2,7
	decfsz	REP_T,f
	goto	RPT3	
	goto	PATT_6
	
; pattern 7. Chase left

PATT_7	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_7
	goto	PATT_7

PAT_7	movlw	B'01110111'	; for chaser
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'11101110'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'
	call	DELY
	movlw	B'11101110'
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'01110111'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'
	call	DELY
	movlw	B'11011101'
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'10111011'
	movwf	COLUMN3
	movwf	COLUMN1	
	movlw	D'50'
	call	DELY
	movlw	B'10111011'
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'11011101'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'
	call	DELY
	return

; pattern 8. Chase Right
	
PATT_8	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_8
	goto	PATT_8
PAT_8  	movlw	B'01110111'	; for chaser
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'11101110'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'
	call	DELY
	movlw	B'10111011'
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'11011101'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'
	call	DELY
	movlw	B'11011101'
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'10111011'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'	
	call	DELY
	movlw	B'11101110'
	movwf	COLUMN2
	movwf	COLUMN0
	movlw	B'01110111'
	movwf	COLUMN3
	movwf	COLUMN1
	movlw	D'50'
	call	DELY
	return

; pattern 9. Strobe with regular flash rate

PATT_9	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_9
	goto	PATT_9

PAT_9	clrf	COLUMN0
	clrf	COLUMN1
	clrf	COLUMN2
	clrf	COLUMN3
	movlw	0x70
	call	DELY
	movlw	0xFF
	movwf	COLUMN0
	movwf	COLUMN1
	movwf	COLUMN2
	movwf	COLUMN3
	movlw	0x70
	call	DELY
	return

; pattern 10. Strobe with random flash rate
	
PATT_10	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_10
	goto	PATT_10

PAT_10	clrf	COLUMN0
	clrf	COLUMN1
	clrf	COLUMN2
	clrf	COLUMN3
	call	RAND32		; random number
	movf	AARGB2,w	; random delay	
	call	DELY
	movlw	0xFF
	movwf	COLUMN0
	movwf	COLUMN1
	movwf	COLUMN2
	movwf	COLUMN3
	call	RAND32		; random number
	movf	AARGB2,w	; random delay	
	call	DELY
	return

; pattern 11. LEDs come on randomly then off randomly in cyclic fashion

PATT_11	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_11
	goto	PATT_11

PAT_11	call	RND_ON		; LEDs on randomly
	movlw	0x05
	movwf	TEMP_6
DEL_1	movlw	0xFF
	call	DELY
	decfsz	TEMP_6,f
	goto	DEL_1
	call	RND_OFF		; LEDs off randomly
	movlw	0x05
	movwf	TEMP_6
DEL_2	movlw	0xFF
	call	DELY
	decfsz	TEMP_6,f
	goto	DEL_2
	return

; pattern 12. Patterns 7, 8, 9, 10 and 11

PATT_12	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	movlw	D'100'		; chaser length
	movwf	REP_T
REP7	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_7
	decfsz	REP_T,f
	goto	REP7	
	movlw	D'100'		; chaser length
	movwf	REP_T
REP8	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_8
	decfsz	REP_T,f
	goto	REP8	
	movlw	D'20'		; strobe length
	movwf	REP_T
REP9	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_9
	decfsz	REP_T,f		
	goto	REP9	
	movlw	D'20'		; strobe length
	movwf	REP_T
REP10	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_10
	decfsz	REP_T,f
	goto	REP10	
	movlw	0x02		; random on length
	movwf	REP_T
REP11	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	call	PAT_11
	decfsz	REP_T,f
	goto	REP11
	goto	PATT_12		


; Pattern 13. All LEDs instantly on then randomly extinguish over time

PATT_13	clrf	COLUMN0		; LEDs on
	clrf	COLUMN1
	clrf	COLUMN2
	clrf	COLUMN3		; all LEDs on
	
DEL_CON	movlw	0x80		; extra delay extension	
	movwf	TEMP_6
DEL_X	movlw	0xFF		; max (LEDs on for a time)
	call 	DELY		; delay
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	decfsz	TEMP_6,f
	goto	DEL_X		; continue delay 
	call	RND_OFF		; random LEDs off subroutine

TST	call 	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	goto	TST

; Pattern 14, all LEDs on 

PATT_14	clrf	COLUMN0		; LEDs on
	clrf	COLUMN1
	clrf	COLUMN2
	clrf	COLUMN3		; all LEDs on
	
FTEN	call 	DELAY
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	goto	FTEN

; routines for sequences

RND_OFF	movlw	COLUMN0		; address of column 0
	movwf	FSR		; indirect address pointer
	call	RAND32		; random number
	movf	AARGB2,w
	andlw	B'00000011'	; only bit 1 & 0
	addwf	FSR,f		; pointer to random column address (column0 to column3)
	movf	AARGB5,w
	andlw	B'00000111'	; mask out to count of 8
	movwf	TEMP_4		; store number
	movlw	B'00000001'	; bit 1 set
	movwf	TEMP_5
	movf	TEMP_4,f	; check value
	btfsc	STATUS,z	; if zero load TEMP_5
	goto	L_INDF
ROLL	bcf	STATUS,c	; clear carry bit	
	rlf	TEMP_5,f	; rotate left
	movf	TEMP_5,w
	decfsz	TEMP_4,f	; decrease
	goto	ROLL
L_INDF	iorwf	INDF,f		; write to LEDs via indirect addressing
	movf	AARGB6,w	; random value
	iorlw	0x0F		; keep above minimum delay number
	call	DELY		; uses w to set delay
	comf	COLUMN0,w	; check if LEDs off
	btfss	STATUS,z	; if not zero continue to switch off LEDs
	goto	RND_OFF		; next LED/s off 
	comf	COLUMN1,w	; check if LEDs off
	btfss	STATUS,z	; if not zero continue to switch off LEDs
	goto	RND_OFF		; next LED/s off
	comf	COLUMN2,w	; check if LEDs off
	btfss	STATUS,z	; if not zero continue to switch off LEDs
	goto	RND_OFF		; next LED/s off
	comf	COLUMN3,w	; check if LEDs off
	btfss	STATUS,z	; if not zero continue to switch off LEDs
	goto	RND_OFF		; next LED/s off
	return			; all off so return   

RND_ON	movlw	COLUMN0		; address of column 0
	movwf	FSR		; indirect address pointer
	call	RAND32		; random number
	movf	AARGB2,w
	andlw	B'00000011'	; only bit 1 & 0
	addwf	FSR,f		; pointer to random column address (column0 to column3)
	
	movf	AARGB5,w
	andlw	B'00000111'	; mask out to count of 8
	movwf	TEMP_4		; store number
	movlw	B'11111110'	; bit 1 set
	movwf	TEMP_5
	movf	TEMP_4,f	; check value
	btfsc	STATUS,z	; if zero load TEMP_5
	goto	S_INDF
ROLL_O	bsf	STATUS,c	; set carry bit
	rlf	TEMP_5,f	; rotate left
	movf	TEMP_5,w
	decfsz	TEMP_4,f	; decrease
	goto	ROLL_O
S_INDF	andwf	INDF,f		; write to LEDs via indirect addressing
	movf	AARGB6,w	; random value
	iorlw	0x0F		; keep above minimum delay number
	call	DELY		; uses w to set delay
	btfsc	FLAG_S,0	; is switch flag set
	goto	SEQU		; goto new sequence
	movf	COLUMN0,w	; check if LEDs on
	btfss	STATUS,z	; if not zero continue to switch on LEDs
	goto	RND_ON		; next LED/s on 
	movf	COLUMN1,w	; check if LEDs on
	btfss	STATUS,z	; if not zero continue to switch on LEDs
	goto	RND_ON		; next LED/s on
	movf	COLUMN2,w	; check if LEDs on
	btfss	STATUS,z	; if not zero continue to switch on LEDs
	goto	RND_ON		; next LED/s on
	movf	COLUMN3,w	; check if LEDs on
	btfss	STATUS,z	; if not zero continue to switch on LEDs
	goto	RND_ON		; next LED/s on
	return			; all off so return   
; .........................................................................

; subroutines

; subroutine to read EEPROM memory

EEREAD	movwf 	EEADR		; indirect special function register
	bsf 	STATUS,RP0	; select memory bank 1
	bsf	EECON1,RD	; read EEPROM
RD_RD	nop
	btfsc	EECON1,RD	; skip if RD low (read complete)
	goto 	RD_RD		; wait for low RD (read RD)	
	bcf	STATUS,RP0	; select bank 0
	movf	EEDATA,w	; EEPROM value in w
	return

; subroutine to write to EEPROM

EWRITE	bcf	FLAG_1,6	; EEPROM write repeat flag
	movwf	TEMP_2		; store w in temporary storage
EWRIT	movf	TEMP_2,w	; place value in w (used for read data sequence) 
	movwf	EEDATA		; data register
	bcf	INTCON,GIE	; disable interrupts
	bsf	STATUS,RP0	; select bank 1
	bsf	EECON1,WREN	; enable write
	movlw	0x55		; place 55H in w for write sequence
	movwf 	EECON2 		; write 55H to EECON2
	movlw 	0xAA		; AAH to w
	movwf	EECON2		; write AA to EECON2
	bsf	EECON1,WR	; set WR bit and begin write sequence
	bsf	INTCON,GIE	; enable interrupts
	bcf	EECON1,WREN	; clear WREN bit
WRITE	btfsc	EECON1,WR	; skip if write complete WR=0 when write complete
	goto 	WRITE		; not written yet
	bcf	EECON1,EEIF	; clear write interrupt flag 
	
; read EEPROM DATA and check if written correctly
	
	bsf 	STATUS,RP0	; select memory bank 1
	bsf	EECON1,RD	; read EEPROM
RD_AGN	nop
	btfsc	EECON1,RD	; skip if RD low (read complete)
	goto 	RD_AGN		; wait for low RD	
	bcf	STATUS,RP0	; select bank 0
	movf	EEDATA,w	; EEPROM value in w
	subwf	EEDATA,w	; compare read value with value stored
	btfsc	STATUS,z	; skip if not the same
	return			; value correctly written 
	btfsc	FLAG_1,6	; write repeat bit, skip if clear and rewrite
	return
	bsf	FLAG_1,6	; set repeat flag rewrite once only 
	goto 	EWRIT		; rewrite as not written correctly

; delay subroutine

DELAY	movlw	D'10'		; set delay period 
DELY	movwf	VALUE_1		; VALUE_1 = w
DELX	movlw	D'255'		; set delay period value 2 
LP_X	movwf	VALUE_2		; VALUE_2 = w
LP_Y	decfsz	VALUE_2,f	; decrease VALUE_2, skip if zero
	goto 	LP_Y
	
; check switch closure

	bsf	PORTA,4		; take RA4 high
	nop	
	btfss	PORTA,4		; is RA4 low
	goto	CK_SW		; check switch

	decfsz	VALUE_1,f	; decrease VALUE_1, skip if zero
	goto	LP_X
	
	return

; switch closure (still within delay subroutine)

CK_SW	movlw	0xFF		; all LEDs off
	movwf	COLUMN0		; column LEDs off
	movwf	COLUMN1
	movwf	COLUMN2
	movwf	COLUMN3
	incf	PATTERN,f	; select next pattern

; *** change number here if patterns added

	movlw	D'14'		; number of patterns ***
	subwf	PATTERN,w
	btfsc	STATUS,c	; if c is set then clear Pattern
	clrf	PATTERN

	movlw	EEPROM1		; storage of PATTERN
	movwf	EEADR
	movf	PATTERN,w	; 
	call	EWRITE		; to EEPROM
	bsf	FLAG_S,0	; switch flag
	
	movlw	D'50'		; delay to debounce switch
	movwf	DELVAL		; decreased every 4th interrupt
CK_AGN	movf	DELVAL,w	; look at delay value
	btfss	STATUS,z	; wait till zero
	goto	CK_AGN

SW_CK	bsf	PORTA,4		; take RA4 high
	nop
	btfss	PORTA,4		; is switch closed
	goto	SW_CK		; wait till clear

; add small delay here to debounce switch

	movlw	D'50'		; delay to debounce switch 50
	movwf	DELVAL		; decreased every 4th interrupt
CK_MOR	movf	DELVAL,w	; look at delay value
	btfss	STATUS,z	; wait till zero
	goto	CK_MOR

; check for closed switch again
	
	bsf	PORTA,4		; take RA4 high
	nop
	btfss	PORTA,4		; is RA4 low check switch again
	goto	CK_SW		; check switch
	
; switch open now so add delay (gap before flash) then flash LED on and off by pattern number

	incf	PATTERN,w	; pattern value
	movwf	TEMP_3		; working pattern value
	movlw	0xFF		; delay FF
	movwf	DELVAL		; decreased every 4th interrupt
CK_NOW	bsf	PORTA,4		; take RA4 high
	nop
	btfss	PORTA,4		; is RA4 low check switch again
	goto	CK_SW		; check switch
	movf	DELVAL,w	; look at delay value
	btfss	STATUS,z	; wait till zero
	goto	CK_NOW

CONTIN	bcf	PORTA,4		; drive LED

	movlw	0xFF		; LED on (flash) delay 
	movwf	DELVAL		; decreased every 4th interrupt
CK_DEL	movf	DELVAL,w	; look at delay value
	btfss	STATUS,z	; wait till zero
	goto	CK_DEL

	bsf	PORTA,4		; LED off

	movlw	0xFF		; LED off delay FF
	movwf	DELVAL		; decreased every 4th interrupt
CK_LOP2	bsf	PORTA,4		; take RA4 high
	nop
	btfss	PORTA,4		; is RA4 low check switch again
	goto	CK_SW		; check switch
	movf	DELVAL,w	; look at delay value
	btfss	STATUS,z	; wait till zero
	goto	CK_LOP2		; check loop
	movf	TEMP_3,w
	btfsc	STATUS,z	; if zero then return
	return
	decfsz	TEMP_3,f	; Pattern value decrease till zero (sets LED flash number)	
	goto	CONTIN		; continue flashing if still not zero
	return			; end of routine

; subroutine for pattern 1 decrement PATT_P and lookup table

DECRMNT
	movwf	FSR		; indirect address pointer
COL_BLK	movf	PATT_P,w	; PATT_P to w (needed for correct operation from goto)
	call	CHASE		; LED patterns for chaser
	movwf	INDF		; drive LEDs via COLUMN register set by FSR pointer
	call	DELAY
	decfsz	PATT_P,f	; decrease and so LEDs chase
	goto	COL_BLK		; column block LED chaser
	return

; subroutine for pattern 1 increment PATT_P and lookup table

INCRMNT
	movwf	FSR		; indirect address pointer
COL_X	incf	PATT_P,f	; next pattern in sequence
	movf	PATT_P,w
	sublw	D'15'		; stop at end of chase
	btfss	STATUS,c	; if c is 0 stop
	return
	movf	PATT_P,w	; PATT_P to w 
	call	CHASE		; LED patterns for chaser
	movwf	INDF		; drive LEDs via column register set by FSR pointer
	call	DELAY
	goto	COL_X		; columnX block LED chaser


; subroutine for pattern 2 decrement PATT_P and lookup table

DEC_2
	movwf	FSR		; indirect address pointer
COL_2	movf	PATT_P,w	; PATT_P to w (needed for correct operation from goto)
	call	CHASE		; LED patterns for chaser
	movwf	INDF		; drive LEDs via COLUMN register set by FSR pointer
	incf	FSR,f
	movwf	INDF		; drive mirrored LEDs
	decf	FSR,f		; reduce to original value
	call	DELAY
	decfsz	PATT_P,f	; decrease and so LEDs chase
	goto	COL_2		; column block LED chaser
	return

; subroutine for pattern 2 increment PATT_P and lookup table

INC_2
	movwf	FSR		; indirect address pointer
COL_X2	incf	PATT_P,f	; next pattern in sequence
	movf	PATT_P,w
	sublw	D'15'		; stop at end of chase
	btfss	STATUS,c	; if c is 0 stop
	return
	movf	PATT_P,w	; PATT_P to w 
	call	CHASE		; LED patterns for chaser
	movwf	INDF		; drive LEDs via column register set by FSR pointer
	incf	FSR,f
	movwf	INDF		; drive mirrored LEDs
	decf	FSR,f		; return to original value
	call	DELAY
	goto	COL_X2		; columnX block LED chaser



; Random number generator

;	Input:	32 bit initial integer seed in AARGB0, AARGB1, AARGB2, AARGB3

;	Use:	CALL	RAND32

;	Output:	32 bit random integer in AARGB0, AARGB1, AARGB2, AARGB3

;	Result:	AARG  <--  RAND32( AARG )

;	

;		min	max	mean
;	Timing:	487	487	487	clks



;	Linear congruential random number generator

;		X <- (a * X + c) mod m

;	The calculation is performed exactly, with multiplier a, increment c, and
;	modulus m, selected to achieve high ratings from standard spectral tests.

RAND32
		MOVF		RANDB0,W
		MOVWF		AARGB0
		MOVF		RANDB1,W
		MOVWF		AARGB1
		MOVF		RANDB2,W
		MOVWF		AARGB2
		MOVF		RANDB3,W
		MOVWF		AARGB3

		MOVLW		0x0D			; multiplier a = 1664525
		MOVWF		BARGB2
		MOVLW		0x66
		MOVWF		BARGB1
		MOVLW		0x19
		MOVWF		BARGB0

		CALL		FXM3224U

                INCF            AARGB6,F		; c = 1
                BTFSC           STATUS,Z
                INCF            AARGB5,F
		BTFSC		STATUS,Z
		INCF		AARGB4,F
		BTFSC		STATUS,Z
		INCF		AARGB3,F
		BTFSC           STATUS,Z
                INCF            AARGB2,F
		BTFSC		STATUS,Z
		INCF		AARGB1,F
		BTFSC		STATUS,Z
		INCF		AARGB0,F

		MOVF		AARGB3,W
		MOVWF		RANDB0			; m = 2**32
		MOVF		AARGB4,W
		MOVWF		RANDB1
		MOVF		AARGB5,W
		MOVWF		RANDB2
		MOVF		AARGB6,W
		MOVWF		RANDB3

		RETLW		0x00

;       32x24 Bit Unsigned Fixed Point Multiply 32x24 -> 56

;       Input:  32 bit unsigned fixed point multiplicand in AARGB0, AARGB1,
;               AARGB2, AARGB3

;               24 bit unsigned fixed point multiplier in BARGB0, BARGB1,
;               BARGB2

;       Use:    CALL    FXM3224U

;       Output: 56 bit unsigned fixed point product in AARGB0

;       Result: AARG  <--  AARG x BARG

;       Max Timing:     11+617+2 = 630 clks

;       Min Timing:     11+151 = 162 clks

;       PM: 11+139+1 = 151              DM: 15

FXM3224U
                CLRF    AARGB4          ; clear partial product
                CLRF    AARGB5
                CLRF    AARGB6
                MOVF   AARGB0,W
                MOVWF   TEMPB0
                MOVF   AARGB1,W
                MOVWF   TEMPB1
                MOVF   AARGB2,W
                MOVWF   TEMPB2
                MOVF   AARGB3,W
                MOVWF   TEMPB3

                CALL 	UMUL3224L

                RETLW           0x00

; UMUL3224L        macro

;       Max Timing:     2+15+6*25+24+2+7*26+25+2+7*27+26 = 617 clks

;       Min Timing:     2+7*6+5+1+7*6+5+1+7*6+5+6 = 151 clks

;       PM: 31+24+2+25+2+26+2+27 = 139            DM: 15

UMUL3224L       MOVLW   0x08
                MOVWF   LOOPCOUNT

LOOPUM3224A
                RRF     BARGB2,F
                BTFSC   STATUS,C
                GOTO    ALUM3224NAP
                DECFSZ  LOOPCOUNT,F
                GOTO    LOOPUM3224A

                MOVWF   LOOPCOUNT

LOOPUM3224B
                RRF     BARGB1,F
                BTFSC   STATUS,C
                GOTO    BLUM3224NAP
                DECFSZ  LOOPCOUNT,F
                GOTO    LOOPUM3224B

                MOVWF   LOOPCOUNT

LOOPUM3224C
                RRF     BARGB0,F
                BTFSC   STATUS,C
                GOTO    CLUM3224NAP
                DECFSZ  LOOPCOUNT,F
                GOTO    LOOPUM3224C

                CLRF    AARGB0
                CLRF    AARGB1
                CLRF    AARGB2
                CLRF    AARGB3
                RETLW   0x00
                
ALUM3224NAP     BCF     STATUS,C
                GOTO    ALUM3224NA
                
BLUM3224NAP     BCF     STATUS,C
                GOTO    BLUM3224NA
                
CLUM3224NAP     BCF     STATUS,C
                GOTO    CLUM3224NA

ALOOPUM3224
                RRF     BARGB2,F
                BTFSS   STATUS,C
                GOTO    ALUM3224NA
                MOVF    TEMPB3,W
                ADDWF   AARGB3,F
                MOVF            TEMPB2,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB2,W
                ADDWF           AARGB2,F
                MOVF            TEMPB1,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB1,W
                ADDWF           AARGB1,F
                MOVF            TEMPB0,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB0,W
                ADDWF           AARGB0,F

ALUM3224NA
                RRF    AARGB0,F
                RRF    AARGB1,F
                RRF    AARGB2,F
                RRF             AARGB3,F
                RRF             AARGB4,F
                DECFSZ  LOOPCOUNT,F
                GOTO    ALOOPUM3224

                MOVLW   0x08
                MOVWF   LOOPCOUNT

BLOOPUM3224
                RRF     BARGB1,F
                BTFSS   STATUS,C
                GOTO    BLUM3224NA
                MOVF    TEMPB3,W
                ADDWF   AARGB3,F
                MOVF            TEMPB2,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB2,W
                ADDWF           AARGB2,F
                MOVF            TEMPB1,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB1,W
                ADDWF           AARGB1,F
                MOVF            TEMPB0,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB0,W
                ADDWF           AARGB0,F

BLUM3224NA
                RRF    AARGB0,F
                RRF    AARGB1,F
                RRF    AARGB2,F
                RRF             AARGB3,F
                RRF             AARGB4,F
                RRF             AARGB5,F
                DECFSZ  LOOPCOUNT,F
                GOTO    BLOOPUM3224

                MOVLW   0x08
                MOVWF   LOOPCOUNT

CLOOPUM3224
                RRF     BARGB0,F
                BTFSS   STATUS,C
                GOTO    CLUM3224NA
                MOVF    TEMPB3,W
                ADDWF   AARGB3,F
                MOVF            TEMPB2,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB2,W
                ADDWF           AARGB2,F
                MOVF            TEMPB1,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB1,W
                ADDWF           AARGB1,F
                MOVF            TEMPB0,W
                BTFSC           STATUS,C
                INCFSZ          TEMPB0,W
                ADDWF           AARGB0,F

CLUM3224NA
                RRF    AARGB0,F
                RRF    AARGB1,F
                RRF    AARGB2,F
                RRF             AARGB3,F
                RRF             AARGB4,F
                RRF             AARGB5,F
                RRF             AARGB6,F
                DECFSZ  LOOPCOUNT,F
                GOTO    CLOOPUM3224
		RETURN	
                


; end of program
	end		 	
