;file vplib.src

;uncomment following 3 lines if SX48/52
;DEV_48
;device			SX48,oschs1
;id			'DEV_SX48'

;uncomment following 3 lines if SX28
DEV_28
device			SX28,oschs1,turbo,stackx,optionx
id			'DEV_SX28'

;uncomment following 3 lines if SX18
;DEV_18
;device			SX18,oschs1,turbo,stackx,optionx
;id			'DEV_SX18'

irc_cal			IRC_SLOW
reset			reset_entry
freq			20_000_000
RESONATOR		equ	20	; set to freq/1_000_000

; application start up register values, set as needed

RA_latch	equ	%00000101	;port A output latch init 1=high 0=low
RA_tris		equ	%11111010	;port A direction register 1=input 0=output
RA_plp		equ	%00000000	;port A pull up register 1=off 0=on
RA_lvl		equ	%11111111	;port A level register 1=ttl 0=cmos

RB_latch	equ	%00000000	;port B output latch 1=high 0=low
RB_tris		equ	%11111111	;port B direction register 1=input 0=output
RB_plp		equ	%00000000	;port B pull up register 1=off 0=on
RB_lvl		equ	%00000000	;port B level register 1=ttl 0=cmos
RB_st		equ	%11111111	;port B schmitt trigger register 1=off 0=on
RB_wken		equ	%11111111	;port B wake up enable register 1=off 0=on
RB_wked		equ	%11111111	;port B wake up edge register 1=neg 0=pos
RB_wkpnd	equ	%00000000	;port B MIWI pending register 1=detected 0=not detected
RB_cmp		equ	%11111111	;port B comparator enable register 1=disabled 0=enabled

ifndef DEV_18
RC_latch	equ	%00000000	;port C output latch 1=high 0=low
RC_tris		equ	%11111111	;port C direction register 1=input 0=output
RC_plp		equ	%00000000	;port C pull up register 1=off 0=on
RC_lvl		equ	%11111111	;port C level register 1=ttl 0=cmos
RC_st		equ	%11111111	;port C schmitt trigger register 1=off 0=on
endif

;ifdef DEV_48
RD_latch	equ	%00000000	;port D output latch 1=high 0=low
RD_tris		equ	%11111111	;port D direction register 1=input 0=output
RD_plp		equ	%11111111	;port D pull up register 1=off 0=on
RD_lvl		equ	%11111111	;port D level register 1=ttl 0=cmos
RD_st		equ	%11111111	;port D schmitt trigger register 1=off 0=on

RE_latch	equ	%00000000	;port E output latch 1=high 0=low
RE_tris		equ	%11111111	;port E direction register 1=input 0=output
RE_plp		equ	%11111111	;port E pull up register 1=off 0=on
RE_lvl		equ	%11111111	;port E level register 1=ttl 0=cmos
RE_st		equ	%11111111	;port E schmitt trigger register 1=off 0=on
;endif

PORTPIN_RA0	equ	0x50
PORTPIN_RA1	equ	0x51
PORTPIN_RA2	equ	0x52
PORTPIN_RA3	equ	0x53

PORTPIN_RB0	equ	0x60
PORTPIN_RB1	equ	0x61
PORTPIN_RB2	equ	0x62
PORTPIN_RB3	equ	0x63
PORTPIN_RB4	equ	0x64
PORTPIN_RB5	equ	0x65
PORTPIN_RB6	equ	0x66
PORTPIN_RB7	equ	0x67

ifndef DEV_18
PORTPIN_RC0	equ	0x70
PORTPIN_RC1	equ	0x71
PORTPIN_RC2	equ	0x72
PORTPIN_RC3	equ	0x73
PORTPIN_RC4	equ	0x74
PORTPIN_RC5	equ	0x75
PORTPIN_RC6	equ	0x76
PORTPIN_RC7	equ	0x77
endif

ifdef DEV_48
PORTPIN_RD0	equ	0x80
PORTPIN_RD1	equ	0x81
PORTPIN_RD2	equ	0x82
PORTPIN_RD3	equ	0x83
PORTPIN_RD4	equ	0x84
PORTPIN_RD5	equ	0x85
PORTPIN_RD6	equ	0x86
PORTPIN_RD7	equ	0x87

PORTPIN_RE0	equ	0x90
PORTPIN_RE1	equ	0x91
PORTPIN_RE2	equ	0x92
PORTPIN_RE3	equ	0x93
PORTPIN_RE4	equ	0x94
PORTPIN_RE5	equ	0x95
PORTPIN_RE6	equ	0x96
PORTPIN_RE7	equ	0x97
endif

ifdef DEV_18
global_org	equ	$07
endif
ifdef DEV_28
global_org	equ	$08
endif
ifdef DEV_48
global_org	equ	$0A
endif

ifdef DEV_48
bank0_org	equ	$00
bank1_org	equ	$10
bank2_org	equ	$20
bank3_org	equ	$30
bank4_org	equ	$40
bank5_org	equ	$50
bank6_org	equ	$60
bank7_org	equ	$70
bank8_org	equ	$80
bank9_org	equ	$90
bankA_org	equ	$A0
bankB_org	equ	$B0
bankC_org	equ	$C0
bankD_org	equ	$D0
bankE_org	equ	$E0
bankF_org	equ	$F0
else
bank0_org	equ	$10
bank1_org	equ	$30
bank2_org	equ	$50
bank3_org	equ	$70
bank4_org	equ	$90
bank5_org	equ	$B0
bank6_org	equ	$D0
bank7_org	equ	$F0
endif

page0_org	equ	$0
page1_org	equ	$200
page2_org	equ	$400
page3_org	equ	$600
ifdef DEV_48
page4_org	equ	$800
page5_org	equ	$A00
page6_org	equ	$C00
page7_org	equ	$E00
endif

;power up register values

RA_tris_PU	equ	%11111111	;port A direction register 1=input 0=output
RA_plp_PU	equ	%11111111	;port A pull up register 1=off 0=on
RA_lvl_PU	equ	%11111111	;port A level register 1=ttl 0=cmos

RB_tris_PU	equ	%11111111	;port B direction register 1=input 0=output
RB_plp_PU	equ	%11111111	;port B pull up register 1=off 0=on
RB_lvl_PU	equ	%11111111	;port B level register 1=ttl 0=cmos
RB_st_PU	equ	%11111111	;port B schmitt trigger register 1=off 0=on
RB_wken_PU	equ	%11111111	;port B wake up enable register 1=off 0=on
RB_wked_PU	equ	%11111111	;port B wake up edge register 1=neg 0=pos
RB_wkpnd_PU	equ	%11111111	;port B MIWI pending register 1=detected 0=not detected
RB_cmp_PU	equ	%11111111	;port B comparator enable register 1=disabled 0=enabled

ifndef DEV_18
RC_tris_PU	equ	%11111111	;port C direction register 1=input 0=output
RC_plp_PU	equ	%11111111	;port C pull up register 1=off 0=on
RC_lvl_PU	equ	%11111111	;port C level register 1=ttl 0=cmos
RC_st_PU	equ	%11111111	;port C schmitt trigger register 1=off 0=on
endif

;ifdef DEV_48
RD_tris_PU	equ	%11111111	;port D direction register 1=input 0=output
RD_plp_PU	equ	%11111111	;port D pull up register 1=off 0=on
RD_lvl_PU	equ	%11111111	;port D level register 1=ttl 0=cmos
RD_st_PU	equ	%11111111	;port D schmitt trigger register 1=off 0=on

RE_tris_PU	equ	%11111111	;port E direction register 1=input 0=output
RE_plp_PU	equ	%11111111	;port E pull up register 1=off 0=on
RE_lvl_PU	equ	%11111111	;port E level register 1=ttl 0=cmos
RE_st_PU	equ	%11111111	;port E schmitt trigger register 1=off 0=on
;endif

