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\Mapper015.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper069.cs" /> <Compile Include="Consoles\Nintendo\NES\Boards\Mapper069.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper107.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\Mapper164.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper176.cs" /> <Compile Include="Consoles\Nintendo\NES\Boards\Mapper176.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper180.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 112 Misc (CN) Nothing
113 =USELESS= Junk 113 =USELESS= Junk
115 MMC3Variant Decent 115 MMC3Variant Decent
116 Unlicensed Minimal (missing correct mirroring logic)
118 TLSROM Complete 118 TLSROM Complete
119 TQROM Complete 119 TQROM Complete
140 Misc (J) 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]); 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() { } public virtual void Dispose() { }
int[] mirroring = new int[4]; int[] mirroring = new int[4];

View File

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

View File

@ -37,6 +37,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//analyze board type //analyze board type
switch (Cart.board_type) switch (Cart.board_type)
{ {
case "MAPPER116_HACKY":
break;
case "MAPPER004": case "MAPPER004":
break; break;
case "NES-TBROM": //tecmo world cup soccer (DE) [untested] 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 public class MMC1
{ {
NES.NESBoardBase board; NES.NESBoardBase board;
MMC1_SerialController scnt = new MMC1_SerialController(); public MMC1_SerialController scnt = new MMC1_SerialController();
public MMC1(NES.NESBoardBase board) public MMC1(NES.NESBoardBase board)
{ {
@ -89,6 +89,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public Action Reset; public Action Reset;
public Action<int, int> WriteRegister; public Action<int, int> WriteRegister;
public void ResetShift()
{
shift_count = shift_val = 0;
}
public void Write(int addr, byte value) public void Write(int addr, byte value)
{ {
int data = value & 1; int data = value & 1;
@ -121,11 +126,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
prg_slot = 1; prg_slot = 1;
} }
void StandardReset() public void StandardReset()
{ {
prg_mode = 1; prg_mode = 1;
prg_slot = 1; prg_slot = 1;
chr_mode = 1; chr_mode = 1;
scnt.Reset();
mirror = NES.NESBoardBase.EMirrorType.Horizontal; mirror = NES.NESBoardBase.EMirrorType.Horizontal;
} }
@ -134,7 +140,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
scnt.Write(addr, value); 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) switch (addr)
{ {
@ -156,7 +163,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
break; break;
} }
//board.NES.LogLine("mapping.. chr_mode={0}, chr={1},{2}", chr_mode, chr_0, chr_1); //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) public int Get_PRGBank(int addr)
@ -201,7 +208,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
protected int vram_mask; protected int vram_mask;
//state //state
protected MMC1 mmc1; public MMC1 mmc1;
public override void WritePRG(int addr, byte value) public override void WritePRG(int addr, byte value)
{ {
@ -254,6 +261,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{ {
switch (Cart.board_type) switch (Cart.board_type)
{ {
case "MAPPER116_HACKY":
break;
case "MAPPER001": case "MAPPER001":
break; break;
case "NES-SAROM": //dragon warrior 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.IO;
using System.Diagnostics; using System.Diagnostics;
@ -10,21 +12,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{ {
//configuration //configuration
int prg_bank_mask_8k, chr_bank_mask_1k; int prg_bank_mask_8k, chr_bank_mask_1k;
int prg_reg_mask_8k;
Func<int, int> remap; Func<int, int> remap;
Func<int, int> fix_chr; Func<int, int> fix_chr;
int type; int type;
//state //state
int[] prg_bank_reg_8k = new int[2]; public int[] prg_bank_reg_8k = new int[2];
int[] chr_bank_reg_1k = new int[16]; public int[] chr_bank_reg_1k = new int[16];
bool prg_mode; bool prg_mode;
ByteBuffer prg_banks_8k = new ByteBuffer(4); 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_mode;
bool irq_enabled, irq_pending, irq_autoen; bool irq_enabled, irq_pending, irq_autoen;
byte irq_reload; byte irq_reload;
byte irq_counter; byte irq_counter;
int irq_prescaler; int irq_prescaler;
public int extra_vrom;
public override void Dispose() public override void Dispose()
{ {
@ -45,6 +49,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ser.Sync("irq_reload", ref irq_reload); ser.Sync("irq_reload", ref irq_reload);
ser.Sync("irq_counter", ref irq_counter); ser.Sync("irq_counter", ref irq_counter);
ser.Sync("irq_prescaler", ref irq_prescaler); ser.Sync("irq_prescaler", ref irq_prescaler);
ser.Sync("extra_vrom", ref extra_vrom);
if (ser.IsReader) 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); //Console.Write("{0}: ", NES.ppu.ppur.status.sl);
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
@ -102,6 +107,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case "MAPPER025": case "MAPPER025":
throw new InvalidOperationException("someone will need to bug me to set these up for failsafe mapping"); 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": case "KONAMI-VRC-4":
AssertPrg(128,256); AssertChr(128,256); AssertVram(0); AssertWram(0,2,8); AssertPrg(128,256); AssertChr(128,256); AssertVram(0); AssertWram(0,2,8);
type = 4; type = 4;
@ -134,7 +144,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo
prg_bank_mask_8k = Cart.prg_size / 8 - 1; prg_bank_mask_8k = Cart.prg_size / 8 - 1;
chr_bank_mask_1k = Cart.chr_size - 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(); SyncPRG();
SyncCHR(); SyncCHR();
SetMirrorType(EMirrorType.Vertical); SetMirrorType(EMirrorType.Vertical);
@ -159,7 +177,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
int ofs = addr & ((1 << 10) - 1); int ofs = addr & ((1 << 10) - 1);
bank_1k = chr_banks_1k[bank_1k]; bank_1k = chr_banks_1k[bank_1k];
addr = (bank_1k << 10) | ofs; addr = (bank_1k << 10) | ofs;
return VROM[addr]; return VROM[addr + extra_vrom];
} }
else return base.ReadPPU(addr); else return base.ReadPPU(addr);
} }
@ -171,17 +189,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
switch (addr) switch (addr)
{ {
default: default:
Console.WriteLine("missed case: {0:X4}", addr); Console.WriteLine("missed case: {0:X4}", addr + 0x8000);
break; break;
case 0x0000: //$8000 case 0x0000: //$8000
case 0x0001: case 0x0001:
case 0x0002: case 0x0002:
case 0x0003: case 0x0003:
if(type==4) prg_bank_reg_8k[0] = value & prg_reg_mask_8k;
prg_bank_reg_8k[0] = value & 0x1F;
else
prg_bank_reg_8k[0] = value & 0xF;
SyncPRG(); SyncPRG();
break; break;
@ -207,10 +222,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case 0x2001: //$A001 case 0x2001: //$A001
case 0x2002: //$A002 case 0x2002: //$A002
case 0x2003: //$A003 case 0x2003: //$A003
if(type==4) prg_bank_reg_8k[1] = value & prg_reg_mask_8k;
prg_bank_reg_8k[1] = value & 0x1F;
else
prg_bank_reg_8k[1] = value & 0xF;
SyncPRG(); SyncPRG();
break; break;

View File

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