Quellcode durchsuchen

Added file and dir creation to BRFS.

bart vor 8 Monaten
Ursprung
Commit
6b31f51206
6 geänderte Dateien mit 264 neuen und 20 gelöschten Zeilen
  1. 2 1
      .gitignore
  2. 0 0
      BCC/compileBareMetal.sh
  3. 199 17
      BCC/userBDOS/BRFS.C
  4. 61 0
      BCC/userBDOS/LIB/STDLIB.C
  5. 1 1
      Programmer/flash.py
  6. 1 1
      Programmer/uartFlasher.py

+ 2 - 1
.gitignore

@@ -36,4 +36,5 @@ BCC/*.tmp
 BCC/*.out
 BCC/bcc
 Programmer/code.list
-Programmer/code.bin
+Programmer/code.bin
+.vscode/

+ 0 - 0
BCC/compileAndSend.sh → BCC/compileBareMetal.sh


+ 199 - 17
BCC/userBDOS/BRFS.C

@@ -3,9 +3,10 @@
 /*
 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
+- SPI NOR Flash provides around the same amount of storage, with very little wear
+    - Very fast reads in QSPI mode
+    - However, writes are extremely slow and need to be performed in pages of 256 bytes (64 words)
+- FPGC has 64MiB RAM, which is a lot even for 32 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
@@ -31,25 +32,42 @@ Implementation Details:
   - (3)  reserved
 
 8 word Dir entries:
-  - (4) filename.ext [4 chars per word]
+  - (4) filename.ext [4 chars per word -> 16 chars total]
   - (1) modify date [to be implemented when RTC]
-  - (1) flags [max 32 flags, TBD]
+  - (1) flags [max 32 flags, from right to left: directory, hidden]
   - (1) 1st FAT idx
   - (1) file size [in words, not bytes]
 */
 
+/*
+Required operations:
+- Format
+- Create directory
+- Create file
+- Open file (allow multiple files open at once)
+- Close file (update dir entry and check/update all FAT entries)
+- Set cursor
+- Get cursor
+- Read file
+- Write file
+- Delete entire file (deleting part of file is not a thing)
+- Change directory
+*/
+
 #define word char
 
 #include "LIB/MATH.C"
 #include "LIB/SYS.C"
 #include "LIB/STDLIB.C"
 
-#define BRFS_RAM_STORAGE_ADDR 0x500000
+#define BRFS_RAM_STORAGE_ADDR 0x600000
 
 #define SUPERBLOCK_SIZE 16
 
 word *brfs_ram_storage = (word*) BRFS_RAM_STORAGE_ADDR; // RAM storage of file system
 
+word brfs_current_dir = 0; // Current directory index, points to block in data section
+
 // 16 words long
 struct brfs_superblock
 {
@@ -60,16 +78,86 @@ struct brfs_superblock
   word reserved[3];
 };
 
-// 16 words long
+// 8 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 flags;             // 32 flags, from right to left: directory, hidden 
   word fat_idx;           // idx of first FAT block
   word filesize;          // file size in words, not bytes
 };
 
