0001   0000             ;*******************************************************************************
0002   0000             ;===============================================================================
0003   0000             ; Program: v_scroll.asm
0004   0000             ; programmer(s): Dincer Aydin (dinceraydin@altavista.net)
0005   0000             ; function: vertical scroll effect
0006   0000             ; The effect is the same as the one you can see at the entrance of my LCD pages:
0007   0000             ; http://www.geocities.com/SiliconValley/Circuit/8882/lcd/index.html
0008   0000             ;===============================================================================
0009   0000             ;*******************************************************************************
0010   0000             ; This code requires a 2*16 LCD connected to a 8255 with base address of 00h
0011   0000             ; routines sendcomA & sendcom & sendcharA & sendchar have been tested on 
0012   0000             ; >> 2*16 Hitachi LCD with HD44780 chip 
0013   0000             ; >> Samsung 1*16 LCD with a KS0062F00 chip
0014   0000             ; >> 2*16 Epson LCD marked P300020400 SANTIS 1 ,and 
0015   0000             ; >> noname 1*16 HD44780 based LCD.
0016   0000             ; The Z80 was clocked at 2 MHz and 4,9152 MHz for each display.This was done 
0017   0000             ; because the routines mentioned above take many t states and in most cases 
0018   0000             ; that will be longer that the time a HD44780 will need to execute a command. 
0019   0000             ;
0020   0000             ; Connections:
0021   0000             ; LCD data bus(pins #14-#7) connected to Port A of a 8255 with 00h base address
0022   0000             ; LCD Enable pin(#6) connected to Port C bit #7
0023   0000             ; LCD R/W pin(#5) connected to Port C bit #6
0024   0000             ; LCD RS pin(#4) connected to Port C bit #5
0025   0000             
0026   0000             #define equ .equ
0027   0000             #define end .end
0028   0000             
0029   0000             ;8255 port address(base 00h):	
0030   0000             paadr 		equ 00h		; Address of PortA
0031   0000             pbadr 		equ 01h		; Address of PortB
0032   0000             pcadr 		equ 02h		; Address of PortC
0033   0000             cwadr 		equ 03h		; Address of Control Word
0034   0000             ;stuff to be written into the control word of the 8255:
0035   0000             ;Some of the change the state of the ports and some manipulate
0036   0000             ;bits on port C
0037   0000             allpsin 	equ 9bh		; set all ports to input mode
0038   0000             paincout 	equ 90h		; A input,C output,B output
0039   0000             pandcout	equ 80h		; set all ports to output mode
0040   0000             pacoutbin	equ 82h		; A output,C output,B input
0041   0000             	
0042   0000             ;bit set/reset commands.These bits are the control signals for the LCD
0043   0000             enable 		equ 0fh		; set portC bit #6
0044   0000             disable		equ 0eh		; reset portC bit #6
0045   0000             read 		equ 0dh		; set portC bit #5
0046   0000             write 		equ 0ch		; reset portC bit #5
0047   0000             command 	equ 0ah		; reset portC bit #4
0048   0000             data 		equ 0bh		; set portC bit #4
0049   0000             	
0050   0000             ; Define number of commands and length of string data
0051   0000             numofc 		equ 4h		; number of commands
0052   0000             
0053   0000             	
0054   0000             ; initialization:		
0055   0000 31 00 02    	ld 	sp,200h 	; Set stack pointer
0056   0003 0E 03       	ld 	c,cwadr 
0057   0005 3E 82       	ld 	a,pacoutbin 	; Ports A&C output,B input
0058   0007 ED 79       	out	(c),a
0059   0009             
0060   0009             ; *********It all begins here**********:
0061   0009             ; This part sends commands to initialize the LCD
0062   0009             				
0063   0009 CD 05 01    	call 	delay	
0064   000C 3E 38       	ld 	a,38h		; function set command
0065   000E 06 04       	ld 	b,4		
0066   0010 0E 03       again:	ld 	c,cwadr		
0067   0012 16 0A       	ld 	d,command	
0068   0014 ED 51       	out	(c),d		; select the instruction register 
0069   0016 16 0C       	ld 	d,write
0070   0018 ED 51       	out	(c),d		; reset RW pin for writing to LCD
0071   001A D3 00       	out	(paadr),a	; place the command into portA
0072   001C 16 0F       	ld 	d,enable	
0073   001E ED 51       	out	(c),d		; enable the LCD
0074   0020 16 0E       	ld 	d,disable
0075   0022 ED 51       	out	(c),d		; disable the LCD 
0076   0024 CD 05 01    	call	delay		; wait for a while
0077   0027 10 E7       	djnz	again		; loop till the command is sent 4 times
0078   0029             	
0079   0029             ; send commands to set input mode, cursor,number of lines ,and etc.
0080   0029 21 14 01    	ld 	hl,combegadr 	; set HL to point the first command
0081   002C 06 04       	ld 	b,numofc	; put the number of commands to be sent in B
0082   002E             nextcom:
0083   002E CD C3 00    	call 	sendcom		; send (HL) as a command 
0084   0031 23          	inc 	hl		; point the next command
0085   0032 10 FA       	djnz 	nextcom		; loop till all commands are sent
0086   0034             	
0087   0034             ; Initialization is complete.
0088   0034             
0089   0034             
0090   0034             ; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
0091   0034             ; This part sends strings to the LCD:
0092   0034             numofcts 	equ 6h		; number of characters to scroll
0093   0034             numofd_line1 	equ 0Fh		; define the number of string bytes to be sent to line #1
0094   0034             numofd_line2	equ 08h		; define the number of string bytes to be sent to line #2
0095   0034             
0096   0034             replay:	
0097   0034 3E 01       	ld 	a,01h		; 01h is the "Clear Screen" command
0098   0036 CD C4 00    	call 	sendcomA	; command is sent 
0099   0039             	
0100   0039 3E 40       	ld 	a,40h		; set CGRAM address to 00h command
0101   003B CD C4 00    	call 	sendcomA	; command is sent and the addrss counter is pointing 00h in CGRAM
0102   003E             	
0103   003E AF          	xor 	a		; clear A
0104   003F 06 40       	ld 	b,64		; 64 CGRAM locations
0105   0041             clear:
0106   0041 CD BC 00    	call 	sendcharA	; 00h is written to a CG ram location (i.e it is cleared)
0107   0044 10 FB       	djnz 	clear		; loop till all CGRAM is cleared
0108   0046             				; CGRAM is clear and any garbage is gone
0109   0046             	
0110   0046 3E 80       	ld 	a,80h		; 80h is the "set DDRAM address to 00h" command
0111   0048 CD C4 00    	call 	sendcomA	; command is sent and the addrss counter is pointing 00h in DDRAM
0112   004B             				; Now that DDRAM address is set, let's print the string data
0113   004B 21 18 01    	ld 	hl,first_line	; set HL to point the first string byte
0114   004E 06 0F       	ld 	b,numofd_line1	; put the number of string bytes to be sent in B
0115   0050             nextdata:			
0116   0050 CD BB 00    	call 	sendchar	; send (HL) as string data 
0117   0053 CD 05 01    	call    delay
0118   0056 23          	inc 	hl		; point the next string byte
0119   0057 10 F7       	djnz	nextdata	; loop till all string bytes are sent
0120   0059             	
0121   0059 21 2F 01    	ld 	hl,scrolldat	; make HL point the  bitmap data of the characters to be scrolled
0122   005C CD 78 00    	call 	scroll		; call the routine that will make it scroll
0123   005F             	
0124   005F 3E C4       	ld 	a,0C4h		; set DDRAM address so that the cursor moves to the 4th location of the second line
0125   0061 CD C4 00    	call 	sendcomA	
0126   0064             				; Now that DDRAM address is set, let's print the string data
0127   0064 21 27 01    	ld 	hl,second_line	; set HL to point the first string byte
0128   0067 06 08       	ld 	b,numofd_line2	; put the number of string bytes to be sent in B
0129   0069             nextdata2:			
0130   0069 CD BB 00    	call 	sendchar	; send (HL) as string data 
0131   006C 23          	inc 	hl		; point the next string byte
0132   006D 10 FA       	djnz	nextdata2	; loop till all string bytes are sent
0133   006F             	
0134   006F 21 FF FF    	ld 	hl,0FFFFh
0135   0072 CD 01 01    	call    pdelay
0136   0075             	
0137   0075 C3 34 00    	jp 	replay
0138   0078             ;====================================================================
0139   0078             ; Subroutine name:Scroll
0140   0078             ; programmer: Dincer Aydin
0141   0078             ; input 1: HL pointing the data of the string to scroll
0142   0078             ; input 2: "numofcts" >>the number of the characters in the string to be scrolled
0143   0078             ; output:
0144   0078             ; Registers altered: many
0145   0078             ; function:	
0146   0078             ;====================================================================
0147   0078             scroll:
0148   0078 E5          	push 	hl	;ld hl',hl
0149   0079 D9          	exx 
0150   007A E1          	pop 	hl
0151   007B D9          	exx
0152   007C             	
0153   007C 06 01       	ld b,1		; B is used as line counter
0154   007E 3E 47       	ld a,47h	; A holds the command to set CGRAM 
0155   0080             			; address to the bottom line 
0156   0080             			; of the first custom chatacter in CGRAM 
0157   0080             				
0158   0080             			; later in the program A will be increased by 8 to
0159   0080             			; create the command to set CGRAM address to the same
0160   0080             			; line of the next custom character in CGRAM
0161   0080             			; The value in B = the number of lines to be 
0162   0080             			; written to CGRAM for each character.
0163   0080             			 
0164   0080 CD 05 01    bidaha:	call delay
0165   0083             	
0166   0083 D9          	exx		;ld hl,hl'
0167   0084 E5          	push	hl
0168   0085 D9          	exx 
0169   0086 E1          	pop 	hl
0170   0087             
0171   0087 C5          	push 	bc	; save bc
0172   0088 F5          	push 	af	; save af
0173   0089 CD 99 00    	call 	tkr	; write to CGRAM to display B lines of the bitmap data,
0174   008C             			; starting from the laction specified by the command in A
0175   008C             			; for the first custom character and  A+8n command for the following 
0176   008C             			; custom characters   (n being the number of the custom character)
0177   008C             			; Need it be said that A and B are Z80 registers,not the hex numbers A and B ?
0178   008C F1          	pop 	af	; restore bc
0179   008D C1          	pop 	bc	; restore af
0180   008E 3D          	dec 	a	; derease A to create a new set CGRAM address command
0181   008F 04          	inc 	b	; increase the number of lines to be sent a time
0182   0090 F5          	push 	af	; save af
0183   0091 3E 09       	ld 	a,09h	; see if all the lines are done (i.e. see if the aanimation is completed)
0184   0093 B8          	cp 	b
0185   0094 C8          	ret 	z	; return if so
0186   0095 F1          	pop 	af	; else restore af
0187   0096 C3 80 00    	jp 	bidaha	; and go shift all custom characters one more line up
0188   0099             	
0189   0099             
0190   0099 16 06       tkr:	ld 	d,numofcts	; d stores the number of custom characters to be scrolled
0191   009B             	
0192   009B F5          other:	push 	af	; save bc
0193   009C C5          	push 	bc	; save af
0194   009D CD AF 00    	call 	ilk	; send the specified number of bytes belonging to this custom character
0195   00A0 C1          	pop 	bc	; restore bc
0196   00A1 F1          	pop 	af	; restore af
0197   00A2             	
0198   00A2 C6 08       	add 	a,8h	; a is increased by 8 to create the command to set CGRAM address to the same
0199   00A4             			; line for the next custom character
0200   00A4             			; add 8 to l so that (HL) points to the bitmap data that belongs to the new CGRAM address
0201   00A4 F5          	push 	af 	
0202   00A5 3E 08       	ld 	a,8
0203   00A7 85          	add 	a,l
0204   00A8 6F          	ld 	l,a
0205   00A9 F1          	pop 	af
0206   00AA 15          	dec 	d	; see if all the custom characters got their share
0207   00AB C2 9B 00    	jp 	nz,other 	; if not, go on with the next one
0208   00AE C9          	ret		; else return
0209   00AF             
0210   00AF E5          ilk:	push hl		; save HL
0211   00B0 CD C4 00    	call sendcomA	; send the commnad in A to set the CGRAM addres
0212   00B3 CD BB 00    next:	call sendchar	; send the byte in (HL) to that CGRAM location
0213   00B6 23          	inc hl		;
0214   00B7 10 FA       	djnz next	; dec B to see is all the lines of this character are done. Loop till they are done.
0215   00B9 E1          	pop hl		; restore HL
0216   00BA C9          	ret	        ; the specified number of bytes belonging to this custom character are sent.It is time to return.
0217   00BB             	
0218   00BB             ; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
0219   00BB             	
0220   00BB             ; ====================================================================
0221   00BB             ; Subroutine name:sendcomA & sendcom & sendcharA & sendchar 
0222   00BB             ; programmer:Caner Buyuktuna & Dincer Aydin
0223   00BB             ; input:A or (HL)
0224   00BB             ; output:
0225   00BB             ; Registers altered:A 
0226   00BB             ; function:	sendcharA sends the data in A to the LCD
0227   00BB             ;  	  	sendchar sends the data in (HL) to the LCD
0228   00BB             ; 		sendcomA sends the command in A to the LCD
0229   00BB             ;  		sendcom sends the command in (HL) to the LCD	
0230   00BB             ; ====================================================================
0231   00BB             sendchar:
0232   00BB 7E          	ld 	a,(hl)		; put the data to be sent to the LCD in A
0233   00BC             sendcharA:	
0234   00BC C5          	push 	bc		; save BC
0235   00BD D5          	push 	de		; save DE
0236   00BE 1E 0B       	ld 	e,data		;  
0237   00C0 C3 C8 00    	jp 	common
0238   00C3             
0239   00C3             sendcom:
0240   00C3 7E          	ld 	a,(hl)
0241   00C4             sendcomA:	
0242   00C4 C5          	push 	bc		; save BC
0243   00C5 D5          	push 	de		; save DE   
0244   00C6 1E 0A       	ld 	e,command	   
0245   00C8             
0246   00C8             common:	
0247   00C8 CD DE 00    	call 	bfcheck    	; See if the LCD is busy. If it is busy wait,till it is not.
0248   00CB ED 59       	out 	(c),e		; Set/reset RS accoring to the content of register E
0249   00CD 16 0C       	ld 	d,write		
0250   00CF ED 51       	out	(c),d		; reset RW pin for writing to LCD
0251   00D1 D3 00       	out	(paadr),a	; place data/instrucrtion to be written into portA
0252   00D3 16 0F       	ld 	d,enable	
0253   00D5 ED 51       	out	(c),d		; enable the LCD
0254   00D7 16 0E       	ld 	d,disable	
0255   00D9 ED 51       	out 	(c),d		; disable the LCD 
0256   00DB D1          	pop 	de		; restore DE
0257   00DC C1          	pop 	bc		; restore BC
0258   00DD C9          	ret			; return
0259   00DE             ; ====================================================================
0260   00DE             ; Subroutine name:bfcheck
0261   00DE             ; programmer:Dincer Aydin
0262   00DE             ; input:
0263   00DE             ; output:
0264   00DE             ; Registers altered:D
0265   00DE             ; function:Checks if the LCD is busy and waits until it is not busy
0266   00DE             ; ====================================================================
0267   00DE             
0268   00DE             bfcheck:
0269   00DE F5          	push 	af		; save AF
0270   00DF 0E 03       	ld 	c,cwadr
0271   00E1 16 90       	ld 	d,paincout
0272   00E3 ED 51       	out 	(c),d		; make A input,C output,B output
0273   00E5 16 0D       	ld 	d,read		
0274   00E7 ED 51       	out 	(c),d		; set RW pin for reading from LCD
0275   00E9 16 0A       	ld 	d,command
0276   00EB ED 51       	out	(c),d		; select the instruction register 
0277   00ED             check_again:	
0278   00ED 16 0F       	ld 	d,enable	
0279   00EF ED 51       	out	(c),d		; enable the LCD
0280   00F1 DB 00       	in 	a,(paadr)	; read from LCD
0281   00F3 16 0E       	ld 	d,disable
0282   00F5 ED 51       	out 	(c),d		; disable the LCD 
0283   00F7 07          	rlca			; rotate A left through C flag to see if the busy flag is set
0284   00F8 DA ED 00    	jp 	c,check_again	; if busy check it again,else continue
0285   00FB 16 80       	ld 	d,pandcout	
0286   00FD ED 51       	out	(c),d		; set all ports to output mode
0287   00FF F1          	pop 	af		; restore AF
0288   0100 C9          	ret
0289   0101             
0290   0101             ;====================================================================
0291   0101             ; Subroutine name:DELAY 
0292   0101             ; programmer(s):Dincer Aydin
0293   0101             ; input:-
0294   0101             ; output:-
0295   0101             ; Registers altered:-
0296   0101             ; function:delay 
0297   0101             ; for more delay you can add a few nops or or some junk commands using the index 
0298   0101             ; registers
0299   0101             ;====================================================================
0300   0101 E5          pdelay:	push 	hl
0301   0102 C3 09 01    	jp 	comdelay
0302   0105 E5          delay:	push    hl
0303   0106 21 22 22    	ld 	hl,2222h
0304   0109             comdelay:	
0305   0109 2D          	dec	l
0306   010A 00          	nop
0307   010B C2 09 01    	jp 	nz,comdelay
0308   010E 25          	dec	h
0309   010F C2 09 01    	jp 	nz,comdelay
0310   0112 E1          	pop	hl
0311   0113 C9          	ret
0312   0114             
0313   0114             ;====================================================================
0314   0114             ; commands and strings
0315   0114             combegadr:
0316   0114 01 80 0C 06 	.db 01h,80h,0ch,06h  	; clear display,set DD RAM adress,
0317   0118             				; turn on display with cursor hidden,set entry mode
0318   0118             
0319   0118             first_line:
0320   0118 564552544943	.text "VERTICAL " 
0320   011E 414C20
0321   0121 000102030405	.db 00h,01h,02h,03h,04h,05h 		; first 5 custom characters
0322   0127             second_line:
0323   0127 497320436F6F	.text "Is Cool!"
0323   012D 6C21
0324   012F             
0325   012F             scrolldat:
0326   012F 8F90908E8181	.db 143,144,144,142,129,129,158,128 ; S
0326   0135 9E80
0327   0137 80808E909091	.db 128,128,142,144,144,145,142,128 ; c
0327   013D 8E80
0328   013F 808096999090	.db 128,128,150,153,144,144,144,128 ; r
0328   0145 9080
0329   0147 80808E919191	.db 128,128,142,145,145,145,142,128 ; o
0329   014D 8E80
0330   014F 8C8484848484	.db 140,132,132,132,132,132,142,128 ; l
0330   0155 8E80
0331   0157 8C8484848484	.db 140,132,132,132,132,132,142,128 ; l
0331   015D 8E80
0332   015F             
0333   015F             endtasm: Number of errors = 0