;**********************************************************************
; f627-lightbar.asm                                                   *
;   This file is code for an emergency light bar controller           *
;   on the PICmicro PIC16F627.   See lightbar.dwg for cct.            *
;**********************************************************************
;                                                                     *
;    Filename:	    f627-lightbar.asm                                 *
;    Date:          July 25 2003                                      *
;    File Version: 	beta test                                         *
;                                                                     *
;    Author:        Lawrence Glaister VE7IT                           *
;    Company:       Glaister Consulting                               *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;        p16f627.inc                                                  *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
; - build using                                                       *
; assembler package found at                                          *
;  http://gputils.sourceforge.net/     or download page of            *
;  https://sourceforge.net/project/showfiles.php?group_id=41924       *                                             *
;   gpasm f627-10mhz.asm                                              *
;                                                                     *
;                                                                     *
; - burn  using                                                       *
;   pp627 ( a modified version of pp84 by L.P Glaister )              *
;   pp627 f627-10mhz.hex                                              *
;                                                                     *
;	This project uses the top 1/2 of the 1k code space for patterns.  *
;	The lower 512 bytes contains the controller code and is roughly   *
;	1/4 used.                                                         *
;**********************************************************************

	list      p=16f627, n=58, c=80      ; list directive to define processor
	radix  	dec
	
	#include <P16F627.INC>        ; processor specific variable definitions

; see page 96 of data sheet for description of config bits
; code protection off
; watch dog timer off
; brown out detection on
; power up timer enabled
; high speed xtal osc
; master clear pin used
; low voltage programming off
; NOTE: rb4 pin 10 must be pulled low (510ohms to gnd) to be
; sure HVP mode will work.
	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _LVP_OFF

; THESE 4 NIBBLES CAN BE USED FOR SOFTWARE VERSION NUMBER
	__idlocs	H'F0AD'


XTAL_FREQ 	equ 12000000	; xtal freq in hz

; I/O defns for 74hc595 shift registers control on port A
SR_CLK		equ 0 		; rising edge shifts in 1 data bit
SR_STB		equ 1		; strobes data from sr to output latches
SR_DAT		equ 2		; data for entry into shift register

;***** RAM LOCATION DEFINITIONS
; locations 70-7f are common to all 4 banks (no bank select issues)
; Bank 0 has 96 bytes of general purpose regs 20h-7fh (hi 16 are common to all banks)
; *** Bank0 *** 80 bytes 0x20 - 0x6f
	CBLOCK	0x020
	sr_tmp				; counter used by sr output routine
	sr_sr				; temp 8 bit register used by output routine
	; i/o image to be sent to shift registers (24 bits worth)
	; if only 16 bits of i/o is built, the hi byte will fall out the end
	; of the shift register
	sr_hi				; 2 lsb are alley lights
	sr_mid				; left endcap ,6 bits director, right endcap. 
	sr_lo				; left endcap ,6 bits front of lightbar, right endcap
	cycle				; counter for current pattern subcycle 0..35
	fcycle				; counter for stepping through flash patterns 0..7
	temp				; local variable used bt various routines
	ENDC

; *** Bank1 *** 80 bytes 0xA0 - 0xEF
	CBLOCK	0x0A0

	ENDC

; *** Bank2 ***	48 Bytes 0x120 - 0x14f
	CBLOCK	0x120
	ENDC


; *** Bank0/1/2/3 mirrored in all banks 0x70, 0xF0, 0x170, 0x1F0, 16 bytes
	CBLOCK	0x070
	w_temp               ; variable used for context saving 
	status_temp          ; variable used for context saving
	ENDC

;**********************************************************************
;* Program description
;*
;* The basic timing function is handled by timer1 that sets the
;* int flag at a rate of  72*12 timeslots/minute (69.4ms / timeslot).
;
;* This cause the main program loop to re-examine the input
;* switches to determine the current mode and to update the output
;* image in memory. The output image is then shifted out to the display
;* drivers and the main loop goes back to sleep.
;**********************************************************************



