;*****************************************************************
;
; File Name		: 'mp3.asm'
; Title			: MP3 Player
; Date			: 2001.11.25
; Version		: 0.01
; Author		: Baris Inan
; Target MCU		: ATmega163
;
;*****************************************************************
;.device ATMEGA163		; Prohibits use of non-implemented instructions;
.nolist
.include "m163def.inc"
.list
;.equ	CPU_CLOCK	=7872800
.equ	BAUD_RATE	=38400
.equ	CPU_CLOCK	=8000000
.equ	UART_BAUD_DIV	=((CPU_CLOCK+8*BAUD_RATE)/(16*BAUD_RATE))-1
; Number of MP3 files stored in SRAM[$60]
.equ	NUM_TRACKS	=$0060
.def	SECTOR		=r2
.def	CYL_LO		=r3
.def	CYL_HI		=r4
.def	HEAD		=r5
.def	TRACK		=r6	; Keeps the current track no
.def	CLUS_LO		=r7	; Current cluster low
.def	CLUS_HI		=r8	; Current cluster hi
.def	UARTREG		=r10	; Uart receive register
.def	RESETREG	=r11	;
.def	FLAGREG		=r12	;
.def	TEMP0		=r16	; temporary register 0
.def	TEMP1		=r17	; temporary register 1
.def	TEMP2		=r18	; temporary register 2
.def	RETURN0		=r19	; function return 0
.def	RETURN1		=r20	; function return 1
.def	ARG0		=r21	; function argument 0
.def	ARG1		=r22	; function argument 1
.def	ARG2		=r23	; function argument 2
.def	TEMP3		=r24
; and as a reminder
; m163def.inc contains
;.def	XL	=r26
;.def	XH	=r27
;.def	YL	=r28
;.def	YH	=r29
;.def	ZL	=r30
;.def	ZH	=r31
; code segment
        .cseg
        .org    0x000
	jmp	reset		; $000 Reset Handler
	jmp	Int0Isr		; $002 IRQ0 Handler
	jmp	reset		; $004 IRQ1 Handler
	jmp	reset		; $006 Timer2 Compare Handler
	jmp	Timer2Isr	; $008 Timer2 Overflow Handler
	jmp	reset		; $00a Timer1 Capture Handler
	jmp	reset		; $00c Timer1 CompareA Handler
	jmp	reset		; $00e Timer1 CompareB Handler
	jmp	reset		; $010 Timer1 Overflow Handler
	jmp	reset		; $012 Timer0 Overflow Handler
	jmp	SPICompIsr	; $014 SPI Transfer Complete Handler
	jmp	reset		; $016 UART RX Complete Handler
	jmp	reset		; $018 UDR Empty Handler
	jmp	reset		; $01a UART TX Complete Handler
	jmp	reset		; $01c ADC Conversion Complete Interrupt Handler
	jmp	reset		; $01e EEPROM Ready Handler
	jmp	reset		; $020 Analog Comparator Handler
	jmp	reset		; $022 2-wire Serial Interface Interrupt Handler
;File size 2020 (07E4 hex)words
.include "p02_0609.inc"
;File size 2011 words (07DB hex)
;.include "p02_0609_mine.inc"
reset:
	; initialize stack pointer
	ldi 	TEMP0, low(RAMEND)    
	out	SPL, TEMP0
	ldi 	TEMP0, high(RAMEND)
	out 	SPH, TEMP0	
	
	clr	TEMP0
	out	UBRRHI, TEMP0
       	ldi	TEMP0, UART_BAUD_DIV	; set baud rate
	out	UBRR, TEMP0
        sbi     UCSRB, TXEN        	; enable serial transmitter
        sbi     UCSRB, RXEN           	; enable serial receiver
;        sbi     UCSRB, RXCIE	        ; enable receiver interrupts
	; Timer2
        ldi	TEMP0, $07		; Prescale 1024
	out	TCCR2, TEMP0
	in	TEMP0, TIMSK
	sbr	TEMP0, 1<<TOIE2		; Enable timer2 interrupt
	out	TIMSK, TEMP0	
       	
       	;I2C bit rate register 
       	; TWBR = 80 gives around 45Kbps for 8Mhz       	
       	ldi	TEMP0, $C0		; 80
       	out	TWBR, TEMP0
       	
       	;SPI configuration
       	;Fclk/16=500Kbps
       	;Fclk/2 and Fclk/4 doesn't work
       	;Fclk/8  has some skips
       	;Fclk/16 can support 128Kbps well and some skips for 192Kbps 
        ldi	TEMP0, 0b11010101	; 
       	out	SPCR, TEMP0
       	cbi	SPSR, 0			; SPI2x=0		
       	
       	; INT0 configuration
       	in	TEMP0, GIMSK
       	sbr	TEMP0, 1<<INT0		; Enable external interrupt INT0
       	out	GIMSK, TEMP0
        ldi	TEMP0, $03		; 0000-0011
       	out	MCUCR, TEMP0		; Rising edge on INT0 
      				       	
	ldi	ARG0, $41		; A
	rcall	putchar			; Debug
	ldi	TEMP0, $FF		; port C all outputs
	out	DDRC, TEMP0
	ldi	TEMP0, $7F		; 0111-1111
        out     PORTC, TEMP0		; CS1=CS0=1 -> CF in standby, PC7=0 -> display off
        
	ldi	TEMP0, $B0		; 0b10110000: MISO is input, B0-B3 input
        out	DDRB, TEMP0
	ldi	TEMP0, $30		; 0b00110000: SCK=0 MOSI=1 SS=1
	out	PORTB, TEMP0
	
        ldi	TEMP0, $E0		; 7-6-5 output, 2 input 111-00-0-00
        out	DDRD, TEMP0		; Port D
        clr	TEMP0
        out	PORTD, TEMP0		; All zeros
	
	; Wait for CF reset
	rcall	chbsy
	
	ldi	ARG0, $61		; a
	rcall	putchar			; Debug
		
	; Set feature to 8-bit mode
        ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $04      		; 000-001-00: A2-A0 = 001 feature reg.
  	ldi	ARG2, $01		; Enable 8-bit data transfers
  	rcall	memrw
  	
  	ldi	ARG0, $42		; B
	rcall	putchar			; Debug
  	
  	; Send Set Feature Command
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $1C		; 000-111-00: A2-A0 = 111 command reg.
  	ldi	ARG2, $EF		; Set Features
  	rcall	memrw
	ldi	ARG0, $62		; b
	rcall	putchar			; Debug
  	
  	;Wait for CF
  	rcall	chbsy			; Check if CF busy
  	
  	rcall	is_lcd_busy		; Check if LCD is busy
  	
  	; Timer 1 for LCD's PWM input
  	ldi	TEMP0, $81		; 1000-0001: COM1A1=PWM10=1
  	out	TCCR1A, TEMP0
  	ldi	TEMP0, $01		; 0000-0001: CS10=1 (Prescale=1)
  	out	TCCR1B, TEMP0
  	clr	TEMP0
  	out	OCR1AH, TEMP0
  	ldi	TEMP0, 21		; 21/256 duty cycle for contrast
  	out	OCR1AL, TEMP0		
  	
  	; Initialize LCD
  	ldi	ARG0, $38		; 8-bit, 2 lines, 5x7
  	rcall	lcd_command_write
	ldi	ARG0, $0C		; Display ON
	rcall	lcd_command_write
	ldi	ARG0, $06		; Increment, no shift
  	 	
  	ldi	ARG0, $43		; C
	rcall	putchar			; Debug
	;Wait for "C" 
;mp3_pause1:	
;	rcall	getchar
;	cpi	RETURN0, $43		; "C"
;	brne	mp3_pause1
	; Read IDENT register in MP3 decoder
	ldi	ARG1, $01
	rcall	I2C_read_byte
	; Write DATA_REQ_ENABLE register
	ldi	ARG1, $18
	ldi	ARG2, $04
	rcall	I2C_write_byte
	
	; Read	DATA_REQ_ENABLE register
	ldi	ARG1, $18
	rcall	I2C_read_byte