;-----------------------------------------------------------------------------------------
; uart constants
;-----------------------------------------------------------------------------------------

if RESONATOR == 50
;192*1200=96*2400=48*4800=24*9600=12*19200=6*38400
;uartfs=192*1200=230400
;int_period=50000000/230400=217
uartfs		equ	230400		; uart's basic frequency 192*1200 = 230400
int_period	equ	217		; used as seed for uart baud rate.
endif

if RESONATOR == 20
;96*1200=48*2400=24*4800=12*9600=6*19200
;uartfs=96*1200=115200
;int_period=20000000/115200=174
uartfs		equ	115200		; uart's basic frequency 96*1200 = 115200
int_period	equ	174		; used as seed for uart baud rate.
endif

if RESONATOR == 10
;48*1200=24*2400=12*4800=6*9600
;uartfs=48*1200=57600
;int_period=10000000/57600=174
uartfs		equ	57600		; uart's basic frequency 48*1200 = 57600
int_period	equ	174		; used as seed for uart baud rate.
endif

if RESONATOR == 4
;24*1200=12*2400=6*4800
;uartfs=24*1200=28800
;int_period=4000000/28800=139
uartfs		equ	28800		; uart's basic frequency 24*1200 = 28800
int_period	equ	139		; used as seed for uart baud rate.
endif

THREADS		equ	3

mscount		equ	((2*1000*RESONATOR/int_period)+1)/2	;isr cycles for 1 msec
			;50MHz -> 230, 20MHz -> 115, 10MHz -> 57, 4MHz -> 29
uscount		equ	((2*250*RESONATOR/int_period)+1)/2	;isr cycles for 250 usec
			;50MHz -> 58, 20MHz -> 29, 10MHz -> 14, 4MHz -> 7

;The following baudrates are available

baud0		equ	1200
baud1		equ	2400
baud2		equ	4800
baud3		equ	9600
baud4		equ	19200
baud5		equ	38400
							; 50MHz  20MHz  10MHz  4MHz
divide0		equ	uartfs / (baud0 * THREADS)	;   64     32    16      8
StDelay0 	equ	divide0 + (divide0 / 2)		;   96     48    24     12
BAUD1200	equ	divide0				;load into rx_baud or tx_baud

divide1		equ	uartfs / (baud1 * THREADS)	;   32     16     8      4
StDelay1 	equ	divide1 + (divide1 / 2)		;   48     24    12      6
BAUD2400	equ	divide1				;load into rx_baud or tx_baud

divide2		equ	uartfs / (baud2 * THREADS)	;   16      8     4      2
StDelay2 	equ	divide2 + (divide2 / 2)		;   24     12     6      3
BAUD4800	equ	divide2				;load into rx_baud or tx_baud

divide3		equ	uartfs / (baud3 * THREADS)	;    8      4     2      -
StDelay3 	equ	divide3 + (divide3 / 2)		;   12      6     3      -
BAUD9600	equ	divide3				;load into rx_baud or tx_baud

divide4		equ	uartfs / (baud4 * THREADS)	;    4      2     -      -
StDelay4 	equ	divide4 + (divide4 / 2)		;    6      3     -      -
BAUD19200	equ	divide4				;load into rx_baud or tx_baud

divide5		equ	uartfs / (baud5 * THREADS)	;    2      -     -      -
StDelay5 	equ	divide5 + (divide5 / 2)		;    3      -     -      -
BAUD38400	equ	divide5				;load into rx_baud or tx_baud

;serial data formats
E71		equ	%00001110	; even parity, 7 databits, 1 stopbit , 1 startbit, 10 bits total
E72		equ	%00001111	; even parity, 7 databits, 2 stopbit , 1 startbit, 11 bits total
E81		equ	%00001011	; even parity, 8 databits, 1 stopbit , 1 startbit, 11 bits total
O71		equ	%00010110	; odd  parity, 7 databits, 1 stopbit , 1 startbit, 10 bits total
O72		equ	%00010111	; odd  parity, 7 databits, 2 stopbit , 1 startbit, 11 bits total
O81		equ	%00010011	; odd  parity, 8 databits, 1 stopbit , 1 startbit, 11 bits total
N71		equ	%00000101	; no   parity, 7 databits, 1 stopbit , 1 startbit,  9 bits total 
N72		equ	%00000110	; no   parity, 7 databits, 2 stopbit , 1 startbit, 10 bits total 
N81		equ	%00000010	; no   parity, 8 databits, 1 stopbit , 1 startbit, 10 bits total
N82		equ	%00000011	; no   parity, 8 databits, 2 stopbit , 1 startbit, 11 bits total
UART_ENABLE	equ	%01000000	; load [UART_ENABLE] + dataformat value into rx_format or tx_format

M_CMP			equ	$08		;values for mode register
M_WKPND			equ	$09
M_WKED			equ	$0A
M_WKEN			equ	$0B
M_ST			equ	$0C
M_LVL			equ	$0D
M_PLP			equ	$0E
M_TRIS			equ	$0F

			; option register constants
RTCC_ON			equ	%10000000	;Enables RTCC at address $01 (RTW hi)
						;*WREG at address $01 (RTW lo) by default
RTCC_ID			equ	%01000000	;Disables RTCC edge interrupt (RTE_IE hi)
						;*RTCC edge interrupt (RTE_IE lo) enabled by default
RTCC_INC_EXT		equ	%00100000	;Sets RTCC increment on RTCC pin transition (RTS hi)
						;*RTCC increment on internal instruction (RTS lo) is defalut
RTCC_FE			equ	%00010000	;Sets RTCC to increment on falling edge (RTE_ES hi)
						;*RTCC to increment on rising edge (RTE_ES lo) is default
RTCC_PS_ON		equ	%00000000	;Assigns prescaler to RTCC (PSA lo)
RTCC_PS_OFF		equ	%00001000	;Assigns prescaler to WDT (PSA hi)
RTCC_PS_000		equ	%00000000	;RTCC = 1:2, WDT = 1:1
RTCC_PS_001		equ	%00000001	;RTCC = 1:4, WDT = 1:2
RTCC_PS_010		equ	%00000010	;RTCC = 1:8, WDT = 1:4
RTCC_PS_011		equ	%00000011	;RTCC = 1:16, WDT = 1:8
RTCC_PS_100		equ	%00000100	;RTCC = 1:32, WDT = 1:16
RTCC_PS_101		equ	%00000101	;RTCC = 1:64, WDT = 1:32
RTCC_PS_110		equ	%00000110	;RTCC = 1:128, WDT = 1:64
RTCC_PS_111		equ	%00000111	;RTCC = 1:256, WDT = 1:128

;-----------------------------------------------------------------------------------------

			; secret instruction fifo
fifo			macro
			dw	$47
endm

			; secret instruction pushW
pushW			macro
			dw	$48
endm

			; secret instruction pushST
pushST			macro
			dw	$49
endm

			; secret instruction pushFSR
pushFSR			macro
			dw	$4A
endm

			; secret instruction pushPC
pushPC			macro
			dw	$4B
endm

			; secret instruction popW
popW			macro
			dw	$4C
endm

			; secret instruction popST
popST			macro
			dw	$4D
endm

			; secret instruction popFSR
popFSR			macro
			dw	$4E
endm

			; secret instruction popPC
popPC			macro
			dw	$4F
endm

;-----------------------------------------------------------------------------------------

