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

📄 ide.s

📁 Frank s MP3 Player Source Files
💻 S
📖 第 1 页 / 共 3 页
字号:
;*
;* C-callable version of SeekSector
;*
;* Prototype is:
;*
;* u08 SeekSectorC (u32 startsector, u08 numsectors);
;*
;* The C compiler passes in numsectors in r20, and startsector in r25:r22
;* It expects a result in r24. Call it a bunch of times and it'll return SeekSect_Done
;* when it's finished.
;*
;**********************************************************************************

SeekSectorC:
    push    temp
    push    param1
    push    param2
    push    ZL
    push    ZH                              ; preserve registers used by SeekSector
    
    mov     param1,r20                      ; numsectors in param1
    push    r25
    push    r24
    push    r23
    push    r22                             ; starting sector on the stack
    rcall   SeekSector
    pop     r22
    pop     r23
    pop     r24
    pop     r25                             ; restore the stack
    mov     r24,param1                      ; move result into r24 for the C compiler

    pop     ZH
    pop     ZL
    pop     param2
    pop     param1
    pop     temp
    ret





;**********************************************************************************
;*
;* SeekSector
;*
;* This routine seeks to the specified sector. The sector number is a 32-bit
;* number passed in via the STACK. The top of the stack contains the low byte;
;* the 4th byte read off the stack is the high byte. Param1 contains the
;* number of sectors required. 
;*
;* Because we have to wait for the drive to seek, this routine is a state machine.
;* The first state initiates the seek. The second state returns "busy" to the calling
;* function until the seek is complete. The calling function must call SeekSect
;* repeatedly until it receives a "done". At that time the drive is ready for 
;* data reads.
;*
;* It is possible for the first Read Sectors command after drive power-up to fail.
;* This is most likely due to the drive not being properly up to speed yet. Should
;* the drive report an error at the completion of the command, simply tell it to
;* do it again.
;*
;* This routine functions as follows:
;*
;* InitSeek state  (SEEKSECT_ST == SeekSect_ISS)
;*		If (drive busy OR drive not ready) then return with param1=SeekSect_Busy
;*		Write param1 to the SECTOR COUNT register (tell drive how many sectors to get)
;*		Write the sector number (4 bytes) into the command block registers and enable LBA
;*		Issue the READ SECTORS WITH RETRY ($20) command
;*		Change state to WaitSeek
;*		Return with param1=SeekSect_Busy
;*
;* WaitSeek state (SEEKSECT_ST == SeekSect_WSS)
;*		If drive busy or DriveSeek not complete yet then return with param1=SeekSect_Busy
;*		If drive reports no error then
;*				Change state to InitSeek
;*				Write SeekSect_Done into param1
;*				Return
;*		Else  (drive had an error)
;*				Do a dummy read of the drive error register
;*				Change state to InitSeek
;*				Return with param1=SeekSect_Busy   (to redo the whole seek)
;*
;*
;* When reading data off the drive, the first byte on the drive is the low byte read
;* by the AVR; the next byte is the high byte.
;*
;*
;* Accepts: sector number on stack, number of sectors in param1
;* Returns: Busy or Done in param1
;* Uses:	temp, param1, param2, ZL, ZH, flags. 
;*
;**********************************************************************************

SeekSector:

; Jump to the correct state  (this is the state dispatcher code)
		ldi		ZL,lo8(SEEKSECT_ST)
		ldi		ZH,hi8(SEEKSECT_ST)				; point Z to SeekSector state variable
		ld		temp,Z							; get the state
		cpi		temp,SeekSect_WSS
		breq	SeekSector_WSS					; branch if state is WaitSeek


;* InitSeek state
;* Execute here for the idle state, the InitSeek state.
; First we check for drive busy or ready, and return if required.
		push	param1							; preserve the number of sectors
		ldi		param1,IDERD_ST
		rcall	IDE_read8						; read drive status register
		sbrc	param1,IDEST_BSY_BIT			; skip forward if BSY bit clear
		rjmp	SeekSector_ISS_1				; jump if drive is busy
		sbrc	param1,IDEST_RDY_BIT			; skip forward if RDY bit clear
		rjmp	SeekSector_ISS_2				; jump if drive is ready

; execute here if drive busy OR drive not ready
SeekSector_ISS_1:		

;		ldi		param1,IDERD_ST
;		call	IDE_read8						; read drive register	
;		call	UART_PutHexWait					; debug only
;		ldi		param1,13
;		call	UART_TxCharWait					; debug only
;		ldi		param1,10
;		call	UART_TxCharWait					; debug only

		pop		param1							; clean the stack
		ldi		param1,SeekSect_Busy
		ret										; return with "SeekSector routine busy" 
		
; execute here if drive not busy AND drive is ready
SeekSector_ISS_2:
		pop		param2							; restore number of sectors now in param2
; write number of sectors into sector count register
SeekSector_ISS_3:
		ldi		param1,IDEWR_SC					; sector count register address in param1
		rcall	IDE_write8						; write number to SECTOR COUNT register 

; write the sector number to the LBA registers and enable LBA
		in		ZL,SPL
		in		ZH,SPH
		adiw	ZL,3							; Z points to low byte parameter on stack
		ldi		param1,IDEWR_LBA0
		ld		param2,Z+
		rcall	IDE_write8						; write low byte to LBA byte 0
		ldi		param1,IDEWR_LBA1
		ld		param2,Z+
		rcall	IDE_write8						; write byte 1 to LBA byte 1
		ldi		param1,IDEWR_LBA2
		ld		param2,Z+
		rcall	IDE_write8						; write byte 2 to LBA byte 2
		ldi		param1,IDEWR_LBA3
		ld		param2,Z+						; get high byte (sector number) off stack
		ori		param2,0b11100000				; enable LBA in LBA byte 3 register
		rcall	IDE_write8						; and give it to the drive

; issue command READ SECTORS WITH RETRY ($20) to the drive
		ldi		param1,IDEWR_CMD				; param1: command register address
		ldi		param2,0x20						; param2: $20
		rcall	IDE_write8						; write command to drive		

; change state to WaitSeek and return with param1 saying "busy"
		ldi		ZL,lo8(SEEKSECT_ST)
		ldi		ZH,hi8(SEEKSECT_ST)				; point Z to SeekSector state variable
		ldi		temp,SeekSect_WSS
		st		Z,temp							; next state is WaitSeek
		ldi		param1,SeekSect_Busy
		ret										; return with Busy param1 code



;* WaitSeek state
;* Execute here if the required state is WaitSeek
SeekSector_WSS:
		mov		param2,param1					; keep a copy of number of sectors in param2
; if drive busy or DriveSeek not complete yet then return with Busy code in param1
		ldi		param1,IDERD_ST
		rcall	IDE_read8						; read drive status register
		
		sbrc	param1,IDEST_BSY_BIT			; skip forward if BSY bit clear
		rjmp	SeekSector_WSS_3				; jump if busy bit set - drive is busy		  

		sbrc	param1,IDEST_ERR_BIT			; skip forward if error bit clear
		rjmp	SeekSector_WSS_2				; jump if error bit set

		sbrs	param1,IDEST_DSC_BIT			; skip forward if DriveSeekComplete bit set
		rjmp	SeekSector_WSS_3				; jump if DriveSeekComplete bit clear (drive not seeked yet)

		sbrs	param1,IDEST_RDY_BIT			; skip forward if Ready bit set
		rjmp	SeekSector_WSS_3				; jump if Ready bit clear (drive not ready yet)

		sbrc	param1,IDEST_COR_BIT			; skip forward if Corrected Data bit clear
		rjmp	SeekSector_WSS_2				; jump if Corrected Data bit set

		rjmp	SeekSector_WSS_1				; if here, everything good, we're green to go...
		
; execute here if drive busy (BSY bit set) or DriveSeekComplete bit clear
SeekSector_WSS_3:
		ldi		param1,SeekSect_Busy
		ret										; return with Busy param1 code

; execute here if drive not busy (BSY bit clear) AND drive reports no errors (ERR bit clear)
; change state to InitSeek and tell calling function we're done; drive is seeked
SeekSector_WSS_1:
		ldi		ZL,lo8(SEEKSECT_ST)
		ldi		ZH,hi8(SEEKSECT_ST)				; point Z to SeekSector state variable
		ldi		temp,SeekSect_ISS
		st		Z,temp							; next state is InitSeek
		ldi		param1,SeekSect_Done
		ret										; return with Done; drive is seeked
				
