;*****************************************************************************
;*								     *
;*			       ST6 Stark				     *
;*								     *
;*****************************************************************************

;|===========================================================================|
;| Assemblaggio	senza linker : ast6 -l -s -x -m -e Stark.asm	              |
;|===========================================================================|

;			Timer 1 
;Utilizzando un quarzo da 8 MHZ e mettendo  prescaler divide x16(PS2=1 PS1=0 PS0=0 in tscr) 
;tcr viene decrementato ogni 1000000/8000000*(12*16)= 24 us 
;quindi ogni incremento di count0 = 256*24 = 6144 us



;			AR Timer
;Per generare con una frequenza di ingresso di 6000 giri/min =100 giri/sec
;una frequenza = 100*1024=102.4 kHz Arrotondata a 105 KHz con duty cycle del 50%,
;usando un quarzo da 8 Mz
;Prescaler ratio uguale a 1  Pr=1
;FIN = 8 MHz / Pr = 8000 kHz
;105 kHz = (8000/Pr) / (255 - RC)
;105*(255 - RC) = 8000
;26775 - 105*RC = 8000
;RC = (26775 - 8000)/105 = 178.8 ->179
;Risoluzione= 1 /(255 - 179) = 1 / 76
;Duty cycle desiderato: 50%
;CP = RC + (255 - RC)/2 = 217

;Frequenza minima(con Prescaler ratio uguale a 1)
;si ottiene quando RC=0 (CP = 127)
;FMin = 8000/255 = 31.37 kHz

;Al minor numero di giri ammesso(supposto 1 giro/sec) la frequenza è 1*1024 = 1.024 kHz
;Il Prescaler sarebbe 
;Pr = 8000/(1.024*255) = 30.63 ->32  (PS2=1 PS1=0 PS0=1)
;FMin = 8000/32/255 = 0.9804 kHz = 0.9804/1.024 giri/sec = 0.957 giri/sec


;			Utilizzo delle Porte

;NMI	Ingresso del segnale 1 - 105 kHz
;PB7	Uscita segnale PWM = PA7*1024


;|===========================================================================|
;|			    Direttive Assembly			     |
;|===========================================================================|

		.title	"Stark"		  
		.vers "st6260"
		.romsize 4

;*****************************************************************************
;*				data space			     *
;*****************************************************************************

count0		.def 84h!m      	; Contatore
count1		.def 85h!m	; Contatore	
fermo		.def 86h!m	; Se 1 Il motore è fermo
comodo		.def 87h!m	
divis		.def 88h!m	; contiene il divisore in valore da dare 
				; a PS0 PS1 PS2

NumeroA		.def 89h!m	;per Divisione e Moltiplicazione
NumeroB		.def 8ah!m
Risult		.def 8bh!m
Resto		.def 8ch!m			
Counter		.def 8dh!m

SaveA		.def 8eh!m	;per Moltiplicazione				
Res_lsb		.def 8fh!m
Res_msb		.def 90h!m

;|===========================================================================|
;|			     data registers			     |
;|===========================================================================|

		.input "6265_reg.asm"

;|===========================================================================|
;|			      constants	definition		     |
;|===========================================================================|

watchtim		.equ 0feh

tmz		.equ 7

;*****************************************************************************
;*			       PROGRAM SPACE			     *
;*****************************************************************************

;|===========================================================================|
;|			       main program			     |
;|===========================================================================|

	.org 0080h

reset	ldi	wdr,watchtim		; carica il  watchdog. 
	
	ldi	ddra,00000000b		; PA1-PA3= Input con Pull Up
	ldi	ora,00000001b	
	ldi	dra,00000000b		; PA0 = Input con Interrupt
	 
	ldi	count0,0			; azzera le variabili
	ldi	count1,0
	ldi	fermo,0
	ldi	comodo,0
	 
	ldi	ior,10h			; Abilita tutti gli interrupts.
	reti  

	ldi	tcr,255			; carica tcr
	ldi	tscr,01111100b		; Avvia il timer COn Interrupt Abilitato



loop	ldi 	wdr,watchtim	   	; Ricarica il watchdog.
	
	jp	loop			; Continua.

;|===========================================================================|
;|			    interrupt routine	                       |
;|===========================================================================|
;|---------------------------------------------------------------------------|
;|			      interrupt NMI			     |
;|---------------------------------------------------------------------------|

it_NMI	ld	a,tcr			; salvo tcr
	ldi	tcr,255			; carica tcr

;forse tcr sarebbe da caricare con 250 per recuperare il tempo perso(5*1.5 us)
	
	ldi	tscr,01111100b		; Riavvia il timer
	
	ld	comodo,a			; comodo=255-tcr(cioè i numeri contati)
	ldi	a,255
	sub	a,comodo
	ld	comodo,a

;Calcola il divisore e il valore di trc equivalenti
	ldi	a,1			
	cp	a,count1
	jrc	Per2
	ldi	divis,0
	jp	OkDiv
	
Per2	sla	a
	cp	a,count1
	jrc	Per4
	ldi	divis,1
	jp	OkDiv
	
Per4	sla	a
	cp	a,count1
	jrc	Per8
	ldi	divis,2
	jp	OkDiv

Per8	sla	a
	cp	a,count1
	jrc	Per16
	ldi	divis,3
	jp	OkDiv

Per16	sla	a
	cp	a,count1
	jrc	Per32
	ldi	divis,4
	jp	OkDiv

