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

📄 ide.asm

📁 这项工程将让您把自己的MP3播放器平台
💻 ASM
字号:
	.title	Low Level IDE I/O Routines
	.sbttl	Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.

;++
; IDE.ASM
;
; Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.
;
; This file is part of the Spare Time Gizmos' MP3 Player firmware.
;
; Thisfirmware 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
; 
; DESCRIPTION:
;   This module contains several low level routines for talking to the Compact
; Flash card in TrueIDE interface mode.  There are functions to read and write
; individual IDE registers, and another one to transfer the 512 byte sector
; buffer.  There's no reason why they couldn't have been written in C (in fact,
; the original prototype versions were) but the C versions are too slow to play
; high bit rate MP3s...
;
; REVISION HISTORY:
; dd-mmm-yy     who     description
; 21-May-05	RLA	New File
; 07-Jul-05	DJA 	ported to SDCC/ASX8051
; 20-Jul-05	DJA 	fixed error with 2nd parameter on readIdeBuffer
;--

	.module	 IDE
	.optsdcc -mmcs51 --model-small
	.radix	 d
	.include "player.inc"

	.globl	_WriteIDE, _ReadIDE, _ReadIDEBuffer

;   DN:  Unlike Keil, SDCC passes all but the first parameter via global
; variables. Only the first parameter is passed in a register.  Public
; (global) declarations below are for said parameters.
	.globl	_WriteIDE_PARM_2, _ReadIDEBuffer_PARM_2
	.area	OSEG(OVR,DATA)
_WriteIDE_PARM_2::
	.ds 1
_ReadIDEBuffer_PARM_2::
	.ds 2

