st7/       

	; ---------------------------------------------------------
	; GAME - Nit4Spid
	; Piotr Bania (12.01.2008)
	; http://www.piotrbania.com
	; ---------------------------------------------------------


	
	TITLE	"starter.asm"
	MOTOROLA
	
	#INCLUDE "st72334.inc"		; ST72C334 registers and memory mapping file 
	#INCLUDE "LED.inc"  
	#INCLUDE "KEYS.inc"
	#INCLUDE "LCD.inc"  
	#INCLUDE "TIME.inc" 
	#INCLUDE "RTC.inc"           
	                    
	                    
	#DEFINE			WYSCIGOWKA_DOL	#0
	#DEFINE			WYSCIGOWKA_GORA	#1                    
	                                  
	#DEFINE			GEN_WCALE	0	                                  
	#DEFINE			GEN_GORA 	1
	#DEFINE			GEN_DOL		2 
	#DEFINE			ROT_PRZE	#$40	; (53h-14h)		
	#DEFINE			ROT_END		#$27
	#DEFINE			ROT_START	#$13  
	                                              
	                                              
	#define			ROT_PART1_END   #$13
	#define			ROT_PART1_START	#$0
	#define			ROT_PART2_END	#$27
	#define			ROT_PART2_START	#$14   
	#define			ROT_PART1_END_PLUS #$14
	
	#define			KRZAK_CHAR	#'#'
	#define			WIPE_CHAR	#' '
	#define			WYSCIGOWKA_CHAR	#'*'		                                              
	                              
	#define			KLAWISZ_UP	#$18
	#define			KLAWISZ_DOWN	#$19	                              
	                                                 
	                                                 
	#define			LEVEL_TIME_3	#50
	#define			LEVEL_TIME_2	#100
	#define			LEVEL_TIME_1	#150
	                                                 
	                                              
	
	#DEFINE			LCD_MEM_SIZE	$27
                   
	

;*******************************************************************************
;	Program entry
;*******************************************************************************
	BYTES
	segment 'ram0'	; definicje zmiennych o dostepie "krótkim"


.baner_addr		DS.W	1
	

.short_variable		DS.B	1  
.licznik		DS.B	1
.lPBDR			DS.B	1
                      

.type_gen		DS.B	1                                        
.random_seed1		DS.W	1
.random_seed2		DS.W	1
.rotate_byte		DS.B	1 
.wyscigowka_pos		DS.B	1  
.status_gry		DS.B	1  
.level_time		DS.B	1

  
                                
.poprzedni_byte		DS.B	1                                                        
                                                        
                                                        
                                                        
	; -------------------------------------------------------
	; BUFOR PAMIECI LCD:
	; 00h-13h GORNA LINIA WRZUCANE NA 00h-13h
	; 14h-27h DOLNA LINIA WRZUCANE NA 40h-53h
	; -------------------------------------------------------                                                        
.lcd_mem		DS.B	LCD_MEM_SIZE			
	     


	WORDS
	segment 'rom'	; program	
	




	
.main	

   	rim    
    	                    
	; ---------------------------------------------------------------------------------------
	; INICJACJA 
	; ---------------------------------------------------------------------------------------
	
  	                    
   	call	init
   	call	init_licznik
   	call	init_randomizer     
                                	 
	call	LCD_INIT		
	call	LED_INIT 
	call	KEYS_INIT 
	call	LCD_CLEAR           
                     
	call	clear_LCD_MEM                  
	call	store_LCD_MEM                         
		                           	
   	call	powitanie
                                                                           
    ld	X,#0  	
    ld	type_gen,X         	
    inc	X            
    ld	status_gry,X
    ld	wyscigowka_pos,X   
    call	set_level
     	                    
     	                    
 	; ---------------------------------------------------------------------------------------
	; PETLA GLOWNA 
	; ---------------------------------------------------------------------------------------
	    
		   	
main_loop:          
	call	LED_CLEAR                   	
	ld		X,type_gen
	call	LED_WRITE

             
    ld	X,status_gry     
	cp	X,#1		; czy gra aktywna?
	jreq	continue_gra
	 
	call	wypisz_game_over 
	jp	delay_it	
     
     
init_PC:
	bset	PCDDR, #7
	bset	PCOR, #7
	bset	PCDR, #7     
	ret

continue_gra:
	; ----------------------------------
	; WYWOLANIE PETLI GLOWNEJ GRY
	; ---------------------------------		               
	call	go_gra	
	                             
	

	; ---------------------------------------------------------------------------------------
	; OPOZNIENIE GRY ZALEZNIE OD LEVELU
	; ---------------------------------------------------------------------------------------
	
	
	ld	A,level_time                   
