Reading Palettes via $2007?

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
User avatar
TylerBarnes
Posts: 17
Joined: Tue Mar 19, 2019 12:41 pm

Reading Palettes via $2007?

Post by TylerBarnes » Tue Nov 05, 2019 1:30 am

Anyone have the secret sauce on reading palettes from the PPU via $2007? I know it is not buffered like normal reads from VRAM since palettes are stored on the PPU itself, but everytime I try to read palettes to save in RAM, I get values from my name table. I'm doing this in my NMI with other graphics updates.

Code: Select all

Routine:                      
    LDA $2002                  ; Clear Hi/Lo Latch
    LDA #$3F                   ; Opening the port $3F00
    STA $2006                  ; to read palette data
    LDA #$00 
    STA $2006 
    TAX                        ; Use #$00 already in A as an X offset.
SaveCurrentPalette:
    LDA $2007
    STA TempPalette, x
    INX 
    CPX #$20                   ; Do this 32 times to aquire both palettes
    BNE SaveCurrentPalette
The pallet I loaded into the PPU at bootup:

Code: Select all

$3E,$16,$36,$3E,$3E,$27,$37,$3F,$3E,$27,$36,$17,$3E,$3E,$3D,$0C
$3F,$1A,$3A,$0B,$3F,$16,$36,$06,$3F,$27,$38,$17,$3F,$20,$3D,$2D

What I get after this routine tries to read the pelette to store into ram. These value are present in my .nam and the first $9A you see there starts at $0260 of that file. That $00 would no doubt be the throw away buffer read.

Code: Select all

$00,$9A,$9A,$9A,$BE,$99,$99,$99,$99,$99,$99,$99,$99,$99,$99,$99
$99,$99,$99,$99,$99,$99,$99,$99,$99,$99,$99,$99,$99,$CD,$BF,$9A

User avatar
tokumaru
Posts: 11772
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Reading Palettes via $2007?

Post by tokumaru » Tue Nov 05, 2019 2:47 am

Is this on hardware or on an emulator? Have you tried multiple emulators?

BTW, even though the palette is mapped to a 32-byte window, it doesn't actually have 32 colors. The PPU only has 28 actual slots for colors (4 colors for each background palette + 3 colors for each sprite palette), and only 25 are displayed under normal circumstances (color 0 from the first background palette is used for all background palettes). I'm telling you this because the first slot in each sprite palette is a mirror of the first slot in the respective background palette, so those $3Fs you have in the sprite palettes are simply overwriting the $3Es you had before.

User avatar
dougeff
Posts: 2712
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Reading Palettes via $2007?

Post by dougeff » Tue Nov 05, 2019 5:08 am

You can only read from the PPU during v-blank or with the screen off.

If you do it during rendering, you just get the value of the tile that it just drew on the screen, and writing an address during rendering would misalign the scroll.
nesdoug.com -- blog/tutorial on programming for the NES

lidnariq
Posts: 9510
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Reading Palettes via $2007?

Post by lidnariq » Tue Nov 05, 2019 11:11 am

Also note that the oldest NESes, and older Famicoms, don't permit reading the palette at all.

User avatar
TylerBarnes
Posts: 17
Joined: Tue Mar 19, 2019 12:41 pm

Re: Reading Palettes via $2007?

Post by TylerBarnes » Tue Nov 05, 2019 11:13 am

tokumaru wrote:Is this on hardware or on an emulator? Have you tried multiple emulators?
Good call, other emulators are having different effects. Was using FCEUX because of the monitors, tried Nestopia with a better result. I will bust out the flash cart when I'm home from work.
tokumaru wrote:so those $3Fs you have in the sprite palettes are simply overwriting the $3Es you had before.
Good catch, that is a mistake. They are just supposed to be 3E black. Them both displaying black made me miss that.
dougeff wrote:You can only read from the PPU during v-blank or with the screen off.

If you do it during rendering, you just get the value of the tile that it just drew on the screen, and writing an address during rendering would misalign the scroll.
I though doing this in NMI was waiting for V-Blank. My NMI looks like

Code: Select all

NMI: 
   JSR UpdateSprites
   JSR CheckRoutine
   JSR CheckController
   RTI
And in reality my routine has a check before it so I'm setting a flag elsewhere and reseting it at the end of the Routine.

Code: Select all

 CheckRoutine: 
   LDA RoutineTrigger
   CMP #$01
   BNE SkipRoutine
   JSR Routine
SkipRoutine: 
   RTS 
Even though I'm in NMI is it better practice to store #$00 into $2000 disable the PPU, then and bring it back online with #%10001000 after I'm done reading $2007? Or is that not needed at all since I'm in V-Blank?

User avatar
TylerBarnes
Posts: 17
Joined: Tue Mar 19, 2019 12:41 pm

Re: Reading Palettes via $2007?

Post by TylerBarnes » Tue Nov 05, 2019 11:18 am

lidnariq wrote:Also note that the oldest NESes, and older Famicoms, don't permit reading the palette at all.
Hmmm, So then I guess my method may just be for nigh then. Compatibility is important, and I can already think of alternative ways for what I want to do without reading from the PPU.

Thanks guys!

User avatar
tokumaru
Posts: 11772
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Reading Palettes via $2007?

Post by tokumaru » Tue Nov 05, 2019 1:07 pm

TylerBarnes wrote:I though doing this in NMI was waiting for V-Blank.
While it's true that code that's supposed to run during vblank goes in the NMI handler, just putting it there doesn't guarantee it will actually run during vblank. Code in the NMI handler can take too long to execute and end up spilling into the visible picture. Just make sure that this is not happening.
Even though I'm in NMI is it better practice to store #$00 into $2000 disable the PPU, then and bring it back online with #%10001000 after I'm done reading $2007? Or is that not needed at all since I'm in V-Blank?
It's not needed, but it does protect you against VRAM corruption in case your PPU updates take too much time and spill into the visible picture - instead of permanent corruption, the screen simply "jumps" for a frame.

I like to use every last drop of vblank time in my engines, so I usually don't include these kinds of safety measures (e.g. resetting the $2005/6 latch, disabling/enabling rendering, etc.), but then I have to be extra cautious about the rest of the code so that this never becomes a problem.

Post Reply