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

📄 fat32.s

📁 Frank s MP3 Player Source Files
💻 S
📖 第 1 页 / 共 5 页
字号:
CalcNextCluster_SDS:
;* SeekDrive state - Execute here for the first state - SeekDrive
;* This state simply makes sure that SeekSector is idle before proceeding
		lds		temp,SEEKSECT_ST
		cpi		temp,SeekSect_ISS				; is SeekSector idle?
		breq	CalcNextC_SDSAA					; yes - branch forward

; print debug message if SeekSector not idle, because it certainly should be
		ldi		param1,'C'
		call	UART_TxCharWait 
		ldi		param1,'N'
		call	UART_TxCharWait 
		ldi		param1,'C'
		call	UART_TxCharWait 
		ldi		param1,'-'
		call	UART_TxCharWait 
		ldi		param1,'S'
		call	UART_TxCharWait 
		ldi		param1,'1'
		call	UART_TxCharWait 
		ldi		param1,'\n'
		call	UART_TxCharWait 
		ldi		param1,'\r'
		call	UART_TxCharWait 
; end debug code
		ldi		temp,SeekSect_ISS
		sts		SEEKSECT_ST,temp				; force SeekSector into idle state
		ldi		param1,CalNxCl_Busy				;		say we're busy
		ret										;		and return to check again next time
		
