; SLdt 250519

;OSCILLATOR=INTERNAL OSCILLATOR
.INCLUDE "TN85def.inc"
;------------REGISTER DEFINITION--------------
.DEF T1COUNTER=R0
.DEF STATUS=R1
.DEF DEFDUR=R2
.DEF DEFOCT=R3
.DEF BPM0=R4
.DEF BPM1=R5
.DEF NEWPRE=R6
.DEF NEWOCR=R7
.DEF T00=R8
.DEF T01=R9
.DEF NOTE=R10
.DEF DURATION=R11
.DEF OCTAVE=R12
.def	null = r15
;------------DATA SPACE DEFINITION--------------
;------------INTERRUPT VECTOR--------------
.ORG 0X0
RJMP INIT

.ORG PCI0addr;0X2
RJMP PC_INT

.ORG OC0Aaddr;0X6
RJMP T0_INT

.INCLUDE "ringtones.inc"
.CSEG
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;START OF PROGRAM AND INITIALIZING
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
INIT:
;INITIALIZING I/O PORTS
LDI R16,0B00100111
OUT DDRB,R16
SBI PORTB,3
SBI PORTB,4 ;ENABLING PULLUP

;INITIALIZING STACK
;LDI R16,0X9F
;OUT SPL,R16

;DISABLE ANALOG COMPARATOR
SBI ACSR,ACD

;INITAILIZING REGISTERS
CLR ZL
CLR ZH
clr null

;INITIALIZING TIMER0
LDI R16,254
OUT OCR0A,R16
LDI R16,0B00000010
OUT TCCR0A,R16								; WGM01: CTC auf OCR0A
LDI R16,0B00000011
OUT TCCR0B,R16								; /64
LDI R16,(1<<OCIE0A);0B00000100
OUT TIMSK,R16								; OCIE0A

;INITIALIZING PIN CHANGE INT
LDI R16,(1<<PCINT3)|(1<<PCINT4)
OUT PCMSK,R16
LDI R16,(1<<PCIE)
OUT GIMSK,R16

SEI
HERE:
	RJMP HERE

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;PIN CHANGE INTERRUPT (USED FOR KEY HANDLING)
;USED REGISTER:R16,R17
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
PC_INT:
	;WAIT FOR SOME SECONDS TO PREVENT BOUNCING
	LDI R16,20
	RCALL WAITMS
	;CHECK PB3
	SBIC PINB,3
	RJMP PC_INT0
	;SET STATUS REGISTER INTO RING
	LDI R16,0X1
	OR STATUS,R16
	RETI
PC_INT0:
	SBIC PINB,4
	RETI
	;TURN OFF THE RING
	;BY TURNING OC0A TO
	;NORMAL PORT OPERATION
	IN R16,TCCR0A
	ANDI R16,0B10111111
	OUT TCCR0A,R16
	CBI PORTB,0
	;INCREASE INTERRUPT DURATION
	;TO THE MAXIMUM (ABOUT 16MS)	
	LDI R16,255
	OUT OCR0A,R16
	LDI R16,0B00000011
	OUT TCCR0B,R16
	;RESET NOTE POINTER
	CLR ZL
	CLR ZH
	;STORE NEW RINGTONE ADDRESS IN E2PROM
	LDI R16,0
	RCALL READROM
	MOV R17,R16
	INC R17
	LDI R16,1
	RCALL READROM
	CP R16,R17
	BRSH PC_INT1
	LDI R17,1
PC_INT1:
	LDI R16,0
	RCALL WRITEROM
	;SET STATUS REGISTER INTO RING
	LDI R16,0X1
	OR STATUS,R16
	RETI
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;TIMER 0 INTERRUPT (USED FOR RING)
;USED REGISTER:R16,R17,R24,R25,ZH,ZL
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
T0_INT:
	SBRC STATUS,0	
	RJMP T0_INT1
	;RING FLAG IS CLEAR
	;SO IS IT STILL RINGING?
	CLR R16
	CP ZL,R16
	CPC ZH,R16
	BRNE T0_INT0
	RETI
