BRFS.C 47 KB

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