|
@@ -0,0 +1,216 @@
|
|
|
+// Test implementation of Bart's RAM File System (BRFS)
|
|
|
+
|
|
|
+/*
|
|
|
+General Idea:
|
|
|
+- HDD for the average home user was <100MB until after 1990
|
|
|
+- SPI NOR Flash provides around the same amount of storage, with relatively little wear
|
|
|
+ - However, writes are extremely slow
|
|
|
+- FPGC has 64MiB RAM, which is a lot even for 64 bit addressable words
|
|
|
+ - 32MiB is already more than enough for the FPGC in its current form
|
|
|
+- Use the other 32MiB as a fully in RAM filesystem
|
|
|
+ - That initializes from SPI flash and writes back to Flash at a chosen time
|
|
|
+*/
|
|
|
+
|
|
|
+/*
|
|
|
+Implementation Idea:
|
|
|
+- Use superblock for info/addresses, no hard-coded sizes!
|
|
|
+ - Allows for different storage media, easier testing on tiny size, and more future proof
|
|
|
+*/
|
|
|
+
|
|
|
+/*
|
|
|
+Implementation Details:
|
|
|
+--------------------------------------------------
|
|
|
+| superblock | FAT | Data+Dir blocks (same size) |
|
|
|
+--------------------------------------------------
|
|
|
+
|
|
|
+16 word superblock:
|
|
|
+ - (1) total blocks
|
|
|
+ - (1) bytes per block
|
|
|
+ - (10) label [1 char per word]
|
|
|
+ - (1) brfs version
|
|
|
+ - (3) reserved
|
|
|
+
|
|
|
+8 word Dir entries:
|
|
|
+ - (4) filename.ext [4 chars per word]
|
|
|
+ - (1) modify date [to be implemented when RTC]
|
|
|
+ - (1) flags [max 32 flags, TBD]
|
|
|
+ - (1) 1st FAT idx
|
|
|
+ - (1) file size [in words, not bytes]
|
|
|
+*/
|
|
|
+
|
|
|
+#define word char
|
|
|
+
|
|
|
+#include "LIB/MATH.C"
|
|
|
+#include "LIB/SYS.C"
|
|
|
+#include "LIB/STDLIB.C"
|
|
|
+
|
|
|
+#define BRFS_RAM_STORAGE_ADDR 0x500000
|
|
|
+
|
|
|
+#define SUPERBLOCK_SIZE 16
|
|
|
+
|
|
|
+word *brfs_ram_storage = (word*) BRFS_RAM_STORAGE_ADDR; // RAM storage of file system
|
|
|
+
|
|
|
+// 16 words long
|
|
|
+struct brfs_superblock
|
|
|
+{
|
|
|
+ word total_blocks;
|
|
|
+ word bytes_per_block;
|
|
|
+ word label[10]; // 1 char per word
|
|
|
+ word brfs_version;
|
|
|
+ word reserved[3];
|
|
|
+};
|
|
|
+
|
|
|
+// 16 words long
|
|
|
+struct brfs_dir_entry
|
|
|
+{
|
|
|
+ word filename[4]; // 4 chars per word
|
|
|
+ word modify_date; // TBD when RTC added to FPGC
|
|
|
+ word flags;
|
|
|
+ word fat_idx; // idx of first FAT block
|
|
|
+ word filesize; // file size in words, not bytes
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+// Creates hexdump like dump
|
|
|
+void brfs_dump_section(word* addr, word len, word linesize)
|
|
|
+{
|
|
|
+ char buf[16];
|
|
|
+ word i;
|
|
|
+ for (i = 0; i < len; i++)
|
|
|
+ {
|
|
|
+ itoah(addr[i], buf);
|
|
|
+ if (strlen(buf+2) == 1)
|
|
|
+ uprintc('0');
|
|
|
+ uprint(buf+2);
|
|
|
+
|
|
|
+ uprintc(' ');
|
|
|
+
|
|
|
+ // newline every linesize words
|
|
|
+ // also print last linesize words as chars if alphanum
|
|
|
+ if (i != 0 && MATH_modU(i+1, linesize) == 0)
|
|
|
+ {
|
|
|
+ uprint(" ");
|
|
|
+ word j;
|
|
|
+ for (j = i - (linesize-1); j < i+1; j++)
|
|
|
+ {
|
|
|
+ if (isalnum(addr[j]) || addr[j] == ' ')
|
|
|
+ uprintc(addr[j]);
|
|
|
+ else
|
|
|
+ uprintc('.');
|
|
|
+ }
|
|
|
+ uprintc('\n');
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void brfs_dump(word* ram_addr, word fatsize, word datasize)
|
|
|
+{
|
|
|
+ // Superblock dump
|
|
|
+ uprintln("Superblock:");
|
|
|
+ brfs_dump_section(ram_addr, SUPERBLOCK_SIZE, 16);
|
|
|
+
|
|
|
+ // FAT dump
|
|
|
+ uprintln("\nFAT:");
|
|
|
+ brfs_dump_section(ram_addr+SUPERBLOCK_SIZE, fatsize, 8);
|
|
|
+
|
|
|
+ // Datablock dump
|
|
|
+ uprintln("\nData:");
|
|
|
+ brfs_dump_section(ram_addr+SUPERBLOCK_SIZE+fatsize, datasize, 16);
|
|
|
+
|
|
|
+ uprintc('\n');
|
|
|
+}
|
|
|
+
|
|
|
+void brfs_format(word* ram_addr, word blocks, word bytes_per_block, char* label, word full_format)
|
|
|
+{
|
|
|
+ // Create a superblock
|
|
|
+ struct brfs_superblock superblock;
|
|
|
+
|
|
|
+ // Initialize to 0
|
|
|
+ memset(&superblock, 0, sizeof(superblock));
|
|
|
+
|
|
|
+ // Set values of superblock
|
|
|
+ superblock.total_blocks = blocks;
|
|
|
+ superblock.bytes_per_block = bytes_per_block;
|
|
|
+ strcpy(&(superblock.label), label);
|
|
|
+ superblock.brfs_version = 1;
|
|
|
+
|
|
|
+ // Copy superblock to head of ram addr
|
|
|
+ memcpy(ram_addr, &superblock, sizeof(superblock));
|
|
|
+
|
|
|
+
|
|
|
+ // Create FAT
|
|
|
+ memset(ram_addr + SUPERBLOCK_SIZE, 0, blocks);
|
|
|
+
|
|
|
+ // Create Data section
|
|
|
+ if (full_format)
|
|
|
+ {
|
|
|
+ memset(ram_addr + SUPERBLOCK_SIZE + blocks, 0, blocks * bytes_per_block);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create root dir entry in first block
|
|
|
+ struct brfs_dir_entry root_dir;
|
|
|
+
|
|
|
+ // Initialize to 0
|
|
|
+ memset(&root_dir, 0, sizeof(root_dir));
|
|
|
+
|
|
|
+ // Copy root dir entry to first block
|
|
|
+ memcpy(ram_addr + SUPERBLOCK_SIZE + blocks, &root_dir, sizeof(root_dir));
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ // Clear UART screen:
|
|
|
+ uprintc(0x1B);
|
|
|
+ uprintc(0x5B);
|
|
|
+ uprintc(0x32);
|
|
|
+ uprintc(0x4A);
|
|
|
+ uprintln("------------------------");
|
|
|
+ uprintln("BRFS test implementation");
|
|
|
+ uprintln("------------------------");
|
|
|
+
|
|
|
+ word blocks = 8;
|
|
|
+ word bytes_per_block = 16;
|
|
|
+ word full_format = 1;
|
|
|
+
|
|
|
+ brfs_format(brfs_ram_storage, blocks, bytes_per_block, "Label", full_format);
|
|
|
+
|
|
|
+ brfs_dump(brfs_ram_storage, blocks, blocks*bytes_per_block);
|
|
|
+
|
|
|
+ return 'q';
|
|
|
+}
|
|
|
+
|
|
|
+void interrupt()
|
|
|
+{
|
|
|
+ // handle all interrupts
|
|
|
+ word i = getIntID();
|
|
|
+ switch(i)
|
|
|
+ {
|
|
|
+ case INTID_TIMER1:
|
|
|
+ timer1Value = 1; // notify ending of timer1
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_TIMER2:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_UART0:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_GPU:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_TIMER3:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_PS2:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_UART1:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case INTID_UART2:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|