It is currently Mon Oct 23, 2017 5:30 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 15 posts ] 
Author Message
 Post subject: timing and sprite 0 hit
PostPosted: Sun Jan 29, 2006 10:51 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
Hi guys.
I was playing with the sprite 0 hit yesterday and noticed something that never came to my mind before. The hit was detected at slightly different times, I think because the CPU can not be perfectly aligned with the PPU and we have to check the hit in software, with CPU code, then it is natural that it varies a little on the timing.

But is there a way to have the detection take place at the exact same pixel every frame? I tried waiting for the hit still inside the NMI, since it should (in my head) fire at the exact same time every frame. With only constant timed code inside the NMI the hit detection would still vary a little. Am I trying to do something impossible here?

Thanks for the help.


Top
 Profile  
 
PostPosted: Sun Jan 29, 2006 12:51 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
tokumaru wrote:
But is there a way to have the detection take place at the exact same pixel every frame? I tried waiting for the hit still inside the NMI, since it should (in my head) fire at the exact same time every frame.

NMI doesn't break an instruction. It can vary by up to 7 CPU cycles (21 NTSC pixels) from frame to frame.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 29, 2006 1:04 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Consider worst-case behavior in PPU clocks using the code below: NMI handling error is 0 to 5, sprite 0 hit polling is 0 to 17, so total error is 0 to 22 PPU clocks (pixels).

Quote:
With only constant timed code inside the NMI the hit detection would still vary a little.


Polling acts as a time quantization function, so it amplifies small timing differences. In the code below, the $2002 polling can cause a timing difference of a single PPU clock to become a differenceof 18 PPU clocks.

Code:
nop
nop ; NMI occurs somewhere in here
...
nmi:
...
bit $2002
bvs sprite_hit
bit $2002
bvs sprite_hit
...


Top
 Profile  
 
PostPosted: Sun Jan 29, 2006 1:06 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
tepples wrote:
NMI doesn't break an instruction. It can vary by up to 7 CPU cycles (21 NTSC pixels) from frame to frame.

Yeah, for some reason I thought maybe it would fire off at the same time. But I guess it has to wait any currently running instruction to finish.

So, there is no way to detect a hit at the same spot in consecutive frames?


Top
 Profile  
 
PostPosted: Wed Feb 15, 2006 10:08 am 
a stupid question or no.. i dont know.. i have a crazy or fool idea... if you put just sprite 0 just at the end of scanline then you can detect hblank without using a irq by just detecting your sprite 0.. that can confunding with a background or something not notorious... can it be real.. or just is another crazy and fool idea of a dreamer boy????

im very newbie...


Top
  
 
PostPosted: Wed Feb 15, 2006 10:11 am 
just making a sprite not notorious..
just putting it on end of scanline...
just you making it sprite being sprite 0..
then you can detect a hblank without irq..
by just reading when sprite 0 come..

or there is timing problems???


Top
  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 10:19 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Yeah, detecting HBlank isn't a real problem.
The real problem is :
bit $2002
bvc -

Takes 4 + 3 CPU cycles, so 7 CPU cycles in total. That means the hit can wrap arround 7*3=21 pixels. So in the best case you can time it to be just in HBlank and 21 pixels later in the worst case, but then if leaves you few time to be sure that your PPU writes will end before the begining of the next scanline in the worst case.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 10:26 am 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3471
Location: Indianapolis
That basically works. But don't put it on the rightmost 8 pixels, it doesn't detect a hit there (just another PPU quirk, I think my 'RTC' demo locks up because of that).

But there are timing issues, like blargg was showing. You can't detect a hit at the exact same time every frame. The margin of error needs to fit within hblank.

It's not a good replacement for IRQs though. Considering that you only get one sprite 0 hit per frame, and also the program has to waste time polling. Sprite 0 is fine though if you just want one hit really early or late in the frame.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 10:45 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Memblers wrote:
That basically works. But don't put it on the rightmost 8 pixels, it doesn't detect a hit there.

I was under the impression that only the 255th pixel didn't work, am I wrong ? If the whole left 8 bits wouldn't work, my window demo wouldn't work on the real hardware, because it relies on the 254th pixels of the line. And you said youreself it was working.

Quote:
Sprite 0 is fine though if you just want one hit really early or late in the frame.

