Filesystem (BRFS)
BRFS (Bart's RAM File System) is a FAT-based filesystem designed for the FPGC that uses RAM as a cache with SPI Flash (currently, but in the future SD card might also be supported) as persistent storage. It provides hierarchical directory support with a simple design optimized for the word-addressable B32P3 architecture.
Overview
BRFS has the following characteristics:
- FAT-based - Uses a File Allocation Table to manage block allocation and file chains
- RAM-cached operation - The entire filesystem is loaded into RAM for fast access since the FPGC has plenty of RAM
- SPI Flash persistence - Data is persisted to SPI Flash for non-volatile storage (explicitly only via
brfs_syncfunction) - Hierarchical directories - Supports nested directories
- Word-aligned storage - All data stored as 32-bit words (native to B32P3)
- Compressed filenames - Max 16-character filenames packed into 4 words
Architecture
Memory Layout
BRFS organizes data in three regions, both in RAM cache and SPI Flash:
┌──────────────────────────────────────────────────┐
│ Superblock (16 words) │
│ - Filesystem metadata and configuration │
├──────────────────────────────────────────────────┤
│ FAT (File Allocation Table) │
│ - One entry per block (total_blocks words) │
│ - Tracks block allocation and file chains │
├──────────────────────────────────────────────────┤
│ Data Blocks │
│ - File and directory content │
│ - Block size configurable │
└──────────────────────────────────────────────────┘
Superblock Structure
The superblock (16 words) contains filesystem metadata:
| Field | Size (words) | Description |
|---|---|---|
total_blocks |
1 | Total number of blocks in filesystem |
words_per_block |
1 | Words per block (e.g., 256 = 1KB) |
label |
10 | Volume label (1 char per word) |
brfs_version |
1 | BRFS version number |
reserved |
3 | Reserved for future use |
File Allocation Table (FAT)
The FAT is an array where each entry corresponds to a data block:
0- Block is free0xFFFFFFFF- End of file chain (EOF)- Any other value - Index of next block in chain
Files larger than one block are stored as linked chains in the FAT. To read a file, follow the chain from the first block (stored in the directory entry) until reaching EOF.
Directory Entries
Directories are special files containing 8-word entries:
| Field | Size (words) | Description |
|---|---|---|
filename |
4 | Compressed filename (4 chars/word, 16 chars max) |
modify_date |
1 | Modification date (reserved for RTC) |
flags |
1 | Entry flags (directory, hidden) |
fat_idx |
1 | Index of first block in FAT |
filesize |
1 | File size in words |
A 1024-word block can hold 128 directory entries.
Implementation Notes
Filename Compression:
Filenames are stored with 4 characters packed per 32-bit word to save space. This allows 16-character filenames in just 4 words.
Dirty Block Tracking:
BRFS uses a bitmap to track which blocks have been modified since the last sync. Only dirty blocks are written to flash during brfs_sync().
Flash Write Strategy:
Due to SPI Flash constraints:
- Reads can be any size from any address
- Writes must be to erased memory, max 256 bytes (64 words) per page
- Erases are 4KB sectors (1024 words) minimum
BRFS handles this by:
- Erasing entire sectors before writing
- Writing data in 64-word page chunks
- Words per block should be a multiple of 64 to align with flash page size
Root Directory
Block 0 is always reserved for the root directory. It is initialized during brfs_format() with . and .. entries pointing to itself.
Limitations
- Maximum 16-character filenames
- Maximum 127-character paths
- No file permissions or ownership
- No timestamps (RTC support reserved but not implemented)
- Single-user, no locking
- Cache must fit entire filesystem in RAM
Most of these limitations are intentional design choices to keep the filesystem simple and efficient for the FPGC's architecture and use cases, but in the future I might want to add something to support larger filesystem sizes with dynamic caching.
Formatting parameters
The number of blocks and block size should be a multiple of 64. The size of the superblock and FAT need to be taken into account when calculating total flash usage. For example, formatting an SPI Flash of 16MiB with 256-word blocks can best be done with 16320 blocks.