Page 1 of 1
Stuck trying to fill one name table.
Posted: Sat May 28, 2011 6:36 pm
by djcouchycouch
I have a 32 by 30 table defined of what my background should be. Problem is, I can't figure out the code to fill the PPU. This is modified from the Nerdy Nights Background 2 example. In it, only the first few lines are filled but I'd like to fill the whole screen.
Code: Select all
FillNametables:
LDA $2002 ; read PPU status to reset the high/low latch
LDA #$20
STA $2006 ; write the high byte of $2000 address (nametable 0)
LDA #$00
STA $2006 ; write the low byte of $2000 address
LDY #$00 ; start a background row 0
LDX #$00 ; start at background column 0
FillNametablesLoop:
LDA #$45 ; this is my tile value. this is supposed to incrementally get the background value from the data, but now it's just hardcoded.
STA $2007
INX ; move right one tile
CPX #$20
BNE FillNametablesLoop
INY ; move down one line
CPY #$1E
BNE FillNametablesLoop
background:
.db $45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45
.db $45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45
etc, etc. for 32 x 30 tiles.
So I'd like to feed A with the background values, but I'm not sure how to do it.
Is there an example I can look at?
Thanks!
Shawn
Posted: Sat May 28, 2011 7:00 pm
by 3gengames
What you do is you"feed" $2007 when you assign to the PPU pointer to the $2000 point of RAM on the PPU side. Problem #1 is you took the palette code and modified it. That's wrong. When you write to $2007, it increments automatically. Can you wrap your head around that or do you need more explanation?
Posted: Sat May 28, 2011 8:09 pm
by djcouchycouch
I'll try again. Let me rephrase:
Ignoring the PPU specifics, I'm not sure how to iterate over my 32 x 30 background data. So I'm looking for an example.
Also, I don't know how to set the background data in my code so that it starts at a $XX00 address, to make iterating over it simpler. The .org command doesn't appear to do this. Maybe I have to pad it with .db?
Posted: Sat May 28, 2011 9:10 pm
by 3gengames
Here's my program to put a screen to the screen, hope it helps! It uses some more advanced memory pointing though. To get a screen, you pass the variable to it from the A register.
You need to have a list of ROM pointers [Low byte first] and then have those point to the ROM where the screen is. Then you need the bulk transfer variable, too. Anyone have any optimizations please show
me/him. Thanks!
Code: Select all
ScreenToScreen:
ASL A
TAX
LDA ScreenPointers,X
STA BulkTransfer
INX
LDA ScreenPointers,X
STA BulkTransfer+1
LDA $2002
LDA #$20
STA $2006
LDA #$00
STA $2006
LDX #$04
LDY #$00
ScreenToScreenLoop:
LDA [BulkTransfer],Y
STA $2007
INY
BNE ScreenToScreenLoop
INC BulkTransfer+1
DEX
BNE ScreenToScreenLoop
LDA #$00
STA $2005
LDA #$FF
STA $2005
RTS
Posted: Sun May 29, 2011 5:44 am
by thefox
shawnleblanc wrote:I'll try again. Let me rephrase:
Ignoring the PPU specifics, I'm not sure how to iterate over my 32 x 30 background data. So I'm looking for an example.
Usually you'll want to use indirect addressing (like in 3gg's example) when the data is over 256 bytes. Basically what you want to do is set up a pointer (2 bytes) on zeropage, copy 256 bytes at a time using indirect y addressing, and increase the high byte of the zeropage pointer after each 256 byte iteration.
Another, maybe easier for a newcomer to understand is just using 4 separate loops. This method is not very generic though and the code will often become harder to maintain because of copy-pasting (unless macros are used).
Also, I don't know how to set the background data in my code so that it starts at a $XX00 address, to make iterating over it simpler. The .org command doesn't appear to do this. Maybe I have to pad it with .db?
Maybe there's a .align directive in the assembler you're using. In any case, aligning it won't necessarily make the code much simpler to write, it'll make it a little bit faster though because there are less page crosses.
Posted: Sun May 29, 2011 5:13 pm
by UncleSporky
One thing that is important to understand (and that others are trying to convey) is that you
don't have to go 32 across, 30 down.
I know it seems obvious and natural, you're filling up a screen that's 32 across and 30 down, but $2007 doesn't care about that - it just takes all the data sequentially, in order.
So what you can do instead is insert 256 tiles in a row, 4 times, which works out to the same result.
Note that you don't have to modify your data at all to do this, even though you have it presented in a nice 32x30 grid, ultimately it's the same thing as 256x4.
Here's my own code for doing it in ASM6, similar to others:
Code: Select all
load_screen
ldy #0 ;y goes from 0 to 256
ldx #4 ;x goes from 4 down to 0
lda #<background
sta tmp16x ;store the low bits of background in a temporary address variable
lda #>background
sta tmp16x+1 ;and also store the high bits
lda #$24 ;load the name table at $2400
sta $2006
lda #$00
sta $2006
- lda (tmp16x),y ;load the data located at the temp variable + y
sta $2007
iny ;increase y by 1
bne - ;loop back until y has gone through 256 iterations
;Increase the high bits of the address by 1.
;This is the same as adding 256, and y is already
;back at 0, so we're ready for the next 256 bytes!
inc tmp16x+1
dex
bne - ;loop until we've done this four times (using x)
ldy #$00 ;clear the name table at $2800 (current location) with blank data
ldx #$04
lda #$00
- sta $2007
iny
bne -
dex
bne -
rts
Posted: Sun May 29, 2011 6:14 pm
by djcouchycouch
Thanks a lot for your feedback! I've been looking into your suggestions. I've also spent a bit more time looking into 16 bit counting/looping and I've got a few ideas I'll try out.