;**********************************************************************
	ORG     0x000           ; processor reset vector
	NOP						; required for the ICD 
	CLRF	STATUS			; ensure we are at bank0	
	CLRF    PCLATH        	; ensure page bits are cleared ( before GOTO xxx !!! )

	goto    start           ; go to beginning of program


	ORG     0x004           ; interrupt vector location
	movwf   w_temp          ; save off current W register contents
	movf	STATUS,W        ; move status register into W register
	movwf	status_temp     ; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere


	movf    status_temp,W   ; retrieve copy of STATUS register
	movwf	STATUS          ; restore pre-isr STATUS register contents
	swapf   w_temp,F
	swapf   w_temp,W        ; restore pre-isr W register contents
	retfie                  ; return from interrupt



start
	MOVLW   B'11111111'     ; PORT REGS TO DEFAULTS
	MOVWF   PORTA
	MOVLW   B'11111111'
	MOVWF   PORTB
	
	MOVLW	7				; turn comparators off
	MOVWF	CMCON			; and enable pins for I/O


	MOVLW   B'00000111'
	; B7:   RBPU   - ENABLE PORT B PULL-UP RES, 0=OFF
	; B6:   INTEDG - RB0 INT EDGE SEL 0=-VE
	; B5:   T0CS   - TMR0 SOURCE, 0=FOSC/4, 1=RA4 PIN
	; B4:   T0SE   - RA4CLK PIN EDGE SELECT, 0=+VE
	; B3:   PSA    - PRESCALE ASSIGN 0=TIMER, 1=WDG
	; B2-0: PS2-0  - PRESCALE RATE 111=256 FOR TIMER (=127 FOR WDT)

	ERRORLEVEL -306, -302
	BSF     STATUS,RP0      ; OPTION & TRIS & VRCON ARE IN BANK 1
	MOVWF   OPTION_REG

	movlw	b'00000000'		; vref powered down, vref not using ra2,
	movwf	VRCON
						;
	; set rb0, rb1, rb2, rb3, rb4, rb5, rb6 rb7 as inputs
	MOVLW   B'11111111'     ; 0=OUTPUT
	MOVWF   TRISB

	; set ra0, ra1, ra2 as outputs, rest are inputs
	MOVLW   B'11111000'     ; 1=INPUT
	MOVWF   TRISA

	BCF     STATUS,RP0      ; BACK TO LO REGS
	ERRORLEVEL +306, +302	

	MOVLW   B'00000000'        
	; B7: GIE  - GLOBAL INT ENABLE, 0=OFF
	; B6: EEIE - EERAW WRITE DONE INT ENABLE, 0=OFF
	; B5: T0IE - TMR0 O/FLOW INT ENABLE, 0=OFF
	; B4: INTE - RB0 INT ENABLE, 0=OFF
	; B3: RBIE - PORTB CHANGE-OF-STATE INT ENABLE, 0=OFF
	; B2: T0IF - TMR0 O'FLOW FLAG, 1=O/FLOW, S/WARE MUST RESET
	; B1: INTF - RB0 INT FLAG, ACTIVE HIGH
	; B0: RBIF - PORTB CHANGE-OF-STATE FLAG, ACTIVE HIGH
	MOVWF   INTCON

	call	init_timer1

	; init any i/o that needs to behave on powerup
	bcf 	PORTA,SR_CLK	; shift register clk low
	nop
	bcf 	PORTA,SR_STB	; output latch strobe low
	nop
	bcf		PORTA,SR_DAT	; to keep things clean drop data bit

	; add application specific inits here
	clrf	cycle
	clrf	fcycle

main  
	btfss	PIR1,TMR1IF		; check to see if time to do something
	goto	main

	; if the timer is running correctly, we get here 14.4 times/sec
	call	init_timer1		; restart the timer for next time


	; manage the basic 36 cycle counter used to step through a pattern
	incf	cycle,f			; bump up the cycle counter
	movf	cycle,w
	sublw	35				; check if its too big (0..35 valid)
	btfsc	STATUS,C
	goto	main01

	; manage the counter used to cycle through the list of flash patterns
	clrf	cycle			; reset counter 0
	incf	fcycle,f		; bump major full cycle counter up

