Fix mapper 215
This one was tricky. Really, I don't see how this could be implemented in hardware as coded, but it works without errors so I'll leave it at that.
This commit is contained in:
parent
0b9e7532e3
commit
25b9878c9b
|
@ -1,136 +1,278 @@
|
|||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||
{
|
||||
public class Mapper215 : MMC3Board_Base
|
||||
{
|
||||
private ByteBuffer exRegs = new ByteBuffer(4);
|
||||
private byte cmd;
|
||||
|
||||
private int prg_mask_32k;
|
||||
|
||||
private readonly byte[,] regperm = new byte[,]
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 0, 2, 6, 1, 7, 3, 4, 5 },
|
||||
{ 0, 5, 4, 1, 7, 2, 6, 3 }, // unused
|
||||
{ 0, 6, 3, 7, 5, 2, 4, 1 },
|
||||
{ 0, 2, 5, 3, 6, 1, 7, 4 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
};
|
||||
|
||||
private readonly byte[,] adrperm = new byte[,]
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 3, 2, 0, 4, 1, 5, 6, 7 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // unused
|
||||
{ 5, 0, 1, 2, 3, 7, 6, 4 },
|
||||
{ 3, 1, 0, 5, 2, 4, 6, 7 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
};
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "MAPPER215":
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseSetup();
|
||||
exRegs[1] = 3;
|
||||
|
||||
prg_mask_32k = Cart.prg_size / 32 - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("exRegs", ref exRegs);
|
||||
ser.Sync("cmd", ref cmd);
|
||||
}
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
if (addr == 0x1000) { exRegs[0] = value; }
|
||||
if (addr == 0x1001) { exRegs[1] = value; }
|
||||
if (addr == 0x1007) { exRegs[2] = value; }
|
||||
|
||||
base.WriteEXP(addr, value);
|
||||
}
|
||||
|
||||
//public override void WritePRG(int addr, byte value)
|
||||
//{
|
||||
// cmd = value;
|
||||
// int addr2 = addr + 0x8000;
|
||||
// byte dat = value;
|
||||
|
||||
// var b = exRegs[2];
|
||||
|
||||
// byte adr = (byte)( adrperm[exRegs[2], ((addr2 >> 12) & 6) | (addr2 & 1)]);
|
||||
// short addr3 = (short)((adr & 1) | ((adr & 6) << 12) | 0x8000);
|
||||
// if (adr < 4)
|
||||
// {
|
||||
// if (adr == 0)
|
||||
// {
|
||||
// dat = (byte)((dat & 0xC0) | (regperm[exRegs[2], dat & 7]));
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// base.WritePRG(addr, dat);
|
||||
//}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
if ((exRegs[0] & 0x40) > 0)
|
||||
{
|
||||
byte sbank = (byte)(exRegs[1] & 0x10);
|
||||
if ((exRegs[0] & 0x80) > 0)
|
||||
{
|
||||
byte bank =(byte)(((exRegs[1] & 3) << 4) | (exRegs[0] & 0x7) | (sbank >> 1));
|
||||
if ((exRegs[0] & 0x20) > 0)
|
||||
{
|
||||
return ROM[(bank << 15) + addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[(bank << 14) + (addr & 0x3FFF)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[(((exRegs[1] & 3) << 5) | (cmd & 0x0F) | sbank) + addr];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((exRegs[0] & 0x80) > 0)
|
||||
{
|
||||
byte bank = (byte)(((exRegs[1] & 3) << 4) | (exRegs[0] & 0xF));
|
||||
if ((exRegs[0] & 0x20) > 0)
|
||||
{
|
||||
return ROM[((bank >> 1) << 15) + addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROM[(bank << 14) + (addr & 0x3FFF)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int bank32k = (((exRegs[1] & 3) << 5) | (cmd & 0x1F));
|
||||
bank32k &= prg_mask_32k;
|
||||
return ROM[(bank32k << 15) + addr];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using BizHawk.Common;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||
{
|
||||
public class Mapper215 : MMC3Board_Base
|
||||
{
|
||||
private ByteBuffer exRegs = new ByteBuffer(4);
|
||||
|
||||
public ByteBuffer prg_regs_8k = new ByteBuffer(4);
|
||||
|
||||
private bool is_mk3;
|
||||
|
||||
private int prg_mask_8k, chr_mask_1k;
|
||||
|
||||
private byte[] regs_sec = { 0, 2, 5, 3, 6, 1, 7, 4 };
|
||||
|
||||
/*
|
||||
* I'm not sure where these matrices originated from, but they don't seem to be needed
|
||||
* so let's leave them as commented out in case a need arises
|
||||
private readonly byte[,] regperm = new byte[,]
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 0, 2, 6, 1, 7, 3, 4, 5 },
|
||||
{ 0, 5, 4, 1, 7, 2, 6, 3 }, // unused
|
||||
{ 0, 6, 3, 7, 5, 2, 4, 1 },
|
||||
{ 0, 2, 5, 3, 6, 1, 7, 4 }, // only one actually used?
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
};
|
||||
|
||||
private readonly byte[,] adrperm = new byte[,]
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 3, 2, 0, 4, 1, 5, 6, 7 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // unused
|
||||
{ 5, 0, 1, 2, 3, 7, 6, 4 },
|
||||
{ 3, 1, 0, 5, 2, 4, 6, 7 }, // only one actully used?
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // empty
|
||||
};
|
||||
*/
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "MAPPER215":
|
||||
break;
|
||||
case "MK3E60":
|
||||
is_mk3 = true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseSetup();
|
||||
exRegs[0] = 0;
|
||||
exRegs[1] = 0xFF;
|
||||
exRegs[2] = 4;
|
||||
exRegs[3] = 0;
|
||||
|
||||
prg_mask_8k = Cart.prg_size / 8 - 1;
|
||||
chr_mask_1k = Cart.chr_size - 1;
|
||||
|
||||
prg_regs_8k[0] = 0;
|
||||
prg_regs_8k[1] = 1;
|
||||
prg_regs_8k[2] = (byte)(0xFE & prg_mask_8k);
|
||||
prg_regs_8k[3] = (byte)(0xFF & prg_mask_8k);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("exRegs", ref exRegs);
|
||||
ser.Sync("cmd", ref is_mk3);
|
||||
ser.Sync("prg_mask", ref prg_mask_8k);
|
||||
ser.Sync("chr_mask", ref chr_mask_1k);
|
||||
}
|
||||
|
||||
public void sync_prg(int i)
|
||||
{
|
||||
|
||||
if ((exRegs[0] & 0x80) == 0)
|
||||
{
|
||||
int temp = 0;
|
||||
//for (int i=0;i<4;i++)
|
||||
//{
|
||||
temp = mmc3.prg_regs_8k[i];
|
||||
|
||||
if ((exRegs[1] & 0x8) > 0)
|
||||
temp = (temp & 0x1F) | 0x20;
|
||||
else
|
||||
temp = ((temp & 0x0F) | (exRegs[1] & 0x10));
|
||||
|
||||
prg_regs_8k[i] = (byte)(temp & prg_mask_8k);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void sync_prg_2()
|
||||
{
|
||||
if ((exRegs[0] & 0x80) > 0)
|
||||
{
|
||||
int bank = (exRegs[0] & 0x0F) | (exRegs[1] & 0x10);
|
||||
bank *= 2;
|
||||
bank &= prg_mask_8k;
|
||||
|
||||
prg_regs_8k[0] = (byte)bank;
|
||||
prg_regs_8k[1] = (byte)(bank+1);
|
||||
prg_regs_8k[2] = (byte)bank;
|
||||
prg_regs_8k[3] = (byte)(bank+1);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sync_prg(0);
|
||||
sync_prg(1);
|
||||
sync_prg(2);
|
||||
sync_prg(3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
if (addr == 0x1000) { exRegs[0] = value; sync_prg_2(); }
|
||||
if (addr == 0x1001) { exRegs[1] = value; }
|
||||
if (addr == 0x1007) { exRegs[2] = value; mmc3.reg_addr = 0; sync_prg_2(); }
|
||||
|
||||
base.WriteEXP(addr, value);
|
||||
}
|
||||
|
||||
public override void WriteWRAM(int addr, byte value)
|
||||
{
|
||||
if (!is_mk3)
|
||||
{
|
||||
if (addr == 0x0000) { exRegs[0] = value; sync_prg_2(); }
|
||||
if (addr == 0x0001) { exRegs[1] = value; }
|
||||
if (addr == 0x0007) { exRegs[2] = value; mmc3.reg_addr = 0; sync_prg_2(); }
|
||||
}
|
||||
|
||||
base.WriteWRAM(addr, value);
|
||||
}
|
||||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
{
|
||||
addr += 0x8000;
|
||||
switch (addr &= 0xE001)
|
||||
{
|
||||
case 0x8000:
|
||||
if (exRegs[2]==0)
|
||||
{
|
||||
base.WritePRG(0x0000, value);
|
||||
sync_prg(0);
|
||||
sync_prg(2);
|
||||
}
|
||||
break;
|
||||
case 0x8001:
|
||||
if (exRegs[2]>0)
|
||||
{
|
||||
if ((exRegs[3]>0) && ((exRegs[0] & 0x80) == 0 || (mmc3.reg_addr & 0x7) < 6))
|
||||
{
|
||||
exRegs[3] = 0;
|
||||
base.WritePRG(0x0001, value);
|
||||
if (mmc3.reg_addr==7)
|
||||
sync_prg(1);
|
||||
else if ((mmc3.reg_addr==6) && mmc3.prg_mode)
|
||||
sync_prg(2);
|
||||
else if ((mmc3.reg_addr == 6) && !mmc3.prg_mode)
|
||||
sync_prg(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WritePRG(0x0001, value);
|
||||
if (mmc3.reg_addr == 7)
|
||||
sync_prg(1);
|
||||
else if ((mmc3.reg_addr == 6) && mmc3.prg_mode)
|
||||
sync_prg(2);
|
||||
else if ((mmc3.reg_addr == 6) && !mmc3.prg_mode)
|
||||
sync_prg(0);
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
if (exRegs[2]>0)
|
||||
{
|
||||
value = (byte)((value & 0xC0) | regs_sec[value & 0x07]);
|
||||
exRegs[3] = 1;
|
||||
|
||||
base.WritePRG(0x0000, value);
|
||||
sync_prg(0);
|
||||
sync_prg(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value==0)
|
||||
{
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMirrorType(EMirrorType.Horizontal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xA001:
|
||||
base.WritePRG(0x4001, value);
|
||||
break;
|
||||
case 0xC000:
|
||||
if (exRegs[2]>0)
|
||||
if ((value >> 7 | value) == 0)
|
||||
{
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMirrorType(EMirrorType.Horizontal);
|
||||
}
|
||||
else
|
||||
base.WritePRG(0x4000, value);
|
||||
break;
|
||||
case 0xC001:
|
||||
if (exRegs[2]>0)
|
||||
base.WritePRG(0x6001, value);
|
||||
else
|
||||
base.WritePRG(0x4001, value);
|
||||
break;
|
||||
case 0xE000:
|
||||
base.WritePRG(0x6000, value);
|
||||
break;
|
||||
case 0xE001:
|
||||
if (exRegs[2]>0)
|
||||
{
|
||||
base.WritePRG(0x4000, value);
|
||||
base.WritePRG(0x4001, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WritePRG(0x6001, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadPPU(int addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
int bank_1k = base.Get_CHRBank_1K(addr);
|
||||
|
||||
if ((exRegs[1] & 0x4) > 0)
|
||||
bank_1k = (bank_1k | 0x100);
|
||||
else
|
||||
bank_1k = (bank_1k & 0x7F) | (exRegs[1] << 3 & 0x80);
|
||||
|
||||
bank_1k &= chr_mask_1k;
|
||||
addr = (bank_1k << 10) | (addr & 0x3FF);
|
||||
return VROM[addr];
|
||||
}
|
||||
else return base.ReadPPU(addr);
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
int bank = addr >> 13;
|
||||
bank = prg_regs_8k[bank];
|
||||
return ROM[(bank << 13) + (addr & 0x1FFF)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue