Define a Pallete Only For The Background

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Define a Pallete Only For The Background

Post by nathanpc »

Hello,
I'm using a background, but I want to use a different pallete for it, because at the time I only have one pallete assigned, but on the source folder I have another one called bkg.pal, that is a pallete for the background. But my code is like this now:

Code: Select all

	.inesprg 1   ; 1 bank of code
	.ineschr 1   ; 1 bank of spr/bkg data
	.inesmir 1   ; something always 1
	.inesmap 0   ; we use mapper 0

	.bank 0   ; bank 0 - our place for code.
	.org $0000
addrLO = $10 
addrHI = $11
Sprite1_X   .db 50       ; a X position for our sprite, start at 20
Sprite1_Y   .db 20       ; a Y position for our sprite, start at 20
;Sprite2_X   .db 50       ; a X position for our sprite, start at 20
;Sprite2_Y   .db 20       ; a Y position for our sprite, start at 20
	.org $8000  ; code starts at $8000
	
Start:  
	lda #%10001000  ; do the setup of PPU
	sta $2000       ; that we

	ldx #$00    ; clear X

	lda #$3F    ; have $2006 tell
	sta $2006   ; $2007 to start
	lda #$00    ; at $3F00 (pallete).
	sta $2006

loadpal:                ; this is a freaky loop
	lda tilepal, x  ; that gives 32 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 32, meaning we
	cpx #32         ; are done.
	bne loadpal     ; if X isn't =32, goto "loadpal:" line.

	lda #$20
	sta $2006 ; give $2006 both parts of address $2020.
	sta $2006 
	ldx #$00

Map_Load: 
  	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 
  	lda #low(ourMap) 
  	sta addrLO 
  	lda #high(ourMap)              ; start out at 0 
  	sta addrHI 

  	ldx #4 
  	ldy #0 

Map_Load_loop: 
  	LDA [addrLO], y     ; load data from address (background + the value in x) 
  	STA $2007             ; write to PPU 
  	INy                   ; X = X + 1 
  	BNE Map_Load_loop  ; Branch to LoadBackgroundLoop if compare was Not Equal to zero 
  	inc addrHI 
  	dex 
  	bne Map_Load_loop 

waitblank1:         
	lda $2002  ; these 3 lines wait for VBlank, this loop will actually miss VBlank
	bpl waitblank1 ; alot, in a later Day, I'll give a better way
	txa 
clrmem: 
	sta $000,x 
	sta $100,x 
	sta $200,x 
	sta $300,x 
	sta $400,x 
	sta $500,x 
	sta $600,x 
	sta $700,x  ; Remove this if you're storing reset-persistent data 
	inx 
	bne clrmem
	
waitblank2:         
	lda $2002  ; these 3 lines wait for VBlank, this loop will actually miss VBlank
	bpl waitblank2 ; alot, in a later Day, I'll give a better way
	lda #%00011110
	sta $2001
	
loop:
	jmp loop
	
infinite:  ; a label to start our infinite loop
nmi:

	; Load Sprite1
	lda Sprite1_Y
	sta $0300
	lda #$11
	sta $0301
	lda #$00
	sta $0302
	lda Sprite1_X
	sta $0303
	
	; Load Sprite2
	;lda Sprite2_Y
	;sta $0304
	;lda #$12
	;sta $0305
	;lda #$00
	;sta $0306
	;lda Sprite2_X
	;sta $0307
	
	lda #$01   ; these
	sta $4016  ; lines
	lda #$00   ; setup/strobe the 
	sta $4016  ; keypad.

	lda $4016  ; load Abutton Status ; note that whatever we ain't interested
	lda $4016  ; load Bbutton Status ; in we just load so it'll go to the next one.
	lda $4016  ; load Select button status
	lda $4016  ; load Start button status
	lda $4016  ; load UP button status
	and #1     ; AND status with #1
	bne UPKEYdown  ; for some reason (not gonna reveal yet), need to use NotEquals
	;with ANDs. So it'll jump (branch) if key was down.
	
	lda $4016  ; load DOWN button status
	and #1     ; AND status with #1
	bne DOWNKEYdown

	lda $4016  ; load LEFT button status
	and #1     ; AND status with #1
	bne LEFTKEYdown

	lda $4016  ; load RIGHT button status
	and #1     ; AND status with #1
	bne RIGHTKEYdown
	jmp NOTHINGdown  ; if nothing was down, we just jump (no check for conditions)
	; down past the rest of everything.

UPKEYdown:
	lda Sprite1_Y ; load A with Y position
	sbc #1  ; subtract 1 from A. Only can do math on A register. SBC (Subtract with Borrow)
	sta Sprite1_Y ; store back to memory
	;lda Sprite2_Y ; load A with Y position
	;sbc #1  ; subtract 1 from A. Only can do math on A register. SBC (Subtract with Borrow)
	;sta Sprite2_Y ; store back to memory
	jmp NOTHINGdown  ; jump over the rest of the handling code.

DOWNKEYdown:
	lda Sprite1_Y 
	adc #1  ; add 1 to A. ADC (Add with Carry)((to A register))
	sta Sprite1_Y
	jmp NOTHINGdown ; jump over the rest of handling code.

LEFTKEYdown:
	lda Sprite1_X
	sbc #1  
	sta Sprite1_X
	jmp NOTHINGdown 
;the left and right handling code does the same as UP and Down except.. well.. with
; left and right. :)

RIGHTKEYdown:
	lda Sprite1_X
	adc #1
	sta Sprite1_X
	; don't need to jump to NOTHINGdown, it's right below. Saved several bytes of
	; PRG-Bank space! :)
	
NOTHINGdown:
	lda #$03
	sta $4014
	rti

tilepal:
	.incbin "our.pal" ; include and label our pallete
	
ourMap:
	.incbin "our.map" ; assuming our.map is the binary map file.
	.bank 1   ; following goes in bank 1
	.org $FFFA  ; start at $FFFA
	.dw nmi    ; dw stands for Define Word and we give 0 as address for NMI routine
	.dw Start ; give address of start of our code for execution on reset of NES.
	.dw 0   ; give 0 for address of VBlank interrupt handler, we tell PPU not to
	; make an interrupt for VBlank.
	
	.bank 2   ; switch to bank 2
	.org $0000  ; start at $0000
	.incbin "our.bkg"  ; background data
	.incbin "our.spr"  ; our sprite pic data
Then I want to know how can I assign a pallete only for the background.

Best Regards,
Nathan Paulino Campos
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

To assign a palette for the background, write to PPU $3F01-$3F0F.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Your code is based on GBAGuy's tutorial isn't it? It's full of errors. Before talking about the palette I'm gonna talk about those errors, or else your program is never going to run on a real NES.

First, there are several initializations steps necessary for your program to be stable that your code just doesn't do. Take a look at the init code from the wiki. All your programs should start with code like that, because all those steps have a reason to be there. I see that you have part of it in your code, but it's erroneously placed after several PPU operations. The initialization must be before everything. clearing the memory is optional though, and not necessary if you are careful with each variable you use (never use memory without initializing it first).

Only after that initial code, after waiting 2 VBlanks, the PPU is ready for being used. See, the PPU needs some time to warm up, this is why we must wait a while before using it. But your program starts using it right away, so it would certainly fail on a real NES.

OK, the palette then: You are currently loading 32 bytes of palette data, and that corresponds to 8 whole palettes (4 for the background and 4 for the foreground). Instead of using that loop that copies 32 bytes to $3F00 you can code a loop to copy any number of bytes you want to any address you want.

If you want to update only the background palettes (the 4 of them), copy 16 bytes to $3F00. Want to update only the sprite palettes? Then copy 16 bytes to $3F10. It all depends of which palettes you want to update, you are not forced to update them all at once.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