delay_it:	                             
	push	A
	call	TIME_5MS
	pop	A
	dec	A    	                                    
	                                             
	call	wyscigowka_handler	
	jrne	delay_it
	   	                            	            		                                 	                                    
     jp	main_loop
     jp	*        
 
init_licznik:
	clr	TACLR      

	; ustawianie prescalera (podzielnik)
 	bres	TACR2,#2
	bset	TACR2,#3        
	ret
                        
   	; ---------------------------------------------------
   	; F: INIT_RANDOMIZER                                                   
   	; Inicjuje wartosc "random_seed1/2".
   	; ---------------------------------------------------
   	
init_randomizer:
	call	ODBIERZ_ZEGAR
	ld	A,SEKUNDY
	xor	A,SETNE_SEKUNDY
	xor	A,MINUTY         
	ld	random_seed1,A
	
	
	ld	A,GODZINY
	xor	A,DNI_TYGODNIA
	xor	A,DNI_MIESIACA
	ld	random_seed2,A
   	ret
   	         
    	                       
  	; ---------------------------------------------------
   	; F: GET_RANDOM                                              
   	; Funkcja zwraca liczbe random do rejestru A
   	; ---------------------------------------------------
   	
get_random:	
	ld	A,random_seed1
	dec	random_seed2
	xor	A,random_seed2
	
	ld	X,A
	and	A,#%0011        
	ld	rotate_byte,A
	inc	A
	push	A
	
rol_it:
	rlc	X   
	dec	A
	jrne	rol_it
		 
	ld	random_seed1,X 
	pop	A
	
	push	A
	add	A,random_seed1
	ld	random_seed1,A
	pop	A
	adc	A,random_seed2  
	add	A,rotate_byte
	
	
	ld	X,A
	ld	A,rotate_byte      
	inc	A
ror_it:                      
	rrc	X
	dec	A    
	jrne	ror_it
	
	ld	A,X
	neg	A
	sub	A,3
	xor	A,random_seed2
	ld	random_seed2,A
	         
	push	A	         
	call	ODBIERZ_ZEGAR
	pop	A
	xor	A,SEKUNDY			
	ret
    	                       
   	; ---------------------------------------------------
   	; F: RANDOM_PRZ                                              
   	; Funkcja zwraca liczbe z przedzialu 0-1
   	; ---------------------------------------------------
   	
czy_gen:   	
random_prz:                                     
	push	X
	call	get_random
	and	A,#1               
        pop	X
        ret         
    	                                   
    	                                   
  	; ---------------------------------------------------
   	; F: przerwanie_TOF                                            
   	; Obsluga przerwania TOF
   	; ---------------------------------------------------
   	
przerwanie_TOF:    
	ld	A,TASR
	ld	A,TACLR
	ld	A,PDDR

	call	wyscigowka_handler	               
	
                       
ret_przerw:
	iret            
                       
                                    
        ; ----------------------------------------------------
        ; F: clear_LCD_MEM
        ; Czysci pamiec zmiennej lcd_mem
        ; ----------------------------------------------------   
           
                       
clear_LCD_MEM:
	ld	X,LCD_MEM_SIZE          
;	clr	A
	ld	A,WIPE_CHAR     
clear_LCD_MEM_loop:                     
	ld	(lcd_mem,X),A
;	inc	A
	dec	X
	jrne	clear_LCD_MEM_loop	
	ld	(lcd_mem,X),A    
	
	ld	X,ROT_PART2_END
	ret                                              
                       
        ; ----------------------------------------------------
        ; F: shift_LCD_MEM
        ; Rotuje pamiec o 1 w lewo, ostatni bajt gubiony
        ; ----------------------------------------------------

shift_LCD_MEM:                                                

	; rotacja pierwszej czesci od 13h do 0               
	ld	X,ROT_PART1_END
	
	ld	Y,WIPE_CHAR  
	ld	poprzedni_byte,Y	           


shift_LCD_loop1:              
	ld	A,(lcd_mem,X)			; A= biezacy bajt
	push	A
	ld	A,poprzedni_byte
	ld	(lcd_mem,X),A
	pop	A
	
    ld	poprzedni_byte,A
   
    cp	X,#0
    jreq	shift_LCD_loop1_end    
	dec	X
	jp	shift_LCD_loop1
	
	
		
shift_LCD_loop1_end:
	; rotacja czesci 2 od (27h do 14h)
	ld	X,ROT_PART2_END    
	ld	Y,WIPE_CHAR  
	ld	poprzedni_byte,Y
	                                	
	                                
	                                