main01
	clrf	sr_lo			; front light bar off
	clrf	sr_mid			; nothing for rear leds
	clrf	sr_hi			; alley lamps off

	; dont change the sequence of calls below as there is some interaction
	; depending on code 1,2,3 and director input switches
	call	frontside		; setup display on front side of lightbar
							; (also sets same pattern in rear)
	call	director		; setup bits for rear director leds
	call	end_caps		; setup bits for lamps on end caps
	call	alley_lamps		; setup bits for alley lamps
	call	auxillary		; spare i/o gets commet flash

	call	sr_24out		; update the outputs for this cycle

	goto	main
;
; ---------------------------------------------------------------------
; auxillary
; 6 spare output bits get comet_alt flash pattern when spare
; switch is active.
; ---------------------------------------------------------------------
;
auxillary
	movf	PORTB,w
	andlw	B'00100000'		; rb5
	btfsc	STATUS,Z
	return

	call	comet_alt
	movwf	temp
	rlf		temp,F			; move pattern into correct bits
	rlf		temp,w			; move pattern into correct bits
	iorwf	sr_hi,F			; plunk current pattern into output buffer		
	return

;
; ---------------------------------------------------------------------
; alley_lamps
; Alley lamps controlled by switch position except in code 3 case
; where they get flashed. Assumes sr images are cleared(off) on entry
; ---------------------------------------------------------------------
;
alley_lamps
	btfss	PORTB,2			; check if code 3 input is active
	goto	alley_01

	; lamps are forced to flash because code 3 input is active
	; by turning them on during portions of cycle
	btfss	cycle,2
	return

	bsf		sr_hi,0			; turn on left alley lamp
	bsf		sr_hi,1			; turn on right alley lamp	
	return

	; lamps are controlled by switch position
alley_01
	btfsc	PORTB,3			; if alley lamps switch on
	bsf		sr_hi,0			; turn on left alley lamp
	btfsc	PORTB,3
	bsf		sr_hi,1			; turn on right alley lamp	
	return


;
; ---------------------------------------------------------------------
; end_caps
; end caps are flashed with a comet pattern in code 2 and code 3
; ---------------------------------------------------------------------
;
end_caps
	movf	PORTB,w
	andlw	B'00000110'		; pick off code 2 & 3 bits
	btfsc	STATUS,Z
	return

	; set 4 corner leds based on comet pattern
	; uses 2 bits from the generic comet pattern
	call	comet_alt		; get comet style pattern
	movwf	temp

	btfsc	temp,0
	bsf		sr_lo,7			; left front corner on

	btfsc	temp,0
	bsf		sr_lo,0			; right front corner on

	btfsc	temp,1
	bsf		sr_mid,7		; left rear corner on

	btfsc	temp,1
	bsf		sr_mid,0		; right rear corner on	
	return	

;
; ---------------------------------------------------------------------
; director
; director pattern ignored in code 3 (rear flashes same as front)
; input switches select left/split/right in all other cases
; ---------------------------------------------------------------------
;
director
	btfsc	PORTB,2			; if code 3 active
	return					; we are done

	movf	PORTA,w
	andlw	B'00011000'		; inputs on ra3 and ra4

	btfsc	STATUS,Z		; if no director bits on,	
	return					; we are done

	clrf	sr_mid			; wipe clean code 1,2 effects
	sublw	B'00011000'		
	btfsc	STATUS,Z		; if both bits on
	goto	dir_00			; go handle split case

	btfsc	PORTA,3			; if only left director input active
	goto	dir_01			; setup for left pattern

	call	scanr			; must want scan right
	goto	dir_02
	
dir_00
	; use split pattern
	call	scansplit
	goto	dir_02

dir_01
	; use left pattern
	call	scanl			; fall through to whack on bits

dir_02
	movwf	temp
	rlf		temp,W			; move pattern into correct bits
	andlw	B'01111110'		; mask off what we are using
	movwf	sr_mid
;	iorwf	sr_mid,F		; plunk current pattern into output buffer	
	return

