This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

MMC3's scanline counter

MMC3's scanline counter
by on (#36389)
I've heard that MMC3's scanline counter is bad, and I've never really heard much reason to back it up. I remember reading that the pattern tables must be set up so that both of them are never using pattern table 1. Is this true? Or only partially true? For what reasons should one avoid the scanline counter?

by on (#36390)
Short answer: Backgrounds on the left pattern table, sprites on the right.

by on (#36392)
And when using 8x16 sprites, don't use patterns from the background side.

These rules make it bad because they take from you the freedom to arrange the pattern tables as you'd like and reuse background tiles as sprites (which could be quite useful!). If you don't need any of that you won't find it bad at all.

by on (#36410)
Also, during your V-Blank code, be sure to perform all VRAM updates BEFORE writing to the IRQ registers (especially $C001). Otherwise an IRQ may occur sooner than you expect. Similarly, if you turn off the PPU mid-frame, be advised that the IRQ counter will be adversely affected, so do not reconfigure the counter until after the PPU has been turned back on.

After the last IRQ of a frame, it is safe to use the upper pattern table for BG and/or the lower pattern table for sprites. Final Fantasy III takes advantage of this, and I'm sure other games do as well.

The MMC5's IRQ counter is better because it doesn't require pattern tables to be used in any particular way. It only needs the PPU to be on to work.

by on (#36414)
Yeah the others pretty said everything. The MMC3 counter may be better than nothing, but not THAT much better because you have to :

- Keep the PPU enabled to make it count at all (this is also the case of MMC5's counter)

- The counter is relative. You can't place the number of the scanline you want the IRQ to happen, you have to place the number of scanline you want to wait. The fastest IRQs you can trigger in a row are 2 scanlines apart, un-elimiating the need for timed code

- You have to use different pattern table for nametables and sprites (I belive it doesn't matter which is left and which is right - this only changes when in the scanline the IRQ triggers, maybe I'm wrong) else the counter will get additional clocks.

- Any write to $2005/6 may accidentally clock the counter no matter if they're during rendering, during VBlank or during "forced VBlank". Unless you're absolutely sure A12 will be constant of course.

The good points of the IRQ counter is that :
- As it's clocked by the PPU and not the CPU, compability between NTSC and PAL consoles is preserved.
- It's better to enable a IRQ than do stupid polling

by on (#36416)
Okay, I see. Well, then I'm pretty sure I won't be able to use it, because I need to swap BG tables as I'm doing heavy PPU updates. Would anyone recommend a good alternative? I know there's sprite #0, but is there anything else?

by on (#36417)
What do you mean heavy BG updates? Generally you'd use the IRQ to change CHR-ROM banks and Scroll position. These are nearly instant. If you are using CHR-RAM, well if you want to change tiles then I don't know what to tell you other than you're crazy. ;)

What exactly are you trying to do? Use more than 256 BG tiles? Have a dixed Status bar at the top or bottom of the screen?

by on (#36429)
I'm trying to blank about about 40 scanlines on top of the screen and on bottom, because over the span of 5 or less frames, I need to update the entire BG (Minus the blanked part and attributes), and 4k of CHR RAM (Minus 4 tiles).

And I'm crazy for wanting to change CHR RAM tiles? What is that all about?

by on (#36433)
I thought you were wanting to change CHR-RAM tiles within a single vblank. That would be crazy to change that many in one vblank.

What you want to do I think will require precise timed code for leaving the screen off for 40 lines or a CPU cycle based IRQ. You could then use the IRQ for turning the screen off early though.

There's nothing crazy about changing CHR-RAM tiles as long as you aren't trying CHR-ROM size banking mid-frame. ;p

by on (#36434)
80 extra scanlines of VRAM drawing time?
That would work out to 102 scanlines with the screen off, and 160 scanlines with the screen on.
What kind of program are you writing?

by on (#36444)
Dwedit wrote:
What kind of program are you writing [that needs so much blanking]?

I checked Celius's posting history, and it appears some sort of polygon-based animation engine.

by on (#36449)
A CPU cycle based IRQ? This may sound weird that I don't know about this by now, but is that like an interrupt that counts cycles? If so, that would definitely be the way I'd go! I haven't dealt much with IRQ's in my days of NESdeving; I've only made simple games that don't require anything special like that. Is there anywhere that I could find more info about this?

And yeah, tepples pretty much got it. Once I optimize the polygon drawing code a little and program it to change frames, I will have proof that it is possible to have polygonal intro movies in games without using illegal opcodes or over 16k of PRG space. Though it requires 5k of SRAM and CHR RAM. I admit, this isn't something where you'd say "Only 5k of SRAM" because 5k is A LOT. Luckily, my ChateauLeVania game holds 3 save files in under 3k of SRAM.

EDIT: And yeah, there's no way I'm planning on updating a whole CHR RAM bank in a frame. THAT would be crazy :) .

by on (#36452)
Tengen's Mapper 64 (Rambo-1 or something) has a CPU Cycle IRQ mode. FME-7 (Sunsoft 5) which is mapper 069 has a CPU cycle based IRQ counter too. It would be ideal as it's a 16bit counter with direct access. The Tengen is CPU cycles * 4.

by on (#36455)
I think I might be able to do some tricks with sprite #0. If I could detect a hit at 40 pixels from the bottom, I could just turn the screen off, and then do some PPU updating until it wraps around and 40 scanlines are drawn from the top of the screen (+ 22 for Vblank) to turn it back on. Do you think this could work?

by on (#36457)
Sure it would work, as long as you have some way of forcing a sprite collision at the right place.
Or just use mapper 69.

by on (#36459)
No, I'm trying to make this work on any mapper that will allow for CHR RAM/SRAM, and also I'm working on a game that uses MMC3.

My polygon engine has a solid white tile that will always be in the same exact place and will never be over written in CHR RAM. I can use this same white tile for sprite #0 which I put on screen once and never need to update. So I think I've found my answer. This will give a good display area of 32x20, which is just a little taller than the widescreen 16:9 ratio. I'll definitely be getting back to you all once I have a good polygon video to show =). Thanks!

by on (#36465)
If you're looking for a way to reliably start the screen up late without relying on a mapper CPU cycle IRQ... there's always that sprite-fetch trick blargg and I came up with a while back.

Be sure to read the whole thread -- I started out with "this'll never work", but made a 180 pretty quick.

Basic outline:

1) put several dummy sprites on the scanline where you want to turn the PPU back on (iirc, blargg figured you'd only need to reserve 3 sprites for this)

2) leave the PPU off until you finish all your drawing (this can spill past the end of VBlank -- after all that is kind of the point)

3) turn sprite rendering on, but leave BG rendering off.

4) wait at least 1 full scanline (or more) so that the PPU can get on track with its OAM fetches.

5) start polling $2004 looking for your dummy sprite fetches.

6) once you've found your scanline, reset your scroll and turn BG rendering on.

As long as you get to step 3 before your target scanline is hit, you should be in the clear.

by on (#36499)
Oh yeah, I forgot about this! This is a pretty nifty scheme... So yeah, I'll turn off the bottom part with sprite #0, and turn it back on once it reaches the bottom of the top part using these tricks! Thanks for mentioning this!

EDIT: I seem to be having some issues... Perhaps I'm not seeing something, but I have like 6 dummy sprites set to $E3 for the X, Attribute and Tile, and I have it on Y = #40. The only other sprite I have is sprite 0, which has none of those values. Every other value in OAM is $FE. Then I have my loop doing this:

   lda #$50
   sta $2001
   lda #$E3
   cmp $2004
   bne -
   lda #$1E
   sta $2001
   lda $99
   bne -
   lda #$00
   sta $99
   jmp loop

In my NMI code, I set $99 to equal #1. Is there something I'm not understanding here? This is just to see that the detection works properly, but I think I'm missing something.

by on (#36511)
You should probably replace the bne with a beq after the lda $99

Also I guess this trick Blargg, Dish and I figured out may not work good under many emulators. In fact it may not work proprely on any emulators at all.

by on (#36526)
Did anyone study the scheme used by Super Cars? It has a gray border at the top of the screen that's somehow related to $2004 reads, and many emulators fail to emulate that border, in some the game is not even playable.

by on (#36533)
Bregalad wrote:
Also I guess this trick Blargg, Dish and I figured out may not work good under many emulators. In fact it may not work proprely on any emulators at all.

While it is pronounced "dish", it is in fact spelled "Disch" ;P

But yeah. Most emus will probably choke. Newer FCEU versions might work (it's possible FCEUX will work, but I doubt earlier versions of FCEUXD/FCEUD would). I don't see why Nintendulator or Nestopia wouldn't work. $2004 read behavior has been known for a while.

by on (#36534)
It won't be the end of the world if I can't get it to work. Most people will be playing my game on emus anyways, and if it doesn't work, it's not likely people are gonna go download the newest version of every emu to get it to work. Also, each section of my drawing code will take a specific amount of time, so I can just make it so it will turn on the screen at the right time.

My only concern is the virtual drawing part. How long that takes will depend on how complicated the frame is. So this will mean I can only do the virtual drawing when the screen is on, then I have to wait for the sprite #0 hit. For the bottom blanked part, I'll still be able to do some virtual drawing, and I'll just have to waste time in the NMI for 40 scanlines outside of Vblank. This makes me a little sad, because that's so much time wasted.

by on (#36544)
Celius wrote:
It won't be the end of the world if I can't get it to work. Most people will be playing my game on emus anyways, and if it doesn't work, it's not likely people are gonna go download the newest version of every emu to get it to work. Also, each section of my drawing code will take a specific amount of time, so I can just make it so it will turn on the screen at the right time.

Well, if your game/demo comes with a website/doccumentation that says which emulators are needed it's likely some people will look into that to play your game/demo. But if you say it's only working on the real console and that no emulator in the world support it most definitely few people will try it on their devcatrs, especially if it uses an advanced mapper.

by on (#36546)
It's a little more likely, but I'd rather just have everyone able to play it on regular emulators. I mostly don't want anyone to miss out =).

And also, I don't even have the materials to test this on hardware right now. I mean, I have a programmer (though every time I've burnt something to a chip, it didn't work), but I don't have all the chips I need. So basically I would like it to use as little real-NES-only functions as possible. Most people that I'll send this to won't know a thing about NES hardware; they'll probably just know how to open a ROM in an emulator.

At any rate, I think my blanking methods will be fine. Thanks for your help guys!