please dont rip this site

Scenix Lib IO OSI2 Serial DUART_0412_JB.SRC

;  *****************************************************************************************
;       Virtual Peripheral Universal Full Duplex UART with Buffering
;
;       Length: xxx bytes (total)
;       Authors: Chip Gracey, President, Parallax Inc. 10/03/97 to 07/09/98
;		 Craig Webb, Consultant to Scenix Semiconductor Inc.
;                Christopher Waters, Celsius Research Ltd.
;		 Stephen Holland, Scenix Semiconductor Inc.
;       Modifications:
;		 11/18/98, Craig Webb
;			- documented source and cleaned up code
;		 01/07/99, Christopher Waters
;			- added TX and RX FIFO buffering for full-duplex 
;		 02/15/99, Craig Webb
;			- expanded for 2 channel operation
;			- minimal clock frequency at 19.2Kbps
;		 03/06/99, Stephen Holland
;			- modified for 50MHz and up to 115.2Kbps operation
;		 03/11/99, Stephen Holland
;			- added autobaud capability for both channels
;		 03/19/99, Stephen Holland
;			- extended autobaud capability for operation from 110 - 115.2Kbps
;		 03/29/99, Stephen Holland
;			- added IFDEF to allow using same code for SX28 or SX48/52 targets
;		 03/30/99, Stephen Holland
;			- modified second channel for fixed 9600bps operation
;		 04/05/99-04/10/99, Stephen Holland
;			- added 166552-like bus interface and debugged
;		 04/12/99, Stephen Holland
;			- debugged additional handshaking lines DTR & DSR
;		 11/01/2004, Jim Brain
;			- made autobaud detection conditional code
;                       - added high speed configurable UART2 back in 
;                       - cleaned up code for prod SX52
;                       - added conditional to inline uart vp code, (saves 7 cycles per uart)
;                       - moved autobaud code to subroutines, to save space.
;
;*****************************************************************************************
; Assembler directives
;
; uses: SX28AC, 2 pages of program memory, 8 banks of RAM, high speed osc.
;       operating in turbo mode, with 8-level stack & extended option reg.
;                
;*****************************************************************************************
LIST Q=37
IRC_CAL IRC_FAST
; if you change this, change xtal as well
FREQ 50000000					;oscillator frequency


;*****************************************************************************************
; Conditional compilation defines
;
; AUTO_BAUD.  Define if you want to use the auto baud rate selection mechanism. (not tested)
; INLINE_VP.  Use if you want to inline the UART VP routines.  Saves 7 cycles per UART
;                
;*****************************************************************************************
;SX28
SX48_52
;AUTO_BAUD
INLINE_VP

include "stdinc.src"

		ID      'DUART'			;program ID label
		RESET   reset_entry		;set reset/boot address

;*****************************************************************************************
; Program constants
;*****************************************************************************************
; Ring buffer sizes
;	Note: if RX+TX values>16 then ring buffer bank definition will need to be adjusted

rx_ring_size_1	equ	16			;size (in bytes) of the rx ring buffer
tx_ring_size_1	equ	16			;size of the tx ring buffer
rx_ring_size_2	equ	16			;size (in bytes) of the rx ring buffer
tx_ring_size_2	equ	16			;size of the tx ring buffer

int_period	=	217			;cycles between interrupt passes
xtal		=	50000000
RTCC_prescalar	=	1

;int_period	=	163			;cycles between interrupt passes
;xtal		=	75000000
;RTCC_prescalar	=	2

;*****************************************************************************************
; Port Assignment: Bit variables
;*****************************************************************************************
IF SX_TYPE = 0		;SX28 port definitions

RA_init		equ     %1011			;initialize port RA
RA_IO		equ     %0100			;Set RA in/out directions;
RB_init		equ	%00000000		;initialize port RB
RB_IO		equ	%11111111		;Sets RB in/out directions
RC_init		equ     %10001010		;initialize port RC
RC_IO		equ     %00100101		;Sets RC in/out directions

rx_pin_1	equ	rc.0			;UART channel 1 receive input
tx_pin_1	equ	rc.1			;UART channel 1 transmit output
RTS_1		equ	rc.2			;RTS input
CTS_1		equ	rc.3			;CTS output
DSR_1		equ	rc.4			;DSR output
DTR_1		equ	rc.5			;DTR input
RI_1		equ	rc.6			;RI output
CD_1		equ	rc.7			;CD output

ELSE		;SX52 port definitions

RA_init		equ     %00000000		;initialize port RA
RA_IO		equ     %11111111		;Set RA in/out directions;
RB_init		equ	%00000000		;initialize port RB(NS16552-like data bus interface)
RB_IO		equ	%11111111		;Sets RB in/out directions
RC_init		equ     %11011010		;initialize port RC(UART channel 1 handshaking)
RC_IO		equ     %00100101		;Sets RC in/out directions
RD_init		equ     %11011010		;initialize port RD(UART channel 2 handshaking)
RD_IO		equ     %00100101		;Sets RD in/out directions
RE_init		equ     %00000000		;initialize port RE(NS16552-like address bus interface)
RE_IO		equ     %11111111		;Sets RE in/out directions

a0		equ	re.0			;UART address bit 0 input
a1		equ	re.1			;UART address bit 1 input
a2		equ	re.2			;UART address bit 2 input
chsl		equ	re.3			;UART channel select input
cs		equ	re.4			;UART chip select input
read		equ	re.5			;UART !read input
write		equ	re.6			;UART !write input

data_bus	equ	rb			;UART 8-bit data bus


; UART (channel 1)
rx_pin_1	equ	rc.0			;RXD input
tx_pin_1	equ	rc.1			;TXD output
RTS_1		equ	rc.2			;RTS input
CTS_1		equ	rc.3			;CTS output
DSR_1		equ	rc.4			;DSR output
DTR_1		equ	rc.5			;DTR input
RI_1		equ	rc.6			;RI output
CD_1		equ	rc.7			;CD output

; UART (channel 2)
rx_pin_2	equ	rd.0			;RXD input
tx_pin_2	equ	rd.1			;TXD output
RTS_2		equ	rd.2			;RTS input
CTS_2		equ	rd.3			;CTS output
DSR_2		equ	rd.4			;DSR output
DTR_2		equ	rd.5			;DTR input
RI_2		equ	rd.6			;RI output
CD_2		equ	rd.7			;CD output

ENDIF

B75		equ	0
B110		equ	1
B134		equ	2
B150		equ	3
B300		equ	4
B600		equ	5
B1200		equ	6
B2400		equ	7
B4800		equ	8
B9600		equ	9
B19200		equ	10
B38400		equ	11
B57600		equ	12
B115200		equ	13

;*****************************************************************************************
; Global Register definitions
;*****************************************************************************************
		org     $0a			;start of program registers

temp            ds      1                       ;temporary storage
isr_temp	ds	1			;used by isr - must be global
flags		ds	1
	uart1_en	equ	flags.0
	uart2_en	equ	flags.1
	rx_flag_1	equ	flags.2
	rx_flag_2	equ	flags.3
	speed_1		equ	flags.4
	speed_2		equ	flags.5
IFDEF AUTO_BAUD
	lo_detected_1	equ	flags.6
	lo_detected_2	equ	flags.7
ENDIF

line_status_1	ds	1
	rx_dr_1		equ	line_status_1.0	;Receiver Data Ready(DR) indicator
	buffer_oe_1	equ	line_status_1.1	;Buffer Overrun Error(OE) indicator
	parity_e_1	equ	line_status_1.2	;Parity Error(PE) indicator
	framing_e_1	equ	line_status_1.3	;Framing Error(FE) indicator
	break_int_1	equ	line_status_1.4	;Break Interrupt(BI) indicator
	thre_1		equ	line_status_1.5	;Transmitter Holding Register Empty(THRE) indicator
	temt_1		equ	line_status_1.6	;Transmitter Empty(TEMT) indicator
	lsr7_1		equ	line_status_1.7	;LSR7