;   This retarded asx8051 assembler needs us to jump thru a few hoops just
; to get the standard 8051 registers defined.  Note that the .area and .ds
; declarations are probably superfluous, but they're reproduced here in the
; interest of correctness.  [Just between you and me, I've got to wonder
; about declaring the register bank segment as "Overlayable" and especially
; "RELocatable", but that's the way the SDCC compiler does it.  I assume
; they know what they're doing!]
	.area	REG_BANK_0 (REL,OVR,DATA)
	.ds	8
AR0=0x00
AR1=0x01
AR2=0x02
AR3=0x03
AR4=0x04
AR5=0x05
AR6=0x06
AR7=0x07

	.area	CSEG (CODE)


;
;++
; SelectRegister
;
;   This local routine will set up the IDE RS0, RS1, RS2, CS1FX and CS3FX bits
; based on the value currently in A.  It's used by both the IDE Read and Write
; routines to set up the register select before any I/O takes place...
;--
SelectRegister:
;   Before we change any of the register select bit, and especially before we
; assert either CS1FX or CS3FX, be sure that both IOWR and IORD are inactive.
; Remember that these signals are shared with other peripherals (e.g. the LCD)
; and we can't depend on their current state!
	SETB	CARD_IORD		; (remember that they're active HIGH!)
	SETB	CARD_IOWR		; ...
	MOV	C, ACC.0		; set up RS0
	MOV	CARD_RS0, C		; ...
	MOV	C, ACC.1		; RS1 ...
	MOV	CARD_RS1, C		; ...
	MOV	C, ACC.2		; and RS2...
	MOV	CARD_RS2, C		; ...
	MOV	C, ACC.3		; get the primary/secondary register set bit
	MOV	CARD_CS1FX, C		; if ACC.3 == 0, select CS1
	CPL	C			; ...
	MOV	CARD_CS3FX, C		; and if ACC.3 == 1, select CS3
	RET				; and all done
	
;
;++
; PRIVATE void WriteIDE (BYTE bReg, BYTE bValue)
; 
;   This routine will write a byte to an IDE register.  The IDE interface
; defines 8 primary registers (addressed 0..7) selected by CS1FX and eight
; alternate registers (although most of these are not implemented) selected
; by CS3FX.  In our case, if bReg is 0..7 a primary register is selected and
; if bReg is 8..15 a secondary register is selected instead.
; 
;   Note that the CS1FX and CS3FX names actually come from IDE's PC legacy -
; CS1FX refers to the registers that were originally addressed in the PC's
; I/O space as 0x1F0..0x1F7.  On a traditional PC the secondary registers
; were addressed by I/O ports 0x3F0..0x3F7 (hence, CS3FX).
;--
_WriteIDE:
;---- Variable 'bReg' assigned to Register 'DPL' ----
;---- Variable 'bValue' assigned to location '_WriteIde_PARM_2'
	MOV	A, DPL			; get the bReg parameter
	LCALL	SelectRegister		; and select the right register
	MOV	CARD_DATA, _WriteIDE_PARM_2; put the data on the bus
	CLR	CARD_IOWR		; strobe IOWR low
	NOP		      		; wait a moment or two
	SETB	CARD_IOWR      		; and back to high

;   Before leaving, be sure that CS1FX and CS3FX are both de-asserted and that
; the data bus is floating, just in case some other device wants to use it.
	SETB	CARD_CS1FX     		; clear both selects
	SETB	CARD_CS3FX     		; ...
	MOV	CARD_DATA, #0x0FF	; and float the data bus
	RET				; all done!

;
;++
; PRIVATE BYTE ReadIDE (BYTE bReg)
;
;   This routine is pretty much the same as WriteIDE except that it (what
; else??) reads an IDE register.  The byte read is returned as the function
; value...
;--
_ReadIDE:
;---- Variable 'bReg' assigned to Register 'DPL' ----
	MOV	A, DPL			; get the bReg parameter
	LCALL	SelectRegister		; and select the right register
	MOV	CARD_DATA, #0x0FF	; make sure the port pins are floating
	CLR	CARD_IORD		; and then strobe IORD low
	MOV	DPL, CARD_DATA		; capture the card data
	SETB	CARD_IORD		; and release IORD
	SETB	CARD_CS1FX		; make sure both selection bits are
	SETB	CARD_CS3FX		;  ... cleared before returning
	RET  				; and we're done

;
;++
; PRIVATE WORD ReadIDEBuffer (PXBYTE pxBuffer, WORD cbMaxBuf)
;
;   This routine will read data from the IDE drive's data register and store it
; in the XDATA buffer.  It stops whenever either the drive's DRQ bit (in the status
; register is no longer set (indicating that the drive has no more data to transfer)
; or whenver the drive's ERR bit _is_ set (indicating that something bad happened!).
; Since this routine never waits for DRQ and returns as soon as DRQ is clear, it's
; up to the caller to wait for DRQ to initially set after issuing a command to the
; drive.  If the caller issues a command and then calls this function without
; first waiting for the command to complete, it's pretty sure that zero bytes will
; be transferred!
;
;   Normally a transfer is always exactly one sector (512 bytes), however the
; cbMaxBuf parameter can be used to specify the buffer size.  If the drive sends
; fewer bytes than the buffer size, then the remainder of the buffer will be
; untouched.  If the drive transfers more bytes than will fit in the buffer, then
; the extra bytes are discarded.  This routine always transfers exactly as many 
; bytes as the drive wants and stops when the drive runs out of data, regardless
; of the actual buffer size.  The return value for this function is the number of
; bytes actually read from the drive, so a buffer over/underrun can be detected
; by the return value != cbMaxBuf.
;
;   This routine returns the number of bytes actually read from the drive even
; if the ERR bit sets, however in that case the drive may have still more data
; to be transferred (and the DRQ bit may still be set).  Normally the caller will
; reset the drive in case of an error, and so any left over data won't matter.
;
;--

;--
_ReadIDEBuffer:
;---- Parameter 'pxBuffer' assigned to Register 'DPTR' 
;---- Parameter 'cbMaxBuf' assigned to location '_ReadIDEBuffer_PARM_2' ----
;---- Variable 'wCount' assigned to Register 'R6/R7' ----
	MOV	R6, #0	    		; First, clear the word count
	MOV	R7, #0	     		; ...
	MOV	R5, _ReadIDEBuffer_PARM_2	; cbMaxBuf low byte
	MOV	R4, _ReadIDEBuffer_PARM_2+1	; ... high byte

;  Ensure that IORD is clear until we need it, as well as IOWR (which we never
; need!).  Clear CS3FX and set CS1FX since we'll always be using the primary
; IDE register set...
	SETB	CARD_IORD      		; all these signals are active high!
	SETB	CARD_IOWR      		; ...
	SETB	CARD_CS3FX		; ...
	CLR	CARD_CS1FX		; ...
	MOV	CARD_DATA, #0xFF	; allow the card to drive the data bus

;   Read the status register and ensure that DRQ is set and ERR is clear.  If
; either of those conditions is false, then return now with the current word
; count.  Remember that the IDE status register is register 7, where as the
; IDE data register is register zero!
;
;   Note that this code takes a few liberties (especially the use of P2
; instead of the pre-defined constants for RS0/1/2) in the interest of speed!
; Sorry about that...
RDBUF1:	ORL	P2, #7			; set RS0=RS1=RS2=1 (register 7)
	CLR	CARD_IORD		; and then strobe IORD low
	MOV	A, CARD_DATA		; read the card status
	SETB	CARD_IORD		; and release IORD
	JB	ACC.0, RDBUF9		; return if ERR is set
	JNB	ACC.3, RDBUF9		;  .... or if DRQ is clear

; Read two bytes from the data register (temporarily) into R0 and R1...
	ANL	P2, #0xF8		; set RS0=RS1=RS2=0 (register 0)
	CLR	CARD_IORD		; strobe data low
	MOV	R0, CARD_DATA		; read the high byte
	SETB	CARD_IORD		; release the strobe
	NOP				; just for symmetry
	CLR	CARD_IORD		; and then do it again
	MOV	R1, CARD_DATA		;  ... with the low byte
	SETB	CARD_IORD		; ...

;   If the remaining buffer size has reached zero, then just loop back to the
; status read and discard these two bytes entirely.  Otherwise, decrement the
; buffer size by two.
	MOV	A, R4			; get cbMaxBuf
	ORL	A, AR5			; are both bytes zero?
	JZ	RDBUF1			; if yes, just skip everything else
	MOV  	A, #0xFE 		; add -2 (0FFFEH) to cbMaxBuf (R4/R5)
	ADD  	A, R5			; first the low byte
	MOV  	R5, A			;  ...
	MOV  	A, #0xFF		; and then the high byte
	ADDC 	A, R4			;  ...
	MOV  	R4, A			;  ...

;   Store the two bytes in memory and increment the actual count of the bytes
; read (kept in R6/R7)...
	MOV	A, R0			; get the first byte
	MOVX	@DPTR, A		; and store that in XRAM
	INC	DPTR			; ...
	MOV	A, R1			; then the next byte, too
	MOVX	@DPTR, A		; ...
	INC	DPTR			; (for the next time around)
	MOV  	A, #2			; add 2 to wCount (R6/R7)
	ADD  	A, R7			; first the low byte
	MOV  	R7, A			;  ...
	MOV  	A, #0			; and then the high byte
	ADDC 	A, R6			;  ...
	MOV  	R6, A			;  ...
	SJMP	RDBUF1			; then go check for more data

;  Land Here when we're done.  Make sure that CS1FX is cleared (since we share the
; IOWR and IORD pins with other peripherals!) and return the actual count of
; the bytes read.
RDBUF9:	SETB	CARD_CS1FX		; make sure nothing is selected
	MOV  	DPL, R7			;  first the count's low byte
	MOV  	DPH, R6			; and then the high byte
	RET				; and that's all we need

⌨️ 快捷键说明

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