smb sprite hit problem

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
smb sprite hit problem
by on (#19960)
Ive some problems with the sprite hit for smb...
When Ive went so far so NameTable is changed to 1 (2000:1) my sprite hit test obviously failes cause it isnt anything there, ive hacked it and understood that (2000:1) always should be clear when the sprite hit test is made.

I have a catch up kind of sprite hit test so first I make a test at PPU cycle 6280 and then I make a new one if 2000 (0x3B changed),2001 (0x1E changed),2006 is written to.

any ideas? all blarggs-ppu test passes, one thought though that I dont believe myself, but I will ask it anyway (since the test don't cover it) but do the spritehit test dont care about bg-scroll? cause if this is true it works.

thanks

by on (#19962)
SMB should not scroll at all until Sprite-0 hit is detected. When the frame starts drawing, it should be drawing from $2000 with zero scroll changes. Until Sprite-0 is hit, at which point the game changes the scroll with $2000 and $2005 writes.

by on (#19964)
Yeah exactly as I thought!
In my emulator I see that 1 is written to $2000 (when mario have advanced to the next nametable) at ppu cycle ~2000...

should this never happen?

and do the sprite0-hit test care about scroll values?

by on (#19966)
n6 wrote:
Yeah exactly as I thought!
In my emulator I see that 1 is written to $2000 (when mario have advanced to the next nametable) at ppu cycle ~2000...

should this never happen?


That's in VBlank? I can't say for sure whether or not that happens -- but if it does, I'm sure the game writes to $2000 again afterwards *or* writes 0 to $2006 twice afterwards (which would reset the scroll).

The one thing I can say for certain is that you should not start drawing the frame from the $2400 nametable in SMB1


Remember that $2000, $2005, and $2006 all affect the temporary PPU address (aka Loopy_T).


Quote:
and do the sprite0-hit test care about scroll values?


Yes.

by on (#19968)
Quote:
That's in VBlank? I can't say for sure whether or not that happens -- but if it does, I'm sure the game writes to $2000 again afterwards *or* writes 0 to $2006 twice afterwards (which would reset the scroll).


thanks! I used the values in control1 instead of the temp vram address

by on (#19971)
To be technical -- you actually are supposed to use the actual PPU address (Loopy_V) for everything. Loopy_T is only used to 'fill' Loopy_V at key times in the frame -- you should never use it directly.

by on (#20029)
I dont understand how the vram address is changed during rendering. is the temp vram address copied at PPU cycle 6820 and then for each tile it advance 1 is added, when its enter a new scanline (1<<12) is added, and then it of course wraps.

by on (#20030)
X scroll is incremented on the 4th cycle of each BG tile fetch. That is -- cycles 3, 11, 19, 27, ..., 235, 243, 251 and 323, 331 of every rendered scanline (including the pre-render 'scanline -1')

Y scroll is incremented on cycle 251 of every rendered scanline (including prerender)

X scroll is reset to what is in the temp address on cycle 257 of every rendered scanline (including prerender)

PPU Address is reset in full to what is in the temp address on cycle 304 of the pre-render scanline.


Or to put it short:
X inc: 3,11,19,...,243,251
Y inc: 251
X reset: 257
X inc: 323,331
reload: 304 (pre-render only)



X increment adds 1 to the PPU address, toggling the X NT bit (bit 10) when it wraps from 31. IE: $001E->$001F->$0400->$0401

Y increment adds 1 to the fine Y scroll (bit 12), then when that wraps from 7, it adds $20 to the PPU address (which increments the coarse Y scroll). That wraps from 29 and 31, but when it wraps from 29 it also toggles the Y NT bit (bit 11). pretty confusing to put in words...but:
$0000->$1000->$2000->...->$7000->$0020->$1020 (fine Y increment)
$0020->$0040->...->$0380->$03A0->$0800->$0820 (coarse Y increment)
03C0->03E0->0000->0020 (still wraps from 31, but does not toggle Y NT bit)


X reset takes only bits 0-4,10 from the temp address and puts them in the real address. Other bits in the PPU Address are unaffected


Here's some pseudo-code!:

Code:
// Scroll Reset
nPPUAddr = nPPUTemp;

// X Increment
if((nPPUAddr & 0x001F) == 0x001F)
  nPPUAddr ^= 0x041F;
else
  nPPUAddr++;

// Y increment
if((nPPUAddr & 0x7000) == 0x7000)
{
  nPPUAddr &= ~0x7000;
  if((nPPUAddr & 0x03E0) == 0x3E0)
    nPPUAddr ^= 0x03E0;
  else if((nPPUAddr & 0x03E0) == 0x03A0)
    nPPUAddr ^= 0x03A0 | 0x0800;
  else
    nPPUAddr += 0x0020;
}
else
  nPPUAddr += 0x1000;

// X reset
nPPUAddr = (nPPUAddr & ~0x041F) | (nPPUTemp & 0x041F);

by on (#20042)
Thank you so much for the detailed answer!
one more thing... do all this happen only when bg is enabled?

by on (#20047)
Only when BG or sprites are enabled. If both of them are disabled, the PPU enters a sort of "off" state and doesn't touch the PPU address at all.