Foreword
In the previous post we developed a DMA module for transferring a read sector from the FIFO in the SC Card module to the 6502 memory space. We also wrote some 6502 Assembly code for testing this functionality.
In this post we will write some more 6502 Assembly code for reading a file from a FAT32 partition.
32-bit operations
When trying to determine the location of a file on an SD Card, one often needs to work with 32-bit quantities. However, as you know the 6502 only works with 8 bits at a times. So, in order to make life simpler, let us start by writing some Assembly Routines for doing a couple of 32-bit operations.
Core of these routines we will imagine a virtual 32 bit accumulator, which we will store at address C0 hex in memory, and will use little endian format.
The first operation we need to define, is a Load Accumulator, which we will define with the symbol ld32. The address containing the data we want to store in the accumulator, must be stored in the X- and Y-registers:
ld32 stx $b0 sty $b1 ldy #$0 lda ($b0),y sta $c0 iny lda ($b0),y sta $c1 iny lda ($b0),y sta $c2 iny lda ($b0),y sta $c3 iny rtsFirst of we need to store the address in memory locations b0 and b1, so we can load the data from the memory location in an indexed addressing fashion. Here I do a bit of loop unrolling, saving a bit of CPU cycles. When this routine returns, our accumulator will contain the necessary data in memory locations c0, c1, c2 and c3.
st32 stx $b0 sty $b1 ldy #$0 lda $c0 sta ($b0),y iny lda $c1 sta ($b0),y iny lda $c2 sta ($b0),y iny lda $c3 sta ($b0),y iny rtsAgain, the destination address needs to be stored in registers X and Y, which we store in memory location b0 and b1 at the beginning of the routine.
st32rev stx $b0 sty $b1 ldy #$3 lda $c0 sta ($b0),y dey lda $c1 sta ($b0),y dey lda $c2 sta ($b0),y dey lda $c3 sta ($b0),y iny rtsWhen determining the location of a file, one 32-bit operation that valuable is add. In FAT32 we are presented with both 16-bit and 32-bit numbers to add, so we need routine for both:
add32 stx $b0 sty $b1 ldy #0 clc lda $c0 adc ($b0),y sta $c0 iny lda $c1 adc ($b0),y sta $c1 iny lda $c2 adc ($b0),y sta $c2 iny lda $c3 adc ($b0),y sta $c3 rts add16 stx $b0 sty $b1 ldy #0 clc lda $c0 adc ($b0),y sta $c0 iny lda $c1 adc ($b0),y sta $c1 iny lda $c2 adc #0 sta $c2 iny lda $c3 adc #0 sta $c3 rts
Finding the root cluster
mbr equ $200 par1 equ $1be lbastart equ 8 lbamemaddr equ mbr+par1+lbastart ldx #<lbamemaddr ldy #>lbamemaddr jsr ld32 ldx #48 ldy #0 jsr st32rev LDA #6 JSR CMD LDA #$12 STA $FB0B LDA #$16 STA $FB0BLet us start by breaking down the EQU's a bit. $200 is the address in 6502 memory space where we previously downloaded the MBR from the SD Card.
... bootsec equ $400 reservedsec equ bootsec+$e ... ldx #<reservedsec ldy #>reservedsec jsr add16 ...As can be seen, the location of the Reserved Sectors is at $e in the Bootsector and is two bytes, so we need to use add16.
... numfat equ bootsec+$10 secperfat equ bootsec+$24 ... ldx numfat addfat txa pha ldx #<secperfat ldy #>secperfat jsr add4 pla tax dex bne addfat ...With this we have the calculated LBA for the root cluster. This number we need to store again at address 48, which will instruct the SD Card core to load the root cluster sectors. We also need to make a backup of this number as well for future calculations:
ldx #48 ldy #0 jsr st32rev ldx #$c4 ldy #0 jsr st32
Searching for the file
FILENAME .TEXT "BOOT BIN"It may look a bot strange with the extra white space between filename and extension, but this is how filenames are stored in file entries in FAT32 partitions. When looping through the file entries we need to compare each filename with the above.
ldx #10 initfilename lda FILENAME,x sta $d0,x dex bpl initfilenameI have become into the habit of when needing to iterate through a number of memory locations, I am doing it in the reverse order. It just eliminates the need to have a compare operation with every loop iteration.
for sectors = 1 to ... read sector for page = 0 to 1 for fileentry = 0 to 7 get file entry do something with file entry end end endEach file entry is 32 bytes, so in a page of 256 bytes, there is 8 entries. For that reason we are looping from 0 to 7 in innermost loop.
nextsec LDA #6 JSR CMD LDA #$12 STA $FB0B LDA #$16 STA $FB0B lda #0 sta $b2 lda #4 sta $b3We start with some code to load a root sector into memory, where the sector number is stored in addresses 48 - 51, as explained previously. The addresses b2/b3 contains the address at which the root sector is stored, which is $0400. We will be incrementing b2/b3 as we loop through the file entries.
nextentry clc lda $b2 adc #32 sta $b2 bcc inspectfileentry inc $b3 lda #1 and $b3 bne inspectfileentry inc 51 jmp nextsecIn this snippet inspectfileentry is where we do something with the current file entry. Basically to get to the next entry we keep adding 32 to the address in b2/b3.
inspectfileentry ldy #11 lda ($b2),y cmp #15 beq nextentry loopfilesearch dey bmi done lda ($b2),y cmp $d0,y beq loopfilesearchAgain, we are working backwards. We start by inspecting the byte following the filename/extension, which contains all the attributes. With this entry we check if this file entry forms part of a long file entry. If it is we skip to the next entry.
Loading the file
DONE ldy #26 sec lda ($b2),y sbc #2 sta $c0 ldy #27 lda ($b2),y sbc #0 sta $c1 ldy #20 lda ($b2),y sbc #0 sta $c2 ldy #21 lda ($b2),y sbc #0 sta $c3In all the code written in this post, we are only doing one subtraction, so I didn't deemed it necessary to create a routine for this process.
addfat txa pha ldx #<secperfat ldy #>secperfat jsr add32 pla tax dex bne addfat ldx #48 ldy #0 jsr st32rev ldx #$c4 ldy #0 jsr st32 lda sectorspercluster ldx #0 clc shift ror a bcs endshift inx bcc shift endshift stx $c8You will recognise this code from an earlier section, of which I have just appended some extra code. We just keep shifting the parameter right until the carry flag is set, keeping count how many shifts is required. This required number of shifts we store in location $c8.
clc ldx $c8 conv rol $c0 rol $c1 rol $c2 rol $c3 dex bne convNow we have the relative sector number where our file begins. We still need to add the location of the root cluster number to get the absolute cluster number. We previously stored this number at location $c4, so we can do the addition like this and load the first sector of the file into memory:
ldx #$c4 ldy #0 jsr add32 ldx #48 ldy #0 jsr st32rev LDA #6 JSR CMD LDA #$12 STA $FB0B LDA #$16 STA $FB0BAfter loading this sector of the file, one can also jump to it with JMP $400.
Testing
lda #0 sta $0 clc ldx #0 ldy #0 lda #0 loop inx bne loop loop2 iny bne loop loop3 adc #1 cmp #60 bne loop lda #$20 eor $0 sta $FB0B sta $0 lda #0 beq loopI have added a couple of nested loops to slow down the flashing enough so the flashing can be visible to the human eye. One needs to assemble this snippet and store as boot.bin on the root directory on the SD Card.
No comments:
Post a Comment