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

Is there anything that could alter an MMC1 reg3 write?

Is there anything that could alter an MMC1 reg3 write?
by on (#74394)
...besides the obvious of doing five more writes to register 3?
Or for that matter, is there anything that could cause the MMC1 to ignore a reg3 ($E000-$FFFF) write? And hence ignore a PRG bank switch?

I've got this weird crash happening now in my code, caused by the wrong PRG bank being loaded at the wrong time.

I'm looking at my Nintendulator dump file that I captured leading up to the crash. Specifically within that file, I'm looking at the previous two runs of a certain subroutine before the game crashes. This sub backs up the current PRG bank number in a variable so that it can jump back to he current sub later, then loads 0 into the accumulator, then jumps to the PRG bank-switching sub.

On the second-to-last run before the game crashes, the code executes perfectly fine. I need it to load bank 0, so I load 0 into A and then jump to the switching sub to do my five writes to $E000/four LSRs. Then scrolling down, I look at the next time a pointer is loading from somewhere in ROM and it's loading the correct data, indicating bank 0 is indeed loaded.

Here's the odd part. The next time this same subroutine runs (and again, the last time it runs before the game crashes) I'm again loading in bank 0, and the swapping subroutine also runs perfectly. However, when I scroll down even further and look at the exact same address being read out of ROM via a pointer, I see two $FF values. So I've checked this address in the debugger and found that $FF is the value when bank 1 is loaded. Bank 1, coincidentally, was the previous PRG bank loaded both times before jumping to this sub. It's like it changed the first time, but ignored the writes to $E000 on the second time. About 1 1/2 scanlines later, the game crashes, of course.

My first thought was that I must be screwing up an offset in a write, that's causing some random value to get written to $E000-$FFFF. I've painstakingly looked at every store instruction after this bank swapping subroutine (the one that gets called right before the crash), and I can't find stores to anything besides RAM or non-MMC1 registers numbered $7FFF and lower.

I'm re-reading this now and realizing it must be confusing as hell to anyone else. Here's a snippet from my dump file that might explain it better, I've annotated with some labels and comments:

bank_backup_se:
FF8D LDA $004B = 01 ;;$004B = prg_bank ;;the current PRG bank
;;loaded
FF90 STA $004E = 01 ;;$004E = bank_bak_se ;;the variable that holds
;;the current PRG bank, as I will need to return
;;to it once this group of code is done
FF93 LDA #$00 ;;target bank = bank 0
FF95 STA $004B = 01
FF98 JSR $E82B

swap_PRG_bank:
E82B LDA $004B = 00
E82E AND #$1F
E830 STA $E000 = 40
E833 LSR A
E834 STA $E000 = 40
E837 LSR A
E838 STA $E000 = 40
E83B LSR A
E83C STA $E000 = 40
E83F LSR A
E840 STA $E000 = 40
E843 RTS
FF9B RTS

;;so pretty standard stuff. now... scrolling down to the next immediate
;;instance when something is read out of the current PRG bank...

FED6 LDA $A1AE,Y @ A1BA = B4
FED9 STA $0053 = 50
FEDC LDA $A1AF,Y @ A1BB = A2
FEDF STA $0054 = A3

;;On the next frame, bank_backup_se and swap_PRG_bank run exactly
;;the same. However, the next time I scroll down a couple dozen lines
;;to find the pointer mentioned above...

FED6 LDA $A1AE,Y @ A1BA = FF
FED9 STA $0053 = 50
FEDC LDA $A1AF,Y @ A1BB = FF
FEDF STA $0054 = A3

;;and it's now apparent that I've pissed off the nesdev/6502/MMC1 gods
;;and they are now giving me the big middle finger.

by on (#74396)
Could an IRQ or NMI be firing when you don't expect it, and the handler switching banks out from under you (and not restoring them when the handler exits)?

Are your IRQs and NMIs disabled when the MMC1 bank switch routine is actually running (or at least, timed to not occur then)?

In my MMC1 experiment, I store the bank's number at $bfff. My NMI handler saves that on the stack (lda, pha), and on NMI exit, it checks to see if the bank has changed, and if so, restores it. But I don't have code to prevent an NMI during the MMC1 switcher (I was no where near close to running over my CPU budget, so it wasn't a problem yet).

by on (#74399)
Hey clueless, thanks for the suggestions. Let's see...

clueless wrote:
Could an IRQ or NMI be firing when you don't expect it, and the handler switching banks out from under you (and not restoring them when the handler exits)?


Actually, this code is part of the game's sound engine. Specifically, you might say it's the "driver" part (is that the correct term?) that runs every frame and runs through all the sound data and writes to he necessary sound registers. All this code is jumped to at the end of my NMI handler, after the xScroll writes to $2005 and right before I restore my Accumulator and X and Y registers.

clueless wrote:
Are your IRQs and NMIs disabled when the MMC1 bank switch routine is actually running (or at least, timed to not occur then)?


NMI is definitely not off, as the block of code this runs in gets ran as the tail end of the NMI handler. So the run_sound stuff is basically the first thing ran every frame. No other IRQs are enabled.

clueless wrote:
In my MMC1 experiment, I store the bank's number at $bfff. My NMI handler saves that on the stack (lda, pha), and on NMI exit, it checks to see if the bank has changed, and if so, restores it. But I don't have code to prevent an NMI during the MMC1 switcher (I was no where near close to running over my CPU budget, so it wasn't a problem yet).


I actually switch banks a few times or more every frame. I keep specific things in specific PRG banks. So for example, all sound data is in bank 0, the first four level's data/boss data is in bank 1, (actually 2 in NESASM, because everything is split into 8K banks), then all enemy code is in another 16K bank, etc. So what I do is, usually the level data is running, and then at a given time it may need to pull some enemy data. So the basic structure looks like this:

JSR level stuff
JSR more level stuff
JSR etc.

JSR backup_PRG_bank
JSR swap_PRG_bank ;usually this is included in the above sub, just separating it here for clarity.

JSR enemy stuff ;code in new bank is sandwitched between
JSR more enemy stuff ;these backup/restore subs
JSR etc. etc. etc.

JSR restore_PRG_bank
JSR swap_PRG_bank ;again, usually included in the restore sub above

JSR even more level stuff
JSR something else blah blah blah

Is that kind of the same thing you're talking about?

by on (#74400)
So this means that your sound engine, which is called at the end of your NMI handler, switches banks, right? Does it also back up the current bank number? Is it possible that it's overwriting the backup made in the game loop?

by on (#74401)
Don't feel too bad, even Capcom screwed up interrupted MMC1 bankswitching in the Mega Man games.

by on (#74403)
This is the reason I absolutely hate the convoluted way MMC1 registers are written to... it's just too error-prone. I also hate how long it takes to complete one single lousy mapper write, because the overhead of bankswitching several times in the same frame becomes too significant.

by on (#74407)
tokumaru wrote:
This is the reason I absolutely hate the convoluted way MMC1 registers are written to... it's just too error-prone. I also hate how long it takes to complete one single lousy mapper write, because the overhead of bankswitching several times in the same frame becomes too significant.


Yup, and is exactly why for years I've wanted an MMC3 devcart. Zero interest in this MMC1 crap. ;D

by on (#74418)
bigjt_2 wrote:
Is that kind of the same thing you're talking about?


Yes, I think. My hypothesises were as follows:
  1. Part way through changing the MMC1 bank via the 'lsr, sta' unrolled loop, your code gets interrupted, and the interrupt handler resets the latch, changes banks, does its work, then resets the bank back to what it found on entry. Your "main" thread then resumes banging out the final bits tot he MMC1 bank register, which is no longer properly latched, so the MMC1 sees an incomplete switch request.
  2. An interrupt handler swaps banks and simply never switches back, independent of the first bug proposal


But in your post (I think) you ruled though out, and I'm out of ideas atm.

by on (#74419)
For hypothesis 1, would it be worth it to try checking, from the NMI handler, whether the interrupted program counter on the stack is within $FF00-$FFFF? Then you could place all your low-level MMC1 handling code there.
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74421)
bigjt_2 wrote:
I'm looking at my Nintendulator dump file that I captured leading up to the crash.

Set a breakpoint at some point which leads to the crash and single step through the mapping code. The debugger shows you what PRG banks are currently mapped in. Unfortunately it doesn't display mapper state though.

If the code gets interrupted that would also show up in the CPU logs.

by on (#74424)
Quote:
Yup, and is exactly why for years I've wanted an MMC3 devcart. Zero interest in this MMC1 crap. ;D

What about the crappy limitations of MMC3's line counter ?
And also to switch a 16k bank in MMC3 it needs no less than 4 writes, only one less than the 5 MMC1 writes... probably not a major save of time if you want my opinion.

Of course the MMC5 fixes all these problems.

by on (#74425)
clueless wrote:
bigjt_2 wrote:
Is that kind of the same thing you're talking about?


Yes, I think. My hypothesises were as follows:
  1. Part way through changing the MMC1 bank via the 'lsr, sta' unrolled loop, your code gets interrupted, and the interrupt handler resets the latch, changes banks, does its work, then resets the bank back to what it found on entry. Your "main" thread then resumes banging out the final bits tot he MMC1 bank register, which is no longer properly latched, so the MMC1 sees an incomplete switch request.
  2. An interrupt handler swaps banks and simply never switches back, independent of the first bug proposal

But in your post (I think) you ruled though out, and I'm out of ideas atm.


The interrupted register write (cause it takes so damn long) seems like a possible cause. I agree that the slow nature of the MMC1 register writes is annoying enough to deter developers from using it and instead wanting to stick to discrete mappers like UxROM. It would be nice though to have something like a mix of UxROM, CNROM, and H/V mirroring control. That or as mentioned a MMC3 development board.

by on (#74426)
Guys, he's using MMC1. Hopefully his cart will get fabricated. That is not going to happen with MMC3 or MMC5.

bigjt, does this bug manifest itself fairly quickly from boot-up, or after the game has been playing for a while?

Would a CPU instruction trace (w/ perl or python post-processing) help figure anything out?

by on (#74430)
MottZilla wrote:
I agree that the slow nature of the MMC1 register writes is annoying enough to deter developers from using it and instead wanting to stick to discrete mappers like UxROM.

The big reason to switch from UxROM or AxROM to SNROM is PRG RAM support, especially if you want to be able to save more than 32 bits of state from one play session to the next. To do so on UxROM would involve adding a 74HC20, which decodes $6000-$7FFF and prevents bus conflicts on the ROM.

by on (#74432)
Maybe this would be a good time to replace your NMI like I had an idea to earlier, which I asked someone earlier if it was a good idea and this is maybe what could fix it.


Something like:

Code:
NMI:
PHA
LDA $2002
INC Frame
PLA
RTI


That way nothing gets messed with in the code, but a bad thing about this is that it'd pretty much go to 30FPS when alot of stuff is happening. Maybe this idea will help you fix it, hope it does. Plus it allows for different NMI's depending on the games kernal instead of using RAM to point to one. Can't wait to see the progress, good luck.

by on (#74435)
3gengames wrote:
Something like:

Code:
NMI:
PHA
LDA $2002
INC Frame
PLA
RTI

You can make this a bit shorter though:
Code:
NMI:
BIT $2002
INC Frame
RTI

Yes, this is a valid way to handle NMIs, and prevents mapper writes from colliding, but it does introduce problems in case of lag frames. If the game loop takes longer than a frame to complete, not only the gameplay will slow down, but also the music/sfx, and raster effects (such as status bars) will glitch up.

by on (#74436)
So basically put the Frame INC in there but do your music stuff at the end? Although that'd cut into vblank time....maybe that's not a good idea....Oh well, I'm sure you have a plan to fix it already if it's not yet.

by on (#74438)
3gengames wrote:
So basically put the Frame INC in there but do your music stuff at the end?

That kinda defeats the purpose, since his music code does some bankswitching.

by on (#74440)
OK to fix the problem without introduce this "fake NMIs" that would have the huge incovenient of making the music slows down if the game slows down (such as SMB, Zelda)...

1) At the begining of EVERY MMC1 writes (not only Reg3 wrties), disable NMIs via $2000, and re-enable them at the end. Yes it's a waste of cycles but it's vital if you don't want this part of code to be in-interuptable. If you ever use IRQs (unlikely on a MMC1 but who knowns) be sure to sei/cli this part of code too.

2) At the begining of every NMI, push the old bank switched in to the stack, and restore it by writing to Reg3 at the end.

This will work with no bugs and solve all your problems, with the inconvenient of potentially stealing a dozen of NMI cycles because of the non-interruptible work.
If your NMI timing is either very tight (you use 100% of the available time for VRAM updates) or must be precise (you use the NMI interrupt to sync with video like Battletoads) then you'll have to find some workarround :
1) Instead of disabling interrupts via $2000, simply increment a variable, and decrement it when the write is finished.

2) During all NMI MMC1 writes (not only Reg3 writes), be sure to reset the shift counter (write $80 to any reg) so that the next write is the first one, even if a previous write was interrupted !

3) Then at the end of NMI, if the variable isn't zero, re-do the complete write to the register by tricking the return address on the stack.
To handle this properly, you'd need up to 4 variables if the main code randomly access any of the 4 MMC1 regs, but in a typical case, you'd only do this for Reg3.

This method not only is a bit more complex than the previous one, but also it won't work if you decide to use 32kb bank switching or high 16kb switching. Writing $80 to a reg will put the MMC1 in 16kb low switching so if you use anything other than this, this method will not work. You'd need a second workaround to do it that way, but I don't feel like making one right now.

Quote:
I also hate how long it takes to complete one single lousy mapper write, because the overhead of bankswitching several times in the same frame becomes too significant.

OK I just took some throught about this, and I ended up with the conclusion that it's the exact same as MMC3. Look at the following piece of ultra-optimized code that bankswitch a 16k prg bank, the first part is MMC1, and the second does the exact same with the MMC3 :
Code:
lda #$01
ldx #$00
stx Reg3
sta Reg3
sta Reg3
stx Reg3
stx Reg3

ldx #$06
ldy #$18
stx $8000
sty $8001
inx
iny
stx $8000
sty $8001

Both are exactly 24 cycles long.

Of course, if you want to switch a variable bank, and take into account what I said above, the MMC3 would probably end up a bit faster, but you'd still have to deal with $8000 being affected by an interrupt.

by on (#74444)
Bregalad wrote:
This will work with no bugs and solve all your problems, with the inconvenient of potentially stealing a dozen of NMI cycles because of the non-interruptible work.


Unless there is other rogue code that is writing to the MMC1 registers, or if the hypotheses is false and the rogue bank switch is coming from some other source than an inconvenient NMI / IRQ.

That is a pretty strong statement "no bugs, will solve all problems". I hear that from vendors almost daily....

However, that approach to writing to the MMC1 register is a good idea, in general. It is coding defensively, and I endorse it.

But the blanket statement, I find, well, kind of short-sighted.

by on (#74445)
The difference of MMC3 is that you can have shadow versions of the bank switching registers, whenever you write to the real one, write to the shadow first.
Push the shadow versions onto the stack, and restore the shadow values before the IRQ finishes. Then you're in a guaranteed consistent state at any interruption, unlike with MMC1 where the count of writes matters.

by on (#74457)
Bregalad wrote:
OK I just took some throught about this, and I ended up with the conclusion that it's the exact same as MMC3. Look at the following piece of ultra-optimized code that bankswitch a 16k prg bank, the first part is MMC1, and the second does the exact same with the MMC3 :
Code:
lda #$01
ldx #$00
stx Reg3
sta Reg3
sta Reg3
stx Reg3
stx Reg3

ldx #$06
ldy #$18
stx $8000
sty $8001
inx
iny
stx $8000
sty $8001

Both are exactly 24 cycles long.

On the MMC3, unless you're mapper-hacking, you probably want the two 8 KiB banks pointed at different places, switched separately instead of as a unit.

EDIT: removed bad example

by on (#74459)
how about just implement a way to check that you're on the right bank before leaving the bank switch routine.. if you're not, do the routine again

kinda dirty but if it works, it works

by on (#74461)
And then end up in an endless loop because you keep writing five times in a row, but you keep writing bits 3, 4, 0, 1, 2 instead of 0, 1, 2, 3, 4. Unlike with $2002 reads resetting the $2005/$2006 latch, there isn't anything on the MMC1 that only resets the 5-write state without also resetting the PRG banking mode to fixed-$C000. Not that there's anything wrong with that if you're just using MMC1 as an alternative to adding a 7420 PRG RAM decoder to your UxROM.

by on (#74464)
Or if you are wanting to use CHR-ROM, the other benefit to MMC1 over UxROM.

by on (#74466)
CHR ROM on SFROM/SJROM/SKROM/SLROM needs to be swapped 4 KiB at a time, which in my mind defeats the advantage of CHR ROM over CHR RAM. With CHR ROM on MMC1, you have to repeat the hero's sprite cels in each set of enemy sprite cels.

by on (#74472)
MottZilla wrote:
Or if you are wanting to use CHR-ROM, the other benefit to MMC1 over UxROM.

I don't see many reasons why anyone would want to use CHR-ROM that's swapable in 4KB chunks over CHR-RAM though. It's not like you'll be doing CHR animations, because that would require a lot of tiles (the non-animated ones) to be repeated.

The only reason I can think of is PRG-ROM space... If you use CHR-ROM there will be 256KB of PRG-ROM just for the program, while with CHR-RAM, under normal circumstances, you'd have to share the PRG-ROM space with the tiles.
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74476)
Yep, found the problem. Clueless' first hypothesis was correct:

clueless wrote:
Part way through changing the MMC1 bank via the 'lsr, sta' unrolled loop, your code gets interrupted, and the interrupt handler resets the latch, changes banks, does its work, then resets the bank back to what it found on entry. Your "main" thread then resumes banging out the final bits tot he MMC1 bank register, which is no longer properly latched, so the MMC1 sees an incomplete switch request.


My problem in bug-checking was that I was ONLY checking for this sound engine backup-bank/switch-bank routine I described in the first post. However, as I explained, many different sections of code utilize the simple PRG bank switching subroutine. The PRG bank always gets backed up before jumping to it and then restored later when the engine is ready to return to the other swappable banks. When I did a check for the actual bank-switch sub, on the immediate previous occurance this sub was called it was indeed cut up by my NMI. It only got through four writes to $E000 and then NMI happened.

Ugh... I thought I'd had my code timed better to keep everything condensed within one frame, but it appears I was wrong.

Now I first started thinking of trying to let the problem go away as I further optimized the code, but it seems like I'd better have one of the fixes you guys mentioned just in case the code does spill out of frame here and there, like some of the extra checks within the sub that Bregalad mentioned and so on. Like I said, I thought I had everything safely working within the frame with twenty-odd scanlines to spare, but I may be getting to the point on my project where it's too hard to gae-ron-tee that everything will fit within the frame 100% of the time.
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74479)
bigjt_2 wrote:
Like I said, I thought I had everything safely working within the frame with twenty-odd scanlines to spare, but I may be getting to the point on my project where it's too hard to gae-ron-tee that everything will fit within the frame 100% of the time.

See? I've been told that I overcomplicate things when I suggest newbies use more robust NMI handlers, but it's almost a certainty that one day they will reach the CPU's limit, and then they'll be dealing with a very hard to track bug. One could argue that dealing with this problem is a part of the learning process, and I kinda agree, but there are cases when fixing this is very frustrating because it requires great changes in the game's architecture.

by on (#74480)
tepples wrote:
And then end up in an endless loop because you keep writing five times in a row, but you keep writing bits 3, 4, 0, 1, 2 instead of 0, 1, 2, 3, 4. Unlike with $2002 reads resetting the $2005/$2006 latch, there isn't anything on the MMC1 that only resets the 5-write state without also resetting the PRG banking mode to fixed-$C000.



ok, add a check to see if vblank fired during the routine (using a flag or frame counter) and if it did, reset the mapper too. if you have the mapper swapping routine in the fixed bank then you should be ok right?

by on (#74481)
tepples wrote:
CHR ROM on SFROM/SJROM/SKROM/SLROM needs to be swapped 4 KiB at a time, which in my mind defeats the advantage of CHR ROM over CHR RAM. With CHR ROM on MMC1, you have to repeat the hero's sprite cels in each set of enemy sprite cels.


One use is in Ninja Gaiden the background is swapped between the status bar and the playfield so that you have more graphical tiles available for the backgrounds. With CHR-RAM you cannot do this. Though I suppose if you made your own MMC1 with 32kb of CHR-RAM then there would be no point in CHR-ROM over it with its large CHR chunk size.

But that just reinforces the point that it would be nice for homebrew to have a mapper that is smoother and more capable. You can always re-purpose a MMC3 but if you plan to produce your game on any scale you'll be stuck using donors rather than being able to have new parts. Although I think I mentioned before I would assume if you published your game through RetroZone that MMC3 wouldn't be an issue.
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74482)
tokumaru wrote:
One could argue that dealing with this problem is a part of the learning process...

Yep!
tokumaru wrote:
... but there are cases when fixing this is very frustrating because it requires great changes in the game's architecture.

And yep again.

Fixed it! I was reluctant to disable my NMI because I'm doing sprite 0 hit for my status bar. So whenever I disable my NMI interrupt during gameplay, everything goes to hell.

Let me describe real quick what I did. A lot of this will be real basic to a lot of you, but just in case it might help some other people with a similar issue in the future.

I took advantage of a variable already in my NMI handler. This variable (called sleeping) gets set to 0 at the end of the NMI handler just before the registers are restored. In the gameloop, it doesn't proceed past the continuous loop into the rest of the engine unless this "sleeping" is 0 (meaning NMI has fired). This particular process I learned from Metalslime, but of course it's a variant of what a lot of you do in your gameloops.

I basically applied the same thing to the PRG bank switching subroutine. At the end of the sub, it now checks if the variable is 0. If not, it branches to RTS. If it is, then it resets the MMC1 latch by writing $80 to $8000 (just to be safe) and then jumps back to the beginning of the sub to re-write to REG3. Also, I've now added a couple of lines pushing my current PRG bank # to the stack (where the registers get pushed) at the beginning on NMI and pulling at the end. Yeah, I think this describes all of what I did.

Regardless, I set a breakpoint on the new part of bankswitching sub and it's working exactly like I needed it to. Also tested it on the NES and there wasn't any noticeable slowdown. Then again, I should hope not, as it's only dropping one of 60 frames about 3% of the time. (This bug frame overflow was really random, another thing that made it so damn hard to find.)

It's still going to be my policy to keep things within the frame as much as possible, but it's nice to have this safegaurd here in case that doesn't happen.

Thanks for the help folks!
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74483)
bigjt_2 wrote:
I took advantage of a variable already in my NMI handler. ... At the end of the sub, it now checks if the variable is 0. If not, it branches to RTS. If it is, then it resets the MMC1 latch by writing $80 to $8000 (just to be safe) and then jumps back to the beginning of the sub


heh, that's exactly what i suggested like 30 minutes ago :D

by on (#74484)
MottZilla wrote:
tepples wrote:
CHR ROM on SFROM/SJROM/SKROM/SLROM needs to be swapped 4 KiB at a time, which in my mind defeats the advantage of CHR ROM over CHR RAM.

One use is in Ninja Gaiden the background is swapped between the status bar and the playfield so that you have more graphical tiles available for the backgrounds. With CHR-RAM you cannot do this.

I understand what you mean. I've never played Ninja Gaiden, but from screenshots, its status bar could also use a lot of slimming down: "SCORE STAGE TIMER NINJA ENEMY" Does it use one set of enemies for all levels? Or how many times does it repeat Ryu's sprite cels?

If I use only three-fourths of the sprite half of the pattern table (and I can prove that with double buffering this can be feasible), that frees up 64 tiles out of which to build a status bar.
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74485)
frantik wrote:
heh, that's exactly what i suggested like 30 minutes ago :D


Yes, the only difference was I really didn't need to add something, per se, as there was already something there to use (the sleeping variable). Nonetheless it was a helpful suggestion, along with the others. Danke!

by on (#74486)
MottZilla wrote:
One use is in Ninja Gaiden the background is swapped between the status bar and the playfield so that you have more graphical tiles available for the backgrounds.

Touché! This is indeed an advantage of CHR-ROM over CHR-RAM, even if the mapper can only switch large chunks of tiles.

Quote:
But that just reinforces the point that it would be nice for homebrew to have a mapper that is smoother and more capable.

I would really like that, one without the oversights present in the Nintendo mappers, but just like with iNES replacements, talks about a homebrew mapper come and go every once in a while but nothing ever changes.

Quote:
Although I think I mentioned before I would assume if you published your game through RetroZone that MMC3 wouldn't be an issue.

I don't know, they can't seem to get the MMC3 right on the PowerPak... Unless something changed since the last time I checked.
Re: Is there anything that could alter an MMC1 reg3 write?
by on (#74498)
bigjt_2 wrote:
frantik wrote:
heh, that's exactly what i suggested like 30 minutes ago :D


Yes, the only difference was I really didn't need to add something, per se, as there was already something there to use (the sleeping variable). Nonetheless it was a helpful suggestion, along with the others. Danke!


well if it helped at all thats cool :)

by on (#74499)
Oh I'm sorry to have stated my solution will solve all problems, because whoever corrected me is right, it's a bad idea to say that !

In this case it happened to solve the problem, but he's right that it might have been something else as well.

Maybe a wiki article about MMC1 writing techniques should be made ? I should include :
1) The normal way to do it (disable interrupts)
2) The tricky workarround (if you rely on tight NMI timing or if you sync with NMIs like Battletoads)
3) Some other workarround that works with 32kb or high 16kb PRGROM switching

by on (#74549)
tepples wrote:
MottZilla wrote:
tepples wrote:
CHR ROM on SFROM/SJROM/SKROM/SLROM needs to be swapped 4 KiB at a time, which in my mind defeats the advantage of CHR ROM over CHR RAM.

One use is in Ninja Gaiden the background is swapped between the status bar and the playfield so that you have more graphical tiles available for the backgrounds. With CHR-RAM you cannot do this.

I understand what you mean. I've never played Ninja Gaiden, but from screenshots, its status bar could also use a lot of slimming down: "SCORE STAGE TIMER NINJA ENEMY" Does it use one set of enemies for all levels? Or how many times does it repeat Ryu's sprite cels?

If I use only three-fourths of the sprite half of the pattern table (and I can prove that with double buffering this can be feasible), that frees up 64 tiles out of which to build a status bar.


As the game is, no you can't free up any space. It is all used. There are no significant free BG or Sprite tiles in banks. Another issue is the game also needs CHR-ROM for bankswitching between Cinema Scene graphics and the font. Though I suppose it might be possible to use the other 4K of pattern tables and switch between them although now we are just talking about it being possible to perhaps achieve something similar, but the point is that NG does need CHR-ROM as it was built. If it did not, it would have used CHR-RAM as CHR-ROM repeats Ryu's sprites since the enemy graphics change depending on the level or boss.

Another issue is the cinema scenes would require substantial pauses to load graphics between each picture where as with CHR-ROM it is instant.

by on (#74550)
MottZilla wrote:
As the game is, no you can't free up any space.

I don't think anyone is considering converting the actual game to CHR-RAM, tepples was probably just thinking of ways to hypothetically "remake" the game with CHR-RAM instead of CHR-ROM, as an exercise.

Quote:
It is all used.

If I understand correctly, his idea was to dynamically load a single frame of animation worth of player tiles to a small section of VRAM as demanded by the game engine, so that there was no need keep all of them mapped at all times. This would free up a great deal of tiles, maybe enough for the status bar tiles.

I seem to remember that there was an item or something that created a ghost of the player, and in this case each copy would need to display different animation frames. This kinda gets in the way of freeing up those tiles.

Quote:
Another issue is the cinema scenes would require substantial pauses to load graphics between each picture where as with CHR-ROM it is instant.

I don't think a couple of black frames would make such a difference (apparently the screen already flashes black between some scenes).

by on (#74566)
Bregalad wrote:
Maybe a wiki article about MMC1 writing techniques should be made ? I should include :
1) The normal way to do it (disable interrupts)
2) The tricky workarround (if you rely on tight NMI timing or if you sync with NMIs like Battletoads)
3) Some other workarround that works with 32kb or high 16kb PRGROM switching

Article about this and interrupt awareness in general would be good. There are other problematic things like updating music pointers (i.e. calling music init routines) from the "main thread" that can cause troubles if the programmer isn't careful.

MottZilla wrote:
but the point is that NG does need CHR-ROM as it was built. If it did not, it would have used CHR-RAM as CHR-ROM repeats Ryu's sprites since the enemy graphics change depending on the level or boss.

Another issue is the cinema scenes would require substantial pauses to load graphics between each picture where as with CHR-ROM it is instant.

If I had to choose a config for a new game, I would go with bankswitchable CHR-RAM. Maybe like 32K.

by on (#74992)
tokumaru wrote:
I don't think anyone is considering converting the actual game to CHR-RAM, tepples was probably just thinking of ways to hypothetically "remake" the game with CHR-RAM instead of CHR-ROM, as an exercise.

Quote:
It is all used.

If I understand correctly, his idea was to dynamically load a single frame of animation worth of player tiles to a small section of VRAM as demanded by the game engine, so that there was no need keep all of them mapped at all times. This would free up a great deal of tiles, maybe enough for the status bar tiles.

I seem to remember that there was an item or something that created a ghost of the player, and in this case each copy would need to display different animation frames. This kinda gets in the way of freeing up those tiles.

Quote:
Another issue is the cinema scenes would require substantial pauses to load graphics between each picture where as with CHR-ROM it is instant.

I don't think a couple of black frames would make such a difference (apparently the screen already flashes black between some scenes).


Actually given my extensive workings with Ninja Gaiden, tonight for fun I converted it to UNROM. I cut out the Cinema Scenes but the rest of the game is there and works. It fits into 128K (though without much to spare) even though it was 256KB before. The Cinema stuff takes up about half of the CHR and probably half of the used PRG.

There is no room in BG graphics for a status bar. For sprites, I wouldn't really know how to go about trying to dynamically load the current animation frame. There are no clones (Phantom Doubles is their actual name) in NG1, only NG2. So the idea does work assuming you actually have enough time to transfer all the tiles needed each frame.

An idea that might also work for a slimmed down Status bar would be to redraw the Item Pickup boxes to reuse and reduce the total tiles used to try to have enough for a status bar. Something like 20 - 24 or maybe more tiles are used by items the player can pickup. So if you cut these down you could probably get to still display the life bars, Score, Chi (special weapon ammo), current level, and time.

Not planning on releasing anything about it on UNROM since the ROM is far too different for any IPS patches or anything like that to not contain huge amounts of copyrighted material. But it could have been done though for the Cinema's I think UOROM would have been needed for the capacity. But I guess that just again proves you don't need a fancy mapper to make a good game.