;mp3_pause4:	
;	rcall	getchar
;	cpi	RETURN0, $43		; "C"
;	brne	mp3_pause4
	
	; Send the MP3 decoder configuration file
	clr	XH			; Counter for .inc file
	clr	XL 
        ldi	ZH, high(config*2)
	ldi	ZL, low (config*2)
mp3_wr:	
	lpm 				; read least signif. byte
	mov	ARG1, r0		; Register address
	adiw	ZL, 1
	lpm				; read most signif. byte
	mov	ARG2, r0		; Data
	adiw	ZL, 1			; increment
	
	rcall	I2C_write_byte
	
	
	;30 ms delay after SOFT RESET command (addr=16)
	cpi	ARG1, 16
	brne	mp3_wr_skip
	clr	TEMP0
	out	TCNT2, TEMP0	; Start timer
	clr	TEMP3	
	sei
timer2: cpi	TEMP3, $00
	nop
	nop
	breq	timer2
	cli
	
	in	TEMP0, TIMSK
	cbr	TEMP0, 1<<TOIE2		; Disable timer2 interrupt
	out	TIMSK, TEMP0
	
		
mp3_wr_skip:
	adiw	XL, 1	
	cpi	XL, $E4			;Compare with file size
	brne	mp3_wr
	cpi	XH, $07			;
	brne	mp3_wr
	;Send RUN command to decoder	
	ldi	ARG1, 114		; RUN
	ldi	ARG2, 1			; RUN
	rcall	I2C_write_byte
	
	;Send Play Command to decoder
	ldi	ARG1, 19		; PLAY
	ldi	ARG2, 1 		; PLAY
	rcall	I2C_write_byte
	
	;Read PLAY register
;	rcall	I2C_read_byte
	;Read SCKL_POL register
;	ldi	ARG1, $0D
;	rcall	I2C_read_byte
	;Wait for "C" 
;mp3_pause:	
;	rcall	getchar
;	cpi	RETURN0, $43		; "C"
;	brne	mp3_pause
	rcall	read_root_dir
	
	rcall	LF_CR
	
	; Print Number of Files
	clr	ARG2			; Don't send to LCD
	lds	ARG1, NUM_TRACKS
	mov	TEMP0, ARG1
	rcall	print_hex
	ldi	ARG0, $2E		; .
	rcall	putchar	
	ldi	ARG0, $2E		; .
	rcall	putchar
	;Print The first cluster no's for files
	ldi	YH, $00
	ldi	YL, $62
files_loop:
	clr	ARG2			; Don't send to LCD	
	ld	ARG1, Y+		; Low byte
	rcall	print_hex
	ld	ARG1, Y+		; High byte
	rcall	print_hex
	ldi	ARG0, $2E		; .
	rcall	putchar	
	ldi	ARG0, $2E		; .
	rcall	putchar
	dec	TEMP0
	cpi	TEMP0, 0
	brne	files_loop
	;Print the last files last cluster no + 1
	clr	ARG2			; Don't send to LCD
	ld	ARG1, Y+		; Low byte
	rcall	print_hex
	ld	ARG1, Y+		; High byte
	rcall	print_hex
	
	; Print the sector addresses of tracks
	rcall	LF_CR 
	clr	TRACK
	inc	TRACK			; Start at Track #1
	lds	TEMP0, NUM_TRACKS
	inc	TEMP0
print_tracks:
	rcall	compute_addr
	clr	ARG2			; Don't send to LCD
	mov	ARG1, CYL_HI
	rcall	print_hex
	ldi	ARG0, $2E		; .
	rcall	putchar	
	mov	ARG1, CYL_LO	
	rcall	print_hex
	ldi	ARG0, $2E		; .
	rcall	putchar	
	mov	ARG1, HEAD
	rcall	print_hex
	ldi	ARG0, $2E		; .
	rcall	putchar	
	mov	ARG1, SECTOR	
	rcall	print_hex
	inc	TRACK
	rcall	LF_CR
	cp	TRACK, TEMP0
	brne	print_tracks
	
	; Initialize to TRACK #1		
	clr	TRACK
	inc	TRACK
	rcall	compute_addr
	rcall	read_tag
	
	; Wait here for PLAY input
play_loop2:	
	sbic	PINB, 3			; Skip rjmp if button is pressed
	rjmp	play_loop2
	ldi	YH, $02
	clr	YL
	clr	RESETREG
	
	sei
main:	
	;Set Cylinder Low Reg.
	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $10      		; 000-100-00: cyl low reg.
  	mov	ARG2, CYL_LO		; cyl_lo = CYL_LO
  	rcall	memrw
  	
  	;Set Cylinder Hi Reg.
	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $14      		; 000-101-00: cyl hi reg.
  	mov	ARG2, CYL_HI		; cyl_hi = 00
  	rcall	memrw
  	
  	;Set Head No.
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $18      		; 000-110-00: select card/head reg.
  	mov	ARG2, HEAD		; 1010-0000: head no = 0
  	rcall	memrw
  	
  	;Set Sector Number Register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $0C      		; 000-011-00: sec num reg.
  	mov	ARG2, SECTOR		; sec_num = SECTOR
  	rcall	memrw
 
  	;Set 01H in sector count register (read one sector)
 	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $08      		; 000-010-00: sec cnt.
  	ldi	ARG2, $01		; 1 sector
  	rcall	memrw
  	
	; Set 20H in Command register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $1C		; 000-111-00: A2-A0 = 111 command reg.
  	ldi	ARG2, $20		; Read Sector(s)
  	rcall	memrw
  	
  	rcall	chbsy			; Check if busy
  	
  	
  	;cbi	PORTB, 0		; LED0 on
  	nop				; instead of upper instr.
  	sbrs	RESETREG, 0
  	rjmp	rd_lp_2a_end
; Z=512
	; Case1: Y<256 pause here until Y=256
	; Case2: Y>=256	continue
rd_lp2a: 
	sbrs	YH, 0	
	rjmp	rd_lp2a
	
rd_lp_2a_end:
	;sbi	PORTB, 0		; LED0 off
	nop				; instead of upper instr.
	
  	; Write to SRAM locations 512-1023
   	ldi	ZH, $02			;
	clr	ZL
	clr	ARG0		
	clr	ARG1
	
	;Read loop 1
	;   0 <= Z <= 255 read into SRAM and SRAM+1
	; 256 <= Z <= 511 ignore twice	
rd_lp1:	
    	; Fast read
  	ldi	TEMP0, 0b01000000  ; Set PC6 to 1 and 000 address
	out	PORTC, TEMP0
	cbi	PORTC, 5	; clear PC5 = -CS0
	sbi	PORTD, 7	; set 	PD7 = -IOWR
	cbi	PORTD, 6	; clear PD6 = -IORD
	ldi	TEMP0, $00	; also delay
	out	DDRA, TEMP0	; PORTA input
	in	RETURN0, PINA	; Read from the memory bus
	sbi	PORTD, 6	; set -IORD
	sbi	PORTC, 5	; set -CS0
  	
  	sbrs	ZH, 0			; skip store if greater than 256
	st	Z, RETURN0		; Store data
	adiw	ZL, 1
	
	; Fast read
  	ldi	TEMP0, 0b01000000  ; Set PC6 to 1 and 000 address
	out	PORTC, TEMP0
	cbi	PORTC, 5	; clear PC5 = -CS0
	sbi	PORTD, 7	; set 	PD7 = -IOWR
	cbi	PORTD, 6	; clear PD6 = -IORD
	ldi	TEMP0, $00	; also delay
	out	DDRA, TEMP0	; PORTA input
	in	RETURN0, PINA	; Read from the memory bus
	sbi	PORTD, 6	; set -IORD
	sbi	PORTC, 5	; set -CS0
	
	sbrs	ZH, 0
	st	Z, RETURN0
	adiw	ZL, 1			; increment
	
	cpi	ZH, $04
	brne	rd_lp1
	
	rcall	chbsy
	
	
	;RESETREG is cleared at reset and set to $FF after on.
	;So, the start_spi_tx function call is executed only once
	sbrs	RESETREG, 0
	rcall	start_spi_tx
		
	; Set 20H in Command register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $1C		; 000-111-00: A2-A0 = 111 command reg.
  	ldi	ARG2, $20		; Read Sector(s)
  	rcall	memrw
  	
  	rcall	chbsy			; Check if busy
  	
	sbrs	RESETREG, 0
  	rjmp	rd_lp_1a_end  	
  	; Z=512
	; Case1: Y>=256 pause here until Y=0
	; Case2: Y<256	continue
