High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

eVeRinOr
Posts: 10
Joined: Wed Aug 12, 2020 9:14 am

High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by eVeRinOr » Wed Aug 12, 2020 9:31 am

Hello, so for the past couple of days I have decided to work on an NES project and came across the need for more than 256 tiles per-screen as the game I am making requires higher-quality images with many unique tiles to get the full effect I am trying to achieve. I can do things like swap palletes out and change scroll mid-frame although I cannot change out much CHR-RAM (to be expected of course) during the rendering of scanlines. I thoguht I might be able to replace tiles that are no longer needed with tiles that will be needed later as they are drawn but I wanted to hear some of your opinions on the best way to go about this as I need it to be as efficient as possible. Thanks in advance! :beer:

User avatar
Dwedit
Posts: 4351
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by Dwedit » Wed Aug 12, 2020 10:12 am

Swapping palettes out is not really a thing. You need at least 1 empty scanline to do that, and you'll see garbage on the screen while the palette is edited. It only worked for Indiana Jones and the Last Crusade because it uses exact timed code, and has a lot of blank space at the right side of the screen.

For 8K CHR-RAM, the best approach would be to switch sides of the CHR bank half way through the screen using PPUCTRL. That would bring the total number of tiles up to 512.
For CHR ROM, I'd just use bankswitching.

One additional trick not mentioned is the ability to use a smaller attribute size. You can simulate a 16x8 attribute size instead of 16x16 by changing horizontal scroll location every 8 scanlines. So it uses attributes for one name table on even rows, and attributes from the other name table on odd rows. Klax uses the 16x8 attribute size trick during gameplay.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

eVeRinOr
Posts: 10
Joined: Wed Aug 12, 2020 9:14 am

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by eVeRinOr » Wed Aug 12, 2020 10:24 am

Oh, awesome! I am definitely going to try the swapping CHR sides thing, that is definitely bounds and leaps more efficient than copying new data to the PPU during scanline renders. In the meantime though, do you (or anyone else) have any ideas as to how I can best go about converting existing images and then touching them up for this type of rendering. I typically use NES Screen Tool to convert images over but it only uses one 4K bank of tiles to render the image, I also want to touch up the final image, so it is as tile-efficient as possible but still includes all the main details. Trying to get similar output to NES Image Converter 2 (If you have heard of it) but in a much more memory efficient way.

lidnariq
Posts: 9659
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by lidnariq » Wed Aug 12, 2020 11:05 am

Of course we've heard of it: viewtopic.php?t=7363

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by tokumaru » Wed Aug 12, 2020 12:50 pm

eVeRinOr wrote:
Wed Aug 12, 2020 9:31 am
the game I am making requires higher-quality images with many unique tiles to get the full effect I am trying to achieve.
Then maybe you should be looking into making it for a more capable console... :roll:
I can do things like swap palletes
This is notoriously hard on the NES, and there are lots of catches... the hblank period is not long enough to change the palette and restore/set the scroll for the next line, requiring the changes to be spread out across multiple (blank) scanlines. Another catch is that this will also disable sprites.
out and change scroll mid-frame
This is simple enough, but due to how late in the scanline MMC3 IRQs fire, you typically have to wait for the next scanline in order to do a perfect scroll split. This may translate to a lot of wasted CPU time if you're doing lots of splits every frame.
although I cannot change out much CHR-RAM (to be expected of course) during the rendering of scanlines.
On real hardware you can easily swap the 8KB CHR-RAM chip for a larger one (32KB chips should be easy to find) and bankswitch it like it was CHR-ROM. Support for this in emulators can vary (needs NES 2.0 header).
I thoguht I might be able to replace tiles that are no longer needed with tiles that will be needed later
If updating 4 palette bytes is already difficult, you can imagine how hard it'd be to update the 16 bytes of a single tile. CHR-RAM updates mid-screen are completely out of the question. You can do it between frames though, but even the vblank time is not long enough to transfer large amounts of data to VRAM. Without forced blanking (when you manually disable rendering on scanlines that would normally be rendered), you can update around 16 tiles tops, if you're not updating anything else.

