Post
by tokumaru » Fri Mar 17, 2017 5:06 pm
OK, let's look at what happens in my simple NROM example:
First we have the variables. To set their address we use ENUM, which is an ASM6 command that temporarily sets the program counter without generating any output for anything inside the ENUM block. This is great for variables because they live in RAM, and an .NES file only contains ROM, so the goal is to define the addresses of all variables, without storing anything anywhere.
Then comes the header. The header must be written to the output file, but since it's never mapped to any address space (it's only used to give the emulator or Flash cart information about what to do with the rest of the file), we don't even need to set an address, just output the header bytes.
Then the PRG-ROM starts. To let the assembler know where in the CPU space the code that follows will be mapped to (so it can calculate addresses for labels and stuff), we use BASE, another ASM6 command. BASE simply sets the program counter to whatever value we want. Since we know that PRG-ROM on the NES starts at $8000 (or $C000 if you only have 16KB of it), we use BASE $8000.
Then comes all of the code, and normally we don't need to do any address manipulation in this part. We just write the code and let the assembler update the program counter accordingly.
Now we need to write the interrupt vectors to the output file. Those must be at $FFFA, always, because that's where the CPU will look for them. So now we use ORG $FFFA (ORG is more universal, and works mostly the same in any assembler). Why ORG and not BASE? Because ORG pads the ROM with zeroes (or another value of our choice) up until the specified address. We need that because we don't know how big our code is, so we need this padding to make the ROM size correct. BASE doesn't pad anything, so if you had only 6KB of code and used BASE, your PRG-ROM would end up being 6KB large, instead of the expected 16 or 32KB.
For NROM we don't really need to use BASE... that command is only necessary when we have to roll back the program counter, which normally only happens when we use bankswitching. I only used BASE in the NROM example for consistency with the other templates, that have multiple banks. For NROM ORG would have worked fine, because ORG behaves exactly like BASE if the program counter hasn't been set yet.