i2cs_var		macro	prefix, isr
prefix??_??state	ds	1	; This indicates the state that the I2C slave is currently in.
prefix??_??sub_state	ds	1	; This indicates the substate that the I2C slave is currently in.
prefix??_??bit_count	ds	1	; Indicates the number of bits left to process in read/write
prefix??_??byte		ds	1	; value, The byte currently being written/read by the I2C slave
prefix??_??past_pres	ds	1	; The last_state of the I2C port (to be compared with the present state)
  prefix??_??pres_sda	equ	prefix??_??past_pres.0 ; The present state of the SDA line
  prefix??_??pres_scl	equ	prefix??_??past_pres.1 ; The present state of the SCL line
  prefix??_??past_sda	equ	prefix??_??past_pres.2 ; The state of the SDA line on last interrupt
  prefix??_??past_scl	equ	prefix??_??past_pres.3 ; The state of the SCL line on last interrupt
prefix??_??flags	ds	1	; i2c flags
  prefix??_??sda_buf	equ	prefix??_??flags.0 ; current direction for sda pin
  prefix??_??scl_buf	equ	prefix??_??flags.1 ; current direction for scl pin
  prefix??_??stop_found	equ	prefix??_??flags.2	; set by stop and cleared by start condition
  prefix??_??rx_flag	equ	prefix??_??flags.3	; set when this slave has received data
  prefix??_??broadcast	equ	prefix??_??flags.4	; set when this slave is addressed by broadcast id
  prefix??_??written_again	equ	prefix??_??flags.5	; set when this slave receives 2nd or later databyte
  prefix??_??data_needed	equ	prefix??_??flags.6	; set when this slave requires data
prefix??_??sdapin	ds	1	;pin SDA
prefix??_??sclpin	ds	1	;pin SCL
endm

lib_i2cs = 0

i2c_slave		macro	nr, prefix
SLAVE_STATIC_ID		equ	$30
			org	data
lib_i2cs_state		=	$+0	; This indicates the state that the I2C slave is currently in.
lib_i2cs_sub_state	=	$+1	; This indicates the substate that the I2C slave is currently in.
lib_i2cs_bit_count	=	$+2	; Indicates the number of bits left to process in read/write
lib_i2cs_byte		=	$+3	; The byte currently being written/read by the I2C slave
lib_i2cs_past_pres	=	$+4	; The last_state of the I2C port (to be compared with the present state)
  lib_i2cs_pres_sda	=	lib_i2cs_past_pres.0 ; The present state of the SDA line
  lib_i2cs_pres_scl	=	lib_i2cs_past_pres.1 ; The present state of the SCL line
  lib_i2cs_past_sda	=	lib_i2cs_past_pres.2 ; The state of the SDA line on last interrupt
  lib_i2cs_past_scl	=	lib_i2cs_past_pres.3 ; The state of the SCL line on last interrupt
lib_i2cs_flags		=	$+5	; i2c flags
  lib_i2cs_sda_buf	=	lib_i2cs_flags.0 ; current direction for sda pin
  lib_i2cs_scl_buf	=	lib_i2cs_flags.1 ; current direction for scl pin
  lib_i2cs_stop_found	=	lib_i2cs_flags.2	; set by stop and cleared by start condition
  lib_i2cs_rx_flag	=	lib_i2cs_flags.3	; set when this slave has received data
  lib_i2cs_broadcast	=	lib_i2cs_flags.4	; set when this slave is addressed by broadcast id
  lib_i2cs_written_again	=	lib_i2cs_flags.5	; set when this slave receives 2nd or later databyte
  lib_i2cs_data_needed	=	lib_i2cs_flags.6	; set when this slave requires data
lib_i2cs_sdapin		=	$+6	;pin SDA
lib_i2cs_sclpin		=	$+7	;pin SCL
vp??nr??_bank		equ	($ & $F8)|nr
i2cs_var prefix,nr
data			=	$
if lib_i2cs == 0
lib_i2cs = 1
			org	code
;-----------------------------------------------------------------------------------------
; I2C Slave Interrupt Service Routines
;-----------------------------------------------------------------------------------------

	; Function: i2cs_get_start_stop
	; This subroutine checks the i2cs_past_pres register for the presence of a start
	; or stop condition.  It takes the values present in the i2cs_past_pres register
	; and checks them against what would be in the register if a start or stop condition
	; had occured.  This subroutine should be called on every pass of the ISR, because
	; it runs independantly to the rest of the slave code and re-initializes the state
	; machine, regardless of its last state, on the receipt of these conditions.
	;---------------------------------------------------------------------------------
i2cs_get_start_stop
		mov	w,lib_i2cs_past_pres	;1
		and	w,#$0f			;1
		xor	w,#%00001110		;1 ;Compare with a start condition.
		snz				;1
		jmp	:start			;3
		xor	w,#%00000101		;1 ;Compare XOR of start and stop with
		sz				;1 ;what would be present if a stop was present.
		retp				;3 = 9

:stop		clr	lib_i2cs_state		;1 ;If stop, then make the I2C slave idle
		clr	lib_i2cs_sub_state		;1
		setb	lib_i2cs_stop_found		;1
		retp				;3 = 12

:start		mov	w,#1			;1 ;If start, then start receiving the address.
		mov	lib_i2cs_state,w		;1
		clr	lib_i2cs_sub_state
		clrb	lib_i2cs_stop_found
		clrb	lib_i2cs_written_again
		retp				;3 = 12

	; Function: i2cs_isr
	; I2C Slave Interrupt-Driven State Machine
	;
	;	This is the main interrupt service routine for the I2C slave interrupt
	;	service routine.  It is a state machine, allowing semi-straightline 
	;	code to operate on successive calls.  The current state of this state
	;	machine is stored in the registers i2cs_state and i2cs_sub_state.  These
	;	are the discrete states of this state machine...
	;
	;  i2cs_idle
	;	i2cs_idle is the state used when no start condition has occurred
	;	and the device has not been addressed.  The I2C slave will sit in this
	;	state until the state is changed by the independant subroutine 
	;	i2cs_get_start_stop.  
	;
	;  i2cs_wait_for_scl_low
	;	This state simply waits until SCL goes low.  It is entered once
	;	i2cs_get_start_stop encounters a start condition.  Once SCL goes low,
	;	the state is incremented
	;
	;  i2cs_get_id
	;	This state prepares the i2cs_read_byte routine to get 8-bits of data. 
	;	It increments the state to i2cs_read_byte before exiting.
	;
	;  i2cs_read_byte
	;	This state reads a byte of data.  i2cs_bit_count needs to be loaded with
	;	#8 before entering this state, or it won't know to increment to the next
	;	state after 8 bits of data have been loaded.
	;
	;  i2cs_process_id
	;	This state simply performs a quick calculation to figure out if this slave
	;	was just addressed.  If it was not, then it changes the state back to 
	;	i2cs_idle.  If this slave was addressed, then this state prepares to either
	;	read data or write data, depending on the bit 1 of the first byte received.
	;
	;  i2cs_send_ack
	;	This state outputs an ACK pulse, to tell the master that data was received
	;	correctly.  It pulls SDA low while SCL is pulsed high and low by the master.
	;
	;  i2cs_waiting_for_data
	;	This state waits for data to be put in i2cs_byte.
	;
	;  i2cs_send_data
	;	This state prepares the i2cs_write_byte state to send the 8-bits of data
	;	in the i2cs_data_out register.
	;
	;  i2cs_write_byte
	;	This state outputs a byte of data, clocked out by the SCL pin.  It must be
	;	pre-prepared to send out a byte by having the i2cs_byte register loaded with
	;	valid data and having the i2cs_bit_count register loaded with #8.
	;
	;  i2cs_get_ack
	;	This state gets an ACK from the I2C master.  If an ACK is received, this state
	;	will return to waiting_for_data. If no ACK is received, the slave will be put
	;	back into its idle state.
	;
	;  i2cs_read_data
	;	This state prepares i2cs_read_byte to receive 8 bits of data.  It increments
	;	the state before exiting.
	;
	;  i2cs_read_again
	;	This state waits for more data to receive.
	;
	;  i2cs_process_data
	;	This state processes a byte of data which was just received.
	;	It sets the i2cs_rx_flag to indicate that a byte of data was received by the slave.
	;
	;---------------------------------------------------------------------------------
