brfs.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436
  1. // Bart's RAM File System (BRFS)
  2. /*
  3. Implementing in BDOS on PCB v3:
  4. - BDOS only uses ~340 pages of 256 bytes -> 90000 bytes
  5. - SPI flash has 65536 pages of 256 bytes -> 16777216 bytes
  6. - With current verilog implementation, only 32MiB of RAM is addressable, so BRFS should be used somewhere in the first 32MiB
  7. - With current BDOS memory map, BRFS should be placed in the first 8MiB available as BDOS Program Code
  8. - Lets use the last 4MiB of this space for BRFS (0x100000 - 0x200000)
  9. */
  10. #define BRFS_SUPPORTED_VERSION 1
  11. #define BRFS_RAM_STORAGE_ADDR 0x100000 // From 4th MiB
  12. // Addresses in SPI Flash
  13. #define SPIFLASH_MEMMAP_ADDR 0x800000
  14. // Note that each section should be in a different 4KiB sector in SPI Flash
  15. #define BRFS_SPIFLASH_SUPERBLOCK_ADDR 0xDF000 // One sector before FAT
  16. #define BRFS_SPIFLASH_FAT_ADDR 0xE0000 // Can be 32768 words (128KiB) for 32MiB of 256word blocks
  17. #define BRFS_SPIFLASH_BLOCK_ADDR 0x100000 // From first MiB
  18. //#define MAX_PATH_LENGTH 127 // Set by BDOS
  19. #define MAX_OPEN_FILES 16 // Can be set higher, but 4 is good for testing
  20. // Length of structs, should not be changed
  21. #define SUPERBLOCK_SIZE 16
  22. #define DIR_ENTRY_SIZE 8
  23. #define BRFS_MAX_BLOCKS 65536 // 64KiB
  24. word brfs_changed_blocks[BRFS_MAX_BLOCKS >> 5]; // Bitmap of changed blocks, each block has 1 bit
  25. // 16 words long
  26. struct brfs_superblock
  27. {
  28. word total_blocks;
  29. word words_per_block;
  30. word label[10]; // 1 char per word
  31. word brfs_version;
  32. word reserved[3];
  33. };
  34. // 8 words long
  35. struct brfs_dir_entry
  36. {
  37. word filename[4]; // 4 chars per word
  38. word modify_date; // TBD when RTC added to FPGC
  39. word flags; // 32 flags, from right to left: directory, hidden
  40. word fat_idx; // idx of first FAT block
  41. word filesize; // file size in words, not bytes
  42. };
  43. word *brfs_ram_storage = (word*) BRFS_RAM_STORAGE_ADDR; // RAM storage of file system
  44. // Variables for open files
  45. word brfs_cursors[MAX_OPEN_FILES]; // Cursor position offset from start of file
  46. word brfs_file_pointers[MAX_OPEN_FILES]; // FAT idx of open file
  47. struct brfs_dir_entry* brfs_dir_entry_pointers[MAX_OPEN_FILES]; // Pointer to dir entry of open file
  48. /**
  49. * Create a hexdump like dump of a section of memory
  50. * addr: address of the section
  51. * len: length of the section in words
  52. * linesize: number of words per line to print
  53. */
  54. void brfs_dump_section(word* addr, word len, word linesize)
  55. {
  56. char buf[16];
  57. word i;
  58. for (i = 0; i < len; i++)
  59. {
  60. itoah(addr[i], buf);
  61. if (strlen(buf+2) == 1)
  62. uprintc('0');
  63. uprint(buf+2);
  64. uprintc(' ');
  65. // newline every linesize words
  66. // also print last linesize words as chars if alphanum
  67. if (i != 0 && MATH_modU(i+1, linesize) == 0)
  68. {
  69. uprint(" ");
  70. word j;
  71. for (j = i - (linesize-1); j < i+1; j++)
  72. {
  73. if (isalnum(addr[j]) || addr[j] == ' ')
  74. uprintc(addr[j]);
  75. else
  76. uprintc('.');
  77. }
  78. uprintc('\n');
  79. }
  80. }
  81. }
  82. /**
  83. * Create a raw filesystem dump over UART
  84. * fatsize: size of the FAT table in words
  85. * datasize: size of the data section in words
  86. */
  87. void brfs_dump(word fatsize, word datasize)
  88. {
  89. // Superblock dump
  90. uprintln("Superblock:");
  91. brfs_dump_section(brfs_ram_storage, SUPERBLOCK_SIZE, 16);
  92. // FAT dump
  93. uprintln("\nFAT:");
  94. brfs_dump_section(brfs_ram_storage+SUPERBLOCK_SIZE, fatsize, 16);
  95. // Datablock dump
  96. uprintln("\nData:");
  97. brfs_dump_section(brfs_ram_storage+SUPERBLOCK_SIZE+fatsize, datasize, 32);
  98. uprintln("\nOpen files:");
  99. word i;
  100. for (i = 0; i < MAX_OPEN_FILES; i++)
  101. {
  102. uprint("FP");
  103. uprintDec(i+1);
  104. uprint(":");
  105. uprint(" FAT idx: ");
  106. uprintDec(brfs_file_pointers[i]);
  107. uprint(" Cursor: ");
  108. uprintDec(brfs_cursors[i]);
  109. uprint(" Size: ");
  110. uprintDec(brfs_dir_entry_pointers[i] ? brfs_dir_entry_pointers[i]->filesize : 0);
  111. uprintc('\n');
  112. }
  113. }
  114. /**
  115. * Return the FAT index of a directory, or -1 if not found
  116. * dir_path: full path of the directory
  117. */
  118. word brfs_get_fat_idx_of_dir(char* dir_path)
  119. {
  120. // Check length of path
  121. if (strlen(dir_path) > MAX_PATH_LENGTH)
  122. {
  123. uprintln("Path too long!");
  124. return -1;
  125. }
  126. // Start with root directory
  127. word current_dir_fat_idx = 0;
  128. // Check if root directory is requested
  129. if (strcmp(dir_path, "/") == 0)
  130. {
  131. return current_dir_fat_idx;
  132. }
  133. // Copy dir_path, size + 1 for null terminator
  134. // Since strtok modifies the string
  135. char dir_path_copy[MAX_PATH_LENGTH+1];
  136. strcpy(dir_path_copy, dir_path);
  137. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  138. word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  139. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  140. // Split path by '/' and traverse directories
  141. char* token = strtok(dir_path_copy, "/");
  142. while (token != (word*)-1)
  143. {
  144. // Find token in current directory
  145. word* dir_addr = brfs_data_block_addr + (current_dir_fat_idx * superblock->words_per_block);
  146. word found_dir = 0; // Keep track if token is found in current directory
  147. word i;
  148. for (i = 0; i < dir_entries_max; i++)
  149. {
  150. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  151. if (dir_entry->filename[0] != 0)
  152. {
  153. char decompressed_filename[17];
  154. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  155. // Also check for directory flag
  156. if (strcmp(decompressed_filename, token) == 0 && dir_entry->flags == 1)
  157. {
  158. // Found token in current directory
  159. // Set current directory to token's FAT index
  160. current_dir_fat_idx = dir_entry->fat_idx;
  161. found_dir = 1;
  162. break;
  163. }
  164. }
  165. }
  166. // If token not found in current directory, return -1
  167. if (!found_dir)
  168. {
  169. uprint("Directory ");
  170. uprint(dir_path);
  171. uprintln(" not found!");
  172. return -1;
  173. }
  174. token = strtok((word*)-1, "/");
  175. }
  176. return current_dir_fat_idx;
  177. }
  178. /**
  179. * Given the address of the FAT table and the number of blocks, find the next free block
  180. * Returns -1 if no free block is found
  181. * fat_addr: address of the FAT table
  182. * blocks: number of blocks in the FAT table
  183. */
  184. word brfs_find_next_free_block(word* fat_addr, word blocks)
  185. {
  186. word i = 0;
  187. word* fat_ptr = fat_addr;
  188. while (i < blocks)
  189. {
  190. if (*fat_ptr == 0)
  191. {
  192. return i;
  193. }
  194. fat_ptr++;
  195. i++;
  196. }
  197. return -1;
  198. }
  199. /**
  200. * Given the address of a directory data block and the maximum number of entries, find the next free directory entry
  201. * Returns -1 if no free entry is found
  202. * dir_addr: address of the directory data block (not the FAT idx)
  203. * dir_entries_max: maximum number of entries in the directory
  204. */
  205. word brfs_find_next_free_dir_entry(word* dir_addr, word dir_entries_max)
  206. {
  207. word i = 0;
  208. word* dir_ptr = dir_addr;
  209. while (i < dir_entries_max)
  210. {
  211. if (*dir_ptr == 0)
  212. {
  213. return i;
  214. }
  215. dir_ptr += sizeof(struct brfs_dir_entry);
  216. i++;
  217. }
  218. return -1;
  219. }
  220. /**
  221. * Create a single directory entry
  222. * dir_entry: pointer to the directory entry to be created
  223. * filename: name of the file, max 16 chars and uncompressed
  224. * fat_idx: index of the first FAT block of the file/directory
  225. * filesize: size of the file in words
  226. * flags: flags of the file/directory
  227. */
  228. void brfs_create_single_dir_entry(struct brfs_dir_entry* dir_entry, char* filename, word fat_idx, word filesize, word flags)
  229. {
  230. // Initialize to 0
  231. memset((char*)dir_entry, 0, sizeof(*dir_entry));
  232. // Set filename
  233. char compressed_filename[4] = {0,0,0,0};
  234. strcompress(compressed_filename, filename);
  235. memcpy((char*)&(dir_entry->filename), compressed_filename, sizeof(compressed_filename));
  236. // Set other fields
  237. dir_entry->fat_idx = fat_idx;
  238. dir_entry->flags = flags;
  239. dir_entry->filesize = filesize;
  240. }
  241. /**
  242. * Initialize a directory with . and .. entries
  243. * dir_addr: address of the directory data block
  244. * dir_entries_max: maximum number of entries in the directory
  245. * dir_fat_idx: index of the FAT block of the directory
  246. * parent_fat_idx: index of the FAT block of the parent directory
  247. */
  248. void brfs_init_directory(word* dir_addr, word dir_entries_max, word dir_fat_idx, word parent_fat_idx)
  249. {
  250. // Get block size from superblock
  251. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  252. word block_size = superblock->words_per_block;
  253. // Set data block of dir_fat_idx to 0
  254. memset(dir_addr, 0, block_size);
  255. // Create . entry
  256. struct brfs_dir_entry dir_entry;
  257. brfs_create_single_dir_entry(&dir_entry, ".", dir_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  258. // Copy to first data entry
  259. memcpy(dir_addr, (char*)&dir_entry, sizeof(dir_entry));
  260. // Create .. entry
  261. brfs_create_single_dir_entry(&dir_entry, "..", parent_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  262. // Copy to second data entry
  263. memcpy(dir_addr+sizeof(dir_entry), (char*)&dir_entry, sizeof(dir_entry));
  264. // Set FAT table
  265. brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
  266. // Set changed block
  267. brfs_changed_blocks[dir_fat_idx >> 5] |= (1 << (dir_fat_idx & 31));
  268. }
  269. /**
  270. * Format the ram storage as a BRFS filesystem
  271. * Also writes the superblock to SPI Flash
  272. * blocks: number of blocks in the filesystem
  273. * words_per_block: number of bytes per block
  274. * label: label of the filesystem
  275. * full_format: if 1, initialize data section to 0
  276. */
  277. void brfs_format(word blocks, word words_per_block, char* label, word full_format)
  278. {
  279. // Create a superblock
  280. struct brfs_superblock superblock;
  281. // Initialize to 0
  282. memset((char*)&superblock, 0, sizeof(superblock));
  283. // Set values of superblock
  284. superblock.total_blocks = blocks;
  285. superblock.words_per_block = words_per_block;
  286. strcpy((char*)&superblock.label, label);
  287. superblock.brfs_version = BRFS_SUPPORTED_VERSION;
  288. // Copy superblock to head of ram addr
  289. memcpy(brfs_ram_storage, (char*)&superblock, sizeof(superblock));
  290. // Create FAT
  291. memset(brfs_ram_storage + SUPERBLOCK_SIZE, 0, blocks);
  292. // Create Data section
  293. if (full_format)
  294. {
  295. memset(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, 0, blocks * words_per_block);
  296. }
  297. // Initialize root dir
  298. word dir_entries_max = words_per_block / sizeof(struct brfs_dir_entry);
  299. brfs_init_directory(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
  300. // Clear open files and cursors
  301. memset(brfs_file_pointers, 0, sizeof(brfs_file_pointers));
  302. memset(brfs_cursors, 0, sizeof(brfs_cursors));
  303. // Set all dir entry pointers to 0
  304. word i;
  305. for (i = 0; i < MAX_OPEN_FILES; i++)
  306. {
  307. brfs_dir_entry_pointers[i] = 0;
  308. }
  309. // For all blocks that have just been formatted, set changed block
  310. word j;
  311. for (j = 0; j < blocks; j++)
  312. {
  313. brfs_changed_blocks[j >> 5] |= (1 << (j & 31));
  314. }
  315. // Write superblock to SPI Flash
  316. spiflash_sector_erase(BRFS_SPIFLASH_SUPERBLOCK_ADDR);
  317. spiflash_write_page_in_words((char*)&superblock, BRFS_SPIFLASH_SUPERBLOCK_ADDR, sizeof(superblock));
  318. }
  319. /**
  320. * Create a new directory in the directory of parent_dir_path
  321. * Returns 1 on success, 0 on error
  322. * parent_dir_path: full path of the parent directory
  323. * dirname: name of the new directory
  324. */
  325. word brfs_create_directory(char* parent_dir_path, char* dirname)
  326. {
  327. // Check length of dirname
  328. if (strlen(dirname) >= 16)
  329. {
  330. uprintln("Directory name too long!");
  331. return 0;
  332. }
  333. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  334. word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  335. // Find first free FAT block
  336. word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
  337. if (next_free_block == -1)
  338. {
  339. uprintln("No free blocks left!");
  340. return 0;
  341. }
  342. // Find data block address of parent directory path
  343. word parent_dir_fat_idx = brfs_get_fat_idx_of_dir(parent_dir_path);
  344. if (parent_dir_fat_idx == -1)
  345. {
  346. uprint("Parent directory ");
  347. uprint(parent_dir_path);
  348. uprintln(" not found!");
  349. return 0;
  350. }
  351. // Check if file or folder already exists
  352. word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block);
  353. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  354. word i;
  355. for (i = 0; i < dir_entries_max; i++)
  356. {
  357. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (parent_dir_addr + (i * sizeof(struct brfs_dir_entry)));
  358. if (dir_entry->filename[0] != 0)
  359. {
  360. char decompressed_filename[17];
  361. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  362. if (strcmp(decompressed_filename, dirname) == 0)
  363. {
  364. uprint(dirname);
  365. uprintln(" already exists!");
  366. return 0;
  367. }
  368. }
  369. }
  370. // Find first free dir entry
  371. word next_free_dir_entry = brfs_find_next_free_dir_entry(
  372. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block),
  373. superblock->words_per_block / sizeof(struct brfs_dir_entry)
  374. );
  375. if (next_free_dir_entry == -1)
  376. {
  377. uprintln("No free dir entries left!");
  378. return 0;
  379. }
  380. // Create dir entry
  381. struct brfs_dir_entry new_entry;
  382. brfs_create_single_dir_entry(&new_entry, dirname, next_free_block, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  383. // Copy dir entry to first free dir entry
  384. memcpy(
  385. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
  386. (char*)&new_entry,
  387. sizeof(new_entry)
  388. );
  389. // Initialize directory
  390. brfs_init_directory(
  391. brfs_data_block_addr + (next_free_block * superblock->words_per_block),
  392. dir_entries_max,
  393. next_free_block,
  394. parent_dir_fat_idx
  395. );
  396. // Update changed block
  397. brfs_changed_blocks[next_free_block >> 5] |= (1 << (next_free_block & 31));
  398. brfs_changed_blocks[parent_dir_fat_idx >> 5] |= (1 << (parent_dir_fat_idx & 31));
  399. return 1;
  400. }
  401. /**
  402. * Create a new file in the directory of parent_dir_path
  403. * Returns 1 on success, 0 on error
  404. * parent_dir_path: full path of the parent directory
  405. * filename: name of the new file
  406. */
  407. word brfs_create_file(char* parent_dir_path, char* filename)
  408. {
  409. // Check length of filename
  410. if (strlen(filename) >= 16)
  411. {
  412. uprintln("Filename too long!");
  413. return 0;
  414. }
  415. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  416. word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  417. // Find first free FAT block
  418. word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
  419. if (next_free_block == -1)
  420. {
  421. uprintln("No free blocks left!");
  422. return 0;
  423. }
  424. // Find data block address of parent directory path
  425. word parent_dir_fat_idx = brfs_get_fat_idx_of_dir(parent_dir_path);
  426. if (parent_dir_fat_idx == -1)
  427. {
  428. uprint("Parent directory ");
  429. uprint(parent_dir_path);
  430. uprintln(" not found!");
  431. return 0;
  432. }
  433. // Check if file or folder already exists
  434. word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block);
  435. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  436. word i;
  437. for (i = 0; i < dir_entries_max; i++)
  438. {
  439. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (parent_dir_addr + (i * sizeof(struct brfs_dir_entry)));
  440. if (dir_entry->filename[0] != 0)
  441. {
  442. char decompressed_filename[17];
  443. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  444. if (strcmp(decompressed_filename, filename) == 0)
  445. {
  446. uprint(filename);
  447. uprintln(" already exists!");
  448. return 0;
  449. }
  450. }
  451. }
  452. // Find first free dir entry
  453. word next_free_dir_entry = brfs_find_next_free_dir_entry(
  454. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block),
  455. superblock->words_per_block / sizeof(struct brfs_dir_entry)
  456. );
  457. if (next_free_dir_entry == -1)
  458. {
  459. uprintln("No free dir entries left!");
  460. return 0;
  461. }
  462. // Create file entry
  463. struct brfs_dir_entry new_entry;
  464. brfs_create_single_dir_entry(&new_entry, filename, next_free_block, 0, 0);
  465. // Copy dir entry to first free dir entry
  466. memcpy(
  467. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
  468. (char*)&new_entry,
  469. sizeof(new_entry)
  470. );
  471. // Initialize file by setting data to 0
  472. memset(
  473. brfs_data_block_addr + (next_free_block * superblock->words_per_block),
  474. 0,
  475. superblock->words_per_block
  476. );
  477. // Update FAT
  478. brfs_ram_storage[SUPERBLOCK_SIZE + next_free_block] = -1;
  479. // Update changed block
  480. brfs_changed_blocks[next_free_block >> 5] |= (1 << (next_free_block & 31));
  481. brfs_changed_blocks[parent_dir_fat_idx >> 5] |= (1 << (parent_dir_fat_idx & 31));
  482. return 1;
  483. }
  484. /**
  485. * Reads all directory entries of a directory into a buffer
  486. * dir_path: full path of the directory
  487. * buffer: buffer to store the directory entries
  488. * Returns the number of entries read, or -1 on error
  489. */
  490. word brfs_read_directory(char* dir_path, struct brfs_dir_entry* buffer)
  491. {
  492. // Find data block address of parent directory path
  493. word dir_fat_idx = brfs_get_fat_idx_of_dir(dir_path);
  494. if (dir_fat_idx == -1)
  495. {
  496. uprint("Parent directory ");
  497. uprint(dir_path);
  498. uprintln(" not found!");
  499. return -1;
  500. }
  501. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  502. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  503. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  504. word entries_read = 0;
  505. word i;
  506. for (i = 0; i < dir_entries_max; i++)
  507. {
  508. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  509. if (dir_entry->filename[0] != 0)
  510. {
  511. memcpy(buffer, dir_entry, sizeof(struct brfs_dir_entry));
  512. buffer++;
  513. entries_read++;
  514. }
  515. }
  516. return entries_read;
  517. }
  518. /**
  519. * Open a file for reading and writing
  520. * Returns the file pointer (FAT idx of file), or -1 on error
  521. * file_path: full path of the file
  522. */
  523. word brfs_open_file(char* file_path)
  524. {
  525. // Split filename from path using basename and dirname
  526. char dirname_output[MAX_PATH_LENGTH];
  527. char* file_path_basename = basename(file_path);
  528. char* file_path_dirname = dirname(dirname_output, file_path);
  529. // Find data block address of parent directory path
  530. word dir_fat_idx = brfs_get_fat_idx_of_dir(file_path_dirname);
  531. if (dir_fat_idx == -1)
  532. {
  533. uprint("Parent directory ");
  534. uprint(file_path_dirname);
  535. uprintln(" not found!");
  536. return -1;
  537. }
  538. // Find file in directory
  539. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  540. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  541. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  542. word i;
  543. for (i = 0; i < dir_entries_max; i++)
  544. {
  545. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  546. if (dir_entry->filename[0] != 0)
  547. {
  548. char decompressed_filename[17];
  549. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  550. // Also check for directory flag to be 0
  551. if (strcmp(decompressed_filename, file_path_basename) == 0 && dir_entry->flags == 0)
  552. {
  553. // Found file
  554. // Check if file is already open
  555. word j;
  556. for (j = 0; j < MAX_OPEN_FILES; j++)
  557. {
  558. if (brfs_file_pointers[j] == dir_entry->fat_idx)
  559. {
  560. uprint("File ");
  561. uprint(file_path_basename);
  562. uprintln(" already open!");
  563. return -1;
  564. }
  565. }
  566. // Find first free file pointer
  567. word next_free_file_pointer = -1;
  568. for (j = 0; j < MAX_OPEN_FILES; j++)
  569. {
  570. if (brfs_file_pointers[j] == 0)
  571. {
  572. next_free_file_pointer = j;
  573. break;
  574. }
  575. }
  576. if (next_free_file_pointer == -1)
  577. {
  578. uprintln("All files already opened!");
  579. return -1;
  580. }
  581. // Open file
  582. brfs_file_pointers[next_free_file_pointer] = dir_entry->fat_idx;
  583. brfs_cursors[next_free_file_pointer] = 0;
  584. brfs_dir_entry_pointers[next_free_file_pointer] = dir_entry;
  585. return brfs_file_pointers[next_free_file_pointer];
  586. }
  587. }
  588. }
  589. uprint("File ");
  590. uprint(file_path_basename);
  591. uprintln(" not found!");
  592. return -1;
  593. }
  594. /**
  595. * Close an opened file
  596. * Returns 1 on success, 0 on error
  597. * file_pointer: file pointer returned by brfs_open_file
  598. */
  599. word brfs_close_file(word file_pointer)
  600. {
  601. // Find file pointer
  602. word i;
  603. for (i = 0; i < MAX_OPEN_FILES; i++)
  604. {
  605. if (brfs_file_pointers[i] == file_pointer)
  606. {
  607. // Close file
  608. brfs_file_pointers[i] = 0;
  609. brfs_cursors[i] = 0;
  610. brfs_dir_entry_pointers[i] = 0;
  611. return 1;
  612. }
  613. }
  614. uprintln("File not found!");
  615. return 0;
  616. }
  617. /**
  618. * Delete a file by removing all FAT blocks and the directory entry
  619. * Deletes a directory only if it is empty
  620. * Returns 1 on success, 0 on error
  621. * file_path: full path of the file
  622. */
  623. word brfs_delete(char* file_path)
  624. {
  625. // Split filename from path using basename and dirname
  626. char dirname_output[MAX_PATH_LENGTH];
  627. char* file_path_basename = basename(file_path);
  628. char* file_path_dirname = dirname(dirname_output, file_path);
  629. // Find data block address of parent directory path
  630. word dir_fat_idx = brfs_get_fat_idx_of_dir(file_path_dirname);
  631. if (dir_fat_idx == -1)
  632. {
  633. uprint("Parent directory ");
  634. uprint(file_path_dirname);
  635. uprintln(" not found!");
  636. return 0;
  637. }
  638. // Find file in directory
  639. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  640. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  641. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  642. word i;
  643. for (i = 0; i < dir_entries_max; i++)
  644. {
  645. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  646. if (dir_entry->filename[0] != 0)
  647. {
  648. char decompressed_filename[17];
  649. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  650. if (strcmp(decompressed_filename, file_path_basename) == 0)
  651. {
  652. if ((dir_entry->flags & 0x01) == 1)
  653. {
  654. // Check if directory is empty
  655. struct brfs_dir_entry buffer[128]; // 128 to be safe
  656. word num_entries = brfs_read_directory(file_path, buffer);
  657. if (num_entries > 2)
  658. {
  659. uprint("Directory ");
  660. uprint(file_path_basename);
  661. uprintln(" is not empty!");
  662. return 0;
  663. }
  664. }
  665. // Check if file is already open
  666. word j;
  667. for (j = 0; j < MAX_OPEN_FILES; j++)
  668. {
  669. if (brfs_file_pointers[j] == dir_entry->fat_idx)
  670. {
  671. uprint("File ");
  672. uprint(file_path_basename);
  673. uprintln(" is open!");
  674. return 0;
  675. }
  676. }
  677. // Delete fat blocks
  678. word current_fat_idx = dir_entry->fat_idx;
  679. word next_fat_idx;
  680. while (current_fat_idx != -1)
  681. {
  682. next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  683. brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = 0;
  684. brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
  685. current_fat_idx = next_fat_idx;
  686. }
  687. // Delete entry
  688. memset((char*)dir_entry, 0, sizeof(struct brfs_dir_entry));
  689. // Update changed block
  690. brfs_changed_blocks[dir_fat_idx >> 5] |= (1 << (dir_fat_idx & 31));
  691. return 1;
  692. }
  693. }
  694. }
  695. uprint("File ");
  696. uprint(file_path_basename);
  697. uprintln(" not found!");
  698. return 0;
  699. }
  700. /**
  701. * Set the cursor of an opened file
  702. * Returns 1 on success, 0 on error
  703. * file_pointer: file pointer returned by brfs_open_file
  704. * cursor: new cursor position in words
  705. */
  706. word brfs_set_cursor(word file_pointer, word cursor)
  707. {
  708. if (file_pointer == 0)
  709. {
  710. uprintln("File not open!");
  711. return 0;
  712. }
  713. // Find file pointer
  714. word i;
  715. for (i = 0; i < MAX_OPEN_FILES; i++)
  716. {
  717. if (brfs_file_pointers[i] == file_pointer)
  718. {
  719. // Set cursor
  720. if (cursor < 0 || cursor > brfs_dir_entry_pointers[i]->filesize)
  721. {
  722. cursor = brfs_dir_entry_pointers[i]->filesize;
  723. }
  724. brfs_cursors[i] = cursor;
  725. return 1;
  726. }
  727. }
  728. uprintln("File not found!");
  729. return 0;
  730. }
  731. /**
  732. * Get the cursor of an opened file
  733. * Returns the cursor position in words, or -1 on error
  734. * file_pointer: file pointer returned by brfs_open_file
  735. */
  736. word brfs_get_cursor(word file_pointer)
  737. {
  738. if (file_pointer == 0)
  739. {
  740. uprintln("File not open!");
  741. return -1;
  742. }
  743. // Find file pointer
  744. word i;
  745. for (i = 0; i < MAX_OPEN_FILES; i++)
  746. {
  747. if (brfs_file_pointers[i] == file_pointer)
  748. {
  749. // Get cursor
  750. return brfs_cursors[i];
  751. }
  752. }
  753. uprintln("File not found!");
  754. return -1;
  755. }
  756. /**
  757. * Get the FAT index of a file at the cursor
  758. * Returns the FAT index, or 0 on error
  759. * file_pointer: file pointer returned by brfs_open_file
  760. * cursor: cursor position of opened file
  761. */
  762. word brfs_get_fat_idx_at_cursor(word file_pointer, word cursor)
  763. {
  764. if (file_pointer == 0)
  765. {
  766. uprintln("File not open!");
  767. return 0;
  768. }
  769. // Get FAT index of file at cursor
  770. word current_fat_idx = file_pointer;
  771. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  772. // Loop through FAT until cursor is reached
  773. while (cursor >= superblock->words_per_block)
  774. {
  775. current_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  776. if (current_fat_idx == -1)
  777. {
  778. uprintln("Cursor is out of bounds!");
  779. return 0;
  780. }
  781. cursor -= superblock->words_per_block;
  782. }
  783. return current_fat_idx;
  784. }
  785. /**
  786. * Read a file from the cursor position
  787. * Returns 1 on success, or 0 on error
  788. * file_pointer: file pointer returned by brfs_open_file
  789. * buffer: buffer to read the file into
  790. * length: number of words to read
  791. */
  792. word brfs_read(word file_pointer, word* buffer, word length)
  793. {
  794. if (file_pointer == 0)
  795. {
  796. uprintln("File not open!");
  797. return 0;
  798. }
  799. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  800. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  801. // Find file pointer
  802. word i;
  803. for (i = 0; i < MAX_OPEN_FILES; i++)
  804. {
  805. if (brfs_file_pointers[i] == file_pointer)
  806. {
  807. if (length < 0)
  808. {
  809. uprintln("Length cannot be negative!");
  810. return 0;
  811. }
  812. // Trunctate length to file size - cursor
  813. if (length > brfs_dir_entry_pointers[i]->filesize - brfs_cursors[i])
  814. {
  815. length = brfs_dir_entry_pointers[i]->filesize - brfs_cursors[i];
  816. }
  817. // Get FAT index of file at cursor
  818. word current_fat_idx = brfs_get_fat_idx_at_cursor(file_pointer, brfs_cursors[i]);
  819. if (current_fat_idx == 0)
  820. {
  821. uprintln("Error getting FAT index at cursor!");
  822. return 0;
  823. }
  824. // Loop:
  825. // - calculate words until end of block (or up to length)
  826. // - read words until end of block (or up to length)
  827. // - decrease length by words read
  828. // - get next block from FAT
  829. // - repeat until length is 0
  830. while (length > 0)
  831. {
  832. word words_until_end_of_block = superblock->words_per_block - (MATH_modU(brfs_cursors[i], superblock->words_per_block));
  833. word words_to_read = words_until_end_of_block > length ? length : words_until_end_of_block;
  834. // Copy words to buffer
  835. memcpy(buffer, data_block_addr + (current_fat_idx * superblock->words_per_block) + MATH_modU(brfs_cursors[i], superblock->words_per_block), words_to_read);
  836. // Update cursor and length
  837. brfs_cursors[i] += words_to_read;
  838. length -= words_to_read;
  839. buffer += words_to_read;
  840. // Get next block from FAT
  841. current_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  842. if (current_fat_idx == -1 && length > 0)
  843. {
  844. uprintln("There is no next block in the file!");
  845. return 0;
  846. }
  847. }
  848. return 1;
  849. }
  850. }
  851. uprintln("File not found!");
  852. return 0;
  853. }
  854. /**
  855. * Write a file from the cursor position
  856. * Returns 1 on success, or 0 on error
  857. * file_pointer: file pointer returned by brfs_open_file
  858. * buffer: buffer to write to the file
  859. * length: number of words to write
  860. */
  861. word brfs_write(word file_pointer, word* buffer, word length)
  862. {
  863. if (file_pointer == 0)
  864. {
  865. uprintln("File not open!");
  866. return 0;
  867. }
  868. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  869. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  870. // Find file pointer
  871. word i;
  872. for (i = 0; i < MAX_OPEN_FILES; i++)
  873. {
  874. if (brfs_file_pointers[i] == file_pointer)
  875. {
  876. if (length < 0)
  877. {
  878. uprintln("Length cannot be negative!");
  879. return 0;
  880. }
  881. // Get FAT index of file at cursor
  882. word current_fat_idx = brfs_get_fat_idx_at_cursor(file_pointer, brfs_cursors[i]);
  883. if (current_fat_idx == 0)
  884. {
  885. uprintln("Error getting FAT index at cursor!");
  886. return 0;
  887. }
  888. // Loop:
  889. // - calculate words until end of block (or up to length)
  890. // - write words until end of block (or up to length)
  891. // - decrease length by words written
  892. // - get next block from FAT, or find next free block if end of block
  893. // - if next block is needed, update FAT
  894. // - repeat until length is 0
  895. while (length > 0)
  896. {
  897. word cursor_in_block = MATH_modU(brfs_cursors[i], superblock->words_per_block);
  898. word words_until_end_of_block = superblock->words_per_block - cursor_in_block;
  899. word words_to_write = words_until_end_of_block > length ? length : words_until_end_of_block;
  900. // Copy words to buffer
  901. memcpy(data_block_addr + (current_fat_idx * superblock->words_per_block) + cursor_in_block, buffer, words_to_write);
  902. // Update changed block
  903. brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
  904. // Update cursor and length
  905. brfs_cursors[i] += words_to_write;
  906. length -= words_to_write;
  907. buffer += words_to_write;
  908. // Get next block from FAT, or find next free block if end of block
  909. if (words_until_end_of_block == words_to_write && length > 0)
  910. {
  911. word next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  912. // Check if next block is already allocated
  913. if (next_fat_idx != -1)
  914. {
  915. current_fat_idx = next_fat_idx;
  916. }
  917. else
  918. {
  919. // Find next free block
  920. word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
  921. if (next_free_block == -1)
  922. {
  923. uprintln("No free blocks left!");
  924. return 0;
  925. }
  926. // Update FAT
  927. brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = next_free_block;
  928. // Go to next block
  929. current_fat_idx = next_free_block;
  930. // Set next block to -1 to indicate end of file
  931. brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = -1;
  932. // Update changed block
  933. brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
  934. }
  935. }
  936. }
  937. // Update file size in dir entry if we wrote past the current size
  938. if (brfs_cursors[i] > brfs_dir_entry_pointers[i]->filesize)
  939. {
  940. brfs_dir_entry_pointers[i]->filesize = brfs_cursors[i];
  941. }
  942. return 1;
  943. }
  944. }
  945. uprintln("File not found!");
  946. return 0;
  947. }
  948. /**
  949. * Stat a file or directory
  950. * Returns the directory entry, or -1 on error
  951. */
  952. struct brfs_dir_entry* brfs_stat(char* file_path)
  953. {
  954. // Remove all trailing slashes
  955. while (strlen(file_path) > 1 && file_path[strlen(file_path)-1] == '/')
  956. {
  957. file_path[strlen(file_path)-1] = 0;
  958. }
  959. // Split filename from path using basename and dirname
  960. char dirname_output[MAX_PATH_LENGTH];
  961. char* file_path_basename = basename(file_path);
  962. char* file_path_dirname = dirname(dirname_output, file_path);
  963. // Find data block address of parent directory path
  964. word dir_fat_idx = brfs_get_fat_idx_of_dir(file_path_dirname);
  965. if (dir_fat_idx == -1)
  966. {
  967. uprint("Parent directory ");
  968. uprint(file_path_dirname);
  969. uprintln(" not found!");
  970. return (struct brfs_dir_entry*)-1;
  971. }
  972. // Find file in directory
  973. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  974. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  975. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  976. word i;
  977. for (i = 0; i < dir_entries_max; i++)
  978. {
  979. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  980. if (dir_entry->filename[0] != 0)
  981. {
  982. char decompressed_filename[17];
  983. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  984. // Also check for directory flag to be 0
  985. if (strcmp(decompressed_filename, file_path_basename) == 0)
  986. {
  987. return dir_entry;
  988. }
  989. }
  990. }
  991. uprint("File or directory ");
  992. uprint(file_path_basename);
  993. uprintln(" not found!");
  994. return (struct brfs_dir_entry*)-1;
  995. }
  996. /**
  997. * Write the FAT table to SPI flash by performing three steps:
  998. * 1. Check which FAT entries have changed
  999. * 2. Erase the 4KiB sectors that contain these FAT entries
  1000. * 3. Write each changed FAT entry to flash by using 16 page writes per sector
  1001. */
  1002. void brfs_write_fat_to_flash()
  1003. {
  1004. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1005. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1006. // 1 sector = 4KiB = 1024 words = 1024 FAT entries
  1007. // 1 word contains 32 flags for changed blocks/FAT entries
  1008. // 1024/32 = 32 words in the changed_blocks array per sector
  1009. uprintln("---Writing FAT to SPI Flash---");
  1010. // Loop over brfs_changed_blocks in 32 word parts
  1011. // Assumes length of brfs_changed_blocks is a multiple of 32
  1012. word i;
  1013. for (i = 0; i < sizeof(brfs_changed_blocks); i+=32)
  1014. {
  1015. // Check if any value within brfs_changed_blocks[i:i+32] is not 0
  1016. word j;
  1017. word changed = 0;
  1018. for (j = 0; j < 32; j++)
  1019. {
  1020. if (brfs_changed_blocks[i+j] != 0)
  1021. {
  1022. changed = 1;
  1023. break;
  1024. }
  1025. }
  1026. if (changed)
  1027. {
  1028. // Erase sector
  1029. word addr = BRFS_SPIFLASH_FAT_ADDR; // Workaround because of large static number
  1030. addr += (i >> 5) * 4096; // Sector idx * bytes per sector
  1031. spiflash_sector_erase(addr);
  1032. uprint("Erased sector ");
  1033. uprintDec(i >> 5);
  1034. uprint(" at address ");
  1035. uprintHex(addr);
  1036. uprintln("");
  1037. // Write sector by writing 16 pages k of 64 words
  1038. // Does not check for boundaries of actual FAT table size,
  1039. // so it can write garbage if block size is not a multiple of 1024
  1040. word k;
  1041. for (k = 0; k < 1024; k+=64)
  1042. {
  1043. addr = BRFS_SPIFLASH_FAT_ADDR; // Workaround because of large static number
  1044. addr += (i >> 5) * 4096; // Sector idx * bytes per sector
  1045. addr += k << 2; // 64 words * 4 bytes per word
  1046. word* fat_addr_ram = brfs_ram_storage + SUPERBLOCK_SIZE + (i << 5) + k;
  1047. spiflash_write_page_in_words(fat_addr_ram, addr, 64);
  1048. uprint("Wrote FAT entries ");
  1049. uprintDec((i << 5) + k);
  1050. uprint(":");
  1051. uprintDec((i << 5) + k + 63);
  1052. uprint(" from RAM addr ");
  1053. uprintHex((word)fat_addr_ram);
  1054. uprint(" to SPI Flash addr ");
  1055. uprintHex(addr);
  1056. uprintln("");
  1057. }
  1058. }
  1059. }
  1060. uprintln("---Finished writing FAT to SPI Flash---");
  1061. }
  1062. /**
  1063. * Write a sector (4KiB) to SPI flash
  1064. * sector_idx: index of the sector
  1065. */
  1066. void brfs_write_sector_to_flash(word sector_idx)
  1067. {
  1068. word spi_addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
  1069. spi_addr += sector_idx * 4096; // Sector idx * bytes per sector
  1070. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1071. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1072. word brfs_sector_addr = data_block_addr + sector_idx * (4096 >> 2); // Divided by 4 because of word size
  1073. // Write sector by writing 16 pages k of 64 words
  1074. // Does not check for boundaries of actual FAT table size,
  1075. // so it can write garbage if block size is not a multiple of 1024
  1076. word k;
  1077. for (k = 0; k < 1024; k+=64)
  1078. {
  1079. spiflash_write_page_in_words(brfs_sector_addr + k, spi_addr + (k << 2), 64);
  1080. uprint("Wrote sector ");
  1081. uprintDec(sector_idx);
  1082. uprint(":");
  1083. uprintDec(sector_idx + 15);
  1084. uprint(" from RAM addr ");
  1085. uprintHex((word)(brfs_sector_addr + k));
  1086. uprint(" to SPI Flash addr ");
  1087. uprintHex(spi_addr + (k << 2));
  1088. uprintln("");
  1089. }
  1090. }
  1091. /**
  1092. * Write the data blocks to SPI flash by performing three steps:
  1093. * 1. Check which blocks have changed
  1094. * 2. Erase the 4KiB sectors that contain these blocks
  1095. * 3. Write each erased sector with the new block data by using 16 page writes per sector
  1096. */
  1097. void brfs_write_blocks_to_flash()
  1098. {
  1099. // Loop over all blocks
  1100. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1101. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1102. // Check if block size is <= 4KiB
  1103. if (superblock->words_per_block > 1024)
  1104. {
  1105. uprintln("Error: block size should be <= 4KiB");
  1106. return;
  1107. }
  1108. // Check if block size is a multiple of 64
  1109. if (superblock->words_per_block & 63)
  1110. {
  1111. uprintln("Error: block size should be a multiple of 64");
  1112. return;
  1113. }
  1114. uprintln("---Writing blocks to SPI Flash---");
  1115. word blocks_per_sector = MATH_divU(4096, superblock->words_per_block * 4);
  1116. uprint("Blocks per sector: ");
  1117. uprintDec(blocks_per_sector);
  1118. uprintln("");
  1119. // Erase 4KiB sectors that contain changed blocks
  1120. // This code is written such that it only erases each sector once, even if multiple blocks in the sector have changed
  1121. word i;
  1122. word sector_to_erase = -1;
  1123. for (i = 0; i < superblock->total_blocks; i++)
  1124. {
  1125. if (brfs_changed_blocks[i >> 5] & (1 << (i & 31)))
  1126. {
  1127. if (sector_to_erase == -1)
  1128. {
  1129. sector_to_erase = MATH_divU(i, blocks_per_sector);
  1130. }
  1131. else if (sector_to_erase != MATH_divU(i, blocks_per_sector))
  1132. {
  1133. word addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
  1134. addr += sector_to_erase * 4096;
  1135. spiflash_sector_erase(addr);
  1136. uprint("Erased sector ");
  1137. uprintDec(sector_to_erase);
  1138. uprint(" at address ");
  1139. uprintHex(addr);
  1140. uprintln("");
  1141. brfs_write_sector_to_flash(sector_to_erase);
  1142. sector_to_erase = MATH_divU(i, blocks_per_sector);
  1143. }
  1144. }
  1145. }
  1146. if (sector_to_erase != -1)
  1147. {
  1148. word addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
  1149. addr += sector_to_erase * 4096;
  1150. spiflash_sector_erase(addr);
  1151. uprint("Erased sector ");
  1152. uprintDec(sector_to_erase);
  1153. uprint(" at address ");
  1154. uprintHex(addr);
  1155. uprintln("");
  1156. brfs_write_sector_to_flash(sector_to_erase);
  1157. }
  1158. uprintln("---Finished writing blocks to SPI Flash---");
  1159. }
  1160. /**
  1161. * Write the FAT and data blocks to SPI flash
  1162. * Superblock should already be written to flash during format
  1163. */
  1164. void brfs_write_to_flash()
  1165. {
  1166. brfs_write_fat_to_flash();
  1167. brfs_write_blocks_to_flash();
  1168. // Reset changed blocks
  1169. memset(brfs_changed_blocks, 0, sizeof(brfs_changed_blocks));
  1170. }
  1171. /**
  1172. * Checks if given superblock is valid
  1173. * Returns 1 if valid, 0 if invalid
  1174. */
  1175. word brfs_superblock_is_valid(struct brfs_superblock* superblock)
  1176. {
  1177. // Check if brfs version is correct
  1178. if (superblock->brfs_version != BRFS_SUPPORTED_VERSION)
  1179. {
  1180. uprint("BRFS version ");
  1181. uprintDec(superblock->brfs_version);
  1182. uprint(" is not supported by this implementation (");
  1183. uprintDec(BRFS_SUPPORTED_VERSION);
  1184. uprintln(")!");
  1185. return 0;
  1186. }
  1187. // Check if total blocks is > 0 and a multiple of 64
  1188. if (superblock->total_blocks == 0 || superblock->total_blocks & 63)
  1189. {
  1190. uprintln("Error: total blocks should be > 0 and a multiple of 64");
  1191. return 0;
  1192. }
  1193. // Check if block size is > 0
  1194. if (superblock->words_per_block == 0)
  1195. {
  1196. uprintln("Error: block size should be > 0");
  1197. return 0;
  1198. }
  1199. // Check if words per block is > 0 and <= 2048
  1200. if (superblock->words_per_block == 0 || superblock->words_per_block > 2048)
  1201. {
  1202. uprintln("Error: words per block should be > 0 and <= 2048");
  1203. return 0;
  1204. }
  1205. return 1;
  1206. }
  1207. /**
  1208. * Read the superblock, FAT and data blocks from SPI flash
  1209. * Reads in QSPI mode and returns to SPI mode after reading
  1210. * Returns 1 on success, or 0 on error
  1211. */
  1212. word brfs_read_from_flash()
  1213. {
  1214. // Set QSPI memory mapped mode
  1215. spiflash_qspi();
  1216. // Read superblock from flash
  1217. char* spi_flash_read_addr = (char*) SPIFLASH_MEMMAP_ADDR + (BRFS_SPIFLASH_SUPERBLOCK_ADDR >> 2);
  1218. memcpy(brfs_ram_storage, spi_flash_read_addr, SUPERBLOCK_SIZE);
  1219. // Perform validity checks on superblock
  1220. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1221. if (!brfs_superblock_is_valid(superblock))
  1222. {
  1223. uprintln("Error: superblock is not valid!");
  1224. spiflash_init(); // Return to SPI mode
  1225. return 0;
  1226. }
  1227. // Read FAT from flash
  1228. spi_flash_read_addr = (char*) SPIFLASH_MEMMAP_ADDR + (BRFS_SPIFLASH_FAT_ADDR >> 2);
  1229. memcpy(brfs_ram_storage + SUPERBLOCK_SIZE, spi_flash_read_addr, superblock->total_blocks);
  1230. // Read data blocks from flash
  1231. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1232. spi_flash_read_addr = (char*) SPIFLASH_MEMMAP_ADDR + (BRFS_SPIFLASH_BLOCK_ADDR >> 2);
  1233. word read_length = superblock->total_blocks * superblock->words_per_block;
  1234. // Check if read_length is a multiple of 16
  1235. if (read_length & 15)
  1236. {
  1237. // Read without progress bar
  1238. memcpy(data_block_addr, spi_flash_read_addr, read_length);
  1239. spiflash_init(); // Return to SPI mode
  1240. return 1;
  1241. }
  1242. // Print progress bar
  1243. GFX_disable_cursor = 1;
  1244. GFX_PrintConsole("Loading blocks: ");
  1245. // Print emtpy block character
  1246. word i;
  1247. for (i = 0; i < 16; i++)
  1248. {
  1249. GFX_PrintcConsole(176);
  1250. }
  1251. // Set cursor back to start of progress bar
  1252. GFX_cursor -= 16;
  1253. // Split in 16 parts
  1254. word read_length_per_part = read_length >> 4;
  1255. for (i = 0; i < 16; i++)
  1256. {
  1257. memcpy(data_block_addr + (i * read_length_per_part), spi_flash_read_addr + (i * read_length_per_part), read_length_per_part);
  1258. GFX_PrintcConsole(219); // Print full block character
  1259. }
  1260. GFX_disable_cursor = 0;
  1261. GFX_PrintcConsole('\n');
  1262. spiflash_init(); // Return to SPI mode
  1263. return 1;
  1264. }