Banks really are just 8KB segments in NESASM.
.bank 0 is the first 8KB of your ROM.
.bank 1 is the second 8KB of your ROM.
etc.
The NES ROM format requires PRG banks to be first, CHR banks (if there are any) to be last. The 6502 requires vectors to be at $FFFA-$FFFF so it knows where to start running your code.
One thing that's a bit of a gotcha is that the ROM header (.inesprg) specifies the number of SIXTEEN KB PRG banks.
So if that value is 1, you need .bank 0 and .bank 1. .bank 2 would be your first CHR bank.
If that value is 2, you need .bank 0, .bank 1, .bank 2, and .bank 3. .bank 4 would be your first CHR bank.
If you are using no mapper, the order of your banks in the ROM file directly corresponds to their order in NES Memory. So the last PRG bank (either .bank 1 or .bank 3 depending on if you have one 16KB PRG bank for two) must have your vectors in its last six bytes. That's less about NESASM and more about NES.
So as far as bank organization, you could totally put .bank 1 as it is before .bank 0 as it is in your file and it'd work. But you're still beholden to the 6502 vector rules. You can't only have .org $FFFA with your vectors in bank 0 because then it doesn't end up in the right place in NES memory.
Edit: To further explain that... .org helps your assembler make references. Say there's a label and a jump to that label:
Code:
.org $8000
label:
jmp label
That would get assembled as jmp $8000. And.
Code:
.org $FFF0
label:
jmp label
That would get assembled as jmp $FFF0
But that's really it. You could do this:
Code:
.bank 0
.org $8000
label:
jmp label
.bank 1
.org $8000
label2:
jmp label2
Even though bank 1 is .org'd to $8000, that's actually not where the code will end up in memory. (Assuming no mapper.) Both jmp label2 and jmp label would go to label. (Because in a mapperless ROM, the first 8KB of your ROM file will get mapped to $8000. Bank 1 would get mapped to $A000... So label2 is REALLY $A000 and should have been .org'd that way so those jmps would make sense. That's similar to why a .org $FFFA wouldn't work in bank 0 (in a mapper less ROM.) It still doesn't end up in $FFFA in NES memory.
And you might wonder why the assembler can't do it automatically... and the reason is because mappers can sort of put any part of the ROM anywhere. Bank 0 and bank 1 could BOTH be designed to be at $8000. (Though not at the same time)
Code:
ldx #$7F;Why $7F and not $FF?
stx stack_ptr
txs
You've got some subtle problems. This never writes $FC to $0200:
Code:
MemoryClear:
ldx #$FF
lda #$FC
MemLoop1:
sta $0200,x
dex
cpx #$00
bne MemLoop1
At MemLoop1, imagine X is 1. sta $0200,x will make $0201 equal to $FC. Dex. X is 0. 0 is equal to 0, so we don't branch again. So an sta $0200,x where x was zero never happens.
You (usually) don't need to do a comparison with zero, because the zero flag is set/cleared by most instructions.
This would do the same thing (in this context):
Code:
MemoryClear:
ldx #$FF
lda #$FC
MemLoop1:
sta $0200,x
dex
bne MemLoop1
But that still missed zero. Instead, start with zero and count up. Getting back to zero will still break the loop, but that's fine since you did zero at the start before any conditional branch check:
Code:
MemoryClear:
ldx #$0
lda #$FC
MemLoop1:
sta $0200,x
inx
bne MemLoop1
The same problems are in your second clear memory loop. Here's both with that change:
Code:
MemoryClear:
ldx #0
lda #$FC
MemLoop1:
sta $0200,x
inx
bne MemLoop1
;We know X is zero, because the branch didn't happen.
;So no need to reload it
lda #$00;For the astute, txa would also work. Since, again, we know X is zero.
MemLoop2:
sta $00,x
sta $0100,x
sta $0300,x
sta $0400,x
sta $0500,x
sta $0600,x
sta $0700,x
inx
bne MemLoop2
Your NMI will break your game because it doesn't restore the registers from the stack correctly.
Code:
NMI:
pha;Pushes A to the stack: Current Stack: A
txa
pha;Pushes X to the stack: Current Stack: AX
tya
pha;Pushes Y to the stack: Current Stack: AXY
;...
SkipNMI:
pla;Get the old value for Y into A ;Current stack: AX
tya;Transfer Y to A... now the old value for Y is completely gone.
pla;Get the old value for X into A ; Currently stack: A
txa;Transfer X to A... now the old value for X is completely gone.
pla
You want:
Code:
SkipNMI:
pla
tay;So that the old value for Y is back in Y when we return
pla
tax;So that the old value for X is back in X when we return
pla
The way you're writing to PPU memory is not correct.
Code:
lda HIGH(PPU_PAL);First, you need the # here. lda HIGH(PPU_PAL) will make
;A the value stored in RAM location $3F rather than the constant #$3F
;As opposed to lda #HIGH(PPU_PAL) which would make A equal to #$3F
;You write the high byte to PPU_ADDR
sta PPU_ADDR;But you also need to write the low byte and you don't.
;X and Y should be switched here. ,x is used as an offset in bg_pal,x, so X is the one you should load
;with update_pal_start
ldy update_pal_start
ldx #$00
UpdatePalLoop:
lda bg_pal1,x
sta PPU_DATA,y;$2007 (PPU_DATA) is the register that writes a byte to the PPU. Not $2008. Not $2009.
;If you write to $2007,y and Y is not zero, you're usually not actually writing a byte
iny
inx
cpx update_pal_size
bne UpdatePalLoop
NoPalUpdate:
rts
So the fixes for all that look like:
Code:
UpdatePal:
lda update_pal
beq NoPalUpdate
bit $2002;Makes it so our next write PPU_ADDR will write the high byte
lda #HIGH(PPU_PAL)
sta PPU_ADDR
lda #LOW(PPU_PAL)
sta PPU_ADDR
ldx update_pal_start
; ldy #$00;No need for this
UpdatePalLoop:
lda bg_pal1,x
sta PPU_DATA
;iny;No need for this
inx
cpx update_pal_size
bne UpdatePalLoop
NoPalUpdate:
rts
If you do all these fixes, your ROM will work. But the palette will still not be black.
Code:
DefaultPal:
.db $00,$30,$21,$02
.db $00,$30,$21,$02
.db $00,$30,$21,$02
.db $00,$30,$21,$02
.db $00,$30,$21,$02
.db $00,$30,$21,$02
.db $00,$30,$21,$02
.db $00,$30,$21,$02
$00 is not black. Try $0F.
Edit: Oh! I was wondering how sprites were moving on the screen when there was seemingly no code to make them do anything.
lda #$02 is different than lda $02.
Code:
;If #$FF is stored at $02
lda $02;A = $FF
lda #$02;A = $02
So this code...
Code:
lda $00
sta OAM_ADDR
lda $02
sta OAM_DMA
Draws sprites using RAM at the zero page when the value at $02 is zero. You want:
Code:
lda #$00
sta OAM_ADDR
lda #$02
sta OAM_DMA