rd_lp1a: 
	sbrc	YH, 0	
	rjmp	rd_lp1a
	
rd_lp_1a_end:
  	
  	
  	ldi	ZH, $02			;
	clr	ZL
    	;Read loop 2
	;   0 <= Z <= 255 ignore twice
	; 256 <= Z <= 511 read into SRAM and SRAM+1	
 rd_lp2:	
	; Fast read
  	ldi	TEMP0, 0b01000000  ; Set PC6 to 1 and 000 address
	out	PORTC, TEMP0
	cbi	PORTC, 5	; clear PC5 = -CS0
	sbi	PORTD, 7	; set 	PD7 = -IOWR
	cbi	PORTD, 6	; clear PD6 = -IORD
	ldi	TEMP0, $00	; also delay
	out	DDRA, TEMP0	; PORTA input
	in	RETURN0, PINA	; Read from the memory bus
	sbi	PORTD, 6	; set -IORD
	sbi	PORTC, 5	; set -CS0
	
	
  	sbrc	ZH, 0			; skip store if less than 256
	st	Z, RETURN0		; Store data
	adiw	ZL, 1
	
	
	; Fast read
  	ldi	TEMP0, 0b01000000  ; Set PC6 to 1 and 000 address
	out	PORTC, TEMP0
	cbi	PORTC, 5	; clear PC5 = -CS0
	sbi	PORTD, 7	; set 	PD7 = -IOWR
	cbi	PORTD, 6	; clear PD6 = -IORD
	ldi	TEMP0, $00	; also delay
	out	DDRA, TEMP0	; PORTA input
	in	RETURN0, PINA	; Read from the memory bus
	sbi	PORTD, 6	; set -IORD
	sbi	PORTC, 5	; set -CS0
	
	sbrc	ZH, 0
	st	Z, RETURN0
	adiw	ZL, 1			; increment
	
	cpi	ZH, $04
	brne	rd_lp2
	
	rcall	chbsy
	
	ldi	ARG0, 1
	rcall	inc_sector		; increment sector by one
	mov	TEMP0, SECTOR		; Check if SECTOR == xxxxxx00
	andi	TEMP0, $03		; increment CLUS if so
	cpi	TEMP0, $00
	brne	skip_inc_clus1
	ldi	TEMP0, 1		; increment CLUS by 1
	clr	TEMP1
	add	CLUS_LO, TEMP0
	adc	CLUS_HI, TEMP1
	rcall	check_overflow	
skip_inc_clus1:
;----------------------------
	; Check buttons for commands
	; B3:PLAY - B2:STOP - B1:FF - B0:REV
		
	; Check FF button
	sbic	PINB, 1			; Skip rjmp if button is pressed
	rjmp	ff_skip1
	
	in	TEMP0, TIMSK
	sbr	TEMP0, 1<<TOIE2		; Enable timer2 interrupt
	out	TIMSK, TEMP0
	
	clr	TEMP0
	out	TCNT2, TEMP0		; Start timer
	clr	TEMP3	
timer2_loop1:			 	; 200ms delay
	cpi	TEMP3, $06
	nop
	nop
	brne	timer2_loop1
	
	sbis	PINB, 1			; Skip rjmp if button is not pressed
	rjmp	ff_skip2
	inc	TRACK
	
	lds	TEMP0, NUM_TRACKS
	inc	TEMP0
	cp	TRACK, TEMP0		
	brne	ff_skip4
	; This is the last Track
	clr	TRACK	
	inc	TRACK			; Reset to Track #1
	; Wait here for PLAY input
play_loop1:	
	sbic	PINB, 3			; Skip rjmp if button is pressed
	rjmp	play_loop1
	
ff_skip4:	
	rcall	compute_addr
	rcall	read_tag
	rjmp	ff_skip3
ff_skip2:				; Button is still pressed
	sbic	PINB, 1			; Skip rjmp if button is pressed
	rjmp	ff_skip3
	clr	TEMP0
	out	TCNT2, TEMP0		; Start timer
	clr	TEMP3	
timer2_loop2:			 	; 33ms delay
	cpi	TEMP3, $01
	nop
	nop
	brne	timer2_loop2
	
	; 33ms ~= 500 bytes (128 kbps) 
	; 16 increment = 16X fast forward (slower for higher bitrates) 
	ldi	ARG0, 16
	rcall	inc_sector		; increment sector by 16
	
	ldi	TEMP0, 4		; increment CLUS by 4
	clr	TEMP1
	add	CLUS_LO, TEMP0
	adc	CLUS_HI, TEMP1
	rcall	check_overflow
		
	rjmp	ff_skip2
ff_skip3:		
	in	TEMP0, TIMSK
	cbr	TEMP0, 1<<TOIE2		; Disable timer2 interrupt
	out	TIMSK, TEMP0
	
ff_skip1:
;------------------------------
	; Check REV button
	sbic	PINB, 0			; Skip rjmp if button is pressed
	rjmp	rev_skip1
	
	in	TEMP0, TIMSK
	sbr	TEMP0, 1<<TOIE2		; Enable timer2 interrupt
	out	TIMSK, TEMP0
	
	clr	TEMP0
	out	TCNT2, TEMP0		; Start timer
	clr	TEMP3	
timer2_loop3:			 	; 200ms delay
	cpi	TEMP3, $06
	nop
	nop
	brne	timer2_loop3
rev_skip2:	
	sbis	PINB, 0			; Skip rjmp if button is not pressed
	rjmp	rev_skip2
	dec	TRACK
	
	clr	TEMP0
	cp	TRACK, TEMP0		
	brne	rev_skip4
	; This is the first Track
	clr	TRACK	
	inc	TRACK			; Reset to Track #1
rev_skip4:	
	rcall	compute_addr
	rcall	read_tag
	rjmp	rev_skip3
; Did not implement Rewinding as inc_sector and check_overflow functions 
; need to be modified.  
;rev_skip2:				; Button is still pressed
;	sbic	PINB, 0			; Skip rjmp if button is pressed
;	rjmp	rev_skip3
;	clr	TEMP0
;	out	TCNT2, TEMP0		; Start timer
;	clr	TEMP3	
;timer2_loop4:			 	; 33ms delay
;	cpi	TEMP3, $01
;	nop
;	nop
;	brne	timer2_loop4
;	
;	; 33ms ~= 500 bytes (128 kbps) 
;	; 16 increment = 16X fast forward (slower for higher bitrates) 
;	ldi	ARG0, 16
;	rcall	inc_sector		; increment sector by 16
	
;	ldi	TEMP0, 4		; increment CLUS by 4
;	clr	TEMP1
;	add	CLUS_LO, TEMP0
;	adc	CLUS_HI, TEMP1
;	rcall	check_overflow
;		
;	rjmp	rev_skip2
rev_skip3:		
	in	TEMP0, TIMSK
	cbr	TEMP0, 1<<TOIE2		; Disable timer2 interrupt
	out	TIMSK, TEMP0
	
rev_skip1:
;------------------------------
	ldi	TEMP0, $FF
	mov	RESETREG, TEMP0
	
  	rjmp	main
;No arguments: Address always 000 
;RETURN0 is output
fastread:
	push	TEMP0
	
	ldi	TEMP0, 0b01000000  	; Set PC6 to 1 and 000 address
	out	PORTC, TEMP0
	
	cbi	PORTC, 5		; clear PC5 = -CS0
	
	sbi	PORTD, 7		; set 	PD7 = -IOWR
	cbi	PORTD, 6		; clear PD6 = -IORD
	
	ldi	TEMP0, $00		; also delay
	out	DDRA, TEMP0		; PORTA input
	in	RETURN0, PINA		; Read from the memory bus
	
	sbi	PORTD, 6		; set -IORD
	
	sbi	PORTC, 5		; set -CS0
	
	pop	TEMP0
	ret
