Difference between revisions of "ROM Addressing"
(Created page with "There are several different ways to refer to data in memory in Zelda II. Which one you use depends on your reasoning for doing so. This page will explain where they're useful...") |
|||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
There are several different ways to refer to data in memory in Zelda II. Which one you use depends on your reasoning for doing so. This page will explain where they're useful and how to translate between them. | There are several different ways to refer to data in memory in Zelda II. Which one you use depends on your reasoning for doing so. This page will explain where they're useful and how to translate between them. | ||
− | = | + | =ROM File= |
− | ==CPU | + | NES ROM files are in a format generally called iNES. Most ROMs (including Zelda 2 ROMs) are in [https://wiki.nesdev.com/w/index.php/INES iNES 1.0 format]. The layout of a Zelda II ROM file is as follows (an [https://wiki.nesdev.com/w/index.php/MMC1 MMC1] cartridge with 8 PRG ROM banks, 16 CHR-ROM banks, and 4KB of SRAM -- for more details see [https://datacrystal.romhacking.net/wiki/Zelda_II:_The_Adventure_of_Link Data Crystal]): |
+ | |||
+ | {| class="wikitable" | ||
+ | !Type | ||
+ | !Number | ||
+ | !File Offset | ||
+ | !Size | ||
+ | !Contents | ||
+ | |- | ||
+ | |iNES Header | ||
+ | | | ||
+ | |0x00000 | ||
+ | |16bytes (0x10) | ||
+ | |- | ||
+ | |PRG Bank | ||
+ | |[[PRG Bank 0|0]] | ||
+ | |0x00010 | ||
+ | |16KB (0x4000) | ||
+ | | | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 1|1]] | ||
+ | |0x04010 | ||
+ | |16KB (0x4000) | ||
+ | |[[Western Hyrule]] | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 2|2]] | ||
+ | |0x08010 | ||
+ | |16KB (0x4000) | ||
+ | |[[Eastern Hyrule]] | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 3|3]] | ||
+ | |0x0C010 | ||
+ | |16KB (0x4000) | ||
+ | |[[Towns]](?) | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 4|4]] | ||
+ | |0x10010 | ||
+ | |16KB (0x4000) | ||
+ | |[[Normal Palaces]] | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 5|5]] | ||
+ | |0x14010 | ||
+ | |16KB (0x4000) | ||
+ | |[[Great Palace]] | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 6|6]] | ||
+ | |0x18010 | ||
+ | |16KB (0x4000) | ||
+ | |[[Music]](?) | ||
+ | |- | ||
+ | | | ||
+ | |[[PRG Bank 7|7]] | ||
+ | |0x1C010 | ||
+ | |16KB (0x4000) | ||
+ | |Global State (permanently mapped) | ||
+ | |- | ||
+ | |CHR Bank | ||
+ | |[[CHR Bank 0|0]] | ||
+ | |0x20000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 1|1]] | ||
+ | |0x22000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 2|2]] | ||
+ | |0x24000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 3|3]] | ||
+ | |0x26000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 4|4]] | ||
+ | |0x28000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 5|5]] | ||
+ | |0x2a000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 6|6]] | ||
+ | |0x2c000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 7|7]] | ||
+ | |0x2e000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 8|8]] | ||
+ | |0x30000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 9|9]] | ||
+ | |0x32000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 10|10]] | ||
+ | |0x34000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 11|11]] | ||
+ | |0x36000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 12|12]] | ||
+ | |0x38000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 13|13]] | ||
+ | |0x3a000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 14|14]] | ||
+ | |0x3c000 | ||
+ | |8KB (0x2000) | ||
+ | |- | ||
+ | | | ||
+ | |[[CHR Bank 15|15]] | ||
+ | |0x3e000 | ||
+ | |8KB (0x2000) | ||
+ | |} | ||
+ | |||
+ | ==Bank Offsets== | ||
+ | |||
+ | Given an offset into a dumped ROM, you can find out what bank it's in by dividing the offset by 0x4000 and subtracting the size of the iNES header (0x10 or 16 bytes). For example: | ||
+ | |||
+ | 0x15244/0x4000-0x10=5 | ||
+ | |||
+ | And then you can use the remainder (or modulus) to get the offset within that bank: | ||
+ | |||
+ | 0x15244%0x4000-0x10=0x1234 | ||
+ | |||
+ | From there you can determine the memory address it would be mapped into memory at, if you want, by figuring out where that bank would be mapped (for banks 0-6, they will be mapped at 0x8000 and for bank 7 they will be mapped at 0xc000): | ||
+ | |||
+ | 0x8000+0x1234=0x9234 | ||
+ | |||
+ | For a bit more clarity on how that works, see the next section. | ||
+ | |||
+ | =Memory= | ||
+ | |||
+ | ==CPU Memory Map== | ||
+ | |||
+ | When the game is running, the 16bit address space on the NES is mapped out roughly like so from the [https://wiki.nesdev.com/w/index.php/CPU_memory_map CPU's perspective]: | ||
+ | |||
+ | {| class="wikitable" | ||
+ | !Offset | ||
+ | !Size | ||
+ | !Area | ||
+ | |- | ||
+ | |0x0000||0x800||RAM | ||
+ | |- | ||
+ | |0x2000||0x2020||Hardware Registers | ||
+ | |- | ||
+ | |0x6000||0x2000||Cartridge SRAM | ||
+ | |- | ||
+ | |0x8000||0x4000||Low PRG Bank (swappable) | ||
+ | |- | ||
+ | |0xC000||0x4000||Upper PRG Bank (fixed to bank 7) | ||
+ | |} | ||
+ | |||
+ | This memory map, which is dictated by the way the MMC1 memory mapper maps memory, means that the area of memory between 0x8000 and 0xC000 is switchable. Addresses in this range can refer to any of the 8 PRG banks in the ROM (though in practice, will only ever refer to the first 7). Addresses above 0xC000, however, will *always* map to the last bank ([[PRG Bank 7]]). | ||
==Bank And Offset== | ==Bank And Offset== | ||
− | =ROM | + | In order to describe a part of the cartridge's ROM, you can refer to it in terms of its bank number and offset within that bank. An address described this way could look like this: |
+ | |||
+ | 5:0x1234 (or bank 5, offset 0x1234) | ||
+ | |||
+ | This allows for pretty easy conversion to other addressing styles. In order to get the offset into a dumped ROM, you can use the following formula: 0x10+(bank*0x4000)+offset. The above address would be found at 0x15244. | ||
+ | |||
+ | This is a pretty rarely used way to refer to locations, but is useful to understand anyways. You can always recognize this address format by the fact that it includes a bank number and another number that is less than 0x4000. | ||
+ | |||
+ | ==Bank And Memory Address== | ||
+ | |||
+ | More convenient for working with addresses in memory, this representation is used a lot by emulator debugging interfaces in particular. As in [[#Bank And Offset]], an address in this format starts with a bank number, but the second number is its address as mapped into RAM at runtime. So, for example, the above address would be: | ||
+ | |||
+ | 5:0x9234 (bank 5, memory address 0x9234) | ||
+ | |||
+ | For Zelda II, all addresses in banks 0 through 6 will be represented as within the range 0x8000-0xBFFF in this format, while addresses in bank 7 will be in the range 0xC000-0xFFFF: | ||
+ | |||
+ | 7:0xD234 (bank 7, memory address 0xd234) | ||
+ | |||
+ | Unfortunately, this format is more complicated to convert into ROM file offsets, or vice versa, because you have to know more about how the game maps memory. For Zelda II in particular, the formula for converting to a dumped ROM offset is 0x10+(bank*0x4000)+(address%0x4000) -- where % is modulus (or remainder). |
Latest revision as of 07:25, 15 April 2021
There are several different ways to refer to data in memory in Zelda II. Which one you use depends on your reasoning for doing so. This page will explain where they're useful and how to translate between them.
Contents
ROM File
NES ROM files are in a format generally called iNES. Most ROMs (including Zelda 2 ROMs) are in iNES 1.0 format. The layout of a Zelda II ROM file is as follows (an MMC1 cartridge with 8 PRG ROM banks, 16 CHR-ROM banks, and 4KB of SRAM -- for more details see Data Crystal):
Type | Number | File Offset | Size | Contents |
---|---|---|---|---|
iNES Header | 0x00000 | 16bytes (0x10) | ||
PRG Bank | 0 | 0x00010 | 16KB (0x4000) | |
1 | 0x04010 | 16KB (0x4000) | Western Hyrule | |
2 | 0x08010 | 16KB (0x4000) | Eastern Hyrule | |
3 | 0x0C010 | 16KB (0x4000) | Towns(?) | |
4 | 0x10010 | 16KB (0x4000) | Normal Palaces | |
5 | 0x14010 | 16KB (0x4000) | Great Palace | |
6 | 0x18010 | 16KB (0x4000) | Music(?) | |
7 | 0x1C010 | 16KB (0x4000) | Global State (permanently mapped) | |
CHR Bank | 0 | 0x20000 | 8KB (0x2000) | |
1 | 0x22000 | 8KB (0x2000) | ||
2 | 0x24000 | 8KB (0x2000) | ||
3 | 0x26000 | 8KB (0x2000) | ||
4 | 0x28000 | 8KB (0x2000) | ||
5 | 0x2a000 | 8KB (0x2000) | ||
6 | 0x2c000 | 8KB (0x2000) | ||
7 | 0x2e000 | 8KB (0x2000) | ||
8 | 0x30000 | 8KB (0x2000) | ||
9 | 0x32000 | 8KB (0x2000) | ||
10 | 0x34000 | 8KB (0x2000) | ||
11 | 0x36000 | 8KB (0x2000) | ||
12 | 0x38000 | 8KB (0x2000) | ||
13 | 0x3a000 | 8KB (0x2000) | ||
14 | 0x3c000 | 8KB (0x2000) | ||
15 | 0x3e000 | 8KB (0x2000) |
Bank Offsets
Given an offset into a dumped ROM, you can find out what bank it's in by dividing the offset by 0x4000 and subtracting the size of the iNES header (0x10 or 16 bytes). For example:
0x15244/0x4000-0x10=5
And then you can use the remainder (or modulus) to get the offset within that bank:
0x15244%0x4000-0x10=0x1234
From there you can determine the memory address it would be mapped into memory at, if you want, by figuring out where that bank would be mapped (for banks 0-6, they will be mapped at 0x8000 and for bank 7 they will be mapped at 0xc000):
0x8000+0x1234=0x9234
For a bit more clarity on how that works, see the next section.
Memory
CPU Memory Map
When the game is running, the 16bit address space on the NES is mapped out roughly like so from the CPU's perspective:
Offset | Size | Area |
---|---|---|
0x0000 | 0x800 | RAM |
0x2000 | 0x2020 | Hardware Registers |
0x6000 | 0x2000 | Cartridge SRAM |
0x8000 | 0x4000 | Low PRG Bank (swappable) |
0xC000 | 0x4000 | Upper PRG Bank (fixed to bank 7) |
This memory map, which is dictated by the way the MMC1 memory mapper maps memory, means that the area of memory between 0x8000 and 0xC000 is switchable. Addresses in this range can refer to any of the 8 PRG banks in the ROM (though in practice, will only ever refer to the first 7). Addresses above 0xC000, however, will *always* map to the last bank (PRG Bank 7).
Bank And Offset
In order to describe a part of the cartridge's ROM, you can refer to it in terms of its bank number and offset within that bank. An address described this way could look like this:
5:0x1234 (or bank 5, offset 0x1234)
This allows for pretty easy conversion to other addressing styles. In order to get the offset into a dumped ROM, you can use the following formula: 0x10+(bank*0x4000)+offset. The above address would be found at 0x15244.
This is a pretty rarely used way to refer to locations, but is useful to understand anyways. You can always recognize this address format by the fact that it includes a bank number and another number that is less than 0x4000.
Bank And Memory Address
More convenient for working with addresses in memory, this representation is used a lot by emulator debugging interfaces in particular. As in #Bank And Offset, an address in this format starts with a bank number, but the second number is its address as mapped into RAM at runtime. So, for example, the above address would be:
5:0x9234 (bank 5, memory address 0x9234)
For Zelda II, all addresses in banks 0 through 6 will be represented as within the range 0x8000-0xBFFF in this format, while addresses in bank 7 will be in the range 0xC000-0xFFFF:
7:0xD234 (bank 7, memory address 0xd234)
Unfortunately, this format is more complicated to convert into ROM file offsets, or vice versa, because you have to know more about how the game maps memory. For Zelda II in particular, the formula for converting to a dumped ROM offset is 0x10+(bank*0x4000)+(address%0x4000) -- where % is modulus (or remainder).