line_status_2	ds	1
	rx_dr_2		equ	line_status_2.0	;Receiver Data Ready(DR) indicator
	buffer_oe_2	equ	line_status_2.1	;Buffer Overrun Error(OE) indicator
	parity_e_2	equ	line_status_2.2	;Parity Error(PE) indicator
	framing_e_2	equ	line_status_2.3	;Framing Error(FE) indicator
	break_int_2	equ	line_status_2.4	;Break Interrupt(BI) indicator
	thre_2		equ	line_status_2.5	;Transmitter Holding Register Empty(THRE) indicator
	temt_2		equ	line_status_2.6	;Transmitter Empty(TEMT) indicator
	lsr7_2		equ	line_status_2.7	;LSR7
rtcc_period	ds	1

;*****************************************************************************************
; RAM Bank Register definitions
;*****************************************************************************************

	;*********************************************************************************
	; Bank 1
	;*********************************************************************************
		org     bank1


uart_1_tx	=       $                       ;UART 1 TX bank

divisor_1	ds	2
tx_high_1	ds      1                       ;hi byte to transmit
tx_low_1	ds      1                       ;low byte to transmit
tx_count_1	ds      1                       ;number of bits sent
tx_divide_1	ds      2                       ;xmit timing (/16) counter2
tx_ring_ip_1	ds	1			;transmit ring in pointer
tx_ring_op_1	ds	1			;transmit ring out pointer
tx_ring_cnt_1	ds	1			;transmit ring contents count

string1		ds      1                       ;indirect ptr to output string

	;*********************************************************************************
	; Bank 2
	;*********************************************************************************
		org     bank2

uart_2_tx	=       $                       ;UART 2 TX bank

divisor_2	ds	2
tx_high_2	ds      1                       ;hi byte to transmit
tx_low_2	ds      1                       ;low byte to transmit
tx_count_2	ds      1                       ;number of bits sent
tx_divide_2	ds      2                       ;xmit timing (/16) counter
tx_ring_ip_2	ds	1			;transmit ring in pointer
tx_ring_op_2	ds	1			;transmit ring out pointer
tx_ring_cnt_2	ds	1			;transmit ring contents count

string2		ds      1                       ;indirect ptr to output string

	;*********************************************************************************
	; Bank 3
	;*********************************************************************************
		org	bank3

uart_rx		=	$			;UART RX bank

rx_count_1      ds      1                       ;number of bits received
rx_divide_1	ds      2                       ;receive timing counter
rx_byte_1	ds      1                       ;buffer for incoming byte
rx_ring_ip_1	ds	1			;receive ring in pointer
rx_ring_op_1	ds	1			;receive ring out pointer
rx_ring_cnt_1	ds	1			;receive ring contents count

rx_count_2      ds      1                       ;number of bits received
rx_divide_2	ds      2                       ;receive timing counter
rx_byte_2	ds      1                       ;buffer for incoming byte
rx_ring_ip_2	ds	1			;receive ring in pointer
rx_ring_op_2	ds	1			;receive ring out pointer
rx_ring_cnt_2	ds	1			;receive ring contents count

	;*********************************************************************************
	; Bank 4
	;*********************************************************************************
		org	bank4

uart_tx_ring_1	=	$			;UART channel 1 TX ring buffers
tx_ring_1	ds	tx_ring_size_1

	;*********************************************************************************
	; Bank 5
	;*********************************************************************************
		org	bank5

uart_rx_ring_1	=	$			;UART channel 1 RX ring buffers
rx_ring_1	ds	rx_ring_size_1

	;*********************************************************************************
	; Bank 6
	;*********************************************************************************
		org	bank6

uart_tx_ring_2	=	$			;UART channel 2 TX ring buffers
tx_ring_2	ds	tx_ring_size_2

	;*********************************************************************************
	; Bank 7
	;*********************************************************************************
		org	bank7

uart_rx_ring_2	=	$			;UART channel 2 RX ring buffers
rx_ring_2	ds	rx_ring_size_2

;*****************************************************************************************
; Watches 
;*****************************************************************************************
		watch	rx_ring_ip_1,8,uhex
		watch	rx_ring_cnt_1,8,udec
		watch	rx_ring_1,16,fstr
		watch	tx_ring_ip_1,8,uhex
		watch	tx_ring_cnt_1,8,udec
		watch	tx_ring_1,16,fstr
		watch	rx_ring_ip_2,8,uhex
		watch	rx_ring_cnt_2,8,udec
		watch	rx_ring_2,16,fstr
		watch	tx_ring_ip_2,8,uhex
		watch	tx_ring_cnt_2,8,udec
		watch	tx_ring_2,16,fstr
		watch	divisor_1,16,udec

;*****************************************************************************************
; Macros
;*****************************************************************************************
	; UART ring macro
	; Advance the pointer through the ring, wrapping around if necessary
	; This could be more efficient for aligned and power of 2 ring sizes.
	;*********************************************************************************
ringadv	macro	3		; Arguments ptr,base,size	
	inc	\1		; Increment the pointer
; Check for wrap around
	mov	w,\1		; Load the pointer
	xor	w,#(\2+\3)	; Check if ptr = base+size
	mov	w,#\2	
	snz	
	mov	\1,w		; Equal, set ptr to base
	endm

	;*********************************************************************************
	; VP: uart_1_transmit
	; 110 - 57.6Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
UART1_TRANSMIT	macro
		bank    uart_1_tx		;switch to serial register bank
		inc	tx_divide_1		;ready to transmit bit?
		snz
		inc	tx_divide_1+1
		sz				;if tx_divide_1+1=0 then skip
		jmp	uart_1_receive		;else, exit
:continue	mov	w,divisor_1		;reload baud period divisor_1(16-bit)
		mov	tx_divide_1,w
		not	tx_divide_1		;compliment tx_divide_1
		mov	w,divisor_1+1
		mov	tx_divide_1+1,w
		not	tx_divide_1+1		;compliment tx_divide_1+1

		test    tx_count_1              ;are we sending?
		sz
		jmp	:txbit			;yes, send next bit
		mov	w,tx_ring_cnt_1		;is tx ring empty?
		snz
		jmp	uart_1_receive		;yes, go to :transmit_out
	;	jnb	DTR_1,uart_1_receive			
	;	jnb	RTS_1,uart_1_receive			
:txring		mov	w,tx_ring_op_1		;move one character from the ring to the
		mov	fsr,w			; transmitter using indirect addressing
		mov	w,indf
		bank	uart_1_tx		;switch back to the uart bank
		not     w                       ;ready bits (inverse logic)
		mov     tx_high_1,w             ; store data byte
		setb    tx_low_1.7              ; set up start bit
		mov     tx_count_1,#10          ;1 start + 8 data + 1 stop bit
		dec	tx_ring_cnt_1		;decrement tx ring byte count

		ringadv	tx_ring_op_1,tx_ring_1,tx_ring_size_1	;advance ring pointer
	
:txbit		clc                             ;ready stop bit
		rr      tx_high_1               ; and shift to next bit
		rr      tx_low_1                ;
		dec     tx_count_1              ;decrement bit counter
		movb    tx_pin_1,/tx_low_1.6    ;output next bit

uart_1_receive
		bank    uart_rx	
	        movb    c,rx_pin_1              ;get current rx bit
		test    rx_count_1              ;currently receiving byte?
		sz
		jmp     :rxbit                  ;if so, jump ahead
		mov     w,#9                    ;in case start, ready 9 bits
		sc                              ;skip ahead if not start bit
		mov     rx_count_1,w            ;it is, so renew bit count
		clc
		bank	uart_1_tx
		mov	w,divisor_1		;reload 1.5 bit period divisor_1(16-bit)
		bank    uart_rx	
		mov	rx_divide_1,w
		bank	uart_1_tx
		mov	w,divisor_1+1
		bank    uart_rx	
		mov	rx_divide_1+1,w
		mov	w,>>rx_divide_1+1	;w=divisor_1/2
		snc
		inc	rx_divide_1+1		;16-bit add
		mov	w,>>rx_divide_1		
		add	rx_divide_1,w
		snc
		inc	rx_divide_1+1
		not	rx_divide_1		;compliment rx_divide_1
		not	rx_divide_1+1		;compliment rx_divide_1+1