Yeah, I was using many parts of the GBAGuy's tutorial, but before I start correcting the Init code things, let's do the pallete thing. I've added a new label called bkgpal after the tilepal label, like this:

Code: Select all

tilepal:
	.incbin "our.pal" ; include and label our sprite pallete
	
bkgpal:
	.incbin "bkg.pal" ; include and label our background pallete
And also, changed some things at the lines 22 to 49, now they are like this:

Code: Select all

	lda #$3F    ; have $2006 tell
	sta $2006   ; $2007 to start
	lda #$10    ; at $3F00 (pallete).
	sta $2008

loadsprpal:                ; this is a freaky loop
	lda tilepal, x  ; that gives 16 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 16, meaning we
	cpx #16         ; are done.
	bne loadsprpal     ; if X isn't =16, goto "loadpal:" line.

	lda #$20
	sta $2006 ; give $2006 both parts of address $2020.
	sta $2006 
	ldx #$00
	
loadbkgpal:                ; this is a freaky loop
	lda bkgpal, x  	; that gives 16 numbers
	sta $2009       ; to $2007, ending when
	inx             ; X is 16, meaning we
	cpx #16         ; are done.
	bne loadbkgpal  ; if X isn't =16, goto "loadpal:" line.

	lda #$20
	sta $2008 ; give $2006 both parts of address $2020.
	sta $2008 
	ldx #$00
But when I've started to emulate, I just displays a entire black screen with nothing.

What's wrong now?
PS: At least now I've tried to do it myself, without asking for code. :)

Best Regards,
Nathan Paulino Campos
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

You're pretty much just guessing, right...? OK, I'll try to help.

The palette is just a group of 32 bytes at address $3F00-$3F1F of VRAM. In order to modify the palette you have to write the colors you want to use to that location.

The code you copied from GBAGuy copies all 32 bytes from the "our.pal" file to that location. The "our.pal" file is nothing more than a list of colors. If you want the quickest and cleanest solution, just edit the "our.pal" file and change the first 16 values to those you want. That's all you have to do.

Now let me point out some things in your code that don't make sense. You had the VRAM address set to $2020 before trying to write your palette. That address is for a name table, you can't write your palette there. The palettes stay at $3F00.

Then you try to write the data to $2009. Where did you get the $2009 from? VRAM should always be written to through the register mapped at $2007.

The code you used should work if you fix it to set the VRAM address to $3F00 instead of $2020 and use register $2007 to write the data instead of $2009. But you should understand that the original 32 colors are still being used, you'll just overwrite the first 16 by doing it like that. The clean solution is to just modify the .pal file, like I said above.

Also, you don't have to use external files for palettes. You can very well write the colors you want directly in the source file, like this (which I find easier to work with than an external binary file):

Code: Select all

bkgpal:
	.db $0f, $11, $21, $31 ;palette 0
	.db $0f, $14, $24, $34 ;palette 1
	.db $0f, $18, $28, $38 ;palette 2
	.db $0f, $19, $29, $39 ;palette 3
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

Thanks very much! Now all is working. :)

Also, now I'm going to take a look on the Init code as you've suggested for me. ;)
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

also note that $2008,$2009 are not registers (they mirror $2000,$2001). So I'm not sure why you're writing to them.
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

Disch wrote:also note that $2008,$2009 are not registers (they mirror $2000,$2001). So I'm not sure why you're writing to them.
- Uh, yeah. Weird. o.O
User avatar
Orsi
Posts: 26
Joined: Sun Mar 21, 2010 7:15 am

Post by Orsi »

$2008 and $2009 are the registers used in the GBAguy tutorial. It left me confused as well.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

One more reason to get rid of his tutorials.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

Oh! :o
Wait, now I've tried to change the code as you said, but I still got the same black and empty screen. My code now:

Code: Select all

	lda #$3F    ; have $2006 tell
	sta $2006   ; $2007 to start
	lda #$10    ; at $3F00 (pallete).
	sta $2008

