Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion include/joybus/common/n64_pak_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,26 @@
/// The most banks whose system area fits in the first bank
#define JOYBUS_N64_PAK_FS_MAX_BANKS 62

/// Page of the first bank holding the four ID copies
#define JOYBUS_N64_PAK_FS_ID_PAGE 0

/// Page of the first bank holding a bank's inode table
#define JOYBUS_N64_PAK_FS_INODE_PAGE(bank) (1 + (bank))

/// Page of the first bank holding the mirror of a bank's inode table, for a given bank count
#define JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(banks, bank) (1 + (banks) + (bank))

/// First page of the note table in the first bank, for a given bank count
#define JOYBUS_N64_PAK_FS_NOTE_TABLE_PAGE(banks) (1 + 2 * (banks))

/// Number of pages the note table takes
#define JOYBUS_N64_PAK_FS_NOTE_TABLE_PAGES 2

/// Number of system pages in the first bank for a given bank count
#define JOYBUS_N64_PAK_FS_SYSTEM_PAGES(banks) (3 + 2 * (banks))
#define JOYBUS_N64_PAK_FS_SYSTEM_PAGES(banks) (JOYBUS_N64_PAK_FS_NOTE_TABLE_PAGE(banks) + JOYBUS_N64_PAK_FS_NOTE_TABLE_PAGES)

/// First page of a bank the filesystem allocates, for a given bank count. Page 0 of every later bank is reserved
#define JOYBUS_N64_PAK_FS_FIRST_DATA_PAGE(banks, bank) ((bank) == 0 ? JOYBUS_N64_PAK_FS_SYSTEM_PAGES(banks) : 1)

/**
* Check whether a block address in the first bank holds a copy of the ID.
Expand Down
18 changes: 12 additions & 6 deletions src/n64_pak_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static void build_id(uint8_t id[ID_SIZE], uint8_t banks, uint32_t random)
static void inode_page(uint8_t *page, uint8_t bank, uint8_t banks)
{
// Bank 0's data starts after the system area, later banks' after a reserved first page
size_t first = bank == 0 ? JOYBUS_N64_PAK_FS_SYSTEM_PAGES(banks) : 1;
size_t first = JOYBUS_N64_PAK_FS_FIRST_DATA_PAGE(banks, bank);

// Mark every data page free
memset(page, 0, JOYBUS_N64_PAK_FS_PAGE_SIZE);
Expand Down Expand Up @@ -148,16 +148,22 @@ int joybus_n64_pak_fs_format_page(uint8_t page[JOYBUS_N64_PAK_FS_PAGE_SIZE], uin
if (banks == 0 || banks > JOYBUS_N64_PAK_FS_MAX_BANKS || index >= JOYBUS_N64_PAK_FS_SYSTEM_PAGES(banks))
return -JOYBUS_ERR_INVALID_ARG;

// One inode page per bank from page 1, then a mirror of each
if (index >= 1 && index <= 2 * banks) {
inode_page(page, (index - 1) % banks, banks);
// One inode page per bank, then a mirror of each
if (index >= JOYBUS_N64_PAK_FS_INODE_PAGE(0) && index < JOYBUS_N64_PAK_FS_INODE_PAGE(banks)) {
inode_page(page, index - JOYBUS_N64_PAK_FS_INODE_PAGE(0), banks);
return 0;
}

// Page 0 and the note table are empty, apart from the ID copies in page 0
if (index >= JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(banks, 0) &&
index < JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(banks, banks)) {
inode_page(page, index - JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(banks, 0), banks);
return 0;
}

// The ID page and the note table are empty, apart from the ID copies
memset(page, 0, JOYBUS_N64_PAK_FS_PAGE_SIZE);

if (index == 0) {
if (index == JOYBUS_N64_PAK_FS_ID_PAGE) {
uint8_t id[ID_SIZE];
build_id(id, banks, random);

Expand Down
28 changes: 28 additions & 0 deletions test/test_n64_pak_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,38 @@ static void test_format_page_ids_valid_by_block()
TEST_ASSERT_EQUAL(4, copies);
}

// Test that the layout macros name the pages the format writes, for sixteen banks and for one
static void test_layout_pages()
{
TEST_ASSERT_EQUAL(0, JOYBUS_N64_PAK_FS_ID_PAGE);
TEST_ASSERT_EQUAL(1, JOYBUS_N64_PAK_FS_INODE_PAGE(0));
TEST_ASSERT_EQUAL(16, JOYBUS_N64_PAK_FS_INODE_PAGE(15));
TEST_ASSERT_EQUAL(17, JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(16, 0));
TEST_ASSERT_EQUAL(32, JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(16, 15));
TEST_ASSERT_EQUAL(33, JOYBUS_N64_PAK_FS_NOTE_TABLE_PAGE(16));
TEST_ASSERT_EQUAL(35, JOYBUS_N64_PAK_FS_SYSTEM_PAGES(16));
TEST_ASSERT_EQUAL(35, JOYBUS_N64_PAK_FS_FIRST_DATA_PAGE(16, 0));
TEST_ASSERT_EQUAL(1, JOYBUS_N64_PAK_FS_FIRST_DATA_PAGE(16, 5));

TEST_ASSERT_EQUAL(2, JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(1, 0));
TEST_ASSERT_EQUAL(3, JOYBUS_N64_PAK_FS_NOTE_TABLE_PAGE(1));
TEST_ASSERT_EQUAL(5, JOYBUS_N64_PAK_FS_SYSTEM_PAGES(1));
TEST_ASSERT_EQUAL(5, JOYBUS_N64_PAK_FS_FIRST_DATA_PAGE(1, 0));

// Every mirror page matches its inode page once formatted
joybus_n64_pak_fs_format(bank0, 16, 0);
for (int bank = 0; bank < 16; bank++) {
TEST_ASSERT_EQUAL_MEMORY(&bank0[JOYBUS_N64_PAK_FS_INODE_PAGE(bank) * 256],
&bank0[JOYBUS_N64_PAK_FS_INODE_MIRROR_PAGE(16, bank) * 256], 256);
}
}

int main(int argc, char **argv)
{
UNITY_BEGIN();

RUN_TEST(test_layout_pages);

RUN_TEST(test_id_valid);
RUN_TEST(test_format_page_rejects_out_of_range);
RUN_TEST(test_format_page_ids_valid_by_block);
Expand Down
Loading