:rxbit
		inc	rx_divide_1		;ready to transmit bit?
		snz
		inc	rx_divide_1+1
		sz				;if rx_divide_1+1=0 then skip
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF

		bank	uart_1_tx
		mov	w,divisor_1		;reload 1 bit period divisor_1(16-bit)
		bank    uart_rx	
		mov	rx_divide_1,w
		bank	uart_1_tx
		mov	w,divisor_1+1
		bank    uart_rx	
		mov	rx_divide_1+1,w
		not	rx_divide_1		;compliment rx_divide_1
		not	rx_divide_1+1		;compliment rx_divide_1+1

:get_bit        movb    c,rx_pin_1              ;get current rx bit
		dec     rx_count_1              ;last bit?
		sz                              ;if not
		rr      rx_byte_1               ;  then save bit
		sz                             	;and skip to end
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		mov	w,rx_ring_cnt_1		; Will this byte make the receive buffer full?
		inc	wreg
		xor	w,#rx_ring_size_1	; Compare with the buffer size
		sz
		jmp	:rx_ok			; Not full
		clrb	CTS_1			; CTS = false - not ready to receive data
		clrb	DSR_1			; DSR = false - not ready to receive data
		setb	buffer_oe_1		; Signal receive buffer overflow
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
:rx_ok		setb	CTS_1			; CTS = true - ready to receive data
		setb	DSR_1			; DSR = true - ready to receive data
		mov	w,rx_byte_1		; Save the received byte in global
		mov	isr_temp,w
		mov	w,rx_ring_ip_1		; Store character in receive buffer
		mov	fsr,w			; Set indirect address
		mov	w,isr_temp			; temp must be global
		mov	indf,w			; Store the received byte
		bank    uart_rx			; Restore bank

		ringadv	rx_ring_ip_1,rx_ring_1,rx_ring_size_1

		inc	rx_ring_cnt_1		; Increment the ring buffer count
:done
ENDM

	;*********************************************************************************
	; VP: uart_2_transmit
	; 110 - 57.6Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
UART2_TRANSMIT	macro
		bank    uart_2_tx		;switch to serial register bank
		inc	tx_divide_2		;ready to transmit bit?
		snz
		inc	tx_divide_2+1
		sz				;if tx_divide_1+1=0 then skip
		jmp	uart_2_receive		;else, exit
:continue	mov	w,divisor_2		;reload baud period divisor_1(16-bit)
		mov	tx_divide_2,w
		not	tx_divide_2		;compliment tx_divide_1
		mov	w,divisor_2+1
		mov	tx_divide_2+1,w
		not	tx_divide_2+1		;compliment tx_divide_1+1
		test    tx_count_2              ;are we sending?
		sz
		jmp	:txbit			;yes, send next bit
		mov	w,tx_ring_cnt_2		;is tx ring empty?
		snz
		jmp	uart_2_receive		;yes, go to :transmit_out
	;	jnb	DTR_2,uart_2_receive			
	;	jnb	RTS_2,uart_2_receive			
:txring		mov	w,tx_ring_op_2		;move one character from the ring to the
		mov	fsr,w			; transmitter using indirect addressing
		mov	w,indf
		bank	uart_2_tx		;switch back to the uart bank
		not     w                       ;ready bits (inverse logic)
		mov     tx_high_2,w             ; store data byte
		setb    tx_low_2.7              ; set up start bit
		mov     tx_count_2,#10          ;1 start + 8 data + 1 stop bit
		dec	tx_ring_cnt_2		;decrement tx ring byte count

		ringadv	tx_ring_op_2,tx_ring_2,tx_ring_size_2	;advance ring pointer
	
:txbit		clc                             ;ready stop bit
		rr      tx_high_2               ; and shift to next bit
		rr      tx_low_2                ;
		dec     tx_count_2              ;decrement bit counter
		movb    tx_pin_2,/tx_low_2.6    ;output next bit

uart_2_receive
		bank    uart_rx	
	        movb    c,rx_pin_2              ;get current rx bit
		test    rx_count_2              ;currently receiving byte?
		sz
		jmp     :rxbit                  ;if so, jump ahead
		mov     w,#9                    ;in case start, ready 9 bits
		sc                              ;skip ahead if not start bit
		mov     rx_count_2,w            ;it is, so renew bit count
		clc
		mov	w,divisor_2		;reload 1 bit period divisor_1(16-bit)
		bank    uart_rx	
		mov	rx_divide_2,w
		bank	uart_2_tx
		mov	w,divisor_2+1
		bank    uart_rx	
		mov	rx_divide_2+1,w
		not	rx_divide_2		;compliment rx_divide_1
		not	rx_divide_2+1		;compliment rx_divide_1+1
:rxbit
		inc	rx_divide_2		;ready to transmit bit?
		snz
		inc	rx_divide_2+1
		sz				;if rx_divide_1+1=0 then skip
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		bank	uart_2_tx
		mov	w,divisor_2		;reload 1 bit period divisor_1(16-bit)
		bank    uart_rx	
		mov	rx_divide_2,w
		bank	uart_2_tx
		mov	w,divisor_2+1
		bank    uart_rx	
		mov	rx_divide_2+1,w
		not	rx_divide_2		;compliment rx_divide_1
		not	rx_divide_2+1		;compliment rx_divide_1+1
:get_bit        movb    c,rx_pin_2              ;get current rx bit
		dec     rx_count_2              ;last bit?
		sz                              ;if not
		rr      rx_byte_2               ;  then save bit
		sz                             	;and skip to end
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		mov	w,rx_ring_cnt_2		; Is the receive buffer already full?
		inc	wreg
		xor	w,#rx_ring_size_2	; Compare with the buffer size
		sz
		jmp	:rx_ok			; Not full
		clrb	CTS_2			; CTS = false - not ready to receive data
		clrb	DSR_2			; DSR = false - not ready to receive data
		setb	buffer_oe_2		; Signal receive buffer overflow
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
:rx_ok		setb	CTS_2			; CTS = true - ready to receive data
		setb	DSR_2			; DSR = true - ready to receive data
		mov	w,rx_byte_2		; Save the received byte in global
		mov	isr_temp,w
		mov	w,rx_ring_ip_2		; Store character in receive buffer
		mov	fsr,w			; Set indirect address
		mov	w,isr_temp			; temp must be global
		mov	indf,w			; Store the received byte
		bank    uart_rx			; Restore bank

		ringadv	rx_ring_ip_2,rx_ring_2,rx_ring_size_2

		inc	rx_ring_cnt_2		; Increment the ring buffer count
:done
endm

	;*********************************************************************************
	; VP: uart_1_transmit_fast
	; 57.6K - 115.2Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
UART1_TRANSMIT_FAST	macro
		bank    uart_1_tx		;switch to serial register bank
		decsz	tx_divide_1		;ready to transmit bit?
		jmp	uart_1_rx_fast
		mov	tx_divide_1,divisor_1	;reload baud period
		test    tx_count_1              ;are we sending?
		sz
		jmp	:txbit			;yes, send next bit
		mov	w,tx_ring_cnt_1		;is tx ring empty?
		snz
		jmp	uart_1_rx_fast		;yes, go to :transmit_out
	;	jnb	DTR_1,uart_1_rx_fast
	;	jnb	RTS_1,uart_1_rx_fast
:txring		mov	w,tx_ring_op_1		;move one character from the ring to the
		mov	fsr,w			; transmitter using indirect addressing
		mov	w,indf
		bank	uart_1_tx		;switch back to the uart bank
		not     w                       ;ready bits (inverse logic)
		mov     tx_high_1,w             ; store data byte
		setb    tx_low_1.7              ; set up start bit
		mov     tx_count_1,#10          ;1 start + 8 data + 1 stop bit
		dec	tx_ring_cnt_1		;decrement tx ring byte count

		ringadv	tx_ring_op_1,tx_ring_1,tx_ring_size_1	;advance ring pointer
	
:txbit		clc                             ;ready stop bit
		rr      tx_high_1               ; and shift to next bit
		rr      tx_low_1                ;
		dec     tx_count_1		;decrement bit counter
		movb    tx_pin_1,/tx_low_1.6    ;output next bit

