1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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
|