Page 1 of 1

Waiting for a scanline

Posted: Sat Aug 12, 2006 4:26 am
by visy
I'm working on a little test demo to gain some understanding into the NES hardware (having learned to program in assembly on the C-64). I'd like to program a full-blown demoscenish demo with some simple effects I've done on different platforms.

What I'd like to know is what is the best/easiest/fastest/whatever way to wait for a scanline? What I mean is, that I'd like, for example, to show on the top half a scrolling picture (one 4k of CHR-ROM) and on the bottom half some text (the other half).

Now, I know that I can change the "graphics page" by using $2000. But how can I change it in midscreen? Also, should this also enable me to use different values for scrolling ($2005) on the different halves of the screen?

EDIT: I'm talking about raster splits, of course.

Posted: Sat Aug 12, 2006 5:52 am
by Dwedit
Using MMC3 IRQs is probably one of the easiest ways to do it, you can tell the mapper how many scanlines to wait, and it does it. You must have backgrounds coming from a different pattern table than sprites (usually BG on the left, sprites on the right). It's not exact, but it was good enough for many NES games.

The other ways to wait for specific numbers of scanlines involve hardcoding the number of cycles to wait, or using sprite 0 hit. Sprite 0 hit is only once per frame, and it has to hit a BG tile.

Sorry for the lack of examples, I don't know how to program for the NES.

Posted: Sat Aug 12, 2006 10:19 am
by tepples
Before you start, make a demo with sprites moving around.

First, set up sprite 0 such that an opaque pixel of sprite 0 overlaps an opaque background pixel just above where you want to put the split. (There are some quirks: if sprite or background rendering is turned off, it won't trigger, and if the overlap is only at x=255, it won't trigger.)

Second, wait for the raster to get to that point. The PPU will signal this by setting PPUSTATUS ($2002) bit 6 to 0 (at the top of the screen) and then 1 (at the desired raster time). The BIT opcode places bit 6 of the operand in the V flag, so do this:

Code: Select all

; wait for sprite 0 overlap flag to become 0
; (at the top of the screen)
@waitSpr0Off:
  bit PPUSTATUS
  bvs @waitForSpr0Off

; wait for sprite 0 overlap flag to become 1
; (at the desired raster point)
@waitSpr0On:
  bit PPUSTATUS
  bvc @waitForSpr0On
Finally, change your scroll position by writing to PPUSCROLL ($2005) and PPUADDR ($2006). Loopy's "skinny" doc and its successors should help you understand how these two registers work.

Posted: Sat Aug 12, 2006 12:06 pm
by Memblers
If you want to do vertical scrolling after the split, it's slightly trickier. Horizontal is easy though.

Sprite #0 hit get you to the first point (a little timed code after the hit detect will get you into hblank, that takes a little experimention). I just wanted to add that if you want to wait for a scanline after that, the simplest way is to used timed code that waits for 113.666 cycles per scanline.

In a loop, you can wait .666 cycles (averages out) like so:

Code: Select all

 lda counter
 clc
 adc #85
 bcc :+
:         ; branch to nowhere
 sta counter

Posted: Sun Aug 13, 2006 5:02 am
by visy
Thanks for your help, works perfectly.

http://babibu.opintanner.fi/twoway.nes

Now the Hoff will never stop ;)

Posted: Tue Aug 22, 2006 10:42 am
by visy
Is there a similar method of scanline timing on PAL?

Posted: Tue Aug 22, 2006 11:24 am
by Quietust
visy wrote:Is there a similar method of scanline timing on PAL?
Yeah, you just need different timing values in your loops.

Posted: Thu Aug 24, 2006 10:20 am
by visy
What I'm now trying to implement are stable bouncing / expanding rasterbars with background color + raster timing. Is sprite-0 hit the best way to do this?

This is the logic I was thinking:

1. wait for sprite-0 off (top of screen)
2. wait for sprite-0 on (starting point for timing)
3. wait a few raster lines
4. set horizontal color
5. waste enough cycles to pass the screen horizontally
6. next line, continue from 4 until rasterbar(s) drawn.

Does that seem correct? I've tried to make a loop that waits for the exact number of cycles, but somehow i always get gray-colored flickering parts on the horizontal lines (which, of course, look _pretty_ ugly).

All this really makes me miss the C-64 and raster interrupts ;)

Posted: Thu Aug 24, 2006 11:28 am
by Memblers
I don't know where the gray-color parts could be coming from, unless you're accidentally (or purposely) enabling the grayscale mode. Otherwise there is gray in your palette. If you shut the screen off manually (I think you won't need to, but I suppose you could do the whole thing with the screen off), whatever palette byte the VRAM pointer is set to will be used as the background color. I'd recommend using Nintendulator's debugger to step through the code, it has the very handy feature of telling you when it's in hblank.