shift_LCD_loop2:  
	ld	A,(lcd_mem,X)			; A= biezacy bajt
	push	A
	ld	A,poprzedni_byte
	ld	(lcd_mem,X),A
	pop	A
	
    ld	poprzedni_byte,A

	cp	X,ROT_PART2_START
	jreq	shift_LCD_loop2_end	
	
	dec	X
	jp	shift_LCD_loop2

			
shift_LCD_loop2_end:
	ret
                    
                    
        ; ----------------------------------------------------
        ; F: store_LCD_MEM
        ; Zapisuje pamiec z buffora lcd_mem na pamiec LCD
        ; zgodnie z reprezentacja przedstawiona w skrypcie
        ; ----------------------------------------------------
store_LCD_MEM:	                                         

	call	LCD_CLEAR

	; wjazd pierwszy zapisujemy wszystko od 0 do 13h
	ld	X,#$0
	call	LCD_POZYCJA                         	
	clr	X

	
store_LCD_MEM_loop1:
	push	X
	call	LCD_POZYCJA	
	pop	X
	     
	push	X  
	ld	X,(lcd_mem,X)                   ; X = znak spod lcd_mem+X
	call	LCD_WRITE	
	pop	X
                                        
	inc	X
                                 

	cp	X,ROT_PART1_END_PLUS
	jrne	store_LCD_MEM_loop1		; powtorz dopoki nie dojedziemy do 13h
	
	          
	; jazda numer dwa zaczynam od adresu 40h
	ld	X,#$40
	call	LCD_POZYCJA
	                         
	; zacznij wpisywac z buffora z pozycji 14h	                         
	ld	X,ROT_PART2_START                                                                              
	dec	X                
	
	   
		
store_LCD_MEM_loop2:
	inc	X                         
	push	X
	ld	X,(lcd_mem,X)	
	; X = znak
	call	LCD_WRITE
	pop	X            
	
	
	cp	X,ROT_PART2_END
	jrne	store_LCD_MEM_loop2                                               	                                                                              
	
	
	ret        
                    
	
   	; ---------------------------------------------------
   	; F: go_gra                                           
   	; Petla glowna gry
   	; ---------------------------------------------------
                
                  
go_gra:   
           
                                                          
	call	collision_detection 
	
	ld	A,status_gry 
	cp	A,#0
	jrne	go_gra_continue
	ret	        
	        
go_gra_continue:	  	                                                             
	call	wpisz_krzaki   
	call	switch_type_gen 

	call	shift_LCD_MEM
	call	store_LCD_MEM      
	                                                
	call	wyswietl_wyscigowke
	call	set_level
	               		
	ret                        
	
  	; ---------------------------------------------------
   	; F: set_level
   	; Funkcja zapisuje aktualny level bazujac na klawiszach
   	; PB0-PB2
   	; ---------------------------------------------------            
          
set_level:  
	push	A                                                 
	btjt	PBDR,#0,ustaw_level_1  
	btjt	PBDR,#1,ustaw_level_2
	btjt	PBDR,#2,ustaw_level_3	

	
ustaw_level_1:					; domyslny
	ld	A,LEVEL_TIME_1
	ld	level_time,A
	jp 	set_level_ret
	
ustaw_level_2:
	ld	A,LEVEL_TIME_2
	ld	level_time,A
	jp 	set_level_ret


ustaw_level_3:
	ld	A,LEVEL_TIME_3
	ld	level_time,A
	jp 	set_level_ret
	


set_level_ret:  
	pop	A
  	ret
  
         
        ; ------------------------------------------------- 
	; F: wyscigowka_handler                            
	; okresla polozenie zaleznie od klawiatury
	; -------------------------------------------------        
wyscigowka_handler:    

	;	na portach
	btjf	PFDR,#0,w_poz_gora
	btjf	PBDR,#4,w_poz_dol
	jp	wyscigowka_handler_ret

w_poz_dol:	
	ld	A,WYSCIGOWKA_DOL
	ld	wyscigowka_pos,A	
	jp	wyscigowka_handler_ret                        
		                        
	                        
	
w_poz_gora:
	ld	A,WYSCIGOWKA_GORA
	ld	wyscigowka_pos,A

	
wyscigowka_handler_ret:   
	ret	
	                                          
	                                          
	; ------------------------------------------------- 
        ; F: collision_detection                            
        ; Detekcja kolizji
        ; -------------------------------------------------        
