darryl.revok wrote:From what I read, hBlank gives you 340 PPU cycles. If so, then does that equate to 1020 CPU cycles? (NTSC) That seems excessive.
No, no, you got it all wrong. There are 341 PPU cycles per scanline, 256 of which output pixels, 85 of which are hblank. The PPU is 3 times *faster* than the CPU, so you have to *divide* by 3 to find the corresponding number of CPU cycles, which is 28.3. It's not a lot of time at all, specially if you have rendering enabled, because the last few cycles (20 PPU cycles, I believe) are used to fetch NT and AT data for the next scanline.
So from what I'm reading, I have to have a blank scanline to change palettes. That's unfortunate. I'm guessing there's no workaround.
If not an entire scanline, at least some blanking near the sides of the screen, but you'll hardly be able to change many colors at a time that way.
So, a black scan line is what's needed for a mid-screen palette swap? That means if I have a strip of black sky, I can use the bottom row of that strip to switch my palette, right?
It's a blank scanline, not black. If black is your background color (color 0), then the scanline will be black, if color 0 is something else, that's the same color the blank scanline will be. Depending on the number of colors you have to change and where the values come from, 1 blank scanline might not be enough. In order to update 3 colors in a palette, you need something like this:
Code: Select all
lda Color1 ;pre-load the first color
ldx Address+1
stx $2006
ldx Address+0 ;preload the low byte of the address
ldy #$00
sty $2001 ;must finish as soon as hblank starts
stx $2006 ;4
sta $2007 ;4
lda Color2 ;3
sta $2007 ;4
lda Color3 ;3
sta $2007 ;4 = 22
That's 22 cycles out of the 28 of hblank, but there's the IRQ latency that depends on the instruction that was running when the IRQ fired, and you'll probably lose a couple of cycles to make sure the $2001 write doesn't happen before hblank starts. So yeah, if the color values come from ZP variables, it does seem possible to update 3 colors right in the first hblank, and then you can use the next scanline to reset the scroll and enable rendering on the next hblank.
So, the palette color getting written is drawn on the screen. I wonder if I can use this to my advantage. Is there any way to make it draw a single color across the entire screen? Like, utilizing a palette swap to change the BG color, and using the color written as a line on the image? For the tops of the sky strips that could work.
I don't understand what you want to do. If you want the entire screen to be the same color, why not do it the conventional way? If you just want to draw strips using any of the colors in your palette, then yeah, you can just change the VRAM pointer during hblank whenever you want to show another color. And you can even show the otherwise unrenderable colors at $3f04, $3f08, $3f0c.
And what is the trouble with leaving the PPU targeting a color that isn't color 0?
No trouble, that color will simply be rendered on the screen.
Make the last write the color you want the next scanline to appear (could even be the same color it already was)
The PPU address auto increments, so it actually points to the next color that will be changed, not to the one you just changed, so what you write last won't matter, but what was already stored in the slot after that.
Is there an easy explanation for how to do so carefully?

I never quite understood the details, but it has something to do with interrupting the sprite evaluation process. To be sure you'll not do that, I believe you have to turn rendering off as soon as hblank starts, since the latest the sprite evaluation process can extend to is the end of the visible scanline. Don't take my word for it though, it's better to look it up in past discussions.
Is there anything other than setting PPU to slave mode that could damage hardware?
I'm not sure, but I don't think it's easy to damage the hardware, considering that a bad connection between the cartridge and the cartridge slot could result in "random" code running and writing unexpected values to registers and such, and that happens somewhat often with the NES.