; execute here if SeekSector is idle
CalcNextC_SDSAA:
		ldi		temp,CalNxCl_SDS2
		sts		CALNXCL_ST,temp					; next state is CalcNextCluster2
		ldi		param1,CalNxCl_Busy				; (say we're busy - just in case you want to return)
		jmp		CalcNextCluster_SDS2			; might as well jump to the next state now										


		
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CalcNextCluster_SDS2:
;* SeekDrive2 state - Execute here for the second state - SeekDrive2
; Pull current cluster number off stack (32 bit value)
		in		ZL,SPL
		in		ZH,SPH
		adiw	ZL,3							; Z points to low byte of cluster number
		ld		r0,Z+							; r0 contains low byte
		ld		r1,Z+
		ld		r2,Z+
		ld		r3,Z+							; r3 contains high byte of cluster number

; IF current_cluster >= CALNXCL_CLUS_LO AND current_cluster <= CALNXCL_CLUS_HI
;  THEN return current_cluster + 1 (via the stack)
; (note that for the second code paragraph below, 2 conditional branch instructions were
; required because the AVR doesn't have a branch-if-higher instruction. Bummer. )
		lds		temp,CALNXCL_CLUS_LO			; get the low byte
		cp		r0,temp							; we will do a compare, as:
		lds		temp,CALNXCL_CLUS_LO+1			; current_cluster - CALNXCL_CLUS_LO, and 
		cpc		r1,temp							; we'll branch forward 
		lds		temp,CALNXCL_CLUS_LO+2			; if current_cluster < CALNXCL_CLUS_LO
		cpc		r2,temp
		lds		temp,CALNXCL_CLUS_LO+3
		cpc		r3,temp							; finish with the high byte
		brlo	CNC_SD_2						; branch for "cache miss" if current_cluster < CALNXCL_CLUS_LO
		
		lds		temp,CALNXCL_CLUS_HI			; get the low byte
		cp		r0,temp							; we will do a compare, as:
		lds		temp,CALNXCL_CLUS_HI+1			; current_cluster - CALNXCL_CLUS_HI, and 
		cpc		r1,temp							; we'll branch forward for a "cache miss" if...
		lds		temp,CALNXCL_CLUS_HI+2			; if current_cluster > CALNXCL_CLUS_HI
		cpc		r2,temp
		lds		temp,CALNXCL_CLUS_HI+3
		cpc		r3,temp							; finish with the high byte		
		breq	CNC_SD_1						; branch for "cache hit" if current_cluster == CALNXCL_CLUS_HI
		brsh	CNC_SD_2						; branch for "cache miss" if current_cluster > CALNXCL_CLUS_HI
		
; execute here if we had a "cache hit"; ie, we know that for the current cluster number, the
; next cluster is simply the current cluster plus 1. So, add 1 to the current cluster number,
; put the result on the stack and return "done".
CNC_SD_1:
		ldi		temp,1							; add 1 to the low byte of the current cluster number
		add		r0,temp
		ldi		temp,0					
		adc		r1,temp							; then move the carry flag through the high 3 bytes
		adc		r2,temp
		adc		r3,temp

		st		-Z,r3							; Z currently points one byte past the previous r3 read
		st		-Z,r2							; so store the new cluster number back in reverse order
		st		-Z,r1							; onto the stack
		st		-Z,r0							
		
		ldi		param1,CalNxCl_Done
		ret										; and finally, return with "done"
		
; execute here if we had a "cache miss" and hence we need to read from the drive
; Calculate offset (drive reads) into sector = remainder(cluster/128) x 2
; and store result in CALNXCL_OF
CNC_SD_2:
		mov		temp,r0							; get low byte of cluster number
		andi	temp,0b01111111					; we only want the low 7 bits - this is Remainder(cluster/128)
		lsl		temp							; multiply by 2
		ldi		ZL,lo8(CALNXCL_OF)
		ldi		ZH,hi8(CALNXCL_OF)				; Z points to CALNXCL_OF
		st		Z,temp							; store calculation result in CALNXCL_OF		

; Calculate FAT sector number = (Cluster/128) + FAT_START_SEC
; note that dividing by 128 is a shift right 7 times
		ldi		temp,7							; count of how many times to shift
CalcNextCluster_1:
		lsr		r3								; shift high byte to the right
		ror		r2
		ror		r1
		ror		r0								; shift right through carry
		dec		temp
		brne	CalcNextCluster_1				; loop back if we have more shifts to do
; now we need to add FAT_START_SEC to our results so far which are in r3:r0
		ldi		ZL,lo8(FAT_START_SEC)
		ldi		ZH,hi8(FAT_START_SEC)			; Z points to FAT_START_SEC low byte
		ld		temp,Z+							; temp contains FAT_START_SEC low byte
		add		r0,temp							; add the low bytes
		ld		temp,Z							; get FAT_START_SEC high byte without affecting carry flag
		adc		r1,temp							; add it in with carry
		ldi		temp,0
		adc		r2,temp
		adc		r3,temp							; add the carry in through the high bytes
		
; Command drive to seek to that sector (which is in r3:r0)
		push	r3
		push	r2
		push	r1
		push	r0								; push sector number onto stack
		ldi		param1,1						; we only want a single sector
		rcall	SeekSector						; start the SeekSector state machine running
		pop		r0
		pop		r1
		pop		r2
		pop		r3								; clean up stack & restore sector number

; store the sector number (32 bits) for use by the next task
		ldi		ZL,lo8(CALNXCL_SN)
		ldi		ZH,hi8(CALNXCL_SN)				; point Z to sector number variable
		st		Z+,r0							; store low byte first
		st		Z+,r1
		st		Z+,r2
		st		Z,r3							; store high byte last
				
; Change state variable to GetCluster
		ldi		ZL,lo8(CALNXCL_ST)
		ldi		ZH,hi8(CALNXCL_ST)				; point Z to CalcNextCluster state variable
		ldi		temp,CalNxCl_GCS
		st		Z,temp							; state variable now contains GetCluster

; Write CalNxCl_Busy into param1 and return				
		ldi		param1,CalNxCl_Busy
		ret
		
				

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GetCluster state - Execute here for the second (GetCluster) state
CalcNextCluster_GCS:
; If drive not seeked yet then return with CalNxCl_Busy in param1
; Note that SeekSector requires the sector number parameter via the stack
		ldi		ZL,lo8(CALNXCL_SN)
		ldi		ZH,hi8(CALNXCL_SN)				; point Z to sector number variable
		ld		r0,Z+							; read low byte first
		ld		r1,Z+
		ld		r2,Z+
		ld		r3,Z							; read high byte last
		push	r3								; push high byte first
		push	r2
		push	r1
		push	r0
		ldi		param1,1						; we only want a single sector
		rcall	SeekSector
		pop		temp
		pop		temp
		pop		temp
		pop		temp							; clean up the stack
		cpi		param1,SeekSect_Done
		breq	CalcNextCluster_2				; branch forward if SeekSector done
		
		ldi		param1,CalNxCl_Busy
		ret										; otherwise return saying Busy

; Perform CALNXCL_OF reads of the drive (and throw away the data)
CalcNextCluster_2:
		ldi		ZL,lo8(CALNXCL_OF)
		ldi		ZH,hi8(CALNXCL_OF)				; Z points to CALNXCL_OF (8 bit value)
		ld		temp2,Z							; temp2 is count of dummy reads required
CalcNextCluster_3:
		cpi		temp2,0							; are we done doing dummy reads?
		breq	CalcNextCluster_4				; branch if we're done with the dummy reads
		
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16						; and ignore the result
		dec		temp2
		brne	CalcNextCluster_3				; loop back if more dummy reads to do
		
; Read the next 4 bytes (2 16-bit drive reads) - this is cluster number
; We'll get them low byte to high byte - store in r3:r0  (r0 is low byte)
CalcNextCluster_4:
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16
		mov		r0,param1						; low byte of cluster number in r0
		mov		r1,param2						
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16
		mov		r2,param1						
		mov		r3,param2						; high byte of cluster number in r3
		ldi		temp,0x0f
		and		r3,temp							; we must ignore high 4 bits of cluster number - reserved bits
		
; If cluster number == $0FFFFFFF then return with CalNxCl_ChainEnd in param1; revert to initial state
		ldi		temp,0xFF
		cp		r0,temp
		brne	CalcNextCluster_5				; if byte 0 (low byte) != $FF then branch forward
		cp		r1,temp
		brne	CalcNextCluster_5				; if byte 1 != $FF then branch forward  
		cp		r2,temp
		brne	CalcNextCluster_5				; if byte 2 != $FF then branch forward
		ldi		temp,0x0F
		cp		r3,temp
		brne	CalcNextCluster_5				; if byte 3 (high byte) != $0F then branch forward

		ldi		param1,CalNxCl_ChainEnd			; execute here if cluster number == $0FFFFFFF
		ldi		temp,CalNxCl_SDS
		sts		CALNXCL_ST,temp					; state variable now contains SeekDrive 
		ret										

; Write new cluster number onto stack, replacing passed-in cluster number
CalcNextCluster_5:
		in		ZL,SPL
		in		ZH,SPH							; Z points to the low byte of the original
		adiw	ZL,3							;	passed-in cluster number
		st		Z+,r0							; write low byte of new cluster number
		st		Z+,r1
		st		Z+,r2
		st		Z+,r3							; write high byte of new cluster number


; Store this new cluster number in CALNXCL_CLUS_LO
		sts		CALNXCL_CLUS_LO,r0				; store low byte first
		sts		CALNXCL_CLUS_LO+1,r1
		sts		CALNXCL_CLUS_LO+2,r2
		sts		CALNXCL_CLUS_LO+3,r3
		
; read_counter = 254 - CALNXCL_OF
		ldi		temp2,254						; temp2 will be read_counter
		lds		temp,CALNXCL_OF
		sub		temp2,temp						; read_counter = 254 - CALNXCL_OF

; if read_counter == 0 then zero CALNXCL_CLUS_HI and hop forward (out of indented code)
		brne	CNC_GC_1						; branch forward if read_counter != 0
		rjmp	CalcNextCluster_8				; otherwise jump out because read_counter == 0
CNC_GC_1:

; next_cluster_temp = CALNXCL_CLUS_LO + 1 (a prediction of what we want the next cluster to be)
		ldi		temp,1
		add		r0,temp							; next_cluster_temp is r3:r0
		ldi		temp,0
		adc		r1,temp
		adc		r2,temp
		adc		r3,temp

; 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)
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16						; param2:param1 contains low "next cluster" nibble
		cp		param1,r0						; compare low bytes of next cluster versus next_cluster_temp
		brne	CalcNextCluster_8				; and branch if not the same
		cp		param2,r1
		brne	CalcNextCluster_8				; similarly for the next byte
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16						; param2:param1 contains high "next cluster" nibble
		cp		param1,r2						; compare bytes of next cluster versus next_cluster_temp
		brne	CalcNextCluster_8				; and branch if not the same
		cp		param2,r3
		brne	CalcNextCluster_8				; similarly for the highest byte

; CALNXCL_CLUS_HI = next_cluster_temp - 1
; decrement read_counter by 2
		ldi		temp,1
		sub		r0,temp
		ldi		temp,0
		sbc		r1,temp
		sbc		r2,temp
		sbc		r3,temp							; next_cluster_temp = next_cluster_temp - 1
		sts		CALNXCL_CLUS_HI,r0				; and store result in CALNXCL_CLUS_HI
		sts		CALNXCL_CLUS_HI+1,r1			
		sts		CALNXCL_CLUS_HI+2,r2			; NOTE we'll have to add 2 to next_cluster_temp when incrementing
		sts		CALNXCL_CLUS_HI+3,r3			; it, to make up for this -1 we just did

		subi	temp2,2							; read_counter = read_counter - 2

; WHILE read_counter != 0 do {
		breq	CalcNextCluster_9				; branch out of the WHILE if read_counter reaches zero
CalcNextCluster_6:

;  next_cluster_temp += 1
		ldi		temp,2
		add		r0,temp							; NOTE that we're adding 2, because when we did the
		ldi		temp,0							; CALNXCL_CLUS_HI = next_cluster_temp - 1 instruction,
		adc		r1,temp							; we decremented next_cluster_temp by 1 while doing it
		adc		r2,temp
		adc		r3,temp

;  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
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16						; param2:param1 contains low "next cluster" nibble
		cp		param1,r0						; compare low bytes of next cluster versus next_cluster_temp
		brne	CalcNextCluster_9				; and branch out of the WHILE if not the same
		cp		param2,r1
		brne	CalcNextCluster_9				; similarly for the next byte
		ldi		param1,IDERD_DATA				; do a read of the drive's data register
		call	IDE_read16						; param2:param1 contains high "next cluster" nibble
		cp		param1,r2						; compare bytes of next cluster versus next_cluster_temp

⌨️ 快捷键说明

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