Or if you're using a mapper with no IRQ such as CNROM, UNROM, A*ROM and S*ROM.
Also, doing it early cause no problem, because you run your VBlank code, then wait for hit, then end your PPU stuff to begin the calculation part.
Doing it late would cause problems, because you'll probably mean doing VBlank, then calculations, then wait for sprite zero hit. But if your calculation takes too long and overflow, your staut bar at the bottom of the screen could blink. If anyone has better idea, taught me, but I think while it can do the work in most case, it isn't 100% reliable for a finished complex game.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 11:45 am 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3471
Location: Indianapolis
Yeah, you're right on both counts. I was getting it confused with the 8 pixel clipping maybe. And for doing a sprite #0 hit late in the frame, yeah that's definitely only good if the worst-case timing for the code is known and can't exceed it's limit.


Top
 Profile  
 
 Post subject: one thing about timing
PostPosted: Wed Feb 15, 2006 12:08 pm 
if you know how many cycles have a instruction... then you can calculate amount of time in order to take sprite 0 hit at near end of scanline????

i think that yes. hard work...


Top
  
 
PostPosted: Wed Feb 15, 2006 12:10 pm 
example: my logic is xx cycles.. i take sprite 0 hit in xx cycle and amount of time for me is xx until the event that take a glitch in graphic come... then if i calculate just.... i can make a perfect stuff...


Top
  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 12:42 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
No, because 1 CPU cycle is 3 PPU cycle, so 3 pixels.
So when VBlank, Sprite zero hit or anything will occur, it will take some time to the CPU to take the PPU change in account. This little time is enough to make the whole thing warp arround a few pixels.
Let's show it clearly :
Admit that youre code is doing that :
Code:
_hitdetect
   bit $2002       ; 4 CPU cycles / 12 PPU cycles
   bpl _hitdetect ; 3 CPU (9 PPU) cycles when the branch is taken (when waiting)


One frame that will happen :
Code:
CPU Cycles        | PPU Cycles (aka pixels)

bpl _hitdetect -1 | Sprite not hit
                  | Sprite not hit
                  | Sprite not hit
bpl _hitdetect -2 | Sprite not hit
                  | Sprite not hit
                  | Sprite HIT HERE
bpl _hitdetect -3 | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -1      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -2      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -3      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -4      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set

This makes a delay of 16 PPU cycles (aka pixels) until the hit is accotumed.
Now, the next frame, the CPU won't be aligned with the PPU the same way. Fore exapmple, that could happen :
Code:
CPU Cycles        | PPU Cycles (aka pixels)

bpl _hitdetect -1 | Sprite not hit
                  | Sprite not hit
                  | Sprite HIT HERE
bpl _hitdetect -2 | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bpl _hitdetect -3 | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -1      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -2      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -3      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set
bit $2002 -4      | Sprite hit set
                  | Sprite hit set
                  | Sprite hit set

That effectively setup a longer delay of 19 PPU cycles, so the changes will takes 3 pixels later than the previous frame and your code cannot do anything to compensate this.
I don't know exactly which of the four setp of bit $2002 is actually fetching the sprite hit, but the whole loop is 21 PPU cycles long, so an error of 21 pixels in total is possible.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 12:48 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Quote:
I don't know exactly which of the four setp of bit $2002 is actually fetching the sprite hit, but the whole loop is 21 PPU cycles long, so an error of 21 pixels in total is possible.


The fourth (last) clock of BIT abs does the actual memory access. And you can reduce the loop by three PPU clocks by unrolling it (note that you need to use the V flag, not N, since sprite 0 hit is bit 6, not bit 7):

Code:
bit $2002
bvs sprite_hit
bit $2002
bvs sprite_hit
bit $2002
bvs sprite_hit
...

sprite_hit:


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 12:50 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Ah, yeah. If you're using an IRQ, your program could just be finishing executing any instruction when IRQ occurs. On the other side, it could just begin to perform lsr $370,X , which is 7 cycles.
So, the error is the same, 7 cycles and 21 pixels. Conclusion : Sprite zero and IRQ have the same tolerance. No one is better than the other in therm of accuracy.

Edit : Blargg you make your post while I was making one.
I think unrolling loop only reduce the chances to have a larger error, but the error is still here. You'll still need to roll it somewhere :
Code:
_bigloop
bit $2002
bvs _hit

bit $2002
bvs _hit

bit $2002
bvs _hit
.... etc ...
bit $2002
bvc _bigloop

_hit
...

If you're unlucky, the hit will occur at the begining of the only bvc instruction, and you'll be done for a 21 pixels delay, even if chances are reducted.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group