collision_detection:   
 	ld	A,wyscigowka_pos
	cp	A,WYSCIGOWKA_GORA	
	jreq	check_collision_UP
	
		
	; sprawdzane kolizji na DOLE
	ld	X,#$14			; --> czy dolny znak to krzak
	ld	X,(lcd_mem,X)
	cp	X,KRZAK_CHAR
	jreq	collision_detected			   
	jp	collision_detection_ret
	
	
check_collision_UP:                     
	clr	X
	ld	X,(lcd_mem,X)
	cp	X,KRZAK_CHAR
	jreq	collision_detected			   
			
collision_detection_ret:
	ret 	
 
collision_detected:         
	clr	X
	ld      status_gry,X	; status_gry = 0 -> nie gram
	ret
	 
	
	

        ; ------------------------------------------------- 
	; F: wyswietl_wyscigowke                            
	; Rysuje wyscigowke zaleznie od zmiennej "wyscigowka_pos"  
	; 0 - DOL / 1 - GORA
	; -------------------------------------------------        

	
	
wyswietl_wyscigowke:
	ld	A,wyscigowka_pos
	cp	A,WYSCIGOWKA_GORA	
	jreq	wyswietl_wyscig_up 
	
	ld	X,#$40      			; <-- dolna linia LCD
	call	LCD_POZYCJA   
	ld	X,WYSCIGOWKA_CHAR
	call	LCD_WRITE
	jp	wyswietl_wyscigowke_ret

	
	
wyswietl_wyscig_up:
	clr	X          			; <-- gorna linia LCD	
	call	LCD_POZYCJA
	ld	X,WYSCIGOWKA_CHAR
	call	LCD_WRITE
		
wyswietl_wyscigowke_ret:
	ret				       
                
       
                     
    	                                   
  	; ---------------------------------------------------
   	; F: wpisz_krzaki                                            
   	; Funkcja wpisuje krzaki zaleznie od zmiennej typ_gen 
   	; na pamiec lcd_mem
   	; ---------------------------------------------------
                                           
wpisz_krzaki:   
	ld	A,type_gen
	cp	A,#GEN_GORA
	jreq	wpisz_krzak_gora	   
	cp	A,#GEN_DOL
	jreq	wpisz_krzak_dol 
	jp	wpisz_krzak_ret  
	                        
	                        
wpisz_krzak_gora:              
	ld	X,ROT_PART1_END
	ld	A,KRZAK_CHAR
	ld	(lcd_mem,X),A
	jp	wpisz_krzak_ret


wpisz_krzak_dol:	                        
	ld	X,ROT_PART2_END
	ld	A,KRZAK_CHAR
	ld	(lcd_mem,X),A
	jp	wpisz_krzak_ret	
	                        
                
wpisz_krzak_ret:
	ret                
                      
                      
	; -----------------------------------------------------
	; GENEROWANIE KRZAKU NA GORZE CZY NA DOLE?
	; Z WYKRYWANIEM KOLIZJI :)
	; -----------------------------------------------------                      
                      

switch_type_gen:                
        ; switch(type_gen)
	ld	A,type_gen

	cp	A,#GEN_WCALE
	jreq	type_GEN_WCALE

	cp	A,#GEN_GORA
	jreq	type_GEN_GORA
	
	
	  
	; GENEROWAC KRZAK NA DOLE?
	; CZY_GEN zwraca 0-NIE GENERUJ/1-GENERUJ w A  
type_GEN_DOL:  
	call	czy_gen                             
	sll	A
	ld	type_gen,A
	jp	ret_GEN

	; GENEROWAC KRZAK NA GORZE?
	; CZY_GEN zwraca 0-NIE GENERUJ/1-GENERUJ w A  
	
type_GEN_GORA:                    
	call	czy_gen  
	ld	type_gen,A
	jp	ret_GEN
	
			                   	
type_GEN_WCALE:                            
	; najpierw czy generowac na gorze?
	call	czy_gen
	ld	type_gen,A
	cp	A,#1
	jreq	ret_GEN		; zagenerowano na gorze
	
	
	; czy generowac na gorze?
	call	czy_gen
	sll	A
	ld	type_gen,A
	cp	A,#2
	jreq	ret_GEN		; zagenerowane na dole
	

	; wcale nie zagenerowano			
ret_GEN:	
	ret
	   	
	   	
new_game:
	call	clear_LCD_MEM                  
	call	store_LCD_MEM   


	ld	X,#0  	
     	ld	type_gen,X         	
     	inc	X            
     	ld	status_gry,X
     	ld	wyscigowka_pos,X   
     	call	set_level
     	ret
	   	
	   	
                                                      
