11 March 2016 - Forum Rules
Started by Pennywise, December 21, 2014, 02:25:17 PM
QuoteThe MadHacker once said that "NES rom expansion is so difficult and time consuming that you might as well think of it as impossible."That was in a time when information was scarce and emulators weren't really any good. The fact is that NES Expansion isn't that complicated despite the myriad of different mappers that do things their own way. The goal of this document is to shed light on the technical details of ROM expansion and to share some common techniques that can be used to utilize the new space.NES Hardware BasicsPRG-ROM and CHR-ROMMost NES games have two ROMs inside a cartridge. The first ROM is PRG-ROM and the second is CHR-ROM. They stand for Program and Character respectively with the first usually containing all the code and data and the second containing the graphics. When we say ROM expansion, we are usually referring to the PRG-ROM. The PRG-ROM is split up into different sections of equal size in what are known as ROM banks. The bank size varies depending on the game and mapper. For example, the bank size is usually either 8kb or 16kb. You can find this information out by using the emulator FCEUX. Just go to Help -> Message Log.The 6502 CPU Memory MapThe NES accesses the PRG-ROM by loading ROM banks into a specific address area of the CPU memory map. The banks are loaded into the address range of $8000-FFFF. This makes for a total size of 32kb the NES can access of the PRG-ROM at a time.It's story time. Once upon a time when the NES first came out, PRG-ROM sizes were only 32kb, the maximum size the NES could access at a time. This worked fine until developers said, "32kb is way too small for me to fit my game into. I want to make bigger and more complex games. I need a bigger ROM." So Nintendo developed mappers, which is what you could call fancy boards, that usually handled ROM sizes of 128kb, 256kb and 512kb. Now the NES can only handle 32kb at a time, so these mappers could "swap" banks in and out as needed, thus being able to access the entire ROM, just not at once. Take this diagram to better picture it.Game that uses 8kb banks+---------------------------------------------------------------+| 1 | 2 | 3 | <4> |+-------------------------------+-------------------------------+Game that uses 16kb banks+---------------------------------------------------------------+| 1 | <2> |+-------------------------------+-------------------------------+Picture that the NES CPU has slots and pretend that banks from the ROM go in there. Then mix and match however you want and that's how the NES accesses the PRG-ROM in a nutshell. But there's one very important piece of information you need to know. The very last bank in the PRG-ROM is what you would call the "fixed bank" or "hard-wired bank". It's always loaded into the the last ROM bank slot in the CPU and can never be changed or moved. The <> is there just to denote the difference.How to determine NES ROM expansion limitsTechnically speaking, the NES could supports ROMs that were 10MB in size, but there isn't a board or mapper that hasn't been designed to support such a size yet. When we talk about ROM size limits, we are referring to the maximum size a game can be that was designed for a particular board or mapper. Maximum ROM sizes are determined from the number of PRG bits a board/mapper that sets the number of ROM banks available. This is all technical mumbo jumbo that's not really necessary to explain because NESDev has an excellent wiki that just lists the max ROM size for all the NES mappers.Question: Let's say I have a ROM that I expanded to 256kb, but the mapper/board can only support 128kb. Is that even possible?Answer: There are two sides to the coin for this. If you wanted to play your translation on a real NES, the original board used wouldn't be able to support the ROM. However, it becomes a moot point when you factor in that flashcarts could play the expanded ROM fine. You can consider a flashcart a sort of all-in-one mapper that can handle any game size which usually maxes out at 512kb. The NES doesn't care about ROM sizes and that's the important thing to remember. A good example is the Hebreke translation that expanded the ROM which the original mapper/board couldn't support, but that a flashcart could play fine.How does the NES "swap" banksFirst off, ROM banks are numbered starting from #$00 and going up the hex scale. You take the bank number and you write them to the PRG register which is something that basically tells the NES to do the bank swap. This is what the code looks like to swap banks.LDA #$01STA $8000Translating this code into English would be something like load the bank #$01 and write it to the PRG register. Think of it like if I write #$01 o $8000 then bank 1 will go into the first PRG slot in the CPU.That is generally how the NES swaps banks, but the register value is just a made up example and will vary by game and mapper. The mapper MMC1 does its bank swaps a little different and is not the same as the above example.How to expand an NES ROMWell, that's actually quite simple. KingMike made a simple program called nflate that can expand your ROM for you in a jiff. Every once in a while there will be special cases where a ROM won't work properly after expansion and you'd need to troubleshoot it and expand the ROM manually. But the vast majority of games work fine after expansion. Expanding the ROM is the easy part, but utilizing the expanded space is where things get tricky.How to use the expanded spaceIn the scope of translation hacking, the goal of ROM expansion is to increase the amount of space you have available so you can fit all the translated text back in without cutting it down. Let's say you have an entire bank of text. There's no way in hell you can fit that all back in the original space. Maybe if you compressed it, but that's a different subject. So what you do is split the text between two different ROM banks effectively doubling the space you have available.Question: How does one split the text between banks?Answer: I use two different methods to accomplish this. To keep things simple, we'll only talk about one.First off, you need to code a new routine that contains our bank swap code. The new code requires space in the ROM and most games usually have free space at the end of the fixed bank. That's where we put our code.Question: But what if there's no free space in the fixed bank?Answer: TBDSo what you do is JSR from the game's text pointer load routine. Your common game's text pointer load routine will look something like this:LDA $8000,YSTA $0000LDA $8001,YSTA $0001Y is the index that selects which pointer from the table to load. Here's a simple breakdown of the pointer table addresses:$8000 = 0$8002 = 1$8004 = 2$8006 = 3$8008 = 4$800A = 5The numbers on the right are what Y needs to be in order to load a particular text pointer.Let's say we want to we want the text to be in another bank for string 5. Let's also assume that the PRG-ROM was 128kb and we expanded it to 256kb. The game uses 16kb banks, which with 128kb total, that makes for 8 banks. So the banks for the expanded space are going to start at #$09 and up. So here's what we do;Load first pointer byteLDA $8000,Y;Write it to RAMSTA $0000@Branch1:LDA $8001,YSTA $0001;Compare if Y is less than or equal to 4CPY #$05;If so, skip this code and go hereBCS @Branch1;load bank 9LDA #$09;swap bank 9 into PRG slotSTA $8000@Branch1:RTS
Quote from: Bregalad on December 22, 2014, 05:24:14 AMIt's pretty good, and was needed. It is about time someone ends the "NES ROMs can't be expanded" fallacy.
Quote from: KingMike on December 22, 2014, 09:50:28 AMWhen doing 256->512KB MMC1 expansion, that introduces another problem: having two "fixed" banks. Code changes in the bank must be kept in sync or the game will break.
Quote from: STARWIN on December 22, 2014, 11:55:24 AMDo games never use the first bank as fixed?Would it be possible to use an existing bank switch routine from the game and just supply it with the new bank numbers, instead of writing your own?I can understand that the new fixed bank has to contain what the old fixed bank did, but in which cases are there then references to the old fixed bank that would break? Do games load the fixed bank to the variable slots or something else?
Quote from: Pennywise on December 22, 2014, 03:09:48 PMI was actually going to use one of the various games I've expanded the ROM for as an example.
Quote from: henke37 on December 22, 2014, 07:11:52 AMYou really should discuss the troubles of when games already do their own bank switching. Having the wrong bank switched in can be disastrous.
Quote from: KingMike on December 22, 2014, 09:50:28 AMYou probably have to do something to make sure the NMI doesn't interrupt the bankswitch
QuoteI thought MMC1 could support 512KB PRG with CHR-ROM, but at the expense of halving the CHR limit (which would make it unusable for ROM hacking). Luckily the games I've done that on have used CHR-RAM.
Page created in 0.061 seconds with 19 queries.