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

📄 ata.asm

📁 老外个人做的MP3/优盘。使用ATMEL MEGA系列的MCU
💻 ASM
字号:
/* ***********************************************************************
**
**  Copyright (C) 2002  Jesper Hansen <jesperh@telia.com> and 
**			Romuald Bialy (MIS) <romek_b@o2.pl>.
**
**
**  Yampp-3/USB - low level support library
**
**
*************************************************************************
**
**   This file is part of the yampp system.
**
**  This program is free software; you can redistribute it and/or
**  modify it under the terms of the GNU General Public License
**  as published by the Free Software Foundation; either version 2
**  of the License, or (at your option) any later version.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program; if not, write to the Free Software Foundation, 
**  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
**
*************************************************************************
**
**  Revision History
**
**  when         what  who	why
**
**  2002-09-01   1.0   MIS      initial public release
**  2003-04-10   1.1   MIS      code size optimisation
**  2003-05-06   1.1   MIS      little code speed-up
**
*********************************************************************** */

#if((__GNUC__ * 1000 + __GNUC_MINOR__) != 3003)
 #error ___ Wrong compiler version !  Use GCC 3.3 ___
#endif

#define __ASSEMBLER__ 1
#define __SFR_OFFSET 0
#include <avr/io.h>
//#include <io-avr.h>

#define ATA_ASM
#include "ata.h"

#define __tmp_reg__	r0
#define __zero_reg__	r1

;#define SLOW_DISK

	.section	.text

.extern delay10
.extern ramdisable
.extern ramenable

 
;******************************************************************************* 
;*
;* ATA Interface stuff
;* 
;******************************************************************************* 
 

; 512 byte sector buffer in internal RAM
	.comm	ata_sbuf,512
	.comm	ata_drive,1
	
	.comm	ata_cmd,1
	.comm	ata_fun,1
	.comm	ata_stat,1

;				  r24	
;void setaddress(u08 reg);
	.global setaddress
setaddress:
		call	ramdisable		; disable RAM 
		ser	r25
						; make sure PORTA and C is outputs
		out	DDRA,r25
		out	DDRC,r25

		out	PORTA,r24
;		out	PORTC,__zero_reg__
						; flip ALE
		sbi	PORTE,PE1
		cbi	PORTE,PE1
		ret


		
;			    r24
;u08 ReadBYTE(u08 reg);
	.global	ReadBYTE
ReadBYTE:
		rcall	setaddress		; setup address on latch
 		out 	DDRA, __zero_reg__	; outp(0x00, DDRA);	// port A as input
  		out	DDRC, __zero_reg__	; outp(0x00, DDRC);	// port C as input
		ser	r25
 		out 	PORTA,r25		; activate pullup on port A
;		nop
		cbi	PORTB,DIOR		; set DIOR lo
		nop				; delay
#ifdef SLOW_DISK
		nop
#endif
		in	r24,PINA		; read byte from PORTA
		sbi	PORTB,DIOR		; set DIOR hi
		jmp	ramenable

;		call	ramenable		; enable RAM
;		clr 	r25
;		ret


;				 r24		r22		
;void WriteBYTE(u08 reg, u08 dat) 
	.global WriteBYTE
WriteBYTE:
		rcall	setaddress		; setup address on latch
		out	PORTA,r22		; write byte to PORTA
		out	PORTC,__zero_reg__
;		nop
		cbi	PORTB,DIOW		; set DIOW lo
#ifdef SLOW_DISK
		nop
#endif
		nop
		sbi	PORTB,DIOW		; set DIOW hi
		jmp	ramenable

;		call	ramenable		; enable RAM
;		ret



;
; read status register
;
;
; r24,r25,r30,r31 destroyed
;
	.global ATA_ReadStat
ATA_ReadStat:
 		ldi 	r24,lo8(ATAPI_Stat)
 		rjmp 	ReadBYTE

;
; r24,r25,r30,r31 destroyed
;
	.global ATA_WaitBusy
