|
@@ -63,26 +63,56 @@ Required operations:
|
|
- [x] List directory
|
|
- [x] List directory
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+Implementing in BDOS on PCB v3:
|
|
|
|
+- BDOS only uses ~340 pages of 256 bytes -> 90000 bytes
|
|
|
|
+- SPI flash has 65536 pages of 256 bytes -> 16777216 bytes
|
|
|
|
+- With current verilog implementation, only 32MiB of RAM is addressable, so BRFS should be used somewhere in the first 32MiB
|
|
|
|
+- With current BDOS memory map, BRFS should be placed in the first 8MiB available as BDOS Program Code
|
|
|
|
+- Lets use the last 4MiB of this space for BRFS (0x100000 - 0x200000)
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+Integrate with SPI Flash:
|
|
|
|
+- [] Function to read from SPI Flash (to be used on startup of BDOS)
|
|
|
|
+ - [] Check for valid BRFS superblock
|
|
|
|
+ - [] Load BRFS into RAM (read total blocks and words per block from superblock)
|
|
|
|
+- [x] Function to write BRFS to SPI Flash (to be used by applications/OS via System Call)
|
|
|
|
+ - [x] Check which blocks have changed using a bitmap
|
|
|
|
+ - [x] Erase changed blocks (by sector) in SPI Flash
|
|
|
|
+ - [x] Write changed blocks to SPI Flash (by page)
|
|
|
|
+*/
|
|
|
|
+
|
|
#define word char
|
|
#define word char
|
|
|
|
|
|
#include "LIB/MATH.C"
|
|
#include "LIB/MATH.C"
|
|
#include "LIB/SYS.C"
|
|
#include "LIB/SYS.C"
|
|
#include "LIB/STDLIB.C"
|
|
#include "LIB/STDLIB.C"
|
|
|
|
+#include "LIB/SPIFLASH.C"
|
|
|
|
+
|
|
|
|
+#define BRFS_RAM_STORAGE_ADDR 0x100000 // From 4th MiB
|
|
|
|
|
|
-#define BRFS_RAM_STORAGE_ADDR 0x600000
|
|
|
|
|
|
+// Addresses in SPI Flash
|
|
|
|
+// Note that each section should be in a different 4KiB sector in SPI Flash
|
|
|
|
+#define BRFS_SPIFLASH_SUPERBLOCK_ADDR 0xDF000 // One sector before FAT
|
|
|
|
+#define BRFS_SPIFLASH_FAT_ADDR 0xE0000 // Can be 32768 words (128KiB) for 32MiB of 256word blocks
|
|
|
|
+#define BRFS_SPIFLASH_BLOCK_ADDR 0x100000 // From first MiB
|
|
|
|
|
|
#define MAX_PATH_LENGTH 127
|
|
#define MAX_PATH_LENGTH 127
|
|
-#define MAX_OPEN_FILES 4 // Can be set higher, but 4 is good for testing
|
|
|
|
|
|
+#define MAX_OPEN_FILES 16 // Can be set higher, but 4 is good for testing
|
|
|
|
|
|
// Length of structs, should not be changed
|
|
// Length of structs, should not be changed
|
|
#define SUPERBLOCK_SIZE 16
|
|
#define SUPERBLOCK_SIZE 16
|
|
#define DIR_ENTRY_SIZE 8
|
|
#define DIR_ENTRY_SIZE 8
|
|
|
|
|
|
|
|
+#define BRFS_MAX_BLOCKS 65536 // 64KiB
|
|
|
|
+word brfs_changed_blocks[BRFS_MAX_BLOCKS >> 5]; // Bitmap of changed blocks, each block has 1 bit
|
|
|
|
+
|
|
// 16 words long
|
|
// 16 words long
|
|
struct brfs_superblock
|
|
struct brfs_superblock
|
|
{
|
|
{
|
|
word total_blocks;
|
|
word total_blocks;
|
|
- word bytes_per_block;
|
|
|
|
|
|
+ word words_per_block;
|
|
word label[10]; // 1 char per word
|
|
word label[10]; // 1 char per word
|
|
word brfs_version;
|
|
word brfs_version;
|
|
word reserved[3];
|
|
word reserved[3];
|
|
@@ -209,14 +239,14 @@ word brfs_get_fat_idx_of_dir(char* dir_path)
|
|
|
|
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
|
|
word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
// Split path by '/' and traverse directories
|
|
// Split path by '/' and traverse directories
|
|
char* token = strtok(dir_path_copy, "/");
|
|
char* token = strtok(dir_path_copy, "/");
|
|
while (token != (word*)-1)
|
|
while (token != (word*)-1)
|
|
{
|
|
{
|
|
// Find token in current directory
|
|
// Find token in current directory
|
|
- word* dir_addr = brfs_data_block_addr + (current_dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
|
|
+ word* dir_addr = brfs_data_block_addr + (current_dir_fat_idx * superblock->words_per_block);
|
|
word found_dir = 0; // Keep track if token is found in current directory
|
|
word found_dir = 0; // Keep track if token is found in current directory
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
@@ -348,16 +378,20 @@ void brfs_init_directory(word* dir_addr, word dir_entries_max, word dir_fat_idx,
|
|
|
|
|
|
// Set FAT table
|
|
// Set FAT table
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
|
|
|
|
+
|
|
|
|
+ // Set changed block
|
|
|
|
+ brfs_changed_blocks[dir_fat_idx >> 5] |= (1 << (dir_fat_idx & 31));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* Format the ram storage as a BRFS filesystem
|
|
* Format the ram storage as a BRFS filesystem
|
|
|
|
+ * Also writes the superblock to SPI Flash
|
|
* blocks: number of blocks in the filesystem
|
|
* blocks: number of blocks in the filesystem
|
|
- * bytes_per_block: number of bytes per block
|
|
|
|
|
|
+ * words_per_block: number of bytes per block
|
|
* label: label of the filesystem
|
|
* label: label of the filesystem
|
|
* full_format: if 1, initialize data section to 0
|
|
* full_format: if 1, initialize data section to 0
|
|
*/
|
|
*/
|
|
-void brfs_format(word blocks, word bytes_per_block, char* label, word full_format)
|
|
|
|
|
|
+void brfs_format(word blocks, word words_per_block, char* label, word full_format)
|
|
{
|
|
{
|
|
// Create a superblock
|
|
// Create a superblock
|
|
struct brfs_superblock superblock;
|
|
struct brfs_superblock superblock;
|
|
@@ -367,7 +401,7 @@ void brfs_format(word blocks, word bytes_per_block, char* label, word full_forma
|
|
|
|
|
|
// Set values of superblock
|
|
// Set values of superblock
|
|
superblock.total_blocks = blocks;
|
|
superblock.total_blocks = blocks;
|
|
- superblock.bytes_per_block = bytes_per_block;
|
|
|
|
|
|
+ superblock.words_per_block = words_per_block;
|
|
strcpy((char*)&superblock.label, label);
|
|
strcpy((char*)&superblock.label, label);
|
|
superblock.brfs_version = 1;
|
|
superblock.brfs_version = 1;
|
|
|
|
|
|
@@ -381,11 +415,11 @@ void brfs_format(word blocks, word bytes_per_block, char* label, word full_forma
|
|
// Create Data section
|
|
// Create Data section
|
|
if (full_format)
|
|
if (full_format)
|
|
{
|
|
{
|
|
- memset(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, 0, blocks * bytes_per_block);
|
|
|
|
|
|
+ memset(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, 0, blocks * words_per_block);
|
|
}
|
|
}
|
|
|
|
|
|
// Initialize root dir
|
|
// Initialize root dir
|
|
- word dir_entries_max = bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word dir_entries_max = words_per_block / sizeof(struct brfs_dir_entry);
|
|
brfs_init_directory(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
|
|
brfs_init_directory(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
|
|
|
|
|
|
// Clear open files and cursors
|
|
// Clear open files and cursors
|
|
@@ -397,6 +431,17 @@ void brfs_format(word blocks, word bytes_per_block, char* label, word full_forma
|
|
{
|
|
{
|
|
brfs_dir_entry_pointers[i] = 0;
|
|
brfs_dir_entry_pointers[i] = 0;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // For all blocks that have just been formatted, set changed block
|
|
|
|
+ word j;
|
|
|
|
+ for (j = 0; j < blocks; j++)
|
|
|
|
+ {
|
|
|
|
+ brfs_changed_blocks[j >> 5] |= (1 << (j & 31));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Write superblock to SPI Flash
|
|
|
|
+ spiflash_sector_erase(BRFS_SPIFLASH_SUPERBLOCK_ADDR);
|
|
|
|
+ spiflash_write_page_in_words((char*)&superblock, BRFS_SPIFLASH_SUPERBLOCK_ADDR, sizeof(superblock));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -430,8 +475,8 @@ word brfs_create_directory(char* parent_dir_path, char* dirname)
|
|
}
|
|
}
|
|
|
|
|
|
// Check if file or folder already exists
|
|
// Check if file or folder already exists
|
|
- word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block);
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
{
|
|
{
|
|
@@ -451,8 +496,8 @@ word brfs_create_directory(char* parent_dir_path, char* dirname)
|
|
|
|
|
|
// Find first free dir entry
|
|
// Find first free dir entry
|
|
word next_free_dir_entry = brfs_find_next_free_dir_entry(
|
|
word next_free_dir_entry = brfs_find_next_free_dir_entry(
|
|
- brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block),
|
|
|
|
- superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
|
|
|
|
|
|
+ brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block),
|
|
|
|
+ superblock->words_per_block / sizeof(struct brfs_dir_entry)
|
|
);
|
|
);
|
|
if (next_free_dir_entry == -1)
|
|
if (next_free_dir_entry == -1)
|
|
{
|
|
{
|
|
@@ -466,19 +511,22 @@ word brfs_create_directory(char* parent_dir_path, char* dirname)
|
|
|
|
|
|
// Copy dir entry to first free dir entry
|
|
// Copy dir entry to first free dir entry
|
|
memcpy(
|
|
memcpy(
|
|
- brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
|
|
|
|
|
|
+ brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
|
|
(char*)&new_entry,
|
|
(char*)&new_entry,
|
|
sizeof(new_entry)
|
|
sizeof(new_entry)
|
|
);
|
|
);
|
|
|
|
|
|
// Initialize directory
|
|
// Initialize directory
|
|
brfs_init_directory(
|
|
brfs_init_directory(
|
|
- brfs_data_block_addr + (next_free_block * superblock->bytes_per_block),
|
|
|
|
|
|
+ brfs_data_block_addr + (next_free_block * superblock->words_per_block),
|
|
dir_entries_max,
|
|
dir_entries_max,
|
|
next_free_block,
|
|
next_free_block,
|
|
parent_dir_fat_idx
|
|
parent_dir_fat_idx
|
|
);
|
|
);
|
|
|
|
|
|
|
|
+ // Update changed block
|
|
|
|
+ brfs_changed_blocks[next_free_block >> 5] |= (1 << (next_free_block & 31));
|
|
|
|
+
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -513,8 +561,8 @@ word brfs_create_file(char* parent_dir_path, char* filename)
|
|
}
|
|
}
|
|
|
|
|
|
// Check if file or folder already exists
|
|
// Check if file or folder already exists
|
|
- word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block);
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
{
|
|
{
|
|
@@ -534,8 +582,8 @@ word brfs_create_file(char* parent_dir_path, char* filename)
|
|
|
|
|
|
// Find first free dir entry
|
|
// Find first free dir entry
|
|
word next_free_dir_entry = brfs_find_next_free_dir_entry(
|
|
word next_free_dir_entry = brfs_find_next_free_dir_entry(
|
|
- brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block),
|
|
|
|
- superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
|
|
|
|
|
|
+ brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block),
|
|
|
|
+ superblock->words_per_block / sizeof(struct brfs_dir_entry)
|
|
);
|
|
);
|
|
if (next_free_dir_entry == -1)
|
|
if (next_free_dir_entry == -1)
|
|
{
|
|
{
|
|
@@ -549,21 +597,24 @@ word brfs_create_file(char* parent_dir_path, char* filename)
|
|
|
|
|
|
// Copy dir entry to first free dir entry
|
|
// Copy dir entry to first free dir entry
|
|
memcpy(
|
|
memcpy(
|
|
- brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
|
|
|
|
|
|
+ brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
|
|
(char*)&new_entry,
|
|
(char*)&new_entry,
|
|
sizeof(new_entry)
|
|
sizeof(new_entry)
|
|
);
|
|
);
|
|
|
|
|
|
// Initialize file by setting data to 0
|
|
// Initialize file by setting data to 0
|
|
memset(
|
|
memset(
|
|
- brfs_data_block_addr + (next_free_block * superblock->bytes_per_block),
|
|
|
|
|
|
+ brfs_data_block_addr + (next_free_block * superblock->words_per_block),
|
|
0,
|
|
0,
|
|
- superblock->bytes_per_block
|
|
|
|
|
|
+ superblock->words_per_block
|
|
);
|
|
);
|
|
|
|
|
|
// Update FAT
|
|
// Update FAT
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + next_free_block] = -1;
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + next_free_block] = -1;
|
|
|
|
|
|
|
|
+ // Update changed block
|
|
|
|
+ brfs_changed_blocks[next_free_block >> 5] |= (1 << (next_free_block & 31));
|
|
|
|
+
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -588,8 +639,8 @@ void brfs_list_directory(char* dir_path)
|
|
}
|
|
}
|
|
|
|
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
- word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
@@ -638,8 +689,8 @@ word brfs_open_file(char* file_path)
|
|
|
|
|
|
// Find file in directory
|
|
// Find file in directory
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
- word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
@@ -746,8 +797,8 @@ word brfs_delete_file(char* file_path)
|
|
|
|
|
|
// Find file in directory
|
|
// Find file in directory
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
- word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
@@ -781,11 +832,15 @@ word brfs_delete_file(char* file_path)
|
|
{
|
|
{
|
|
next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
|
|
next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = 0;
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = 0;
|
|
|
|
+ brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
|
|
current_fat_idx = next_fat_idx;
|
|
current_fat_idx = next_fat_idx;
|
|
}
|
|
}
|
|
|
|
|
|
// Delete file
|
|
// Delete file
|
|
memset((char*)dir_entry, 0, sizeof(struct brfs_dir_entry));
|
|
memset((char*)dir_entry, 0, sizeof(struct brfs_dir_entry));
|
|
|
|
+
|
|
|
|
+ // Update changed block
|
|
|
|
+ brfs_changed_blocks[dir_fat_idx >> 5] |= (1 << (dir_fat_idx & 31));
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -875,7 +930,7 @@ word brfs_get_fat_idx_at_cursor(word file_pointer, word cursor)
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
|
|
|
|
// Loop through FAT until cursor is reached
|
|
// Loop through FAT until cursor is reached
|
|
- while (cursor > superblock->bytes_per_block)
|
|
|
|
|
|
+ while (cursor > superblock->words_per_block)
|
|
{
|
|
{
|
|
current_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
|
|
current_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
|
|
if (current_fat_idx == -1)
|
|
if (current_fat_idx == -1)
|
|
@@ -883,7 +938,7 @@ word brfs_get_fat_idx_at_cursor(word file_pointer, word cursor)
|
|
uprintln("Cursor is out of bounds!");
|
|
uprintln("Cursor is out of bounds!");
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
- cursor -= superblock->bytes_per_block;
|
|
|
|
|
|
+ cursor -= superblock->words_per_block;
|
|
}
|
|
}
|
|
|
|
|
|
return current_fat_idx;
|
|
return current_fat_idx;
|
|
@@ -940,11 +995,11 @@ word brfs_read(word file_pointer, word* buffer, word length)
|
|
// - repeat until length is 0
|
|
// - repeat until length is 0
|
|
while (length > 0)
|
|
while (length > 0)
|
|
{
|
|
{
|
|
- word words_until_end_of_block = superblock->bytes_per_block - (MATH_modU(brfs_cursors[i], superblock->bytes_per_block));
|
|
|
|
|
|
+ word words_until_end_of_block = superblock->words_per_block - (MATH_modU(brfs_cursors[i], superblock->words_per_block));
|
|
word words_to_read = words_until_end_of_block > length ? length : words_until_end_of_block;
|
|
word words_to_read = words_until_end_of_block > length ? length : words_until_end_of_block;
|
|
|
|
|
|
// Copy words to buffer
|
|
// Copy words to buffer
|
|
- memcpy(buffer, data_block_addr + (current_fat_idx * superblock->bytes_per_block) + brfs_cursors[i], words_to_read);
|
|
|
|
|
|
+ memcpy(buffer, data_block_addr + (current_fat_idx * superblock->words_per_block) + brfs_cursors[i], words_to_read);
|
|
|
|
|
|
// Update cursor and length
|
|
// Update cursor and length
|
|
brfs_cursors[i] += words_to_read;
|
|
brfs_cursors[i] += words_to_read;
|
|
@@ -1014,12 +1069,15 @@ word brfs_write(word file_pointer, word* buffer, word length)
|
|
// - repeat until length is 0
|
|
// - repeat until length is 0
|
|
while (length > 0)
|
|
while (length > 0)
|
|
{
|
|
{
|
|
- word cursor_in_block = MATH_modU(brfs_cursors[i], superblock->bytes_per_block);
|
|
|
|
- word words_until_end_of_block = superblock->bytes_per_block - cursor_in_block;
|
|
|
|
|
|
+ word cursor_in_block = MATH_modU(brfs_cursors[i], superblock->words_per_block);
|
|
|
|
+ word words_until_end_of_block = superblock->words_per_block - cursor_in_block;
|
|
word words_to_write = words_until_end_of_block > length ? length : words_until_end_of_block;
|
|
word words_to_write = words_until_end_of_block > length ? length : words_until_end_of_block;
|
|
|
|
|
|
// Copy words to buffer
|
|
// Copy words to buffer
|
|
- memcpy(data_block_addr + (current_fat_idx * superblock->bytes_per_block) + cursor_in_block, buffer, words_to_write);
|
|
|
|
|
|
+ memcpy(data_block_addr + (current_fat_idx * superblock->words_per_block) + cursor_in_block, buffer, words_to_write);
|
|
|
|
+
|
|
|
|
+ // Update changed block
|
|
|
|
+ brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
|
|
|
|
|
|
// Update cursor and length
|
|
// Update cursor and length
|
|
brfs_cursors[i] += words_to_write;
|
|
brfs_cursors[i] += words_to_write;
|
|
@@ -1051,6 +1109,8 @@ word brfs_write(word file_pointer, word* buffer, word length)
|
|
current_fat_idx = next_free_block;
|
|
current_fat_idx = next_free_block;
|
|
// Set next block to -1 to indicate end of file
|
|
// Set next block to -1 to indicate end of file
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = -1;
|
|
brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = -1;
|
|
|
|
+ // Update changed block
|
|
|
|
+ brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1091,8 +1151,8 @@ struct brfs_dir_entry* brfs_stat(char* file_path)
|
|
|
|
|
|
// Find file in directory
|
|
// Find file in directory
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
- word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->bytes_per_block);
|
|
|
|
- word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
+ word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
|
|
|
|
+ word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
|
|
|
|
|
|
word i;
|
|
word i;
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
for (i = 0; i < dir_entries_max; i++)
|
|
@@ -1115,6 +1175,225 @@ struct brfs_dir_entry* brfs_stat(char* file_path)
|
|
return (struct brfs_dir_entry*)-1;
|
|
return (struct brfs_dir_entry*)-1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Check if a block has changed by comparing it to the flash, returns 1 if changed and 0 if not
|
|
|
|
+ * Note: this is slow and should eventually be replaced by a list of changed blocks
|
|
|
|
+ * block_idx: index of the block
|
|
|
|
+*/
|
|
|
|
+word brfs_check_block_changed(word block_idx)
|
|
|
|
+{
|
|
|
|
+ struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
|
|
+ word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
|
|
|
|
+
|
|
|
|
+ word spi_data_buffer[256];
|
|
|
|
+
|
|
|
|
+ if (superblock->words_per_block > 256)
|
|
|
|
+ {
|
|
|
|
+ uprintln("Error: words_per_block should be <= 256 for this function!");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Read block from flash, and enable bytes to word
|
|
|
|
+ spiflash_read_from_address(spi_data_buffer, BRFS_SPIFLASH_BLOCK_ADDR + block_idx * superblock->words_per_block, superblock->words_per_block, 1);
|
|
|
|
+
|
|
|
|
+ // Compare block to flash
|
|
|
|
+ return memcmp(data_block_addr + (block_idx * superblock->words_per_block), spi_data_buffer, superblock->words_per_block);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Write the FAT table to SPI flash by performing three steps:
|
|
|
|
+ * 1. Check which FAT entries have changed
|
|
|
|
+ * 2. Erase the 4KiB sectors that contain these FAT entries
|
|
|
|
+ * 3. Write each changed FAT entry to flash by using 16 page writes per sector
|
|
|
|
+*/
|
|
|
|
+void brfs_write_fat_to_flash()
|
|
|
|
+{
|
|
|
|
+ struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
|
|
+ word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
|
|
|
|
+
|
|
|
|
+ // 1 sector = 4KiB = 1024 words = 1024 FAT entries
|
|
|
|
+ // 1 word contains 32 flags for changed blocks/FAT entries
|
|
|
|
+ // 1024/32 = 32 words in the changed_blocks array per sector
|
|
|
|
+
|
|
|
|
+ uprintln("---Writing FAT to SPI Flash---");
|
|
|
|
+
|
|
|
|
+ // Loop over brfs_changed_blocks in 32 word parts
|
|
|
|
+ // Assumes length of brfs_changed_blocks is a multiple of 32
|
|
|
|
+ word i;
|
|
|
|
+ for (i = 0; i < sizeof(brfs_changed_blocks); i+=32)
|
|
|
|
+ {
|
|
|
|
+ // Check if any value within brfs_changed_blocks[i:i+32] is not 0
|
|
|
|
+ word j;
|
|
|
|
+ word changed = 0;
|
|
|
|
+ for (j = 0; j < 32; j++)
|
|
|
|
+ {
|
|
|
|
+ if (brfs_changed_blocks[i+j] != 0)
|
|
|
|
+ {
|
|
|
|
+ changed = 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (changed)
|
|
|
|
+ {
|
|
|
|
+ // Erase sector
|
|
|
|
+ word addr = BRFS_SPIFLASH_FAT_ADDR; // Workaround because of large static number
|
|
|
|
+ addr += (i >> 5) * 4096; // Sector idx * bytes per sector
|
|
|
|
+ spiflash_sector_erase(addr);
|
|
|
|
+ uprint("Erased sector ");
|
|
|
|
+ uprintDec(i >> 5);
|
|
|
|
+ uprint(" at address ");
|
|
|
|
+ uprintHex(addr);
|
|
|
|
+ uprintln("");
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // Write sector by writing 16 pages k of 64 words
|
|
|
|
+ // Does not check for boundaries of actual FAT table size,
|
|
|
|
+ // so it can write garbage if block size is not a multiple of 1024
|
|
|
|
+ word k;
|
|
|
|
+ for (k = 0; k < 1024; k+=64)
|
|
|
|
+ {
|
|
|
|
+ addr = BRFS_SPIFLASH_FAT_ADDR; // Workaround because of large static number
|
|
|
|
+ addr += (i >> 5) * 4096; // Sector idx * bytes per sector
|
|
|
|
+ addr += k << 2; // 64 words * 4 bytes per word
|
|
|
|
+
|
|
|
|
+ word* fat_addr_ram = brfs_ram_storage + SUPERBLOCK_SIZE + (i << 5) + k;
|
|
|
|
+ spiflash_write_page_in_words(fat_addr_ram, addr, 64);
|
|
|
|
+
|
|
|
|
+ uprint("Wrote FAT entries ");
|
|
|
|
+ uprintDec((i << 5) + k);
|
|
|
|
+ uprint(":");
|
|
|
|
+ uprintDec((i << 5) + k + 63);
|
|
|
|
+ uprint(" from RAM addr ");
|
|
|
|
+ uprintHex((word)fat_addr_ram);
|
|
|
|
+ uprint(" to SPI Flash addr ");
|
|
|
|
+ uprintHex(addr);
|
|
|
|
+ uprintln("");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ uprintln("---Finished writing FAT to SPI Flash---");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Write the data blocks to SPI flash by performing three steps:
|
|
|
|
+ * 1. Check which blocks have changed
|
|
|
|
+ * 2. Erase the 4KiB sectors that contain these blocks
|
|
|
|
+ * 3. Write each erased sector with the new block data by using 16 page writes per sector
|
|
|
|
+*/
|
|
|
|
+void brfs_write_blocks_to_flash()
|
|
|
|
+{
|
|
|
|
+ // Loop over all blocks
|
|
|
|
+ struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
|
|
|
|
+ word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
|
|
|
|
+
|
|
|
|
+ // Check if block size is <= 4KiB
|
|
|
|
+ if (superblock->words_per_block > 1024)
|
|
|
|
+ {
|
|
|
|
+ uprintln("Error: block size should be <= 4KiB");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Check if block size is a multiple of 64
|
|
|
|
+ if (superblock->words_per_block & 63)
|
|
|
|
+ {
|
|
|
|
+ uprintln("Error: block size should be a multiple of 64");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ uprintln("---Writing blocks to SPI Flash---");
|
|
|
|
+
|
|
|
|
+ word blocks_per_sector = MATH_divU(4096, superblock->words_per_block * 4);
|
|
|
|
+ uprint("Blocks per sector: ");
|
|
|
|
+ uprintDec(blocks_per_sector);
|
|
|
|
+ uprintln("");
|
|
|
|
+
|
|
|
|
+ // Erase 4KiB sectors that contain changed blocks
|
|
|
|
+ // This code is written such that it only erases each sector once, even if multiple blocks in the sector have changed
|
|
|
|
+ word i;
|
|
|
|
+ word sector_to_erase = -1;
|
|
|
|
+ for (i = 0; i < superblock->total_blocks; i++)
|
|
|
|
+ {
|
|
|
|
+ if (brfs_changed_blocks[i >> 5] & (1 << (i & 31)))
|
|
|
|
+ {
|
|
|
|
+ if (sector_to_erase == -1)
|
|
|
|
+ {
|
|
|
|
+ sector_to_erase = MATH_divU(i, blocks_per_sector);
|
|
|
|
+ }
|
|
|
|
+ else if (sector_to_erase != MATH_divU(i, blocks_per_sector))
|
|
|
|
+ {
|
|
|
|
+ word addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
|
|
|
|
+ addr += sector_to_erase * 4096;
|
|
|
|
+ spiflash_sector_erase(addr);
|
|
|
|
+ uprint("Erased sector ");
|
|
|
|
+ uprintDec(sector_to_erase);
|
|
|
|
+ uprint(" at address ");
|
|
|
|
+ uprintHex(addr);
|
|
|
|
+ uprintln("");
|
|
|
|
+
|
|
|
|
+ sector_to_erase = MATH_divU(i, blocks_per_sector);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (sector_to_erase != -1)
|
|
|
|
+ {
|
|
|
|
+ word addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
|
|
|
|
+ addr += sector_to_erase * 4096;
|
|
|
|
+ spiflash_sector_erase(addr);
|
|
|
|
+ uprint("Erased sector ");
|
|
|
|
+ uprintDec(sector_to_erase);
|
|
|
|
+ uprint(" at address ");
|
|
|
|
+ uprintHex(addr);
|
|
|
|
+ uprintln("");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Write each block to flash in parts of 64 words
|
|
|
|
+ for (i = 0; i < superblock->total_blocks; i++)
|
|
|
|
+ {
|
|
|
|
+ if (brfs_changed_blocks[i >> 5] & (1 << (i & 31)))
|
|
|
|
+ {
|
|
|
|
+ word j;
|
|
|
|
+ for (j = 0; j < superblock->words_per_block; j+=64)
|
|
|
|
+ {
|
|
|
|
+ word spiflash_addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
|
|
|
|
+ spiflash_addr += i * superblock->words_per_block + j;
|
|
|
|
+
|
|
|
|
+ word* data_addr = data_block_addr + (i * superblock->words_per_block) + j;
|
|
|
|
+ spiflash_write_page_in_words(data_addr, spiflash_addr, 64);
|
|
|
|
+
|
|
|
|
+ uprint("Wrote block ");
|
|
|
|
+ uprintDec(i);
|
|
|
|
+ uprint(" from RAM addr ");
|
|
|
|
+ uprintHex((word)data_addr);
|
|
|
|
+ uprint(" to SPI Flash addr ");
|
|
|
|
+ uprintHex(spiflash_addr);
|
|
|
|
+ uprintln("");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ uprintln("---Finished writing blocks to SPI Flash---");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void read_test()
|
|
|
|
+{
|
|
|
|
+ word read_buffer[1024];
|
|
|
|
+ memset(read_buffer, 0, 1024);
|
|
|
|
+ spiflash_read_from_address(&read_buffer[0], 0, 1024, 1);
|
|
|
|
+
|
|
|
|
+ word i;
|
|
|
|
+ for(i = 0; i < 1024; i+=128)
|
|
|
|
+ {
|
|
|
|
+ uprintHex(read_buffer[i]);
|
|
|
|
+ uprintc(' ');
|
|
|
|
+ }
|
|
|
|
+ uprintln("");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
int main()
|
|
int main()
|
|
{
|
|
{
|
|
@@ -1127,14 +1406,28 @@ int main()
|
|
uprintln("BRFS test implementation");
|
|
uprintln("BRFS test implementation");
|
|
uprintln("------------------------");
|
|
uprintln("------------------------");
|
|
|
|
|
|
- word blocks = 16;
|
|
|
|
- word bytes_per_block = 32;
|
|
|
|
|
|
+ spiflash_init();
|
|
|
|
+
|
|
|
|
+ // Small scale test values
|
|
|
|
+ //word blocks = 16;
|
|
|
|
+ //word words_per_block = 64; // 256 bytes per block
|
|
|
|
+ //word full_format = 1;
|
|
|
|
+
|
|
|
|
+ // Large scale test values for 4MiB
|
|
|
|
+ word blocks = 16; //4096; // 1KiB per block * 4096 = 4MiB
|
|
|
|
+ word words_per_block = 256; // 1KiB per block
|
|
word full_format = 1;
|
|
word full_format = 1;
|
|
|
|
|
|
- brfs_format(blocks, bytes_per_block, "Label", full_format);
|
|
|
|
- //brfs_list_directory("/");
|
|
|
|
- //brfs_dump(blocks, blocks*bytes_per_block);
|
|
|
|
- //uprintln("");
|
|
|
|
|
|
+ uprintln("Formatting BRFS filesystem...");
|
|
|
|
+ brfs_format(blocks, words_per_block, "SystemBRFS", full_format);
|
|
|
|
+ uprintln("BRFS filesystem formatted!");
|
|
|
|
+
|
|
|
|
+ brfs_dump(blocks, blocks*words_per_block);
|
|
|
|
+ brfs_write_fat_to_flash();
|
|
|
|
+ brfs_write_blocks_to_flash();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /* TEST CODE FOR SMALL SCALE TEST
|
|
|
|
|
|
// Create directories
|
|
// Create directories
|
|
if (!brfs_create_directory("/", "dir1"))
|
|
if (!brfs_create_directory("/", "dir1"))
|
|
@@ -1215,7 +1508,9 @@ int main()
|
|
|
|
|
|
brfs_list_directory("/");
|
|
brfs_list_directory("/");
|
|
brfs_list_directory("/dir1");
|
|
brfs_list_directory("/dir1");
|
|
- brfs_dump(blocks, blocks*bytes_per_block);
|
|
|
|
|
|
+ brfs_dump(blocks, blocks*words_per_block);
|
|
|
|
+
|
|
|
|
+ */
|
|
|
|
|
|
return 'q';
|
|
return 'q';
|
|
}
|
|
}
|