Stuck trying to fill one name table.

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Stuck trying to fill one name table.
by on (#78857)
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:
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

by on (#78858)
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?

by on (#78863)
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?

by on (#78866)
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:
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

by on (#78874)
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).

Quote:
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.

by on (#78888)
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:
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

by on (#78891)
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.