uart_1_rx_fast	bank    uart_rx			;switch to serial register bank
	        movb    c,rx_pin_1              ;get current rx bit
		test    rx_count_1              ;currently receiving byte?
		sz
		jmp     :rxbit                  ;if so, jump ahead
		mov     w,#9                    ;in case start, ready 9 bits
		sc                              ;skip ahead if not start bit
		mov     rx_count_1,w            ;it is, so renew bit count
		clc
		bank    uart_1_tx
		mov	w,>>divisor_1
		add	w,divisor_1
		bank    uart_rx
		mov     rx_divide_1,w		;ready 1.5 bit periods
:rxbit          decsz   rx_divide_1		;middle of next bit?
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		bank    uart_1_tx
		mov	w,divisor_1		;yes, reload 1 bit period
		bank    uart_rx
		mov	rx_divide_1,w
		dec     rx_count_1              ;last bit?
		sz                              ;if not
		rr      rx_byte_1               ;  then save bit
		sz                             	;and skip to end
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		mov	w,rx_ring_cnt_1		; Is the receive buffer already full?
		inc	wreg
		xor	w,#rx_ring_size_1	; Compare with the buffer size
		sz
		jmp	:rx_ok			; Not full
		clrb	CTS_1			; CTS = false - not ready to receive data
		clrb	DSR_1			; DSR = false - not ready to receive data
		setb	buffer_oe_1		; Signal receive buffer overflow
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
:rx_ok		setb	CTS_1			; CTS = true - ready to receive data
		setb	DSR_1			; DSR = true - ready to receive data
		mov	w,rx_byte_1		; Save the received byte in global
		mov	isr_temp,w
		mov	w,rx_ring_ip_1		; Store character in receive buffer
		mov	fsr,w			; Set indirect address
		mov	w,isr_temp			; temp must be global
		mov	indf,w			; Store the received byte
		bank	uart_rx			; Restore the bank

		ringadv	rx_ring_ip_1,rx_ring_1,rx_ring_size_1

		inc	rx_ring_cnt_1		; Increment the ring buffer count
:done
endm

	;*********************************************************************************
	; VP: uart_2_transmit_fast
	; 57.6K - 115.2Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
UART2_TRANSMIT_FAST	macro
		bank    uart_2_tx		;switch to serial register bank
		decsz	tx_divide_2		;ready to transmit bit?
		jmp	uart_2_rx_fast
		mov	tx_divide_2,divisor_2	;reload baud period
		test    tx_count_2              ;are we sending?
		sz
		jmp	:txbit			;yes, send next bit
		mov	w,tx_ring_cnt_2		;is tx ring empty?
		snz
		jmp	uart_2_rx_fast		;yes, go to :transmit_out
	;	jnb	DTR_2,uart_2_rx_fast
	;	jnb	RTS_2,uart_2_rx_fast
:txring		mov	w,tx_ring_op_2		;move one character from the ring to the
		mov	fsr,w			; transmitter using indirect addressing
		mov	w,indf
		bank	uart_2_tx		;switch back to the uart bank
		not     w                       ;ready bits (inverse logic)
		mov     tx_high_2,w             ; store data byte
		setb    tx_low_2.7              ; set up start bit
		mov     tx_count_2,#10          ;1 start + 8 data + 1 stop bit
		dec	tx_ring_cnt_2		;decrement tx ring byte count

		ringadv	tx_ring_op_2,tx_ring_2,tx_ring_size_2	;advance ring pointer
	
:txbit		clc                             ;ready stop bit
		rr      tx_high_2               ; and shift to next bit
		rr      tx_low_2                ;
		dec     tx_count_2		;decrement bit counter
		movb    tx_pin_2,/tx_low_2.6    ;output next bit

uart_2_rx_fast	bank    uart_rx			;switch to serial register bank
	        movb    c,rx_pin_2              ;get current rx bit
		test    rx_count_2              ;currently receiving byte?
		sz
		jmp     :rxbit                  ;if so, jump ahead
		mov     w,#9                    ;in case start, ready 9 bits
		sc                              ;skip ahead if not start bit
		mov     rx_count_2,w            ;it is, so renew bit count
		clc
		bank    uart_2_tx
		mov	w,>>divisor_2
		add	w,divisor_2
		bank    uart_rx
		mov     rx_divide_2,w		;ready 1.5 bit periods
:rxbit          decsz   rx_divide_2		;middle of next bit?
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		bank    uart_2_tx
		mov	w,divisor_2		;yes, reload 1 bit period
		bank    uart_rx
		mov	rx_divide_2,w
		dec     rx_count_2              ;last bit?
		sz                              ;if not
		rr      rx_byte_2               ;  then save bit
		sz                             	;and skip to end
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
		mov	w,rx_ring_cnt_2		; Is the receive buffer already full?
		inc	wreg
		xor	w,#rx_ring_size_2	; Compare with the buffer size
		sz
		jmp	:rx_ok			; Not full
		clrb	CTS_2			; CTS = false - not ready to receive data
		clrb	DSR_2			; DSR = false - not ready to receive data
		setb	buffer_oe_2		; Signal receive buffer overflow
IFDEF INLINE_VP
		jmp	:done
ELSE
		retp				; Return to the interrupt handler
ENDIF
:rx_ok		setb	CTS_2			; CTS = true - ready to receive data
		setb	DSR_2			; DSR = true - ready to receive data
		mov	w,rx_byte_2		; Save the received byte in global
		mov	isr_temp,w
		mov	w,rx_ring_ip_2		; Store character in receive buffer
		mov	fsr,w			; Set indirect address
		mov	w,isr_temp			; temp must be global
		mov	indf,w			; Store the received byte
		bank	uart_rx			; Restore the bank

		ringadv	rx_ring_ip_2,rx_ring_2,rx_ring_size_2

		inc	rx_ring_cnt_2		; Increment the ring buffer count
:done
endm

;*****************************************************************************************
; Interrupt Service Routine
;*****************************************************************************************
	       ORG     0                       ;interrupt starts at 0h
interrupt

IFDEF AUTO_BAUD
		call @uart_1_autobaud
  IF SX_TYPE=1
		call @uart_2_autobaud
  ENDIF
ENDIF


	;*********************************************************************************
	; Virtual Peripheral: Universal Asynchronous Receiver Transmitter (UART) 
	;
	;   This routine sends and receives 2 channels of RS232C serial data, 
	; currently configured (though modifications can be made) for the popular
	; "No parity-checking, 8 data bit, 1 stop bit" (N,8,1) data format.
	;
	; RECEIVING:
	;   Whenever a valid byte of data has been received, it is put into
	; the rx_ring FIFO buffer. The address pointer rx_ring_ip and FIFO byte count  
	; rx_ring_cnt are also incremented with every new byte. A receive buffer overflow
	; is signaled by the uart_rx_oflow flag.
	;
	; TRANSMITTING:
	;   The transmit routine requires the data to be inverted and loaded (tx_high+tx_low)
	; register pair (with the inverted 8 data bits stored in tx_high and tx_low bit 7 set 
	; high to act as a start bit). Then the number of bits ready for transmission
	; (10=1 start + 8 data + 1 stop) must be loaded into the tx_count register.
	; As soon as this latter is done, the transmit routine immediately begins sending the data.
	;   The handshaking signals RTS and CTS have also been implemented. 
	; The CTS output is used to indicate that the DCE (SX) is ready to receive data. 
	; The RTS input is used to indicate that the DTE (terminal) is ready for receiving. 
	; Data is only sent if the RTS line is active.
	;
	; This routine has a varying execution rate and therefore should always be
	; placed after any timing-critical virtual peripherals such as timers,
	; adcs, pwms, etc.
	; Note: The transmit and receive routines are independent and either may be
	;	removed, if not needed, to reduce execution time and memory usage,
	;	as long as the initial "BANK serial" (common) instruction is kept.
	;
	;       Input variable(s) : tx_low (only high bit used), tx_high, tx_count
	;       Output variable(s) : rx_flag, rx_byte
	;       Variable(s) affected : tx_divide, rx_divide, rx_count
	;       Flag(s) affected : rx_flag
	;	Size : Transmit - 34 bytes + 1 byte shared with receive code
	;		Receive - 41 bytes + 1 byte shared with transmit code
	;       Timing (turbo) : 
	;	       Transmit - (a) [multiplexing] 2 cycles
	;			  (b) [not sending] 5 cycles
	;			  (c) [sending] 18 cycles
	;                         (d) [buffer empty] 13 cycles
	;		          (e) [start sending] 34 cycles
	;			  + 1 cycle shared with RX code ("bank" instr.)
	;		Receive - (a) [multiplexing] 2 cycles
	;			  (b) [not receiving] 9 cycles
	;			  (c) [start receiving] 15 cycles
	;			  (d) [receiving, awaiting bit] 13 cycles
	;			  (e) [receiving, bit ready] 20 cycles
	;		          (f) [receiving, last bit] 37 cycles
	;                         (g) [receiving, buffer full] 25 cycles
	;
	;
	;*********************************************************************************

