This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

What happens when disabling PPU in Hblank?

What happens when disabling PPU in Hblank?
by on (#232820)
After asking questions to Vectrex28 on twitter about how he was changing palette mid-screen, I learned that it was done during hblank (which I already had a doubt about it) and that he was disabling the ppu while doing so.

My question is, my assumption was that the PPU was disabled to some degree since it's in hblank, so what does happens when doing so? What is affected when disabling the PPU in hblank? I was able to change some color when keeping the PPU active but it seems more stable when deactivating it.

I don't remember reading anything about it so it must be something I missed on the subject.
Re: What happens when disabling PPU in Hblank?
by on (#232821)
Banshaku wrote:
My question is, my assumption was that the PPU was disabled to some degree since it's in hblank, so what does happens when doing so?
Not really disabled. The only real thing is that the PPU is not sending pixels to the screen, but it's still 100% busy internally.

Every two pixels it reads some value from the PPU's address bus. Every pixel it does something to OAM.

Quote:
What is affected when disabling the PPU in hblank? I was able to change some color when keeping the PPU active but it seems more stable when deactivating it.
... I thought you couldn't successfully write to the PPU's memories without being in vertical or forced blanking.

Certainly for normal writes to OAM or not-palette space will cause a condition where both /WR and /RD are true at the same time. Visual2C02 implies writes to the palette don't happen at all during hblanking if rendering is still enabled.
Re: What happens when disabling PPU in Hblank?
by on (#232824)
Quote:
I thought you couldn't successfully write to the PPU's memories without being in vertical or forced blanking.


When I tested this, there was a huge difference between trying it in an emulator and on a real NES. It only seems to work fine in emulators, if perfectly timed, but fails on hardware.
Re: What happens when disabling PPU in Hblank?
by on (#232825)
lidnariq wrote:
Not really disabled. The only real thing is that the PPU is not sending pixels to the screen, but it's still 100% busy internally.

I think there's an important distinction that it's not going to increment the address while it's disabled, though.

lidnariq wrote:
Certainly for normal writes to OAM or not-palette space will cause a condition where both /WR and /RD are true at the same time. Visual2C02 implies writes to the palette don't happen at all during hblanking.

I don't understand this statement. How is this ROM I wrote able to change palette during the horizontal blank?
http://forums.nesdev.com/viewtopic.php?f=3&t=13264
Re: What happens when disabling PPU in Hblank?
by on (#232826)
Well, the first half of it was me making an edit-o. The latter half is just me reporting what I saw in testing in Visual2C02.
Re: What happens when disabling PPU in Hblank?
by on (#232827)
Or wait, I guess I'm confusing two cases. You mean that if rendering isn't disabled, i.e. forced blank within hblank, then you can't actually write the palette in hblank?

(The ROM I linked does write 0 to $2001 before writing the palette during hblank.)
Re: What happens when disabling PPU in Hblank?
by on (#232828)
I mean that I asked Visual2C02 to time two writes to $2006 and a write to $2007 to cause a write to the PPU palette memory during hblanking without turning off rendering first, and the data didn't go through.
Re: What happens when disabling PPU in Hblank?
by on (#232829)
i do this for the textbox at the bottom of the screen in my game, the IRQ first waits strictly until the H blank period by with one of those "wait a specific amount of cpu cycles" loops ..until it's at like PPU pixel 270 or whatever ...turn off the PPU, and update 1 color as fast as possible where you preload the 2006/2007 LDX/LDY/LDA right about ppu pixel 230-ish ..just when it's about to begin.

wait another full scanline until next H blank, update 2nd color, and again for the 3rd color.

Disch helped me with this when i first implemented it many years ago. About getting the timing just precise.

Some emulators do flicker those "dot crawl" on the very right edge of the screen in certain places. :( ...fceux is totally 100% fine.
Re: What happens when disabling PPU in Hblank?
by on (#232830)
For my status bar, I've timed it to where the second write to $2006 happens just after hblank starts. Then you can write 3 colors in one go (I don't have to reset the scroll since there is a gap between the status bar and the playing field and rendering is disabled).

Code:
         ldx pal_RAM + 10                      ; change $3F09, $3F0A, $3F0B
         ldy pal_RAM + 11
         lda #$3F
         sta PPU_ADDR
         lda #$09
            jsr func_Nop60
         sta PPU_ADDR                          ; hblank has started
         lda pal_RAM + 9
         sta PPU_DATA
         stx PPU_DATA
         sty PPU_DATA


The vram address then points to entry #0 (or a mirror) and I don't get a garbage line across the screen while waiting for the next hblank to update more of the palette.

That only works if your gap matches the color of entry #0.

edit: for clarity
Re: What happens when disabling PPU in Hblank?
by on (#232831)
If I'm working through Visual2C02 correctly, palette reads and writes depend on the contents of the PPU's physical address bus, not the "v" or "t" scrolling registers.
During active PPU operation A12 and A13 are never both high simultaneously, not even in response to register writes.
So if I'm reading things correctly, it should be impossible to write to the palette while rendering is happening, period.
Re: What happens when disabling PPU in Hblank?
by on (#232833)
I should have added that I have rendering disabled during the gap, and by vaddr I meant whatever is used to show the behavior described in the wiki.
Re: What happens when disabling PPU in Hblank?
by on (#232835)
woa is your routine really that short ? dang mine is moderately long. and it's been years since i looked at it, i actually updated 2 colors on first H blank, and the 3rd color on 2nd H-blank, so i only did it twice. But there was still 1 more scanline of waiting. :|

Maybe i should show what mine looks like, and you might be able to make it shorter.

Also i apparently reset the 2006 thing after the first 2 colors to PPU 0000 (not 3F00 like you said)...and then 02E0 after the 3rd color, cause if i didn't then it wont point to the right area of the NES nametable thing where the textbox is at
Re: What happens when disabling PPU in Hblank?
by on (#232839)
That snippet only does 3 colors, but I do it 4 times to change half the palette. Basically it goes:

NMI fires
-write status bar palette
-swap in status bar chr
-change to name table B

<status bar gets drawn>

IRQ fires
-disable rendering
-change bkg palette #2
-swap in gameplay chr
-wait for hblank, change bkg palette #3
-change to name table A
-wait for hblank, change bkg palette #4
-wait for hblank, change spr palette #1
-wait for hblank, set the scroll, enable rendering

<playing field gets drawn>


Note: I use single screen mirroring with the playing field in A and the status bar in B.
Re: What happens when disabling PPU in Hblank?
by on (#232853)
It was a good thing I asked that question! If I didn't, I would have had some interesting surprise later.

The reason I didn't turn ppu off is because of my wrong assumption that hblank should be similar to vlbank in some way (first error). The second one is, when testing with mesen and fceux, it allows me to change the color when ppu is on as long that I time my code to be inside hblank, everything is fine. This means you have to be careful to test timed code in hblank with those 2.

What made me research more on the subject was that nintendulator was not reacting the same: it was either not changing the color and creating a lot of flickers or the artifact were occurring at a different place. For now, nintendulor may be the closest to what happens on hardware then.

As for why I didn't test on hardware, it's because I started to code that part this week and my current setup speed is like "doing it like it's 1985" (i.e. it takes 5 minutes by epprom so I don't feel to use that writer much. Maybe it was even faster in 1985, actually :lol:) so I didn't test yet.

As for the dot crawl when color of background is different (first NT is blue, change one color then switch in NT that is black), nintendulator does show some artifact, all the time. Does PPU/CPU sync that I asked it another thread would make it more stable then?
Re: What happens when disabling PPU in Hblank?
by on (#232877)
Banshaku wrote:
What made me research more on the subject was that nintendulator was not reacting the same: it was either not changing the color and creating a lot of flickers or the artifact were occurring at a different place. For now, nintendulor may be the closest to what happens on hardware then.
As far as I can tell from the source, Nintentulator doesn't appear to prevent palette writes during HBlank, whether or not rendering is disabled.

In the code, the 2nd write to $2006 immediately changes VRAMAddr, and then writes to $2007 change the palette if VRAMAddr is still >= $3F00. There isn't any extra logic beyond this, so my best guess is that the value of VRAMAddr was changed between your $2006 & $2007 writes. But it also looks like VRAMAddr doesn't get changed beyond the usual stuff (H/V scroll increments, etc.), so not quite sure what could be causing the difference in this particular case.

It does, however, look like read/writes to $2007 will do nothing if rendering is not disabled. The VRAM increment (by 1 or 32) is still triggered. This only applies to non-palette read/writes, so it doesn't explain the behavior you're seeing.

As a quick test, preventing all reads/writes to $2007 (including palette) when rendering is enabled & before scanline 240 changes absolutely nothing to the 230 recorded tests I have (these are all test roms), so that's a good start. I don't have any recorded tests for actual games to try, though, unfortunately.
Re: What happens when disabling PPU in Hblank?
by on (#232878)
Also, the rendering Y scroll is incremented on the second write to 2006...(if you write to the screen during rendering)

http://wiki.nesdev.com/w/index.php/PPU_ ... 8w_is_1.29

...shifting the screen up 1 pixel below the place where the second 2006 write occurred.
Re: What happens when disabling PPU in Hblank?
by on (#232881)
Sour wrote:
In the code, the 2nd write to $2006 immediately changes VRAMAddr, and then writes to $2007 change the palette if VRAMAddr is still >= $3F00.
I did actually mention this above, but I didn't call it "VRAMAddr". In Visual2C02, it looks like it's explicitly the physical address on the address bus that controls whether reads come from and writes go to the palette. And although the second write to $2006 does immediately update "loopy_v", that value isn't what appears on the address bus during rendering.
Re: What happens when disabling PPU in Hblank?
by on (#232907)
@sour

I didn't meant to imply that one emulator may do it better than the other but more that the behavior was different and had artifact, like some people mentioned, when switching to a nametable with a different color. Which meant "maybe" nintendulator could have been closer to the nes hardware but unless that I test my own code on hardware myself, it was just speculation. Now from looking at the code, there seems to be no special processing and the behavior may be not appropriate too.

I guess this specific scenario only affect people that creates new games and need to do special effect (albeit the time to do it in hblank is quite short) so it's no priority to get it to work like the hardware right away. Still, the timed code part got half of it right so it was already a good start.

I'm curious what happens on real hardware when you forget to close the PPU (I guess nothing is written and garbage occurs?). Still, emulators today improved so much compared to 10 years ago that the case that we need to absolutely test on hardware to confirming the real behavior are becoming smaller, which I'm quite grateful of such a time saver ;)
Re: What happens when disabling PPU in Hblank?
by on (#232952)
lidnariq wrote:
I did actually mention this above, but I didn't call it "VRAMAddr". In Visual2C02, it looks like it's explicitly the physical address on the address bus that controls whether reads come from and writes go to the palette. And although the second write to $2006 does immediately update "loopy_v", that value isn't what appears on the address bus during rendering.
I was actually just referring to the variable name in Nintendulator's code here. A bit unrelated, but I'm curious how the bus actually works: during rendering (scanline -1 to 239), the PPU puts the address it needs to fetch the data on the bus, and any register writes will directly set the bus to that address (but the PPU's next fetch will be affected by the new value)? When scanline 240 begins (or when rendering is turned off), the bus returns to the current value of "VRAMAddr" and keeps that value until the prerender line? (unless changed by register writes)

So, because the bus' value is controlled by the PPU during rendering, and the PPU never fetches anything in the $3000+ range, it's impossible to write to the palette during this time. Whereas writes to $0000-$2FFF via $2007 are possible, but will (almost?) never write to the correct address, because writing to $2006 during rendering will update VRAMAddr, but will not have an immediate impact on the bus' current value (but it will have an impact on the bus' value the next time the PPU reads VRAMAddr to fetch a byte for rendering purposes)?

I'm sure I'm missing some details & oversimplifying, but is this more or less how it works? If so, I can probably make a few changes to my PPU code to prevent stuff like writes during HBlank from working properly without too much trouble.

Banshaku wrote:
I didn't meant to imply that one emulator may do it better than the other
No worries (and to be fair, Nintendulator does go more in-depth than Mesen when it comes to emulating the PPU's internal state), I'm just genuinely interested in making this more robust in Mesen if possible, especially since it would likely have no impact on performance.
Re: What happens when disabling PPU in Hblank?
by on (#232963)
Sour wrote:
during rendering (scanline -1 to 239), the PPU puts the address it needs to fetch the data on the bus
Yes.
Quote:
, and any register writes will directly set the bus to that address (but the PPU's next fetch will be affected by the new value)?
Typo? I assume you mean "will not directly set"
Quote:
When scanline 240 begins (or when rendering is turned off), the bus returns to the current value of "VRAMAddr" and keeps that value until the prerender line? (unless changed by register writes)
I believe that's accurate.

Quote:
So, because the bus' value is controlled by the PPU during rendering, and the PPU never fetches anything in the $3000+ range, it's impossible to write to the palette during this time. Whereas writes to $0000-$2FFF via $2007 are possible, but will (almost?) never write to the correct address, because writing to $2006 during rendering will update VRAMAddr, but will not have an immediate impact on the bus' current value (but it will have an impact on the bus' value the next time the PPU reads VRAMAddr to fetch a byte for rendering purposes)?
That also sounds accurate.



Quickly tracking down the PPU A8 signal in Visual2C02...

* It's synchronized on left half dots (t13798)

There's a five-way analog multiplexer behind this, selecting between
* Vcc during attribute fetches = node 1162 (+hpos_eq_0-255_or_320-335_and_hpos_mod_8_eq_2_or_3_and_rendering)
* vramaddr_+v8 during node 2047 (must be used for both nametable fetches and the inactive portion)
* node10730 during node 1275 (node 10730 is just a floating node... node 1275 is part of the "CPU writes to $2007" handler)
* node 9110 during node 1963 = pattern table fetch
** Node 9110 ultimately comes from another multiplexer,
** ultimately spr_d4, after nodes 1870, 328 (++hpos_eq_256_to_319_and_rendering), and a right half dot
** ultimately _db4, after a right half dot, and nodes 1870 and 1910 and another (the same) right half dot

In contrast, PPU A13 (still synchronized on left half dots) only has a two-way analog multiplexer, selecting between
* Ground during node 1963 (pattern table fetch)
* node 2042 during node 2047 or attribute fetches (1162)
** node 2042 is ultimately OR(vramaddr_+v13 , rendering_1)

PPU A12 is the one that does all the dirty work, because it has to be able to operate in the most different ways.
bkg_pat_out, spr_pat_out, spr_d0 (8x16 mode), NOR(vramaddr_/v12, rendering_1)



oh. ... huh, the timing glitches we saw on [$2000] & 3 or writes to $2005 and $2006 should also happen to [$2000] & $38, but only for a single sliver.
Re: What happens when disabling PPU in Hblank?
by on (#232971)
lidnariq wrote:
Typo? I assume you mean "will not directly set"
Whoops, yea, I meant "will not" there.

So, I've been playing around with Visual NES a bit. It looks like the bus' address reverts to the current value of VRAMAddr on scanline 240, cycle 1. And then on the prerender scanline (-1) at cycle 1, it goes back to being whatever address the CPU is using for rendering (this is probably just the result of the PPU fetching the first NT byte)

I used a ROM that enables BG rendering only and keeps running this loop:
Code:
-:
  STX $2007
  INX
  JMP -
Here's what the memory looks like after running it for a good 15+ full frames:
Attachment:
VramTesting.png
VramTesting.png [ 54.77 KiB | Viewed 3634 times ]

lidnariq wrote:
oh. ... huh, the timing glitches we saw on [$2000] & 3 or writes to $2005 and $2006 should also happen to [$2000] & $38, but only for a single sliver.
Still haven't gotten around to implementing that one (or fully reading the thread, either), hoping to get to that relatively soon, though.
Re: What happens when disabling PPU in Hblank?
by on (#232972)
Sour wrote:
Still haven't gotten around to implementing that one (or fully reading the thread, either), hoping to get to that relatively soon, though.
Well, the shoot-through glitches only happen on certain alignments, so I'm not entirely certain when it's appropriate to emulate.
Re: What happens when disabling PPU in Hblank?
by on (#232980)
Did some more testing and noticed that, in Visual NES, the code ended up writing proper values to CHR RAM starting at around $185 during vblank. I get something similar in Mesen (but it starts around $1A5 instead). I tried adding/tweaking the logic to suppress the V/H increments on write during rendering (e.g don't do them if the PPU is also doing them for its regular rendering on this cycle, like Nintendulator does), and while that does change the exact addresses that get written to, it usually ends up writing around $2185, instead (presumably because it did a few too many or too little vertical increments).

Either way, I think this is probably good enough - the real idea here is just preventing devs from being able to write to the palette/chr/nametables during HBlank without disabling rendering. The exact pattern created by the small test I wrote most likely varies based on CPU/PPU alignment and the like, anyway.

lidnariq wrote:
Well, the shoot-through glitches only happen on certain alignments, so I'm not entirely certain when it's appropriate to emulate.
That was actually one of my questions. I guess in that case it would make more sense for this to be an option, e.g "Emulate CPU-PPU alignment-specific glitches" or the like (and disabled by default, because nobody wants to see scroll glitches while playing Zelda!)
Re: What happens when disabling PPU in Hblank?
by on (#232995)
Sour wrote:
Did some more testing and noticed that, in Visual NES, the code ended up writing proper values to CHR RAM starting at around $185 during vblank. I get something similar in Mesen (but it starts around $1A5 instead). I tried adding/tweaking the logic to suppress the V/H increments on write during rendering (e.g don't do them if the PPU is also doing them for its regular rendering on this cycle, like Nintendulator does), and while that does change the exact addresses that get written to, it usually ends up writing around $2185, instead (presumably because it did a few too many or too little vertical increments).
I suspect it will smear the write across multiple bytes, for analog reasons.

The $2007-triggered rd cadence is aligned to pixels: ALE, idle, /RD, each for one aligned whole dot. However, it looks like $2007-triggered writes are not aligned. ALE is a left and right half dot; idle is just one left half dot; /WR is asserted for a right half dot but with the wrong value on the data bus, and then /WR is asserted for just a left half dot more with the correct value on the bus. (* note: this should be verified on hardware)

This should collide with the normal rendering cadence (left half dot: ALE. right half dot: idle. one aligned whole dot: /RD).

Internally to the PPU, if /RD is asserted, the multiplexed bus is high impedance, regardless of what the earlier multiplexers say should be presented.
Re: What happens when disabling PPU in Hblank?
by on (#233002)
I may be getting closer to find the source of a bug that I had for a long time and it "may" be related to doing things in hblank. My question would be, it is possible that if I write to 2005 inside a MMC3 IRQ but not in hblank, weird things could occurs?

For example (it's not the complete code), if I comment out this part of code:

Code:
   bit PPU_STATUS
   lda #0                     ; location of scroll
   sta PPU_SCROLL


which is used to reset position of scroll X in second NT (nt was selected just before), now my palette refresh code inside NMI is working fine by waiting for NMI. I put this part of the code only, palette refresh doesn't work anymore.

It's an odd bug but I'm getting closer to the source of the error. Maybe there is something else triggering the bug but now, at the least, I know where inside IRQ that makes it fails. Before, I only knew something related to IRQ was causing it but not what.

edit:

Found my bug, at last: changing the scroll affect the latch, which means when it try to write to the palette, you need to reset the latch with bit PPU_STATUS. I didn't realize it was affecting the palette too but it just make sense because you change the address and it may end up in the wrong location. I feel ashamed to make such a simple mistake for a long time :lol:
Re: What happens when disabling PPU in Hblank?
by on (#233028)
Sour wrote:
I guess in that case it would make more sense for this to be an option, e.g "Emulate CPU-PPU alignment-specific glitches" or the like (and disabled by default, because nobody wants to see scroll glitches while playing Zelda!)

To my knowledge, the scroll glitching in Zelda (tested with split_scroll_test_v2) occurs regardless of alignment, though it looks like one of the alignments caused my writes to appear to take effect one dot early. The single-scanline issues seen in the ppu_xxxx_glitch tests are the ones that are only present on some alignments.
Re: What happens when disabling PPU in Hblank?
by on (#233032)
Fiskbit wrote:
To my knowledge, the scroll glitching in Zelda (tested with split_scroll_test_v2) occurs regardless of alignment
Right. The shoot-through glitches are the ones that only happen on some alignments if the CPU write starts during the right half of dot 257.

The Zelda glitches are bus conflicts due to colliding increment and reload operations, and occur
1- to all 15 bits of both vramaddr_v and _t if the CPU's second write to $2006 finishes during dot 256.
2- to all six coarse horizontal position bits in both if the CPU's second write finishes during dot X where X%8 = 0 and (X≤256 or X=328 or X=336)