; Function memrw
; Read and Write to the Flash Card.
; CS1=1 and CS0=0 when reading or writing.
; So, don't use for Device Control, Alt Status and Drive Address regs.
 
; ARG0: Address 0-2 : PC2-4 (xxxnnnxx)
; ARG1= $00 -> read
; ARG1= $FF -> write
; ARG2: Write value (not used in read)
; RETURN0: Read value (unchanged in write)
memrw:
	push	TEMP0
	push	TEMP1
	push	TEMP2
	push	ARG0
	mov 	TEMP1,	ARG0
	andi	TEMP1, $1C	; 00011100 and TEMP1 = 000xxx00	
	
	ldi	TEMP2, $00	; port C all inputs
	out	DDRC, TEMP2	;		
	in	TEMP0, PINC	; Read current bus value
	ldi	TEMP2, $FF	; port C all outputs
	out	DDRC, TEMP2	;
	
	or	TEMP0, TEMP1	; Set ones
	
	mov	TEMP1, ARG0
	ori	TEMP1, $E3	; 11100011 or TEMP1  = 111xxx11 
	
	and	TEMP0, TEMP1	; Set zeros
	out	PORTC, TEMP0	; Addr 0-2
		
	sbi	PORTC, 6	; set   PC6 = -CS1
	cbi	PORTC, 5	; clear PC5 = -CS0	
	cpi	ARG1, $00
	brne	wr_jmp	
	;Read
	sbi	PORTD, 7	; set 	PD7 = -IOWR
	cbi	PORTD, 6	; clear PD6 = -IORD
	ldi	TEMP1, $00	; also delay
	out	DDRA, TEMP1	; PORTA input
	in	RETURN0, PINA	; Read from the memory bus
	sbi	PORTD, 6	; set -IORD
	rjmp	wr_end
	;Write
wr_jmp:
	sbi	PORTD, 6	; set   PD6 = -IORD
	cbi	PORTD, 7	; clear PD7 = -IOWR
	ldi	TEMP1, $FF
	out	DDRA, TEMP1	; PORTA output
	out	PORTA, ARG2	; Write to the memory bus
	nop			; tsu(IOWR)
	
	sbi	PORTD, 7	; set -IOWR
wr_end:	sbi	PORTC, 5	; set -CS0
	   	
	pop	ARG0
	pop	TEMP2
	pop	TEMP1
	pop	TEMP0
	ret
; Read CF status register for busy
chbsy:  push	ARG1
	push	ARG0
	push	TEMP0
	
bsy_lp: ldi	ARG1, $00		; Read operation
  	ldi	ARG0, $1C		; 000-111-00: status reg.
  	rcall 	memrw
  	mov	TEMP0, RETURN0		; Save original status
  	andi	RETURN0, $F7		; ignore DRQ bit
  	cpi	RETURN0, $51		
  	brne	no_err
  	
  	; Ready but, Error bit is set
  	ldi	ARG1, $00		; Read operation
  	ldi	ARG0, $04		; 000-001-00: error reg.
  	rcall 	memrw
  	com	RETURN0
  	;out	PORTB, RETURN0		; Display error
  	rjmp	bsy_lp
no_err: mov	RETURN0, TEMP0
	andi	RETURN0, $F7
	cpi	RETURN0, $50		; if still busy, just loop back
  	brne	bsy_lp
  	
  	pop	TEMP0
  	pop	ARG0
  	pop	ARG1
  	ret
  	
; Function print_hex: Gets ARG1 as 8-bit input and outputs hex value
; If ARG2(0) is cleared, function does not send characters to LCD
print_hex:
	push	TEMP0
	push	ARG0
 
;higher nibble
	mov	TEMP0, ARG1
	swap	TEMP0
	andi	TEMP0, $0F
	cpi	TEMP0, $0A
	brsh	let1
	ldi	ARG0, $30
	add	ARG0, TEMP0
	rcall	putchar
	sbrc	ARG2, 0		
	rcall	lcd_data_write	
	rjmp	nib1
let1:	ldi	ARG0, $37
	add	ARG0, TEMP0
	rcall	putchar
	sbrc	ARG2, 0		
	rcall	lcd_data_write
;lower nibble
nib1:	mov	TEMP0, ARG1
	andi	TEMP0, $0F		; Lower nibble
	cpi	TEMP0, $0A
	brsh	let2			; Branch if same or higher than "A"
	ldi	ARG0, $30
	add	ARG0, TEMP0
	rcall	putchar
	sbrc	ARG2, 0		
	rcall	lcd_data_write
	rjmp	nib2
let2:	ldi	ARG0, $37
	add	ARG0, TEMP0
	rcall	putchar
	sbrc	ARG2, 0		
	rcall	lcd_data_write		
nib2:	
	pop	ARG0
	pop	TEMP0	
	ret
	
; Function LF_CR
; Take the cursor to new line in terminal 			
LF_CR:	push	ARG0
	ldi	ARG0, $0A		; Line Feed
	rcall	putchar
	ldi	ARG0, $0D		; Carriage Return
	rcall	putchar
	
	pop	ARG0
	ret
;Function putchar
;Transmit to UART, waits for empty buffer 
putchar:
	sbis	UCSRA, UDRE               ; loop until USR:UDRE is 1
	rjmp	putchar
	out	UDR, ARG0		; write ARG0 to transmitter buffer
	ret
	
;Function putchar2
;Transmit to UART, both true value and MSB inverted waits for empty buffer 
putchar2:
	push	TEMP0
	
putc1:	sbis	UCSRA, UDRE               ; loop until USR:UDRE is 1
	rjmp	putc1
	out	UDR, ARG0		; write ARG0 to transmitter buffer
putc2:	sbis	UCSRA, UDRE
	rjmp	putc2
	ldi	TEMP0, $80		
	eor	TEMP0, ARG0
	out	UDR, TEMP0
	
	pop	TEMP0
	ret
	
;Function getchar
;Waits to receive data from UART
getchar:
	sbis	UCSRA, RXC              ; loop until USR:RXC is 1
	rjmp	getchar
	in	RETURN0, UDR		; return receive data in RETURN0
	ret 
;I2C master transmitter Function
; Writes ARG2 into the MP3 decoder register ARG1
; Refer to Mega163 manual
I2C_write_byte:
	push	TEMP0
	push	ARG0
	
	; Initialization for writing
	ldi	TEMP0, $04	; 00000100
	out	TWCR, TEMP0
	nop
	nop
	
	; Initialize TWBR
	ldi	TEMP0, $C0		; 30
       	out	TWBR, TEMP0
       	nop
       	nop
	
	; Send Start Condition
	ldi	TEMP0, (1<<TWSTA) | (1<<TWEN)
retry_w:out	TWCR, TEMP0
	nop
	nop
	
wait1:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait1
	
	; Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $08	; START
	brne	WR_ERR
	
	; Select decoder chip for Write
	ldi	TEMP0, 0x86
	out	TWDR, TEMP0
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait2:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait2
		
	;Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $18	; MT_SLA_ACK
	brne	WR_ERR
	
	; Write the address
	out	TWDR, ARG1
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait3:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait3
	
	;Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $28	; MT_DATA_ACK
	brne	WR_ERR
	
	; Write the data
	out	TWDR, ARG2
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait4:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait4
	
	;Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $28	; MT_DATA_ACK
	brne	WR_ERR
	
	; Send Stop Condition
	ldi	TEMP0, (1<<TWINT) | (1<<TWSTO) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
	rjmp	skip_w
	
	; Send Status to UART
WR_ERR:
	ldi	ARG0, $57	; "W"
	rcall	putchar
	;ldi	TEMP0, (1<<TWSTA) | (1<<TWEN) | (1<<TWINT)
	;rjmp	retry_w	
