1
0

BRFS.C 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. Required operations:
  38. - Format
  39. - Create directory
  40. - Create file
  41. - Open file (allow multiple files open at once)
  42. - Close file (update dir entry and check/update all FAT entries)
  43. - Set cursor
  44. - Get cursor
  45. - Read file
  46. - Write file
  47. - Delete entire file (deleting part of file is not a thing)
  48. - Change directory
  49. - List directory
  50. */
  51. #define word char
  52. #include "LIB/MATH.C"
  53. #include "LIB/SYS.C"
  54. #include "LIB/STDLIB.C"
  55. #define BRFS_RAM_STORAGE_ADDR 0x600000
  56. #define SUPERBLOCK_SIZE 16
  57. word *brfs_ram_storage = (word*) BRFS_RAM_STORAGE_ADDR; // RAM storage of file system
  58. word brfs_current_dir = 0; // Current directory index, points to block in data section
  59. // 16 words long
  60. struct brfs_superblock
  61. {
  62. word total_blocks;
  63. word bytes_per_block;
  64. word label[10]; // 1 char per word
  65. word brfs_version;
  66. word reserved[3];
  67. };
  68. // 8 words long
  69. struct brfs_dir_entry
  70. {
  71. word filename[4]; // 4 chars per word
  72. word modify_date; // TBD when RTC added to FPGC
  73. word flags; // 32 flags, from right to left: directory, hidden
  74. word fat_idx; // idx of first FAT block
  75. word filesize; // file size in words, not bytes
  76. };
  77. word brfs_find_next_free_block(word* fat_addr, word blocks)
  78. {
  79. word i = 0;
  80. word* fat_ptr = fat_addr;
  81. while (i < blocks)
  82. {
  83. if (*fat_ptr == 0)
  84. {
  85. return i;
  86. }
  87. fat_ptr++;
  88. i++;
  89. }
  90. return -1;
  91. }
  92. word brfs_find_next_free_dir_entry(word* dir_addr, word dir_entries_max)
  93. {
  94. word i = 0;
  95. word* dir_ptr = dir_addr;
  96. while (i < dir_entries_max)
  97. {
  98. if (*dir_ptr == 0)
  99. {
  100. return i;
  101. }
  102. dir_ptr += sizeof(struct brfs_dir_entry);
  103. i++;
  104. }
  105. return -1;
  106. }
  107. void brfs_create_single_dir_entry(struct brfs_dir_entry* dir_entry, char* filename, word fat_idx, word filesize, word flags)
  108. {
  109. // Initialize to 0
  110. memset(dir_entry, 0, sizeof(*dir_entry));
  111. // Set filename
  112. char compressed_filename[4] = {0,0,0,0};
  113. strcompress(compressed_filename, filename);
  114. memcpy(&(dir_entry->filename), compressed_filename, sizeof(compressed_filename));
  115. // Set other fields
  116. dir_entry->fat_idx = fat_idx;
  117. dir_entry->flags = flags;
  118. dir_entry->filesize = filesize;
  119. }
  120. void brfs_init_directory(word* dir_addr, word dir_entries_max, word dir_fat_idx, word parent_fat_idx)
  121. {
  122. // Create . entry
  123. struct brfs_dir_entry dir_entry;
  124. brfs_create_single_dir_entry(&dir_entry, ".", dir_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  125. // Copy to first data entry
  126. memcpy(dir_addr, &dir_entry, sizeof(dir_entry));
  127. // Create .. entry
  128. brfs_create_single_dir_entry(&dir_entry, "..", parent_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  129. // Copy to second data entry
  130. memcpy(dir_addr+sizeof(dir_entry), &dir_entry, sizeof(dir_entry));
  131. // Set FAT table
  132. brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
  133. }
  134. // Creates hexdump like dump
  135. void brfs_dump_section(word* addr, word len, word linesize)
  136. {
  137. char buf[16];
  138. word i;
  139. for (i = 0; i < len; i++)
  140. {
  141. itoah(addr[i], buf);
  142. if (strlen(buf+2) == 1)
  143. uprintc('0');
  144. uprint(buf+2);
  145. uprintc(' ');
  146. // newline every linesize words
  147. // also print last linesize words as chars if alphanum
  148. if (i != 0 && MATH_modU(i+1, linesize) == 0)
  149. {
  150. uprint(" ");
  151. word j;
  152. for (j = i - (linesize-1); j < i+1; j++)
  153. {
  154. if (isalnum(addr[j]) || addr[j] == ' ')
  155. uprintc(addr[j]);
  156. else
  157. uprintc('.');
  158. }
  159. uprintc('\n');
  160. }
  161. }
  162. }
  163. void brfs_dump(word* ram_addr, word fatsize, word datasize)
  164. {
  165. // Superblock dump
  166. uprintln("Superblock:");
  167. brfs_dump_section(ram_addr, SUPERBLOCK_SIZE, 16);
  168. // FAT dump
  169. uprintln("\nFAT:");
  170. brfs_dump_section(ram_addr+SUPERBLOCK_SIZE, fatsize, 8);
  171. // Datablock dump
  172. uprintln("\nData:");
  173. brfs_dump_section(ram_addr+SUPERBLOCK_SIZE+fatsize, datasize, 32);
  174. uprintc('\n');
  175. }
  176. void brfs_list_directory(word* ram_addr)
  177. {
  178. struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
  179. word* dir_addr = ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block);
  180. word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
  181. uprintln("-------------------");
  182. word i;
  183. for (i = 0; i < dir_entries_max; i++)
  184. {
  185. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  186. if (dir_entry->filename[0] != 0)
  187. {
  188. uprint("Filename: ");
  189. char decompressed_filename[16];
  190. strdecompress(decompressed_filename, &(dir_entry->filename));
  191. uprintln(decompressed_filename);
  192. uprint("FAT idx: ");
  193. uprintDec((dir_entry->fat_idx));
  194. uprint("Flags: ");
  195. uprintDec((dir_entry->flags));
  196. uprint("Filesize: ");
  197. uprintDec((dir_entry->filesize));
  198. uprintc('\n');
  199. }
  200. }
  201. }
  202. void brfs_change_directory(word* ram_addr, char* dirname)
  203. {
  204. struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
  205. word* dir_addr = ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block);
  206. word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
  207. word i;
  208. for (i = 0; i < dir_entries_max; i++)
  209. {
  210. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  211. if (dir_entry->filename[0] != 0)
  212. {
  213. char decompressed_filename[16];
  214. strdecompress(decompressed_filename, &(dir_entry->filename));
  215. if (strcmp(decompressed_filename, dirname) == 1)
  216. {
  217. brfs_current_dir = dir_entry->fat_idx;
  218. return;
  219. }
  220. }
  221. }
  222. uprintln("Directory not found!");
  223. }
  224. void brfs_format(word* ram_addr, word blocks, word bytes_per_block, char* label, word full_format)
  225. {
  226. // Create a superblock
  227. struct brfs_superblock superblock;
  228. // Initialize to 0
  229. memset(&superblock, 0, sizeof(superblock));
  230. // Set values of superblock
  231. superblock.total_blocks = blocks;
  232. superblock.bytes_per_block = bytes_per_block;
  233. strcpy(&(superblock.label), label);
  234. superblock.brfs_version = 1;
  235. // Copy superblock to head of ram addr
  236. memcpy(ram_addr, &superblock, sizeof(superblock));
  237. // Create FAT
  238. memset(ram_addr + SUPERBLOCK_SIZE, 0, blocks);
  239. // Create Data section
  240. if (full_format)
  241. {
  242. memset(ram_addr + SUPERBLOCK_SIZE + blocks, 0, blocks * bytes_per_block);
  243. }
  244. // Initialize root dir
  245. word dir_entries_max = bytes_per_block / sizeof(struct brfs_dir_entry);
  246. brfs_init_directory(ram_addr + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
  247. brfs_current_dir = 0;
  248. }
  249. /*
  250. * Creates directory in current directory
  251. */
  252. void brfs_create_directory(word* ram_addr, char* dirname)
  253. {
  254. struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
  255. // Find first free FAT block
  256. word next_free_block = brfs_find_next_free_block(ram_addr + SUPERBLOCK_SIZE, superblock->total_blocks);
  257. if (next_free_block == -1)
  258. {
  259. uprintln("No free blocks left!");
  260. return;
  261. }
  262. // Find first free dir entry
  263. word next_free_dir_entry = brfs_find_next_free_dir_entry(
  264. ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block),
  265. superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
  266. );
  267. if (next_free_dir_entry == -1)
  268. {
  269. uprintln("No free dir entries left!");
  270. return;
  271. }
  272. // Create dir entry
  273. struct brfs_dir_entry new_entry;
  274. brfs_create_single_dir_entry(&new_entry, dirname, next_free_block, 0, 1);
  275. // Copy dir entry to first free dir entry
  276. memcpy(
  277. ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
  278. &new_entry,
  279. sizeof(new_entry)
  280. );
  281. // Initialize directory
  282. word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
  283. brfs_init_directory(
  284. ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (next_free_block * superblock->bytes_per_block),
  285. dir_entries_max,
  286. next_free_block,
  287. brfs_current_dir
  288. );
  289. }
  290. /*
  291. * Creates an empty file in current directory
  292. */
  293. void brfs_create_file(word* ram_addr, char* filename)
  294. {
  295. struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
  296. // Find first free FAT block
  297. word next_free_block = brfs_find_next_free_block(ram_addr + SUPERBLOCK_SIZE, superblock->total_blocks);
  298. if (next_free_block == -1)
  299. {
  300. uprintln("No free blocks left!");
  301. return;
  302. }
  303. // Find first free dir entry
  304. word next_free_dir_entry = brfs_find_next_free_dir_entry(
  305. ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block),
  306. superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
  307. );
  308. if (next_free_dir_entry == -1)
  309. {
  310. uprintln("No free dir entries left!");
  311. return;
  312. }
  313. // Create file entry
  314. struct brfs_dir_entry new_entry;
  315. brfs_create_single_dir_entry(&new_entry, filename, next_free_block, 0, 0);
  316. // Copy dir entry to first free dir entry
  317. memcpy(
  318. ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
  319. &new_entry,
  320. sizeof(new_entry)
  321. );
  322. // Initialize file by setting data to 0
  323. memset(
  324. ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (next_free_block * superblock->bytes_per_block),
  325. 0,
  326. superblock->bytes_per_block
  327. );
  328. // Update FAT
  329. ram_addr[SUPERBLOCK_SIZE + next_free_block] = -1;
  330. }
  331. int main()
  332. {
  333. // Clear UART screen:
  334. uprintc(0x1B);
  335. uprintc(0x5B);
  336. uprintc(0x32);
  337. uprintc(0x4A);
  338. uprintln("------------------------");
  339. uprintln("BRFS test implementation");
  340. uprintln("------------------------");
  341. word blocks = 8;
  342. word bytes_per_block = 32;
  343. word full_format = 1;
  344. brfs_format(brfs_ram_storage, blocks, bytes_per_block, "Label", full_format);
  345. brfs_create_file(brfs_ram_storage, "file1");
  346. brfs_create_directory(brfs_ram_storage, "dir1");
  347. brfs_list_directory(brfs_ram_storage);
  348. brfs_change_directory(brfs_ram_storage, "dir1");
  349. brfs_create_file(brfs_ram_storage, "file2");
  350. brfs_list_directory(brfs_ram_storage);
  351. brfs_change_directory(brfs_ram_storage, "..");
  352. brfs_list_directory(brfs_ram_storage);
  353. brfs_dump(brfs_ram_storage, blocks, blocks*bytes_per_block);
  354. return 'q';
  355. }
  356. void interrupt()
  357. {
  358. // handle all interrupts
  359. word i = getIntID();
  360. switch(i)
  361. {
  362. case INTID_TIMER1:
  363. timer1Value = 1; // notify ending of timer1
  364. break;
  365. case INTID_TIMER2:
  366. break;
  367. case INTID_UART0:
  368. break;
  369. case INTID_GPU:
  370. break;
  371. case INTID_TIMER3:
  372. break;
  373. case INTID_PS2:
  374. break;
  375. case INTID_UART1:
  376. break;
  377. case INTID_UART2:
  378. break;
  379. }
  380. }