You're free to try and create the "best looking NES game ever" by abusing the PPU, but keep in mind that there's a reason these kinds of tricks aren't used often in NES homebrews... they may sound simple in theory, but the NES is not nearly as friendly to raster effects as the SNES or the Genesis, and there are a lot of timing quirks and limitations to get around. Real hardware for testing is absolutely essential (this includes a real MMC3, as the IRQ functionality in flash carts is known to not be 100% accurate), because emulators are not accurate enough to replicate the exact effects of mid-rendering PPU manipulation (they're generally more forgiving than the real hardware).

EDIT: With a custom mapper you could significantly improve the tile count and the attribute resolution, much like the MMC5 already provides access to 16384 tiles at once and 8x8-pixel attributes - a custom mapper could go as fine as 8x1-pixel attributes. Nothing can be done about the palettes though, since those are stored inside the PPU itself, meaning you can't expand them using hardware in the cartridge like you can with the rest of VRAM.

eVeRinOr
Posts: 10
Joined: Wed Aug 12, 2020 9:14 am

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by eVeRinOr » Wed Aug 12, 2020 1:12 pm

Then maybe you should be looking into making it for a more capable console... :roll:
The reason I am not doing this is because I am porting an already existing game to see how it would be done on the NES. Just a project for fun because I got bored. If I have to sacrifice some of the graphics and gameplay, but not so much to where it is no longer playable, I will but I am attempting to sacrifice as little as I have to with original hardware.
Real hardware for testing is absolutely essential (this includes a real MMC3, as the IRQ functionality in flash carts is known to not be 100% accurate),
I own multiple real NES systems, along with many peripherals and such, although not an MMC3. Do you have any recommended sources for flash carts? Or, if not, possibly a way I can get my game tested on real hardware without a flash cart? I heard that the controller port can be used as a serial port if adapted but I am not sure.

Also, it seems that everyone here is assuming that I require pallete swaps. Just to clear things up, I absolutely do not as the game is not too colorful (in fact the NES may allocate more than enough palletes to me) I was just mentioning in my original post that I had already accomplished that when playing around with the MMC3 IRQs and learning how to use them.

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by tokumaru » Wed Aug 12, 2020 1:48 pm

eVeRinOr wrote:
Wed Aug 12, 2020 1:12 pm
The reason I am not doing this is because I am porting an already existing game to see how it would be done on the NES. Just a project for fun because I got bored. If I have to sacrifice some of the graphics and gameplay, but not so much to where it is no longer playable, I will but I am attempting to sacrifice as little as I have to with original hardware.
I'm all for reimagining newer games on older hardware (I'm coding a first person shooter on the NES for for crying out loud), but in my experience, fighting the hardware is not always the best approach. You can still achieve amazing results by embracing the system's design and making the most efficient possible use of it. Look at this platformer called "Sam's Journey" someone is making... it looks leagues better than anything previously seen on the NES, and it doesn't seem like they needed copious amounts of raster effects to achieve those visuals.
Do you have any recommended sources for flash carts?
My point was precisely NOT to use a flash cart (the FPGA kind) if you're experimenting with raster effects finely timed from MMC3 IRQs. We've seen many instances of status bars flickering and jumping on flash carts when they didn't on actual MMC3 cartridges. The best solution would be to get a real MMC3 cartridge and install a socket in place of the original mask ROM, so that you can burn your own chips to test on 100% authentic hardware. This is important for experimenting with raster effects that rely on really fine timing... for projects that use the hardware in more normal ways, flash carts are fine.
Also, it seems that everyone here is assuming that I require pallete swaps.
You mentioned palette swaps in your post. If you don't need that, then things get much simpler. The timing for scroll splits is reasonably loose (you need to fit a 5-cycle operation in a ~21-cycle window) and CHR swaps are instantaneous and happen completely outside the PPU (it's a mapper-only operation), and can be timed with minimal effort.

eVeRinOr
Posts: 10
Joined: Wed Aug 12, 2020 9:14 am

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by eVeRinOr » Wed Aug 12, 2020 2:03 pm