wr_pause2:
	call	getchar
	cpi	RETURN0, $43		; "C"
	brne	wr_pause2
	
	mov	TEMP0, ARG1
	com	TEMP0
	;out	PORTB, TEMP0
	
	;Wait for "C" 
wr_pause1:	
	rcall	getchar
	cpi	RETURN0, $43		; "C"
	brne	wr_pause1
	
	; Deactivate interface before ending
skip_w: clr	TEMP0
	out	TWCR, TEMP0
	nop
	nop
	pop	ARG0
	pop	TEMP0
	ret
	
;I2C master receiver Function
; Reads the address in MP3 decoder chip.
; First writes the address to be read (without writing a data)
; Then reads one byte 
; ARG1: read address
; RETURN0: return data
; Refer to Mega163 manual
I2C_read_byte:
	push	TEMP0
	push	ARG0
	
	; WRITING the address to be read
	; Initialization for writing
	ldi	TEMP0, $04	; 00000100
	out	TWCR, TEMP0
	nop
	nop
	
	; Initialize TWBR
	ldi	TEMP0, $C0		; 30
       	out	TWBR, TEMP0
	
	; Send Start Condition
	ldi	TEMP0, (1<<TWSTA) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait1r:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait1r
	
	ldi	ARG0, $31	; "1"
	rcall	putchar
		
	; Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $08	; START
	brne	RD_ERR
	
	; Select decoder chip for Write
	ldi	TEMP0, 0x86
	out	TWDR, TEMP0
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait2r:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait2r
	
	ldi	ARG0, $32	; "2"
	rcall	putchar
	
	;Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $18	; MT_SLA_ACK
	brne	RD_ERR
	
	; Write the address
	out	TWDR, ARG1
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait3r:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait3r
	
	ldi	ARG0, $33	; "3"
	rcall	putchar
	
	;Check Status
	in	TEMP0, TWSR
	;out	PORTB, TEMP0
	cpi	TEMP0, $28	; MT_DATA_ACK
	brne	RD_ERR
	
	; Send Stop Condition
	;ldi	TEMP0, (1<<TWINT) | (1<<TWSTO) | (1<<TWEN)
	;out	TWCR, TEMP0
	; Branch out of reach
	rjmp	skip_next	
RD_ERR:	rjmp	RD_ERR2
skip_next:			
	; READING
	; Send a REPEATED Start Condition
	;ldi	TEMP0, (1<<TWINT) | (1<<TWSTO) | (1<<TWSTA) | (1<<TWEN)
	;out	TWCR, TEMP0
	ldi	TEMP0, (1<<TWINT) | (1<<TWSTO) | (1<<TWEN)
	out	TWCR, TEMP0	
	;sbi	TWCR, TWSTA
	ori	TEMP0, $20	; TWSTA: 00100000
	out	TWCR, TEMP0
	
	nop
	nop
	
wait5:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait5
	
	ldi	ARG0, $34	; "4"
	rcall	putchar
	
	; Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $08	; START
	brne	RD_ERR
	
	; Select decoder chip for Read
	ldi	TEMP0, 0x87
	out	TWDR, TEMP0
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
wait6:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait6
	
	ldi	ARG0, $35	; "5"
	rcall	putchar
	
	; Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $40	; MR_SLA_ACK
	brne	RD_ERR
	
	; Read one byte (TWEA not set to send NACK after reading which stops reading)
	ldi	TEMP0, (1<<TWINT) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
wait9:	in	TEMP0, TWCR
	nop
	sbrs	TEMP0, TWINT
	rjmp	wait9
	
	ldi	ARG0, $36	; "6"
	rcall	putchar
	
	; Check Status
	in	TEMP0, TWSR
	cpi	TEMP0, $58	; MR_DATA_NACK
	brne	RD_ERR
	; Get the return value
	in	RETURN0, TWDR
	
	; Send Stop Condition
	ldi	TEMP0, (1<<TWINT) | (1<<TWSTO) | (1<<TWEN)
	out	TWCR, TEMP0
	nop
	nop
	
	rjmp	skip_r
	
	; Send Status to UART
RD_ERR2: 
	ldi	ARG0, $52	; "R"
	rcall	putchar
	
	com	ARG0
	;out	PORTB, ARG0
	
	;Wait for "C" 
rd_pause1:	
	rcall	getchar
	cpi	RETURN0, $43		; "C"
	brne	rd_pause1
	
	com	TEMP0
	;out	PORTB, TEMP0
	
	;Wait for "C" 
rd_pause2:	
	rcall	getchar
	cpi	RETURN0, $43		; "C"
	brne	rd_pause2
	
	; Disable interface before exit
skip_r:	clr	TEMP0
	out	TWCR, TEMP0
	nop
	
	pop	ARG0
	pop	TEMP0
	ret
; Function start_spi_tx
; Y register has the current reading position
; Takes the byte from SRAM(Y) and transmits over SPI 
; This function starts a burst of transfers until DATA_REQ = 0
start_spi_tx:
	push	TEMP0
	
	; Load from current position
	ld	TEMP0, Y
	; Transmit over SPI
	out	SPDR, TEMP0
		
	adiw	YL, 1		; increment to next location
	sbrc	YH, 2		; Wrap around at 1024 (YH=$04)
				; doesn't reset YH if YH=010 or 011
	ldi	YH, $02
	
	pop	TEMP0
	ret
	
; Function read_tag
; 
read_tag:
	push	SECTOR
	push	CYL_LO
	push	CYL_HI
	push	HEAD
	push	CLUS_LO
	push	CLUS_HI
	push	TEMP0
	push	TEMP1
	push	TEMP2
	clr	TEMP1		
	; State=0 no letter found
	; State=1 "T"   has been found
	; State=2 "TA"  has been found
	; State=3 "TAG" has been found
	
	rcall	lcd_clear
	; Set SECTOR, CYL_LO etc. to next track's beginning	
	inc	TRACK
	rcall	compute_addr
	
	; Note: compute_addr goes to the location one cluster before next song
	; So, no need to decrement
	
	; Decrement sector by 1 to read the last 4 sectors of current TRACK
	;ldi	TEMP0, 4
;tag_dec_sec:
;	rcall	dec_sector
;	dec	TEMP0
;	cpi	TEMP0, 0
;	brne	tag_dec_sec
	
	clr	ZH
	clr	ZL
tag_loop:
	;Set Cylinder Low Reg.
	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $10      		; 000-100-00: cyl low reg.
  	mov	ARG2, CYL_LO		; cyl_lo = CYL_LO
  	rcall	memrw
  	
  	;Set Cylinder Hi Reg.
	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $14      		; 000-101-00: cyl hi reg.
  	mov	ARG2, CYL_HI		; cyl_hi = 00
  	rcall	memrw
  	
  	;Set Head No.
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $18      		; 000-110-00: select card/head reg.
  	mov	ARG2, HEAD		; 1010-0000: head no = 0
  	rcall	memrw
  	
  	;Set Sector Number Register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $0C      		; 000-011-00: sec num reg.
  	mov	ARG2, SECTOR		; sec_num = SECTOR
  	rcall	memrw
 
  	;Set 01H in sector count register (read one sector)
 	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $08      		; 000-010-00: sec cnt.
  	ldi	ARG2, $01		; 1 sector
  	rcall	memrw
  	
	; Set 20H in Command register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $1C		; 000-111-00: A2-A0 = 111 command reg.
  	ldi	ARG2, $20		; Read Sector(s)
  	rcall	memrw
  	
  	rcall	chbsy			; Check if busy
  	
  	rjmp	tag_rd_lp		; Relative branch was out of reach
tag_loop1:
	rjmp	tag_loop 	
  	
tag_rd_lp:  	
  	rcall	fastread
  	;mov	ARG0, RETURN0
	;rcall	putchar
  	; State=0
  	cpi	TEMP1, 0
  	brne	state_1
  	cpi	RETURN0, $54		; "T"
  	brne	tag_skip
	ldi	TEMP1, 1		; Found first letter
	mov	TEMP2, ZL		; Record the starting offset
	rjmp	tag_skip
	; State=1
