diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index f49d89e49..355f20a08 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -487,3 +487,29 @@ void romboot(void) boot(0, 0, 0, ROM_BOOT_ADDRESS); } #endif + +// SPI HARDWARE BITBANG +#ifdef CSR_SPI_BASE +#include + +void spisdboot(void) +{ + printf("SD Card via SPI Initialising\n"); + if(spi_sdcard_goidle() == 0) { + printf("SD Card Timeout\n"); + return; + } + + if(spi_sdcard_readMBR() == 0) { + printf("SD Card MBR Timeout\n"); + return; + } + + if(spi_sdcard_readFile("IMAGE","",MAIN_RAM_BASE+KERNEL_IMAGE_RAM_OFFSET)==0) return; + if(spi_sdcard_readFile("ROOTFS~1","CPI",MAIN_RAM_BASE+ROOTFS_IMAGE_RAM_OFFSET)==0) return; + if(spi_sdcard_readFile("RV32","DTB",MAIN_RAM_BASE+DEVICE_TREE_IMAGE_RAM_OFFSET)==0) return; + if(spi_sdcard_readFile("EMULATOR","BIN",EMULATOR_RAM_BASE)==0) return; + + boot(0,0,0,EMULATOR_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); +} +#endif diff --git a/litex/soc/software/bios/boot.h b/litex/soc/software/bios/boot.h index 65dcf4574..fd1d06a2e 100644 --- a/litex/soc/software/bios/boot.h +++ b/litex/soc/software/bios/boot.h @@ -6,4 +6,8 @@ void netboot(void); void flashboot(void); void romboot(void); +#ifdef CSR_SPI_BASE +void spisdboot(void); +#endif + #endif /* __BOOT_H */ diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 83bff1e10..d1ca017e2 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -388,12 +388,8 @@ static void help(void) puts("sdinit - SDCard initialization"); puts("sdtest - SDCard test"); #endif -#ifdef USDDRPHY_DEBUG - puts(""); - puts("sdram_cdly value - Set SDRAM clk/cmd delay"); - puts("sdram_cal - run SDRAM calibration"); - puts("sdram_mpr - read SDRAM MPR"); - puts("sdram_mrwr reg value - write SDRAM mode registers"); +#ifdef CSR_SPI_BASE + puts("spisdboot - boot from SDCard via SPI hardware bitbang"); #endif } @@ -486,24 +482,10 @@ static void do_command(char *c) else if(strcmp(token, "sdinit") == 0) sdcard_init(); else if(strcmp(token, "sdtest") == 0) sdcard_test(atoi(get_token(&c))); #endif -#ifdef USDDRPHY_DEBUG - else if(strcmp(token, "sdram_cdly") == 0) - ddrphy_cdly(atoi(get_token(&c))); - else if(strcmp(token, "sdram_cal") == 0) - sdrcal(); - else if(strcmp(token, "sdram_mpr") == 0) - sdrmpr(); - else if(strcmp(token, "sdram_mrwr") == 0) { - unsigned int reg; - unsigned int value; - reg = atoi(get_token(&c)); - value = atoi(get_token(&c)); - sdrsw(); - printf("Writing 0x%04x to SDRAM mode register %d\n", value, reg); - sdrmrwr(reg, value); - sdrhw(); - } +#ifdef CSR_SPI_BASE + else if(strcmp(token, "spisdboot") == 0) spisdboot(); #endif + else if(strcmp(token, "") != 0) printf("Command not found\n"); } diff --git a/litex/soc/software/include/base/spi.h b/litex/soc/software/include/base/spi.h new file mode 100644 index 000000000..db6ade284 --- /dev/null +++ b/litex/soc/software/include/base/spi.h @@ -0,0 +1,6 @@ +int spi_sdcard_init(uint32_t device); +int spi_sdcard_read_sector(uint32_t device, unsigned long lba,unsigned char *buf); + +unsigned char spi_sdcard_goidle(void); +unsigned char spi_sdcard_readMBR(void); +unsigned char spi_sdcard_readFile(char *, char *, unsigned long); diff --git a/litex/soc/software/libbase/Makefile b/litex/soc/software/libbase/Makefile index 5cc816004..7ccb4d0b8 100755 --- a/litex/soc/software/libbase/Makefile +++ b/litex/soc/software/libbase/Makefile @@ -2,7 +2,7 @@ include ../include/generated/variables.mak include $(SOC_DIRECTORY)/software/common.mak OBJECTS=exception.o libc.o errno.o crc16.o crc32.o console.o \ - system.o id.o uart.o time.o qsort.o strtod.o spiflash.o strcasecmp.o mdio.o + system.o id.o uart.o time.o qsort.o strtod.o spiflash.o spi.o strcasecmp.o mdio.o all: crt0-$(CPU)-ctr.o crt0-$(CPU)-xip.o libbase.a libbase-nofloat.a diff --git a/litex/soc/software/libbase/spi.c b/litex/soc/software/libbase/spi.c new file mode 100644 index 000000000..b602860ae --- /dev/null +++ b/litex/soc/software/libbase/spi.c @@ -0,0 +1,585 @@ +// SD CARD bitbanging code for loading files from a FAT16 forrmatted partition into memory +// +// Code is known to work on a de10nano with MiSTer SDRAM and IO Boards - IO Board has a secondary SD CARD interface connected to GPIO pins +// SPI signals CLK, CS and MOSI are configured as GPIO output pins, and MISO is configued as GPIO input pins +// +// Protocol details developed from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ +// +// FAT16 details developed from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ and https://codeandlife.com/2012/04/07/simple-fat-and-sd-tutorial-part-2/ + +// Import LiteX SoC details that are generated each time the SoC is compiled for the FPGA +// csr defines the SPI Control registers +// soc defines the clock CONFIG_CLOCK_FREQUENCY (50MHz for the VexRiscV processor on the MiSTer FPGA +// mem defines the addresses for the SDRAM MAIN_RAM_BASE and MAIN_RAM_SIZE +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CSR_SPI_BASE +// Import prototypes for the functions +#include + +// SPI +// cs line - high to indicate DESELECT +// - low to indicate SELECT +#define CS_HIGH 0x00 +#define CS_LOW 0x01 + +// control register values +// onebyte to indicate 1 byte being transferred +// spi_start to indicate START of transfer +// spi_done to indicate transfer DONE +#define ONEBYTE 0x0800 +#define SPI_START 0x01 +#define SPI_DONE 0x01 + +// Return values +#define SUCCESS 0x01 +#define FAILURE 0x00 + +// spi_write_byte +// Send a BYTE (8bits) to the SD CARD +// Seqeunce +// Set MOSI +// Set START bit and LENGTH=8 +// Await DONE +// +// No return values +// +// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands" +void spi_write_byte(unsigned char char_to_send); +void spi_write_byte(unsigned char char_to_send) +{ + // Place data into MOSI register + // Pulse the START bit and set LENGTH=8 + spi_mosi_write(char_to_send); + spi_control_write(ONEBYTE | SPI_START); + + // Wait for DONE + while( (spi_status_read() != SPI_DONE)) {} + + // Signal end of transfer + spi_control_write( 0x00 ); +} + + +// spi_read_rbyte +// Read a command response from the SD CARD - Equivalent to and R1 response or first byte of an R7 response +// Sequence +// Read MISO +// If MSB != 0 then send dsummy byte and re-read MISO +// +// Return value is the response from the SD CARD +// If the MSB is not 0, this would represent an ERROR +// Calling function to determine if the correct response has been received +// +// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands" +unsigned char spi_read_rbyte(void); +unsigned char spi_read_rbyte(void) +{ + int timeout=32; + unsigned char r=0; + + // Check if MISO is 0x0xxxxxxx as MSB=0 indicates valid response + r = spi_miso_read(); + while( ((r&0x80)!=0) && timeout>0) { + spi_mosi_write( 0xff ); + spi_control_write(ONEBYTE | SPI_START); + while( (spi_status_read() != SPI_DONE)) {} + r = spi_miso_read(); + spi_control_write( 0x00 ); + timeout--; + } + +// printf("Done\n"); + return r; +} + +// spi_read_byte +// Sequence +// Send dummy byte +// Read MISO +// +// Read subsequenct bytes from the SD CARD - MSB first +// NOTE different from the spi_read_rbyte as no need to await an intial 0 bit as card is already responsing +// Used to read additional response bytes, or data bytes from the SD CARD +// +// Return value is the byte read +// NOTE no error status as assumed bytes are read via CLK pulses +// +// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands" +unsigned char spi_read_byte(void); +unsigned char spi_read_byte(void) +{ + unsigned char r=0; + + spi_write_byte( 0xff ); + r = spi_miso_read(); + + return r; +} + +// SETSPIMODE +// Signal the SD CARD to switch to SPI mode +// Pulse the CLK line HIGH/LOW repeatedly with MOSI and CS_N HIGH +// Drop CS_N LOW and pulse the CLK +// Check MISO for HIGH +// Return 0 success, 1 failure +// +// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Initializing the SD Card" +unsigned char spi_setspimode(void); +unsigned char spi_setspimode(void) +{ + unsigned int i, r, timeout=32; + + // Initialise SPI mode + // set CS to HIGH + // Send pulses + do { + // set CS HIGH and send pulses + spi_cs_write(CS_HIGH); + for (i=0; i<10; i++) { + spi_write_byte( 0xff ); + } + + // set CS LOW and send pulses + spi_cs_write(CS_LOW); + r = spi_read_rbyte(); + + timeout--; + } while ( (timeout>0) && (r==0) ); + + if(timeout==0) return FAILURE; + + return SUCCESS; +} + +// SPI_SDCARD_GOIDLE +// Function exposed to BIOS to initialise SPI mode +// +// Sequence +// Set 100KHz timer mode +// Send CLK pulses to set SD CARD to SPI mode +// Send CMD0 - Software RESET - force SD CARD IDLE +// Send CMD8 - Check SD CARD type +// Send CMD55+ACMD41 - Force SD CARD READY +// Send CMD58 - Read SD CARD OCR (status register) +// Send CMD16 - Set SD CARD block size to 512 - Sector Size for the SD CARD +// NOTE - Each command is prefixed with a dummy set of CLK pulses to prepare SD CARD to receive a command +// Return 0 success, 1 failure +// +// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Initializing the SD Card" +unsigned char spi_sdcard_goidle(void) +{ + unsigned char r; // Response from SD CARD + int i, timeout; // TIMEOUT loop to send CMD55+ACMD41 repeatedly + + r = spi_setspimode(); // Set SD CARD to SPI mode + if( r != 0x01 ) return FAILURE; + + // CMD0 - Software reset - SD CARD IDLE + // Command Sequence is DUMMY=0xff CMD0=0x40 0x00 0x00 0x00 0x00 CRC=0x95 + // Expected R1 response is 0x01 indicating SD CARD is IDLE + spi_write_byte( 0xff ); spi_write_byte( 0x40 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x95 ); + r = spi_read_rbyte(); + if(r!=0x01) return FAILURE; + + // CMD8 - Check SD CARD type + // Command sequence is DUMMY=0xff CMD8=0x48 0x00 0x00 0x01 0xaa CRC=0x87 + // Expected R7 response is 0x01 followed by 0x00 0x00 0x01 0xaa (these trailing 4 bytes not currently checked) + spi_write_byte( 0xff ); spi_write_byte( 0x48 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x01 ); spi_write_byte( 0xaa ); spi_write_byte( 0x87 ); + r = spi_read_rbyte(); + if(r!=0x01) return FAILURE; + // Receive the trailing 4 bytes for R7 response - FIXME should check for 0x00 0x00 0x01 0xaa + for(i=0; i<4; i++) + r=spi_read_byte(); + + // CMD55+ACMD41 - Force SD CARD READY - prepare card for reading/writing + // Command sequence is CMD55 followed by ACMD41 + // Send commands repeatedly until SD CARD indicates READY 0x00 + // CMD55 Sequence is DUMMY=0xff CMD55=0x77 0x00 0x00 0x00 0x00 CRC=0x00 + // ACMD41 Sequence is DUMMY=0xff ACMD41=0x69 0x40 0x00 0x00 0x00 CRC=0x00 + // Expected R1 response is 0x00 indicating SD CARD is READY + timeout=32; + do { + spi_write_byte( 0xff ); spi_write_byte( 0x77 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); + r = spi_read_rbyte(); + + spi_write_byte( 0xff ); spi_write_byte( 0x69 ); spi_write_byte( 0x40 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); + r = spi_read_rbyte(); + timeout--; + } while ((r != 0x00) && (timeout>0)); + if(r!=0x00) return FAILURE; + + // CMD58 - Read SD CARD OCR (status register) + // FIXME - Find details on expected response from CMD58 to allow accurate checking of SD CARD R3 response + // Command sequence is DUMMY=0xff CMD58=0x7a 0x00 0x00 0x01 0xaa CRC=0xff + // Expected R3 response is 0x00 OR 0x01 followed by 4 (unchecked) trailing bytes + spi_write_byte( 0xff ); spi_write_byte( 0x7a ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0xff ); + r = spi_read_rbyte(); + if(r>0x01) return FAILURE; + // // Receive the trailing 4 bytes for R3 response + for(i=0; i<4; i++) + r=spi_read_byte(); + + // CMD16 - Set SD CARD block size to 512 - Sector Size for the SD CARD + // Command Sequence is DUMMY=0xff (512 as unsigned long = 0x00000200) 0x00 0x00 0x02 0x00 CRC=0xff + // Expected R1 response is 0x00 indicating SD CARD is READY + spi_write_byte( 0xff ); spi_write_byte( 0x50 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x02 ); spi_write_byte( 0x00 ); spi_write_byte( 0xff ); + r=spi_read_rbyte(); + if(r!=0x00) return FAILURE; + + return SUCCESS; +} + +// READSECTOR +// Read a 512 byte sector from the SD CARD +// Given SECTORNUMBER and memory STORAGE +// +// Sequence +// Send CMD17 - Read Block +// Command Sequence is DUMMY=0xff CMD17=0x51 SECTORNUMBER (32bit UNSIGNED as bits 32-25,24-17, 16-9, 8-1) CRC=0xff +// Wait for SD CARD to send 0x00 indicating SD CARD is processing +// Wait for SD CARD to send 0xfe indicating SD CARD BLOCK START +// Read 512 bytes +// Read 8 DUMMY bytes +// Return 0 success, 1 failure +// +// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Read/Write SD Card" +unsigned char readSector(unsigned int sectorNumber, unsigned char *storage); +unsigned char readSector(unsigned int sectorNumber, unsigned char *storage) +{ + unsigned int n,timeout; // Number of bytes loop, timeout loop awaiting response bytes + unsigned char r; // Response bytes from SD CARD + + // CMD17 - Read Block + // Command Sequence is DUMMY=0xff CMD17=0x51 SECTORNUMBER (32bit UNSIGNED as bits 32-25,24-17, 16-9, 8-1) CRC=0xff + // Expected R1 response is 0x00 indicating SD CARD is processing + spi_write_byte( 0xff ); spi_write_byte( 0x51 ); spi_write_byte( (sectorNumber>>24)&0xff ); spi_write_byte( (sectorNumber>>16)&0xff ); spi_write_byte( (sectorNumber>>8)&0xff ); spi_write_byte( (sectorNumber)&0xff ); spi_write_byte( 0xff ); + r=spi_read_rbyte(); + if( r!=0x00 ) return FAILURE; + + // Await 0xfe to indicate BLOCK START + r=spi_read_byte(); + timeout=16384; + while( (r!=0xfe) && (timeout>0) ) { + r=spi_read_byte(); + timeout--; + } + if( r!=0xfe ) return FAILURE; + + // Read 512 bytes into storage + for(n=0; n<512; n++) + storage[n]=spi_read_byte(); + + // Read 8 dummy bytes + for(n=0; n<8; n++) + r=spi_read_byte(); + + return SUCCESS; +} + + +// FAT16 Specific code starts here +// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ + +// Structure to store SD CARD partition table +typedef struct { + unsigned char first_byte; + unsigned char start_chs[3]; + unsigned char partition_type; + unsigned char end_chs[3]; + unsigned long start_sector; + unsigned long length_sectors; +} __attribute((packed)) PartitionTable; + +PartitionTable sdCardPartition; + +// Structure to store SD CARD FAT16 Boot Sector (boot code is ignored, provides layout of the FAT16 partition on the SD CARD) +typedef struct { + unsigned char jmp[3]; + char oem[8]; + unsigned short sector_size; + unsigned char sectors_per_cluster; + unsigned short reserved_sectors; + unsigned char number_of_fats; + unsigned short root_dir_entries; + unsigned short total_sectors_short; // if zero, later field is used + unsigned char media_descriptor; + unsigned short fat_size_sectors; + unsigned short sectors_per_track; + unsigned short number_of_heads; + unsigned long hidden_sectors; + unsigned long total_sectors_long; + + unsigned char drive_number; + unsigned char current_head; + unsigned char boot_signature; + unsigned long volume_id; + char volume_label[11]; + char fs_type[8]; + char boot_code[448]; + unsigned short boot_sector_signature; +} __attribute((packed)) Fat16BootSector; + +Fat16BootSector sdCardFatBootSector; + +// Structure to store SD CARD FAT16 Root Directory Entries +// Allocated to MAIN RAM - hence pointer +typedef struct { + unsigned char filename[8]; + unsigned char ext[3]; + unsigned char attributes; + unsigned char reserved[10]; + unsigned short modify_time; + unsigned short modify_date; + unsigned short starting_cluster; + unsigned long file_size; +} __attribute((packed)) Fat16Entry; + +Fat16Entry *sdCardFat16RootDir; + +// Structure to store SD CARD FAT16 Entries +// Array of UNSIGNED SHORTS (16bit integers) +unsigned short *sdCardFatTable; + +// Calculated sector numbers on the SD CARD for the FAT16 Entries and ROOT DIRECTORY +unsigned int fatSectorStart, rootDirSectorStart; + +// Storage for SECTOR read from SD CARD +unsigned char sdCardSector[512]; + +// SPI_SDCARD_READMBR +// Function exposed to BIOS to retrieve FAT16 partition details, FAT16 Entry Table, FAT16 Root Directory +// MBR = Master Boot Record - Sector 0x00000000 on SD CARD - Contains Partition 1 details at 0x1be +// +// FIXME only checks partition 1 out of 4 +// +// Return 0 success, 1 failure +// +// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ +unsigned char spi_sdcard_readMBR(void) +{ + int i, n; + + // Read Sector 0x00000000 + printf("Reading MBR\n"); + if( readSector(0x00000000, sdCardSector)==SUCCESS ) { + // Copy Partition 1 Entry from byte 0x1be + // FIXME should check 0x55 0xaa at end of sector + memcpy(&sdCardPartition, &sdCardSector[0x1be], sizeof(PartitionTable)); + + // Check Partition 1 is valid, FIRST_BYTE=0x00 or 0x80 + // Check Partition 1 has type 4, 6 or 14 (FAT16 of various sizes) + printf("Partition 1 Information: Active=0x%02x, Type=0x%02x, LBAStart=0x%08x\n", sdCardPartition.first_byte, sdCardPartition.partition_type, sdCardPartition.start_sector); + if( (sdCardPartition.first_byte!=0x80) && (sdCardPartition.first_byte!=0x00) ) { + printf("Partition 1 Not Valid\n"); + return FAILURE; + } + if( (sdCardPartition.partition_type==4) || (sdCardPartition.partition_type==6) || (sdCardPartition.partition_type==14) ) { + printf("Partition 1 is FAT16\n"); + } + else { + printf("Partition 1 Not FAT16\n"); + return FAILURE; + } + } + else { + printf("Failed to read MBR\n"); + return FAILURE; + } + + // Read Parition 1 Boot Sector - Found from Partion Table + printf("\nRead FAT16 Boot Sector\n"); + if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) { + memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector)); + } + else { + printf("Failed to read FAT16 Boot Sector\n"); + return FAILURE; + } + + // Print details of Parition 1 + printf(" Jump Code: 0x%02x 0x%02x 0x%02x\n",sdCardFatBootSector.jmp[0],sdCardFatBootSector.jmp[1],sdCardFatBootSector.jmp[2]); + printf(" OEM Code: ["); + for(n=0; n<8; n++) + printf("%c",sdCardFatBootSector.oem[n]); + printf("]\n"); + printf(" Sector Size: %d\n",sdCardFatBootSector.sector_size); + printf(" Sectors Per Cluster: %d\n",sdCardFatBootSector.sectors_per_cluster); + printf(" Reserved Sectors: %d\n",sdCardFatBootSector.reserved_sectors); + printf(" Number of Fats: %d\n",sdCardFatBootSector.number_of_fats); + printf(" Root Dir Entries: %d\n",sdCardFatBootSector.root_dir_entries); + printf(" Total Sectors Short: %d\n",sdCardFatBootSector.total_sectors_short); + printf(" Media Descriptor: 0x%02x\n",sdCardFatBootSector.media_descriptor); + printf(" Fat Size Sectors: %d\n",sdCardFatBootSector.fat_size_sectors); + printf(" Sectors Per Track: %d\n",sdCardFatBootSector.sectors_per_track); + printf(" Number of Heads: %d\n",sdCardFatBootSector.number_of_heads); + printf(" Hidden Sectors: %d\n",sdCardFatBootSector.hidden_sectors); + printf(" Total Sectors Long: %d\n",sdCardFatBootSector.total_sectors_long); + printf(" Drive Number: 0x%02x\n",sdCardFatBootSector.drive_number); + printf(" Current Head: 0x%02x\n",sdCardFatBootSector.current_head); + printf(" Boot Signature: 0x%02x\n",sdCardFatBootSector.boot_signature); + printf(" Volume ID: 0x%08x\n",sdCardFatBootSector.volume_id); + printf(" Volume Label: ["); + for(n=0; n<11; n++) + printf("%c",sdCardFatBootSector.volume_label[n]); + printf("]\n"); + printf(" Volume Label: ["); + for(n=0; n<8; n++) + printf("%c",sdCardFatBootSector.fs_type[n]); + printf("]\n"); + printf(" Boot Sector Signature: 0x%04x\n\n",sdCardFatBootSector.boot_sector_signature); + + // Check Partition 1 is valid, not 0 length + if(sdCardFatBootSector.total_sectors_long==0) { + printf("Error reading FAT16 Boot Sector\n"); + return FAILURE; + } + + // Read in FAT16 File Allocation Table, array of 16bit unsinged integers + // Calculate Storage from TOP of MAIN RAM + sdCardFatTable = (unsigned short *)(MAIN_RAM_BASE+MAIN_RAM_SIZE-sdCardFatBootSector.sector_size*sdCardFatBootSector.fat_size_sectors); + printf("sdCardFatTable = 0x%08x Reading Fat16 Table (%d Sectors Long)\n\n",sdCardFatTable,sdCardFatBootSector.fat_size_sectors); + + // Calculate Start of FAT16 File Allocation Table (start of partition plus reserved sectors) + fatSectorStart=sdCardPartition.start_sector+sdCardFatBootSector.reserved_sectors; + for(n=0; n0)) { + printf(" File %d [",n); + for( i=0; i<8; i++) { + if( (sdCardFat16RootDir[n].filename[i]>31) && (sdCardFat16RootDir[n].filename[i]<127) ) + printf("%c",sdCardFat16RootDir[n].filename[i]); + else + printf(" "); + } + printf("."); + for( i=0; i<3; i++) { + if( (sdCardFat16RootDir[n].ext[i]>31) && (sdCardFat16RootDir[n].ext[i]<127) ) + printf("%c",sdCardFat16RootDir[n].ext[i]); + else + printf(" "); + } + printf("] @ Cluster %d for %d bytes\n",sdCardFat16RootDir[n].starting_cluster,sdCardFat16RootDir[n].file_size); + } + } + + printf("\n"); + return SUCCESS; +} + +// SPI_SDCARD_READFILE +// Function exposed to BIOS to retrieve FILENAME+EXT into ADDRESS +// +// FIXME only checks UPPERCASE 8+3 filenames +// +// Return 0 success, 1 failure +// +// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ +unsigned char spi_sdcard_readFile(char *filename, char *ext, unsigned long address) +{ + int i, n, sector; + unsigned short fileClusterStart; + unsigned long fileLength, bytesRemaining, clusterSectorStart; + unsigned short nameMatch; + printf("Reading File [%s.%s] into 0x%08x : ",filename, ext, address); + + // Find FILENAME+EXT in Root Directory + // Indicate FILE found by setting the starting cluster number + fileClusterStart=0; n=0; + while( (fileClusterStart==0) && (n1) + for(i=0; i<1+((fileLength/sdCardFatBootSector.sectors_per_cluster)/sdCardFatBootSector.sector_size); i++) { + printf("%d ",fileClusterStart); + + // Locate start of cluster on SD CARD and read appropraite number of sectors + clusterSectorStart=rootDirSectorStart+(fileClusterStart-1)*sdCardFatBootSector.sectors_per_cluster; + for(sector=0; sectorsdCardFatBootSector.sector_size) { + if( readSector(clusterSectorStart+sector,(unsigned char *)address) == FAILURE ) { + printf("Read Error\n"); + return FAILURE; + } + bytesRemaining=bytesRemaining-sdCardFatBootSector.sector_size; + address=address+sdCardFatBootSector.sector_size; + } else { + if( readSector(clusterSectorStart+sector,sdCardSector) == FAILURE ) { + printf("Read Error\n"); + return FAILURE; + } + memcpy((unsigned char *)address, sdCardSector, bytesRemaining); + bytesRemaining=0; + } + } + + // Move to next cluster + fileClusterStart=sdCardFatTable[fileClusterStart]; + } + printf("\n\n"); + return SUCCESS; +} +#endif