ATA_WaitBusy:
		rcall	ATA_ReadStat		; read status register
 		tst 	r24			; check for BUSY set
 		brlt 	ATA_WaitBusy		; set, goto check again
		ret



;u08 WaitReady(void);
;
;modifies  R24, R25, Z
;
	.global ATA_WaitReady
ATA_WaitReady:
		rcall	ATA_WaitBusy		; get status register
 		sbrc 	r24,0			; skip if Error bit is clear
		rjmp	ATA_wrdy2		; else return err
		sbrs	r24,3			; test for DRQ, skip if set
		rjmp	ATA_WaitReady		; not yet, loop again	
ATA_wrdy2:
		andi	r24,1			; return 0 on OK, 1 on FAIL
		sts	ata_stat,r24		; save result
 		ret

;					r24
;void ATA_SetDrive(u08 Drive);
	.global ATA_SetDrive
ATA_SetDrive:
		andi	r24,1				; mask bit
		swap	r24

		ldi	r25,0xE0			; LBA and fixed bits for Device/Head register
		or	r24,r25				; combine
		sts	ata_drive,r24			; save in variable
		mov	r22,r24	
  		ldi 	r24,lo8(ATAPI_DRVSelect)
		cli
 		rcall 	WriteBYTE			; write drive select value to drive
		rcall	ATA_WaitBusy			; wait for not busy
		sei
		ret



	.global ATA_Read
;	      r25..r22		r20	  r19/r18
;u08 ATA_Read( u32 lba, u08 numsectors, u08*Buffer ) 

ATA_Read:
		sts	ata_stat,__zero_reg__		; clear error flag
		ldi	r21,0x20			; read command
		rcall	ATA_Request
		tst	r24
		brne	ATA_CMD_END

ATA_ReadBuffer:
		rcall	DiskToBuffer
		ldi	r27,hi8(ata_sbuf)
		ldi	r26,lo8(ata_sbuf)		; X points to buffer
		movw	r30,r18				; Z points to RAM
		rcall	bufcopy				; copy X to Z
		movw	r18,r30				; store back
		dec	r20
		brne	ATA_ReadBuffer

ATA_CMD_END:	lds	r24,ata_stat			; read ata error flag
		mov	r25,r24
 		ret



	.global ATA_Write
;	      r25..r22		r20	  r19/r18
;u08 ATA_Write( u32 lba, u08 numsectors, u08*Buffer ) 

ATA_Write:
		sts	ata_stat,__zero_reg__		; clear error flag
		ldi	r21,0x30			; write command
		rcall	ATA_Request
		tst	r24
		brne	ATA_CMD_END
.AW0:
		ldi	r31,hi8(ata_sbuf)
		ldi	r30,lo8(ata_sbuf)		; Z points to buffer
		movw	r26,r18				; X points to RAM
		rcall	bufcopy				; copy X to Z
		movw	r18,r26				; store back
	; store to disk
		rcall	BufferToDisk
		dec	r20				; dec sector counter
		brne	.AW0				; and loop until done
		rjmp	ATA_CMD_END


#define USB_PORT	PORTD

#define USB_TXRDY	PD4
#define USB_RXRDY	PD5
#define USB_WR		PD6
#define USB_RD		PD7

#define USB_ADDR	0x8000


	.global ATA_Read_USB
;		   r25..r22 		r20     	
;u08 ATA_Read_USB( u32 lba,  u08 numsectors);
;	
ATA_Read_USB:
		sts	ata_stat,__zero_reg__		; clear error flag
		ldi	r21,0x20			; read command
		rcall	ATA_Request
		tst	r24
		brne	ATA_CMD_END

.RTU0:
		rcall	DiskToBuffer

	; send buffer to USB

		ldi	r27,hi8(ata_sbuf)
		ldi	r26,lo8(ata_sbuf)		; X points to buffer
		ldi	r31,hi8(USB_ADDR)
		ldi	r30,lo8(USB_ADDR)		; Z points to USB
		clr	r21				; loop count = 256 words