; execute here if drive reported an error (error bit in status register set)
; do a dummy read from the drive error register, change the state to InitSeek,
; and return saying busy. This way we'll redo the entire seek again.
SeekSector_WSS_2:

; debug - print out the parameters which resulted in the error
		call	UART_PutHexWait					; print drive status register value
		ldi		param1,' '
		call	UART_TxCharWait
		mov		param1,param2
		call	UART_PutHexWait					; print number of sectors
		ldi		param1,' '
		call	UART_TxCharWait
		in		ZL,SPL
		in		ZH,SPH
		adiw	ZL,7							; Z points to high byte parameter on stack
		ld		param1,-Z
		call	UART_PutHexWait					; print high sector number byte
		ld		param1,-Z
		call	UART_PutHexWait					
		ld		param1,-Z
		call	UART_PutHexWait					
		ld		param1,-Z								
		call	UART_PutHexWait					; print low byte of sector number
		ldi		param1,' '
		call	UART_TxCharWait					
		ldi		param1,'S'
		call	UART_TxCharWait 
		ldi		param1,'e'
		call	UART_TxCharWait 
		ldi		param1,'e'
		call	UART_TxCharWait 
		ldi		param1,'k'
		call	UART_TxCharWait			
		ldi		param1,'S'
		call	UART_TxCharWait 
		ldi		param1,'e'
		call	UART_TxCharWait			
		ldi		param1,'c'
		call	UART_TxCharWait 
		ldi		param1,'t'
		call	UART_TxCharWait 
		ldi		param1,'o'
		call	UART_TxCharWait 
		ldi		param1,'r'
		call	UART_TxCharWait					
		ldi		param1,13
		call	UART_TxCharWait					; CR
		ldi		param1,10
		call	UART_TxCharWait					; LF
; end of debug code

		ldi		param1,IDERD_ERR
		rcall	IDE_read8						; dummy read of drive error register
		ldi		temp,SeekSect_ISS
		sts		SEEKSECT_ST,temp				; next state is InitSeek
		ldi		param1,SeekSect_Busy
		ret										; return with busy
		



;**********************************************************************************
;*
;* PrintDriveData
;* 
;* This routine prints out 16 lines of 16 bytes of hex data
;* from the drive data buffer.
;*
;* This routine is just used for debug purposes.
;*
;* R14 is the outer loop counter (line counter); R15 is the inner loop (byte) counter.
;*
;* Accepts: Nothing
;* Returns: Nothing
;* Uses:	param1, param2, temp, r14, r15, r20, r21, r23, r24, r26 (X low), flags 
;*			XL, XH, ZL, ZH
;*
;**********************************************************************************

PrintDriveData:

; wait for drive to clear busy flag
		ldi		param1,IDERD_ST
		rcall	IDE_read8						; read status register
		sbrc	param1,IDEST_BSY_BIT			; skip forward if BSY bit clear
		rjmp	PrintDriveData
		
		ldi		param1,13
		rcall	UART_TxCharWait					; print a CR
		ldi		param1,10
		rcall	UART_TxCharWait					; print a LF	
		ldi		param1,10
		rcall	UART_TxCharWait					; print a LF	
		
		ldi		temp,20
		mov		r14,temp						; 16 iterations of the outer (line) loop

PrintDriveData100_o:
		ldi		temp,8
		mov		r15,temp						; 8 iterations of the inner (byte) loop
PrintDriveData100_i:							;  with 2 bytes output per iteration
		ldi		param1,IDERD_DATA				; read 16-bit data word from the drive
		rcall	IDE_read16						; low byte returned in param1; high in param2
		rcall	UART_PutHexWait					; put low byte out the uart
		ldi		param1,' '
		rcall	UART_TxCharWait					; print a space
		mov		param1,param2
		rcall	UART_PutHexWait					; put high byte out the uart
		ldi		param1,' '
		rcall	UART_TxCharWait					; print a space
		dec		r15
		brne	PrintDriveData100_i				; repeat inner loop until r15==0
		
		ldi		param1,13
		rcall	UART_TxCharWait					; print a CR
		ldi		param1,10
		rcall	UART_TxCharWait					; print a LF	

		dec		r14
		brne	PrintDriveData100_o				; repeat outer loop until r14==0
				
		ret
		




⌨️ 快捷键说明

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