- For making cartridges of your Super NES games, see Reproduction.
So I've been messing with f-blank at H-interrupts on screen, when I noticed something odd about how sprites are handled during f-blank in h-blank.
I've created a small demo program which creates a different screen on emulators compared to hardware - It seems to differ on all emulators I've tried, including ZSNES, SNES9X and BSNES+.
I'm not exactly sure what happens, but I reckon it's because the forced blank means that the ppu only loads the latter sprites rather than the earlier ones.
But I will say, force blank being on does prevent sprite caching. anomie mentioned it can take up to a full scanline before sprites will start acting normally again whenever you force blank. It's insidiously difficult behavior to reverse engineer without a logic analyzer, which is why emulators do a bad job at it.
Yeah, the Titan Overdrive group was exactly what I was thinking of. You can ask 94143, Lolida, etc ... I'm eager to work with homebrew devs to emulate new behaviors, but it's absolutely no fun when the goal is to antagonize us (with the obvious fact that no emulator is perfect.)
My bandwidth is a bit low at the moment, but I'll try to get to this when I can, thanks! Since I don't have my SNES set up here yet, would you be able to post a picture of how it looks on hardware? Preferably on something that isn't a 1CHIP or a Mini.
Aside: it hasn't landed in main yet, but I also just revamped sprite cache timing, which was causing a glitch in Megalomania. I'd imagine it'll have an effect on this demo.
PAL 3CHIP & PAL 1-CHIP: Correct behavior screen
NTSC CPU-APU & NTSC 1-CHIP: Showing left half Emulator suxx & right half correct behavior screen
All consoles: Showing left half Incorrect behaviour& right half correct behavior screen.
1-CHIP has a purple bar on the side.
Wait, what?!?paulb_nl wrote:I am getting varying results on my consoles.
So I tuned this to work on my 3 chip PAL SNES, so the first image makes sense.
I must've changed something by accident between the first and second versions, because that should still work.
NTSC is slightly wrong, which I should've seen coming. The overlaying image which says that it's an emulator is made of four sprites at 64x64, so it makes sense that the two righter sprites are just not getting loaded in the h-blank. Confusingly, these are in sprite slots 2 and 4, so their position on screen matters more than their position in OAM.
The most interesting is that the 1-chip has a purple bar, which I totally didn't expect. It goes without saying that the colour purple is nowhere in the demo.
I feel that this needs far more looking into than this demo provides, which you lot most likely have already done much of.
Sorry if I'm coming in a repeating a lot of what you already know.
Code: Select all
8081f1 lda #$8280 A:8282 X:0000 Y:0090 S:1ff5 D:0000 DB:80 NvmXdIzC V:231 H:233 F: 9 8081f4 sta $2100  A:8280 X:0000 Y:0090 S:1ff5 D:0000 DB:80 NvmXdIzC V:231 H:238 F: 9 8081f7 sta $2102  A:8280 X:0000 Y:0090 S:1ff5 D:0000 DB:80 NvmXdIzC V:231 H:245 F: 9
Code: Select all
8081f1 lda #$82ff A:8282 X:0000 Y:0090 S:1ff5 D:0000 DB:80 NvmXdIzC V:233 H:235 F: 9 8081f4 sta $2100  A:82ff X:0000 Y:0090 S:1ff5 D:0000 DB:80 NvmXdIzC V:233 H:239 F: 9 8081f7 sta $2102  A:82ff X:0000 Y:0090 S:1ff5 D:0000 DB:80 NvmXdIzC V:233 H:247 F: 9
$80 (%10000000) ends up in $2100. This sets forced blanking (bit 7 = 1) and sets the screen brightness to black (0) (bits 3-0 = 0).
$ff (%11111111) ends up in $2100. This sets forced blanking (bit 7 = 1), sets undefined bits (bits 6-4) to 1, and the screen brightness to full (15) (bits 3-0 = 1).
I don't know if this is a problem specific to the 1-CHIP itself or if your units are RGB-modded. In either case, the cause is identical to what ikari_01 described here.
The short of it: author either needs to keep track of the screen brightness using a variable somewhere in DP/RAM and ensure the value is kept consistent throughout all $2100 writes when forced blanking is enabled -- or if there's no reason to, then just hard-code the same screen brightness value universally. Use whatever approach you want for implementation (i.e. code it however you wish).
I say all of this without having looked at the code/a disassembly or trace session of said ROM.
On an unrelated (to the last post, but related to the subject in general): don't miss what nocash mentioned in his documentation for $2100, just in case there's any cases of "garbage" being shown on-screen.
Seems like a useful effect to emulate once SNES system PCB revision selection is implemented (they all report 2/1/3 so that's not enough), but I'll need a good test ROM. Does anyone have that old example test ROM of the red to black gradient, and the picture of how it looks on a 1CHIP system, handy?I don't know if this is a problem specific to the 1-CHIP itself or if your units are RGB-modded. In either case, the cause is identical to what ikari_01 described here.
I'm thinking I can emulate this by making a new class that, on each cycle, updates the true value to be closer to the new value by a fixed percentage, eg: currentValue = writtenValue*0.001 + currentValue*0.999 and repeats every dot clock. Adjust the weights until the output matches hardware. Take the actual value as round(currentValue) for outputting a picture (it didn't appear to be a smooth transition to imply there could be more than 16 states ...)
Pretty much all major remaining issues in SNES emulation come down to analog effects at this point.
SNES DSP mute, randomization of SRAM and DRAM on power-up, 1CHIP PPU display brightness.
Throw in bus contention issues (DMA+HDMA at the same time, CPU+SMP driving the I/O ports at the same time), and proper PPU latching times, and we'd be almost perfect.
Far as I know, it's the latter. Force blank inhibits all of the internal latching of tiledata / attributes / etc, so when you turn the screen back on mid-scanline, it will be using stale state until everything gets reloaded. And depending on what it is (eg mode 7 parameters, sprite fetches), junk can get latched for the entire scanline as a result.Forced blank doesn't apply immediately... so one must wait whatever
(maybe a scanline) before VRAM can be freely accessed... or is it only
vice-versa: disabling forced blank doesn't apply immediately/shows garbage
I have been experimenting with the game Aladdin which disables forced blank on line 8 in h-blank.byuu wrote: Far as I know, it's the latter. Force blank inhibits all of the internal latching of tiledata / attributes / etc, so when you turn the screen back on mid-scanline, it will be using stale state until everything gets reloaded. And depending on what it is (eg mode 7 parameters, sprite fetches), junk can get latched for the entire scanline as a result.
There are no sprites visible on line 9 on hardware but bsnes does show sprites. You can see the top of the lamp is missing:
If I patch the game to disable forced blank on line 8 before visible pixel ~207 then sprites do show up the next line. Some garbage sprites also show up sometimes but that is to be expected.
So here's what's happening:
This demo is enabling force blanking from Hclock = ~986 to ~1136.
Tile fetching in higan happens between 1162 and 1228. Sprite evaluation happens all at once at Hclock = 0.
Mesen-S does both of these at Hclock = 1140 (or Hdot 285), and chooses to do no on-scanline sprite evaluations, and no tile fetching, when force blanking is on. I guess in Mesen-S, timing is a bit further ahead and the demo still has force blanking on at H = 1140.
Basically, your demo requires that the on-scanline sprite evaluation portion of the sprite processing must not occur when force blank is enabled between 986 - 1136.
There is of course no way that process is going to occur instantaneously, of course. So that's why sometimes you were getting only half the screen updating, and half not.
I can patch this code to run correctly, but it's just yet another minor bandaid on the leaking dam that is PPU cycle timings. We're not going to stop running into these problems until exact cycle timings are known and emulated.