;*****************************************************************************************
; Copyright © [01/26/1999] Scenix Semiconductor, Inc. All rights reserved.
;
; Scenix Semiconductor, Inc. assumes no responsibility or liability for
; the use of this [product, application, software, any of these products].
; Scenix Semiconductor conveys no license, implicitly or otherwise, under
; any intellectual property rights.
; Information contained in this publication regarding (e.g.: application,
; implementation) and the like is intended through suggestion only and may
; be superseded by updates. Scenix Semiconductor makes no representation
; or warranties with respect to the accuracy or use of these information,
; or infringement of patents arising from such use or otherwise.
;*****************************************************************************************
; 
; Filename:	lcd8xmpl.src	
;
; Authors:	Chris Fogelklou at Scenix Semiconductor
;		
;		
;
; Revision:	1.00
;
; Part:		SX28AC datecode 9932AB
; Freq:		50Mhz
; Compiled using Parallax SX-Key software v1.07 and SASM 1.40
;
; Date Written: Thursday, August 20, 1998.
;
; Last Revised: Tuesday November 23, 1999.
;
; Program Description:
;
; This is simple code to demonstrate how to use an SX chip to interface 
; with an LCD display.  It initializes the display and infinitely loops,
; printing "Scenix. " to the display.  This code will work with any type of 
; HITACHI HD44780 driven display (1*16, 2*16, 1*20, etc...).   
; It does not efficiently use the processor.
; (It contains a wait loop, as well as several delays).  This example
; code is simply a good program to build upon.  ;
;
; lcd_init
; Because the LCD should only need to be initialized once, the LCD_Init 
; routine does not return until it is fully completed.  Comments in
; LCD_Init suggest changes for any number of different settings.  
; (eg. more/fewer display lines, cursor direction, display shifting...)
; CALLS:
;  -lcd_write_command
;  -lcd_write_data
;  -lcd_wait_busy
;  -delay	
;
; 
; lcd_write_command
; This subroutine is called to write a command to the LCD, such as 
; 'clear screen and return home'.  The command to be written is passed in
; inside the W register.
; CALLS:
;  -nopdel
;  -delay
;
;
; lcd_write_data
; This subroutine is called to write data to the LCD, such as a character
; to be displayed.  Like lcd_write_command, lcd_write_data accepts the
; data in the W register.
; CALLS:
;  -nopdel
;  -delay
;
;
; lcd_wait_busy
; This subroutine does not return until the LCD is ready to accept more
; data/commands.  
; CALLS:
;  -nopdel
;  -delay
;
;
; nopdel
; A simple subroutine containing 8 nops, returning after the nops.  
;
;
; delay
; This subroutine delays for (w-1)*20us at 50MIPS, (w-1)*1ms at 1MIPS
;
; 
; REGISTER USAGE
; The only registers used in this program are
; dlycnt1
; dlycnt2
; in the "delay_regs" bank
;
;	
;
; Revision History:
;
;*****************************************************************************************
; Integrated into Scenix VP template.  November 25 1999
; 
;*****************************************************************************************
; Target SX
; Uncomment one of the following lines to choose the SX18AC, SX20AC, SX28AC, SX48BD/ES,
; SX48BD, SX52BD/ES or SX52BD. For SX48BD/ES and SX52BD/ES, uncomment both defines,
; SX48_52 and SX48_52_ES.
;*****************************************************************************************
;SX18_20
SX28
;SX48_52
;SX48_52_ES

;*****************************************************************************************
; Assembler Used
; Uncomment the following line if using the Parallax SX-Key assembler. SASM assembler
; enabled by default.
;*****************************************************************************************
SX_Key

	;*********************************************************************************
	; Assembler directives:
	;	high speed external osc, turbo mode, 8-level stack, and extended option reg.
	;
	;	SX18/20/28 - 4 pages of program memory and 8 banks of RAM enabled by default.
	;	SX48/52 - 8 pages of program memory and 16 banks of RAM enabled by default.
	;                
	;*********************************************************************************