;
; ---------------------------------------------------------------------
; frontside
; Setup output bits for front side of lightbar.
; Variables cycle and fcycle are used to determine pattern.
; fcycle is used to sequence through several 2.5 second long patterns.
; cycle is used to pick up one of 36 samples in a particular pattern.
; In code 3, rear pattern is the same as the front pattern.
; 
; ---------------------------------------------------------------------
;
frontside
	movf	PORTB,w
	andlw	B'00000111'		; inputs on rb0, rb1 and rb2

	btfsc	STATUS,Z		; if no code bits active
	return					; we are done

	; if we get here, we are code 2 or code 3
	; lookup which pattern routine we should be using based on fcycle
	; feel free to change this order if sequencial patterns do not
	; look good together.
jmptab
	movlw	HIGH jmptab		; setup to index into jump table
	movwf	PCLATH
	movf	fcycle,w
	movwf	temp
	rlf		temp,W				
	andlw	B'00001110'		; force to 0,2,4,6,8,10,12,14 for case
	addwf	PCL,F			; jump into state table

	call	alt				; 0) alternating led modules on
	goto	front_00
	call	comet_alt		; 1) strobe effect alternating modules on
	goto	front_00
	call	nrider			; test...
;	call	wigwag			; 2) left and right groups of 3 alternate		
	goto	front_00
	call	cometww			; 3) strobe effect alternating groups of 3
	goto	front_00
	call	centersww		; 4) center steady alternating groups of 2
	goto	front_00
	call	cscww			; 5) center steady strobe effect alternating groups of 2
	goto	front_00
	call	flash			; 6) all 6 leds flash
	goto	front_00
	call	cometflash		; 7) all 6 leds simulate strobe
	goto	front_00
	; this is a spare pattern that never gets called