IFDEF INLINE_VP		; we are inlining the VP functions, to save 7 cycles per UART
UART1		jnb	uart1_en,UART2		;execute UART channel 1 only when enabled
		jb	speed_1,uart_1_transmit_fast
		UART1_TRANSMIT
		jmp	UART2
uart_1_transmit_fast
		UART1_TRANSMIT_FAST
UART2

IF SX_TYPE = 1		;only compile if target is SX52

		jnb	uart2_en,uarts_done	;execute UART channel 2 only when enabled
		jb	speed_2,uart_2_transmit_fast
		UART2_TRANSMIT
		jmp	uarts_done
uart_2_transmit_fast
		UART2_TRANSMIT_FAST
ENDIF
ELSE			; we are calling the VP functions, not inlining
UART1		jnb	uart1_en,UART2		;execute UART channel 1 only when enabled
		jb	speed_1,:fast
		call	@uart_1_transmit
		jmp	UART2
:fast
		call	@uart_1_transmit_fast
UART2

IF SX_TYPE = 1		;only compile if target is SX52

		jnb	uart2_en,uarts_done	;execute UART channel 2 only when enabled
		jb	speed_2,:fast
		call	@uart_2_transmit
		jmp	uarts_done
:fast
		call	@uart_2_transmit_fast
ENDIF
ENDIF

uarts_done

;*****************************************************************************************
; End of Interrupt Service Routine
;*****************************************************************************************
isr_end
	;*********************************************************************************
	; Set Interrupt Rate
	;*********************************************************************************
		mov     w,#-int_period          ;interrupt every 'int_period' clocks
		retiw                           ;exit interrupt

;*****************************************************************************************
; RESET VECTOR 
;*****************************************************************************************

	;*********************************************************************************
	; Program execution begins here on power-up or after a reset
	;*********************************************************************************
reset_entry
IF SX_TYPE = 0	;SX28
		mov	m,#$0f			;point mode to port I/O's
		mov      ra,#RA_init		;initialize port RA
		mov     !ra,#RA_IO		;Set RA in/out directions
		mov      rb,#RB_init		;initialize port RB
		mov     !rb,#RB_IO		;Set RB in/out directions
		mov      rc,#RC_init		;initialize port RC
		mov     !rc,#RC_IO		;Set RC in/out directions

ELSE		;SX52
		mov	m,#$1f			;point mode to port I/O's
		mov      ra,#RA_init		;initialize port RA
		mov     !ra,#RA_IO		;Set RA in/out directions
		mov      rb,#RB_init		;initialize port RB
		mov     !rb,#RB_IO		;Set RB in/out directions
		mov      rc,#RC_init		;initialize port RC
		mov     !rc,#RC_IO		;Set RC in/out directions
		mov      rd,#RD_init		;initialize port RD
		mov     !rd,#RD_IO		;Set RD in/out directions
		mov      re,#RE_init		;initialize port RE
		mov     !re,#RE_IO		;Set RE in/out directions
ENDIF

	;*********************************************************************************
	; Clear all Data RAM locations
	;*********************************************************************************
IF SX_TYPE = 0	;SX28
		clr	fsr			;reset all ram banks
:zero_ram	sb	fsr.4			;are we on low half of bank?
		setb	fsr.3			;If so, don't touch regs 0-7
		clr	ind			;clear using indirect addressing
		incsz	fsr			;repeat until done
		jmp	:zero_ram

ELSE		;SX52
		mov	w,#$0a			;reset all ram starting at 08h
		mov	fsr,w
:zero_ram	clr	ind			;clear using indirect addressing
		incsz	fsr			;repeat until done
		jmp	:zero_ram

		clrb	fsr.7
ENDIF

		call	@uarts_init		;initialise the uarts

IF RTCC_prescalar = 1
		mov     !option,#%10011111      ;enable rtcc interrupt
ENDIF
IF RTCC_prescalar = 2
		mov     !option,#%10010000      ;enable rtcc interrupt
ENDIF

IFNDEF	AUTO_BAUD
		mov	w,#B115200
		call	@set_bps_rate_1
IF SX_TYPE = 1		;only compile if target is SX48/52
		mov	w,#B115200
		call	@set_bps_rate_2
ENDIF
ENDIF

		jmp	@main

;*****************************************************************************************
; MAIN PROGRAM CODE 
;*****************************************************************************************
		org	$200
main

	;*********************************************************************************
	; Main Program Loop
	;*********************************************************************************
IF SX_TYPE = 0		;only compile if target is SX28

		mov	w,#_hello		;send hello string to channel 1
		call	@send_string_1

:prompt		mov	w,#_prompt		;send prompt to channel 1
		call	@send_string_1

main_loop
		call	@get_byte_1		;get byte via UART channel 1
		sz
		call	@send_byte_1		;echo byte back to sender on channel 1

		jmp	main_loop		;return

ELSE

		mov	w,#_hello		;send hello string to channel 2
		call	@send_string_2
		mov	w,#_ch2			;send channel string to channel 2
		call	@send_string_2
		mov	w,#_prompt		;send prompt to channel 2
		call	@send_string_2
		mov	w,#_hello		;send hello string to channel 1
		call	@send_string_1
		mov	w,#_ch1			;send channel string to channel 1
		call	@send_string_1
		mov	w,#_prompt		;send prompt to channel 1
		call	@send_string_1

main_loop
		call	@get_byte_1		;get byte via UART channel 1
		sz
		call	@send_byte_1		;echo byte back to sender on channel 1
		call	@get_byte_2		;get byte via UART channel 2
		sz
		call	@send_byte_2		;echo byte back to sender on channel 2

		jmp	main_loop		;return

; this stuff was left in, to show how to create a 16550 device
cs_loop		
		snb	cs			;wait for chip select active(low)
		jmp	cs_loop			;return

		sb	read			;check for read active(low)
		jmp	:cont			; it's low, must be a request
		sb	write			;check for write active(low)
		jmp	:cont			; it's low, must be a request
		jmp	main_loop		;return
		
:cont		mov	temp,re			;keep only the lower 3 address bits
		and	temp,#$07
		sb	chsl			;if chsl = 0, 
		jmp	channel_2		; then channel 2 is being addressed

channel_1
		snz				;if lower 3 address bits = 0,
		jmp	tx_rx_buffer_1		; then tx/rx buffer is being addressed

		mov	w,#1			;is current address = $01?
		mov	w,temp-w
		snz
		jmp	int_enable_1

		mov	w,#2			;is current address = $02?
		mov	w,temp-w
		snz
		jmp	int_id_1

		mov	w,#3			;is current address = $03?
		mov	w,temp-w
		snz
		jmp	fifo_control_1

		mov	w,#4			;is current address = $04?
		mov	w,temp-w
		snz
		jmp	modem_control_1

		mov	w,#5			;is current address = $05?
		mov	w,temp-w
		snz
		jmp	line_status_1

		mov	w,#6			;is current address = $06?
		mov	w,temp-w
		snz
		jmp	modem_status_1
		jmp	main_loop		;return

tx_rx_buffer_1					;$00 -> Receive Buffer/Transmit Holding Register
		sb	read			;if read bit = 0,
		jmp	:read			; then receive buffer is being addressed
		sb	write			;if write bit = 0,
		jmp	:write			; then transmit holding buffer is being addressed
		jmp	main_loop		;return
:read
		mov	w,#$00			;change data bus to output
		mov	!rb,w	
		call	@get_byte_1		;get byte
		mov	rb,w		;load byte in w on data bus
		jnb	read,$
		mov	w,#$ff			;change data bus to input(hi-Z)
		mov	!rb,w	
		jmp	main_loop		;return