IFDEF SX_Key 				;SX-Key Directives
  IFDEF SX18_20				;SX18AC or SX20AC device directives for SX-Key
		device	SX18L,oscxt4,turbo,stackx_optionx
  ENDIF
  IFDEF SX28				;SX28AC device directives for SX-Key		
		device	SX28L,oscxt4,turbo,stackx_optionx
  ENDIF
  IFDEF SX48_52_ES			;SX48BD/ES or SX52BD/ES device directives for SX-Key
		device	oschs,turbo,stackx,optionx
  ELSE
    IFDEF SX48_52				;SX48/52/BD device directives for SX-Key
		device	oschs2,stackx_optionx
    ENDIF
  ENDIF
		freq	50_000_000
ELSE  					;SASM Directives
  IFDEF SX18_20				;SX18AC or SX20AC device directives for SASM
		device	SX18,oschs2,turbo,stackx,optionx
  ENDIF
  IFDEF SX28				;SX28AC device directives for SASM
		device	SX28,oschs2,turbo,stackx,optionx
  ENDIF
  IFDEF SX48_52_ES			;SX48BD/ES or SX52BD/ES device directives for SASM
		device	SX52,oschs,turbo,stackx,optionx
  ELSE
    IFDEF SX48_52			;SX48BD or SX52BD device directives for SASM
		device	SX52,oschs2,stackx,optionx   
    ENDIF
  ENDIF
ENDIF
		id	'LCD VP  '			;
		reset	reset_entry		; set reset vector

;*****************************************************************************************
; Macros
;*****************************************************************************************

	;*********************************************************************************
	; Macro: _bank
	; Sets the bank appropriately for all revisions of SX.
	;
	; This is required since the bank instruction has only a 3-bit operand, it cannot
	; be used to access all 16 banks of the SX48/52. For this reason FSR.4 (for SX48/52BD/ES)
	; or FSR.7 (SX48/52bd production release) needs to be set appropriately, depending
	; on the bank address being accessed. This macro fixes this.
	;
	; So, instead of using the bank instruction to switch between banks, use _bank instead.
	; 
	;*********************************************************************************
