1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
// We need 64 * 32 bytes (2K) of SRAM for file indexes. To avoid corruption
// issues we ignore the first file (32 bytes).
// Note that the filename should include the null terminator if we want to use
// strcmp.
#define FILE_NAME_SIZE 27
#define FILE_CAPACITY 63
#define FILE_HEADER_OFFSET 2
#define FILE_INDEX_OFFSET 32
#define FILE_DATA_OFFSET KB(2)
#define FILE_MAX_SIZE KB(1)
#define SRAM ((vu8*)(MEM_CART))
typedef struct File {
char name[FILE_NAME_SIZE + 1];
u16 size;
u16 mem_offset; // NOTE: Unused...
} File;
// The filesystem header.
typedef struct FileSystem {
u16 num_files;
u16 data_size; // NOTE: Unused...
u16 data_capacity; // NOTE: Unused...
File files[FILE_CAPACITY];
} FileSystem;
static FileSystem filesystem;
void
_fs_read(u8 *dst, size_t pos, size_t n_bytes) {
for (size_t i = 0; i < n_bytes; ++i) {
dst[i] = SRAM[pos + i];
}
}
void
_fs_write(u8 *src, size_t pos, size_t n_bytes) {
for (size_t i = 0; i < n_bytes; ++i) {
SRAM[pos + i] = src[i];
}
}
void
fs_init() {
// Load header if existing.
_fs_read(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));
if (filesystem.num_files == 0xFFFF
&& filesystem.data_capacity == 0xFFFF
&& filesystem.data_size == 0xFFFF) {
filesystem.num_files = 0;
filesystem.data_size = 0;
filesystem.data_capacity = 27 * FILE_MAX_SIZE;
memset(&filesystem.files, 0, FILE_CAPACITY * sizeof(File));
_fs_write(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));
} else {
_fs_read(&filesystem.files, FILE_INDEX_OFFSET, sizeof(File) * filesystem.num_files);
}
}
int
fs_open_file(char *name) {
// Try to find an existing file.
for (size_t i = 0; i < filesystem.num_files; ++i) {
// TODO: Replace strcmp with vectorized fixed size char comparison.
if (strcmp(name, filesystem.files[i].name) == 0) {
return i;
}
}
// Create a new file if there is space.
if (filesystem.num_files < FILE_CAPACITY) {
size_t index = filesystem.num_files++;
size_t k = 0;
while(*name) {
filesystem.files[index].name[k++] = *name++;
}
filesystem.files[index].size = 0;
filesystem.files[index].mem_offset = 0;
// Update file index.
_fs_write(&filesystem.files[index],
FILE_INDEX_OFFSET + index * sizeof(File),
sizeof(File));
// Update header.
_fs_write(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));
return index;
}
return -1;
}
int
fs_write(u8 *src, size_t n_bytes, u16 file_index, u16 offset, bool append) {
File *file = &filesystem.files[file_index];
// Check if there is enough capacity for this write operation.
if (offset + n_bytes >= FILE_MAX_SIZE) {
return -1;
}
// Write data to file block.
_fs_write(src, FILE_DATA_OFFSET + FILE_MAX_SIZE * file_index + offset, n_bytes);
// Update file index.
if (append) {
if (offset + n_bytes > file->size) {
file->size = offset + n_bytes;
}
} else {
file->size = offset + n_bytes;
}
_fs_write(file, FILE_INDEX_OFFSET + file_index * sizeof(File), sizeof(File));
// Update header.
_fs_write(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));
return n_bytes;
}
|