Klarth's reply is good, and I don't mean to step on his toes here, but I felt I could elaborate on a few things a bit:IRQs / NMIs
I wouldn't worry about these until you get a very basic "hello world" program running and understanding how that works.
NMIs and IRQs are "interrupts". As Klarth mentioned, these are external signals that are used to "cut into" or "interrupt" the running program to let you know that a certain event has happened.
NMIs and IRQs are mostly the same, but with some minor differences:
- The 'I' processor flag (see CLI/SEI instructions) will prevent IRQs from occurring, but will not stop NMIs.
- IRQs go the the IRQ vector ($FFFE) when they happen, whereas NMIs go to the NMI vector ($FFFA)
- On the NES, NMIs are used exclusively for notifying you when VBlank happens, whereas IRQs have various mapper-specific uses (though virtually all of them are raster related, like letting you know when a specific scanline is starting)
You can think of it this way -- the CPU is always running instructions. When an interrupt happens, the CPU will stop running code from it's current position, and will jump to a new position (designated by the address in the NMI/IRQ vector). Once you do an RTI, the interrupt code will stop, and the CPU will jump back to the code it was running before the interrupt happened.
Basically interrupts cause the system to jump to new code when something significant happens. But to really understand why that's useful, you need to understand the basics of timing. Which is not a topic I would recommend until you've got the basics of displaying a simple image on screen.clrmem
clrmem is clearing memory (RAM).
On the NES, RAM resides between the $0000-07FF address range. On powerup, this RAM contains unreliable garbage, so it's good practice to clear it (set it all to zero) before using any of it. clrmem accomplishes this with a basic loop:
; It's not mentioned, but for this loop to work properly, X must be 0 at the start
; It is 0 in the code (due to the INX on line 19) but it's not exactly clear...
LDA #$00 ; sets A=0
STA $0000, x ; writes A (0) to address $0000+X
STA $0100, x ; then to $0100+X
STA $0200, x ; then to $0200+X
STA $0400, x ; etc...
STA $0500, x
STA $0600, x
STA $0700, x
STA $0300, x ; then writes $FE to address $0300+X
INX ; Increments X
BNE clrmem ; Jumps back until X is zero, which won't happen until it wraps from $FF->$00
The loop works like so: Each time the code runs (each "iteration" of the loop), 'X' will be a new value (one higher than it was before). So "STA $0000,X" will write to address $0000 the first iteration, but will write to address $0001 the next time (because X=1), then $0002 the time after that (because X=2), and so on.
The last iteration, X will be $FF... which will write to $00FF. Then, once it hits that INX, since X is only 8-bits wide, it will wrap from $FF to $00, resulting in the Z flag being set, and the BNE to not branch, allowing the code to exit the loop.
The end result is that all addresses in the $0000-07FF range get zero written to them (with the exception of the $0300-03FF page, which gets $FE written to it instead).
If might help to run this code in FCEUX and step through it line by line with the hex editor open so you can see how memory changes with each STA.Why certain addresses need to be written to
This is a pretty generic question, as you don't specify which addresses you're talking about.
Klarth linked to the memory map, which is a good general outline. But if you want more details about what certain addresses do, you can look at the nesdev wiki. In fact, you might want to see if you can find answers to any questions on the nesdev wiki.
PPU (graphics) registers:http://wiki.nesdev.com/w/index.php/PPU_registers#Summary
APU (sound) registers (I wouldn't worry about this for now -- get graphics working first):http://wiki.nesdev.com/w/index.php/APU#Registers
Klarth did a good job explaining the basics of what the stack is.
Only other thing worth noting is that the NES pushes values to the stack to "remember" where you came from when you do a JSR (or when an interrupt happens). That way when you RTS/RTI, the CPU will pop values off the stack to know where to jump back to.BIT / BPL
BIT is an awkward and not frequently used instruction. The way it's being used in that code, LDA would do the same thing and would be much, much less confusing for newbies. My advice is to replace the BIT with an LDA in the code, and don't worry about understanding BIT until you're more comfortable with the system.
BPL is a branch that examines the 'N' status flag. Most instructions will modify 'N' according to the high bit (bit 7: "$80") of the resulting value. For example, with LDA (and BIT) if the high bit of the value you read was set, so too will the N flag be set. Likewise if the high bit was cleared, so too will the N flag be cleared.
BPL will branch (jump) if the N flag is clear.
Therefore this loop:
LDA $2002 ; (or BIT $2002)
BPL vblankwait 1
Is effectively polling the $2002 register (aka PPUSTATUS
) hundreds of times to examine the high bit (VBlank flag)... and keeps looping until that flag is set, at which point N will be set and the loop will exit.
This is a common way to wait for VBlank during startup -- but don't rely on it at any other time, as the VBlank flag is unreliable. When you get to the point where VBlank matters -- you'll want to use NMIs. However, don't worry about that yet -- just get something drawing first.