⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat32.s

📁 Frank s MP3 Player Source Files
💻 S
📖 第 1 页 / 共 5 页
字号:
		ldi		param1,IDERD_DATA				; read bytes 36 & 37
		call	IDE_read16						; low byte  in param1; high in param2
		mov		r0,param1
		mov		r1,param2						; r0 is low byte, r1 is next
		ldi		param1,IDERD_DATA				; read bytes 38 & 39
		call	IDE_read16						; low byte  in param1; high in param2
		mov		r2,param1
		mov		r3,param2						; r2 is next byte, r3 is high byte

; shift left 1 bit (to multiply BPD_FATSz32 by 2)
		lsl		r0
		rol		r1
		rol		r2
		rol		r3
		
; add 63 + BPD_ResvdSecCnt  (think of it as: 0 0 0 (63+BPD_ResvdSecCnt) plus r3 r2 r1 r0 equals r3 r2 r1 r0)
		ldi		temp,63
        add     temp,r4                         ; temp contains 63 + BPD_ResvdSecCnt (low byte only; BPD_ResvdSecCnt assumed small)
		add		r0,temp							; note this sets carry flag as required
		ldi		temp,0							; ldi does not affect carry flag
		adc		r1,temp
		adc		r2,temp
		adc		r3,temp							; just moving the carry flag through

; Store result in DIR_START_SEC and return		
		ldi		ZL,lo8(DIR_START_SEC)
		ldi		ZH,hi8(DIR_START_SEC)			; point Z to DIR_START_SEC
		st		Z+,r0
		st		Z+,r1
		st		Z+,r2
		st		Z,r3							; store result, low byte first
		
        pop     r4
		pop		r3
		pop		r2
		pop		r1
		pop		r0
		pop		ZH
		pop		ZL
		pop		param2
		pop		param1
		pop		temp
		ret
		

		
;**********************************************************************************
;*
;* StreamFileC
;*
;* Same as StreamFile below, but preserves all the registers.
;*
;**********************************************************************************
StreamFileC:
		push	temp
		push	temp2
		push	param1
		push	param2
		push	XL
		push	XH
		push	YL
		push	YH
		push	ZL
		push	ZH
		push	r0
		push	r1
		push	r2
		push	r3
		push	r20
		push	r21
		
;		ldi		param1,'S'
;		call	UART_TxCharWait 
;		ldi		param1,'F'
;		call	UART_TxCharWait 
;		ldi		param1,'C'
;		call	UART_TxCharWait 
;		ldi		param1,'-'
;		call	UART_TxCharWait 
;		ldi		param1,'i'
;		call	UART_TxCharWait 
;		ldi		param1,'n'
;		call	UART_TxCharWait 
;		ldi		param1,'\r'
;		call	UART_TxCharWait 
;		ldi		param1,'\n'
;		call	UART_TxCharWait					; short debug message

		rcall	StreamFile

;		ldi		param1,'S'
;		call	UART_TxCharWait 
;		ldi		param1,'F'
;		call	UART_TxCharWait 
;		ldi		param1,'C'
;		call	UART_TxCharWait 
;		ldi		param1,'-'
;		call	UART_TxCharWait 
;		ldi		param1,'o'
;		call	UART_TxCharWait 
;		ldi		param1,'u'
;		call	UART_TxCharWait 
;		ldi		param1,'t'
;		call	UART_TxCharWait 
;		ldi		param1,'\r'
;		call	UART_TxCharWait 
;		ldi		param1,'\n'						; short debug message
;		call	UART_TxCharWait 
		
		pop		r21
		pop		r20
		pop		r3
		pop		r2
		pop		r1
		pop		r0
		pop		ZH
		pop		ZL
		pop		YH
		pop		YL
		pop		XH
		pop		XL
		pop		param2
		pop		param1
		pop		temp2
		pop		temp
		ret		


