📄 fat32.s
字号:
;***************************************************************************
;*
;* Title: FAT32 Routines
;* Version: 1.1
;* Last updated: 10 Mar 2003
;* Target: ATMEGA128
;*
;*
;* DESCRIPTION:
;* This file contains routines for dealing with the FAT32 file system.
;*
;* Some notes & assumptions:
;*
;* It is required that the drive be jumpered as a master. Although this software
;* could be modified to look for a slave & then talk to it, the Cypress USB
;* code requires the drive to be a master. Hence this code follows suit.
;*
;* This code does NOT examine the MBR (master boot record in sector 0 of the
;* drive) to find the FAT32 partition. It assumes that the first partition on
;* the drive is a FAT32 partition, and that it's in the usual place, ie sector 63.
;*
;* Note that bytes are read off the drive low-byte first. For example, to read
;* a 32-bit value off the drive, the low (least significant, 0-7) 8 bites are read
;* first, then the next 8 bits, then the next 8 bits, and finally the most-
;* significant (high byte, bits 24-31) is read last.
;*
;* Variables in AVR memory are treated similarly: low byte first to high byte last
;* (Exception to this are the queueing routines, which store their internal addresses
;* - read, write, end pointers, hi-byte first)
;*
;* Stack parameter passing: push high byte first
;*
;***************************************************************************
/* Make the routines in this file available to other files */
.global FAT32_init
.global GetFatParams
.global StreamFile
.global StreamFileC
.global CalcNextCluster
.global Cluster2Sector
.global ResetAVR
/* Make some variables global as well */
.global SEC_PER_CLUS
.global FAT_START_SEC
.global DIR_START_SEC
.global FINDFILE_RET_NAME
.global FINDFILE_RET_CLUS
.global FINDFILE_RET_SIZE
.global FINDFILE_CLUS
.global CURRENT_DIRCL
.global FINDFILE_OFSET
.global STREAMFILE_ST
.global STREAMFILE_FILESZ
.global STREAMFILE_CLUS
.global STREAMFILE_QPOINTER
.global STREAMFILE_CMD
/* Here are the definitions we need, both in included files and defined right here */
#include "frankmp3.h"
#include "frankasm.h"
; Allocate SRAM space for the variables
.comm SEC_PER_CLUS, 1 ; number of 512-byte sectors per cluster
.comm FAT_START_SEC, 2 ; FAT32 table start sector number
.comm DIR_START_SEC, 4 ; directory sector number (low byte first)
.comm CALNXCL_ST, 1 ; state variable for CalcNextCluster
.comm CALNXCL_OF, 1 ; number of 16-bit reads offset into sector
.comm CALNXCL_SN, 4 ; store the sector number of interest
.comm CALNXCL_CLUS_LO, 4 ; sequential cluster range low value
.comm CALNXCL_CLUS_HI, 4 ; sequential cluster range high value
.comm STREAMFILE_ST, 1 ; StreamFile state variable
.comm STREAMFILE_SEC_REM, 2 ; StreamFile # bytes remaining in current sector
.comm STREAMFILE_SECCLUS_REM, 1 ; Streamfile # sectors remaining in current cluster
.comm STREAMFILE_FILESZ, 4 ; Streamfile # bytes remaining in file
.comm STREAMFILE_CLUS, 4 ; Streamfile current cluster number
.comm STREAMFILE_CMD, 1 ; Streamfile command variable
.comm STREAMFILE_QPOINTER, 2 ; Streamfile data queue pointer
.comm FINDFILE_CLUS, 4 ; cluster number FindFile's currently reading from
.comm FINDFILE_OFSET, 2 ; byte offset into cluster to start looking for files
.comm FINDFILE_TEMPO, 2 ; temporary copy of FINDFILE_OFSET
.comm CURRENT_DIRCL, 4 ; first cluster number for current directory
.comm FINDFILE_RET_CLUS, 4 ; FindFile result: starting cluster number
.comm FINDFILE_RET_SIZE, 4 ; FindFile result: File size (in bytes)
.comm FINDFILE_RET_NAME, ((FindFile_NumLongDirs*13)+2) ; FindFile result: File name text array: first byte is length, string null-terminated
.comm FINDFILE_LNCOUNT, 1 ; count of how many more longname dir entries to check
.text
;**********************************************************************************
;*
;* FAT32_init
;*
;* Initialises any FAT32 routines which need it. Called during system initialization.
;* This routine does the following:
;*
;* Set the initial state of CalcNextCluster to SeekDrive
;* Set the initial state of StreamFile to Idle
;* Set the initial command for StreamFile to Stop
;* Set the initial state of FindFile to Idle
;* Set both the initial cluster numbers for FindFile to the root directory
;* (Note: by definition, this is cluster number 2)
;* Set the initial byte offset for FindFile's cluster to zero
;*
;*
;* Accepts: nothing
;* Returns: Nothing
;* Uses: flags.
;*
;**********************************************************************************
FAT32_init:
push temp
push ZL
push ZH
; Set the initial state of CalcNextCluster to SeekDrive, and zero both the low and high
; sequential cluster range variables.
ldi ZL,lo8(CALNXCL_ST)
ldi ZH,hi8(CALNXCL_ST) ; point Z to CalcNextCluster state variable
ldi temp,CalNxCl_SDS
st Z,temp ; make initial state to be SeekDrive
clr temp
sts CALNXCL_CLUS_LO,temp
sts CALNXCL_CLUS_LO+1,temp
sts CALNXCL_CLUS_LO+2,temp
sts CALNXCL_CLUS_LO+3,temp ; sequential cluster range low value is zero
sts CALNXCL_CLUS_HI,temp
sts CALNXCL_CLUS_HI+1,temp
sts CALNXCL_CLUS_HI+2,temp
sts CALNXCL_CLUS_HI+3,temp ; sequential cluster range high value also zero
; Set the initial state of StreamFile to Idle
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
; Set the initial command for StreamFile to Stop
ldi ZL,lo8(STREAMFILE_CMD)
ldi ZH,hi8(STREAMFILE_CMD) ; Z points to command variable
ldi temp,StreamFile_Cmd_Stop
st Z,temp ; command variable says Stop
pop ZH
pop ZL
pop temp
ret
;**********************************************************************************
;*
;* GetFatParams
;*
;* This routine reads from the drive and performs a number of reads and calculations
;* to obtain some necessary information about the file system on the drive. These
;* items of interest are:
;* - number of sectors per cluster
;* - sector number of the FAT table start
;* - sector number of the root directory start
;*
;* Now to describe each of these individually:
;*
;* Numbers of sectors per cluster is easy. That's read directly out of the
;* BPB (boot parameter block), ie drive sector 63, byte offset 13.
;*
;* Sector number of the start of the FAT table is also easy. It is equal to
;* BPD_ResvdSecCnt + 63.
;*
;* Sector number of the root directory start is slightly more complex. We need to calc
;* the sector number of the "FirstDataSector" (as microsoft calls it). This is
;* actually the sector number ON THE DRIVE of the start of the directory entries.
;* We perform the following calculation:
;* FirstDataSector = BPD_ResvdSecCnt + (2 * BPD_FATSz32) + 0 + 63
;* = (63 + BPD_ResvdSecCnt) + (2 * BPD_FATSz32)
;* where BPD_FATSz32 is read from sector 63 bytes 36-39 off the drive
;* Note that sector 63 on the drive is the first sector of the FAT32 partition.
;* The above calculation is done using 32-bit arithmetic.
;*
;* In both of the calculations above requiring BPD_ResvdSecCnt, although this is strictly a
;* 16-bit number, the code below only reads the low 8 bits and calculates accordingly.
;* That's because microsoft seems to set BPD_ResvdSecCnt to either 32 or 34. So then
;* BPD_ResvdSecCnt+63 equals 95 or 97; well below the 255 value limit of a byte.
;* Which makes the code simpler. (It's a little cheat, I know :-)
;*
;* This routine does not itself require any initialization in the Fat32 init routine. However
;* it does call SeekSector, which is initialized in the IDE init routine.
;*
;*
;* This routine functions as follows:
;*
;* Seek to sector 63
;* Read byte offset 13 and store in SEC_PER_CLUS
;* If SEC_PER_CLUS == 0 then jump to start (reboot system)
;* Store (63+BPD_ResvdSecCnt) in FAT_START_SEC
;* Read bytes offset 36 through 39 (this is the 32-bit FatSize)
;* Shift left 1 bit (to multiply by 2)
;* Add (63+BPD_ResvdSecCnt)
;* Store result in DIR_START_SEC
;* Return
;*
;* All values are read from the drive low-byte first and written into
;* memory low-byte first.
;*
;*
;* Accepts: nothing
;* Returns: Nothing
;* Uses: flags
;*
;**********************************************************************************
GetFatParams:
push temp
push param1
push param2
push ZL
push ZH
push r0
push r1
push r2
push r3
push r4 ; r4 used to hold BPD_ResvdSecCnt
; make sure SeekSector is idle before calling it
GetFatParamsAA:
lds temp,SEEKSECT_ST
cpi temp,SeekSect_ISS ; is SeekSector idle, ready for new command?
breq GetFatParamsS ; yes - branch forward
call SeekSector ; no - call it (to give it some CPU time)
jmp GetFatParamsAA ; and repeat until it's idle
GetFatParamsS:
; seek to sector 63
ldi temp,0
push temp
push temp
push temp
ldi temp,63
push temp
ldi param1,1
rcall SeekSector ; seek to sector 63
pop temp
pop temp
pop temp
pop temp
ldi temp,SeekSect_Done
cp param1,temp
brne GetFatParamsS ; loop until SeekSector says seek is complete
; read byte offset 13 from the drive & store in SEC_PER_CLUS
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; param2 contains our offset 13 data byte
ldi ZL,lo8(SEC_PER_CLUS)
ldi ZH,hi8(SEC_PER_CLUS) ; point Z to SEC_PER_CLUS
st Z,param2 ; store byte from offset 13 in SEC_PER_CLUS
cpi param2,0
brne GetFatParams_1 ; reboot system if SectorsPerCluster == 0
jmp main ; as there's a problem reading the drive
GetFatParams_1:
; get value of BPD_ResvdSecCnt (offset 14)
ldi param1,IDERD_DATA ; read 16-bit data word from the drive
call IDE_read16 ; low byte returned in param1; high in param2
mov r4,param1 ; BPD_ResvdSecCnt now in r4 (we only care about the low byte; high byte ignored)
; store 63 plus BPD_ResvdSecCnt in FAT_START_SEC
ldi ZL,lo8(FAT_START_SEC)
ldi ZH,hi8(FAT_START_SEC) ; point Z to FAT_START_SEC
ldi temp,63
add temp,r4 ; temp now contains 63 + BPD_ResvdSecCnt
st Z+,temp ; write low byte first (all we care about; assume BPD_ResvdSecCnt small)
ldi temp,0
st Z,temp ; then high byte
; read bytes offset 36 through 39. r0 is low byte through r3 being high byte
ldi param1,IDERD_DATA ; read bytes 16 & 17
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 18 & 19
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 20 & 21
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 22 & 23
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 24 & 25
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 26 & 27
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 28 & 29
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 30 & 31
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 32 & 33
call IDE_read16 ; low byte in param1; high in param2
ldi param1,IDERD_DATA ; read bytes 34 & 35
call IDE_read16 ; low byte in param1; high in param2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -