MMC3: IRQ counter has multiple correctness issues
- Dominant language
- JavaScript
- Stars
- 6.4k
- Forks
- 857
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The MMC3 scanline IRQ counter has several fundamental issues that affect split-screen effects in games like Super Mario Bros. 3, Kirby's Adventure, and many others.
### Issue 1: \$C000/\$C001 register roles are swapped
Per nesdev, \`\$C000\` sets the **latch** (reload value) and \`\$C001\` triggers a **reload**. The code has them backwards:
\`\`\`javascript
case 0xc000:
this.irqCounter = value; // WRONG: should set irqLatchValue
break;
case 0xc001:
this.irqLatchValue = value; // WRONG: should set irqReload flag
break;
\`\`\`
### Issue 2: Counter logic is fundamentally wrong
Current (\`mapper4.js:221-231\`):
\`\`\`javascript
clockIrqCounter() {
if (this.irqEnable === 1) {
this.irqCounter--;
if (this.irqCounter < 0) {
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_NORMAL);
this.irqCounter = this.irqLatchValue;
}
}
}
\`\`\`
Problems:
1. Always decrements instead of reloading from latch when counter=0 or reload flag is set
2. No reload flag tracked at all
3. IRQ fires on **underflow** (<0) instead of when counter **reaches** 0
4. Counter logic skipped entirely when IRQ is disabled (should still clock)
### Issue 3: \$E000 doesn't acknowledge pending IRQ
Writing to \`\$E000\` should both disable IRQs AND acknowledge any pending IRQ. Current code only disables.
### Correct behavior
Per [nesdev MMC3 wiki](https://www.nesdev.org/wiki/MMC3), when the IRQ counter is clocked:
1. If counter is 0 OR reload flag is set → reload counter from latch, clear reload flag
2. Otherwise → decrement counter
3. If counter is 0 AND IRQs enabled → trigger IRQ
## References
- [MMC3 wiki](https://www.nesdev.org/wiki/MMC3)
- [MMC3 IRQ behavior](https://forums.nesdev.org/viewtopic.php?t=19413)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.