;**********************************************************************************
;*
;* StreamFile
;*
;* Main loop routine - this routine is called in the main loop.
;* This means no parameters passed in as-such (via param1,2, stack, etc) - everything
;* is communicated to this routine via variables.
;*
;* This routine "streams" a file off the disk and into the specified queue.
;* It is told (in variables) the starting cluster number of the file, as well as
;* the file length. It then streams that file into the queue until either it's 
;* commanded to stop, or the file comes to an end. Simple enough concept.
;*
;* Because this routine sometimes has to wait for the drive to seek to the next cluster,
;* it's implemented as a state machine. While it's waiting for the drive to seek it
;* will just return.
;*
;* To prevent this routine from hogging too much CPU time, it limits the number of
;* reads it performs from the drive, ie, it only streams a certain number of bytes
;* into the queue at a time. This is important because with a large MP3 data queue
;* it can spend so much time filling it that the task giving the data to the MP3 codec
;* chip may not get sufficient time, resulting in breaks in music playback. The number
;* of bytes that may be read per execution MUST be an 8-bit EVEN number, and is 
;* kept as the constant (.equ) StreamFile_MaxBytes.
;* 
;* The file length may be an odd number. It is the only odd "number of bytes"
;* number permitted. All other "byte count" type numbers MUST be even. This is because
;* bytes are read from the drive in pairs - the drive has a 16-bit bus. When we
;* determine the number of free bytes in the MP3 data queue we zero the LSB of the
;* result to ensure it too is an even number.
;*
;* From experience with my test drive, I've found that although I've commanded it to
;* read an entire cluster, it sometimes returns "busy" after reading only a couple
;* of sectors worth of data from that cluster. Hence... this routine is forced to
;* keep track of sectors, and check that the drive is ready before reading from
;* a new sector boundary. It keeps track of the number of bytes remaining in
;* the current sector in STREAMFILE_SEC_REM (it contains 512 & is decremented to zero).
;* The number of sectors remaining in the current cluster is stored in 
;* STREAMFILE_SECCLUS_REM (which starts at SEC_PER_CLUS and decrements to zero).
;* When a sector is finished (STREAMFILE_SEC_REM==0) the drive is checked to make
;* sure it's not busy. That's the purpose of the WaitDriveNotBusy state. 
;* When a cluster is finished (STREAMFILE_SECCLUS_REM==0)
;* the drive is seeked to the next cluster. All provided that we haven't been
;* commanded to stop; the file is not finished; etc.
;*
;* This routine may be commanded to stop at any time. For example, a file may be
;* playing and the user may press the "stop" key. Also, the file may end for a
;* couple of reasons. One is that the end of the file is reached (length has decremented
;* all the way down to zero). Another is that the file cluster chaining may have a
;* problem, causing the CalcNextCluster routine to return a ChainEnd error message.
;*
;* This routine knows only 3 commands: Stop, Stream, and StreamWithClusterNumbers.
;* StreamWithClusterNumbers inserts the 4-byte cluster number into the data Q low-byte first
;* at the beginning of that cluster's data. 
;*
;* Any routine wanting to know what this routine is doing may examine the state variable
;* STREAMFILE_ST. If a routine wants this routine to stream a file, it MUST wait until this 
;* routine is idle (it can force idle by issuing a stop command) before loading up the 
;* parameters and issuing the stream command. Changing the parameters while this routine 
;* is streaming a file will have unpredictable results.
;*
;* This routine functions as follows:
;*
;*
;* IDLE state:  (STREAMFILE_ST == StreamFile_St_Idle)
;*		If Command == Stop then return, else (command == stream):
;*		If filesize == 0 then 
;*				Write Stop into command variable & return
;*		Change state variable to SeekCluster state
;*		Jump to SeekCluster state
;*
;* SeekCluster State (STREAMFILE_ST == StreamFile_St_SeekClus)
;*		If SeekSector is idle then
;*				change state to SeekCluster2
;*				if Command == StreamFile_Cmd_SmWithCl put cluster number (STREAMFILE_CLUS) in Q, low byte first
;*				return
;*		else  (SeekSector busy)
;*				force SeekSector idle & return
;*
;* SeekCluster2 State (STREAMFILE_ST == StreamFile_St_SeekClus2)
;*		Store 512 in STREAMFILE_SEC_REM				 (# of bytes remaining in this sector)
;*		Store SEC_PER_CLUS in STREAMFILE_SECCLUS_REM	(# of sectors remaining in this cluster)
;*		Read cluster number from STREAMFILE_CLUS		
;*		Convert to a sector number & push onto stack
;*		Get number of sectors per cluster (SEC_PER_CLUS) into param1
;*		Command a seek to this sector (call SeekSector)
;*		If SeekSector does not return "done" then Return,  (we'll return to this state to try again)
;*		else (SeekSector is finished)	
;*				Change state variable to ReadData state
;*				Jump to ReadData state
;*
;* ReadData State (STREAMFILE_ST == StreamFile_St_ReadData)
;*		If Command == Stop then change state variable to idle state and return.
;*		Determine the lowest of:
;*				Bytes remaining in the file  (32 bits)					(odd or even)
;*				Free bytes remaining in the MP3 data queue  (16 bits)	(even only)
;*				Bytes remaining in the current sector  (16 bits)		(even only)
;*				Number of bytes read permitted per execution (8 bits)	(even only)
;*		Call this result NumBytes  (8 bit number) - keep a copy (NumberBytesRead)
;*		If NumBytes == 0 then return
;*				Read 2 bytes from drive
;*				Place first byte in MP3 data queue
;*				Decrement NumBytes
;*				If NumBytes == 0 then exit this loop
;*				Place second byte in MP3 data queue
;*				Decrement NumBytes
;*				If NumBytes != 0 then loop back to read from drive again
;*		Filesize (STREAMFILE_FILESZ) = Filesize - NumberBytesRead
;*		If FileSize == 0 then
;*				Write "stop" into command variable
;*				Change state variable to Idle state & return
;*		BytesRemainingInSector (STREAMFILE_SEC_REM) = BytesRemainingInSector - NumberBytesRead
;*		If BytesRemainingInSector != 0 then
;*				Return
;*		Else
;*				Decrement SectorsRemainingInCluster (STREAMFILE_SECCLUS_REM)
;*				If SectorsRemainingInCluster == 0 then
;*						Change state variable to LearnNextCluster
;*						Jump to LearnNextCluster state
;*				Change state variable to WaitDriveNotBusy
;*				Jump to WaitDriveNotBusy state
;*
;* WaitDriveNotBusy state  (STREAMFILE_ST == StreamFile_St_WaitDrv)
;*		Read drive status register
;*		If drive busy (BSY flag set) then return
;*		If drive not ready (RDY flag clear) then return
;*		Change state variable to ReadData
;*		Store 512 in STREAMFILE_SEC_REM				(# of bytes remaining in this sector)
;*		Return  
;*
;* LearnNextCluster state (STREAMFILE_ST == StreamFile_St_LearnClus)
;*		Get current cluster number (STREAMFILE_CLUS)
;*		Push it onto stack
;*		Call CalcNextCluster
;*		If result code == Busy then return
;*		If result code == ChainEnd then
;*				Write "stop" into command variable
;*				Change state variable to Idle state & return
;*		else  (result code == Done)
;*				Get new cluster number off stack & write into STREAMFILE_CLUS
;*				Change state variable to SeekCluster
;*				Jump to SeekCluster state
;*
;*
;* Accepts: Commands in STREAMFILE_CMD							(8 bits)
;*			Initial file cluster number in STREAMFILE_CLUS		(32 bits)
;*			Initial file length in STREAMFILE_FILESZ			(32 bit number of bytes)
;*			Queue to stream into in STREAMFILE_QPOINTER			(16 bit pointer)
;* Returns: State of the routine in STREAMFILE_ST				(8 bits)
;* Uses:	temp, temp2, param1, param2, X, Y, Z, r0, r1, r2, r3, r20, r21, flags
;*
;**********************************************************************************

StreamFile:

; If Command == Stop then change to idle state & return. Dangerous, because if StreamFile
; has kicked off another state machine, then suddenly stops (here), that other state machine
; will remain in an undefined state. Probably better to stop only at controlled times.
;		lds		temp,STREAMFILE_CMD				; get command
;		cpi		temp,StreamFile_Cmd_Stop
;		brne	StreamFileSD1					; branch forward if command NOT stop
;		ldi		temp,StreamFile_St_Idle			; but if command is stop...
;		sts		STREAMFILE_ST,temp				; change to IDLE state
;		ret										; and return

StreamFileSD1:
; Jump to the correct state  (this is the state dispatcher code)
		ldi		ZL,lo8(STREAMFILE_ST)
		ldi		ZH,hi8(STREAMFILE_ST)			; point Z to StreamFile state variable
		ld		temp,Z							; get the state
		cpi		temp,StreamFile_St_Idle
		breq	StreamFile_IDL_J				; branch if state is Idle
		cpi		temp,StreamFile_St_SeekClus
		breq	StreamFile_SC_J					; branch if state is SeekCluster
		cpi		temp,StreamFile_St_SeekClus2
		breq	StreamFile_SC2_J				; branch if state is SeekCluster2
		cpi		temp,StreamFile_St_ReadData
		breq	StreamFile_RD_J					; branch if state is ReadData
		cpi		temp,StreamFile_St_WaitDrv
		breq	StreamFile_WD_J					; branch if state is WaitDriveNotBusy
		cpi		temp,StreamFile_St_LearnClus
		breq	StreamFile_LC_J					; branch if state is LearnNextCluster
		
		ldi		temp,StreamFile_St_Idle			; otherwise it's an unknown state
		st		Z,temp							; so make the state to be idle
		ret										; and return

; jump table (because branches can't reach far enough in this routine)
StreamFile_IDL_J:		jmp		StreamFile_IDL
StreamFile_SC_J:		jmp		StreamFile_SC
StreamFile_SC2_J:		jmp		StreamFile_SC2
StreamFile_RD_J:		jmp		StreamFile_RD
StreamFile_WD_J:		jmp		StreamFile_WD

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -