brfs.c 43 KB

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