+word brfs_find_next_free_block(word* fat_addr, word blocks)
+{
+  word i = 0;
+  word* fat_ptr = fat_addr;
+
+  while (i < blocks)
+  {
+    if (*fat_ptr == 0)
+    {
+      return i;
+    }
+
+    fat_ptr++;
+    i++;
+  }
+
+  return -1;
+}
+
+word brfs_find_next_free_dir_entry(word* dir_addr, word dir_entries_max)
+{
+  word i = 0;
+  word* dir_ptr = dir_addr;
+
+  while (i < dir_entries_max)
+  {
+    if (*dir_ptr == 0)
+    {
+      return i;
+    }
+
+    dir_ptr += sizeof(struct brfs_dir_entry);
+    i++;
+  }
+
+  return -1;
+}
+
+void brfs_create_single_dir_entry(struct brfs_dir_entry* dir_entry, char* filename, word fat_idx, word filesize, word flags)
+{
+  // Initialize to 0
+  memset(dir_entry, 0, sizeof(*dir_entry));
+
+  // Set filename
+  char compressed_filename[4] = {0,0,0,0};
+  strcompress(compressed_filename, filename);
+  memcpy(&(dir_entry->filename), compressed_filename, sizeof(compressed_filename));
+
+  // Set other fields
+  dir_entry->fat_idx = fat_idx;
+  dir_entry->flags = flags;
+  dir_entry->filesize = filesize;
+}
+
+void brfs_init_directory(word* dir_addr, word dir_entries_max, word dir_fat_idx, word parent_fat_idx)
+{
+  // Create . entry
+  struct brfs_dir_entry dir_entry;
+  brfs_create_single_dir_entry(&dir_entry, ".", dir_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
+  // Copy to first data entry
+  memcpy(dir_addr, &dir_entry, sizeof(dir_entry));
+
+  // Create .. entry
+  brfs_create_single_dir_entry(&dir_entry, "..", parent_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
+  // Copy to second data entry
+  memcpy(dir_addr+sizeof(dir_entry), &dir_entry, sizeof(dir_entry));
+
+  // Set FAT table
+  brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
+}
 
 // Creates hexdump like dump
 void brfs_dump_section(word* addr, word len, word linesize)
@@ -115,7 +203,7 @@ void brfs_dump(word* ram_addr, word fatsize, word datasize)
 
   // Datablock dump
   uprintln("\nData:");
-  brfs_dump_section(ram_addr+SUPERBLOCK_SIZE+fatsize, datasize, 16);
+  brfs_dump_section(ram_addr+SUPERBLOCK_SIZE+fatsize, datasize, 32);
 
   uprintc('\n');
 }
@@ -147,16 +235,106 @@ void brfs_format(word* ram_addr, word blocks, word bytes_per_block, char* label,
     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 root dir
+  word dir_entries_max = bytes_per_block / sizeof(struct brfs_dir_entry);
+  brfs_init_directory(ram_addr + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
 
-  // Initialize to 0
-  memset(&root_dir, 0, sizeof(root_dir));
+  brfs_current_dir = 0;
+}
 
-  // Copy root dir entry to first block
-  memcpy(ram_addr + SUPERBLOCK_SIZE + blocks, &root_dir, sizeof(root_dir));
+/*
+* Creates directory in current directory
+*/
+void brfs_create_directory(word* ram_addr, char* dirname)
+{
+  struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
 
-  
+  // Find first free FAT block
+  word next_free_block = brfs_find_next_free_block(ram_addr + SUPERBLOCK_SIZE, superblock->total_blocks);
+  if (next_free_block == -1)
+  {
+    uprintln("No free blocks left!");
+    return;
+  }
+
+  // Find first free dir entry
+  word next_free_dir_entry = brfs_find_next_free_dir_entry(
+    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block), 
+    superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
+  );
+  if (next_free_dir_entry == -1)
+  {
+    uprintln("No free dir entries left!");
+    return;
+  }
+
+  // Create dir entry
+  struct brfs_dir_entry new_entry;
+  brfs_create_single_dir_entry(&new_entry, dirname, next_free_block, 0, 1);
+
+  // Copy dir entry to first free dir entry
+  memcpy(
+    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
+    &new_entry,
+    sizeof(new_entry)
+  );
+
+  // Initialize directory
+  word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
+  brfs_init_directory(
+    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (next_free_block * superblock->bytes_per_block),
+    dir_entries_max,
+    next_free_block,
+    brfs_current_dir
+  );
+}
+
+/*
+* Creates an empty file in current directory
+*/
+void brfs_create_file(word* ram_addr, char* filename)
+{
+  struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
+
+  // Find first free FAT block
+  word next_free_block = brfs_find_next_free_block(ram_addr + SUPERBLOCK_SIZE, superblock->total_blocks);
+  if (next_free_block == -1)
+  {
+    uprintln("No free blocks left!");
+    return;
+  }
+
+  // Find first free dir entry
+  word next_free_dir_entry = brfs_find_next_free_dir_entry(
+    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block), 
+    superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
+  );
+  if (next_free_dir_entry == -1)
+  {
+    uprintln("No free dir entries left!");
+    return;
+  }
+
+  // Create file entry
+  struct brfs_dir_entry new_entry;
+  brfs_create_single_dir_entry(&new_entry, filename, next_free_block, 0, 0);
+
+  // Copy dir entry to first free dir entry
+  memcpy(
+    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
+    &new_entry,
+    sizeof(new_entry)
+  );
+
+  // Initialize file by setting data to 0
+  memset(
+    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (next_free_block * superblock->bytes_per_block),
+    0,
+    superblock->bytes_per_block
+  );
+
+  // Update FAT
+  ram_addr[SUPERBLOCK_SIZE + next_free_block] = -1;
 }
 
 
