nes-mmc3/namcot108 differences have become more clear in the past few months. refactor those mappers (split them apart, theyre not as similar as once thought) to reflect new understandings. no functional improvement from this other than maybe some new bugs, but it will help on some other mappers later
This commit is contained in:
parent
931c9c9b23
commit
916066c3f0
|
@ -154,23 +154,24 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper242.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper078.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper046.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\DRROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\HKROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper012.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper044.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper049.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper095.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper115.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper182.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper189.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper191.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper206.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\MMC3_family.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\MMC3.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\NES-QJ.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\TQROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\TLSROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\TVROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\TxROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\DRROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Mapper095.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Mapper206.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Namcot1xx.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\NAMCOT_m19_m210.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
|
|
@ -1,121 +1,23 @@
|
|||
//this file contains the MMC3 family of chips
|
||||
//which includes:
|
||||
//NAMCOT 109
|
||||
//MMC3 (which was apparently based on NAMCOT 109 and shares enough functionality to be derived from it in this codebase)
|
||||
|
||||
//see http://nesdev.parodius.com/bbs/viewtopic.php?t=5426&sid=e7472c15a758ebf05c588c8330c2187f
|
||||
//and http://nesdev.parodius.com/bbs/viewtopic.php?t=311
|
||||
//for some info on NAMCOT 109
|
||||
|
||||
//mappers handled by this:
|
||||
//004,095,118,119,206
|
||||
//this file contains the MMC3 family of boards
|
||||
|
||||
//fceux contains a comment in mmc3.cpp:
|
||||
//Code for emulating iNES mappers 4,12,44,45,47,49,52,74,114,115,116,118,119,165,205,214,215,245,249,250,254
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
// this is the base class for the MMC3 mapper
|
||||
public class Namcot109 : IDisposable
|
||||
public class MMC3 : IDisposable
|
||||
{
|
||||
//state
|
||||
public int chr_mode, prg_mode, reg_addr;
|
||||
int reg_addr;
|
||||
bool chr_mode, prg_mode;
|
||||
ByteBuffer chr_regs_1k = new ByteBuffer(8);
|
||||
ByteBuffer prg_regs_8k = new ByteBuffer(8);
|
||||
ByteBuffer prg_regs_8k = new ByteBuffer(4);
|
||||
ByteBuffer regs = new ByteBuffer(8);
|
||||
|
||||
protected NES.NESBoardBase board;
|
||||
public Namcot109(NES.NESBoardBase board)
|
||||
{
|
||||
this.board = board;
|
||||
|
||||
prg_regs_8k[0] = 0;
|
||||
prg_regs_8k[1] = 1;
|
||||
prg_regs_8k[2] = 0xFE; //constant
|
||||
prg_regs_8k[3] = 0xFF; //constant
|
||||
prg_regs_8k[4 + 0] = 0xFE; //constant
|
||||
prg_regs_8k[4 + 1] = 1;
|
||||
prg_regs_8k[4 + 2] = 0;
|
||||
prg_regs_8k[4 + 3] = 0xFF; //constant
|
||||
|
||||
chr_regs_1k[0] = 0;
|
||||
chr_regs_1k[1] = 1;
|
||||
chr_regs_1k[2] = 2;
|
||||
chr_regs_1k[3] = 3;
|
||||
chr_regs_1k[4] = 4;
|
||||
chr_regs_1k[5] = 5;
|
||||
chr_regs_1k[6] = 6;
|
||||
chr_regs_1k[7] = 7;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
chr_regs_1k.Dispose();
|
||||
prg_regs_8k.Dispose();
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("chr_mode", ref chr_mode);
|
||||
ser.Sync("prg_mode", ref prg_mode);
|
||||
ser.Sync("reg_addr", ref reg_addr);
|
||||
ser.Sync("chr_regs_1k", ref chr_regs_1k);
|
||||
ser.Sync("prg_regs_8k", ref prg_regs_8k);
|
||||
}
|
||||
|
||||
public virtual void WritePRG(int addr, byte value)
|
||||
{
|
||||
switch (addr & 0x6001)
|
||||
{
|
||||
case 0x0000: //$8000
|
||||
chr_mode = (value >> 7) & 1;
|
||||
chr_mode <<= 2;
|
||||
prg_mode = (value >> 6) & 1;
|
||||
prg_mode <<= 2;
|
||||
reg_addr = (value & 7);
|
||||
break;
|
||||
case 0x0001: //$8001
|
||||
switch (reg_addr)
|
||||
{
|
||||
case 0: chr_regs_1k[0] = (byte)(value & ~1); chr_regs_1k[1] = (byte)(value | 1); break;
|
||||
case 1: chr_regs_1k[2] = (byte)(value & ~1); chr_regs_1k[3] = (byte)(value | 1); break;
|
||||
case 2: chr_regs_1k[4] = value; break;
|
||||
case 3: chr_regs_1k[5] = value; break;
|
||||
case 4: chr_regs_1k[6] = value; break;
|
||||
case 5: chr_regs_1k[7] = value; break;
|
||||
case 6: prg_regs_8k[0] = value; prg_regs_8k[4 + 2] = value; break;
|
||||
case 7: prg_regs_8k[1] = value; prg_regs_8k[4 + 1] = value; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
int bank_8k = addr >> 13;
|
||||
bank_8k += prg_mode;
|
||||
bank_8k = prg_regs_8k[bank_8k];
|
||||
return bank_8k;
|
||||
}
|
||||
|
||||
public int Get_CHRBank_1K(int addr)
|
||||
{
|
||||
int bank_1k = addr >> 10;
|
||||
bank_1k ^= chr_mode;
|
||||
bank_1k = chr_regs_1k[bank_1k];
|
||||
return bank_1k;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class MMC3 : Namcot109
|
||||
{
|
||||
//state
|
||||
public byte mirror;
|
||||
int a12_old;
|
||||
byte irq_reload, irq_counter;
|
||||
|
@ -147,22 +49,80 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
bool oldIrqType;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
chr_regs_1k.Dispose();
|
||||
prg_regs_8k.Dispose();
|
||||
regs.Dispose();
|
||||
}
|
||||
|
||||
public NES.NESBoardBase.EMirrorType MirrorType { get { return mirror == 0 ? NES.NESBoardBase.EMirrorType.Vertical : NES.NESBoardBase.EMirrorType.Horizontal; } }
|
||||
|
||||
protected NES.NESBoardBase board;
|
||||
public MMC3(NES.NESBoardBase board, int num_prg_banks)
|
||||
: base(board)
|
||||
{
|
||||
this.board = board;
|
||||
if (board.Cart.chips.Contains("MMC3A")) MMC3Type = EMMC3Type.MMC3A;
|
||||
else if (board.Cart.chips.Contains("MMC3B")) MMC3Type = EMMC3Type.MMC3BSharp;
|
||||
else if (board.Cart.chips.Contains("MMC3BNONSHARP")) MMC3Type = EMMC3Type.MMC3BNonSharp;
|
||||
else if (board.Cart.chips.Contains("MMC3C")) MMC3Type = EMMC3Type.MMC3C;
|
||||
else MMC3Type = EMMC3Type.MMC3C; //arbitrary choice. is it the best choice?
|
||||
|
||||
Sync();
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
void Sync()
|
||||
{
|
||||
base.SyncState(ser);
|
||||
if (prg_mode)
|
||||
{
|
||||
prg_regs_8k[0] = 0xFE;
|
||||
prg_regs_8k[1] = regs[7];
|
||||
prg_regs_8k[2] = regs[6];
|
||||
prg_regs_8k[3] = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
prg_regs_8k[0] = regs[6];
|
||||
prg_regs_8k[1] = regs[7];
|
||||
prg_regs_8k[2] = 0xFE;
|
||||
prg_regs_8k[3] = 0xFF;
|
||||
}
|
||||
|
||||
byte r0_0 = (byte)(regs[0] & ~1);
|
||||
byte r0_1 = (byte)(regs[0] | 1);
|
||||
byte r1_0 = (byte)(regs[1] & ~1);
|
||||
byte r1_1 = (byte)(regs[1] | 1);
|
||||
|
||||
if (chr_mode)
|
||||
{
|
||||
chr_regs_1k[0] = regs[2];
|
||||
chr_regs_1k[1] = regs[3];
|
||||
chr_regs_1k[2] = regs[4];
|
||||
chr_regs_1k[3] = regs[5];
|
||||
chr_regs_1k[4] = r0_0;
|
||||
chr_regs_1k[5] = r0_1;
|
||||
chr_regs_1k[6] = r1_0;
|
||||
chr_regs_1k[7] = r1_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
chr_regs_1k[0] = r0_0;
|
||||
chr_regs_1k[1] = r0_1;
|
||||
chr_regs_1k[2] = r1_0;
|
||||
chr_regs_1k[3] = r1_1;
|
||||
chr_regs_1k[4] = regs[2];
|
||||
chr_regs_1k[5] = regs[3];
|
||||
chr_regs_1k[6] = regs[4];
|
||||
chr_regs_1k[7] = regs[5];
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("reg_addr", ref reg_addr);
|
||||
ser.Sync("chr_mode", ref chr_mode);
|
||||
ser.Sync("prg_mode", ref prg_mode);
|
||||
ser.Sync("regs", ref regs);
|
||||
ser.Sync("mirror", ref mirror);
|
||||
ser.Sync("a12_old", ref a12_old);
|
||||
ser.Sync("irq_reload", ref irq_reload);
|
||||
|
@ -174,6 +134,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
ser.Sync("irq_reload_flag", ref irq_reload_flag);
|
||||
ser.Sync("wram_enable", ref wram_enable);
|
||||
ser.Sync("wram_write_protect", ref wram_write_protect);
|
||||
Sync();
|
||||
}
|
||||
|
||||
protected virtual void SyncIRQ()
|
||||
|
@ -181,13 +142,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
board.NES.irq_cart = irq_pending;
|
||||
}
|
||||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
public void WritePRG(int addr, byte value)
|
||||
{
|
||||
switch (addr & 0x6001)
|
||||
{
|
||||
case 0x0000: //$8000
|
||||
chr_mode = value.Bit(7);
|
||||
prg_mode = value.Bit(6);
|
||||
reg_addr = (value & 7);
|
||||
Sync();
|
||||
break;
|
||||
case 0x0001: //$8001
|
||||
base.WritePRG(addr, value);
|
||||
regs[reg_addr] = value;
|
||||
Sync();
|
||||
break;
|
||||
case 0x2000: //$A000
|
||||
//mirroring
|
||||
|
@ -272,6 +239,20 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
}
|
||||
|
||||
public virtual int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
int bank_8k = addr >> 13;
|
||||
bank_8k = prg_regs_8k[bank_8k];
|
||||
return bank_8k;
|
||||
}
|
||||
|
||||
public virtual int Get_CHRBank_1K(int addr)
|
||||
{
|
||||
int bank_1k = addr >> 10;
|
||||
bank_1k = chr_regs_1k[bank_1k];
|
||||
return bank_1k;
|
||||
}
|
||||
|
||||
|
||||
public virtual void AddressPPU(int addr)
|
||||
{
|
||||
|
@ -292,30 +273,45 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
a12_old = a12;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract class MMC3_Family_Board_Base : NES.NESBoardBase
|
||||
public abstract class MMC3Board_Base : NES.NESBoardBase
|
||||
{
|
||||
protected Namcot109 mapper;
|
||||
//state
|
||||
protected MMC3 mmc3;
|
||||
|
||||
public override void AddressPPU(int addr)
|
||||
{
|
||||
mmc3.AddressPPU(addr);
|
||||
}
|
||||
|
||||
public override void ClockPPU()
|
||||
{
|
||||
mmc3.ClockPPU();
|
||||
}
|
||||
|
||||
//configuration
|
||||
protected int prg_mask, chr_mask;
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
mapper.Dispose();
|
||||
mmc3.Dispose();
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
mapper.SyncState(ser);
|
||||
mmc3.SyncState(ser);
|
||||
}
|
||||
|
||||
protected virtual int Get_CHRBank_1K(int addr)
|
||||
{
|
||||
return mapper.Get_CHRBank_1K(addr);
|
||||
return mmc3.Get_CHRBank_1K(addr);
|
||||
}
|
||||
|
||||
protected virtual int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
return mmc3.Get_PRGBank_8K(addr);
|
||||
}
|
||||
|
||||
int MapCHR(int addr)
|
||||
|
@ -352,12 +348,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
{
|
||||
mapper.WritePRG(addr, value);
|
||||
}
|
||||
|
||||
protected virtual int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
return mapper.Get_PRGBank_8K(addr);
|
||||
mmc3.WritePRG(addr, value);
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
|
@ -370,58 +361,28 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
protected virtual void BaseSetup()
|
||||
{
|
||||
//remember to setup the PRG banks -1 and -2
|
||||
int num_prg_banks = Cart.prg_size / 8;
|
||||
prg_mask = num_prg_banks - 1;
|
||||
|
||||
int num_chr_banks = (Cart.chr_size);
|
||||
chr_mask = num_chr_banks - 1;
|
||||
|
||||
mmc3 = new MMC3(this, num_prg_banks);
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
|
||||
//used by a couple of boards for controlling nametable wiring with the mapper
|
||||
protected int RewireNametable_Mapper095_and_TLSROM(int addr, int bitsel)
|
||||
protected int RewireNametable_TLSROM(int addr, int bitsel)
|
||||
{
|
||||
int bank_1k = mapper.Get_CHRBank_1K(addr & 0x1FFF);
|
||||
int bank_1k = mmc3.Get_CHRBank_1K(addr & 0x1FFF);
|
||||
int nt = (bank_1k >> bitsel) & 1;
|
||||
int ofs = addr & 0x3FF;
|
||||
addr = 0x2000 + (nt << 10);
|
||||
addr |= (ofs);
|
||||
return addr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract class MMC3Board_Base : MMC3_Family_Board_Base
|
||||
{
|
||||
//state
|
||||
protected MMC3 mmc3;
|
||||
|
||||
public override void AddressPPU(int addr)
|
||||
{
|
||||
mmc3.AddressPPU(addr);
|
||||
}
|
||||
|
||||
public override void ClockPPU()
|
||||
{
|
||||
mmc3.ClockPPU();
|
||||
}
|
||||
|
||||
protected override void BaseSetup()
|
||||
{
|
||||
int num_prg_banks = Cart.prg_size / 8;
|
||||
mapper = mmc3 = new MMC3(this, num_prg_banks);
|
||||
|
||||
base.BaseSetup();
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Namcot109Board_Base : MMC3_Family_Board_Base
|
||||
{
|
||||
protected override void BaseSetup()
|
||||
{
|
||||
mapper = new Namcot109(this);
|
||||
base.BaseSetup();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
protected override int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
int bank_8k = mapper.Get_PRGBank_8K(addr);
|
||||
int bank_8k = mmc3.Get_PRGBank_8K(addr);
|
||||
return (bank_8k & PRG_AND[block_select]) | PRG_OR[block_select];
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
protected override int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
if (mode)
|
||||
return (mapper.Get_PRGBank_8K(addr)&0xF) + block * (128 / 8);
|
||||
return (mmc3.Get_PRGBank_8K(addr)&0xF) + block * (128 / 8);
|
||||
int block_offset = addr >> 13;
|
||||
return prg * 4 + block_offset;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
protected override int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
int bank_8k = mapper.Get_PRGBank_8K(addr);
|
||||
int bank_8k = mmc3.Get_PRGBank_8K(addr);
|
||||
if (prg_mode == false) return bank_8k;
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
|
|
|
@ -17,13 +17,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
return false;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("THIS MAPPER ISNT TESTED! WHAT GAME USES IT? PLEASE REPORT!");
|
||||
|
||||
//this board has 2k of chr ram
|
||||
Cart.vram_size = 2;
|
||||
BaseSetup();
|
||||
|
||||
return true;
|
||||
throw new InvalidOperationException("THIS MAPPER ISNT TESTED! WHAT GAME USES IT? PLEASE REPORT!");
|
||||
|
||||
//return true;
|
||||
}
|
||||
|
||||
public override byte ReadPPU(int addr)
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
int bank_1k = mapper.Get_CHRBank_1K(addr);
|
||||
int bank_1k = mmc3.Get_CHRBank_1K(addr);
|
||||
int use_ram = (bank_1k >> 6) & 1;
|
||||
if (use_ram == 1)
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
int bank_1k = mapper.Get_CHRBank_1K(addr);
|
||||
int bank_1k = mmc3.Get_CHRBank_1K(addr);
|
||||
int use_ram = (bank_1k >> 6) & 1;
|
||||
if (use_ram == 1)
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Diagnostics;
|
|||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//this board contains a Namcot 109 and some extra ram for nametables
|
||||
public class DRROM : Namcot109Board_Base
|
||||
public class DRROM : Namcot108Board_Base
|
||||
{
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
|
@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
{
|
||||
//pretty much just one game.
|
||||
//wires the mapper outputs to control the nametables. check out the companion board TLSROM
|
||||
public class Mapper095 : Namcot109Board_Base
|
||||
public class Mapper095 : Namcot108Board_Base
|
||||
{
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
|
@ -26,15 +26,26 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
return true;
|
||||
}
|
||||
|
||||
int RewireNametable(int addr, int bitsel)
|
||||
{
|
||||
int bank_1k = mapper.Get_CHRBank_1K(addr & 0x1FFF);
|
||||
int nt = (bank_1k >> bitsel) & 1;
|
||||
int ofs = addr & 0x3FF;
|
||||
addr = 0x2000 + (nt << 10);
|
||||
addr |= (ofs);
|
||||
return addr;
|
||||
}
|
||||
|
||||
//mapper 095's chief unique contribution is to add this nametable rewiring logic: CHR A15 directly controls CIRAM A10
|
||||
public override byte ReadPPU(int addr)
|
||||
{
|
||||
if (addr < 0x2000) return base.ReadPPU(addr);
|
||||
else return base.ReadPPU(RewireNametable_Mapper095_and_TLSROM(addr, 5));
|
||||
else return base.ReadPPU(RewireNametable(addr, 5));
|
||||
}
|
||||
public override void WritePPU(int addr, byte value)
|
||||
{
|
||||
if (addr < 0x2000) base.WritePPU(addr, value);
|
||||
else base.WritePPU(RewireNametable_Mapper095_and_TLSROM(addr, 5), value);
|
||||
else base.WritePPU(RewireNametable(addr, 5), value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@ using System.Diagnostics;
|
|||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//various japanese namcot 109 boards plus DEROM
|
||||
public class Mapper206 : Namcot109Board_Base
|
||||
//various japanese Namcot108 boards plus DEROM
|
||||
public class Mapper206 : Namcot108Board_Base
|
||||
{
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
|
@ -0,0 +1,187 @@
|
|||
//see http://nesdev.parodius.com/bbs/viewtopic.php?t=5426&sid=e7472c15a758ebf05c588c8330c2187f
|
||||
//and http://nesdev.parodius.com/bbs/viewtopic.php?t=311
|
||||
//for some info on NAMCOT 108
|
||||
//but mostly http://wiki.nesdev.com/w/index.php/INES_Mapper_206
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//also, Namcot109, Namcot118, Namcot119 chips are this exact same thing
|
||||
public class Namcot108Chip : IDisposable
|
||||
{
|
||||
//state
|
||||
int reg_addr;
|
||||
ByteBuffer chr_regs_1k = new ByteBuffer(8);
|
||||
ByteBuffer prg_regs_8k = new ByteBuffer(4);
|
||||
|
||||
NES.NESBoardBase board;
|
||||
public Namcot108Chip(NES.NESBoardBase board)
|
||||
{
|
||||
this.board = board;
|
||||
|
||||
prg_regs_8k[0] = 0;
|
||||
prg_regs_8k[1] = 1;
|
||||
prg_regs_8k[2] = 0xFE; //constant
|
||||
prg_regs_8k[3] = 0xFF; //constant
|
||||
|
||||
chr_regs_1k[0] = 0;
|
||||
chr_regs_1k[1] = 1;
|
||||
chr_regs_1k[2] = 2;
|
||||
chr_regs_1k[3] = 3;
|
||||
chr_regs_1k[4] = 4;
|
||||
chr_regs_1k[5] = 5;
|
||||
chr_regs_1k[6] = 6;
|
||||
chr_regs_1k[7] = 7;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
chr_regs_1k.Dispose();
|
||||
prg_regs_8k.Dispose();
|
||||
}
|
||||
|
||||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("reg_addr", ref reg_addr);
|
||||
ser.Sync("chr_regs_1k", ref chr_regs_1k);
|
||||
ser.Sync("prg_regs_8k", ref prg_regs_8k);
|
||||
}
|
||||
|
||||
public virtual void WritePRG(int addr, byte value)
|
||||
{
|
||||
switch (addr & 0x6001)
|
||||
{
|
||||
case 0x0000: //$8000
|
||||
reg_addr = (value & 7);
|
||||
break;
|
||||
case 0x0001: //$8001
|
||||
switch (reg_addr)
|
||||
{
|
||||
//bottom bits of these chr regs are ignored
|
||||
case 0:
|
||||
chr_regs_1k[0] = (byte)(value & ~1);
|
||||
chr_regs_1k[1] = (byte)(value | 1);
|
||||
break;
|
||||
case 1:
|
||||
chr_regs_1k[2] = (byte)(value & ~1);
|
||||
chr_regs_1k[3] = (byte)(value | 1);
|
||||
break;
|
||||
|
||||
case 2: chr_regs_1k[4] = value; break;
|
||||
case 3: chr_regs_1k[5] = value; break;
|
||||
case 4: chr_regs_1k[6] = value; break;
|
||||
case 5: chr_regs_1k[7] = value; break;
|
||||
case 6: prg_regs_8k[0] = value; break;
|
||||
case 7: prg_regs_8k[1] = value; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
int bank_8k = addr >> 13;
|
||||
bank_8k = prg_regs_8k[bank_8k];
|
||||
return bank_8k;
|
||||
}
|
||||
|
||||
public int Get_CHRBank_1K(int addr)
|
||||
{
|
||||
int bank_1k = addr >> 10;
|
||||
bank_1k = chr_regs_1k[bank_1k];
|
||||
return bank_1k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract class Namcot108Board_Base : NES.NESBoardBase
|
||||
{
|
||||
//state
|
||||
protected Namcot108Chip mapper;
|
||||
|
||||
//configuration
|
||||
protected int prg_mask, chr_mask;
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
mapper.Dispose();
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
mapper.SyncState(ser);
|
||||
}
|
||||
|
||||
public int Get_CHRBank_1K(int addr)
|
||||
{
|
||||
return mapper.Get_CHRBank_1K(addr);
|
||||
}
|
||||
|
||||
public int Get_PRGBank_8K(int addr)
|
||||
{
|
||||
return mapper.Get_PRGBank_8K(addr);
|
||||
}
|
||||
|
||||
int MapCHR(int addr)
|
||||
{
|
||||
int bank_1k = Get_CHRBank_1K(addr);
|
||||
bank_1k &= chr_mask;
|
||||
addr = (bank_1k << 10) | (addr & 0x3FF);
|
||||
return addr;
|
||||
}
|
||||
|
||||
public override byte ReadPPU(int addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
addr = MapCHR(addr);
|
||||
if (VROM != null)
|
||||
return VROM[addr];
|
||||
else return VRAM[addr];
|
||||
}
|
||||
else return base.ReadPPU(addr);
|
||||
}
|
||||
|
||||
public override void WritePPU(int addr, byte value)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (VRAM == null) return;
|
||||
addr = MapCHR(addr);
|
||||
VRAM[addr] = value;
|
||||
}
|
||||
base.WritePPU(addr, value);
|
||||
}
|
||||
|
||||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
{
|
||||
mapper.WritePRG(addr, value);
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
int bank_8k = Get_PRGBank_8K(addr);
|
||||
bank_8k &= prg_mask;
|
||||
addr = (bank_8k << 13) | (addr & 0x1FFF);
|
||||
return ROM[addr];
|
||||
}
|
||||
|
||||
protected virtual void BaseSetup()
|
||||
{
|
||||
int num_prg_banks = Cart.prg_size / 8;
|
||||
prg_mask = num_prg_banks - 1;
|
||||
|
||||
int num_chr_banks = (Cart.chr_size);
|
||||
chr_mask = num_chr_banks - 1;
|
||||
|
||||
mapper = new Namcot108Chip(this);
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue