News: 11 March 2016 - Forum Rules

Author Topic: Converting SNES and NES addresses to PC address  (Read 4865 times)

FCandChill

  • Hero Member
  • *****
  • Posts: 591
    • View Profile
Converting SNES and NES addresses to PC address
« on: September 17, 2018, 10:18:57 pm »
Hi all... I'm working on a flexible script editor and manager. Right now, I found code to convert LoROM addresses to computer addresses. However, I'd like some leads (code libraries and/or documentation) on how to convert other address formats (HiROM, ExLoROM, EXHiROM). I recall from another discussion that the NES has its own formats, which depends on the mapper as well. Also ... I recall converting FDS addresses to be easy.

darkmoon2321

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: Converting SNES and NES addresses to PC address
« Reply #1 on: September 17, 2018, 11:39:00 pm »
For HiROM, the simple code I used to convert SNES addresses to ROM position recently was:

Code: [Select]
uint32_t convertAddress(uint32_t & addr){
if(addr&0x400000){
addr &= 0x3FFFFF;
}
else{
addr = (addr&0x8000)? addr&0x3FFFFF : 0;
}
return addr;
}

In the case were bit 22 and bit 15 of the 24 bit pointer are both clear, you end up in a situation where the program counter could point to RAM, SRAM, or to various hardware registers.  For the code I was working on (disassembler), I could not use such addresses without fully emulating the game, so I simply set the address to 0 and checked for that condition elsewhere in my code. Here's a resource for SNES memory mapping for more information:

https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map


For the game I was working on, I checked for and manually stripped the header prior to loading the ROM into memory, but if you want to keep track of it like in the example you linked, you could just add 0x200 to the final address if a header boolean is set.  You also want to compare the address to the file size to ensure you don't attempt to read faulty data or get a segmentation fault.  In my case I didn't bother to check for 0x7E0000 to 0x7FFFFF range (WRAM) as this would have already returned a value outside the file size, but if you are working on a general purpose tool you should check for it.

Here's information on the NES memory map:
https://wiki.nesdev.com/w/index.php/CPU_memory_map

On the NES there is also the additional complication of bank switching.  Which banks can be swapped out and size of the swappable regions depends on the mapper.  On some mappers, there may be multiple banks of the memory map that can be swapped out individually.  It is possible for a game to load the same part of the ROM to different parts of a memory map, which means that the same region in ROM may have more than one possible PC address.

Disch

  • Hero Member
  • *****
  • Posts: 2814
  • NES Junkie
    • View Profile
Re: Converting SNES and NES addresses to PC address
« Reply #2 on: September 18, 2018, 01:35:34 am »
I recall from another discussion that the NES has its own formats, which depends on the mapper as well.

