Accessing OAM during H-blank

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Accessing OAM during H-blank
by on (#65529)
This morning my brain hatched the idea of using H-blank IRQs to allow the sPPU to display up to 900 small sprites at once. It requires updating 16 bytes in the OAM per line. I'm not quite sure if I'm allowed to do that on real hardware, so I'm asking that here? If there are any quirks or hardware bugs to watch out for please tell me. What emulator would I need to test it out properly?

by on (#65531)
No substitute for a SNES in this case. You might also be able to use HDMA for this, perhaps getting more writes into hblank. Maybe even a combination of the two, with the HDMA doing the first 8 writes to whatever registers, then the CPU finishing it.

by on (#65544)
At least on the GBA, it's definitely doable on hardware, and in fact, that's how Super Puzzle Fighter II displays its playfields. But I've never seen it done on the Super NES; you'll definitely want to try that on hardware.

by on (#65550)
I think having 900 8x8 sprites could make the Snes more programmer friendly since you no longer have to rely on 2 sizes at one time, and the collumn/row sprite pattern allocation.

by on (#65562)
OAM is not supposed to be accessed during any portion of the active display or Hblank, unless force blank is enabled.

If you try and do it anyway, the writes will not go to OAMADDR, but will instead go to whatever the S-PPU is currently fetching for its internal processing.

During the active display area, it builds a sprite item cache. It first fetches data from the low attribute table; and then once it's done, from the high attribute table.

Your write during Hblank will end up going to the high attribute table address of the last sprite the S-PPU fetched. Even if you hit a patch of empty scanlines, the address is still the last sprite fetched. Rewriting OAMADDR during Hblank will not help you.

Also note that the PPU fetches sprite information for the next scanline, and not the current one, for obvious reasons.

I would strongly recommend you stick to real hardware if you are still crazy enough to try this. Your best bet for playing with this effect in an emulator would be bsnes using the dot-based renderer, here:
http://bsnes.googlecode.com/files/bsnes_v067r04.tar.bz2
(Get the DLLs from v067 official here: http://bsnes.googlecode.com/files/bsnes_v067.zip)

Any other emulator will just allow your write to go wherever you set OAMADDR to, regardless of whether or not the screen is in force blank, active display, Hblank or Vblank.

Lastly, for fun, I will note that Uniracers in two-player mode does exactly what you suggest, but does it for only two sprites. Every other SNES emulator uses hacks to get that game playable as a result.

by on (#65582)
So it leave off on the highest numbered sprite that appears on the scanline in the extra 32 bytes?

by on (#65589)
Yes, writing to OAM during Hblank goes to:

Code:
uint16 addr = 0x0200 + (last_accessed_sprite_item >> 2);
memory::oam[addr] = (uint8)data;


As you should know, the extended 32-bytes encode data for four sprites at a time. It control d8 of X and the size of the sprite (small or large.) It's not a very useful thing to be able to write to, but again, Uniracers manages to make use of this. I haven't really bothered to figure out how.

by on (#65600)
Does it auto-increment when writing to it more than once, and if it does, does it wrap around back to the beginning of the oam?

by on (#65605)
I have no idea, I would suspect not but you'd have to try for yourself.

by on (#65842)
it can be done on MD to some extent... I messed around with single sprite every line and could display 240 "sprites", in a jiggly manner (got to forget interrupts when doing this, VDP polling would be effective but the use gets severly limited then)...