(I'm coding a first person shooter on the NES for for crying out loud)
The sounds awesome, all the best of luck to you. It would be really cool too see that.
My point was precisely NOT to use a flash cart (the FPGA kind)
Sorry, I should have worded that a little bit differently. I meant do you know of any good sources for EEPROM / RAM chips (parts of the cart that can use repos essentially) to put in original MMC3 boards or alternatively flash carts that are compatible with original MMC3 chips if that is a possible option.
If you don't need that, then things get much simpler. The timing for scroll splits is reasonably loose (you need to fit a 5-cycle operation in a ~21-cycle window) and CHR swaps are instantaneous and happen completely outside the PPU (it's a mapper-only operation), and can be timed with minimal effort.
Yes, the main thing I am trying to accomplish is to have access to more tiles avaliable to the background on one screen as every screen of the game consists of large static images which make up the bulk of the gameplay visuals (besides the ever-so-simple HUD) so I want them to look acceptable since that is what you're going to be looking at all the time. Well, that and you need to actually be able to see what is going on without making the images too simple.

EDIT: I am currently making a test ROM for the CHR side swapping mechanism and I have zeros on half the screen and ones on the other half of the screen (which are always in motion.) They both get their graphics from two seperate tilesets although it seems the method that I am using isn't working on Mesen (which I am told is a more accurate emulator.) The code that I am using works perfectly in FCEUX however, but I definitely want this game compatible with the actual console. I also don't want development to halt until I can test on actual hardware though. Do you guys have any ideas what might be going on with this code? This is my current NMI and IRQ routine:

Code: Select all

NMI:

	;lda #$00
	;sta $2003
	;lda #$02
	;sta $4014

	; Begin Game Code
	; Stop the top of the screen from scrolling
	lda #0
	sta PPUSCRL
	lda #0
	stx PPUSCRL

	; Setup MMC3 to generate an IRQ after 119 scanlines
	lda #$01
	sta $E000
	lda #$77
	sta $C000
	sta $C001
	lda $01
	sta $E000
	sta $E001
	
	; Backgrounds Use Pattern Table 0
	lda #%10000000
	sta $2000
	
	rti

IRQ:

	pha
	txa
	pha
	tya
	pha

	; Acknowledge the IRQ and disable further IRQ generation
	lda #$01
	sta $E000
	
	; Scroll the bottom half of the screen
	ldx scrollx
	inx
	stx scrollx
	ldy #0
	stx PPUSCRL
	sty PPUSCRL
	
	; Backgrounds Use Pattern Table 1
	lda #%10010000
	sta $2000

	pla
	tay
	pla
	tax
	pla
	
	rti
A visual of my program working in FCEUX
A visual of my program working in FCEUX

User avatar
Controllerhead
Posts: 148
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by Controllerhead » Wed Aug 12, 2020 2:40 pm

eVeRinOr wrote:
Wed Aug 12, 2020 2:03 pm
flash carts that are compatible with original MMC3 chips
Everdrive N8 and PowerPak are both fine options. They both support most chipsets and run most games (nearly) flawlessly. I use an (original) Everdrive N8 to develop, i would highly recommend it.
eVeRinOr wrote:
Wed Aug 12, 2020 2:03 pm
The code that I am using works perfectly in FCEUX however, but I definitely want this game compatible with the actual console.
FCEUX is a solid option, but i would check out Mesen. The development tools and the accuracy are superior. Sour, the main developer, is very active in the NESdev community and is highly dedicated to accuracy and awesome dev tools (and an absolute sweetheart).

EDIT: Ok, you are aware of Mesen and using it already. Reply first and read later. ...Amazing dev right here :roll:
Last edited by Controllerhead on Wed Aug 12, 2020 3:53 pm, edited 5 times in total.
Image

User avatar
Dwedit
Posts: 4351
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by Dwedit » Wed Aug 12, 2020 2:46 pm

Make sure *everything* about the MMC3's state is set. That includes manually mapping in all CHR pages. Some emulators might apply a default mapping of 01234567, and real hardware does not do that.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by tokumaru » Wed Aug 12, 2020 3:30 pm