@@ -172,11 +350,15 @@ int main()
   uprintln("------------------------");
 
   word blocks = 8;
-  word bytes_per_block = 16;
+  word bytes_per_block = 32;
   word full_format = 1;
 
   brfs_format(brfs_ram_storage, blocks, bytes_per_block, "Label", full_format);
 
+  brfs_create_file(brfs_ram_storage, "file1");
+
+  brfs_create_directory(brfs_ram_storage, "dir1");
+
   brfs_dump(brfs_ram_storage, blocks, blocks*bytes_per_block);
 
   return 'q';

+ 61 - 0
BCC/userBDOS/LIB/STDLIB.C

@@ -193,6 +193,67 @@ char* strchr (const char *s, char c)
   return 0;
 }
 
+/*
+Compress a string made of one char per word, into a string made of one char per byte.
+*/
+void strcompress(word* dest, char* src)
+{
+  word i_src = 0;
+  word i_dst = 0;
+  word byte_offset = 0;
+  word c = src[i_src];
+
+  while (c != 0)
+  {
+    dest[i_dst] |= (c << byte_offset);
+
+    if (byte_offset == 24)
+    {
+      byte_offset = 0;
+      i_dst++;
+      dest[i_dst] = 0;
+    }
+    else
+    {
+      byte_offset += 8;
+    }
+
+    i_src++;
+    c = src[i_src];
+  }
+}
+
+/*
+Decompress a string made of one char per byte, into a string made of one char per word.
+*/
+void strdecompress(char* dest, word* src)
+{
+  word i_src = 0;
+  word i_dst = 0;
+  word byte_offset = 0;
+
+  while (1)
+  {
+    word c = (src[i_src] >> byte_offset) & 0xFF;
+    if (c == 0)
+      break;
+
+    dest[i_dst++] = c;
+
+    if (byte_offset == 24)
+    {
+      byte_offset = 0;
+      i_src++;
+    }
+    else
+    {
+      byte_offset += 8;
+    }
+  }
+
+  // Terminate
+  dest[i_dst] = 0;
+}
 
 /*
 Recursive helper function for itoa

+ 1 - 1
Programmer/flash.py

@@ -18,7 +18,7 @@ PAGESIZE = 256
 
 parser = argparse.ArgumentParser(description='Interface to FPGC SPI Flash Programmer')
 
-parser.add_argument('-d', dest='device', default='/dev/ttyUSB1',
+parser.add_argument('-d', dest='device', default='/dev/ttyUSB0',
                     help='serial port to communicate with')
 
 parser.add_argument('-i', dest='input', default='code.bin',

+ 1 - 1
Programmer/uartFlasher.py

@@ -28,7 +28,7 @@ if len(sys.argv) > 1:
     if (sys.argv[1] == "testMode"):
         testReturnMode = True
 
-port = serial.Serial("/dev/ttyUSB1", baudrate=1000000, timeout=None)
+port = serial.Serial("/dev/ttyUSB0", baudrate=1000000, timeout=None)
 
 sleep(0.3) # give the FPGC time to reset, even though it also works without this delay