T0_INT0:
	;TURN OFF THE RING
	;BY TURNING OC0A TO
	;NORMAL PORT OPERATION
	IN R16,TCCR0A
	ANDI R16,0B10111111
	OUT TCCR0A,R16
	CBI PORTB,0
	;INCREASE INTERRUPT DURATION
	;TO THE MAXIMUM (ABOUT 16MS)	
	LDI R16,255
	OUT OCR0A,R16
	LDI R16,0B00000011
	OUT TCCR0B,R16
	;RESET NOTE POINTER
	CLR ZL
	CLR ZH
	;SET STATUS REGISTER INTO NOT RINGING
	LDI R16,0XFE
	AND STATUS,R16
	RETI

T0_INT1:
	;RING FLAG IS SET
	;SO TEST THE NOTE POINTER
	TST ZL
	BRNE T0_INT2
	TST ZH
	BRNE T0_INT2	
	;NOTE POINTER IS ZERO
	;SO LOAD RINGTONE TABLE ADDRESS
	;FROM E2PROM
	LDI R16,0
	RCALL READROM
	LSL R16
	MOV R17,R16
	RCALL READROM
	MOV ZL,R16
	MOV R16,R17
	INC R16
	RCALL READROM
	MOV ZH,R16
	;LOAD DEFAULTS
	LPM DEFDUR,Z+
	LPM DEFOCT,Z+
	LPM BPM0,Z+
	LPM BPM1,Z+
	RJMP T0_INT3

T0_INT2:
	;TEST NEW PRESCALAR VALUE
	;IF ZERO THEN TURN OFF THE RING
	TST NEWPRE
	BREQ T0_INT0
	OUT OCR0A,NEWOCR
	OUT TCCR0B,NEWPRE
	;IF NOTE IS "P" THEN SET NPO
	LDI R16,'P'
	CP NOTE,R16
	BRNE T0_INT2A
	IN R16,TCCR0A
	ANDI R16,0B10111111
	OUT TCCR0A,R16
	CBI PORTB,0
	RJMP T0_INT2B
T0_INT2A:
	;TURN ON THE RING
	IN R16,TCCR0A
	ORI R16,0B01000000
	OUT TCCR0A,R16
T0_INT2B:
	;DECREASE COUNTER
	LDI R16,1
	CLR R17
	SUB T00,R16
	SBC T01,R17
	;COMPARE COUNTER WITH 0
	CLR R16
	CP T00,R16
	CPC T01,R16
	BREQ T0_INT3
	RETI

T0_INT3:
	;LOAD THE NEXT NOTE
	LPM NOTE,Z+
	;IF NOTE IS ZERO THEN STOP PLAYING	
	TST NOTE
	BRNE T0_INT4
	CLR NEWPRE
	RETI

T0_INT4:
	;LOAD DEFAULTS
	MOV OCTAVE,DEFOCT
	MOV DURATION,DEFDUR
	;CHECK BIT 7 OF NOTE
	SBRS NOTE,7
	RJMP T0_INT5
	;IF BIT7 IS ONE THEN 
	;NEXT BYTE CONTAINS
	;OCTAVE AND DURATION
	LPM R17,Z+
	MOV OCTAVE,R17
	LDI R16,7
	AND OCTAVE,R16
	MOV DURATION,R17
	LSR DURATION
	LSR DURATION
	LSR DURATION
	INC DURATION
T0_INT5:
	;CLEAR NOTE MSB
	LDI R16,127
	AND NOTE,R16
	;IF NOTE IS "P" THEN SET OCTAVE TO 3
	LDI R16,'P'
	LDI R17,3
	CPSE NOTE,R16
	MOV R17,OCTAVE
	MOV OCTAVE,R17
	;KEEP NOTE POINTER IN STACK
	PUSH ZH
	PUSH ZL
	;LOAD OCTAVE TABLE ADDRESS
	MOV R16,OCTAVE
	LDI ZL,LOW(OCTAVE3<<1)
	LDI ZH,HIGH(OCTAVE3<<1)
