1
0

BRFS.C 45 KB

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