FCEUX is a good development tool, but in terms of accuracy it's a bit lacking. Be sure to test your program, at least periodically, in more accurate emulators such as Nintendulator and Mesen. Mesen is also the emulator with the most complete set of debugging features, topping FCEUX in every way. If you're not working under any restrictions that require you to use FCEUX (e.g. an underpowered computer), consider using Mesen even more frequently.

Edit: You said it isn't working in Mesen but didn't say what exactly is wrong... Does the scrolling fail? The pattern switch? What do Mesen's pattern and name table viewers show?

eVeRinOr
Posts: 10
Joined: Wed Aug 12, 2020 9:14 am

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by eVeRinOr » Wed Aug 12, 2020 3:44 pm

You said it isn't working in Mesen but didn't say what exactly is wrong... Does the scrolling fail? The pattern switch? What do Mesen's pattern and name table viewers show?
Ah, sorry about that. It seems that the IRQ interrupt fails to trigger causing the pattern switch and the scrolling (on the bottom half) to both fail. Instead it scrolls the entire screen one way, and it all appears as zeros in Mesen. I have a feeling it has to do with my init code and/or the interrupt setup code although I can't find much information on it so I don't know how else I can write the previously provided code to work on Mesen. @Dwedit mentioned something about manually mapping all the CHR pages, although I am not exactly sure how to do that if I am not doing that already (I don't believe I am)

Fiskbit
Posts: 153
Joined: Sat Nov 18, 2017 9:15 pm

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by Fiskbit » Wed Aug 12, 2020 3:52 pm

I suggest trying on the newest development build of Mesen, available here. I'm pretty sure were some issues in Mesen with MMC3's IRQs not too long ago, and I don't know if the fixes are in the latest official release. Mesen also has development options under Options -> Emulation -> Advanced that I recommend using to more closely match hardware.

To get a better idea of what's happening in Mesen, you can use the Event Viewer to see where your IRQ and mapper writes are occurring.

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by tokumaru » Wed Aug 12, 2020 3:57 pm

How are you handling the I flag?
eVeRinOr wrote:
Wed Aug 12, 2020 3:44 pm
@Dwedit mentioned something about manually mapping all the CHR pages, although I am not exactly sure how to do that if I am not doing that already (I don't believe I am)
Most people (and emulators) assume that since you're using CHR-RAM that you don't need to worry about the banking state of CHR memory, which's not true. Even if you have only 8KB of CHR-RAM, the CHR banking hardware is very much active, and it boots to an unknown state on power up, scrambling the CHR memory. What you have to do is manually map the 6 banks of CHR into a contiguous 8KB block before you can safely use that memory.

eVeRinOr
Posts: 10
Joined: Wed Aug 12, 2020 9:14 am

Re: High quality images on the NES with MMC3 scanline interrupts and CHR-RAM

Post by eVeRinOr » Wed Aug 12, 2020 4:24 pm

How are you handling the I flag?
I am not sure if it is what you are looking for but in my initialization code I just execute cli
My initialization code is as follows (minus vblank waiting and memory initialization)

Code: Select all

RESET:

	; Ignore IRQs
	cli
	; Disable Decimal Mode
	cld
	ldx #$40
	; Disable APU frame IRQ
	stx $4017
	ldx #$ff
	; Set up stack
	txs
	; Set x to 0
	inx
	; Disable NMI
	stx PPUCTRL
	; Disable Rendering
	stx $2001
	; Disable DMC IRQs
	stx $4010
What you have to do is manually map the 6 banks of CHR into a contiguous 8KB block before you can safely use that memory.
Does this mean that if I had not mapped the CHR banks I could not reliably output any sort of graphics? In my code I am writing an entire 8KB of data to both Pattern Tables in order to initialize it, is that it? In Mesen my game looks like this:
Mesen.png
You can also see in the screenshot that the IRQ interrupt is not being called at all in Mesen. Graphics work fine however, it's just the MMC3 scanline counter which doesn't seem to be working. I am using the latest development version of Mesen now as a side note.

Post Reply