nes-support vrc2 and vrc4

This commit is contained in:
zeromus 2011-09-24 20:43:01 +00:00
parent 2f25237548
commit 3ba330cef6
4 changed files with 322 additions and 5 deletions

View File

@ -56,6 +56,7 @@
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
@ -135,6 +136,7 @@
<Compile Include="Consoles\Nintendo\NES\Boards\UxROM.cs"> <Compile Include="Consoles\Nintendo\NES\Boards\UxROM.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Consoles\Nintendo\NES\Boards\VRC2_4.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\VRC6.cs" /> <Compile Include="Consoles\Nintendo\NES\Boards\VRC6.cs" />
<Compile Include="Consoles\Nintendo\NES\Core.cs" /> <Compile Include="Consoles\Nintendo\NES\Core.cs" />
<Compile Include="Consoles\Nintendo\NES\iNES.cs" /> <Compile Include="Consoles\Nintendo\NES\iNES.cs" />

View File

@ -29,11 +29,11 @@ Open bus and bus conflict emulation is not considered complete or thorough in an
016 Bandai Started doesn't work(+159) 016 Bandai Started doesn't work(+159)
018 Jaleco* Nothing 018 Jaleco* Nothing
019 Namcot106 Needed (+210) 019 Namcot106 Needed (+210)
021 VRC4 Needed 021 VRC4 Decent
022 VRC2 Nothing 022 VRC2 Decent
023 VRC*? Nothing 023 VRC2/4 Decent
024 VRC6 Decent (no sound) 024 VRC6 Decent (no sound)
025 VRC4? Nothing 025 VRC4? Decent
026 VRC6(newer) Decent (but no sound) 026 VRC6(newer) Decent (but no sound)
032 Irem_G101 Complete 032 Irem_G101 Complete
033 Taito Complete 033 Taito Complete

View File

@ -0,0 +1,316 @@
using System;
using System.IO;
using System.Diagnostics;
namespace BizHawk.Emulation.Consoles.Nintendo
{
//mapper 21 + 22 + 23 + 25 (docs largely in 021.txt for VRC4 and 22.txt for VRC2)
//If you change any of the IRQ logic here, be sure to change it in VRC4 as well.
public class VRC2_4 : NES.NESBoardBase
{
//configuration
int prg_bank_mask_8k, chr_bank_mask_1k;
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];
bool prg_mode;
ByteBuffer prg_banks_8k = new ByteBuffer(4);
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 override void Dispose()
{
base.Dispose();
prg_banks_8k.Dispose();
chr_banks_1k.Dispose();
}
public override void SyncState(Serializer ser)
{
base.SyncState(ser);
for (int i = 0; i < 2; i++) ser.Sync("prg_bank_reg_8k_" + i, ref prg_bank_reg_8k[i]);
for (int i = 0; i < 16; i++) ser.Sync("chr_bank_reg_1k_" + i, ref chr_bank_reg_1k[i]);
ser.Sync("irq_mode", ref irq_mode);
ser.Sync("irq_enabled", ref irq_enabled);
ser.Sync("irq_pending", ref irq_pending);
ser.Sync("irq_autoen", ref irq_autoen);
ser.Sync("irq_reload", ref irq_reload);
ser.Sync("irq_counter", ref irq_counter);
ser.Sync("irq_prescaler", ref irq_prescaler);
if (ser.IsReader)
{
SyncPRG();
SyncCHR();
}
}
void SyncPRG()
{
if (prg_mode)
{
prg_banks_8k[0] = 0xFE;
prg_banks_8k[1] = (byte)(prg_bank_reg_8k[1]);
prg_banks_8k[2] = (byte)(prg_bank_reg_8k[0]);
prg_banks_8k[3] = 0xFF;
}
else
{
prg_banks_8k[0] = (byte)(prg_bank_reg_8k[0]);
prg_banks_8k[1] = (byte)(prg_bank_reg_8k[1]);
prg_banks_8k[2] = 0xFE;
prg_banks_8k[3] = 0xFF;
}
}
void SyncCHR()
{
//Console.Write("{0}: ", NES.ppu.ppur.status.sl);
for (int i = 0; i < 8; i++)
{
int low = (chr_bank_reg_1k[i * 2]);
int high = (chr_bank_reg_1k[i * 2 + 1]);
int temp = low + high * 16;
temp = fix_chr(temp);
//Console.Write("{0},", temp);
temp &= chr_bank_mask_1k;
chr_banks_1k[i] = (byte)temp;
}
//Console.WriteLine();
}
void SyncIRQ()
{
NES.irq_cart = (irq_pending && irq_enabled);
}
public override bool Configure(NES.EDetectionOrigin origin)
{
fix_chr = (b) => b;
switch (Cart.board_type)
{
case "KONAMI-VRC-4":
AssertPrg(128,256); AssertChr(128,256); AssertVram(0); AssertWram(0,2,8);
type = 4;
if (Cart.pcb == "352396")
remap = (addr) => ((addr & 0xF000) | ((addr >> 2) & 3));
else if (Cart.pcb == "351406")
remap = (addr) => ((addr & 0xF000) | ((addr & 1) << 1) | ((addr & 2) >> 1));
else throw new Exception("Unknown PCB type for VRC4");
break;
case "KONAMI-VRC-2":
AssertPrg(128); AssertChr(128); AssertVram(0); AssertWram(0);
type = 2;
if (Cart.pcb == "350926")
//likely VRC2b [mapper 23]
remap = (addr) => addr;
else if (Cart.pcb == "351618")
{
//ex. ganbare pennant race - important chr note applies (VRC2a [mapper 22])
remap = (addr) => ((addr & 0xF000) | ((addr & 1) << 1) | ((addr & 2) >> 1));
fix_chr = (b) => (b >> 1);
}
else throw new Exception("Unknown PCB type for VRC2");
break;
default:
return false;
}
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;
SyncPRG();
SyncCHR();
SetMirrorType(EMirrorType.Vertical);
return true;
}
public override byte ReadPRG(int addr)
{
int bank_8k = addr >> 13;
int ofs = addr & ((1 << 13) - 1);
bank_8k = prg_banks_8k[bank_8k];
bank_8k &= prg_bank_mask_8k;
addr = (bank_8k << 13) | ofs;
return ROM[addr];
}
public override byte ReadPPU(int addr)
{
if (addr < 0x2000)
{
int bank_1k = addr >> 10;
int ofs = addr & ((1 << 10) - 1);
bank_1k = chr_banks_1k[bank_1k];
addr = (bank_1k << 10) | ofs;
return VROM[addr];
}
else return base.ReadPPU(addr);
}
public override void WritePRG(int addr, byte value)
{
//Console.WriteLine("mapping {0:X4} = {1:X2}", addr, value);
addr = remap(addr);
switch (addr)
{
default:
Console.WriteLine("missed case: {0:X4}", addr);
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;
SyncPRG();
break;
case 0x1000: //$9000
case 0x1001: //$9001
switch (value & 3)
{
case 0: SetMirrorType(NES.NESBoardBase.EMirrorType.Vertical); break;
case 1: SetMirrorType(NES.NESBoardBase.EMirrorType.Horizontal); break;
case 2: SetMirrorType(NES.NESBoardBase.EMirrorType.OneScreenA); break;
case 3: SetMirrorType(NES.NESBoardBase.EMirrorType.OneScreenB); break;
}
break;
case 0x1002: //$9002
case 0x1003: //$9003
if (type == 4) prg_mode = value.Bit(1);
else goto case 0x1000;
SyncPRG();
break;
case 0x2000: //$A000
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;
SyncPRG();
break;
case 0x3000: //$B000
case 0x3001: //$B001
case 0x3002: //$B002
case 0x3003: //$B003
chr_bank_reg_1k[addr-0x3000] = value & 0xF;
SyncCHR();
break;
case 0x4000: //$C000
case 0x4001: //$C001
case 0x4002: //$C002
case 0x4003: //$C003
chr_bank_reg_1k[addr - 0x4000 + 4] = value & 0xF;
SyncCHR();
break;
case 0x5000: //$D000
case 0x5001: //$D001
case 0x5002: //$D002
case 0x5003: //$D003
chr_bank_reg_1k[addr - 0x5000 + 8] = value & 0xF;
SyncCHR();
break;
case 0x6000: //$E000
case 0x6001: //$E001
case 0x6002: //$E002
case 0x6003: //$E003
chr_bank_reg_1k[addr - 0x6000 + 12] = value & 0xF;
SyncCHR();
break;
case 0x7000: //$F000 (reload low)
if (type == 2) break;
irq_reload = (byte)((irq_reload&0xF0) | value);
break;
case 0x7001: //$F001 (reload high)
if (type == 2) break;
irq_reload = (byte)((irq_reload&0x0F)|(value<<4));
break;
case 0x7002: //$F001 (control)
if (type == 2) break;
irq_mode = value.Bit(2);
irq_autoen = value.Bit(0);
if (value.Bit(1))
{
//enabled
irq_enabled = true;
irq_counter = irq_reload;
irq_prescaler = 341;
}
else
{
//disabled
irq_enabled = false;
}
SyncIRQ();
break;
case 0x7003: //$F003 (ack)
if (type == 2) break;
irq_pending = false;
irq_enabled = irq_autoen;
SyncIRQ();
break;
}
}
void ClockIRQ()
{
if (type == 2) return;
if (irq_counter == 0xFF)
{
irq_pending = true;
irq_counter = irq_reload;
SyncIRQ();
}
else
irq_counter++;
}
public override void ClockPPU()
{
if (type == 2) return;
if (!irq_enabled) return;
if (irq_mode)
{
ClockIRQ();
}
else
{
irq_prescaler--;
if (irq_prescaler == 0)
{
irq_prescaler += 341;
ClockIRQ();
}
}
}
}
}

View File

@ -34,7 +34,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
base.SyncState(ser); base.SyncState(ser);
ser.Sync("prg_bank_16k", ref prg_bank_16k); ser.Sync("prg_bank_16k", ref prg_bank_16k);
ser.Sync("prg_bank_8k", ref prg_bank_8k); ser.Sync("prg_bank_8k", ref prg_bank_8k);
ser.Sync("prg_banks_8k", ref prg_banks_8k);
ser.Sync("chr_banks_1k", ref chr_banks_1k); ser.Sync("chr_banks_1k", ref chr_banks_1k);
ser.Sync("irq_mode", ref irq_mode); ser.Sync("irq_mode", ref irq_mode);
ser.Sync("irq_enabled", ref irq_enabled); ser.Sync("irq_enabled", ref irq_enabled);