emulating MMC5

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
emulating MMC5
by on (#47894)
I'm about to start writing some MMC5 emulation code so I can get Castlevania 3 to run on my emulator. Anything special I should be aware of before tackling this? Any gotchas, etc.? Not planning on implementing ExRAM (yet), since it sounds like C3 doesn't use it. Does it use IRQs?

Thanks,
James

by on (#47897)
Quote:
Any gotchas, etc.?


Not really. MMC5 features are greatly separated in the register layout, so you can easily add support for features one by one without much worry.

About the only unusual obstacle you have to face right off the bat is the fact that the BG has separate CHR space from the sprites (ie: there's 12K of CHR "swapped in" instead of the usual 8K -- the BG uses a separate 4K for tiles so it doesn't have to share with the sprites).

Castlevania 3 does rely on that.

CV3 does not use ExRAM, I'm pretty sure. I don't even think it uses WRAM.

CV3 does use IRQs

by on (#47898)
Quote:
BG has separate CHR space from the sprites


Yeah, I'm sort of aware of this from some of the initial research I've done. My plan for handling this is to simply swap in the appropriate bank before drawing bg/sprites (scanline based rendering). e.g.

Code:
mapper->setMMC5Chr(MMC5_CHR_BACKGROUND); //map in bg chr bank
DrawBackgroundLine();
mapper->setMMC5Chr(MMC5_CHR_SPRITE); //map in sprite chr bank
DrawSpriteLine();


I'm assuming it's ROM only, so I don't need to worry about writes.... or am I over-simplifying it?

by on (#47899)
p.s. -- thanks a lot for the info. Very helpful!

by on (#47901)
Quote:
Not planning on implementing ExRAM (yet), since it sounds like C3 doesn't use it. Does it use IRQs?

Castlevania 3 use IRQs to show the status bar, and does a second scroll split for the second form of Death and the last 2 forms of Dracula. It does use EXRAM and IRQs in Aquarius level when the water is rising, the level is using the normal 2 nametables, while the water is from the third nametable in EXRAM. Other levels should be OK without EXRAM support though. It doesn't have WRAM on the board (altough I don't think it relies on open bus or anything like that).

by on (#47905)
Getting MMC5 emulated enough to run Castlevania 3 is pretty straight forward. The only trouble I had with it was I messed up acknowledgement of IRQs causing problems. There isn't anything tricky about it if you just want basic Castlevania 3 support. EXRAM support is not a big deal and you shouldn't have any trouble adding that I would think.

by on (#47972)
Quote:
The only trouble I had with it was I messed up acknowledgement of IRQs causing problems.


I may have the same problem. Everything seems to work ok until I get to the first vertical scrolling location in level 1:

Image

If I fiddle with the IRQ counter after the IRQ counter reaches the target scanline, I can sort of get the background to display properly.

Any ideas?

Code:
void Nes::Mapper5::HBlank(int scanline)
{
   if (scanline < 241)
   {
      if(ppu->DrawingEnabled())
      {
         if (inFrame == 0)
         {
            inFrame = 1;
            irqCounter = 0;
            irqPending = 0;
         }
         else
         {
            irqCounter++;
            if (irqCounter == irqTarget)
            {
               irqPending = 1;
               if (irqEnable)
               {
                  cpu->ExecuteIRQ();

               }
            }
         }
      }
      else
      {
         inFrame = 0;
      }
   }
   else if (scanline == 241)
   {
      inFrame = 0;
      irqCounter = 0;
   }
}

void Nes::Mapper5::WriteByte(unsigned short address, unsigned char value)
{
   switch (address)
   {
//...
   case 0x5203:
      irqTarget = value;
      break;
   case 0x5204:
      if (!irqEnable)
      {
      irqEnable = value & 0x80;
      if (irqPending && irqEnable)
         cpu->ExecuteIRQ();
      }
      break;
//...
}

unsigned char Nes::Mapper5::ReadByte(unsigned short address)
{
   switch (address)
   {
//...
   case 0x5204:
      int val = (inFrame << 6) | (irqPending << 7);
      irqPending = 0;
      return val;
   }
//...
}



by on (#47974)
One scanline after the IRQ fires, IRQ is automatically acknowledged.
Or in other words, every scanline with frame on that doesn't trip the IRQ also acknowledges it.

by on (#47975)
thanks. doesn't seem to make a difference in this case though... when should the irqcounter be reset to 0? Only when the In-Frame signal is clear?

by on (#47976)
fixed :). Turned out to be a bug in my cpu. I wasn't handling maskable interrupts properly.

(and just so it's clear which area I was referring to in case someone comes across this later)

Image

by on (#47989)
Dwedit wrote:
One scanline after the IRQ fires, IRQ is automatically acknowledged.
Or in other words, every scanline with frame on that doesn't trip the IRQ also acknowledges it.


This is not true. At least not to my knowledge.

Do you have a source for this?

by on (#48022)
Quote:
This is not true. At least not to my knowledge.


In which cases should interrupts be acknowledged, then? Only when the In Frame signal is clear when MMC5 detects a scanline? Not when any registers are read/written to? Not when rendering stops?

Also, I'm assuming that acknowledged means 'pending flag cleared, IRQ line high'. Please correct me if I'm wrong.

by on (#48023)
Quote:
In which cases should interrupts be acknowledged, then?


Now that you mention it -- I remember hearing somewhere that they're acknowledged when rendering stops (and of frame, or when PPU is switched off) -- but this is not what I wrote in my doc. To be honest I don't really know the exact behavior.

Does anyone have an MMC5 test cart?

by on (#48029)
- I though Kevtris had REd CV3 including the IRQ timing...?

by on (#48032)
That doc has disappeared from his site, and it lacked exact timing details. Though if someone has a copy of that doc...