:write
		mov	w,rb			;load byte on data bus in w
		call	@send_byte_1		;send byte
		jnb	write,$
		jmp	main_loop		;return

int_enable_1					;$01 -> Interrupt Enable
		jmp	main_loop		;return

int_id_1					;$02 -> Interrupt ID
		jmp	main_loop		;return

fifo_control_1					;$03 -> FIFO Control
		jmp	main_loop		;return

modem_control_1					;$04 -> MODEM Control
		jmp	main_loop		;return

line_stat_1					;$05 -> Line Status
		snb	read			;if read bit = 1(not active),
		jmp	:write			; then return(not meant to be written to)
:read						; else line status register is being read
		mov	w,#$00			;change data bus to output
		mov	!data_bus,w	
		mov	w,line_status_1		;get line_status
		mov	data_bus,w		;load byte in w on data bus
		mov	w,#$ff			;change data bus to input(hi-Z)
		mov	!data_bus,w	
:write		jmp	main_loop		;return

modem_status_1					;$06 -> MODEM Status
		jmp	main_loop		;return

scratch_1					;$07 -> Scratch
		jmp	main_loop		;return

channel_2
		snz				;if lower 3 address bits = 0,
		jmp	tx_rx_buffer_2		; then tx/rx buffer is being addressed

		mov	w,#1			;is current address = $01?
		mov	w,temp-w
		snz
		jmp	int_enable_2

		mov	w,#2			;is current address = $02?
		mov	w,temp-w
		snz
		jmp	int_id_2

		mov	w,#3			;is current address = $03?
		mov	w,temp-w
		snz
		jmp	fifo_control_2

		mov	w,#4			;is current address = $04?
		mov	w,temp-w
		snz
		jmp	modem_control_2

		mov	w,#5			;is current address = $05?
		mov	w,temp-w
		snz
		jmp	line_status_2

		mov	w,#6			;is current address = $06?
		mov	w,temp-w
		snz
		jmp	modem_status_2
		jmp	main_loop		;return

tx_rx_buffer_2					;$00 -> Receive Buffer/Transmit Holding Register
		sb	read			;if read bit = 0,
		jmp	:read			; then receive buffer is being addressed
		sb	write			;if write bit = 0,
		jmp	:write			; then transmit holding buffer is being addressed
		jmp	main_loop		;return
:read
		mov	w,#$00			;change data bus to output
		mov	!rb,w	
		call	@get_byte_2		;get byte
		mov	rb,w			;load byte in w on data bus
		jnb	read,$
		mov	w,#$ff			;change data bus to input(hi-Z)
		mov	!rb,w	
		jmp	main_loop		;return
:write
		mov	w,rb			;load byte on data bus in w
		call	@send_byte_2		;send byte
		jnb	write,$
		jmp	main_loop		;return

int_enable_2					;$01 -> Interrupt Enable
		jmp	main_loop		;return

int_id_2					;$02 -> Interrupt ID
		jmp	main_loop		;return

fifo_control_2					;$03 -> FIFO Control
		jmp	main_loop		;return

modem_control_2					;$04 -> MODEM Control
		jmp	main_loop		;return

line_stat_2					;$05 -> Line Status
		snb	read			;if read bit = 1(not active),
		jmp	:write			; then return(not meant to be written to)
:read						; else line status register is being read
		mov	w,#$00			;change data bus to output
		mov	!data_bus,w	
		mov	w,line_status_2		;get line_status
		mov	data_bus,w		;load byte in w on data bus
		mov	w,#$ff			;change data bus to input(hi-Z)
		mov	!data_bus,w	
:write		jmp	main_loop		;return

modem_status_2					;$06 -> MODEM Status
		jmp	main_loop		;return

scratch_2					;$07 -> Scratch
		jmp	main_loop		;return

ENDIF

;*****************************************************************************************
; PROGRAM DATA 
;*****************************************************************************************
		org	$400			;must be lower half of page (for calls)
datapage

; String data for user interface (must be in lower half of memory page)
;
_hello		dw	13,10,13,10,'High speed SX DUART Demo 11/01/2004',0
_ch1		dw	13,10,13,10,'Channel 1',0
_ch2		dw	13,10,13,10,'Channel 2',0
_prompt		dw	13,10,'>',0
			; 75  110  134  150  300  600 1200 2400 4800 9600 19200 38400 57600 115200 230400
IF xtal=50000000
;50MHz @ 217
_divisors	dw	3072,2095,1719,1536, 768, 384, 192,  96,  48,  24,   12,    6,    4,     2,     0
ENDIF
IF xtal=75000000
  IF RTCC_prescalar=2
;75MHz, half speed @ 163
_divisors	dw	3067,2091,1717,1534, 767, 383, 192,  96,  48,  24,   12,    6,    4,     2,     0
  ELSE
;75Mhz, @ 217
_divisors       dw         0,3142,2579,2304,1152, 576, 288, 144,  72,  36,   18,    9,    6      3,     0
  ENDIF
ENDIF
;_divisors	dw	0,2304,1536,1048,856,768,384,192,96,94,48,32,24,16,12,6,4,2

;*****************************************************************************************
; SUBROUTINES 
;*****************************************************************************************

	;*********************************************************************************
	; Function: set_bps_rate_1
	; Set the baud rate, based on an index
	; 0 = 75bps
	; 1 = 110bps
	; 2 = 134bps
   	; 3 = 150bps
	; 4 = 300bps
	; 5 = 600bps
	; 6 = 1200bps
	; 7 = 2400bps
	; 8 = 4800bps
	; 9 = 9600bps
	; 10 = 19200bps
	; 11 = 38400bps
	; 12 = 57600bps
	; 13 = 115200bps
	;
	;*********************************************************************************
set_bps_rate_1
		mov	m,#4;datapage/100h	; with indirect addressing*
		mov	temp,w
		mov	w,#_divisors
		add	w,temp			;store divisors address
		iread 				; using the mode register
		snz				; if W is zero, invalid bps rate
		retp
		bank	uart_1_tx
		setb	uart1_en
		mov	divisor_1,w
		mov	w,m
		and	w, #$0f
		jnz	:lo_speed
		setb	speed_1
		retp
:lo_speed
		mov	divisor_1+1,w
		clrb	speed_1
		retp
		
IF SX_TYPE = 1		;only compile if target is SX52
	;*********************************************************************************
	; Function: set_bps_rate_2
	; Set the baud rate, based on an index
	;*********************************************************************************
set_bps_rate_2
		mov	m,#4;datapage/100h	; with indirect addressing*
		mov	temp,w
		mov	w,#_divisors
		add	w,temp			;store divisors address
		iread 				; using the mode register
		snz				; if W is zero, invalid bps rate
		retp
		bank	uart_2_tx
		setb	uart2_en
		mov	divisor_2,w
		mov	w,m
		and	w, #$0f
		jnz	:lo_speed
		setb	speed_2
		retp
:lo_speed
		mov	divisor_2+1,w
		clrb	speed_2
		retp
ENDIF

	;*********************************************************************************
	; Function: uarts_init
	; Initialise the UARTs
	;*********************************************************************************
uarts_init	
		jmp	_uarts_init

	;*********************************************************************************
	; Function: get_byte_1
	; Get byte via serial port
	; Byte received is returned in W
	;*********************************************************************************
get_byte_1	bank	uart_rx			; Select the bank
:wait		mov	w,rx_ring_cnt_1		; Get the number of bytes in the rx ring
		snz				; Is the receive ring empty?
		jmp	:return			; Yes, block until not empty
		mov	w,rx_ring_op_1		; Load the ring out pointer
		mov	fsr,w
		mov	w,indf			; Get character from buffer
		mov	temp,w			; Save character in temp
		bank	uart_rx			; Restore the bank

		ringadv	rx_ring_op_1,rx_ring_1,rx_ring_size_1	; Advance ring pointer

		dec	rx_ring_cnt_1		; Decrement rx char count
		sb	CTS_1			; If CTS is set, clear it
		setb	CTS_1			; CTS = true - ready to receive data
		sb	DSR_1			; If DSR is set, clear it
		setb	DSR_1			; DSR = true - ready to receive data
		mov	w,temp			; Return byte in W
		setb	rx_flag_1
		retp
:return		;clr	w			; Return 0 in W
		retp
	;*********************************************************************************
	; Function: get_byte_2
	; Get byte via serial port
	; Byte received is returned in W
	;*********************************************************************************
IF SX_TYPE = 1		;only compile if target is SX52

get_byte_2	bank	uart_rx			; Select the bank
:wait		mov	w,rx_ring_cnt_2		; Get the number of bytes in the rx ring
		snz				; Is the receive ring empty?
		jmp	:return			; Yes, block until not empty
		mov	w,rx_ring_op_2		; Load the ring out pointer
		mov	fsr,w
		mov	w,indf			; Get character from buffer
		mov	temp,w			; Save character in temp
		bank	uart_rx			; Restore the bank

		ringadv	rx_ring_op_2,rx_ring_2,rx_ring_size_2	; Advance ring pointer

		dec	rx_ring_cnt_2		; Decrement rx char count
		sb	CTS_2			; If CTS is set, clear it
		setb	CTS_2			; CTS = true - ready to receive data
		sb	DSR_2			; If DSR is set, clear it
		setb	DSR_2			; DSR = true - ready to receive data
		mov	w,temp			; Return byte in W
		setb	rx_flag_2
		retp
:return		;clr	w			; Return 0 in W
		retp

ENDIF
	;*********************************************************************************
	; Function: send_byte_1
	; Send byte via serial port
	; Byte to be sent should be in W
	;*********************************************************************************
send_byte_1	bank	uart_1_tx		; Select the bank
		mov	temp,w

:wait		mov	w,tx_ring_cnt_1		; Load the current ring contents
		xor	w,#tx_ring_size_1	; Compare to the ring size
		snb	status.2		; Is there room for a character?
		jmp	:wait			; No, block until there is room

		mov	w,tx_ring_ip_1		; Get buffer pointer
		mov	fsr,w
		mov	w,temp	
		mov	indf,w			; Save temp in the ring
		bank	uart_1_tx		; Restore the bank

		ringadv	tx_ring_ip_1,tx_ring_1,tx_ring_size_1	; Advance ring pointer

		inc	tx_ring_cnt_1		; Increment tx char count
		retp                            ;leave and fix page bits

	;*********************************************************************************
	; Function: send_byte_2
	; Send byte via serial port
	; Byte to be sent should be in W
	;*********************************************************************************
IF SX_TYPE = 1		;only compile if target is SX52

send_byte_2	bank	uart_2_tx		; Select the bank
		mov	temp,w

:wait		mov	w,tx_ring_cnt_2		; Load the current ring contents
		xor	w,#tx_ring_size_2	; Compare to the ring size
		snb	status.2		; Is there room for a character?
		jmp	:wait			; No, block until there is room

		mov	w,tx_ring_ip_2		; Get buffer pointer
		mov	fsr,w
		mov	w,temp	
		mov	indf,w			; Save temp in the ring
		bank	uart_2_tx		; Restore the bank

		ringadv	tx_ring_ip_2,tx_ring_2,tx_ring_size_2	; Advance ring pointer

		inc	tx_ring_cnt_2		; Increment tx char count
:return		retp				;leave and fix page bits

ENDIF
	;*********************************************************************************
	; Function: bytes_avail_1
	; Get number of bytes waiting in receive buffer
	; Number of bytes in buffer will be returned in W
	;*********************************************************************************
bytes_avail_1	bank	uart_rx			; Ensure ring variables
		mov	w,rx_ring_cnt_1		; Get receive ring count	
		retp

	;*********************************************************************************
	; Function: bytes_avail_2
	; Get number of bytes waiting in receive buffer
	; Number of bytes in buffer will be returned in W
	;*********************************************************************************
IF SX_TYPE = 1		;only compile if target is SX52

bytes_avail_2	bank	uart_rx			; Ensure ring variables
		mov	w,rx_ring_cnt_2		; Get receive ring count	
		retp

ENDIF
	;*********************************************************************************
	; Function: send_string_1
	; Send string pointed to by address in W register
	; *Note: High nibble into mode register denotes page address of data
	;*********************************************************************************
send_string_1	bank	uart_1_tx
		mov	string1,w		;store string address
	;	jnb	CTS_1,$			;wait for CTS_1 = true - ready to receive data
:loop		mov	w,string1		;read next string character
		mov	m,#4;datapage/100h		; with indirect addressing*
		iread 				; using the mode register
IF SX_TYPE = 0	;SX28
		mov	m,#$0f			;point mode to port I/O's
ELSE		;SX52
		mov	m,#$1f			;point mode to port I/O's
ENDIF
		test	w 			;are we at the last char?
		snz				;if not=0, skip ahead
		retp 				;yes, leave & fix page bits
						;not 0, so send character
		mov	temp,w
:wait		mov	w,tx_ring_cnt_1		; Load the current ring contents
		xor	w,#tx_ring_size_1	; Compare to the ring size
		snb	status.2		; Is there room for a character?
		jmp	:wait			; No, block until there is room

		mov	w,tx_ring_ip_1		; Get buffer pointer
		mov	fsr,w
		mov	w,temp	
		mov	indf,w			; Save temp in the ring
		bank	uart_1_tx		; Restore the bank
		ringadv	tx_ring_ip_1,tx_ring_1,tx_ring_size_1	; Advance ring pointer
		inc	tx_ring_cnt_1		; Increment tx char count

		inc	string1			;point to next character
		jmp	:loop			;loop until done

	;*********************************************************************************
	; Function: send_string_2
	; Send string pointed to by address in W register
	; *Note: High nibble into mode register denotes page address of data
	;*********************************************************************************
IF SX_TYPE = 1		;only compile if target is SX52

send_string_2	bank	uart_2_tx
		mov	string2,w		;store string address
	;	jnb	CTS_2,$			;wait for CTS_2 = true - ready to receive data
:loop		mov	w,string2		;read next string character
		mov	m,#4;datapage/100h		; with indirect addressing*
		iread 				; using the mode register
		mov	m,#$1f			;point mode to port I/O's
		test	w 			;are we at the last char?
		snz				;if not=0, skip ahead
		retp 				;yes, leave & fix page bits
						;not 0, so send character
		mov	temp,w
:wait		mov	w,tx_ring_cnt_2		; Load the current ring contents
		xor	w,#tx_ring_size_2	; Compare to the ring size
		snb	status.2		; Is there room for a character?
		jmp	:wait			; No, block until there is room

		mov	w,tx_ring_ip_2		; Get buffer pointer
		mov	fsr,w
		mov	w,temp	
		mov	indf,w			; Save temp in the ring
		bank	uart_2_tx		; Restore the bank
		ringadv	tx_ring_ip_2,tx_ring_2,tx_ring_size_2	; Advance ring pointer
		inc	tx_ring_cnt_2		; Increment tx char count

		inc	string2			;point to next character
		jmp	:loop			;loop until done
		
ENDIF

_uarts_init	bank	uart_rx			; Select the bank
		clr	rx_ring_cnt_1		; The receive ring is empty
		mov	w,#rx_ring_1
		mov	rx_ring_ip_1,w		; Set the in and out pointers to the start of
		mov	rx_ring_op_1,w		; the receive ring

IF SX_TYPE = 1		;only compile if target is SX52
		clr	rx_ring_cnt_2		; The receive ring is empty
		mov	w,#rx_ring_2
		mov	rx_ring_ip_2,w		; Set the in and out pointers to the start of
		mov	rx_ring_op_2,w		; the receive ring
ENDIF
		bank	uart_1_tx	
		clr	tx_ring_cnt_1		; The transmit ring is empty
		mov	w,#tx_ring_1
		mov	tx_ring_ip_1,w		; Set the in and out pointers to the start of
		mov	tx_ring_op_1,w		; the transmit ring

IF SX_TYPE = 1		;only compile if target is SX52
		bank	uart_2_tx	
		clr	tx_ring_cnt_2		; The transmit ring is empty
		mov	w,#tx_ring_2
		mov	tx_ring_ip_2,w		; Set the in and out pointers to the start of
		mov	tx_ring_op_2,w		; the transmit ring
		setb	uart2_en		;enable UART channel 2
