Understanding Backgrounds

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
NEStegg
Posts: 10
Joined: Fri Jul 29, 2011 12:31 pm
Location: Seattle

Understanding Backgrounds

Post by NEStegg »

Hello. I am in need of some help following Nerdy Nights' Background tutorial. In attempting to fill in background tiles 5 thru 19 (where mario would be standing) with "all sky," I experienced a problem. I (supposedly) coded the nametables right, but I still see zeroes in the rows that I coded. What am I doing wrong?

Also, I need some help deciphering attribute bytes. The way I am interpreting them is this:

%wwxxyyzz

ww=Bottom Right
xx=Bottom Left
yy=Top Right
zz=Top Left

Am I correct?

Thanks in advance!
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

You you see all zeros, after you set the PPU address with two $2006 writes, you store the number of the tile you want, make sure the number you want is right.

Code please?
Shiru
Posts: 1161
Joined: Sat Jan 23, 2010 11:41 pm

Post by Shiru »

NEStegg
Posts: 10
Joined: Fri Jul 29, 2011 12:31 pm
Location: Seattle

Post by NEStegg »

3gengames wrote:You you see all zeros, after you set the PPU address with two $2006 writes, you store the number of the tile you want, make sure the number you want is right.

Code please?

Code: Select all

LoadBackground:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$20
  STA $2006             ; write the high byte of $2000 address
  LDA #$00
  STA $2006             ; write the low byte of $2000 address
  LDX #$00              ; start out at 0
LoadBackgroundLoop:
  LDA background, x     ; load data from address (background + the value in x)
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$80              ; Compare X to hex $80, decimal 128 - copying 128 bytes
  BNE LoadBackgroundLoop  ; Branch to LoadBackgroundLoop if compare was Not Equal to zero
                        ; if compare was equal to 128, keep going down
              
              
LoadAttribute:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$23
  STA $2006             ; write the high byte of $23C0 address
  LDA #$C0
  STA $2006             ; write the low byte of $23C0 address
  LDX #$00              ; start out at 0
LoadAttributeLoop:
  LDA attribute, x      ; load data from address (attribute + the value in x)
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$08              ; Compare X to hex $08, decimal 8 - copying 8 bytes
  BNE LoadAttributeLoop  ; Branch to LoadAttributeLoop if compare was Not Equal to zero
                        ; if compare was equal to 128, keep going down 
later...

Code: Select all

background:
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 1
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 2
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24  ;;row 3
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24  ;;some brick tops

  .db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24  ;;row 4
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24  ;;brick bottoms

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 5
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 6
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 7
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 8
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 9
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 10
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 11
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 12
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 13
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 14
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 15
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 16
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 17
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;row 18
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;all sky

  .db $45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45  ;;row 19
  .db $45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45,$45  ;;all brick tops

attribute:
  .db %00000000, %00010000, %01010000, %00010000, %00000000, %00000000, %00000000, %00110000 
  .db %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000
  .db %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000
  .db %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000
  .db %00000000, %00000000, %00010000, %00010000, %00010000, %00010000, %00010000, %00010000




pallete:

  .db $24,$24,$24,$24, $47,$47,$24,$24 ,$47,$47,$47,$47, $47,$47,$24,$24 ,$24,$24,$24,$24 ,$24,$24,$24,$24, $24,$24,$24,$24, $55,$56,$24,$24  ;;brick bottoms

3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

You'll need to load all of the data, I think you only upload the top 4 rows of data with that code. If you want, would you just like a program that you point to 1KB of data and have it upload the screen? As long as you understand what happens when uploading backgrounds and stuff, I don't really see a problem with taking a shortcut and showing you how to upload a whole screen and not just confusing chunks and such. Mail me if you'd like me to teach you how to upload a whole background separate. :)
NEStegg
Posts: 10
Joined: Fri Jul 29, 2011 12:31 pm
Location: Seattle

Post by NEStegg »

@3gengames...

I'll re-read the tutorial and try it again myself, then if I need help I'll let you know.

UPDATE: OK, how do I address the PPU RAM beyond $FF in the LoadBackgroundLoop?
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

You need to keep another variable, when you max out the 256 steps the 1st time, decrease it until you transfer all 4*256 bytes of data. You usually can use just Y for loop count, as background uploading a chunk of ROM to the PPU is pretty simple, no RAM really needed, unless you use my flexible example that uses a couple bytes of zeropage, I'll show you it once you understand it after you write yours though. Seems like you have at least a good idea of what needs to happen, that's good.
NEStegg
Posts: 10
Joined: Fri Jul 29, 2011 12:31 pm
Location: Seattle

Post by NEStegg »

I solved it myself! Just needed to do a little research. I'd still love to hear your methods, though.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

Well, you'll need two bytes of zeropage for this, but it's pretty flexible for a method compared to most:

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
  RTS
You need to have two labels, really. One in Zeropage [$00-$FE with 2 bytes reserved] reserving 2 bytes of RAM The next thing for this you'll need is just a single table of pointers, low byte first, for it to use. Mine looks like:

Code: Select all

ScreenPointers:
  .db LOW(TitleScreen),HIGH(TitleScreen)
  .db LOW(MainScreen),HIGH(MainScreen)
with the LOW and HIGH grabbing the high and low bytes of another label at compile time, which are for mine just:

Code: Select all

TitleScreen:
  .incbin "Screens/StartupScreen.bin"
MainScreen:
  .incbin "Screens/MainScreen.bin"
with the binary data from saving the screen. It just wastes the whole 1K, I need to do an RLE version of this one day.

I also hace a palette program like this, but I think you can handle writing the program for palettes yourself or something. If you have any problems with understanding this program at all just tell me, I'll explain it more for you to learn about better methods like this. This is 100% not the best way to upload screen, but for people just starting out, it allows multiple screens and isn't that complex/big to add. :)

The full code pretty much:

Code: Select all

.resset $0000
BulkTransfer: .rs 2;2 bytes of RAM for the screen transfer program up there.

.bank 1
.org $E000
Start:
   JMP Start ;Startup code here and such, this is where you can put that you already have if you want.
  LDA #$00 ;Screen to upload. #$00-#$7F.
  JSR ScreenToScreen ;Upload a screen somewhere like this.
  ;More program afterwords.

.include "ScreenToScreen.asm" ;Include the coe for screntoscreen in another file to keep the mess down.
.org $E800
ScreenPointers:
  .db LOW(TitleScreen),HIGH(TitleScreen)
  .db LOW(MainScreen),HIGH(MainScreen) ;Maybe put these at somewhere in rom $E800 and the two pointers below to $E900 to make sure they align in memory and program execution doesn't take longer.
.org $E900
TitleScreen:
  .incbin "Screens/StartupScreen.bin"
MainScreen:
  .incbin "Screens/MainScreen.bin"
Yeah, this all goes in your main program, you can just add what you need there, don't use this as a base truthfully.
Post Reply