Day 19 - Easy Large Loads
What?
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.
Indirect Addressing?
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:
lda [$10]
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:
Surgeon General's Warning:
Attempting to understand the ASM Code in the
following sections of this document may cause
the reader to either increase their ASM skills
or drive them to suicidal frustration.
The Loop
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
low() and high() are builtin instructions for NESASM.exe that take the high and low
bytes of an address, in this case, backg.
Note that $10 and $11 memory addresses are consecutive, it has to be that way, but
they could be any consecutive addresses.
The second:
ldx #4
ldy #0
loop:
X controls how many chunks of 256 bytes to load in this case, 4. Y must be 0 (zero).
The third:
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.
The last:
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...
The Full Code File
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 pallete
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 pallete
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).
This Day In Review
I thought that was fun. Day 20 could be anything, maybe Attributes,
maybe a lesson on the conditional branches.
Have fun!,
- GbaGuy
Intro - Day 20
Patater GBAGuy Mirror
Contact