Page 1 of 2

MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 1:25 pm
by colinvella
NOTE: I fixed the problem - thanks to everyone's help on this thread!
Solution may be found towards the end of the thread

I have done quite a few strides with my MMC5 mapper implementation, and in the process rewrote the mirroring mode to allow the generality required by MMC5, and also a mechanism for reading nametables 2 and 3 externally from the PPU (that is the MMC5 mapper in this case). The $5120-$5512B CHR bank switching range seems to be working well both for 8x8 and 8x16 sprite modes. Fill mode also seems to be working well, although the only test in this regard (Castlevania III), fill mode is only used as a temporary blank screen transition, from what I gather. The Intro of the game is also working well (the moving reel bit), except for a tiny glitch at the top 8 pixels, which I suspect could be due to a problem with the scanline irq counter.

Now I am struggling with trying to get the first floor of the castle within Castlevania III to look right. The game's code up to this point seems to only set Extanded Ram mode zero, and to be honest, I'm not quite sure how to apply the Expanded Ram mode rules, for instance if at the point of reading/writing to the range $5C00-$5FFF, or when the PPU reads nametable C, or for both cases. I'm referring to the following:

Code: Select all

Extended RAM mode ($5104)
7  bit  0
---- ----
xxxx xxXX
       ||
       ++- Specify extended RAM usage
0 - Use as extra nametable (possibly for split mode)
1 - Use as extended attribute data (can also be used as extended nametable)
2 - Use as ordinary RAM
3 - Use as ordinary RAM, write protected
From what I understand Mode zero simply allows a name table C to be read from Extended Ram (both tiles and attributes). From what I gather, Castlevania is trying to build the castle's first floor from this. Am I correct?

I'm attaching a screenshot for reference in the hope that it might help lead to the cause of the problem:

Castle First Floor:
Image

The garbled screen is directly above the castle ground floor:
Image

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 2:24 pm
by koitsu
Not sure if this will help you or not, but: the screenshot depicting "garbled graphics" appears to have nametable/screen layout that matches the very end of the first section when you start the game, before you enter the door (i.e. start the game, go all the way to the right, but don't open the door -- that screen), just with wrong CHR data. Attached is a screenshot as evidence.

A lot of early emulators got MMC5 wrong (some may still!), so the mess-ups in your screenshots look very familiar. I just don't know what the root cause is in every case (varies per emulator).

My impression is that when $5104 is %00, the MMC5's expansion RAM is used as an additional nametable that can be mapped at $2000/2400/2800/2C00 in PPU space (controlled with $5105). You might try reading Disch's mapper doc (005.txt) to get a different (rephrased) view of how it works.

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 2:30 pm
by Zepper
In short words: IRQ timing problem, not nametable-based.

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 2:41 pm
by colinvella
koitsu wrote:Not sure if this will help you or not, but: the screenshot depicting "garbled graphics" appears to have nametable/screen layout that matches the very end of the first section
Well spotted! I do see it now. Cheers :)

Still not sure what's happening though.

Edit: If I go down the stairs to ground floor and then back up. The nametable from the ground floor seems to be used:
Image

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 2:43 pm
by colinvella
Zepper wrote:In short words: IRQ timing problem, not nametable-based.
Could you explain in more detail please? Why is it so?

Thanks

This is my IRQ counter code BTW. It may well have some incorrect boundary condition handling:

Code: Select all

        public override void StepVideo(int scanLine, int cycle, bool showBackground, bool showSprites)
        {
            ppuRendering = scanLine >= 0 && scanLine < 240 && (showBackground || showSprites);

            if (!ppuRendering)
                irqCounter = 0;

            if (cycle != 0)
                return;

            if (scanLine == 0)
            {
                irqPending = false;
                irqCounter = 0;
            }
            else if (scanLine > 0)
                ++irqCounter;

            if (irqCounter == irqScanline)
            {
                irqPending = true;
                if (irqEnabled)
                    TriggerInterruptRequest?.Invoke();
            }

            if (scanLine > 239)
            {
                irqPending = false;
            }
        }

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 3:25 pm
by koitsu
I'd suggest logging writes to $5104 and $5105 to see what may be going on. I get the impression those might be tweaked within the IRQ handler as well, but I'm not sure. I haven't spent much time analysing this game (last time was a few years ago where we began discussing the exact same registers in question; fellow in question posted his MMC5 emulation code as well, including IRQ).

Possibly you have an uninitialised variable somewhere, re: going down the stairs to the ground floor and back up? Grasping at straws here; there isn't a lot of data to go on. :\

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Mon Jun 27, 2016 5:34 pm
by Zepper

Code: Select all

MMC5 IRQ timing
---------------

READS
   $5204:  [PI.. ....]
     P = IRQ currently pending
     I = "In Frame" signal 
   Reading $5204 will clear the pending flag (acknowledging the IRQ).

WRITES
   $5203:  [vvvv vvvv]
     v = IRQ latch
   $5204:  [E... ....]
     E = IRQ enable (1=enabled)

=============
Operation

-At any time when the MMC5 detects that the PPU is inactive*,
the In Frame signal is automatically cleared.

*inactive if out of visible field, or background and sprites are disabled.
(return).

