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.
Then maybe you should be looking into making it for a more capable console...
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.I can do things like swap palletes
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.out and change scroll mid-frame
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).although I cannot change out much CHR-RAM (to be expected of course) during the rendering of scanlines.
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.I thoguht I might be able to replace tiles that are no longer needed with tiles that will be needed later
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.
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.Then maybe you should be looking into making it for a more capable console...
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.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),
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.
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.eVeRinOr wrote: ↑Wed Aug 12, 2020 1:12 pmThe 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.
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.Do you have any recommended sources for flash carts?
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.Also, it seems that everyone here is assuming that I require pallete swaps.
The sounds awesome, all the best of luck to you. It would be really cool too see that.(I'm coding a first person shooter on the NES for for crying out loud)
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.My point was precisely NOT to use a flash cart (the FPGA kind)
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.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.
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
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.
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
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?
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)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?
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.
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.
I am not sure if it is what you are looking for but in my initialization code I just execute cliHow are you handling the I flag?
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
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: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.
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.