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

📄 fat32.s

📁 Frank s MP3 Player Source Files
💻 S
📖 第 1 页 / 共 5 页
字号:
; Note that temp2 still contains zero from the previous calculations	
		ldi		ZL,lo8(STREAMFILE_SEC_REM)
		ldi		ZH,hi8(STREAMFILE_SEC_REM)		; Z points to bytes remaining in sect (16 bits)
		ld		temp,Z							; temp contains low byte of BytesRemaining
		sub		temp,r21						; subract NumBytesRead from lowbyte
		st		Z,temp							; store low byte back
		ldd		temp,Z+1						; temp contains next byte of BytesRemaining
		sbc		temp,temp2						; subtract the carry flag from it
		std		Z+1,temp						; and store the result back		

; If BytesRemainingInSector != 0 then Return
		ld		temp,Z							; get low byte of BytesRemaining
		cpi		temp,0
		brne	StreamFile_RD_9					; branch forward if low byte != 0
		ldd		temp,Z+1						; else get high byte of BytesRemaining
		cpi		temp,0
		breq	StreamFile_RD_10				; branch forward if high byte == 0
StreamFile_RD_9:
		ret										; return if BytesRemaining (16 bits) != 0

; execute here if BytesRemainingInSector (16 bits) == 0 
StreamFile_RD_10:		
; Decrement SectorsRemainingInCluster (STREAMFILE_SECCLUS_REM)
; If SectorsRemainingInCluster == 0 then
;		Change state variable to LearnNextCluster
;		Jump to LearnNextCluster state
		ldi		ZL,lo8(STREAMFILE_SECCLUS_REM)
		ldi		ZH,hi8(STREAMFILE_SECCLUS_REM)
		ld		temp,Z							; temp contains STREAMFILE_SECCLUS_REM
		dec		temp							; decrement it
		st		Z,temp							; and store the result
		brne	StreamFile_RD_11				; branch forward if it's NOT zero
		
		; execute here if SectorsRemainingInCluster == 0
		ldi		ZL,lo8(STREAMFILE_ST)
		ldi		ZH,hi8(STREAMFILE_ST)			; point Z to StreamFile state variable
		ldi		temp,StreamFile_St_LearnClus
		st		Z,temp							; store LearnNextCluster state
		jmp		StreamFile_LC					; jump to LearnNextCluster state

; execute here if SectorsRemainingInCluster != 0		
StreamFile_RD_11:
; Change state variable to WaitDriveNotBusy
; Jump to WaitDriveNotBusy state
		ldi		ZL,lo8(STREAMFILE_ST)
		ldi		ZH,hi8(STREAMFILE_ST)			; point Z to StreamFile state variable
		ldi		temp,StreamFile_St_WaitDrv
		st		Z,temp							; store WaitDriveNotBusy state
		rjmp	StreamFile_WD					; jump to WaitDriveNotBusy state

		
		
		
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WaitDriveNotBusy state
StreamFile_WD:
; Read drive status register
; If drive busy (BSY flag set) then return
		ldi		param1,IDERD_ST
		rcall	IDE_read8						; read drive status register
		sbrc	param1,IDEST_BSY_BIT			; skip forward if BSY bit clear
		ret										; BSY flag set so return

; If drive not ready (RDY flag clear) then return
		sbrs	param1,IDEST_RDY_BIT			; skip forward if RDY bit set
		ret										; return if RDY flag clear - drive not ready yet
		
