Page 3 of 5

Re: How do I use Vblank?

Posted: Thu Mar 16, 2017 9:57 am
by DementedPurple
Sorry, I thought the BASE statement was something like a .db statement that wouldn't work on the actual hardware. If I were to write the binary file to an actual EPROM, would the NMI code appear in that section?

Re: How do I use Vblank?

Posted: Thu Mar 16, 2017 10:06 am
by dustmop
.db reserves space in memory (RAM or ROM, depending on usage and the assembler), and it works just fine on hardware.

Generally speaking, anything in a compiled .nes file that runs in emulator will work the same on hardware when burned on an EPROM. There are tons of exceptions (buggy emulators, startup state, improper mapper usage, lua scripting), but generally speaking the features are the same, especially when talking about how assemblers work.

NMI code will appear in the NES hardware's address space the same way it will in an emulator, regardless of whether you use .BANK for linker relocation, or .SEGMENT directives, or whatever.

Re: How do I use Vblank?

Posted: Thu Mar 16, 2017 10:40 am
by tokumaru
The .nes file you run on emulators contains the exact same binary data you burn on EPROMs to run on real hardware, you don't need 2 separate builds when coding the program. To burn EPROMs you just need to take the .nes file and use a tool or an hex editor to split it into header, PRG-ROM and CHR-ROM, and then burn the PRG and CHR to different chips.

Re: How do I use Vblank?

Posted: Thu Mar 16, 2017 11:25 am
by DementedPurple
Then how would the actual NES know where to go when the NMI is true?

Re: How do I use Vblank?

Posted: Thu Mar 16, 2017 11:29 am
by dustmop
Tepples mentioned this earlier. The address at $FFFA contains the NMI "vector", which is just an address that points to the NMI function. So for example, if your NMI function gets compiled such that it is in the ROM at $8123, then the value at $FFFA is $23, and the value at $FFFB is $81 (little-endian order swaps the bytes of the address). You maybe were confused and thought that the vectors were "metadata", like the 16 byte header at the start of the ROM, but they're not. They exist in the binary even when on hardware.

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 10:09 am
by DementedPurple
If the NMI vector is at $FFFA, would that mean I'm limited to only 4 bytes of NMI code?

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 10:20 am
by tepples
The vector $FFFA can point anywhere in ROM or RAM.

The vast majority of Super Mario Bros., for instance, is its NMI handler. That's because it's structured roughly like the following pseudocode:

Code: Select all

main() {
  setup_hardware();
  init_globals();
  enable_nmi();
  for (;;) { }
}

__interrupt__ void nmi() {
  PUSH_ALL;
  if (vram_data_ready) {
    copy_data_to_vram();
    vram_data_ready = 0;
  }
  read_controllers();
  game_logic();
  prepare_data_for_vram();
  vram_data_ready = 1;
  POP_ALL;
}

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 10:26 am
by dougeff
Nothing at fffa but an address.

When the processor gets an Interrupt signal, it will jump somewhere. Fffa tells it where to jump.

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 10:33 am
by mikejmoffitt
DementedPurple wrote:If the NMI vector is at $FFFA, would that mean I'm limited to only 4 bytes of NMI code?
Think of it as a function pointer.

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 10:51 am
by tepples
DementedPurple wrote:What is a function pointer

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 12:31 pm
by Pokun
DementedPurple wrote:If the NMI vector is at $FFFA, would that mean I'm limited to only 4 bytes of NMI code?
No the interrupt vectors just points to your interrupt handlers. They don't contain any code, just addresses (addresses are 2 byte each). The interrupt handlers contains the code.

The templates you are using looks something like this:

Code: Select all

;iNES header here

.org $8000

RESET:
;init code here
main:
  ;main loop code here
  jmp main

NMI:
;nmi code here
  rti

IRQ:
;irq code here
  rti

;Interrupt vectors:
  .org $FFFA
  .dw NMI
  .dw RESET
  .dw IRQ
You use labels like "RESET" so you don't have to hard-code the addresses for your interrupt handlers. Of course when the ROM is assembled the vectors will contain constant addresses, but that is the assemblers job to solve. Instructions like .org and .base is for the assembler to know where in the output file everything should be placed. The reason we start at $8000 (or $C000 if ROM is small) is because $8000 is where the ROM area starts in the address space. If we would use .org $0000 as start address, the interrupt vectors (if we don't change their start addresses) would be in the wrong place and the assembled ROM would become too big. It makes more sense to start counting from a number that matches the start address in the ROM area in the address space.

The order of the three interrupt handlers (RESET, NMI and IRQ) doesn't matter, they can be anywhere in the ROM (or RAM as Tepples said). Just make sure that NMI and IRQ handlers ends with an RTI instruction, and the RESET handler ends with an endless loop.

The order of the interrupt vectors DO matter however.

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 12:55 pm
by mikejmoffitt
Think of it as the NES doing something similar to

Code: Select all

JSR $FFFA
every time there is an NMI. That's not literally what's going on, but the point is that $FFFA stores the address of your NMI routine, and the 6502 reads that memory to find where to jump. We say that $FFFA points to a location in memory.

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 1:06 pm
by DementedPurple
So it goes to the NMI code automatically, no matter what the CPU is doing. So if I where to have a loop like the one down below:

Code: Select all

example:
jmp example
would it still go to the NMI? And also, does the NROM template have that built in? Also, could I just do BASE $FFFA before the header?

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 1:50 pm
by tokumaru
DementedPurple wrote:would it still go to the NMI?
Yes, as long as NMI generation is enabled in the PPU (bit 7 of register $2000), which you normally do at the end of the initialization code.
And also, does the NROM template have that built in?
All mappers behave the same way in regard to NMIs.
Also, could I just do BASE $FFFA before the header?
Again, what's with this BASE stuff, man? No more BASE, forget about BASE. Specially before the header, that makes no sense whatsoever. Just out of curiosity, what would you be trying to accomplish with a BASE before the header anyway?

Re: How do I use Vblank?

Posted: Fri Mar 17, 2017 3:56 pm
by DementedPurple
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?