Where things are
Offsets are from the end of the file (a ROM is a power of two in size, so the end is the only fixed place). With the ROM end at CPU address 0xFFFFFFFF the addresses are those in the last column.
| From the end | Size | What | CPU address |
|---|---|---|---|
| −0x220 | 32 | the game header | 0xFFFFFDE0 |
| −0x200 | 512 | the vector table: 32 slots of 16 bytes | 0xFFFFFE00 |
| −0x10 | 16 | the reset vector, the last slot | 0xFFFFFFF0 |
The game header
| Offset | Size | Field | Meaning |
|---|---|---|---|
| +0x00 | 20 | Title | The game’s name in Shift-JIS (single-byte ASCII and half-width katakana, or two-byte characters), padded with spaces (or zeros). The viewer shows printable ASCII, a space for a zero pad and ? for other bytes, and flags a title that is not valid Shift-JIS (a two-byte character is a lead byte 0x81–0x9F or 0xE0–0xFC and a trail byte 0x40–0x7E or 0x80–0xFC). |
| +0x14 | 5 | Reserved | Five reserved bytes, zero. |
| +0x19 | 2 | Maker code | Two ASCII characters naming the publisher. |
| +0x1B | 4 | Game code | Four ASCII characters naming the game. |
| +0x1F | 1 | Version | The game’s version, written 1.<value> (a byte of 2 is version 1.2). |
This layout, the field sizes and the character sets are from the raw text of the Virtual Boy Sacred Tech Scroll (“Virtual Boy ROM Header”: 0xFFFFFDE0–0xFFFFFDF3 title, 0xFFFFFDF4–0xFFFFFDF8 reserved, 0xFFFFFDF9–0xFFFFFDFA maker, 0xFFFFFDFB–0xFFFFFDFE game code, 0xFFFFFDFF version), read from a Wayback Machine copy. The Scroll also says the significant data is at rom_size − 544 (0x220) and that a ROM is at least 1024 bytes and a power of two. Beetle VB/Mednafen does not read the header at all: it accepts any power-of-two size from 256 bytes to 16 MiB. No retail ROM was available to test against, so no real header was decoded.
The vector table
When an interrupt or an exception happens, the CPU saves the PC and PSW and jumps to a vector: a 16-byte slot that holds code, usually a JR to the real handler or a RETI. Interrupts use the slot for their level, 0xFFFFFE00 + 0x10 × level; the exceptions have fixed slots. The viewer labels each slot and shows the first instruction in it.
| From the end | CPU address | Label | What |
|---|---|---|---|
| −0x200 | 0xFFFFFE00 | VEC_GAMEPAD | Game pad interrupt (level 0) |
| −0x1F0 | 0xFFFFFE10 | VEC_TIMER_ZERO | Timer zero interrupt (level 1) |
| −0x1E0 | 0xFFFFFE20 | VEC_EXPANSION | Game pak expansion port interrupt (level 2) |
| −0x1D0 | 0xFFFFFE30 | VEC_LINK | Link (communication) port interrupt (level 3) |
| −0x1C0 | 0xFFFFFE40 | VEC_VIP | Video (VIP) interrupt (level 4) |
| −0xA0 | 0xFFFFFF60 | VEC_FPU_EXCEPTION | Floating-point exception |
| −0x80 | 0xFFFFFF80 | VEC_DIVIDE_BY_ZERO | Divide by zero |
| −0x70 | 0xFFFFFF90 | VEC_INVALID_OPCODE | Invalid opcode |
| −0x60 | 0xFFFFFFA0 | VEC_TRAP_0_15 | TRAP 0 to 15 |
| −0x50 | 0xFFFFFFB0 | VEC_TRAP_16_31 | TRAP 16 to 31 |
| −0x40 | 0xFFFFFFC0 | VEC_ADDRESS_TRAP | Address trap |
| −0x30 | 0xFFFFFFD0 | VEC_DUPLEXED_EXCEPTION | Duplexed (fatal) exception |
| −0x10 | 0xFFFFFFF0 | VEC_RESET | Reset: the CPU starts here. A JR (FF AB 10 FC in the emulators.org demo: JR 0xFFFFFC00) or a MOVHI/MOVEA pair and a JMP |
The interrupt vectors at levels 5 to 15 (0xFFFFFE50 to 0xFFFFFF50) and the other slots are shown as unused. The vector addresses agree with the Sacred Tech Scroll’s exception table and with the raw Beetle VB source (v810_oploop.inc: SetPC(0xFFFFFE00 | (iNum << 4)); v810_cpu.h: floating-point 0xFFFFFF60, zero divide 0xFFFFFF80, invalid opcode 0xFFFFFF90, TRAP 0xFFFFFFA0 + (n & 0x10); v810_cpu.cpp: double exception 0xFFFFFFD0, reset PC 0xFFFFFFF0; vb.h: levels input 0, timer 1, expansion 2, comm 3, VIP 4). Two vectors are 32 bytes long in the Scroll, not 16: the floating-point handler (0xFFFFFF60–0xFFFFFF7F, shared by all floating-point exceptions) and the duplexed-exception/NMI handler (0xFFFFFFD0–0xFFFFFFEF; the NMI is unused on the Virtual Boy). The maskable interrupt vectors are the game pad, timer zero, cartridge, link and VIP; an interrupt’s level is the second-least-significant nibble of its exception code (0xFE40 is level 4). The address trap slot (0xFFFFFFC0) is in the Scroll but Mednafen does not use it.
Not described
See the overview: no retail ROM header has been decoded, and the maker-code values are not listed.