state_1:
	cpi	TEMP1, 1
	brne	state_2
	cpi	RETURN0, $41		; "A"
	brne	state_1T
	ldi	TEMP1, 2		; Found second letter
	rjmp	tag_skip
state_1T:
	cpi	RETURN0, $54		; "T"
	brne	state_1_other
	ldi	TEMP1, 1		; Found first letter
	mov	TEMP2, ZL		; Record the starting offset
	rjmp	tag_skip
state_1_other:
	ldi	TEMP1, 0		; Not "A" or "T"
	rjmp	tag_skip
	; State=2	
state_2:
	cpi	TEMP1, 2
	brne	state_3
	cpi	RETURN0, $47		; "G"
	brne	state_2T
	ldi	TEMP1, 3		; Found third letter
	rjmp	tag_skip
state_2T:
	cpi	RETURN0, $54		; "T"
	brne	state_2_other
	ldi	TEMP1, 1		; Found first letter
	mov	TEMP2, ZL		; Record the starting offset
	rjmp	tag_skip
state_2_other:
	ldi	TEMP1, 0		; Not "G" or "T"
	rjmp	tag_skip
	; State=3	
state_3:
	sub	ZL, TEMP2
	cpi	ZL, 33			; (3-32): Title
	brsh	tag_artist
	cpi	ZL, 3
	brne	tag_title_skip
	ldi	ARG0, $80		
	rcall	lcd_command_write	; Go to first line of LCD
tag_title_skip:	
	mov	ARG0, RETURN0
	cpi	ARG0, $00		; If char = $00 make it $20
	brne	space_skip1
	ldi	ARG0, $20
	
	rjmp	space_skip1		; Relative branch was out of reach
tag_loop2:
	rjmp	tag_loop1
tag_rd_lp1:
	rjmp	tag_rd_lp	
space_skip1:	
	rcall	lcd_data_write
	rcall	putchar
	rjmp	state_3_end
tag_artist:
	cpi	ZL, 63			; (33-62): Artist
	brsh	tag_escape		; SHOULD I READ UNTIL THE END OF SECTOR?
	cpi	ZL, 33
	brne	tag_artist_skip
	ldi	ARG0, $C0
	rcall	lcd_command_write	; Go to second line of LCD
tag_artist_skip:	
	mov	ARG0, RETURN0
	cpi	ARG0, $00
	brne	space_skip2
	ldi	ARG0, $20
space_skip2:	
	rcall	lcd_data_write
	rcall	putchar
state_3_end:	
	add	ZL, TEMP2		; restore ZL	
				  	
tag_skip:
	adiw	ZL, 1			; increment
	mov	TEMP0, ZH
	andi	TEMP0, $01
	cpi	TEMP0, $00
	brne	tag_rd_lp1
	cpi	ZL, $00
	brne	tag_rd_lp1  	
  		
	rcall	chbsy
	
	ldi	ARG0, $01
	rcall	inc_sector
	
	cpi	ZH, $08
	brne	tag_loop2
tag_escape:
	dec	TRACK
	ldi	ARG0, $E0
	rcall	lcd_command_write	; Go to address $60
	ldi	ARG0, $54		; "T"
	rcall	lcd_data_write
	ldi	ARG0, $52		; "R"
	rcall	lcd_data_write
	ldi	ARG0, $41		; "A"
	rcall	lcd_data_write
	ldi	ARG0, $43		; "C"
	rcall	lcd_data_write
	ldi	ARG0, $4B		; "K"
	rcall	lcd_data_write
	ldi	ARG0, $20		; Space
	rcall	lcd_data_write
	ldi	ARG2, $FF		; Send to display
	mov	ARG1, TRACK
	rcall	print_hex		; Display track number
	
	pop	TEMP2
	pop	TEMP1
	pop	TEMP0
	pop	CLUS_HI
	pop	CLUS_LO
	pop	HEAD
	pop	CYL_HI
	pop	CYL_LO
	pop	SECTOR
	ret
; Function read_root_dir
; Reads the Root Directory in FAT(0, 00, 01, 1C). Stores the first cluster 
; address of each file in SRAM starting at SRAM[0x62]. Each entry is 2 bytes. 
; Maximum entries is around 200 NUM_TRACKS is the number of files. Also reads 
; the file size and stores it in TEMP:0-1-2. This is used to find the last 
; cluster number for the last file.
read_root_dir:
	push	ARG0
	push	ARG1
	push	ARG2
	push	TEMP0
	push	TEMP1
	push	TEMP2
	push	TEMP3			; used as temporary
	
	ldi	TEMP3, $1C
	mov	SECTOR, TEMP3		; Sector = $1C
	ldi	TEMP3, $01
	mov	CYL_LO, TEMP3		; cyl_lo = $01
	clr	CYL_HI			; cyl_hi = $00
	ldi	TEMP3, $A0		; Head = 0
	mov	HEAD, TEMP3
	
	ldi	YH, $00
	ldi	YL, $62
	
	clr	FLAGREG
	
root_dir_loop:
	;Set Cylinder Low Reg.
	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $10      		; 000-100-00: cyl low reg.
  	mov	ARG2, CYL_LO		; cyl_lo = CYL_LO
  	rcall	memrw
  	
  	;Set Cylinder Hi Reg.
	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $14      		; 000-101-00: cyl hi reg.
  	mov	ARG2, CYL_HI		; cyl_hi = 00
  	rcall	memrw
  	
  	;Set Head No.
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $18      		; 000-110-00: select card/head reg.
  	mov	ARG2, HEAD		; 1010-0000: head no = 0
  	rcall	memrw
  	
  	;Set Sector Number Register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $0C      		; 000-011-00: sec num reg.
  	mov	ARG2, SECTOR		; sec_num = SECTOR
  	rcall	memrw
 
  	;Set 01H in sector count register (read one sector)
 	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $08      		; 000-010-00: sec cnt.
  	ldi	ARG2, $01		; 1 sector
  	rcall	memrw
  	
	; Set 20H in Command register
  	ldi	ARG1, $FF		; Write operation
  	ldi	ARG0, $1C		; 000-111-00: A2-A0 = 111 command reg.
  	ldi	ARG2, $20		; Read Sector(s)
  	rcall	memrw
  	
  	rcall	chbsy			; Check if busy
  	
  	;Read 512 times the data register.  Write to SRAM
  	ldi	ZH, $02			; 512
	clr	ZL	
root_rd_lp:	
	rcall	fastread
	st	Z, RETURN0		; Store data
	adiw	ZL, 1			; increment
	cpi	ZH, $04
	brne	root_rd_lp
	rcall	chbsy
	
	; Parse the stored Sector to find first clusters
	ldi	ZH, $02
	ldi	ZL, $00
	mov	TEMP3, FLAGREG
	clr	FLAGREG
	cpi	TEMP3, 0
	brne	root_skip2		; If 1 was at last 32 bytes of previous sector
					; Just start reading the first cluster and file size
root_parse:
	ld	TEMP3, Z
	cpi	ZH, $04			
	breq	root_skip	
	adiw	ZL, 32
	cpi	TEMP3, 1		; 44-3-2-1 if one Z
	brne	root_parse
	
	cpi	ZH, $04
	brne	root_skip2
	inc	FLAGREG			; If 1 is at last 32 bytes of sector set this flag
	rjmp	root_skip
	
root_skip2:
	
	; Store first cluster address
	adiw	ZL, 26			
	ld	TEMP3, Z+		; FirstCluster lower byte (location 26)
	st	Y+, TEMP3			
	ld	TEMP3, Z+		; FirstCluster higher byte (location 27)
	st	Y+, TEMP3
	
	; Store file size into temporary registers
	; $0061-$0064: Lower to Higher
	adiw	ZL, 1			; Skip	FileSize byte[0]	
	ld	TEMP0, Z+		; FileSize byte[1] (lowest byte - loc. 29)
	ld	TEMP1, Z+		; FileSize byte[2] (lowest byte - loc. 30)
	ld	TEMP2, Z+		; FileSize byte[3] (lowest byte - loc. 31)
	
	cpi	ZH, $04
	breq	root_skip	
	
	; Z=0 (mod 32) here
	; LOCK TEMP0, TEMP1, TEMP2 here
	
	ld	TEMP3, Z
	cpi	TEMP3, $E5		; End of entries
	brne	root_parse
	
	
	; Divide file size by 2048 (shift by 11). Done by shifting right by three
	; TEMP0 and TEMP1 holds the file size in clusters
	ldi	TEMP3, 3