;	call	nrider			; 8) 2 leds sweep back and forth
;	goto	front_00
jtabend
	if ((jmptab & 0xff00 ) != (jtabend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif


front_00
	movwf	temp
	rlf		temp,W			; move pattern into correct bits
	andlw	B'01111110'		; mask off what we are using
	iorwf	sr_mid,F		; plunk current pattern into rear output buffer	

	btfsc	PORTB,0			; if code 1,
	return					; nothing goes in the front pattern
				
	movf	sr_mid,w		; copy pattern to front director leds
	movwf	sr_lo
	return	


;
; ---------------------------------------------------------------------
; init_timer1
; set up registers associated with timer1 so that TMR1IF in PIR1 gets
; set at the interval we require ( 69.4ms )
; Sample timer calcs:
; XTAL_FREQ = 12mhz => .0000833 milliseconds period
; basic flash freq = 14.4hz => 69.4ms period
; .0000833ms * 4 * 8 = .0026656ms for 1 count of timer1 when using
; fosc/4 and prescaler of 8.
; we want a period of 69.4ms (72 flashes/min and 12 subsamples/flash)
; so the divider gets set to 69.4/.0026656 = 26035
; ---------------------------------------------------------------------
;
init_timer1
	; shut off the timer
	bcf		T1CON,TMR1ON

	; load the divider registers (clears prescaler counter)
	; divider calcs... scaled to use integer math.
	; to be totally correct, the preset value should be reduced
	; by the time it takes to call this routine and get the timer
	; restarted. In a polled environment detecting the TMR1IF is
	; going to vary, so the actual time interval will wander slightly.
base equ (XTAL_FREQ/4/8)
divi equ (10 * base/144)
divh equ (65536 - divi) >> 8
divl equ (65536 - divi) & 0x00ff
	movlw	divh
	movwf	TMR1H
	movlw	divl
	movwf	TMR1L

	; clr the interrupt flag
	bcf		PIR1,TMR1IF

;	see page 50 of data sheet for definition of T1CON
;	set timer 1 prescaler to /8
;	set timer 1 osc enable to off
;	dont care on sync bit
;	set timer 1 to use fosc/4 as input
;	enable timer 1
	movlw	(1<<T1CKPS1) + (1<<T1CKPS0) + (1<<TMR1ON)
	movwf	T1CON
	return

;
; ---------------------------------------------------------------------
; SR_24OUT
; updates shift registers from memory variables sr_hi,sr_mid,sr_lo
; this routine takes about 100us on a 11mhz xtal
; ---------------------------------------------------------------------
;
sr_24out
	
	movf	sr_hi,w		; high 8 bits of 24
	movwf	sr_sr		; save copy in shift register	
	call	sr_8out		; send 8 MSB starting with MS bit

	movf	sr_mid,w	; middle 8 bits of 24
	movwf	sr_sr		; save copy in shift register
	call	sr_8out		; send 8 more bits starting with MS bit
	
	movf	sr_lo,w		; low 8 bits of 24
	movwf	sr_sr		; save copy in shift register
	call	sr_8out		; send 8 more bits starting with MS bit

	; move all 24 bits to output device latches
	bsf 	PORTA,SR_STB	; output latch strobe hi
	nop
	bcf 	PORTA,SR_STB	; output latch strobe low
	return

;
; ---------------------------------------------------------------------
; sr_8out
; send 8 bits (sr_sr variable) out to output shift registers
; uses sr_tmp as a loop counter
; ---------------------------------------------------------------------
;
sr_8out
	movlw 	d'8'		; 8 hi bits to shift out
	movwf 	sr_tmp

sr_001
	bcf	PORTA,SR_DAT	; start with bit low
	rlf 	sr_sr,f		; rotate bits through c
	btfsc	STATUS,C
	bsf	PORTA,SR_DAT	; flip data if needed
	nop

	bsf	PORTA,SR_CLK	; strobe active rising edge
	nop
	bcf	PORTA,SR_CLK

	decfsz	sr_tmp,f
	goto	sr_001		; loop for rest of bits in byte	
	return

; put tables in top half of program space
; at a fixed location so they dont move around as we add code
	org H'0200'
; ---------------------------------------------------------------------
; below is a collection of sub routines that when called
; will return a light pattern in the w register. You can
; add to the patterns by defining more subroutines. The basic
; pattern is defined in 36 clock intervals.
; IMPORTANT: These routines cannot cross a page boundary!
; ---------------------------------------------------------------------
;alternating (fine pattern)
alt
	movlw	HIGH alt
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'

	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'

	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'

	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'

	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'
	retlw	B'00101010'

	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
	retlw	B'00010101'
altend
	if ((alt & 0xff00 ) != (altend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( altend - alt)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
; comet alternating
comet_alt
	movlw	HIGH comet_alt
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00101010'
	retlw	B'00000000'
	retlw	B'00101010'
	retlw	B'00000000'
	retlw	B'00101010'
	retlw	B'00000000'

	retlw	B'00010101'
	retlw	B'00000000'
	retlw	B'00010101'
	retlw	B'00000000'
	retlw	B'00010101'
	retlw	B'00000000'

	retlw	B'00101010'
	retlw	B'00000000'
	retlw	B'00101010'
	retlw	B'00000000'
	retlw	B'00101010'
	retlw	B'00000000'

	retlw	B'00010101'
	retlw	B'00000000'
	retlw	B'00010101'
	retlw	B'00000000'
	retlw	B'00010101'
	retlw	B'00000000'

	retlw	B'00101010'
	retlw	B'00000000'
	retlw	B'00101010'
	retlw	B'00000000'
	retlw	B'00101010'
	retlw	B'00000000'

	retlw	B'00010101'
	retlw	B'00000000'
	retlw	B'00010101'
	retlw	B'00000000'
	retlw	B'00010101'
	retlw	B'00000000'
cometaltend
	if ((comet_alt & 0xff00 ) != (cometaltend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( cometaltend - comet_alt)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
; normal wigwag
wigwag
	movlw	HIGH wigwag
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'

	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'

	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'

	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'

	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'

	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
	retlw	B'00000111'
wigwagend
	if ((wigwag & 0xff00 ) != (wigwagend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( wigwagend - wigwag)!= 40)
		error "Table must have 36 states - please checkit!"
	endif


;----------------------------------------------------------------------
; comet wig wag
cometww
	movlw	HIGH cometww
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00111000'
	retlw	B'00000000'
	retlw	B'00111000'
	retlw	B'00000000'
	retlw	B'00111000'
	retlw	B'00000000'

	retlw	B'00000111'
	retlw	B'00000000'
	retlw	B'00000111'
	retlw	B'00000000'
	retlw	B'00000111'
	retlw	B'00000000'

	retlw	B'00111000'
	retlw	B'00000000'
	retlw	B'00111000'
	retlw	B'00000000'
	retlw	B'00111000'
	retlw	B'00000000'

	retlw	B'00000111'
	retlw	B'00000000'
	retlw	B'00000111'
	retlw	B'00000000'
	retlw	B'00000111'
	retlw	B'00000000'

	retlw	B'00111000'
	retlw	B'00000000'
	retlw	B'00111000'
	retlw	B'00000000'
	retlw	B'00111000'
	retlw	B'00000000'

	retlw	B'00000111'
	retlw	B'00000000'
	retlw	B'00000111'
	retlw	B'00000000'
	retlw	B'00000111'
	retlw	B'00000000'
cometwwend
	if ((cometww & 0xff00 ) != (cometwwend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( cometwwend - cometww)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
; center steady wig wag
centersww
	movlw	HIGH centersww
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'

	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'

	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'

	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'

	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'

	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
	retlw	B'00001111'
centerswwend
	if ((centersww & 0xff00 ) != (centerswwend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( centerswwend - centersww)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
; center steady comet wig wag
cscww
	movlw	HIGH cscww
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00111100'
	retlw	B'00001100'
	retlw	B'00111100'
	retlw	B'00001100'
	retlw	B'00111100'
	retlw	B'00001100'

	retlw	B'00001111'
	retlw	B'00001100'
	retlw	B'00001111'
	retlw	B'00001100'
	retlw	B'00001111'
	retlw	B'00001100'

	retlw	B'00111100'
	retlw	B'00001100'
	retlw	B'00111100'
	retlw	B'00001100'
	retlw	B'00111100'
	retlw	B'00001100'

	retlw	B'00001111'
	retlw	B'00001100'
	retlw	B'00001111'
	retlw	B'00001100'
	retlw	B'00001111'
	retlw	B'00001100'

	retlw	B'00111100'
	retlw	B'00001100'
	retlw	B'00111100'
	retlw	B'00001100'
	retlw	B'00111100'
	retlw	B'00001100'

	retlw	B'00001111'
	retlw	B'00001100'
	retlw	B'00001111'
	retlw	B'00001100'
	retlw	B'00001111'
	retlw	B'00001100'
cscwwend
	if ((cscww & 0xff00 ) != (cscwwend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( cscwwend - cscww)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;	force table up to next page so it doesnt cross 256 byte boundaries
	org H'0300'
;----------------------------------------------------------------------
; scan right
scanr
	movlw	HIGH scanr
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'

	retlw	B'00100000'
	retlw	B'00100000'
	retlw	B'00100000'
	retlw	B'00100000'
	retlw	B'00100000'
	
	retlw	B'00110000'
	retlw	B'00110000'
	retlw	B'00110000'
	retlw	B'00110000'
	retlw	B'00110000'

	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'
	retlw	B'00111000'

	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'
	retlw	B'00111100'


	retlw	B'00111110'	
	retlw	B'00111110'
	retlw	B'00111110'
	retlw	B'00111110'
	retlw	B'00111110'


	retlw	B'00111111'
	retlw	B'00111100'
	retlw	B'00111111'
	retlw	B'00111100'
	retlw	B'00111111'
	retlw	B'00111100'
scanrend
	if ((scanr & 0xff00 ) != (scanrend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( scanrend - scanr)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
; scan left
scanl
	movlw	HIGH scanl
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'

	retlw	B'00000001'
	retlw	B'00000001'
	retlw	B'00000001'
	retlw	B'00000001'
	retlw	B'00000001'

	retlw	B'00000011'
	retlw	B'00000011'
	retlw	B'00000011'
	retlw	B'00000011'
	retlw	B'00000011'

	retlw	B'00000111'	
	retlw	B'00000111'	
	retlw	B'00000111'	
	retlw	B'00000111'	
	retlw	B'00000111'	

	retlw	B'00001111'	
	retlw	B'00001111'	
	retlw	B'00001111'	
	retlw	B'00001111'	
	retlw	B'00001111'	

	retlw	B'00011111'	
	retlw	B'00011111'	
	retlw	B'00011111'	
	retlw	B'00011111'	
	retlw	B'00011111'	

	retlw	B'00111111'	
	retlw	B'00001111'	
	retlw	B'00111111'	
	retlw	B'00001111'	
	retlw	B'00111111'	
	retlw	B'00001111'	
scanlend
	if ((scanl & 0xff00 ) != (scanlend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( scanlend - scanl)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
;scan split
scansplit
	movlw	HIGH scansplit
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'

	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00001100'

	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00011110'
	retlw	B'00011110'
	retlw	B'00011110'
	retlw	B'00011110'

	retlw	B'00011110'
	retlw	B'00011110'
	retlw	B'00011110'
	retlw	B'00011110'
	retlw	B'00111111'
	retlw	B'00111111'

	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'

	retlw	B'00111111'
	retlw	B'00011110'
	retlw	B'00111111'
	retlw	B'00011110'
	retlw	B'00111111'
	retlw	B'00011110'
scansplitend
	if ((scansplit & 0xff00 ) != (scansplitend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( scansplitend - scansplit)!= 40)
		error "Table must have 36 states - please checkit!"
	endif


;----------------------------------------------------------------------
; flash
flash
	movlw	HIGH flash
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'

	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'

	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'

	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
	retlw	B'00000000'
flashend
	if ((flash & 0xff00 ) != (flashend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( flashend - flash)!= 40)
		error "Table must have 36 states - please checkit!"
	endif

;----------------------------------------------------------------------
; cometflash
; high duty cycle comet/steady on combo dreamed up by the author
cometflash
	movlw	HIGH cometflash
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00111111'
	retlw	B'00000000'
	retlw	B'00111111'
	retlw	B'00000000'
	retlw	B'00111111'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00000000'
	retlw	B'00111111'
	retlw	B'00000000'
	retlw	B'00111111'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00000000'
	retlw	B'00111111'
	retlw	B'00000000'
	retlw	B'00111111'
	retlw	B'00000000'

	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00111111'
	retlw	B'00000000'


cometflashend
	if ((cometflash & 0xff00 ) != (cometflashend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( cometflashend - cometflash)!= 40)
		error "Table must have 36 states - please checkit!"
	endif


;----------------------------------------------------------------------
; night rider
nrider
	movlw	HIGH nrider
	movwf	PCLATH
	movf	cycle,w		;0..35
	addwf	PCL,F		;jump into state table
	retlw	B'00000001'	;0
	retlw	B'00000001'
	retlw	B'00000001'
	retlw	B'00000011'
	retlw	B'00000011'
	retlw	B'00000011'

	retlw	B'00000110'	;6
	retlw	B'00000110'
	retlw	B'00000110'
	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00001100'

	retlw	B'00011000'	;12
	retlw	B'00011000'
	retlw	B'00011000'
	retlw	B'00110000'
	retlw	B'00110000'
	retlw	B'00110000'

	retlw	B'00100000'	;18
	retlw	B'00100000'
	retlw	B'00100000'
	retlw	B'00110000'
	retlw	B'00110000'
	retlw	B'00110000'

	retlw	B'00011000'	;24
	retlw	B'00011000'
	retlw	B'00011000'
	retlw	B'00001100'
	retlw	B'00001100'
	retlw	B'00001100'

	retlw	B'00000110'	;30
	retlw	B'00000110'
	retlw	B'00000110'
	retlw	B'00000011'
	retlw	B'00000011'
	retlw	B'00000011'

nriderend
	if ((nrider & 0xff00 ) != (nriderend & 0xff00))
		error "Table must not cross page boundary - please movit!"
	endif
	if (( nriderend - nrider)!= 40)
		error "Table must have 36 states - please checkit!"
	endif


	END                 ; directive 'end of program'