T0_INT6:
	CPI R16,4
	BRNE T0_INT7
	LDI ZL,LOW(OCTAVE4<<1)
	LDI ZH,HIGH(OCTAVE4<<1)
T0_INT7:
	CPI R16,5
	BRNE T0_INT8
	LDI ZL,LOW(OCTAVE5<<1)
	LDI ZH,HIGH(OCTAVE5<<1)
T0_INT8:
	CPI R16,6
	BRNE T0_INT9
	LDI ZL,LOW(OCTAVE6<<1)
	LDI ZH,HIGH(OCTAVE6<<1)
T0_INT9:
	CPI R16,7
	BRNE T0_INT10
	LDI ZL,LOW(OCTAVE7<<1)
	LDI ZH,HIGH(OCTAVE7<<1)
T0_INT10:
	;FIND NOTE THROUGH TABLES
	LPM R16,Z
	ADIW ZH:ZL,5
	CPSE R16,NOTE
	RJMP T0_INT10
	SBIW ZH:ZL,4
	;LOAD PRESCALAR AND OCR
	LPM NEWPRE,Z+
	LPM NEWOCR,Z+
	;(12f)/TEMPO
	LPM R24,Z+
	LPM R25,Z
	MOV ZL,BPM0
	MOV ZH,BPM1
	RCALL Di16U
	;% * 40
	LDI R24,40
	LDI R25,0
	RCALL Mp16u
	;% / DURATION
	MOV R24,ZL
	MOV R25,ZH
	MOV ZL,DURATION
	CLR ZH
	RCALL Di16U
	MOV T00,ZL
	MOV T01,ZH
	POP ZL
	POP ZH
	RETI
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;READ E2PROM ROUTINE
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
READROM:
	out	EEARH,null
	OUT EEARL,R16
	SBI EECR,EERE
	IN R16,EEDR
	RET
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;WRITE E2PROM ROUTINE
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
WRITEROM:
	out	EEARH,null
	OUT EEARL,R16
	OUT EEDR,R17
	SBI EECR,EEMPE
	SBI EECR,EEPE
WRITEROM0:
	SBIC EECR,EEPE
	RJMP WRITEROM0
	RET
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;16/16 UNSIGNED DIVISION
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Di16u:	
	MOV R22,ZL
	MOV	R23,ZH
	MOV	ZL,R24
	MOV	ZH,R25
	CLR	R24
	SUB	R25,R25
	LDI	R20,0x11
d16u1:	
	ROL ZL
	ROL	ZH
	DEC	R20
	BRNE d16u2
	RET
d16u2:
	ROL R24
	ROL	R25
	SUB	R24,R22
	SBC	R25,R23
	BRCC d16u3
	ADD	R24,R22
	ADC	R25,R23
	CLC
	RJMP d16u1
d16u3:
	SEC
	RJMP d16u1
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;16x16 unsigned multiply
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Mp16u:	clr		r23
		clr		r22
		ldi		r21,0x10
		lsr		zh
		ror		zl
m16u1:	brcc	m16u2
		add		r22,r24
		adc		r23,r25
m16u2:	ror		r23
		ror		r22
		ror		zh
		ror		zl
		dec		r21
		brne	m16u1
		ret
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;Wait milliseconds
;FOR 1MHZ OSC
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
WAITMS:
	PUSH R20
	PUSH R21
_Wms:	
	LDI R20,20
_Wms1:
	LDI R21,17
_Wms2:
	DEC R21
	BRNE _Wms2
	DEC R20
	BRNE _Wms1
	DEC R16
	BRNE _Wms
	POP R21
	POP R20
RET