When I scroll the background, it moves 32 pixels up from what it's supposed to be at. It only moves up once the scrolling starts. It does not move up continually, and if the scrolling stops, it still stays up. I've tested it on recent versions of Nintendulator, Nestopia, FCE Ultra, and RockNES, and this occurs on all of them. Does anyone know what causes this?
What method are you using to scroll the screen? It's possible you're using the wrong method.
I'm using this:
Code:
lda #$00 ; Reset VRAM
sta $2006
sta $2006
inc Value
ldx Value
stx $2005
sta $2005 ;No vertical movement
Nothing is wrong with the code you have presented. This code would work on each one of those emulators; the problem exists somewhere else. Have you checked the value of "Value" after it does this scroll jump?
My first thought was that his scrolling code is right, but the code he has before he starts scrolling is wrong (ie, what he thinks is wrong is actually right, and what he is basing it on to be right is actually wrong)
What code are you using before you start scrolling (before the screen shifts up 32 pixels)
Most probably you set the scroll during the frame and not during VBlank. The twice write to $2006 set the vertical scroll to zero, but during the frame, it will shake the whole screen down. Then the $2005 writes setup the proper horizontal scrolling, and the vertical one is ignored because not refreshed until anything is written to $2006.
Okay, I'm doing this after each NMI:
Code:
inc Ticks
ldx Ticks
cpx #$08 ;once every 8 frames
bne InfiniteLoop
inc Value
lda #$00
sta Ticks
sta $2006
sta $2006
ldx Value
stx $2005
sta $2005 ;No vertical movement
jmp InfiniteLoop
I'm using NESASM, if that helps anyone.
Well, it's recommanded you write to $2005 DURING the NMI code so that you're sure it is during VBlank.
This is your scrolling code which looks like it would be working fine.
Which supports my earlier idea, that what you think the screen is "supposed to be" is actually wrong, and what you think is wrong is actually right.
What code are you using to draw before you start scrolling? You said that's when it shows up "right" -- so that's probably where the problem is.
Or just upload the whole ROM or source somewhere and link us to it. It's really hard to remotely debug something with only small code snippits.
Okay, I'll upload the ROM. But where can I get free file hosting without spam?
As for "right" being "wrong," I made the nametable using NSA, and it shows up there the same way it shows up when the screen is not scrolled. But whenever I scroll the screen, it suddenly jumps.
And for the "during the frame" hypothesis, I do all of this code right after the NMI is triggered. There is nothing else going on.
CartCollector wrote:
Okay, I'll upload the ROM. But where can I get free file hosting without spam?
Geocities/Angelfire/etc
just don't give them your real e-mail address and you won't get spam. Who cares if you have ads on the site if you're only using it for file storage.
Here's the full source code. GeoCities wouldn't let me upload any .nes, .chr, or .nam files, because they had "invalid filenames." You could use any 8k .chr and 1k .nam with that source, assemble it through NESASM, and get the same results I'm getting.
Ah, I see what's going on.
Your VRAM address got left at $3F10 after writing to the palette, which is effectively moving the viewport upward. You must initialize the VRAM address before you enable rendering, and it also doesn't hurt to set it on every frame.
In short, Disch was right.
You could .zip things up, you know ;P
Anyway -- having looked it over:
- in your 'ClrMem' routine you're performing STA's without ever having set A to anything (no prior LDA command). So you're effectively writing garbage instead of $00
- You're having NMIs occur, but you never RTI, you just jump back to your infinite loop, which will cause your stack to overflow like mad (run your ROM in FCEUXD and look at RAM at $0100-01FF in the memory viewer / hex editor). This will still work for what you're doing now -- but it's bad practice and will probably cause problems later when you're doing more things with the stack.
Always exit your NMI with an RTI.
- (Probalby the cause to the problem you're talking about): You're never setting the scroll to any initial value... so the screen will be starting from a "garbage starting point". So for the first 8 frames, the scroll is screwed. I believe you left the PPU address at $3F20 when you turned the screen on -- so that's like starting with a Y scroll of 11. It isn't until 8 frames in where you reset that scroll to zero -- which is why your screen is shifting up by ~11 pixels when the screen starts scrolling
So I was right before -- your scrolling is correct -- and what you're thinking is "right" is actually a little off.
To remedy this -- set the scroll before turning the screen on. You can do this by writing zero to $2006 twice.
- Also -- to avoid one frame of flicker -- you might want to wait until VBlank before turning the screen on. If you turn the frame on in the middle of rendering time, the screen will start rendering halfway down the frame (will look weird).
EDIT -- I'm too slow! Q is too quick ;D and whoops -- I thought you were starting at $3F20 but Q is right about $3F10 -- which would only be a Y scroll of 3?
Disch wrote:
$3F10 -- which would only be a Y scroll of 3?
Remember, $3F10 is $310 relative to that nametable. If he's using horizontal mirroring (which he probably is, otherwise he'd be seeing junk for the first 8 frames), that'll result in an effective Y-scroll of -40 (plus horizontally scrolled halfway).
Here's the source with bug fixes and the compiled file. The only thing is, it delays for 2 seconds (I counted about 120 frames in Nintendulator' frame stepper), moves right one pixel, then starts scrolling left. What's causing that?
Oh, and I have some extra stuff in the source (like everything under "ScrewingWithScanlines"). I'ts unorganized stuff I might use once I get this working.
So, has anyone tried it? How did it run for you?
Well, I tried the demo, and it doesn't really scroll... At all... I tried it on both FCEUXD and Nintendulator, and it just scrolled 1 pixel. And I waited for a long time, like 20 seconds. Maybe I missed something, but it didn't work for me.
Looks like you're reusing variables without reinitializing them. When the first NMI hits, $00 is set to #$90 and $01 is set to #$94, which is causing the screen to be scrolled REALLY far to the right - once $00 overflows past zero and up to 4 (exactly 116 frames), THEN it sets horizontal scroll to 0, 1, 2, 3, etc.
Oh yeah, I forgot I was using $00 and $01 for the name table loading. So, I just changed the locations of my variables, and it works! Thanks Quietust!
Okay, now there's other things I'd like to know.
1) How long is the time, in CPU cycles, between the end of rendering one scanline and the start of rendering the next (aka HBlank)?
2) I've read that the MMC3 interrupts can be triggered up to 7 CPU cycles before the scanline ends. How long should I delay before I start writing to the PPU?
3) I notice that in many demos, there's "shearing" between scanlines where mid-frame scroling takes place. What can be done to prevent ths? I read somewhere that you can't scroll more than 8 pixels without shearing, citing Chris Covell's CMCWavy demo. I was also thinking I could have certain scanlines where I do scrolling solid colors, but I don't know which scanline would shear (the one before or after the HBlank scroll).
CartCollector wrote:
1) How long is the time, in CPU cycles, between the end of rendering one scanline and the start of rendering the next (aka HBlank)?
Each scanline is 341 PPU cycles, consisting of 256 cycles of draw and 85 cycles of hblank, and there are 3.00 (NTSC) or 3.20 (PAL) PPU cycles in a CPU cycle. So hblank is a hair longer than 28 (NTSC) or 26 (PAL) CPU cycles; don't count on being able to run more than about 8 instructions.
Quote:
2) I've read that the MMC3 interrupts can be triggered up to 7 CPU cycles before the scanline ends. How long should I delay before I start writing to the PPU?
If you're having trouble getting the whole screen to scroll, you might want to wait a while before tackling an MMC3 split. But if you feel ready to do an MMC3 scroll split, it's best to use a little less than one scanline (113.667 cycles on NTSC) to set up the registers first.
Quote:
3) I notice that in many demos, there's "shearing" between scanlines where mid-frame scroling takes place. What can be done to prevent ths? I read somewhere that you can't scroll more than 8 pixels without shearing, citing Chris Covell's CMCWavy demo.
As I understand it, the problem here is that the high order bits (8's place) of the horizontal scroll take effect only at the end of the scanline, while the low order bits take effect immediately. This precise behavior of the PPU was not well understood back then.
Tepples has a great post but there are a few points I want to touch on:
- The PPU is never really idle during rendering time. Even in 'HBlank' it's doing stuff. During cycles 320-340 of the scanline, the PPU is fetching tiles which will be displayed on the next scanline -- and up to cycle 251, the PPU is still using the VRAM address for rendering purposes. Therefore, if you want to be sure to avoid ALL forms of tearing/stray pixels/and other unwanted artifacts when splitting the screen, you'll want to keep your $2005/$2006 writes all between cycles 252-319... which gives you 67 PPU cycles of work time... which is about 22 CPU cycles (not quite 28) IF you manage to hit that first cycle at exactly the right time! Considering it's impossible to hit that cycle every time, you should give yourself a few cycles of "padding" -- maybe keep it down to 18 or 16 cycles if you want to be really safe.
Being off by a few cycles probably won't be that big of a deal... but it may cause unwanted rendering artifacts.
- I concur with tepples on the MMC3 deal. When I glanced at your demo it didn't look like you were even setting MMC3 up -- you just assigned your ROM to be mapper number 4. I would stick with mapper 0 until you get pretty comfortable. Mappers, while powerful, add more complication to the picture. MMC3 in paticular has a few funky rules you have to follow for the IRQs to work like you'd expect.
Until you know exactly what you're doing, stick to splits using the sprite 0 overlap bit of the PPU status register. Commercial NES programmers made do just fine with sprite 0 in the two to three years between when Balloon Fight first split the screen and when the MMC3 was introduced.
I had a scrolling bug and this thread helped me fix it.
It turned out I was setting scroll and VRAM to zero in my resetHandler infiniteLoop when I was setting up my NMI statemachine to go to scrolling.
Now I am behaving myself and only playing with those during NMI.
Thanks,
Al