nes-support mapper 116

This commit is contained in:
zeromus 2012-06-23 08:52:12 +00:00
parent c89b55696a
commit 50d4564e0e
9 changed files with 300 additions and 28 deletions

View File

@ -147,6 +147,7 @@
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper015.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper069.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper107.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper116.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper164.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper176.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper180.cs" />

View File

@ -87,6 +87,7 @@ Open bus and bus conflict emulation is not considered complete or thorough in an
112 Misc (CN) Nothing
113 =USELESS= Junk
115 MMC3Variant Decent
116 Unlicensed Minimal (missing correct mirroring logic)
118 TLSROM Complete
119 TQROM Complete
140 Misc (J) Complete

View File

@ -76,6 +76,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
for (int i = 0; i < 4; i++) ser.Sync("mirroring" + i, ref mirroring[i]);
}
public virtual void SyncIRQ(bool flag)
{
NES.irq_cart = flag;
}
public virtual void Dispose() { }
int[] mirroring = new int[4];

View File

@ -14,12 +14,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//state
int reg_addr;
bool chr_mode, prg_mode;
ByteBuffer regs = new ByteBuffer(8);
public ByteBuffer regs = new ByteBuffer(8);
public byte mirror;
int a12_old;
byte irq_reload, irq_counter;
protected bool irq_pending, irq_enable, irq_reload_flag;
public bool irq_pending, irq_enable, irq_reload_flag;
public bool wram_enable, wram_write_protect;
//it really seems like these should be the same but i cant seem to unify them.
@ -72,7 +72,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
Sync();
}
void Sync()
public void Sync()
{
if (prg_mode)
{
@ -140,7 +140,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
protected virtual void SyncIRQ()
{
board.NES.irq_cart = irq_pending;
board.SyncIRQ(irq_pending);
}
public void WritePRG(int addr, byte value)
@ -279,7 +279,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public abstract class MMC3Board_Base : NES.NESBoardBase
{
//state
protected MMC3 mmc3;
public MMC3 mmc3;
public int extra_vrom;
public override void AddressPPU(int addr)
{
@ -303,6 +305,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
base.SyncState(ser);
mmc3.SyncState(ser);
ser.Sync("extra_vrom", ref extra_vrom);
}
protected virtual int Get_CHRBank_1K(int addr)
@ -329,7 +332,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
addr = MapCHR(addr);
if (VROM != null)
return VROM[addr];
return VROM[addr + extra_vrom];
else return VRAM[addr];
}
else return base.ReadPPU(addr);

View File

@ -37,6 +37,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//analyze board type
switch (Cart.board_type)
{
case "MAPPER116_HACKY":
break;
case "MAPPER004":
break;
case "NES-TBROM": //tecmo world cup soccer (DE) [untested]

View File

@ -0,0 +1,237 @@
//TODO - emulation of mirroring is all bolloxed.
using System;
using System.IO;
using System.Diagnostics;
namespace BizHawk.Emulation.Consoles.Nintendo
{
class Mapper116 : NES.NESBoardBase
{
class MMC3_CustomBoard : MMC3Board_Base
{
public override void WritePRG(int addr, byte value)
{
base.WritePRG(addr, value);
SetMirrorType(mmc3.MirrorType); //often redundant, but gets the job done
}
public override bool Configure(NES.EDetectionOrigin origin)
{
BaseSetup();
return true;
}
public MMC3_CustomBoard(Mapper116 master)
{
this.master = master;
}
public override void SyncIRQ(bool flag)
{
master.SyncIRQ(flag);
}
Mapper116 master;
}
//configuration
//state
int mode;
SxROM mmc1;
MMC3_CustomBoard mmc3;
VRC2_4 vrc2;
public override void SyncState(Serializer ser)
{
ser.Sync("mod", ref mode);
mmc1.SyncState(ser);
mmc3.SyncState(ser);
vrc2.SyncState(ser);
SyncIRQ(mmc3.mmc3.irq_pending);
}
public override bool Configure(NES.EDetectionOrigin origin)
{
string oldBoardType = Cart.board_type;
//configure
switch (Cart.board_type)
{
case "MAPPER116":
break;
default:
return false;
}
SetMirrorType(Cart.pad_h, Cart.pad_v);
Cart.board_type = "MAPPER116_HACKY";
vrc2 = new VRC2_4();
vrc2.Create(NES);
vrc2.Configure(origin);
//not exactly the same as fceu-mm. is it important?
for(int i=0;i<16;i++)
vrc2.chr_bank_reg_1k[i] = 0x0F;
vrc2.SyncCHR();
mmc3 = new MMC3_CustomBoard(this);
mmc3.Create(NES);
mmc3.Configure(origin);
//is this important? not sure.
mmc3.mmc3.regs[0] = 0;
mmc3.mmc3.regs[1] = 2;
mmc3.mmc3.regs[2] = 3;
mmc3.mmc3.regs[3] = 4;
mmc3.mmc3.regs[4] = 5;
mmc3.mmc3.regs[5] = 7;
mmc3.mmc3.Sync();
mmc1 = new SxROM();
mmc1.Create(NES);
mmc1.Configure(origin);
mmc1_reset();
Cart.board_type = oldBoardType;
mode = 0;
Sync();
return true;
}
public override void PostConfigure()
{
SyncRoms();
base.PostConfigure();
}
public override void SyncIRQ(bool flag)
{
if(mode == 1)
base.SyncIRQ(flag);
}
void SyncRoms()
{
foreach (var board in new NES.NESBoardBase[] { mmc3, vrc2, mmc1 })
{
board.ROM = ROM;
board.VROM = VROM;
board.VRAM = VRAM;
board.WRAM = WRAM;
}
}
void Sync()
{
}
void mmc1_reset()
{
mmc1.mmc1.StandardReset();
}
void WriteModeControl(int addr, byte value)
{
if ((addr & 0x4100) != 0x4100) return;
mode = value & 3;
bool chr_base = value.Bit(2);
vrc2.extra_vrom = mmc3.extra_vrom = chr_base ? 256 * 1024 : 0;
//fceu-mm has special "hacky hacky" logic here to initialize mmc1 a special way sometimes. read about it on the nesdevwiki. not sure how important it is
if ((addr & 1) == 1)
{
mmc1_reset();
}
Sync();
if(mode == 1) SyncIRQ(mmc3.mmc3.irq_pending);
Console.Write("MODE: {0} ",mode);
if (mode == 0) Console.WriteLine("(vrc2)");
if (mode == 1) Console.WriteLine("(mmc3)");
if (mode == 2) Console.WriteLine("(mmc1)");
if (mode == 3) Console.WriteLine("(mmc1)");
}
public override void WriteEXP(int addr, byte value)
{
WriteModeControl(addr + 0x4000, value);
}
public override void WritePPU(int addr, byte value)
{
switch (mode)
{
case 0: vrc2.WritePPU(addr, value); break;
case 1: mmc3.WritePPU(addr, value); break;
case 2:
case 3: mmc1.WritePPU(addr, value); break;
}
}
public override byte ReadPPU(int addr)
{
switch (mode)
{
case 0: return vrc2.ReadPPU(addr);
case 1: return mmc3.ReadPPU(addr);
case 2:
case 3: return mmc1.ReadPPU(addr);
}
return 0;
}
public override void WritePRG(int addr, byte value)
{
Console.WriteLine("{0:X4} = {1:X2}", addr+0x8000, value);
switch (mode)
{
case 0:
addr += 0x8000;
if((addr & 0xF000) < 0xB000) addr &= 0xF000; //Garou Densetsu Special depends on this
addr -= 0x8000;
vrc2.WritePRG(addr, value);
break;
case 1: mmc3.WritePRG(addr, value); break;
case 2:
case 3: mmc1.WritePRG(addr, value); break;
}
}
public override byte ReadPRG(int addr)
{
switch (mode)
{
case 0: return vrc2.ReadPRG(addr);
case 1: return mmc3.ReadPRG(addr);
case 2:
case 3: return mmc1.ReadPRG(addr);
}
return 0;
}
public override void AddressPPU(int addr)
{
mmc3.AddressPPU(addr);
}
public override void ClockPPU()
{
mmc3.ClockPPU();
}
public override void SyncState(Serializer ser)
{
base.SyncState(ser);
}
}
}

View File

@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public class MMC1
{
NES.NESBoardBase board;
MMC1_SerialController scnt = new MMC1_SerialController();
public MMC1_SerialController scnt = new MMC1_SerialController();
public MMC1(NES.NESBoardBase board)
{
@ -89,6 +89,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public Action Reset;
public Action<int, int> WriteRegister;
public void ResetShift()
{
shift_count = shift_val = 0;
}
public void Write(int addr, byte value)
{
int data = value & 1;
@ -121,11 +126,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
prg_slot = 1;
}
void StandardReset()
public void StandardReset()
{
prg_mode = 1;
prg_slot = 1;
chr_mode = 1;
scnt.Reset();
mirror = NES.NESBoardBase.EMirrorType.Horizontal;
}
@ -134,7 +140,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
scnt.Write(addr, value);
}
void SerialWriteRegister(int addr, int value)
//logical register writes, called from the serial controller
public void SerialWriteRegister(int addr, int value)
{
switch (addr)
{
@ -156,7 +163,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
break;
}
//board.NES.LogLine("mapping.. chr_mode={0}, chr={1},{2}", chr_mode, chr_0, chr_1);
//board.NES.LogLine("mapping.. prg_mode={0}, prg_slot{1}, prg={2}", prg_mode, prg_slot, prg);
board.NES.LogLine("mapping.. prg_mode={0}, prg_slot{1}, prg={2}", prg_mode, prg_slot, prg);
}
public int Get_PRGBank(int addr)
@ -201,7 +208,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
protected int vram_mask;
//state
protected MMC1 mmc1;
public MMC1 mmc1;
public override void WritePRG(int addr, byte value)
{
@ -254,6 +261,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
switch (Cart.board_type)
{
case "MAPPER116_HACKY":
break;
case "MAPPER001":
break;
case "NES-SAROM": //dragon warrior

View File

@ -1,4 +1,6 @@
using System;
//TODO - for chr, refactor to use 8 registers of 8 bits instead of 16 registers of 4 bits. more realistic, less weird code.
using System;
using System.IO;
using System.Diagnostics;
@ -10,21 +12,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
//configuration
int prg_bank_mask_8k, chr_bank_mask_1k;
int prg_reg_mask_8k;
Func<int, int> remap;
Func<int, int> fix_chr;
int type;
//state
int[] prg_bank_reg_8k = new int[2];
int[] chr_bank_reg_1k = new int[16];
public int[] prg_bank_reg_8k = new int[2];
public int[] chr_bank_reg_1k = new int[16];
bool prg_mode;
ByteBuffer prg_banks_8k = new ByteBuffer(4);
ByteBuffer chr_banks_1k = new ByteBuffer(8);
public ByteBuffer chr_banks_1k = new ByteBuffer(8);
bool irq_mode;
bool irq_enabled, irq_pending, irq_autoen;
byte irq_reload;
byte irq_counter;
int irq_prescaler;
public int extra_vrom;
public override void Dispose()
{
@ -45,6 +49,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ser.Sync("irq_reload", ref irq_reload);
ser.Sync("irq_counter", ref irq_counter);
ser.Sync("irq_prescaler", ref irq_prescaler);
ser.Sync("extra_vrom", ref extra_vrom);
if (ser.IsReader)
{
@ -71,7 +76,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
}
}
void SyncCHR()
public void SyncCHR()
{
//Console.Write("{0}: ", NES.ppu.ppur.status.sl);
for (int i = 0; i < 8; i++)
@ -102,6 +107,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case "MAPPER025":
throw new InvalidOperationException("someone will need to bug me to set these up for failsafe mapping");
case "MAPPER116_HACKY":
remap = (addr) => addr;
type = 2;
break;
case "KONAMI-VRC-4":
AssertPrg(128,256); AssertChr(128,256); AssertVram(0); AssertWram(0,2,8);
type = 4;
@ -134,7 +144,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo
prg_bank_mask_8k = Cart.prg_size / 8 - 1;
chr_bank_mask_1k = Cart.chr_size - 1;
prg_bank_reg_8k[0] = prg_bank_reg_8k[1] = 0;
if(type == 4) prg_reg_mask_8k = 0x1F;
else prg_reg_mask_8k = 0xF;
//this VRC2 variant has an extra large PRG reg
if (Cart.board_type == "MAPPER116_HACKY")
prg_reg_mask_8k = 0x1F;
prg_bank_reg_8k[0] = 0;
prg_bank_reg_8k[1] = 1;
SyncPRG();
SyncCHR();
SetMirrorType(EMirrorType.Vertical);
@ -159,7 +177,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
int ofs = addr & ((1 << 10) - 1);
bank_1k = chr_banks_1k[bank_1k];
addr = (bank_1k << 10) | ofs;
return VROM[addr];
return VROM[addr + extra_vrom];
}
else return base.ReadPPU(addr);
}
@ -171,17 +189,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
switch (addr)
{
default:
Console.WriteLine("missed case: {0:X4}", addr);
Console.WriteLine("missed case: {0:X4}", addr + 0x8000);
break;
case 0x0000: //$8000
case 0x0001:
case 0x0002:
case 0x0003:
if(type==4)
prg_bank_reg_8k[0] = value & 0x1F;
else
prg_bank_reg_8k[0] = value & 0xF;
prg_bank_reg_8k[0] = value & prg_reg_mask_8k;
SyncPRG();
break;
@ -207,10 +222,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case 0x2001: //$A001
case 0x2002: //$A002
case 0x2003: //$A003
if(type==4)
prg_bank_reg_8k[1] = value & 0x1F;
else
prg_bank_reg_8k[1] = value & 0xF;
prg_bank_reg_8k[1] = value & prg_reg_mask_8k;
SyncPRG();
break;

View File

@ -530,7 +530,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
cart = choice;
board.Create(this);
board.Configure(origin);
board.PostConfigure();
if (origin == EDetectionOrigin.BootGodDB)
{
@ -573,6 +572,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
if (cart.vram_size != 0)
board.VRAM = new byte[cart.vram_size * 1024];
board.PostConfigure();
HardReset();
SetupMemoryDomains();
}