div_8:	lsr	TEMP0
	lsr	TEMP1
	brcc	div_skip1		; Skip next instruction if C bit is zero	
	ori	TEMP0, $80		; Shift TEMP1[0] into TEMP0[7]
	div_skip1:	
	lsr	TEMP2
	brcc	div_skip_2		; Skip next instruction if C bit is zero
	ori	TEMP1, $80		; Shift TEMP2[0] into TEMP1[7]
	div_skip_2:	
	dec	TEMP3
	cpi	TEMP3, 0
	brne	div_8
	
	;NUM_TRACKS = Y/2 - $31 (Y<256 so YH = 0)
	mov	TEMP3, YL
	lsr	TEMP3
	subi	TEMP3, $31
	sts	NUM_TRACKS, TEMP3
	
	mov	ZL, YL
	mov	ZH, YL
	sbiw	ZL, 2			; Z = address of last entry in SRAM
	ld	TEMP2, Z+		; Last cluster entry lower byte
	ld	TEMP3, Z+		; Last cluster entry higher byte
	add	TEMP0, TEMP2
	adc	TEMP1, TEMP3		
	;TEMP0 and TEMP1 holds last files last cluster
	mov	ZL, TEMP0
	mov	ZH, TEMP1
	adiw	ZL, 1
	;Store lastfile_lastcluster+1 into the next empty location in SRAM
	st	Y+, ZL
	st	Y+, ZH
	rjmp	root_exit
root_skip:	  	
; Increment sector. If sector = 20h increment HEAD
	mov	TEMP3, SECTOR
  	cpi	TEMP3, $20
 	brne	root_inc_sc
 	clr	SECTOR
 	inc	HEAD
 	mov	TEMP3, HEAD
 	cpi	TEMP3, $A4
 	brne	root_inc_sc
 	ldi	TEMP3, $A0
 	mov	HEAD, TEMP3
 	inc	CYL_LO
 	
 	; CYL_HI = 0  $00<=CYL_LO<=$FF
 	mov	TEMP3, CYL_HI
 	cpi	TEMP3, $00
 	brne	root_hi_1
	mov	TEMP3, CYL_LO
	cpi	TEMP3, $00		; Overflow
	brne	root_inc_sc
	inc	CYL_HI
	rjmp	root_inc_sc
	; CYL_HI = 1 $00<=CYL_LO<=$E9
root_hi_1:	
	mov	TEMP3, CYL_LO
	cpi	TEMP3, $EA
	brne	root_inc_sc
	clr	CYL_HI
	clr	CYL_LO
root_inc_sc:	
	inc	SECTOR
  	rjmp	root_dir_loop
root_exit:
	pop	TEMP3
	pop	TEMP2
	pop	TEMP1
	pop	TEMP0  	
  	pop	ARG2
  	pop	ARG1
  	pop	ARG0
  	ret
; Function inc_sector
; Increments SECTOR by the number specified with ARG0
inc_sector:
	push	TEMP2
	; Increment sector. If sector = 20h increment HEAD
	mov	TEMP2, SECTOR
  	cpi	TEMP2, $20
 	brne	inc_sc
 	clr	SECTOR
 	inc	HEAD
 	mov	TEMP2, HEAD
 	cpi	TEMP2, $A4
 	brne	inc_sc
 	ldi	TEMP2, $A0
 	mov	HEAD, TEMP2
 	inc	CYL_LO
 	
 	; CYL_HI = 0  $00<=CYL_LO<=$FF
 	mov	TEMP2, CYL_HI
 	cpi	TEMP2, $00
 	brne	hi_1
	mov	TEMP2, CYL_LO
	cpi	TEMP2, $00		; Overflow
	brne	inc_sc
	inc	CYL_HI
	rjmp	inc_sc
	; CYL_HI = 1 $00<=CYL_LO<=$E9
hi_1:	mov	TEMP2, CYL_LO
	cpi	TEMP2, $EA
	brne	inc_sc
	clr	CYL_HI
	clr	CYL_LO
inc_sc:	add	SECTOR, ARG0		; Increment by AGR0
	mov	TEMP2, SECTOR
	cpi	TEMP2, $20		; If SECTOR>=$20 SECTOR=$20
	brlo	sc_skip			; This gives a maximum increment amount
	ldi	TEMP2, $20		; of 16.  e.g.: (20+12)/2 = 16
	mov	SECTOR, TEMP2
sc_skip:	
	pop	TEMP2
	ret
	
; Function dec_sector
; Decrements SECTOR by 1
dec_sector:
	push	TEMP2
	; Decrement sector. If sector = 01h decrement HEAD
	mov	TEMP2, SECTOR
  	cpi	TEMP2, $01
 	brne	dec_sc
 	ldi	TEMP2, $21
 	mov	SECTOR, TEMP2
 	dec	HEAD
 	mov	TEMP2, HEAD
 	cpi	TEMP2, $9F
 	brne	dec_sc
 	ldi	TEMP2, $A3
 	mov	HEAD, TEMP2
 	dec	CYL_LO
 	
 	; CYL_HI = 0  $00<=CYL_LO<=$FF
 	mov	TEMP2, CYL_HI
 	cpi	TEMP2, $00
 	brne	dec_hi_1
	mov	TEMP2, CYL_LO
	cpi	TEMP2, $FF		; Overflow
	brne	dec_sc
	inc	CYL_HI
	ldi	TEMP2, $E9
	mov	CYL_LO, TEMP2
	rjmp	dec_sc
	; CYL_HI = 1 $00<=CYL_LO<=$E9
dec_hi_1:	
	mov	TEMP2, CYL_LO
	cpi	TEMP2, $FF
	brne	dec_sc
	clr	CYL_HI
dec_sc:	dec	SECTOR
	pop	TEMP2
	ret

; Function check_overflow
; Checks whether the current cluster no exceeds the next track's cluster no
; If the cluster no overflows there are two cases:
; -this was the last track: resets TRACK# to 1 and waits for PLAY button
; -else: Increment TRACK, Read and Display Tag information of next track	
check_overflow:
	push	TEMP0
	push	TEMP1
	push	YH
	push	YL
	
	;Read next TRACK's first cluster no 
	;SRAM offset (r1:r0) = 2*(TRACK+1) + $60
	ldi	TEMP0, 2
	ldi	TEMP1, 1
	add	TEMP1, TRACK		; TEMP1 = TRACK+1
	mul	TEMP1, TEMP0		; 2*(TRACK+1) -> r1:r0
	mov	YH, r1
	mov	YL, r0
	adiw	YL, $30
	adiw	YL, $30			; Y = Y + $60
	
	; Y has the next TRACK's first cluster no
	; TEMP0 = Cluster lower byte, TEMP1 = Cluster higher byte
	ld	TEMP0, Y+
	ld	TEMP1, Y+
	
	cp	CLUS_HI, TEMP1
	brlo	ovfl_skip1		; skip if CLUS_HI < TEMP1
	cp	TEMP1, CLUS_HI
	brlo	ovfl_skip2		; skip if CLUS_HI > TEMP1
	cp	CLUS_LO, TEMP0		; CLUS_HI = TEMP1 here
	brlo	ovfl_skip1		; skip if CLUS_LO < TEMP0
; Overflow detected
ovfl_skip2:
	lds	TEMP0, NUM_TRACKS
	cp	TRACK, TEMP0		
	brne	ovfl_skip3
	; This is the last Track
	clr	TRACK
	inc	TRACK			; Reset to Track #1
	rcall	compute_addr
	rcall	read_tag
	; Wait here for PLAY input