Per32	sla	a
	cp	a,count1
	jrc	Per64
	ldi	divis,5
	jp	OkDiv

Per64	sla	a
	cp	a,count1
	jrc	Per128
	ldi	divis,6
	jp	OkDiv

Per128	sla	a
	cp	a,count1
	ldi	divis,7
	jrnc	OkDiv
	
	sla	a		;qui A diventa 0
	ldi	divis,8
	
OkDiv	cp	a,count1		;se è uguale va raddoppiato(perchè deve essere maggiore)
				;mentre jrnc lo dà >= 
	jrnz	OkDiv1
	sla	a		;raddoppia

OkDiv1	cpi	a,0		;se A=0 ->128
	jrnz	OkDiv2
	ldi	a,128
	ld	Risult,a		;risult=A
	jp	OkDiv3
	
OkDiv2	ld	NumeroA,a	;divide per 2 per non avere il valore 256(A=0)
	ldi	NumeroB,2
	call	Dividi
		
OkDiv3	ld	a,Risult		;Risult contiene il divisore
	ldi	NumeroA,128	;tcr sarà uguale a 128/a*count1 + tcr/count1
	ld	NumeroB,a			
	call	Dividi
	
	ld	a,Risult
	ld	NumeroA,a
	ld	a,count1
	ld	NumeroB,a
	call	Moltip		;Res_lsb	contiene il risultato 128/a*count1
		
	ld	a,comodo		;a=comodo=255-tcr(i numeri contati)
	ld	NumeroA,a	;Su NumeroA
	ld	a,count1
	ld	NumeroB,a	;Divisore
	call	Dividi
	
	ld	a,Risult		;a=valore per tcr
	add	a,Res_lsb
	ld	count0,a		;count0=valore per tcr


	reti
	
;|---------------------------------------------------------------------------|
;|                           routine Divisione                               |
;|---------------------------------------------------------------------------|

; Initialize registers and save the contexte.

Dividi	clr	Risult		;clear the result register.
	clr	Resto		;clear the remainder register.

; Test A and B in order to enable the division subroutine.
	ld	a,NumeroB	; B = 0 then the result = 0 ( not valid ).
	jrnz	Div0
End_Div	ret

Div0	ld	a,NumeroA	; A = 0 then the result = 0.
	jrz	End_Div
; Division subroutine.
	addi	a,0FFh		; clear the carry.
	ldi	Counter,08h	; load the shift counter.
	ld	a,NumeroA	; \
	rlc	a		;  |rotate left and save in result register.
	ld	Risult,a		; /
Div1	ld	a,Resto		; \
	rlc	a		;  |rotate left the remainder register in
	ld	Resto,a		; /  order to include the carry.
	sub	a,NumeroB
	jrc	Div2		; test if the subtraction is valid.
	ld	Resto,a
Div2	ld	a,Risult		; \
	rlc	a		;  |rotate left the result register.
	ld	Risult,a		; /
	dec	Counter
	jrz	Div3
	jp	Div1
Div3	com	a		; complement the result.
	ld	Risult,a
	jp	End_Div

;|---------------------------------------------------------------------------|
;|                           routine Moltiplicazione                         |
;|---------------------------------------------------------------------------|
; Initialize registers and save the contexte.

Moltip	ld	SaveA,a		; save the accumulator.
	clr	Res_msb		; clear the msb of the result.
	clr	Res_lsb		; clear the lsb of the result.

; test a and b in order to enable the multiplication subroutine.

	ld	a,NumeroB	; b = 0 then the result = 0.
	jrnz	Mul0            
End_mul	ld	a,SaveA		; restore the accumulator.
	ret
Mul0	ld	a,NumeroA	; a = 0 then the result = 0.
	jrz	End_mul

; multiplication subroutine.

	ld	a,NumeroA
	ld	Res_msb,a
	ldi	Counter,08h	; load the shift counter.
Mul1	ld	a,Res_lsb	; \
	sla	a		;  | shift left the lsb of the result.
	ld	Res_lsb,a	; /
	ld	a,Res_msb	; \
	rlc	a		;  | rotate left the msb of the result.
	ld	Res_msb,a	; /
	jrnc	Mul2
	ld	a,Res_lsb	; \
	add	a,NumeroB	;  | res_lsb = res_lsb + number_b.
	ld	Res_lsb,a	; /
	jrnc	Mul2
	inc	Res_msb		; increase the msb of the result.
Mul2	dec	Counter
	jrnz	Mul3
	jp	End_mul
Mul3	jp	Mul1	

;|---------------------------------------------------------------------------|
;|			      interrupt Timer			     |
;|---------------------------------------------------------------------------|

it_Tim	res	tmz,tscr			; riavvia il Timer
	
	ldi	fermo,0			; predispone motore in movimento

	inc	count1			; Incrementa count0
	jrnz	endTim			; se overflow
	
	ldi	fermo,1			; il motore è fermo


endTim	reti
	

;*****************************************************************************
;*		       Restart and interrupt Vectors		     *
;*****************************************************************************

	 .org 0ff0h


timAdc	jp	it_Tim		;FF0 FF1
ArTim	nop			;FF2
	reti	       		;FF3
int2	nop	       		;FF4
	reti	       		;FF5
int1	nop			;FF6
	reti			;FF7
	nop
	nop
	nop
	nop
nmi	jp	it_NMI		;FFC FFD
res	jp reset			;FFE FFF
