From ea72e87e92a85b42a828af4bb345b156fea7e820 Mon Sep 17 00:00:00 2001 From: Tharo <17233964+Thar0@users.noreply.github.com> Date: Sat, 23 Mar 2024 17:06:00 +0000 Subject: [PATCH] Rework rom_header.s (#1932) * Rework rom_header.s * Offset comments, spaces in libultra version * Adjust some comments, remove value arg from checksum macro --- src/makerom/rom_header.h | 145 +++++++++++++++++++++++++++++++++++++++ src/makerom/rom_header.s | 31 ++++----- 2 files changed, 159 insertions(+), 17 deletions(-) create mode 100644 src/makerom/rom_header.h diff --git a/src/makerom/rom_header.h b/src/makerom/rom_header.h new file mode 100644 index 0000000000..1069ae86fe --- /dev/null +++ b/src/makerom/rom_header.h @@ -0,0 +1,145 @@ +#ifndef ROM_HEADER_H +#define ROM_HEADER_H + +/* Storage medium IDs, used internally in MEDIUM below */ + +#define STORAGE_MEDIUM_CARTRIDGE "N" +#define STORAGE_MEDIUM_CARTRIDGE_EXPANDABLE "C" +#define STORAGE_MEDIUM_DISK "D" +#define STORAGE_MEDIUM_DISK_EXPANSION "E" + +/* Region IDs, used internally in REGION below */ + +#define REGION_CODE_ALL "A" +#define REGION_CODE_JP "J" +#define REGION_CODE_US "E" +#define REGION_CODE_PAL "P" +#define REGION_CODE_GATEWAY "G" +#define REGION_CODE_LODGENET "L" + +/** + * Magic value to determine if the ROM is byteswapped. + * + * This is not totally reliable since the PI Domain 1 Latency could also hold this value, however generally it can be + * assumed that this is not the case. + */ +#define ENDIAN_IDENTIFIER \ + .byte 0x80 + +/** + * Configures the timings for PI Domain 1. This determines how fast the PI hardware will read from the ROM. IPL2 reads + * this configuration using the slowest possible configuration before switching to the provided configuration. + */ +#define PI_DOMAIN_1_CFG(lat, pwd, pgs, rls) \ + .byte (((rls) & 3) << 4) | ((pgs) & 0xF); \ + .byte (pwd) & 0xFF; \ + .byte (lat) & 0xFF + +/** + * Some older libultra versions use this field to set osClockRate. It does not have any other meaningful effect, the + * clock rate of physical units does not actually change to match this value. + */ +#define SYSTEM_CLOCK_RATE_SETTING(num) \ + .word (num) + +/** + * Indicates the entrypoint address of the program that IPL3 will load the boot segment to and execute. + * This should be >= 0x80000400. + */ +#define ENTRYPOINT(sym) \ + .word (sym) + +/** + * Indicates the hardware revision the program is designed for (hw_major, hw_minor) + * and what libultra version (os_ver) it uses. + * + * The hardware revision for a retail N64 is (2,0). + * The libultra version may be a single letter, without quotes. + */ +#define LIBULTRA_VERSION(hw_major, hw_minor, os_ver) \ + .half 0; \ + .byte (hw_major) * 10 + (hw_minor); \ + _os_ver_start = .; \ + .ascii #os_ver ; \ + .if (. - _os_ver_start) != 1; \ + .error "OS version should be just one letter"; \ + .endif + +/** + * Leaves space to insert the ROM Checksum value. IPL3 computes a checksum over ROM data in the range 0x1000 to 0x101000 + * and compares it to this value, if the results differ it will refuse to boot the program. + * + * This macro just writes 8 bytes of 0. The correct checksum value is filled in after the full ROM image is available to + * compute the checksum with. + */ +#define CHECKSUM() \ + .word 0, 0 + +/** + * For unused header space. Fills num bytes with 0. + */ +#define PADDING(num) \ + .fill (num) + +/** + * Defines the ROM name. This should be a string that is at most 20 characters long, a null terminator is not required. + * If a name is less than 20 characters, the remaining space will be padded with spaces. + */ +#define ROM_NAME(name) \ + _name_start = .; \ + .ascii name; \ + .if (. - _name_start) > 20; \ + .error "ROM name too long, must be at most 20 characters"; \ + .endif; \ + .if (. - _name_start) < 20; \ + .fill 20 - (. - _name_start), 1, 0x20; \ + .endif + +/** + * Identifies the storage medium the program intends to use. + * + * Should be one of: + * - CARTRIDGE + * - CARTRIDGE_EXPANDABLE + * - DISK + * - DISK_EXPANSION + */ +#define MEDIUM(type) \ + .ascii STORAGE_MEDIUM_##type + +/** + * Two-letter game identifier. Should be wrapped in quotes. + */ +#define GAME_ID(id) \ + _game_id_start = .; \ + .ascii id ; \ + .if (. - _game_id_start) != 2; \ + .error "Game ID should be two letters"; \ + .endif + +/** + * Identifies the region the game is made for. + * + * Should be one of: + * - ALL + * - JP + * - US + * - PAL + * - GATEWAY + * - LODGENET + * + * Note: Often flashcarts and emulators will read this value to determine whether to act as an NTSC or PAL system and + * will adjust the VI timings appropriately, which may be used to determine target FPS. + * This can lead to glitchy video output on hardware if the program configures a video mode other than the native + * video mode for the hardware version. + */ +#define REGION(name) \ + .ascii REGION_CODE_##name + +/** + * Identifies the game revision number. Can be between 0 and 255. + */ +#define GAME_REVISION(num) \ + .byte (num) + +#endif diff --git a/src/makerom/rom_header.s b/src/makerom/rom_header.s index 883b8b0ab8..ec243cc9cb 100644 --- a/src/makerom/rom_header.s +++ b/src/makerom/rom_header.s @@ -1,18 +1,15 @@ -/* - * The Legend of Zelda: Ocarina of Time ROM header - */ +#include "rom_header.h" -.byte 0x80, 0x37, 0x12, 0x40 /* PI BSD Domain 1 register */ -.word 0x0000000F /* Clockrate setting */ -.word 0x80000400 /* Entrypoint function (`entrypoint`) */ -.word 0x0000144C /* Revision */ -.word 0x917D18F6 /* Checksum 1 */ -.word 0x69BC5453 /* Checksum 2 */ -.word 0x00000000 /* Unknown */ -.word 0x00000000 /* Unknown */ -.ascii "THE LEGEND OF ZELDA " /* Internal ROM name */ -.word 0x00000000 /* Unknown */ -.word 0x0000004E /* Cartridge */ -.ascii "ZL" /* Cartridge ID */ -.ascii "P" /* Region */ -.byte 0x0F /* Version */ +/* 0x00 */ ENDIAN_IDENTIFIER +/* 0x01 */ PI_DOMAIN_1_CFG(64, 18, 7, 3) +/* 0x04 */ SYSTEM_CLOCK_RATE_SETTING(0xF) +/* 0x08 */ ENTRYPOINT(0x80000400) +/* 0x0C */ LIBULTRA_VERSION(2, 0, L) +/* 0x10 */ CHECKSUM() +/* 0x18 */ PADDING(8) +/* 0x20 */ ROM_NAME("THE LEGEND OF ZELDA") +/* 0x34 */ PADDING(7) +/* 0x3B */ MEDIUM(CARTRIDGE) +/* 0x3C */ GAME_ID("ZL") +/* 0x3E */ REGION(PAL) +/* 0x3F */ GAME_REVISION(15)