play_loop:	
	sbic	PINB, 3			; Skip rjmp if button is pressed
	rjmp	play_loop
	
	rjmp	ovfl_skip1
ovfl_skip3:
	; Not Last Track: Skip to next track
	inc	TRACK
	
	
	ldi	ARG0, $54		; T
	rcall	putchar			; Debug
	ldi	ARG0, $52		; R
	rcall	putchar			; Debug
	ldi	ARG0, $30
	add	ARG0, TRACK
	rcall	putchar
	
	rcall	compute_addr
	rcall	read_tag	
ovfl_skip1:
	
	pop	YL
	pop	YH
	pop	TEMP1
	pop	TEMP0
	ret	
  	
; Function compute_addr
; Input is the TRACK register
; Grabs the FirstCluster no from SRAM and computes HEAD, CYL_HI, 
; CYL_LO and SECTOR values
; Also sets CLUS_LO and CLUS_HI registers to FisrtCluster no
; SRAM offset = $60 + 2*TRACK   (2 bytes)
; Sector = $AF + 4*FirstCluster (2 bytes)
;   15   | 14 13 12 11 10 9 8  7 | 6 5  | 4 3 2 1 0
; CYL_HI |        CYL_LO         | HEAD |   SECTOR
; Add 1 to SECTOR as it starts from 1
compute_addr:
	push	TEMP0
	push	TEMP1
	push	YH
	push	YL
	
	;SRAM offset (r1:r0) = 2*TRACK + $60
	ldi	TEMP0, 2
	mul	TRACK, TEMP0		; 2*TRACK -> r1:r0
	mov	YH, r1
	mov	YL, r0
	adiw	YL, $30
	adiw	YL, $30			; Y = Y + $60
	
	; TEMP0 = Cluster lower byte, TEMP1 = Cluster higher byte
	ld	TEMP0, Y+
	ld	TEMP1, Y+
	
	mov	CLUS_LO, TEMP0
	mov	CLUS_HI, TEMP1
	
	;Sector(r1:r0) = $AF + 4*FirstCluster
	;MaxCluster= $3CF1   $3C*4 = $00F0 -----> stored in YH
	;		     $FF*4 = $  03FC
	;			     $    B0
	;			   +________	  	
	ldi	YL, 4
	mul	TEMP1, YL		; 4*Cluster_hi -> r1:r0
	mov	YH, r0			; r1 is always 0
	mul	TEMP0, YL		; 4*Cluster_lo -> r1:r0
	ldi	YL, $AF
	add	r0, YL			
	adc	r1, YH			; r1:r0 = sector(15:0)			
	
	clr	CYL_HI
	bst	r1, 7			; Store bit 15 to T
	bld	CYL_HI, 0		; Load T into CYL_HI(0)
	
	mov	CYL_LO, r1		; CYL_LO = bits 15:8
	lsl	CYL_LO			; CYL_LO(7:1) = bits 14:8
	bst	r0, 7			; Store bit 7 to T
	bld	CYL_LO, 0		; CYL_LO(0) = bit 7
	
	ldi	TEMP0, $A0
	mov	HEAD, TEMP0
	bst	r0, 6			; Store bit 6 to T
	bld	HEAD, 1			; HEAD(1) = bit 6
	bst	r0, 5			; Store bit 5 to T
	bld	HEAD, 0			; HEAD(0) = bit 5
	
	mov	TEMP0, r0
	andi	TEMP0, $1F		; and with 0001-1111				
	mov	SECTOR, TEMP0		; SECTOR(4:0) = bits 4:0
	inc	SECTOR			; SECTOR starts at 1 and ends at 32
	
	pop	YL
	pop	YH
	pop	TEMP1
	pop	TEMP0
	ret
	
; Function is_lcd_busy
is_lcd_busy:
	push	TEMP0
	push	TEMP1
	
	rcall	five_nops		; Enable cycle delay 
	rcall	five_nops
	
	cbi	PORTC, 2		; Control word
	sbi	PORTD, 7		; read
	clr	TEMP1
	out	PORTA, TEMP1
	out	DDRA, TEMP1		; Port A input
	sbi	PORTC, 7		; Enable
	rcall	five_nops		; Min 160ns delay
	in	TEMP0, PINA		; Read LCD data
	nop
	nop
	cbi	PORTC, 7
	
	;Wait here if LCD is busy
lcd_busy_loop:		
	sbrs	TEMP0, 7		; skip rjmp if set (busy)
	rjmp	lcd_busy_end
	rcall	five_nops		; Enable cycle delay
	rcall	five_nops
	sbi	PORTC, 7		; Enable
	rcall	five_nops		; Min 160ns delay
	in	TEMP0, PINA		; Read LCD data
	nop
	nop
	cbi	PORTC, 7
	rjmp	lcd_busy_loop
lcd_busy_end:	
	pop	TEMP1
	pop	TEMP0
	ret
	
; Function five_nops
five_nops:
	nop
	nop
	nop
	nop
	nop
	ret
	
; Function lcd_data_write
; ARG0 is the data to write
lcd_data_write:	
	push	TEMP0
	sbi	PORTC, 2		; Data word
	cbi	PORTD, 7		; Write
	out	PORTA, ARG0
	ldi	TEMP0, $FF
	out	DDRA, TEMP0		; Port A output
	sbi	PORTC, 7		; Enable
	rcall	five_nops
	rcall	five_nops
	cbi	PORTC, 7
	rcall	is_lcd_busy
	pop	TEMP0	
	ret
	
; Function lcd_command_write
; ARG0 is the command to write
lcd_command_write:	
	push	TEMP0
	cbi	PORTC, 2		; Control word
	cbi	PORTD, 7		; Write
	out	PORTA, ARG0
	ldi	TEMP0, $FF
	out	DDRA, TEMP0		; Port A output
	sbi	PORTC, 7		; Enable
	rcall	five_nops
	rcall	five_nops
	cbi	PORTC, 7
	rcall	is_lcd_busy
	pop	TEMP0	
	ret			
; Function lcd_clear
lcd_clear:
	push	ARG0
	ldi	ARG0, $01
	rcall	lcd_command_write
	pop	ARG0	
	ret
; SPI transfer Complete Interrupt Handler
; Transmits next byte and increments Y register
; Continously transfer until DATA_REQ=0
; For a rate of F/32 there are 256 clocks of execution
; until the next interrupt.
SPICompIsr:
	push	TEMP0
	push	TEMP1			; Stores only SREG in here
	in	TEMP1, SREG		; Save Status register
	
	;cbi	PORTB, 1		; LED1 on
	nop				; Instead of instr. above	
		
	sbis	PIND, 2			; skip rjmp if DATA_REQ is high	
	rjmp	spi1
	; Load from current position
	ld	TEMP0, Y	
	; Transmit over SPI
	out	SPDR, TEMP0
	adiw	YL, 1			; increment to next location
	sbrc	YH, 2			; Wrap around at 1024 (YH=$04)
					; doesn't reset YH if YH=010 or 011
	ldi	YH, $02
	;sbi	PORTB, 1		; LED1 off
	nop				; Instead of instr. above
		
spi1:	out	SREG, TEMP1		; Save Status register
	pop	TEMP1
	pop	TEMP0
	reti
; INT0 interrupt handler.
; Triggered by a rising edge on DATA_REQ input from decoder
Int0Isr:
	push	TEMP0			; save registers
	in      TEMP0, SREG		; save status register
	
	rcall	start_spi_tx		; Start a burst of transfer
	
	out	SREG, TEMP0		; restore status register
	pop 	TEMP0			; restore registers
	reti				; return from the interrupt
; Timer2 interrupt handler
; This routine will be automatically called whenever timer 2 overflows
; Overflows after 33ms
Timer2Isr:
	push	TEMP0			; save registers
	in      TEMP0, SREG		; save status register
	
	inc	TEMP3
	
	out	SREG, TEMP0		; restore status register
	pop 	TEMP0			; restore registers
	reti				; return from the interrupt