_bank	macro	1
	bank	\1

	IFDEF SX48_52
	  IFDEF SX48_52_ES
	    IF \1 & %00010000		;SX48BD/ES and SX52BD/ES (engineering sample) bank instruction
		setb	fsr.4		;modifies FSR bits 5,6 and 7. FSR.4 needs to be set by software.
	    ENDIF
	  ELSE
	    IF \1 & %10000000		;SX48BD and SX52BD (production release) bank instruction 
		setb	fsr.7		;modifies FSR bits 4,5 and 6. FSR.7 needs to be set by software.
	    ELSE
		clrb	fsr.7
	    ENDIF
	  ENDIF
	ENDIF
	endm

	;*********************************************************************************
	; Macro: _mode
	; Sets the MODE register appropriately for all revisions of SX.
	;
	; This is required since the MODE (or MOV M,#) instruction has only a 4-bit operand. 
	; The SX18/20/28AC use only 4 bits of the MODE register, however the SX48/52BD have 
	; the added ability of reading or writing some of the MODE registers, and therefore use
	; 5-bits of the MODE register. The  MOV M,W instruction modifies all 8-bits of the 
	; MODE register, so this instruction must be used on the SX48/52BD to make sure the MODE
	; register is written with the correct value. This macro fixes this.
	;
	; So, instead of using the MODE or MOV M,# instructions to load the M register, use
	;  _mode instead.
	; 
	;*********************************************************************************
_mode	macro	1
	IFDEF SX48_52
		mov	w,#\1&$1f	;loads the M register correctly for the SX48BD and SX52BD
		mov	m,w
	ELSE
		mov	m,#\1&$0f	;loads the M register correctly for the SX18AC, SX20AC
					;and SX28AC
	ENDIF
	endm

;*****************************************************************************************
; Data Memory address definitions
; These definitions ensure the proper address is used for banks 0 - 7 for 2K SX devices
; (SX18/20/28) and 4K SX devices (SX48/52). 
;*****************************************************************************************
IFDEF SX48_52

global_org	=	$0A
bank0_org	=	$00
bank1_org	=	$10
bank2_org	=	$20
bank3_org	=	$30
bank4_org	=	$40
bank5_org	=	$50
bank6_org	=	$60
bank7_org	=	$70

ELSE

global_org	=	$08
bank0_org	=	$10
bank1_org	=	$30
bank2_org	=	$50
bank3_org	=	$70
bank4_org	=	$90
bank5_org	=	$B0
bank6_org	=	$D0
bank7_org	=	$F0

ENDIF
;*****************************************************************************************
; Global Register definitions
; NOTE: Global data memory starts at $0A on SX48/52 and $08 on SX18/20/28.
;*****************************************************************************************
		org     global_org

function_temp	equ	global_org+1
global_temp	equ	global_org+2


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

	;*********************************************************************************
	; Bank 0
	;*********************************************************************************
		org     bank0_org

bank0		=	$


	;*********************************************************************************
	; Bank 1
	;*********************************************************************************
		org     bank1_org

bank1		=	$

dlycnt1		ds	1
dlycnt2		ds	1


	;*********************************************************************************
	; Bank 2
	;*********************************************************************************
		org     bank2_org

bank2		=	$


	;*********************************************************************************
	; Bank 3
	;*********************************************************************************
		org     bank3_org

bank3		=	$


	;*********************************************************************************
	; Bank 4
	;*********************************************************************************
		org     bank4_org

bank4		=	$


	;*********************************************************************************
	; Bank 5
	;*********************************************************************************
		org     bank5_org

bank5		=	$


	;*********************************************************************************
	; Bank 6
	;*********************************************************************************
		org     bank6_org

bank6		=	$


	;*********************************************************************************
	; Bank 7
	;*********************************************************************************
		org     bank7_org

bank7		=	$


IFDEF SX48_52
	;*********************************************************************************
	; Bank 8
	;*********************************************************************************
		org	$80	;bank 8 address on SX52

bank8		=	$


	;*********************************************************************************
	; Bank 9
	;*********************************************************************************
		org	$90	;bank 9 address on SX52

bank9		=	$


	;*********************************************************************************
	; Bank A
	;*********************************************************************************
		org	$A0	;bank A address on SX52

bankA		=	$


	;*********************************************************************************
	; Bank B
	;*********************************************************************************
		org	$B0	;bank B address on SX52

bankB		=	$


	;*********************************************************************************
	; Bank C
	;*********************************************************************************
		org	$C0	;bank C address on SX52

bankC		=	$


	;*********************************************************************************
	; Bank D
	;*********************************************************************************
		org	$D0	;bank D address on SX52

bankD		=	$


	;*********************************************************************************
	; Bank E
	;*********************************************************************************
		org	$E0	;bank E address on SX52

bankE		=	$


	;*********************************************************************************
	; Bank F
	;*********************************************************************************
		org	$F0	;bank F address on SX52

bankF		=	$


ENDIF
;*****************************************************************************************
; Port Assignment
;*****************************************************************************************

RA_init		equ	%00000000		;SX18/20/28/48/52 port A latch init
RA_io		equ	%00000000		;SX18/20/28/48/52 port A DDIR value
RB_init		equ	%00000000		;SX18/20/28/48/52 port B latch init
RB_io		equ	%00000000		;SX18/20/28/48/52 port B DDIR value
RC_init		equ	%00000000		;SX18/20/28/48/52 port C latch init
RC_io		equ	%11111010		;SX18/20/28/48/52 port C DDIR value

IFDEF SX48_52
RD_init		equ	%11111111		;SX48/52 port D latch init
RD_io		equ	%11111111		;SX48/52 port D DDIR value
RE_init		equ	%11111111		;SX48/52 port E latch init
RE_io		equ	%11111111		;SX48/52 port E DDIR value
ENDIF

;*********************************************************************************
; Pin Definitions
;*********************************************************************************

lcd_control	=	ra

lcd_RS		=	ra.1		; 0 = instruction, 1 = data
lcd_RW		=	ra.2		; 0 = write, 1 = read
lcd_E		=	ra.3		; 1,1-->0 is the LCD enable

lcd_data	= 	rb

lcd_DB0		=	rb.0		; DB0 = Data bus line 0 (LSB)
lcd_DB1		=	rb.1
lcd_DB2		=	rb.2
lcd_DB3		=	rb.3
lcd_DB4		=	rb.4
lcd_DB5		=	rb.5
lcd_DB6		=	rb.6
lcd_DB7		=	rb.7		; DB7 = Data bus line 7 (MSB)


;*****************************************************************************************
; Program constants
;*****************************************************************************************

int_period	equ	217


;*****************************************************************************************
; LCD_Interface Constants.
;  Commands
LCD_Clear		equ	%00000001
LCD_Cursor_Home		equ	%00000010
LCD_Entry_Mode		equ	%00000100
LCD_Display_control	equ	%00001000
LCD_Cursor		equ	%00010000
LCD_Function		equ	%00100000
LCD_Set_CGRam		equ	%01000000
LCD_Set_DDRam		equ	%10000000
;  Control Bits
LCD_S			equ	%00000001	; Display Shift
LCD_B			equ	%00000001	; Cursor Blink
LCD_ID			equ	%00000010	; Cursor Position Decrement
LCD_C			equ	%00000010	; Cursor off/ on
LCD_RL			equ	%00000100	; Cursor direction (Right = 1 left =0)
LCD_F			equ	%00000100	; Character resolution 1= 5x10, 0= 5x7
LCD_D			equ	%00000100	; Display 0n = 1 off = 0
LCD_SC			equ	%00001000	; Shift 0=cursor 1=diaplay
LCD_N			equ	%00001000	; Number od lines 0 for 1 line 
LCD_DL			equ	%00010000	; Data lines 0 for 4 data lines 1 for 8 data lines
LCD_BF			equ	%10000000	; Busy Flag,  0 = not busy

LCD_Delay		equ	4		; waste time between characters for tcyc value

;*****************************************************************************************
; Interrupt Service Routine
;*****************************************************************************************
; Note: The interrupt code must always originate at address $0.
;
; Interrupt Frequency = (Cycle Frequency / -(retiw value))  For example:
; With a retiw value of -217 and an oscillator frequency of 50MHz, this
; code runs every 4.34us.
;*****************************************************************************************
		org     $0
interrupt					;3


	;*********************************************************************************
	; Virtual Peripheral: 
	;
	;
	;	Input variable(s): 
	;	Output variable(s): 
	;	Variable(s) affected: 
	;	Flag(s) affected: 
	;*********************************************************************************
label



	;*********************************************************************************
	; Virtual Peripheral: 
	;
	;
	;	Input variable(s): 
	;	Output variable(s): 
	;	Variable(s) affected: 
	;	Flag(s) affected: 
	;*********************************************************************************
label1

	;*********************************************************************************
	; Set Interrupt Rate
	;*********************************************************************************
isr_end		mov	w,#-int_period		;refresh RTCC on return
		retiw				;return from the interrupt
						; = 1/(int_period*RTCC prescaler*1/50MHz)
						; = 1/(217*1*20ns) = 4.34us
;*****************************************************************************************
; End of the Interrupt Service Routine
;*****************************************************************************************

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

	;*********************************************************************************
	; Program execution begins here on power-up or after a reset
	;*********************************************************************************
reset_entry		
	;*********************************************************************************
	; Initialise all port configuration
	;*********************************************************************************

		_mode	$01f			; point MODE to write DDIR
						;*(5-bit value used to ensure correct value
						; for SX48/52, only 4-bits of this value are
						; used on SX18/20/28)
		mov     w,#RA_init            	; Initialize data latches for
		mov     ra,w			; port A.
		mov	w,#RA_io		; Initialize data direction register for		
		mov	!ra,w			; port A.
		mov     w,#RB_init          	; Initialize data latches for
		mov     rb,w			; port B.
		mov	w,#RB_io		; Initialize data direction register for
		mov	!rb,w			; port B.
		mov     w,#RC_init          	; Initialize data latches for
		mov     rc,w			; port C.
		mov	w,#RC_io		; Initialize data direction register for
		mov	!rc,w			; port C.

IFDEF SX48_52
		mov     w,#RD_init          	; Initialize data latches for
		mov     rd,w			; port D.
		mov	w,#RD_io		; Initialize data direction register for
		mov	!rd,w			; port D.
		mov     w,#RE_init          	; Initialize data latches for
		mov     re,w			; port E.
		mov	w,#RE_io		; Initialize data direction register for
		mov	!re,w			; port E.
ENDIF
	;*********************************************************************************
	; Clear all Data RAM locations
	;*********************************************************************************
IFDEF SX48_52   				;SX48/52 RAM clear routine
		mov	w,#$0a			;reset all ram starting at $0A
		mov	fsr,w
:zero_ram	clr	ind			;clear using indirect addressing
		incsz	fsr			;repeat until done
		jmp	:zero_ram

		_bank	bank0			;clear bank 0 registers
		clr	$10
		clr	$11
		clr	$12
		clr	$13
		clr	$14
		clr	$15
		clr	$16
		clr	$17
		clr	$18
		clr	$19
		clr	$1a
		clr	$1b
		clr	$1c
		clr	$1d
		clr	$1e
		clr	$1f

ELSE     					;SX18/20/28 RAM clear routine
		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
ENDIF
	;*********************************************************************************
	; Initialize program/VP registers
	;*********************************************************************************


	;*********************************************************************************
	; Setup and enable RTCC interrupt, WREG register, RTCC/WDT prescaler
	;*********************************************************************************

RTCC_ON		=	%10000000	;Enables RTCC at address $01 (RTW hi)
					;*WREG at address $01 (RTW lo) by default
RTCC_ID		=	%01000000	;Disables RTCC edge interrupt (RTE_IE hi)
					;*RTCC edge interrupt (RTE_IE lo) enabled by default
RTCC_INC_EXT	=	%00100000	;Sets RTCC increment on RTCC pin transition (RTS hi)
					;*RTCC increment on internal instruction (RTS lo) is default
RTCC_FE		=	%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	=	%00000000	;Assigns prescaler to RTCC (PSA lo)
RTCC_PS_OFF	=	%00001000	;Assigns prescaler to RTCC (PSA lo)
PS_000		=	%00000000	;RTCC = 1:2, WDT = 1:1
PS_001		=	%00000001	;RTCC = 1:4, WDT = 1:2
PS_010		=	%00000010	;RTCC = 1:8, WDT = 1:4
PS_011		=	%00000011	;RTCC = 1:16, WDT = 1:8
PS_100		=	%00000100	;RTCC = 1:32, WDT = 1:16
PS_101		=	%00000101	;RTCC = 1:64, WDT = 1:32
PS_110		=	%00000110	;RTCC = 1:128, WDT = 1:64
PS_111		=	%00000111	;RTCC = 1:256, WDT = 1:128

		mov	w,#RTCC_ON 					;setup option register
		mov	!option,w
		jmp	@main

;*****************************************************************************************
; MAIN PROGRAM CODE 
;*****************************************************************************************

	;*********************************************************************************
	; Main
	;*********************************************************************************
main		
	call 	@lcd_init
	mov 	W, #LCD_Clear		; Clear the screen
	call 	@lcd_write_command
	call 	@lcd_wait_busy	


	;*********************************************************************************
	; Main Program Loop
	;*********************************************************************************
main_loop
	mov 	W, #'S'			; Write "S"	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #'c'			; Write "c"	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #'e'			; Write "e"	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #'n'			; Write "n"	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #'i'			; Write "i"	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #'x'			; Write "x"	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #'.'			; Write "."	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 

	mov 	W, #' '			; Write " "	
	call 	@lcd_write_data
	call 	@lcd_wait_busy	
	mov	W,#LCD_Delay
	call	@delay		; Delay 


	jmp 	main_loop
	





org	$200
;*****************************************************************************************
; Jump table for page 1
; Enables CALLs to functions in the second half of the page 
;*****************************************************************************************
function_label_2	jmp	function_label_2_

;*****************************************************************************************
; Subroutines
;*****************************************************************************************

	;*********************************************************************************
	; Function: 		lcd_init
	; 
	; Inputs:		None
	;	
	; Outputs:		None
	;	
	; Registers affected:	None
	;
	; Functions Called:	lcd_wait_busy,  lcd_write_command
	;
	;*********************************************************************************
lcd_init
	;	Initialize The LCD.

	; First, set the data length, number of display lines, and character font.
	;------------------------------------------------------------------------------------------------------
	;	RS-RA2 R/!W-RA3 DB7-RB7	DB6-RB6	DB5-RB5	DB4-RB4	DB3-RB3	DB2-RB2	DB1-RB1	DB0-RB0	Execution Time
	;	0	0	0	0	1	DL	N	F	*	*	40us
	;------------------------------------------------------------------------------------------------------
	; DL--Interface Data Length  		0 = 4-bit interface		1 = 8-bit interface
	; N --Number of Display Lines		0 = 1 line			1 = 2 lines
	; F --Character Font			0 = 5*7 dots			1 = 5*10 dots

		call 	@lcd_wait_busy		; Wait until the LCD is finished initializing.
		mov 	W, #LCD_Function | LCD_DL | LCD_N
		call 	@lcd_write_command 	; set for for 8 bits, 2 lines, and 5*7 dots
		call 	@lcd_wait_busy		; Wait until the LCD is finished processing.


	; Next, turn the display on, turn the cursor on, and turn cursor blink on (so we know LCD is alive)
	;------------------------------------------------------------------------------------------------------
	;	RS-RA2 R/!W-RA3 DB7-RB7	DB6-RB6	DB5-RB5	DB4-RB4	DB3-RB3	DB2-RB2	DB1-RB1	DB0-RB0	Execution Time
	;	0	0	0	0	0	0	1	D	C	B	40us
	;------------------------------------------------------------------------------------------------------
	; D --Display ON/OFF control		0 = Display OFF			1 = Display ON
	; C --Cursor ON/OFF control		0 = Cursor OFF			1 = Cursor ON
	; B --Blink ON/OFF control		0 = Blink OFF			1 = Blink ON

		clr	W
		call 	@lcd_write_command
		call	@lcd_wait_busy		; Display off

		mov 	W, #LCD_Display_Control | LCD_D | LCD_C | LCD_B 
		call 	@lcd_write_command 	; turn display on, cursor on, and blink on..
		call 	@lcd_wait_busy		; Wait until the LCD is finished processing.

	; Next, set display so that the cursor moves as characters are entered.
	;------------------------------------------------------------------------------------------------------
	;	RS-RA2 R/!W-RA3 DB7-RB7	DB6-RB6	DB5-RB5	DB4-RB4	DB3-RB3	DB2-RB2	DB1-RB1	DB0-RB0	Execution Time
	;	0	0	0	0	0	1	S/C	R/L	*	*	40us
	;------------------------------------------------------------------------------------------------------
	; S/C--Cursor move/Display Shift	0 = Cursor Move			1 = Shift Display 
	; R/L--Shift Direction			0 = Shift left			1 = Shift right

		mov 	W, #LCD_Cursor
		call 	@lcd_write_command 	; set for cursor move and display shift.
		call 	@lcd_wait_busy		; Wait until the LCD is finished processing.

	; Next, set entry mode (cursor move direction, shift or no shift).
	;------------------------------------------------------------------------------------------------------
	;	RS-RA2 R/!W-RA3 DB7-RB7	DB6-RB6	DB5-RB5	DB4-RB4	DB3-RB3	DB2-RB2	DB1-RB1	DB0-RB0	Execution Time
	;	0	0	0	0	0	0	0	1	I/D	S	40us ~ 1.64ms
	;------------------------------------------------------------------------------------------------------
	; I/D--Increment/Decrement address	0 = Decrement Cursor Address	1 = Increment Cursor Address 
	; S  --Display shift			0 = No shift			1 = Shift

		mov 	W, #LCD_Entry_Mode | LCD_ID
		call 	@lcd_write_command 	; set for incrementing address and no shift..
		call 	@lcd_wait_busy		; Wait until the LCD is finished processing.
	
		retp	; Return from lcd_init subroutine.

	;*************************************************************************
	; End of lcd_init subroutine.
	;*************************************************************************


	
	;*********************************************************************************
	; Function:			lcd_write_command 
	; 
	; Inputs:			command  in W
	;	
	; Outputs:			None
	;	
	; Registers affected:		None
	;
	; Functions Called:		None called,  function body and return shared with lcd_write_data
	;
	;*********************************************************************************
lcd_write_command
;------------------------------------------------------------------------------------------------------
; This function writes the command in W to the LCD display, using the 8-bit interface.  The procedure is:
; 1.  Clear RS
; 2.  Set up R/!W
; 3.  Write the data to the port
;------------------------------------------------------------------------------------------------------
	clrb 	lcd_RS		; Drive RS low so LCD knows to write COMMAND.
	jmp 	lcd_write	; goto WRITE code

; body of the function and return are shared by lcd_write_data

	
	;*********************************************************************************
	; Function:			lcd_write_data
	; 
	; Inputs:			command  in W
	;	
	; Outputs:			None
	;	
	; Registers affected:		None
	;
	; Functions Called:		None called,  function body and return shared with lcd_write_data
	;
	;*********************************************************************************
lcd_write_data
;------------------------------------------------------------------------------------------------------
; This function writes the data in W to the LCD display, using the 8-bit interface.
; 1.  Set RS
; 2.  Set up R/!W
; 3.  Write the data to the port
;------------------------------------------------------------------------------------------------------

	setb 	lcd_RS		; Drive RS high so LCD knows to write DATA.
lcd_write	
	mov 	lcd_data,W	; Write the data in W to the port latches.
	mov 	W,#000h		; Write zeroes to the control register to switch the data pins to outputs.
	mov 	!lcd_data,W
	clrb 	lcd_RW 		; Drive R/!W low so LCD knows to WRITE.
	call	@nopdel
	call	@nopdel
	setb 	lcd_E		; Pulse LCD's enable pin.
	call	@nopdel
	call	@nopdel
	clrb 	lcd_E		; Force LCD to latch the data present on the data bus.
	call	@nopdel
	call	@nopdel
	retp


	;*********************************************************************************
	; Function: 			lcd_wait_busy
	; 
	; Inputs:			None
	;	
	; Outputs:			None
	;	
	; Registers affected:		None
	;
	; Functions Called:		nopdel, 
	;
	;*********************************************************************************
lcd_wait_busy
	; waits until the LCD is ready to accept a command.
	;------------------------------------------------------------------------------------------------------
	;		RS-RA2 R/!W-RA3 DB7-RB7	DB6-RB6	DB5-RB5	DB4-RB4	DB3-RB3	DB2-RB2	DB1-RB1	DB0-RB0	Execution Time
	;	0	1	BF	* ------------------DDRAM Address-------------- *	1us
	;------------------------------------------------------------------------------------------------------

		mov 	W, #0FFh	; write ones to the control register to switch the data pins to inputs.
		mov 	!lcd_data,W
		clrb 	lcd_RS		; clear RS for instruction
		setb 	lcd_RW		; set for READ.	
		call	@nopdel
		call	@nopdel
		setb 	lcd_E		; set enable high to read busy flag
		call	@nopdel	
		call	@nopdel		; wait for the LCD to tx data.	
		mov	W,lcd_data
		clrb 	lcd_E		; clear LCD enable
		call	@nopdel
		call	@nopdel
		and 	W, #LCD_BF	; test W for zero (Z is cleared if LCD is busy)
		sb	Z
		jmp	lcd_wait_busy
		setb	lcd_RW
		mov	W,#00h
		mov	!lcd_data,W	; Switch the data pins back to outputs
		call	@nopdel
		call	@nopdel
		call	@nopdel
		retp			; return from subroutine 


	;*********************************************************************************
	; Function: 			nopdel
	; 
	; Inputs:			None
	;	
	; Outputs:			None
	;	
	; Registers affected:		None
	;
	; Functions Called:		None
	;
	;*********************************************************************************
nopdel	;	returns to main program in 11 cycles (11us@1MIPS) from call
	;------------------------------------------------------------------------------------------------------
		nop
		nop 
		nop
		nop
		nop
		nop
		nop
		nop
		retp



	;*********************************************************************************
	; Function: 			delay
	; 
	; Inputs:			delay count in w reg
	;	
	; Outputs:			none
	;	
	; Registers affected:		dlycnt1 and dlycnt2
	;
	; Functions Called:		none
	;
	;*********************************************************************************

delay
	; (delays for [((w-1) * 1ms )] at 1MIPS, or [((w-1) * 20us)] at 50MIPS ... 0<=W<=255) 
	;****************************************************************************************************** 
	; This function delays for ((W-1)*20us), plus/minus a few ns 
	;****************************************************************************************************** 
		bank	bank1
		mov 	dlycnt1,W 
	; 
delay1 
		decsz 	dlycnt1; 
		jmp 	loop1; 
		retp	;	 
 
loop1 
		mov 	w,#166; 
		mov 	dlycnt2,W; 

loop; 
		nop 
		nop 
		nop 
		decsz 	dlycnt2; 
		jmp 	loop; 
		jmp 	delay1; 
	



	;*********************************************************************************
	; Function: 
	; 
	; Inputs:
	;	
	; Outputs:
	;	
	; Registers affected:
	;
	; Functions Called:
	;
	;*********************************************************************************
function_label_2_

		retp

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