Nice work!
AFAICS, the first 0x120 bytes of the ROM contain some kind of table, with each entry occupying 32 bytes.
Code:
0x00000 5A04 0000 E10A 0000 E00A 0000 2001 0000
0x00010 D00C 0100 D00C 0100 010A 0000 0000 0019
0x00020 0101 0000 C968 0000 C868 0000 010C 0000
0x00030 0000 0000 FFFF FFFF 010A 0000 A882 00A1
0x00040 0201 0000 C944 0000 C844 0000 CA74 0000
0x00050 B082 0000 FFFF FFFF 010A 0000 9C62 0091
...
0x00100 0801 0000 D960 0000 D860 0000 CCEB 0100
0x00110 009A E2FF 0000 0000 010A 0000 6C7B 009F
Each entry appears to point to a block of code or data.
For example, the first entry suggests that there is a block at 0x0120 of length 0x0AE0 bytes.
The next entry points to a block at 0x0C01 of length 0x68C8.
Block #1: 0x0120 + 0x0AE0 = 0x0C00
Block #2: 0x0C01 + 0x68C8 = 0x74C9
Block #3: 0x74CA + 0x44C8 = 0xB992
Block #4: 0xB993 + 0x0784 = 0xC117
Block #5: 0xC118 + 0x01D4 = 0xC2EC
Block #6: 0xC2ED + 0x048C = 0xC779
Block #7: 0xC77A + 0x159C = 0xDD16
Block #8: 0xDD17 + 0x010EB4 = 0x01EBCB
Block #9: 0x01EBCC + 0x60D8 = 0x024CA4
The last block ends at 0x024CA4, after which the ROM is filled with 0xFF bytes until offset 0x02C000. The block from 0x02C000 to 0x02C8CB appears to contain data rather than code.
Offsets 0x02C8CC through 0x02F89A once again contain 0xFF bytes. The point at which you noticed the difference (0x02F8A7) is the first CRC byte of ROM module 0x0D. You can see the firmware version (12.01C01).
Each ROM module begins with a "ROYL" header. If we use this as our guide, then the ROM MODs are as follows:
MOD 0x0D, location 0x2F89B - 0x2F8E0, length 0x01 sectors, 0x46 bytes
MOD 0x47, location 0x2F8E1 - 0x2FAE0, length 0x01 sectors, 0x200 bytes
MOD 0x30, location 0x2FAE1 - 0x2FEE0, length 0x02 sectors, 0x400 bytes
MOD 0x0B, location 0x2FEE1 - 0x2FFB1, length 0x01 sectors, 0xD1 bytes
MOD 0x0A, location 0x2FFB2 - 0x2FFEF, length 0x01 sectors, 0x3E bytes
If we now examine the contents of ROM MOD 0B (directory of ROM MOds), then the structure becomes clear.
Code:
12 01 0A 00 3E 00 00 19 00 00 B2 FF 02 00 00 00 00 00
12 01 0B 00 D1 00 00 19 00 00 E1 FE 02 00 00 00 00 00
12 01 30 00 00 04 00 19 00 00 E1 FA 02 00 00 00 00 00
12 01 47 00 00 02 00 19 00 00 E1 F8 02 00 00 00 00 00
12 01 0D 00 46 00 00 19 00 00 9B F8 02 00 00 00 00 00
12 01 00 00 00 00 00 19 00 00 00 00 00 00 00 00 00 00
We can recognise the MOD ID, size in bytes, and starting offset.
I suspect that the leading 0x12 is the size of each table entry (18 bytes).
I would also hazard a guess that the 0x01 bytes indicate that these are ROM MODs, whereas a value of 0x02 would denote SA MODs.
The sixth MOD entry appears empty. Coincidentally (?) I notice that MOD 4F referred to in the Salvation Data article is not present.