; MAKRO laduje adres argumentu tekst do zmiennej baner_addr
zaladuj_addr 	MACRO tekst
		ld	A,#tekst.h
		ld	{baner_addr},A	 
		ld	A,#tekst.l
		ld	{baner_addr+1},A			
		MEND                                      
         
                                      
	; ---------------------------------------------------                                      
        ; TEKSTY
        ; ---------------------------------------------------
                                      
powitanie_tekst		DC.B	" ... Nit4Spid! ...               ",0  
powitanie_tekst1        DC.B	"   programmed by                 ",0
powitanie_tekst2	DC.B	" ... Piotr Bania ...             ",0
powitanie_tekst3	DC.B	"  *** GET READY ***              ",0
powitanie_tekst4	DC.B	"        !GO!                     ",0 
game_over_tekst 	DC.B	"  *** GAME OVER ***              ",0   
game_new_game		DC.B	"PRESS 'PB3' TO START            ",0

powitanie:
	zaladuj_addr powitanie_tekst
	call	wypisz_tekst     	
	zaladuj_addr powitanie_tekst1
	call	wypisz_tekst
	zaladuj_addr powitanie_tekst2
	call	wypisz_tekst    
	zaladuj_addr powitanie_tekst3
	call	wypisz_tekst    
	zaladuj_addr powitanie_tekst4
	call	wypisz_tekst    		    	
	
	ret            
         
wypisz_game_over:
	zaladuj_addr game_over_tekst
	call	wypisz_tekst 
	
	zaladuj_addr game_new_game	
	call	wypisz_tekst  
	call	LCD_CLEAR
 

	btjf	PBDR,#3,no_game	
	
	call	new_game
	zaladuj_addr powitanie_tekst4
	call	wypisz_tekst 
		
no_game:		       
	ret   
    
    
	; ---------------------------------------------------
   	; F: wpisz_tekst                                           
   	; Funkcja wpisuje tekst pobierajac adres tekstu ze zmiennej
   	; baner_addr (stosowac z makrem zaladuj_addr)
   	; ---------------------------------------------------
                                      
        
wypisz_tekst:  	          
	clr	X     
	call	LCD_POZYCJA
wypisz_tekst_loop:
	ld	A,([baner_addr.w],X) 
	cp	A,#0
	jreq	wypisz_tekst_end

	push	X    
	ld	X,A
	call	LCD_WRITE   
	        
	;	czy przejsc do nowego wiersza?
;	cp	X,#20
;	jrne	wypisz_tekst_co	        
;	ld	X,#$40
;	call	LCD_POZYCJA	        
	        
wypisz_tekst_co:	                        
	ld	X,#10	                        
	call	zrob_opoznienie	
			
	pop	X  
	                 	              	                 
	inc	X
	jp	wypisz_tekst_loop        
	
             
	
wypisz_tekst_end:   
	ld	X,#80
	call	zrob_opoznienie
	ret	
	 
	 
zrob_opoznienie:	         
	call	TIME_5MS   
	dec 	X
	jrne	zrob_opoznienie
	ret
	



	        
;*******************************************************************************
init:	; Inicjacja: konfiguracja ukladów peryferyjnych, ukladow zewnetrznych i przerwan
	; ...

	ld	A,#%00000000
	ld	PBDDR,A
	ld	PBOR, A

	ld	A,#%00001111
	ld	PDDDR,A
	ld	PDOR, A

	ld	A,#%10000000
	ld	PCDDR,A
	ld	PCOR,A	
	                      	               	                       
        bset	PCDR, #7
	
	ret

;*******************************************************************************
int_catch	iret			; "pusty" podprogram obslugi przerwania


	segment 'vectit'		; tablica wektorów przerwan

	DC.W	int_catch		; FFE0-FFE1h location
	DC.W	int_catch		; FFE2-FFE3h location
	DC.W	int_catch		; FFE4-FFE5h location
	DC.W	int_catch		; FFE6-FFE7h location
	DC.W	int_catch		; FFE8-FFE9h location
	DC.W	przerwanie_TOF		; FFEA-FFEBh location
	DC.W	int_catch		; FFEC-FFEDh location
	DC.W	int_catch		; FFEE-FFEFh location
	DC.W	int_catch		; FFF0-FFF1h location
	DC.W	int_catch		; FFF2-FFF3h location
	DC.W	int_catch		; FFF4-FFF5h location
	DC.W	int_catch		; FFF6-FFF7h location
	DC.W	int_catch		; FFF8-FFF9h location
	DC.W	int_catch		; FFFA-FFFBh location
	DC.W	int_catch		; FFFC-FFFDh location
	DC.W	main			; FFFE-FFFFh location = poczatek programu

	END