; Change state variable to ReadData
; Store 512 in STREAMFILE_SEC_REM					(# of bytes remaining in this sector)
; Return
		ldi		ZL,lo8(STREAMFILE_ST)
		ldi		ZH,hi8(STREAMFILE_ST)			; point Z to StreamFile state variable
		ldi		temp,StreamFile_St_ReadData
		st		Z,temp							; state variable is ReadData
		ldi		ZL,lo8(STREAMFILE_SEC_REM)
		ldi		ZH,hi8(STREAMFILE_SEC_REM)		; Z now points to STREAMFILE_SEC_REM
		ldi		temp,lo8(512)
		st		Z+,temp							; store low byte of 512
		ldi		temp,hi8(512)
		st		Z,temp							; store high byte of 512 into STREAMFILE_SEC_REM		
		ret										; and return	




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; LearnNextCluster state
StreamFile_LC:
; Get current cluster number (STREAMFILE_CLUS)  (32 bits)
; Push it onto stack
		ldi		ZL,lo8(STREAMFILE_CLUS)
		ldi		ZH,hi8(STREAMFILE_CLUS) 
		ldd		temp,Z+3						; get high byte of current cluster number
		push	temp							; push high byte onto stack
		ldd		temp,Z+2
		push	temp
		ldd		temp,Z+1
		push	temp	
		ld		temp,Z					
		push	temp							; push low byte of cluster number onto stack

; Call CalcNextCluster
; If result code == Busy then return
		rcall	CalcNextCluster
		pop		r0								; low byte of potential result
		pop		r1
		pop		r2
		pop		r3								; high byte of potential result
		cpi		param1,CalNxCl_Busy
		brne	StreamFile_LC_1					; branch forward if CalcNextCluster not busy
		ret										; otherwise return

; execute here if CalcNextCluster not busy anymore		
StreamFile_LC_1:
; If result code == ChainEnd then
;		Write "stop" into command variable
;		Change state variable to Idle state & return
		cpi		param1,CalNxCl_ChainEnd
		brne	StreamFile_LC_2					; branch forward if result != ChainEnd
		
		; execute here if CalcNextCluster returned ChainEnd
		ldi		ZL,lo8(STREAMFILE_CMD)
		ldi		ZH,hi8(STREAMFILE_CMD)			; Z points to command variable
		ldi		temp,StreamFile_Cmd_Stop
		st		Z,temp							; write Stop into command variable
		ldi		ZL,lo8(STREAMFILE_ST)
		ldi		ZH,hi8(STREAMFILE_ST)			; point Z to StreamFile state variable
		ldi		temp,StreamFile_St_Idle
		st		Z,temp							; store Idle state		
		ret										; and return	

; execute here if result code != busy or Chainend, ie, result code is "done" (by default)
StreamFile_LC_2:
; Get new cluster number off stack & write into STREAMFILE_CLUS
; note that we cunningly already have resulting cluster number in r3:r0
		ldi		ZL,lo8(STREAMFILE_CLUS)
		ldi		ZH,hi8(STREAMFILE_CLUS)
		st		Z,r0							; store low byte of new cluster number
		std		Z+1,r1
		std		Z+2,r2
		std		Z+3,r3							; store high byte of new cluster number
		
; Change state varible to SeekCluster
; Jump to SeekCluster state		
		ldi		ZL,lo8(STREAMFILE_ST)
		ldi		ZH,hi8(STREAMFILE_ST)			; point Z to StreamFile state variable
		ldi		temp,StreamFile_St_SeekClus
		st		Z,temp							; store SeekCluster state
		jmp		StreamFile_SC					; jump to SeekCluster state
		
		
		
		
		

;**********************************************************************************
;*
;* CalcNextCluster
;*
;* This routine is the one that knows about the FAT32 file allocation table
;* structure. Given a cluster number, it looks in the FAT and determines what
;* the next cluster number for that file is.
;*
;* This routine functions as a state machine. This is because this routine
;* has to seek the drive to a particular sector (which it calculates based on
;* the requested cluster number) and it has to wait until the drive has
;* performed the seek.
;*
;* This routine must be called repeatedly. While it's waiting for the drive
;* it will just return "busy" to the calling function. Once it has managed to
;* get the next cluster number it returns "done" to the calling function, and
;* returns the cluster number. It returns "busy" or "done" in param1. It returns
;* the next cluster number on the stack (!), by replacing the passed-in cluster
;* number with the new cluster number. So that when the calling function does
;* its 4 pops to clean up the stack, it gets the new cluster number at the same time.
;*
;* If there is no next cluster number, ie, it's hit the end of the cluster chain,
;* it returns "ChainEnd".
;* 
;* The most complex part of this routine is calculating where in the drive the
;* FAT entry we need is. The FAT structure is simple: each cluster has 4 bytes
;* in the table, starting with cluster number 0. The start of the table is in
;* found in the FAT_START_SEC 16-bit variable. There are 512 bytes in each
;* sector, which corresponds to (512/4) 128 clusters.
;* Hence, the sector number containing our cluster entry is 
;* equal to: (cluster/128) + FAT_START_SEC
;* The offset into that sector will be: REMAINDER( cluster/128 ) x 4
;*
;* Dividing by 128 means shifting right 7 bits. This means losing the low 7 bits.
;* Determining remainder( cluster/128 ) is to simply take the low 7 bits of cluster.
;* Multiplying by 4 means shift left 2 bits (inserting zeros at the LSB of course).
;*
;* Although there are 4 bytes per cluster entry, each read of the drive
;* returns 2 bytes. So, in terms of number of drive reads, the offset into the
;* sector is only remainder(cluster/128) x 2. This is an 8-bit number.
;*
;* Just out of interest:
;* This relatively simple system only works because the FAT is a series of
;* consecutive sectors. Unlike directories and files, where clusters may be scattered
;* around the drive, resulting in the need to follow the cluster chains.
;*
;*
;* The following added Dec 21 2001 (and later)
;* As described above this routine has to seek the drive back to the FAT every time.
;* This is both very hard on the drive and it's slow. It would be nice to keep an
;* image of the FAT in SRAM; unfortunately this is not possible. So we'll do the
;* next best thing. Unfragmented files have consectutive cluster numbers. So when
;* it does a seek to a sector this routine can "look ahead" and determine if the next
;* few clusters are indeed consectutive. If they are it can hold this information
;* in a couple of variables, so that if it's asked about one of those clusters
;* (which it likely will be) it already knows the answer is "the next cluster" and
;* can respond accordingly, without having to reread the FAT. That's the concept.
;* In practice: the 32-bit number CALNXCL_CLUS_LO holds the low cluster number, and
;* CALNXCL_CLUS_HI holds the high cluster number, for the series of clusters we know 
;* (from looking ahead in the FAT) that are consecutive. Important: for this series
;* of clusters, _including_ the lo and hi numbers, we know that the next cluster
;* number is the current cluster number +1. If the next cluster in the FAT is not
;* consecutive (ie fragmented file) then we'll detect that and make the hi cluster
;* number zero. For example, in the FAT (decimal numbers shown):
;*
;* Current cluster #	Next cluster # (this column is the actual FAT entries)
;*		17						18
;*		18						19
;*	 -> 19						20
;*		20						21
;*		21						22
;*		22						23
;*		23						24
;*		24						39
;*								40
;*				
;* Let's say we're called asking what the next cluster number is for a current
;* cluster 19. We look in the FAT and see the answer is 20. This is a consecutive
;* number, ie the file is not fragmented here, so we continue on. (If the answer was
;* not 20, ie the file was fragmented, we would zero the hi variable and just return
;* 20. But for this example it's not fragmented here...) Because it's consecutive
;* we write 20 into the lo variable and look at the next number, in this case 21, which
;* is again consecutive. If it was not we would zero the hi variable and return. But it's
;* OK so we look again and see 22, then 23, then 24, then 39 (!). So either the file is 
;* fragmented or it's finished; this routine has no way of knowing. But the variables
;* would contain: CALNXCL_CLUS_LO = 20 and CALNXCL_CLUS_HI = 23 for this example.
;* It will only read the FAT until either it finds a fragmentation OR it reaches the
;* end of the current sector. Seeing as CALNXCL_OF contains the number of drive reads 
;* required to reach the current cluster number, and then at that point it will perform
;* 2 reads to get the next cluster number, the number of drive reads this code section
;* can perform from the current sector is 256 - (CALNXCL_OF + 2), ie 254 - CALNXCL_OF.
;*
;*
;* This routine functions as follows:
;*
;* SeekDrive state  (CALNXCL_ST = CalNxCl_SDS)
;*		If SeekSector is idle then
;*				change state to SeekDrive2 & return with busy
;*		else
;*				force SeekSector idle & return with busy
;*
;* SeekDrive2 state  (CALNXCL_ST = CalNxCl_SDS2)
;*		Pull current cluster number off stack (32 bit value)
;*		IF current_cluster >= CALNXCL_CLUS_LO AND current_cluster <= CALNXCL_CLUS_HI
;*		  THEN return current_cluster + 1 (via the stack)
;*		Calculate offset (drive reads) into sector = remainder(cluster/128) x 2
;*		Write result into CALNXCL_OF  (8 bit value)
;*		Calculate FAT sector number = (Cluster/128) + FAT_START_SEC
;*		Command drive to seek to that sector
;*		Store that sector number (for use by the next state)
;*		Change state variable to GetCluster
;*		Write CalNxCl_Busy into param1
;*		Return
;*
;* GetCluster state  (CALNXCL_ST = CalBxCl_GCS)
;*		If drive not seeked yet then return with CalNxCl_Busy in param1
;*		Perform CALNXCL_OF reads of the drive (and throw away the data)
;*		Read the next 4 bytes (2 16-bit drive reads) - this is cluster number
;*		If cluster number == $0FFFFFFF then return with CalNxCl_ChainEnd in param1 & revert to SeekDrive state
;*		Write cluster number onto stack, replacing passed-in cluster number
;*		  (the following indented lines added to implement the FAT pseudo-caching)
;*		  Store this new cluster number in CALNXCL_CLUS_LO
;*		  read_counter = 254 - CALNXCL_OF
;*		  if read_counter == 0 then zero CALNXCL_CLUS_HI and hop forward (out of indented code)
;*		  next_cluster_temp = CALNXCL_CLUS_LO + 1 (a prediction of what we want the next cluster to be)
;*		  Read the next 4 bytes (2 16-bit drive reads) - this is the next cluster number
;*		  if this next cluster number != next_cluster_temp then zero CALNXCL_CLUS_HI and hop forward (out of indented code)
;*		  CALNXCL_CLUS_HI = next_cluster_temp - 1
;*		  decrement read_counter by 2
;*		  WHILE read_counter != 0 do {
;*			next_cluster_temp += 1
;*			Read the next 4 bytes (2 16-bit drive reads) - this is the next cluster number
;*			if this next cluster number != next_cluster_temp then break out of the while loop
;*			CALNXCL_CLUS_HI = next_cluster_temp - 1
;*			decrement read_counter by 2
;*			}
;*		Change state variable to SeekDrive
;*		Write CalNxCl_Done into param1
;*		Return
;*		
;* 
;* All values are read from the drive low-byte first.
;*
;*
;* Accepts: cluster number on the stack (32 bit value)
;* Returns: result code in param1; next cluster number on the stack
;* Uses:	temp, temp2, param1, param2, Z, r0, r1, r2, r3, flags. 
;*			
;*
;**********************************************************************************

CalcNextCluster:

; Jump to the correct state  (this is the state dispatcher code)
		ldi		ZL,lo8(CALNXCL_ST)
		ldi		ZH,hi8(CALNXCL_ST)				; point Z to CalcNextCluster state variable
		ld		temp,Z							; get the state
		cpi		temp,CalNxCl_SDS
		breq	CalcNextCluster_SDS				; branch if state is SeekDrive
		cpi		temp,CalNxCl_SDS2
		breq	CalcNextCluster_SDS2			; branch if state is SeekDrive2
		jmp		CalcNextCluster_GCS				; otherwise jump to GetCluster state



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

⌨️ 快捷键说明

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