2011-10-01 12:06:48 +00:00
|
|
|
struct MMC1 : Chip {
|
2015-12-05 05:44:49 +00:00
|
|
|
MMC1(Board& board) : Chip(board) {
|
|
|
|
revision = Revision::MMC1B2;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto main() -> void {
|
2016-02-09 11:51:12 +00:00
|
|
|
if(writedelay) writedelay--;
|
|
|
|
tick();
|
2015-12-05 05:44:49 +00:00
|
|
|
}
|
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
auto addrPRG(uint addr) -> uint {
|
2015-12-05 05:44:49 +00:00
|
|
|
bool region = addr & 0x4000;
|
2016-06-27 13:07:57 +00:00
|
|
|
uint bank = (prgBank & ~1) + region;
|
2011-10-01 12:06:48 +00:00
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
if(prgSize) {
|
2015-12-05 05:44:49 +00:00
|
|
|
bank = (region == 0 ? 0x0 : 0xf);
|
2016-06-27 13:07:57 +00:00
|
|
|
if(region != prgMode) bank = prgBank;
|
Update to v082r32 release.
byuu says:
Added delay to MMC1 register writes, to fix Bill & Ted's Godawful
Adventure.
Fixed up MMC5 RAM+fill mode, and added EXRAM mode support (8x8
tiles/attributes.)
Just Breed is fully playable now.
MMC5 is a total pain in the ass, the documentation on it is just
terrible. I basically just tried seven hundred variations until
something worked.
I still need to add MMC5 vertical split screen (for one single game's
attract screen, ugh), and the extra sound channels.
Would like to rework the NES APU first. Since the pulse channels are
identical sans sweep, it'd be nice to just inherit those and mask out
the sweep register bit writes.
So that probably won't make it into the first release, at least.
Still, overall I think it'll be an impressive showing of complex mappers
for a first release: MMC3, MMC5, VRC6 and 5B. The latter two with full
audio. The only other really, really hard bit is the VRC7 audio,
supposedly.
2011-10-08 07:34:16 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
return (bank << 14) | (addr & 0x3fff);
|
Update to v082r32 release.
byuu says:
Added delay to MMC1 register writes, to fix Bill & Ted's Godawful
Adventure.
Fixed up MMC5 RAM+fill mode, and added EXRAM mode support (8x8
tiles/attributes.)
Just Breed is fully playable now.
MMC5 is a total pain in the ass, the documentation on it is just
terrible. I basically just tried seven hundred variations until
something worked.
I still need to add MMC5 vertical split screen (for one single game's
attract screen, ugh), and the extra sound channels.
Would like to rework the NES APU first. Since the pulse channels are
identical sans sweep, it'd be nice to just inherit those and mask out
the sweep register bit writes.
So that probably won't make it into the first release, at least.
Still, overall I think it'll be an impressive showing of complex mappers
for a first release: MMC3, MMC5, VRC6 and 5B. The latter two with full
audio. The only other really, really hard bit is the VRC7 audio,
supposedly.
2011-10-08 07:34:16 +00:00
|
|
|
}
|
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
auto addrCHR(uint addr) -> uint {
|
2015-12-05 05:44:49 +00:00
|
|
|
bool region = addr & 0x1000;
|
2016-06-27 13:07:57 +00:00
|
|
|
uint bank = chrBank[region];
|
|
|
|
if(chrMode == 0) bank = (chrBank[0] & ~1) | region;
|
2015-12-05 05:44:49 +00:00
|
|
|
return (bank << 12) | (addr & 0x0fff);
|
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
auto addrCIRAM(uint addr) -> uint {
|
2015-12-05 05:44:49 +00:00
|
|
|
switch(mirror) {
|
|
|
|
case 0: return 0x0000 | (addr & 0x03ff);
|
|
|
|
case 1: return 0x0400 | (addr & 0x03ff);
|
|
|
|
case 2: return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
|
|
|
|
case 3: return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
}
|
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
auto writeIO(uint addr, uint8 data) -> void {
|
2015-12-05 05:44:49 +00:00
|
|
|
if(writedelay) return;
|
|
|
|
writedelay = 2;
|
|
|
|
|
|
|
|
if(data & 0x80) {
|
|
|
|
shiftaddr = 0;
|
2016-06-27 13:07:57 +00:00
|
|
|
prgSize = 1;
|
|
|
|
prgMode = 1;
|
2015-12-05 05:44:49 +00:00
|
|
|
} else {
|
|
|
|
shiftdata = ((data & 1) << 4) | (shiftdata >> 1);
|
|
|
|
if(++shiftaddr == 5) {
|
|
|
|
shiftaddr = 0;
|
|
|
|
switch((addr >> 13) & 3) {
|
|
|
|
case 0:
|
2016-06-27 13:07:57 +00:00
|
|
|
chrMode = (shiftdata & 0x10);
|
|
|
|
prgSize = (shiftdata & 0x08);
|
|
|
|
prgMode = (shiftdata & 0x04);
|
2015-12-05 05:44:49 +00:00
|
|
|
mirror = (shiftdata & 0x03);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
2016-06-27 13:07:57 +00:00
|
|
|
chrBank[0] = (shiftdata & 0x1f);
|
2015-12-05 05:44:49 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
2016-06-27 13:07:57 +00:00
|
|
|
chrBank[1] = (shiftdata & 0x1f);
|
2015-12-05 05:44:49 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2016-06-27 13:07:57 +00:00
|
|
|
ramDisable = (shiftdata & 0x10);
|
|
|
|
prgBank = (shiftdata & 0x0f);
|
2015-12-05 05:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto power() -> void {
|
|
|
|
writedelay = 0;
|
Update to v082r31 release.
byuu says:
Enable Overscan->Mask Overscan [best I'm doing]
Video settings -> Overscan mask: (horizontal, vertical: 0-16 on each
side) [only works on NES+SNES]
BPS patching works for NES+SNES+GB; note that long-term I want BPS to
only patch headerless PRG+CHR files, but we'll need a database
/ completed board mapping system first.
MMC1 splits the board/chip markups a bit better. My attempts to emulate
the extra CHR bits per hardware fail repeatedly. Docs do not explain how
it works at all.
Emulated enough of the MMC5 to play Castlevania 3.
The MMC5 is easily the most complicated mapper the NES has to offer, and
of course, has the most pitifully vague and difficult documentation of
any mapper around.
It seems the only way anyone is able to emulate this chip is
empirically.
Everyone else apparently hooks the MMC5 right into the PPU core, which
I of course cannot do. So I had to come up with my own (probably wrong)
way to synchronize the PPU simply by observing CHR bus accesses.
I must say, I over-estimated how well fleshed out the NES hardware
documentation was. Shit hits the fan right after MMC3.
It's miles beyond the GB scene, but I find myself wanting for someone
with the technical writing ability of anomie.
I can't find anything at all on how we're supposed to support the $2007
port reads/writes without it extra-clocking the PPU's bus, which could
throw off mapper timing.
Absolutely nothing at all on the subject anywhere, something everybody
is required to do for all cycle-based emulators and ... nada.
Anyway, I'd like to refine the MMC5 a bit, getting Just Breed playable
even without sound would be really nice (it's a fun game.)
Then we need to get libsnes building again (ugh, getting worn out in
backporting changes to it.)
Once v083 is public, we can start discussing a new API for multiple
emulators.
2011-10-06 09:53:16 +00:00
|
|
|
shiftaddr = 0;
|
2015-12-05 05:44:49 +00:00
|
|
|
shiftdata = 0;
|
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
chrMode = 0;
|
|
|
|
prgSize = 1;
|
|
|
|
prgMode = 1;
|
2015-12-05 05:44:49 +00:00
|
|
|
mirror = 0;
|
2016-06-27 13:07:57 +00:00
|
|
|
chrBank[0] = 0;
|
|
|
|
chrBank[1] = 1;
|
|
|
|
ramDisable = 0;
|
|
|
|
prgBank = 0;
|
2015-12-05 05:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto serialize(serializer& s) -> void {
|
|
|
|
s.integer(writedelay);
|
|
|
|
s.integer(shiftaddr);
|
|
|
|
s.integer(shiftdata);
|
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
s.integer(chrMode);
|
|
|
|
s.integer(prgSize);
|
|
|
|
s.integer(prgMode);
|
2015-12-05 05:44:49 +00:00
|
|
|
s.integer(mirror);
|
2016-06-27 13:07:57 +00:00
|
|
|
s.array(chrBank);
|
|
|
|
s.integer(ramDisable);
|
|
|
|
s.integer(prgBank);
|
Update to v082r31 release.
byuu says:
Enable Overscan->Mask Overscan [best I'm doing]
Video settings -> Overscan mask: (horizontal, vertical: 0-16 on each
side) [only works on NES+SNES]
BPS patching works for NES+SNES+GB; note that long-term I want BPS to
only patch headerless PRG+CHR files, but we'll need a database
/ completed board mapping system first.
MMC1 splits the board/chip markups a bit better. My attempts to emulate
the extra CHR bits per hardware fail repeatedly. Docs do not explain how
it works at all.
Emulated enough of the MMC5 to play Castlevania 3.
The MMC5 is easily the most complicated mapper the NES has to offer, and
of course, has the most pitifully vague and difficult documentation of
any mapper around.
It seems the only way anyone is able to emulate this chip is
empirically.
Everyone else apparently hooks the MMC5 right into the PPU core, which
I of course cannot do. So I had to come up with my own (probably wrong)
way to synchronize the PPU simply by observing CHR bus accesses.
I must say, I over-estimated how well fleshed out the NES hardware
documentation was. Shit hits the fan right after MMC3.
It's miles beyond the GB scene, but I find myself wanting for someone
with the technical writing ability of anomie.
I can't find anything at all on how we're supposed to support the $2007
port reads/writes without it extra-clocking the PPU's bus, which could
throw off mapper timing.
Absolutely nothing at all on the subject anywhere, something everybody
is required to do for all cycle-based emulators and ... nada.
Anyway, I'd like to refine the MMC5 a bit, getting Just Breed playable
even without sound would be really nice (it's a fun game.)
Then we need to get libsnes building again (ugh, getting worn out in
backporting changes to it.)
Once v083 is public, we can start discussing a new API for multiple
emulators.
2011-10-06 09:53:16 +00:00
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
enum class Revision : uint {
|
|
|
|
MMC1,
|
|
|
|
MMC1A,
|
|
|
|
MMC1B1,
|
|
|
|
MMC1B2,
|
|
|
|
MMC1B3,
|
|
|
|
MMC1C,
|
|
|
|
} revision;
|
|
|
|
|
|
|
|
uint writedelay;
|
|
|
|
uint shiftaddr;
|
|
|
|
uint shiftdata;
|
|
|
|
|
2016-06-27 13:07:57 +00:00
|
|
|
bool chrMode;
|
|
|
|
bool prgSize; //0 = 32K, 1 = 16K
|
|
|
|
bool prgMode;
|
2015-12-05 05:44:49 +00:00
|
|
|
uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal
|
2016-06-27 13:07:57 +00:00
|
|
|
uint5 chrBank[2];
|
|
|
|
bool ramDisable;
|
|
|
|
uint4 prgBank;
|
2011-10-01 12:06:48 +00:00
|
|
|
};
|