i2cs_isr
		mov	w,lib_i2cs_state	;1 
		add	PC,w		;3 ;Add the state to the program counter
					   ;and go to the state in the jump table.

		; States for I2C slave while idle
		;-------------------------------------------------------------------------
	i2cs_idle_loc		=	$
		jmp	i2cs_idle		;3 ;If I2C_state = 0, I2C is idle
		jmp	i2cs_wait_for_scl_low	;3 ;Wait for SCL line to go low after start condition
		jmp	i2cs_get_id		;3 ;Get the id
		jmp	i2cs_read_byte		;3 
		jmp	i2cs_process_id		;3 ;Check to see if this device was addressed, and set
						   ;up for read or write if it was.

		; States for I2C slave being read
		;-------------------------------------------------------------------------
	i2cs_being_read		=	$	; Go to this state if the slave is being read.
		jmp	i2cs_send_ack		;3 
	i2cs_being_read_again	=	$
		jmp	i2cs_request_for_data	;3 ;tell mainline code to supply data.
		jmp	i2cs_waiting_for_data	;3 ;wait for data.
		jmp	i2cs_send_data		;3 ;Set up to send out a byte.
		jmp	i2cs_write_byte		;3 ;Send the byte, clocked by SCL
		jmp	i2cs_get_ack		;3 ;If we receive an ACK, then we are being read again.
	
		; States for I2C slave being written
		;-------------------------------------------------------------------------
	i2cs_being_written	=	$	; Go to this state if the slave is being written
		jmp	i2cs_send_ack		;3 ;Send an ACK
	i2cs_being_written_again	=	$
		jmp	i2cs_read_data		;3 
		jmp	i2cs_read_byte		;3 
		jmp	i2cs_process_data	;3 
		jmp	i2cs_send_ack		;3 
		jmp	i2cs_read_again

	; State: i2cs_idle
	;	i2cs_idle is the state used when no start condition has occurred
	;	and the device has not been addressed.  The I2C slave will sit in this
	;	state until the state is changed by the independant subroutine 
	;	i2cs_get_start_stop.  
	;---------------------------------------------------------------------------------
i2cs_idle	setb	lib_i2cs_scl_buf	;1
		setb	lib_i2cs_sda_buf	;1
		retp				;3 = 5 + 7 = 12

	; State: i2cs_wait_for_scl_low
	;	This state simply waits until SCL goes low.  It is entered once
	;	i2cs_get_start_stop encounters a start condition.  Once SCL goes low,
	;	the state is incremented
	;---------------------------------------------------------------------------------
i2cs_wait_for_scl_low
		snb	lib_i2cs_pres_scl		;1
		retp				;3 = 4 + 7 = 11
		clrb	lib_i2cs_scl_buf	;1
		inc	lib_i2cs_state		;1
		retp				;3 = 6 + 7 = 13

	; State: i2cs_get_id
	;	This state prepares the i2cs_read_byte routine to get 8-bits of data. 
	;	It increments the state to i2cs_read_byte before exiting.
	;---------------------------------------------------------------------------------
i2cs_get_id
		mov	w,#8			;1
		mov	lib_i2cs_bit_count,w	;1
		inc	lib_i2cs_state		;1
		retp				;3 = 6 + 7 = 13

	; State: i2cs_read_byte
	;	This state reads a byte of data.  i2cs_bit_count needs to be loaded with
	;	#8 before entering this state, or it won't know to increment to the next
	;	state after 8 bits of data have been loaded.
	;---------------------------------------------------------------------------------
i2cs_read_byte
		mov	w,lib_i2cs_sub_state	;1
		add	PC,w			;3
		skip	; goto state1		;1
		jmp	:state2			;3

:state1						; wait until SCL goes high
		setb	lib_i2cs_scl_buf	;1
		sb	lib_i2cs_pres_scl		;1
		retp				;3 = 10 + 7 = 17		
		inc	lib_i2cs_sub_state		;1 ;If SCL is high, rotate in the bit
		clc				;1
		snb	lib_i2cs_pres_sda		;1
		stc				;1
		rl	lib_i2cs_byte		;1
		retp				;3 = 15/17 + 7 = 22/24
:state2						; wait until SCL goes low
		snb	lib_i2cs_pres_scl		;1
		retp				;3 = 11 + 7 = 18
		clrb	lib_i2cs_scl_buf	;1
		clr	lib_i2cs_sub_state		;1
		dec	lib_i2cs_bit_count		;1
		sz				;1
		retp				;3 = 15 + 7 = 22
		inc	lib_i2cs_state		;1
		retp				;3 = 16 + 7 = 23
						; Stay in this i2cs_state until all 8 bits
						; are received	

	; State: i2cs_process_id
	;	This state simply performs a quick calculation to figure out if this slave
	;	was just addressed.  If it was not, then it changes the state back to 
	;	i2cs_idle.  If this slave was addressed, then this state prepares to either
	;	read data or write data, depending on the bit 1 of the first byte received.
	;---------------------------------------------------------------------------------
i2cs_process_id
		mov	w,lib_i2cs_byte		;1 ;Get the received I2C byte
		xor	w,#SLAVE_STATIC_ID	;1 ;Compare with the id of this slave
		and	w,#$FE			;1 ;And out the R/!W bit
		clrb	lib_i2cs_broadcast
		jz	:slave_addressed
  IFDEF I2C_BROADCAST
		mov	w,#BROADCAST_ID		;compare broadcast id
		xor	w,lib_i2cs_byte
		and	w,#$FE
		setb	lib_i2cs_broadcast		;identify broadcast
		jz	:slave_addressed
		clrb	lib_i2cs_broadcast
  ENDIF
:broadcast_read					;if addressed for read using broadcast id or
		clr	lib_i2cs_state		;1 if the device was not addressed, then
		clr	lib_i2cs_sub_state		;1 go back to the idle state
		retp				;3 = 12 + 7 = 19
:slave_addressed
		clrb	lib_i2cs_scl_buf	;1	
						; If bit zero of the incoming byte is a 0,
		snb	lib_i2cs_byte.0		;1 ;then go to the being written state, otherwise
		jmp	:being_read		;3 ;go to the being read state
		mov	w,#(i2cs_being_written-i2cs_idle_loc) ;1
		mov	lib_i2cs_state,w		;1
		retp				;3 = 14 + 7 = 21
:being_read
		jb	lib_i2cs_broadcast,:broadcast_read
		mov	w,#(i2cs_being_read-i2cs_idle_loc);1
		mov	lib_i2cs_state,w		;1
		retp				;3 = 18 + 7 = 25

	; State: i2cs_send_ack
	;	This state outputs an ACK pulse, to tell the master that data was received
	;	correctly.  It pulls SDA low while SCL is pulsed high and low by the master.
	;---------------------------------------------------------------------------------
i2cs_send_ack	
		mov	w,lib_i2cs_sub_state	;1
		add	pc,w			;3
		jmp	:state1			;3
		jmp	:state2			;3
		jmp	:state3			;3

:state1
		sb	lib_i2cs_broadcast		;this IOC device does not generate an ACK for broadcast id
		clrb	lib_i2cs_sda_buf	;1 ;Clear SDA to set up ACK
		inc	lib_i2cs_sub_state		;1
		retp				;3 = 12 + 7 = 19
:state2					
		setb	lib_i2cs_scl_buf	;1 ;Allow the clock to go high
		sb	lib_i2cs_pres_scl		;1 ;Check to see if the clock is high.
		retp				;3 = 12 + 7 = 19
		inc	lib_i2cs_sub_state		;1
		retp				;3 = 13 + 7 = 20
:state3
		snb	lib_i2cs_pres_scl		;1
		retp				;3 = 11 + 7 = 18
		clrb	lib_i2cs_scl_buf	;1
		setb	lib_i2cs_sda_buf	;1
		clr	lib_i2cs_sub_state		;1
		inc	lib_i2cs_state		;1
		retp				;3 = 15 + 7 = 22

	; State: i2cs_read_data
	;	This state prepares i2cs_read_byte to receive 8 bits of data.  It increments
	;	the state before exiting.
	;---------------------------------------------------------------------------------
i2cs_read_data
		mov	w,#8			;1
		mov	lib_i2cs_bit_count,w	;1
		inc	lib_i2cs_state		;1
		retp				;3 = 13 + 7 = 20

	; State: i2cs_read_again
	;	This state prepares to re-enter i2cs_read_data to receive another 8 bits of data.
	;	It stays in this state until i2cs_rx_flag is cleared.
	;---------------------------------------------------------------------------------
i2cs_read_again
		snb	lib_i2cs_rx_flag		;wait till mainline code has grabbed data
		retp
		setb	lib_i2cs_written_again	; identifies 2nd or later databyte, cleared by stop condition
		mov	w,#(i2cs_being_written_again-i2cs_idle_loc) ;1
		mov	lib_i2cs_state,w		;  ;we may receive another byte
		retp				;3 = 13 + 7 = 20

	; State: i2cs_process_data
	;	This state processes a byte of data which was just received.  It moves the 
	;	byte that was just received into the i2cs_data_in register, and sets the 
	;	i2cs_event_flag to indicate an i2cs event and sets the i2cs_rx_flag to 
	;	indicate that a byte of data was received by the slave.
	;---------------------------------------------------------------------------------
i2cs_process_data
		setb	lib_i2cs_rx_flag		;1
		inc	lib_i2cs_state		;1
		retp				;3 = 15 + 7 = 22

	; State: i2cs_send_data
	;	This state prepares the i2cs_write_byte state to send the 8-bits of data
	;	in the i2cs_data_out register.
	;---------------------------------------------------------------------------------
i2cs_send_data
		mov	w,#8			;1
		mov	lib_i2cs_bit_count,w	;1
		inc	lib_i2cs_state		;1
		clr	lib_i2cs_sub_state		;1
		retp				;3 = 17 + 7 = 24

	; State: i2cs_write_byte
	;	This state outputs a byte of data, clocked out by the SCL pin.  It must be
	;	pre-prepared to send out a byte by having the i2cs_byte register loaded with
	;	valid data and having the i2cs_bit_count register loaded with #8.
	;---------------------------------------------------------------------------------
i2cs_write_byte
		mov	w,lib_i2cs_sub_state	;1
		add	pc,w			;3
		jmp	:state1			;3
		jmp	:state2			;3
		jmp	:state3			;3
:state1
		rl	lib_i2cs_byte		;1
		setb	lib_i2cs_sda_buf	;1
		sc				;1
		clrb	lib_i2cs_sda_buf	;1
		inc	lib_i2cs_sub_state		;1
		retp				;3 = 15 + 7 = 22
:state2
		setb	lib_i2cs_scl_buf	;1 ;allow scl to go high, indicating slave is
						; ready
		snb	lib_i2cs_pres_scl		;1 ;If SCL is not yet high, don't proceed to next state.
		inc	lib_i2cs_sub_state		;1
		retp				;3 = 13 + 7 = 20
:state3
		snb	lib_i2cs_pres_scl		;1
		retp				;3 = 11 + 7 = 18
		clr	lib_i2cs_sub_state		;1
		clrb	lib_i2cs_scl_buf	;1 ;Put scl low again to indicate slave is processing
		setb	lib_i2cs_sda_buf	;1 ;release sda line again
		dec	lib_i2cs_bit_count		;1
		sz				;1 ;once we've done all 8 bits, go to next state	
		retp				;3 = 16 + 7 = 23
		inc	lib_i2cs_state		;1
		retp				;3 = 17 + 7 = 24

	; State: i2cs_get_ack
	;	This state gets an ACK from the I2C master.  If an ACK is received, this state
	;	will return to send more data.  If no ACK is received, the slave will be put back
	;	into its idle state.
	;---------------------------------------------------------------------------------
i2cs_get_ack
		mov	w,lib_i2cs_sub_state	;1
		add	pc,w			;3
		jmp	:state1			;3
		jmp	:state2			;3

:state1		setb	lib_i2cs_scl_buf	;1
		sb	lib_i2cs_pres_scl		;1
		retp				;3 = 12 + 7 = 19
		snb	lib_i2cs_pres_sda		;1
		jmp	:NACK			;3 = 13 + 7 = 20
		inc	lib_i2cs_sub_state		;1
		retp				;3 = 14 + 7 = 21

:NACK		clr	lib_i2cs_sub_state		;1
		clr	lib_i2cs_state		;1
		retp				;3 = 18 + 7 = 25

:state2		snb	lib_i2cs_pres_scl		;1
		retp				;3 = 11 + 7 = 18
		clrb	lib_i2cs_scl_buf	;1
		clr	lib_i2cs_sub_state		;1
		mov	w,#(i2cs_being_read_again-i2cs_idle_loc);1
		mov	lib_i2cs_state,w		;1
		retp				;3 = 14 + 7 = 21

	; State: i2cs_request_for_data
	;	This state tells the mainline code to supply data in the i2cs_byte register.
	;---------------------------------------------------------------------------------
i2cs_request_for_data
		setb	lib_i2cs_data_needed	;1 mainline code must fill i2cs_byte and clear i2cs_data_needed
		inc	lib_i2cs_state
		retp				;3 = 13 + 7 = 20

	; State: i2cs_waiting_for_data
	;	This state waits for the mainline routine to put some valid data in the
	;	i2cs_byte register.  This state is only reached if the master has
	;	indicated it wants more data by sending an ACK after the last byte.
	;---------------------------------------------------------------------------------
i2cs_waiting_for_data
		snb	lib_i2cs_data_needed	;1 wait till mainline code has cleared i2cs_data_needed
		retp				;3 = 13 + 7 = 20
		inc	lib_i2cs_state
		retp
i2cs_input_task
		clrb	lib_i2cs_rx_flag			;mark byte grabbed
		mov	w,fsr			;isr_flag to use in lownib
		call	pinmask
		or	isr_flags,w		;set isr flag
		retp
i2cs_output_task
		mov	w,++fsr			;isr_flag to use in lownib
		call	pinmask
		or	isr_flags,w		;set isr flag
		retp
endif
vp??nr??_isr
	; I2C Slave Stuff...	Runs every ISR to enable high sampling rate
	;---------------------------------------------------------------------------------
slave_i2c
read_sclpin
		mov	fsr,vp_bank
		mov	w,<>lib_i2cs_sclpin
		and	w,#$0F
		mov	fsr,w
		mov	w,indf
		mov	isr_temp,w
		mov	fsr,vp_bank
		mov	w,lib_i2cs_sclpin
		call	pinmask
		and	isr_temp,w
		clc
		sz
		stc
		mov	fsr,vp_bank
		rl	lib_i2cs_past_pres
read_sdapin
		mov	w,<>lib_i2cs_sdapin
		and	w,#$0F
		mov	fsr,w
		mov	w,indf
		mov	isr_temp,w
		mov	fsr,vp_bank
		mov	w,lib_i2cs_sdapin
		call	pinmask
		and	isr_temp,w
		clc
		sz
		stc
		mov	fsr,vp_bank
		rl	lib_i2cs_past_pres
		call	@i2cs_get_start_stop	;3 + 9/12 ;Check the new states to see if we've received a start or a stop
		call	@i2cs_isr		;3 + 11/30(I2C_isr length) = 37/59 ;Call I2C slave ISR
I2C_done

	; Update i2c pins with buffered port data
	;---------------------------------------------------------------------------------
		mov	fsr,vp_bank
		mov	w,lib_i2cs_sclpin
		call	pinmask
		sb	lib_i2cs_scl_buf
		not	w
		mov	isr_temp,w
		mov	w,<>lib_i2cs_sclpin
		or	w,#$F0
		jb	lib_i2cs_scl_buf,:setdir
:clrdir
		mov	fsr,w
		mov	w,isr_temp
		and	indf,w
		jmp	:dir_done
:setdir
		mov	fsr,w
		mov	w,isr_temp
		or	indf,w
:dir_done
		retp
vp??nr??_main
		mov	fsr,#vp??nr??_bank
		jb	lib_i2cs_rx_flag,i2cs_input_task
		jb	lib_i2cs_data_needed,i2cs_output_task
		retp
code			=	$
endm

;-----------------------------------------------------------------------------------------

uart_var		macro	prefix, isr
prefix??_??count	ds	1		;number of bits
prefix??_??divide	ds	1		;timing counter
prefix??_??low		ds	1		;shift register
prefix??_??high		ds	1		;value
prefix??_??format	ds	1
  prefix??_??bits_0	equ	prefix??_??format.0	;bits 1 and 0 specify number of total bits
  prefix??_??bits_1	equ	prefix??_??format.1	;01 -> 9bits, 10 -> 10bits, 11 -> 11bits (start+data+parity+stop)
  prefix??_??7bits	equ	prefix??_??format.2	;set for 7 databits (0 = 8 databits)
  prefix??_??even	equ	prefix??_??format.3	;set for even parity
  prefix??_??odd	equ	prefix??_??format.4	;set for odd parity
  prefix??_??data	equ	prefix??_??format.5	;set if valid value, cleared after value grabbed
  prefix??_??enable	equ	prefix??_??format.6	;set to enable uart
  prefix??_??parity	equ	prefix??_??format.7	;parity bit placeholder
prefix??_??baud		ds	1		;baudrate
prefix??_??datapin	ds	1		;high nib = port (5 to 9), low nib = pin (0 to 7)
  prefix??_??error	equ	prefix??_??datapin.3	;set if parity error
prefix??_??hspin	ds	1		;high nib = port (5 to 9), low nib = pin (0 to 7)
endm

even_parity_count = 0

uart_even_parity	macro
if even_parity_count == 0
even_parity_count = 1
	; calculate even parity for w
	; result in main_temp.0
	;---------------------------------------------------------------------------------
even_parity
			mov	main_temp,w

	;calculation code by John Payson, as found on sxlist.com
	;This routine will leave the parity of main_temp in main_temp.0
	;while blenderizing most of the rest of main_temp

			mov	w,<>main_temp	; DL = abcdefgh
			xor	main_temp,w
			mov	w,>>main_temp
			xor	main_temp,w

	; at this point, the parity for half the bits
	; (a, b, e, and f) is in bit 2 of main_temp, and the
	; parity for the other half (bits c, d, g, and h)
	; is in bit 0 of main_temp.

			snb	main_temp.2		; if the parity of (a,b,e,f) is 0,
                        			; then the parity of (a,b,c,d,e,f,g,h)
                        			; is equal to the parity of (c,d,g,h)...
                        			; which is already in bit 0, so skip ahead.

			inc	main_temp		; otherwise, the parity of (a,b,e,f) is 1,
						; so the parity of (a,b,c,d,e,f,g,h) is
						; NOT equal to the parity of (c,d,g,h).
						; invert bit 0.

	; at this point, bit 0 contains the parity of
	; (a,b,c,d,e,f,g,h).

			retp
endif
endm

lib_txuart = 0

txuart			macro	nr, prefix
			org	data
lib_tx_count		=	$+0		;number of bits
lib_tx_divide		=	$+1		;timing counter
lib_tx_low		=	$+2		;shift register
lib_tx_high		=	$+3		;value
lib_tx_format		=	$+4
  lib_tx_bits_0		=	lib_tx_format.0	;bits 1 and 0 specify number of total bits
  lib_tx_bits_1		=	lib_tx_format.1	;01 -> 9bits, 10 -> 10bits, 11 -> 11bits (start+data+parity+stop)
  lib_tx_7bits		=	lib_tx_format.2	;set for 7 databits (0 = 8 databits)
  lib_tx_even		=	lib_tx_format.3	;set for even parity
  lib_tx_odd		=	lib_tx_format.4	;set for odd parity
  lib_tx_data		=	lib_tx_format.5	;set if valid value, cleared after value grabbed
  lib_tx_enable		=	lib_tx_format.6	;set to enable uart
  lib_tx_parity		=	lib_tx_format.7	;parity bit placeholder
lib_tx_baud		=	$+5		;baudrate
lib_tx_datapin		=	$+6		;high nib = port (5 to 9), low nib = pin (0 to 7)
  lib_tx_error		=	lib_tx_datapin.3	;set if parity error
lib_tx_hspin		=	$+7		;high nib = port (5 to 9), low nib = pin (0 to 7)
vp??nr??_bank		equ	($ & $F8)|nr
uart_var prefix,nr
data			=	$
			org	code
uart_even_parity
if lib_txuart == 0
lib_txuart = 1
uart_transmit
			mov	fsr,vp_bank		;select target uart bank
			jnb	lib_tx_enable,:txdone
			decsz	lib_tx_divide		;time for next bit?
			jmp	:txdone			;no
			mov	w,lib_tx_baud		;renew delay time
			mov	lib_tx_divide,w
			test    lib_tx_count		;bits to send?
			snz
			jmp	:txdone			;no
			clc				;ready stop bit
			rr	lib_tx_high			;and shift to next bit
			rr	lib_tx_low
			mov	w,lib_tx_datapin		;pin number 0 to 7 in lownib
			call	pinmask			;get ORmask for pin
			stc
			snb	lib_tx_low.5		;clear carry and keep ORmask to make pin high
			not	w			;set carry and make ANDmask to make pin low
			sb	lib_tx_low.5
			clc
			mov	isr_temp,w
			mov	w,<>lib_tx_datapin		;port (ra to re) in lownib
			and	w,#$0F
			mov	fsr,w			;ports ra to re
			mov	w,isr_temp
			snc
			and	indf,w
			sc
			or	indf,w
			mov	w,vp_bank		;select target uart bank
			mov	fsr,w
			dec	lib_tx_count		;decrement bit counter
			jnz	:txdone
			call	pinmask			;set isr_flag
			or	isr_flags,w
:txdone
			retp
uart_output_task
			snb	lib_tx_7bits		;8 databits?
			clrb	lib_tx_high.7		;no, clear b7 for parity calculation
			mov	w,lib_tx_high
			call	even_parity
			snb	lib_tx_7bits		;8 databits?
			setb	lib_tx_high.7		;no, ready stop bit
			jnb	lib_tx_odd,:uot1
			movb	C,/main_temp.0
			jmp	:uot2
:uot1
			jnb	lib_tx_even,:uot3
			movb	C,main_temp.0
:uot2
			jnb	lib_tx_7bits,:uot4		;7 databits?
			movb	lib_tx_high.7,C		;yes, move parity into b7
:uot3
			stc				;ready stop bit
:uot4
			clrb	lib_tx_low.7		;setup start bit
			rr	lib_tx_high			;rotate in parity bit or stop bit
			rr	lib_tx_low
			not	lib_tx_high			;inverted mode
			not	lib_tx_low
			mov	w,lib_tx_format		;get total number of bits
			and	w,#$03			;1, 2 or 3
			or	w,#$08			;9, 10, or 11
			mov	lib_tx_count,w		;now uart vp starts to transmit
			clrb	lib_tx_data			;mark byte grabbed
			retp
endif
vp??nr??_isr
			mov	vp_bank,#vp??nr??_bank
			jmp	uart_transmit
vp??nr??_main
			mov	fsr,#vp??nr??_bank
			jb	lib_tx_data,uart_output_task
			retp
code			=	$
endm

lib_rxuart = 0

rxuart			macro	nr, prefix
			org	data
lib_rx_count		=	$+0		;number of bits
lib_rx_divide		=	$+1		;timing counter
lib_rx_low		=	$+2		;shift register
lib_rx_high		=	$+3		;value
lib_rx_format		=	$+4
  lib_rx_bits_0		=	lib_rx_format.0	;bits 1 and 0 specify number of total bits
  lib_rx_bits_1		=	lib_rx_format.1	;01 -> 9bits, 10 -> 10bits, 11 -> 11bits (start+data+parity+stop)
  lib_rx_7bits		=	lib_rx_format.2	;set for 7 databits (0 = 8 databits)
  lib_rx_even		=	lib_rx_format.3	;set for even parity
  lib_rx_odd		=	lib_rx_format.4	;set for odd parity
  lib_rx_data		=	lib_rx_format.5	;set if valid value, cleared after value grabbed
  lib_rx_enable		=	lib_rx_format.6	;set to enable uart
  lib_rx_parity		=	lib_rx_format.7	;parity bit placeholder
lib_rx_baud		=	$+5		;baudrate
lib_rx_datapin		=	$+6		;high nib = port (5 to 9), low nib = pin (0 to 7)
  lib_rx_error		=	lib_rx_datapin.3	;set if parity error
lib_rx_hspin		=	$+7		;high nib = port (5 to 9), low nib = pin (0 to 7)
vp??nr??_bank		equ	($ & $F8) | nr
uart_var prefix,nr
data			=	$
			org	code
uart_even_parity
if lib_rxuart == 0
lib_rxuart = 1
uart_receive
			mov	fsr,vp_bank		;select target uart rambank
			jnb	lib_rx_enable,:rxdone
			mov	w,<>lib_rx_datapin		;port (ra to re) in lownib
			and	w,#$0F
			mov	fsr,w			;ports ra to re
			mov	w,indf			;read all pins
			mov	isr_temp,w		;save pin states
			mov	fsr,vp_bank
			mov	w,lib_rx_datapin		;pin number 0 to 7 in lownib
			call	pinmask			;get mask for pin
			and	isr_temp,w		;extract bit for pin
			test	lib_rx_count		;currently receiving byte?
			sz				;no
			jmp	:rx1			;yes, jump ahead
			mov	w,--lib_rx_format		;ready bits for start
			and	w,#$03			;number of bits 1, 2 or 3
			or	w,#$08			;9, 10 or 11
			test	isr_temp		;start bit?
			snz				;no
			mov	lib_rx_count,w		;yes, renew bit count
			mov	w,>>lib_rx_baud		;half bittime delay
			add	w,lib_rx_baud		;plus bittime delay -> start delay
			mov	lib_rx_divide,w
:rx1
			clc
			test	isr_temp
			sz
			stc
			decsz	lib_rx_divide		;middle of next bit?
          		jmp	:rxdone			;no
			dec	lib_rx_count		;last bit?
			jz	:rx2			;yes
			rr	lib_rx_low			;no, rotate in new bit
			movb	lib_rx_parity,C		;save b0
			jmp	:rx3			;renew delay time
:rx2
			mov	w,lib_rx_low		;save byte to allow receive another byte
			mov	lib_rx_high,w
			setb	lib_rx_data			;mark byte received
:rx3
			mov	w,lib_rx_baud		;renew delay time
			mov	lib_rx_divide,w
:rxdone
			retp
uart_input_task
			movb	C,lib_rx_parity		;get last saved b0
			jb	lib_rx_format.1,:uit1
			clc				;adjust for 7 databits + no parity (total bits is 9)
			rr	lib_rx_high
			rr	lib_rx_high
:uit1
			snb	lib_rx_format.0
			rl	lib_rx_high			;adjust for 8 databits + parity (total bits is 11)
			jnb	lib_rx_7bits,:uit2
			movb	C,lib_rx_high.7		;save possible parity in case 7 databits
			clrb	lib_rx_high.7		;clear b7 in case 7 databits
:uit2
			movb	lib_rx_parity,C		;save possible parity bit
			clrb	lib_rx_error		;assume no error
			jb	lib_rx_odd,:uit3
			jb	lib_rx_even,:uit3
			jmp	:uit4
:uit3
			mov	w,lib_rx_high
			call	even_parity
			snb	lib_rx_odd
			not	main_temp			;invert calculated even parity bit for odd parity
			addb	main_temp,lib_rx_parity		;if parity matches, b0 will be cleared
			snb	main_temp.0
			setb	lib_rx_error		;parity error
:uit4
			clrb	lib_rx_data			;mark byte grabbed
			mov	w,fsr			;isr_flag to use in lownib
			call	pinmask
			or	isr_flags,w		;set isr flag
			retp
endif
vp??nr??_isr
			mov	vp_bank,#vp??nr??_bank
			jmp	uart_receive
vp??nr??_main
			mov	fsr,#vp??nr??_bank
			jb	lib_rx_data,uart_input_task
			retp
code			=	$
endm

;-----------------------------------------------------------------------------------------

defvp			macro	nr, name, prefix
name nr, prefix
endm

;-----------------------------------------------------------------------------------------

PORT_RA			equ	$05		;storage RA latch
PORT_RB			equ	$06		;storage RB latch
PORT_RC			equ	$07		;storage RC latch (ram if SX18)
PORT_RD			equ	$08		;storage RD latch (ram if SX18/28)
PORT_RE			equ	$09		;storage RE latch (ram if SX18/28)
isr_temp		equ	$0A
isr_flags		equ	$0B
  isr0_flag		equ	isr_flags.0	;system timer (VP0)
  isr1_flag		equ	isr_flags.1	;vp1
  isr2_flag		equ	isr_flags.2	;vp2
  isr3_flag		equ	isr_flags.3	;vp3
  isr4_flag		equ	isr_flags.4	;vp4
  isr5_flag		equ	isr_flags.5	;vp5
  isr6_flag		equ	isr_flags.6	;vp6
  isr7_flag		equ	isr_flags.7	;??
vp_bank			equ	$0C
main_temp		equ	$0F
DIR_RA			equ	$F5		;storage RA direction register
DIR_RB			equ	$F6		;storage RB direction register
DIR_RC			equ	$F7		;storage RC direction register
DIR_RD			equ	$F8		;storage RD direction register
DIR_RE			equ	$F9		;storage RE direction register

			org	page0_org
sxinterrupt		jmp	_sxinterrupt
reset_entry		jmp	init
do_clear_ram		jmp	clear_ram
do_vp1_main		jmp	vp1_main
do_vp1_isr		jmp	vp1_isr
do_vp2_main		jmp	vp2_main
do_vp2_isr		jmp	vp2_isr
do_vp3_main		jmp	vp3_main
do_vp3_isr		jmp	vp3_isr
do_vp4_main		jmp	vp4_main
do_vp4_isr		jmp	vp4_isr
do_vp5_main		jmp	vp5_main
do_vp5_isr		jmp	vp5_isr
do_vp6_main		jmp	vp6_main
do_vp6_isr		jmp	vp6_isr
code			=	$

;-----------------------------------------------------------------------------------------
; RAM Bank Register VP definitions
;-----------------------------------------------------------------------------------------

	; bank 0
	;---------------------------------------------------------------------------------
			org	bank0_org
data			=	$
defvp 1,rxuart,rx
defvp 2,txuart,tx

			org	code

pinmask
			and	w,#$07
			add	pc,w
			retw	1		;pin0
			retw	2		;pin1
			retw	4		;pin2
			retw	8		;pin3
			retw	16		;pin4
			retw	32		;pin5
			retw	64		;pin6
			retw	128		;pin7
code			=	$

	; bank 1
	;---------------------------------------------------------------------------------
			org	bank1_org
data			=	$
defvp 3,rxuart,rx1
defvp 4,txuart,tx1

	; bank 2
	;---------------------------------------------------------------------------------
			org	bank2_org
data			=	$
defvp 5,i2c_slave,i2cs

			org	data
;timer VP
timer_bank		=	$
timer_isr		ds	1		;increments every isr
timer_thread		ds	1		;increments 4 every 3 isr
data			=	$

;-----------------------------------------------------------------------------------------

			org	code

	;clear all ram
clear_ram
			mov	fsr,#global_org
:zero_global
			clr	indf
			inc	fsr
			cjne	fsr,#$10,:zero_global
:zero_ram
			clr	indf
			inc	fsr
			snz
			retp
ifndef DEV_48
			setb	fsr.4
endif
			jmp	:zero_ram

_sxinterrupt
isr_timer
			bank	timer_bank
ifdef DEV_48
			clrb	fsr.7
endif
			inc	timer_isr
			inc	timer_thread
			sb	timer_thread.1	;skip if 2 or 3
			inc	timer_thread	;if 0 or 1, make 2
						;lowest 2 bits of timer_thread has repeated 01,10,11 sequence
			cjne	timer_isr,#mscount,:timer_done
			clr	timer_isr
			setb	isr0_flag	;main calls isr0()
:timer_done

update_dir
			mov	w,#$F0
			mov	fsr,w
			mov	m,#$0F		;access port direction registers
			mov	w,DIR_RA
			mov	!ra,w
			mov	w,DIR_RB
			mov	!rb,w
ifndef DEV_18
			mov	w,DIR_RC
			mov	!rc,w
endif
ifdef DEV_48
			mov	w,DIR_RD
			mov	!rd,w
			mov	w,DIR_RE
			mov	!re,w
endif

thread_start
			mov	w,#timer_bank
			mov	fsr,w
			mov	w,--timer_thread
			and	w,#$03		;w = 0, 1 or 2
			add	pc,w
			jmp	isr_thread_0
			jmp	isr_thread_1
isr_thread_2
			;insert thread_2 code here
ifdef vp6_bank
			call	do_vp6_isr
endif
ifdef vp5_bank
			call	do_vp5_isr
endif
			jmp	isr_thread_end
isr_thread_1
			;insert thread_1 code here
ifdef vp4_bank
			call	do_vp4_isr
endif
ifdef vp3_bank
			call	do_vp3_isr
endif
			jmp	isr_thread_end
isr_thread_0
			;insert thread_0 code here
ifdef vp2_bank
			call	do_vp2_isr
endif
ifdef vp1_bank
			call	do_vp1_isr
endif
isr_thread_end
			;insert code here
isr_end
			mov	w,#(-int_period)&255
			retiw

;-------------- end of the Interrupt Service Routines ------------------------------------

	; program initialization
init
			call	do_clear_ram
portinit
if RB_wked != RB_wked_PU
			mov	m,#M_WKED	; point mode to WKED
			mov	!rb,#RB_wked
endif
if RB_wken != RB_wken_PU
			mov	m,#M_WKEN	; point mode to WKEN
			mov	!rb,#RB_wken
endif
if RB_wkpnd != RB_wkpnd_PU
			mov	m,#M_WKPND	 ;point mode to WKPND
			mov	w,#RB_WKPND
			mov	!rb,w
endif
if RB_cmp != RB_cmp_PU
			mov	m,#M_CMP	; point mode to CMP
			mov	w,#RB_cmp
			mov	!rb,w
endif
			mov	m,#M_ST		; point mode to ST
ifndef DEV_18
if RC_st != RC_st_PU
			mov	!rc,#RC_st
endif
endif
if RB_st != RB_st_PU
			mov	!rb,#RB_st
endif
			mov	m,#M_LVL	; point mode to LVL
ifdef DEV_48
if RE_lvl != RE_lvl_PU
			mov	!re,#RE_lvl
endif
if RD_lvl != RD_lvl_PU
			mov	!rd,#RD_lvl
endif
endif
ifndef DEV_18
if RC_lvl != RC_lvl_PU
			mov	!rc,#RC_lvl
endif
endif
if RB_lvl != RB_lvl_PU
			mov	!rb,#RB_lvl
endif
if RA_lvl != RA_lvl_PU
			mov	!ra,#RA_lvl
endif
			mov	m,#M_PLP	; point mode to PLP
ifdef DEV_48
if RE_plp != RE_plp_PU
			mov	!re,#RE_plp
endif
if RD_plp != RD_plp_PU
			mov	!rd,#RD_plp
endif
endif
ifndef DEV_18
if RC_plp != RC_plp_PU
			mov	!rc,#RC_plp
endif
endif
if RB_plp != RB_plp_PU
			mov	!rb,#RB_plp
endif
if RA_plp != RA_plp_PU
			mov	!ra,#RA_plp
endif
ifdef DEV_48
			mov	rc,#RE_latch
			mov	rb,#RD_latch
endif
ifndef DEV_18
			mov	rc,#RC_latch	; init latches
endif
			mov	rb,#RB_latch
			mov	ra,#RA_latch
			mov	m,#M_TRIS	; point mode to TRIS
			mov	w,#$F0
			mov	fsr,w
ifdef DEV_48
			mov	w,#RE_tris
if RE_tris != RE_tris_PU
			mov	!re,w
endif
			mov	DIR_RE,w
			mov	w,#RD_tris
if RD_tris != RD_tris_PU
			mov	!rd,w
endif
			mov	DIR_RD,w
endif
ifndef DEV_18
			mov	w,#RC_tris
if RC_tris != RC_tris_PU
			mov	!rc,w
endif
			mov	DIR_RC,w
endif
			mov	w,#RB_tris
if RB_tris != RB_tris_PU
			mov	!rb,w
endif
			mov	DIR_RB,w
			mov	w,#RA_tris
if RA_tris != RA_tris_PU
			mov	!ra,w
endif
			mov	DIR_RA,w

	;setup option register
			mov	w,#RTCC_PS_OFF+RTCC_ON	;RTCC prescaler 1:1 and RTCC at $01
			mov	!option,w
	;insert vp initialization code (set baudrates, parity etc)
main
ifdef vp1_bank
			call	do_vp1_main
endif
ifdef vp2_bank
			call	do_vp2_main
endif
ifdef vp3_bank
			call	do_vp3_main
endif
ifdef vp4_bank
			call	do_vp4_main
endif
ifdef vp5_bank
			call	do_vp5_main
endif
ifdef vp6_bank
			call	do_vp6_main
endif
	;insert main loop code
			test	isr_flags
			jz	main			;no isr_flags interrupts
	;insert code to handle isr_flags interrupts
			jmp	main
code			=	$

			org	code
ifndef vp1_bank
vp1_main		=	$
vp1_isr			=	$
endif
ifndef vp2_bank
vp2_main		=	$
vp2_isr			=	$
endif
ifndef vp3_bank
vp3_main		=	$
vp3_isr			=	$
endif
ifndef vp4_bank
vp4_main		=	$
vp4_isr			=	$
endif
ifndef vp5_bank
vp5_main		=	$
vp5_isr			=	$
endif
ifndef vp6_bank
vp6_main		=	$
vp6_isr			=	$
endif
			retp

;end of file vplib.src
