Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.
DementedPurple wrote:I don't know, I think that a BASE command is like a header, I honestly have no idea. How would the NES know where $FFFA is?
The 6502 processor, as well as the derivative 2A03 processor in the NES, is hard-coded to look to $FFFA, $FFFC, and $FFFE for the three vectors. When it boots up (reset state), it immediately does a JMP ($FFFC) effectively, and that's how your program begins. Whatever you put in $FFFC tells it where to start execution.
I don't know what BASE is - it may be related to the assembler you're using, or whatever - but there's nothing linking it to 6502 programming intrinsically.
Last edited by mikejmoffitt on Fri Mar 17, 2017 6:39 pm, edited 1 time in total.
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.
Sounds like maybe you are not fully familiar with interrupts yet? When an interrupt happens, the program counter is interrupted in the code, no matter where it currently is, and then it jumps to the interrupt handler (the NMI handler in this case). It will then run the code from the start of the interrupt handler until it runs into an RTI instruction. When it does, it will jump back to wherever it was before the interrupt happened.
does the NROM template have that built in?
As long as the interrupt vectors are in the correct place the CPU will be able to find the address for the three interrupt handlers, so yes it does have this built in. The three vectors are a minimal requirement for a 6502 program to work at all I think, it's not NES-specific.
Yes. Super Mario Bros. does exactly this. It sets up the hardware and game state and falls into an infinite JMP loop, and then the entire game runs inside of the NMI handler.
DementedPurple wrote:And also, does the NROM template have that built in? Also, could I just do BASE $FFFA before the header?
As far as I can tell, BASE isn't very useful unless you're trying to copy code to RAM, such as for self-modification or to keep code available no matter which 32K bank is switched in.
mikejmoffitt wrote:When it boots up (reset state), it immediately does a JMP $FFFC effectively, and that's how your program begins. Whatever you put in $FFFC tells it where to start execution.
I thought it was JMP ($FFFC), which reads the program counter from $FFFC instead of actually looking for an opcode at $FFFC.
mikejmoffitt wrote:When it boots up (reset state), it immediately does a JMP $FFFC effectively, and that's how your program begins. Whatever you put in $FFFC tells it where to start execution.
I thought it was JMP ($FFFC), which reads the program counter from $FFFC instead of actually looking for an opcode at $FFFC.
As far as I can tell, BASE isn't very useful unless you're trying to copy code to RAM, such as for self-modification or to keep code available no matter which 32K bank is switched in.
tepples wrote:As far as I can tell, BASE isn't very useful unless you're trying to copy code to RAM
Or if you have more than one PRG-ROM bank, in which case you have to move the PC from the end of the bank back to the beginning ($C000 back to $8000 in the case of UNROM, for example). Another option for multiple banks in ASM6 I'm aware of is to assemble each bank separately, but that can get really hard if the banks reference each other a lot.
tokumaru wrote:Another option for multiple banks in ASM6 I'm aware of is to assemble each bank separately, but that can get really hard if the banks reference each other a lot.
That is what I do for the FDS mapper, I couldn't figure out another way that would work.
It depends on what exactly you mean by "know[ing] when the NMI is not true". What would "know[ing] when the NMI is not true" tell you? Are you trying to wait for the end of vertical blanking?
tepples wrote:It depends on what exactly you mean by "know[ing] when the NMI is not true". What would "know[ing] when the NMI is not true" tell you? Are you trying to wait for the end of vertical blanking?
The only reliable way to know when vblank ends is to wait for the sprite overflow or sprite 0 hit flags to be cleared (which happens near the end of vblank), but you have to make sure they were set in the previous frame to begin with. May I ask why you'd need this information? Most people just optimize their vblank handling code so it never extrapolates the allowed time.
I'm afraid that my Vblank my be too short, and it'll finish early and go to the part where it will read the controllers and then you will be still pressing the right arrow and the x-position will be increasing too fast.