ENDIF
		retp

;*****************************************************************************************
; Jump Table for Page 2 
;*****************************************************************************************
		org	$600
IFDEF AUTO_BAUD
	;*********************************************************************************
	; Virtual Peripheral: UART Autobaud (channel 1)
	;
	; This routine adds Autobaud capability to the UARTs by incrementing an 8-bit count
	; while the rx line is low. If a known character (the 'a' or 'A', $61 or $41 in this case)
	; is input, the count will be proportional to the bit rate of the received datastream.
	;*********************************************************************************
uart_1_autobaud	
		snb	uart1_en		;Don't run if UART channel 1 is already running
		jmp	:autobaud1_done

	;	jnb	RTS_1,:autobaud1_done	; if RTS = false, so DTE has nothing to send
	;	jnb	DTR_1,:autobaud1_done	; if DTR = false, so DTE is not ready to receive
		setb	CTS_1			; CTS = true - ready to receive data
		setb	DSR_1			; DSR = true - ready to receive data
		bank	uart_1_tx
		snb	lo_detected_1		;low detected on previous pass, start count
		jmp	:start_count
		snb	rx_pin_1		;wait for rx line go low
		jmp	:autobaud1_done		;rx line is high, exit
		setb	lo_detected_1		;start counting during low pulse
:start_count	snb	rx_pin_1		;increment count only when rx line is low
		jmp	:test_result		;rising edge after low pulse, test result
:inc_low	inc	divisor_1		;increment count while low
		snz
		inc	divisor_1+1
		jmp	:autobaud1_done

:test_result
		mov	w,divisor_1		;divisor_1(16-bit) contains baudrate divisor
		mov	tx_divide_1,w
		mov	w,divisor_1+1
		mov	tx_divide_1+1,w
		setb	uart1_en		;enable uarts

		mov	w,#2^$ff		;Check to see if baud > 57.6Kbps
		add	w,tx_divide_1
		snc				;skip if less than 2
		jmp	:comp			;jump if greater than 2

:no_comp	setb	speed_1			; then set speed_1 to indicate fast UART rate
		jmp	:setup_rx_115

:comp		dec	divisor_1		;trim divisor_1
		dec	tx_divide_1		;trim tx_divide_1
		not	tx_divide_1		;compliment tx_divide_1
		not	tx_divide_1+1		;compliment tx_divide_1+1

:setup_rx
		bank	uart_1_tx
		clc
		mov	w,>>divisor_1+1		;reload 1/2 bit period divisor_1(16-bit)
		bank    uart_rx	
		mov	rx_divide_1+1,w
		bank	uart_1_tx
		mov	w,>>divisor_1
		bank    uart_rx	
		mov	rx_divide_1,w
		mov     w,#9                    ;ready 9 bits
		mov     rx_count_1,w            ;renew bit count
		not	rx_divide_1		;compliment rx_divide_1
		not	rx_divide_1+1		;compliment rx_divide_1+1
		jmp	:autobaud1_done

:setup_rx_115
		bank    uart_rx	
		mov     w,#9                    ;ready 9 bits
		mov     rx_count_1,w            ;renew bit count
		mov	rx_divide_1,#1
:autobaud1_done
		retp

	;*********************************************************************************
	; Virtual Peripheral: UART Autobaud (channel 2)
	;
	; This routine adds Autobaud capability to the UARTs by incrementing an 8-bit count
	; while the rx line is low. If a known character (the 'a' or 'A', $61 or $41 in this case)
	; is input, the count will be proportional to the bit rate of the received datastream.
	;*********************************************************************************
IF SX_TYPE=1
uart_2_autobaud
		snb	uart2_en		;Don't run if UART channel 1 is already running
		jmp	:autobaud2_done

	;	jnb	RTS_2,:autobaud2_done	; if RTS = false, so DTE has nothing to send
	;	jnb	DTR_2,:autobaud2_done	; if DTR = false, so DTE is not ready to receive
		setb	CTS_2			; CTS = true - ready to receive data
		setb	DSR_2			; DSR = true - ready to receive data
		bank	uart_2_tx
		snb	lo_detected_2		;low detected on previous pass, start count
		jmp	:start_count
		snb	rx_pin_2		;wait for rx line go low
		jmp	:autobaud2_done		;rx line is high, exit
		setb	lo_detected_2		;start counting during low pulse
:start_count	snb	rx_pin_2		;increment count only when rx line is low
		jmp	:test_result		;rising edge after low pulse, test result
:inc_low	inc	divisor_2		;increment count while low
		snz
		inc	divisor_2+1
		jmp	:autobaud2_done

:test_result
		mov	w,divisor_2		;divisor_1(16-bit) contains baudrate divisor
		mov	tx_divide_2,w
		mov	w,divisor_2+1
		mov	tx_divide_2+1,w
		setb	uart2_en		;enable uarts

		mov	w,#2^$ff		;Check to see if baud > 57.6Kbps
		add	w,tx_divide_2
		snc				;skip if less than 2
		jmp	:comp			;jump if greater than 2

:no_comp	setb	speed_2			; then set speed_1 to indicate fast UART rate
		jmp	:setup_rx_115

:comp		dec	divisor_2		;trim divisor_1
		dec	tx_divide_2		;trim tx_divide_1
		not	tx_divide_2		;compliment tx_divide_1
		not	tx_divide_2+1		;compliment tx_divide_1+1

:setup_rx
		bank	uart_2_tx
		clc
		mov	w,>>divisor_2+1		;reload 1/2 bit period divisor_1(16-bit)
		bank    uart_rx	
		mov	rx_divide_2+1,w
		bank	uart_2_tx
		mov	w,>>divisor_2
		bank    uart_rx	
		mov	rx_divide_2,w
		mov     w,#9                    ;ready 9 bits
		mov     rx_count_2,w            ;renew bit count
		not	rx_divide_2		;compliment rx_divide_1
		not	rx_divide_2+1		;compliment rx_divide_1+1
		jmp	:autobaud2_done

:setup_rx_115
		bank    uart_rx	
		mov     w,#9                    ;ready 9 bits
		mov     rx_count_2,w            ;renew bit count
		mov	rx_divide_2,#1
:autobaud2_done
		retp
ENDIF
ENDIF

IFNDEF INLINE_VP
uart_1_transmit_fast
		jmp	_uart_1_transmit_fast
IF SX_TYPE = 1
uart_2_transmit_fast
		jmp	_uart_2_transmit_fast
ENDIF

	;*********************************************************************************
	; VP: uart_1_transmit
	; 110 - 57.6Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
uart_1_transmit
		UART1_TRANSMIT
		retp				; Return to the interrupt handler

	;*********************************************************************************
	; VP: uart_2_transmit
	; 110 - 57.6Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
IF SX_TYPE = 1		;only compile if target is SX52

uart_2_transmit
		UART2_TRANSMIT
		retp				; Return to the interrupt handler

ENDIF
	;*********************************************************************************
	; VP: uart_1_transmit_fast
	; 57.6K - 115.2Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
_uart_1_transmit_fast
		UART1_TRANSMIT_FAST
		retp				; Return to the interrupt handler

IF SX_TYPE=1
	;*********************************************************************************
	; VP: uart_2_transmit_fast
	; 57.6K - 115.2Kbaud UART with RTS/CTS handshake
	; ** Part of the Interrupt Service Routine **
	;*********************************************************************************
_uart_2_transmit_fast
		UART2_TRANSMIT_FAST
		retp				; Return to the interrupt handler
ENDIF
ENDIF

;*****************************************************************************************
END		;End of program code
;*****************************************************************************************



file: /Techref/scenix/lib/io/osi2/serial/DUART_0412_JB.SRC, 60KB, , updated: 2004/11/19 15:12, local time: 2024/12/8 20:14,
TOP NEW HELP FIND: 
18.97.14.82:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://www.piclist.com/techref/scenix/lib/io/osi2/serial/DUART_0412_JB.SRC"> scenix lib io osi2 serial DUART_0412_JB</A>

Did you find what you needed?

  PICList 2024 contributors:
o List host: MIT, Site host massmind.org, Top posters @none found
- Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.
 

Welcome to www.piclist.com!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  .