NES Mappers have so much variety that you can't really add "nes support", you'd have to support individual mappers (though there's a lot of overlap between different mappers).  Supporting the ~8 most common mappers will get you coverage of like ~80% of the NES library, but there are a TON (read: over a hundred) of weird/obscure mappers that were only used in like one or two games.  But again -- if you're just doing address translations, there's a lot of overlap.

It's also worth noting that converting file offset to CPU address is MUCH simpler than vice versa, since it's a many-to-one relationship.


The easiest NES mappers (like #2, #7) have only one swapping mode and only one swappable region.  Mapper 7, for instance, puts a single 32K block in the $8000-FFFF region.  So converting offset to CPU address is as simple as masking out the low 15 bits and ORing with $8000:

Code: [Select]
cpu_addr = ((offset-0x10) & 0x7FFF) | 0x8000;    // minus 0x10 for the header


Mapper #2 is also pretty easy, with the very last 16K block of PRG-ROM being fixed at $C000-FFFF, and every other bank being swapped into $8000-BFFF region:
Code: [Select]
if( offset_is_in_last_16K_of_ROM )
    cpu_addr = ((offset-0x10) & 0x3FFF) | 0xC000;
else
    cpu_addr = ((offset-0x10) & 0x3FFF) | 0x8000;


... other mappers, though....

Mapper #1 is more complicated.  While it only has one swappable region, it has multiple swapping MODES.  Meaning MOST of the time it operates like mapper #2.  But sometimes it operates like mapper #7.  But it also might do things a weird 3rd way (which honestly I've never seen a game use it's 3rd mode so maybe you don't have to worry about it so much unless you're a perfectionist).

And technically, which mode it uses can change at runtime, but in practice no game would ever do that.  Reliably figuring out WHICH mode any game uses is probably going to be extremely difficult, and I can't think of a good way to do it.  :(


.... and that's not the worst of it.  The most common mapper, #4, not only has multiple swapping modes, but also has multiple swapping regions.  So even if you know what mode the game uses, you have to figure out which page of PRG is going to be swapped into which region.  The first 8K in the ROM might map to the $8000-9FFF range... OR it might map to the $A000-BFFF range -- and there isn't really any way to know.


So... yeah.  Doing this on the NES is going to be a nightmare.  SNES and FDS are much easier.

Quote
Also ... I recall converting FDS addresses to be easy.

Yeah FDS is pretty straight forward.  FDS disks actually have a file system, and each file it contains has a header indicating its size and where it memory it is to be loaded.  So all you really have to do is find/read that header.

KingMike

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 7183
  • *sigh* A changed avatar. Big deal.
    • View Profile
Re: Converting SNES and NES addresses to PC address
« Reply #3 on: September 18, 2018, 12:32:26 pm »
But on the FDS, you would have to know the filename to find the file, I believe.
Which you can't know without already hacking the game.

There is a value in the disk's header which says how many files are on the disk side, but it's better to just ignore that since some games will pull the simple copy-protection trick of including additional files (which I think need to be store sequentially on the disk?) after the "last" file.
"My watch says 30 chickens" Google, 2018

FCandChill

  • Hero Member
  • *****
  • Posts: 591
    • View Profile
Re: Converting SNES and NES addresses to PC address
« Reply #4 on: September 18, 2018, 08:14:57 pm »
Thanks everyone! Yeah ... the NES is too conditional to convert. So I'll just support the two mapper you showed me, Disch. :)

Now that I think about it, I made an editor for the Nakayama Miho's Tokimeki High School FDS game that successfully read and repointed dialogue ... but I used a trick due to laziness. I would read the pointer and then added or subtract a predetermined value. This value was the difference between the FDS pointer and the PC pointer that I figured out somehow. For example, for the pointers at 0x917B, I would convert the pointers to integers and then add 0x28B9. To convert the PC address back into a FDS address I would subtract that value.

Hacky? Yes... But it might just be the best solution to have flexible program.

As for me saying that converting FDS pointers was easy, I believe I was thinking of this:

Can you find the dialogue in RAM (using the hex editor in FCEUX to search RAM while running)?
Or using a program, such one I wrote ;) (I think I called it FDS Builder) to split the FDS image into files, the pointer can be found by finding the offset within the split file and adding it to the file's RAM offset (which would be listed in a contents file generated by the program).

Also...

The RAM address in that screenshot should be C088. So, C088 should be the pointer value.

You can't easily convert from offset in a .FDS file because an FDS game is an image with several files inside. Files get loaded to RAM (which is where the games are run from), and so the pointer depends on WHERE in RAM that data gets loaded to (that RAM address is in the file header, if you can find the header in the .FDS).
I'm not 100% but it SEEMS that files in an FDS image are stored sequentially and they seem to always have filenames (8 characters) in ASCII (at least the games I have looked at). If I recall, the header format was: a 0x03 flag, 8-character file name, file size and RAM offset (2 bytes each, maybe not that order), then 1 byte indicating destination RAM (PRG-RAM, CHR-RAM or PPU), then a 0x04 flag then the file data.
Without using a tool to rip a file list from the FDS, you'd have to scan through the file to look for ASCII text (for the filenames) and do math using the file size data to find where the files are. Or use the FCEUX hex editor to find the RAM offsets to find pointer values and then do a hex search to find those.

Is that FDS builder program open source? I did find the Nori's document you used as a reference to make the program.

Psyklax

  • Hero Member
  • *****
  • Posts: 1112
    • View Profile
    • Psyklax Translations
Re: Converting SNES and NES addresses to PC address
« Reply #5 on: September 20, 2018, 02:11:18 am »
I know I should probably say nothing because I feel I'm not contributing to the thread, but...

Is there a great need for a tool to convert addresses? I use OpenOffice Calc to put all my addresses in a column, then use a simple formula to convert them all. Combined with a little program my dad made to list every address where a particular byte is found, plus Textpad, and everything is pretty straightforward. Sure, I haven't done much work on the SNES so perhaps there's some tricky stuff with the HiROM LoROM business, but I don't recall anything too taxing.

Also, the terminology confuses me: "PC addresses"? In this context I think of Program Counter, how does an address connect with a Wintel computer? I would think ROM address or file address is more appropriate.

Again, apologies if it looks like I'm just being negative in the thread. I just had some questions on my mind. :)

mziab

  • Sr. Member
  • ****
  • Posts: 321
    • View Profile
    • mteam
Re: Converting SNES and NES addresses to PC address
« Reply #6 on: September 20, 2018, 06:00:54 am »
For converting SNES addresses back and forth there's always Lunar Address. As a bonus, it detects which kind of mapping a ROM uses and whether or not it has a header, allowing to avoid some confusion.

Then again, once you've done this romhacking thing long enough, you can do most of the math in your head. HiROM is dead simple to do actually. Most of the time you take the ROM offset and add 0xC0 to the bank (or 0xC00000 to the whole address) and substract the header if you have one.

To convert a HiROM address to a ROM offset just do the reverse (add the header if necessary, then substract). Alternatively, you can use binary AND to mask off the two top-most bits of the address like so: "address & 0x3FFFFF" and then adjust for the header if needed.

LoROM is a bit trickier, since banks are half the size and the address within the bank is always in the 8000-FFFF range, so there's more math involved.
« Last Edit: September 20, 2018, 06:07:26 am by mziab »

KingMike

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 7183
  • *sigh* A changed avatar. Big deal.
    • View Profile
Re: Converting SNES and NES addresses to PC address
« Reply #7 on: September 20, 2018, 12:46:21 pm »
Also, the terminology confuses me: "PC addresses"? In this context I think of Program Counter, how does an address connect with a Wintel computer? I would think ROM address or file address is more appropriate.
The address of the instruction the (emulated) CPU is executing. Program Counter is the standard term, we're not talking about a Windows PC or whatever.
It is not the same as file address (well, for most consoles. For Genesis it does only because the console maps the ROM linearly at 0.
"My watch says 30 chickens" Google, 2018