Accessing OAM during H-blank
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
-
psycopathicteen
- Posts: 3001
- Joined: Wed May 19, 2010 6:12 pm
Accessing OAM during H-blank
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?
-
psycopathicteen
- Posts: 3001
- Joined: Wed May 19, 2010 6:12 pm
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.
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.
-
psycopathicteen
- Posts: 3001
- Joined: Wed May 19, 2010 6:12 pm
Yes, writing to OAM during Hblank goes to:
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.
Code: Select all
uint16 addr = 0x0200 + (last_accessed_sprite_item >> 2);
memory::oam[addr] = (uint8)data;-
psycopathicteen
- Posts: 3001
- Joined: Wed May 19, 2010 6:12 pm