.RTU1:
		sbic 	USB_PORT-2,USB_TXRDY		; while flag is set
 		rjmp 	.RTU1				; wait for bit to be cleared
		ld	r24,X+				; read from RAM
		st	Z,r24				; store to USB
.RTU2:
		sbic 	USB_PORT-2,USB_TXRDY		; while flag is set
 		rjmp 	.RTU2				; wait for bit to be cleared
		ld	r24,X+				; read from USB
		st	Z,r24				; store to RAM
		dec	r21				; dec loop counter
		brne	.RTU1				; and loop until done
		dec	r20				; dec sector counter
		brne	.RTU0				; and loop until done
		rjmp	ATA_CMD_END



;		    r25..r22 		r20     	
;u08 ATA_Write_USB( u32 lba,  u08 numsectors);
;	
	.global ATA_Write_USB
ATA_Write_USB:
		sts	ata_stat,__zero_reg__		; clear error flag
		ldi	r21,0x30			; write command
		rcall	ATA_Request
		tst	r24
		brne	ATA_CMD_END

.LJ0:
	; read from USB
	
		ldi	r31,hi8(ata_sbuf)
		ldi	r30,lo8(ata_sbuf)		; Z points to buffer
		ldi	r27,hi8(USB_ADDR)
		ldi	r26,lo8(USB_ADDR)		; X points to USB
		clr	r21				; loop count = 256 words
.LJ1:
		sbic 	USB_PORT-2,USB_RXRDY		; while flag is set
 		rjmp 	.LJ1				; wait for bit to be cleared
		ld	r24,X				; read from USB
		st	Z+,r24				; store to RAM
.LJ2:
		sbic 	USB_PORT-2,USB_RXRDY		; while flag is set
 		rjmp 	.LJ2				; wait for bit to be cleared
		ld	r24,X				; read from USB
		st	Z+,r24				; store to RAM
		dec	r21				; dec loop counter
		brne	.LJ1				; and loop until done

	; store to disk
		rcall	BufferToDisk
		dec	r20				; dec sector counter
		brne	.LJ0				; and loop until done
		rjmp	ATA_CMD_END


;****************************************

;	head cyl sect
;	 8   16   8
	 

;r22   		sect = (u16) ( lba & 0x000000ffL );	
;   			lba = lba >> 8;
;r24/r23   	cyl = (u16) ( lba & 0x0000ffff );
;   			lba = lba >> 16;
;r25   		head = ( (u16) ( lba & 0x0fL ) ) | 0x40;
	


; Command in R21
;			      r25..r22     r20
;u08 ATA_Request_Sectors_LBA( u32 lba, u08 numsectors);
	
	.global ATA_Request
ATA_Request:	
		push	r18				; save buffer address
		push	r19
		mov	r19,r22				; save sector (low LBA) value
		mov	r18,r24				; save LBA 23:16
		
		andi	r25,0x0f			; mask high LBA (LBA 27:24) 
		lds	r22,ata_drive			; get drive
		or 	r22,r25				; combine	

 		rcall	ATA_WaitBusy
		
  		ldi 	r24,lo8(ATAPI_DRVSelect)
 		rcall 	WriteBYTE			; write drive select value
 
 	; wait for !BUSY and DRDY
