Today, we will use a new loading loop that utilizes indirect addressing to load a lot of data at a time. The data we will load will be the Zelda title screen, and yes, today will include all of the code. I've included the 3 necessary data files in nesasm.zip. Please redownload it, I could have sworn that I already had them in there... sorry for any inconveniece.
Yep, indirect addressing (which is hard for me to type for some reason...) is simply getting an address from the contents of another address, so say we wanted to get a value from an address contained at $0010-$0011 (16-bit address, remember that).
But first a little review (I hope), vocab lesson #whatever: Take the address $8000, $00 is the high byte and $80 is the low byte, got it? (I might have that backwards, I have bronchitis at the moment...)
The low byte would be in $10 and the high byte in $11 (note that I use two digits only, because the first 2 in the address are zero). So assuming the address that we really want to load from is $82C5 which is at $10-$11, to load the byte at $82C5 into the A register, we would do:
this can also be indexed, like so:
lda [$10], y
What this would do is take the address $82C5, add the contents of Y to that address (the address not the contents), and get byte at the resulting address.
I hope you understood all that, because it's just going to get more confusing. And just a short joke before we continue:
I think, therefore I am? no. I think therefore I'll give the complete loop and explain it in pieces. Assume backg is the label of where a bunch of name table data is included, also assume $2006 is pointing to $2000:
lda #low(backg) sta $10 lda #high(backg) sta $11 ldx #4 ldy #0 loop: lda [$10],y sta $2007 iny bne loop inc $11 dex bne loop
The first piece:
lda #low(backg) sta $10 lda #high(backg) sta $11
high() are builtin instructions for
NESASM.exe that take the high and low bytes of an address, in this case,
Note that $10 and $11 memory addresses are consecutive, it has to be that way, but they could be any consecutive addresses.
ldx #4 ldy #0 loop:
X controls how many chunks of 256 bytes to load in this case, 4. Y must be 0 (zero).
lda [$10],y sta $2007 iny bne loop
This part loads 256 bytes to $2007 using indirect addressing indexed by Y. Note that the registers (A,X,Y) wrap around so adding 1 to #$FF will make the register contain #$00. And that's how this works, because when Y is incremented to #$00, the loop will be done loading the 256 byte chunk.
inc $11 dex bne loop
This part increments the high byte of the address of the data to the next 256 byte chunk. It also counts down 1 in the X register which contains the amount of chunks left, if X is zero, it won't loop and we're done loading everything.
That went better than I expected...
Before I give you the full code file (fully commented, of course), make sure you have those 3 files in your code folder.
;--- CODE START ---; .inesmir 1 .inesmap 0 ; INES header $H!7. .ineschr 1 .inesprg 1 .bank 1 .org $FFFA ; vector table .dw 0 .dw Start .dw 0 .bank 0 .org $0010 addrLO: .db 0 ; make "variable"s for our indirect addressing addrHI: .db 0 .org $8000 Start: ldx #0 lda #$20 ; set the destination address in PPU memory sta $2006 ; should be $2000 stx $2006 lda #low(backg) ; put the high and low bytes of the address "backg" sta addrLO ; into the variables so we can use indirect addressing. lda #high(backg) sta addrHI ldx #4 ; number of 256-byte chunks to load ldy #0 loop: lda [addrLO],y sta $2007 ; load 256 bytes iny bne loop ;-------------------- inc addrHI ; increment high byte of address backg to next 256 byte chunk dex ; one chunk done so X = X - 1. bne loop ; if X isn't zero, do again lda #$3F sta $2006 lda #$00 ; point $2006 to the palette sta $2006 ldx #$00 palload: lda tilepal, X ; use a simple load of 32 bytes. inx sta $2007 cpx #32 bne palload jsr turn_screen_on ; call subroutine to turn on / setup the PPU. infin: ; our infinite loop jmp infin turn_screen_on: ; Setup the PPU lda #%00001000 sta $2000 lda #%00011110 sta $2001 rts tilepal: .incbin "zelda.pal" ; include the palette backg: .incbin "zelda.nam" ; include the name table data .bank 2 .org $0000 .incbin "zelda.chr" ; include the picture data in the background part ;of the CHR-BANK (#2) ;;--- CODE END/ END OF FILE ---;;
I hope you got all that and that it works (I did some modifications from my testing file).
I thought that was fun. Day 20 could be anything, maybe Attributes, maybe a lesson on the conditional branches.