-If the scanline number has changed...

  - If In Frame Signal is clear...
    a) Set In Frame signal
    b) Reset IRQ counter to 0
    c) Clear IRQ pending flag (automatically acknowledging IRQ)
   - otherwise...
    a) Increment IRQ counter
    b) If IRQ counter now equals the trigger value, raise IRQ pending flag

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 3:40 am
by colinvella
koitsu wrote:I'd suggest logging writes to $5104 and $5105 to see what may be going on. I get the impression those might be tweaked within the IRQ handler as well, but I'm not sure. I haven't spent much time analysing this game (last time was a few years ago where we began discussing the exact same registers in question; fellow in question posted his MMC5 emulation code as well, including IRQ).

Possibly you have an uninitialised variable somewhere, re: going down the stairs to the ground floor and back up? Grasping at straws here; there isn't a lot of data to go on. :\
I added some tracing - here's what I found.
ExRamMode is set only once at the beginning with value $00

The mirror mode is changed a few times for the intro and start screens, alternating between the Pseudo 4 screen mode (11 10 01 00) , Single Page 1 (01 01 01 01) and Vertical (01 00 01 00).
After a brief use of fill mode (11 11 11 11), presumably for a quick transition to black, the game rapidly alternates between Pseudo 4 Screen and Vertical during gameplay (the ruins/garden outside the castle). I'm wondering.. are these rapid mirroring changes to be expected?

Code: Select all

ExRamMode ($5104) = $00 (00000000)        <----- Extended Ram Mode set to 0
Mirror Mode ($5105) = Vertical($44) (01000100)    <----- game intro (movie reel thingy + name select etc.)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Single1($55) (01010101)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Single1($55) (01010101)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = SingleFillMode($FF) (11111111) <----- black screen before playing
Mirror Mode ($5105) = Pseudo4($E4) (11100100)          <----- gameplay starts here
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)
Mirror Mode ($5105) = Pseudo4($E4) (11100100)
Mirror Mode ($5105) = Vertical($44) (01000100)

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 3:59 am
by colinvella
I did a minor change to my IRQ counter code (reset IRQ counter when the IRQ latch is written in $5203) and I can already see a difference, parts of the screen seem to have updated correctly as I can see some stained glass windows. I probably have to overhaul the IRQ counter logic as per the algorithm you suggested.

Image

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 4:45 am
by colinvella
I have a question concerning when an IRQ is raised by the counter. The specs say that when the IRQ counter matches the IRQ latch specified by a write to $5203, the "Irq Pending Flag should be raised". Does this mean that the CPU should trigger the IRQ (as in jump to the IRQ vector) as soon as the mapper processing step is over, or should there be some kind of delay? If this is the case, does this allow for the IRQ counter to "cancel" an IRQ request?

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 5:32 am
by James
I had the same problem and it turned out to be a CPU issue. I don't recall the exact details, but I think it had to do with handling the case where the interrupt disable flag was cleared while the irq line was being asserted.

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 8:11 am
by Zepper
colinvella wrote:I have a question concerning when an IRQ is raised by the counter. The specs say that when the IRQ counter matches the IRQ latch specified by a write to $5203, the "Irq Pending Flag should be raised". Does this mean that the CPU should trigger the IRQ (as in jump to the IRQ vector) as soon as the mapper processing step is over, or should there be some kind of delay? If this is the case, does this allow for the IRQ counter to "cancel" an IRQ request?
No delay.
Just note that you must add the InFrame bits for reads.

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 8:42 am
by colinvella
I added more logs for writing to $5203 (IRQ counter) and $5204 (IRQ enable/disable) and from what I gather the game is doing the following:

During the first horizontal walk outside the castle, it sets the IRQ counter to 46, presumably to render the game's HUD in the top 4 rows from one nametable, before splitting to the level nametable (vertical mirrored to allow horizontal scrolling)

Once the player gets inside the castle and walks up to the upper part, the game starts setting the IRQ counter successively to 41, 42, 52 and 53, interspersed with toggles to the IRQ enable flag. I don't know why it is doing this, but it seems to result in too much of the HUD being shown, and not enough of the background. It's as if the horizontal split required between HUD and background is happening much further down the screen and the resulting garbage is simply unused tiles in the nametable used for the HUD.

An excerpt from my debug log:

Code: Select all

MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42
MMC5 IRQ Counter($5203) = 52
MMC5 Mirror Mode ($5105) = Single1 ($55) (%01010101)
MMC5 IRQ Counter($5203) = 53
MMC5 IRQ ($5204) = Disabled
MMC5 Mirror Mode ($5105) = 216 ($D8) (%11011000)
MMC5 IRQ ($5204) = Enabled
MMC5 IRQ Counter($5203) = 41
MMC5 IRQ Counter($5203) = 42

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 9:02 am
by James
Are you properly handling this scenario?

- CPU I flag set
...
- MMC5 asserts IRQ (CPU should ignore)
...
- CPU I flag cleared (e.g., CLI or PLP) <-- IRQ should be handled here (after the next instruction)

Re: MMC5 Castlevania III - garbled castle first floor

Posted: Tue Jun 28, 2016 1:11 pm
by colinvella
James wrote:Are you properly handling this scenario?

- CPU I flag set
...
- MMC5 asserts IRQ (CPU should ignore)
...
- CPU I flag cleared (e.g., CLI or PLP) <-- IRQ should be handled here (after the next instruction)
I actually had my CPU coding wrong there. My I flag was effectively suppressing pending IRQs and hence doing CLI would not have triggered the IRQ afterwards. I'm changing this but I think I have a problem elsewhere. Still.. thanks for the tip.. one step closer to emulating the real thing! :)