diff --git a/include/joybus/common/n64_pak_fs.h b/include/joybus/common/n64_pak_fs.h index db7bd42..65516c8 100644 --- a/include/joybus/common/n64_pak_fs.h +++ b/include/joybus/common/n64_pak_fs.h @@ -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. diff --git a/src/n64_pak_fs.c b/src/n64_pak_fs.c index 90fa104..932750b 100644 --- a/src/n64_pak_fs.c +++ b/src/n64_pak_fs.c @@ -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); @@ -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); diff --git a/test/test_n64_pak_fs.c b/test/test_n64_pak_fs.c index c7d1921..c55b4d1 100644 --- a/test/test_n64_pak_fs.c +++ b/test/test_n64_pak_fs.c @@ -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);