.L927:
		rcall	ATA_WaitBusy
		sbrs	r24,6				; skip if DRDY is set
		rjmp	.L927
		
  		mov 	r22,r20
 		ldi 	r24,lo8(ATA_SectorCount)	; nSectors
 		rcall 	WriteBYTE

 		mov 	r22,r19				; get saved value
		ldi 	r24,lo8(ATA_Sector)		; Start Sector (LBA 7:0)
		rcall 	WriteBYTE

		mov 	r22,r23			
		ldi 	r24,lo8(ATAPI_CountLSB)		; LSB of track (LBA 15:8)
		rcall 	WriteBYTE

  		mov 	r22,r18				; get saved value	
 		ldi 	r24,lo8(ATAPI_CountMSB)		; MSB of track (LBA 23:16)
 		rcall 	WriteBYTE
 
 		mov 	r22,r21
 		ldi 	r24,lo8(ATAPI_Cmd)		; Send the command
 		rcall 	WriteBYTE
		nop
		nop
		nop
		nop

	; dummy read of Alternate Status register
 		ldi 	r24,lo8(ATAPI_AltStat)
 		rcall 	ReadBYTE
		pop	r19				; restore buffer address
		pop	r18
		rjmp	ATA_WaitReady			; check and return result

;
; r21, r24,r25, r30,r31 modified
;
BufferToDisk:
		rcall	ATA_WaitBusy			; check disk ready for sector writing

		; disable the RAM interface and SetAddress to point to Data Register
		ldi	r24,lo8(ATAPI_Data)
		rcall	setaddress

		; set Z to ram buffer

  		ldi 	r31,hi8(ata_sbuf)
 		ldi 	r30,lo8(ata_sbuf)

 		clr	r21				; loop count = 256 words
BTD2:
		ld	r25,Z+				; read from buffer
		ld	r24,Z+				; read from buffer
		out	PORTA,r25			; setup on PORTA
		out	PORTC,r24			; setup on PORTC
#ifdef SLOW_DISK
		nop
#endif
		nop
 		cbi 	PORTB, DIOW			; set DIOW lo
; 		nop
  		sbi 	PORTB, DIOW			; set DIOW hi
		dec	r21				; dec loop counter
		brne	BTD2				; and loop until done
		jmp	ramenable

; 		call	ramenable			; enable the RAM interface
;		ret


;
; r21, r24,r25, r30,r31 modified
;
DiskToBuffer:
		rcall	ATA_WaitBusy			; check disk ready for sector reading

		; disable the RAM interface and  SetAddress to point to Data Register
		ldi	r24,lo8(ATAPI_Data)
		rcall	setaddress

		; set Z to ram buffer
  		ldi 	r31,hi8(ata_sbuf)
 		ldi 	r30,lo8(ata_sbuf)

		; set PORTA and PORTC as inputs
		out	DDRA,__zero_reg__		; port A as input
		out	DDRC,__zero_reg__		; port C as input
		ser	r25
		out	PORTA,r25			; activate pullup on PORTA
		out	PORTC,r25			; activate pullup on PORTC

 		clr	r21				; loop count = 256 words
DTB2:
 		cbi 	PORTB, DIOR			; set DIOR lo
#ifdef SLOW_DISK
		nop
#endif
		nop
 		in 	r24,PINA			; read lo byte
 		in 	r25,PINC			; read hi byte
  		sbi 	PORTB, DIOR			; set DIOR hi
		st	Z+,r24				; write to buffer
		st	Z+,r25				; write to buffer
		dec	r21				; dec loop counter
		brne	DTB2				; and loop until done

		; enable the RAM interface
 		jmp	ramenable

; 		call	ramenable
;		ret


;
; copy a sector from X to Z
;
bufcopy:
		clr	r21					; loop count = 256 words
bc1:
		ld	r24,X+
		st	Z+,r24
		ld	r24,X+
		st	Z+,r24
		dec	r21					; dec loop counter
		brne	bc1					; and loop until done
		ret


;					r25/r24
;u08 IdentifyDrive(u08 *Buffer)
	.global IdentifyDrive
IdentifyDrive:	
		sts	ata_stat,__zero_reg__
		push	r24
		push	r25
		clr	r25
		clr	r24
		movw	r22,r24
		clr	r20
		ldi	r21,0xEC
		rcall	ATA_Request	
		pop	r19
		pop	r18
		ldi	r20,1
		rcall	ATA_ReadBuffer
		ret

⌨️ 快捷键说明

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