/* // PicoPAC MultiCART by Andrea Ottaviani 2024 // // VIDEOPAC multicart based on Raspberry Pico board - // // More info on https://github.com/aotta/ // // parts of code are directly from the A8PicoCart project by Robin Edwards 2023 // // Needs to be a release NOT debug build for the cartridge emulation to work // // Edit myboard.h depending on the type of flash memory on the pico clone// // // v. 1.0 2024-08-05 : Initial version for Pi Pico // */ #include "pico/stdlib.h" #include "hardware/flash.h" #include "hardware/sync.h" #include #include #include "flash_fs.h" // Implements 512 byte FAT sectors on 4096 byte flash sectors. // Doesn't really implement wear levelling (e.g. the fs_map) so not for heavy use but should be // fine for the intended use case. #define HW_FLASH_STORAGE_BASE (1024 * 1024) #define MAGIC_8_BYTES "RHE!FS30" #define NUM_FAT_SECTORS 30716 // 15megs / 512bytes = 30720, but we used 4 records for the header (8 bytes) #define NUM_FLASH_SECTORS 3840 // 15megs / 4096bytes = 3840 typedef struct { uint8_t header[8]; uint16_t sectors[NUM_FAT_SECTORS]; // map FAT sectors -> flash sectors } sector_map; sector_map fs_map; bool fs_map_needs_written[15]; uint8_t used_bitmap[NUM_FLASH_SECTORS]; // we will use 256 flash sectors for 2048 fat sectors uint16_t write_sector = 0; // which flash sector we are writing to uint8_t write_sector_bitmap = 0; // 1 for each free 512 byte page on the sector // each sector entry in the sector map is: // 13 bits of sector (indexing 8192 4k flash sectors) // 3 bits of offset (0->7 512 byte FAT sectors in each 4k flash sector) uint16_t getMapSector(uint16_t mapEntry) { return (mapEntry & 0xFFF8) >> 3; } uint8_t getMapOffset(uint16_t mapEntry) { return mapEntry & 0x7; } uint16_t makeMapEntry(uint16_t sector, uint8_t offset) { return (sector << 3) | offset; }; // forward declns void flash_read_sector(uint16_t sector, uint8_t offset, void *buffer, uint16_t size); void flash_erase_sector(uint16_t sector); void flash_write_sector(uint16_t sector, uint8_t offset, const void *buffer, uint16_t size); void flash_erase_with_copy_sector(uint16_t sector, uint8_t preserve_bitmap); void debug_print_in_use() { return; // just shows first 1meg printf("IN USE-----------------------------------\n"); for (int i=0; i<16; i++) { printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", used_bitmap[i*16+0], used_bitmap[i*16+1], used_bitmap[i*16+2], used_bitmap[i*16+3], used_bitmap[i*16+4], used_bitmap[i*16+5], used_bitmap[i*16+6], used_bitmap[i*16+7], used_bitmap[i*16+8], used_bitmap[i*16+9], used_bitmap[i*16+10], used_bitmap[i*16+11], used_bitmap[i*16+12], used_bitmap[i*16+13], used_bitmap[i*16+14], used_bitmap[i*16+15]); } printf("END--------------------------------------\n"); } void write_fs_map() { debug_print_in_use(); for (int i=0; i<15; i++) { if (fs_map_needs_written[i]) { // printf("Writing FS Map %d\n", i); flash_erase_sector(i); flash_write_sector(i, 0, (uint8_t*)&fs_map+(4096*i), 4096); fs_map_needs_written[i] = false; } } } uint16_t getNextWriteSector() { static uint16_t search_start_pos = 0; int i; if (write_sector == 0 || write_sector_bitmap == 0) { // first try to find a completely free sector for (i=0; i