loadsprpal:                ; this is a freaky loop
	lda tilepal, x  ; that gives 16 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 16, meaning we
	cpx #16         ; are done.
	bne loadsprpal     ; if X isn't =16, goto "loadpal:" line.

	lda #$20
	sta $2006 ; give $2006 both parts of address $2020.
	sta $2006 
	ldx #$00
	
loadbkgpal:                ; this is a freaky loop
	lda bkgpal, x  	; that gives 16 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 16, meaning we
	cpx #16         ; are done.
	bne loadbkgpal  ; if X isn't =16, goto "loadpal:" line.

	lda #$3F
	sta $2006 ; give $2006 both parts of address $3F00.
	lda #$00
	sta $2006 
	ldx #$00
This is making me crazy! :?
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

You are doing things in the wrong order.

FIRST you have to set the destination address for the palette (through register $2006), THEN you write the data to register $2007. There is no reason for you to use the address $2020 (that address points to a name table, it has nothing to do with palettes) there in the middle, and your use of X is all messed up. You forgot to initialize it before the first loop, and you needlessly initialize it at the end.

I don't like to give out code (because people tend to just copy&paste it rather than study it), but this is the correction to the code you just posted:

Code: Select all

	;set the destination address for sprite palettes ($3F10)
	lda #$3F
	sta $2006
	lda #$10
	sta $2006

	;copy 16 colors
	ldx #$00
LoadSpritePalette:
	lda SpritePalette, x
	sta $2007
	inx
	cpx #16
	bne LoadSpritePalette

	;set the destination address for background palettes ($3F00)
	lda #$3F
	sta $2006
	lda #$00
	sta $2006

	;copy 16 colors
	ldx #$00
LoadBackgroundPalette:
	lda BackgroundPalette, x
	sta $2007
	inx
	cpx #16
	bne LoadBackgroundPalette
This will write the palettes to the correct locations. However, this is just a waste of space, you don't need 2 loops for that, you could very well just store the 2 palettes together (one after the other) and copy all 32 bytes using a single loop, like the original code did.

Nathan, let me give you some advice: You are clearly just guessing things, instead of trying to understand them. Guessing things until the program works is a very bad way of learning things, because in the end you don't know what you did right, it was pure luck. At this point, you should already have understood what $2006 and $2007 do, and you should already know where the palette and the name tables are in VRAM, so you shouldn't be making these silly mistakes of setting the wrong addresses.

If you don't know that stuff, then you should go back and read a bit more about the architecture of the NES before trying to code again. Knowing the memory map well and knowing how to write data to VRAM are things that every newbie has to understand before writing code, otherwise we'll keep being part of this frustrating cycle where you have no idea of what's happening and need others to fix the most basic things in your code.

If english is a barrier for you, you can always PM me or use the international forum and I'll try to explain stuff in portuguese, if you think that will help. But you have to do your part and study these things, because I will not have time to teach you about every little thing. I can help with stuff you don't get, but for this to work you must get some of it on your own.
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

Code: Select all

	
   ldx #$00
   lda $2002  ; clears the flip flop, you probably already did it before, no?
   lda #$3F
	sta $2006 
	lda #$10   ; sprite color RAM start
	sta $2006

loadsprpal:                ; this is a freaky loop
	lda tilepal, x  ; that gives 16 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 16, meaning we
	cpx #16         ; are done.
	bne loadsprpal     ; if X isn't =16, goto "loadpal:" line.

	lda #$3F
	sta $2006
	lda #$00
	sta $2006 
	
loadbkgpal:                ; this is a freaky loop
	lda bkgpal, x  	; that gives 16 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 16, meaning we
	cpx #16         ; are done.
	bne loadbkgpal  ; if X isn't =16, goto "loadpal:" line.
EDIT: Meh, Tokumaru was faster. :)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Zepper, you forgot to initialize X for the second loop.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

:lol: Dois brazucas vendo quem vai ser o primeiro a ajudar. :P
tokumaru Wins! :P

Thanks very much guys, now I promise that I'm going to study the code. ;)
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
Post Reply