parent
d2f8c5b621
commit
1362c43b99
|
@ -362,6 +362,7 @@
|
|||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\PxROM_FxROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Sachen8259.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\SachenSimple.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\SEEPROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Sunsoft1.cs" />
|
||||
|
|
|
@ -0,0 +1,304 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||
{
|
||||
// describes Sachen8259A/B/C. D is in a different class
|
||||
// behavior from fceumm
|
||||
|
||||
public class Sachen8259ABC : NES.NESBoardBase
|
||||
{
|
||||
// config
|
||||
int prg_bank_mask_32k;
|
||||
int chr_bank_mask_2k;
|
||||
|
||||
int shiftout; // reg lines are shifted on the PCB to increase capacity
|
||||
int shiftmask;
|
||||
|
||||
// state
|
||||
int port; // register that gets written next
|
||||
int prg; // 32K prg swap
|
||||
int[] chr = new int[4]; // 6 bits of chr, 3 from an outer bank
|
||||
bool simple; // when true, we're in some sort of "simplified" mode
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
// quite a few crappy games on these boards, shouldn't be hard to find examples?
|
||||
case "MAPPER141":
|
||||
case "UNIF_UNL-Sachen-8259A":
|
||||
case "SACHEN-8259A":
|
||||
shiftout = 1; // 256KiB chr max
|
||||
break;
|
||||
case "MAPPER138":
|
||||
case "UNIF_UNL-Sachen-8259B":
|
||||
case "SACHEN-8259B":
|
||||
shiftout = 0; // 128KiB chr max
|
||||
break;
|
||||
case "MAPPER139":
|
||||
case "UNIF_UNL-Sachen-8259C":
|
||||
case "SACHEN-8259C":
|
||||
shiftout = 2; // 512KiB chr max
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
Cart.wram_size = 0; // cart responds to regs in 6000:7fff
|
||||
Cart.vram_size = 0;
|
||||
|
||||
shiftmask = (1 << shiftout) - 1;
|
||||
prg_bank_mask_32k = Cart.prg_size / 32 - 1;
|
||||
chr_bank_mask_2k = Cart.chr_size / 2 - 1;
|
||||
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
Write(addr, value);
|
||||
}
|
||||
public override void WriteWRAM(int addr, byte value)
|
||||
{
|
||||
Write(addr, value);
|
||||
}
|
||||
void Write(int addr, byte value)
|
||||
{
|
||||
addr &= 0x0101;
|
||||
if (addr == 0x100)
|
||||
{
|
||||
port = value & 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// low 3 bits
|
||||
chr[port] &= 0x38;
|
||||
chr[port] |= value & 7;
|
||||
break;
|
||||
case 4:
|
||||
// outer bank high 3 bits
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
chr[i] &= 0x07;
|
||||
chr[i] |= (value & 7) << 3;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
prg = value & 7;
|
||||
break;
|
||||
case 6: // unused?
|
||||
break;
|
||||
case 7:
|
||||
simple = value.Bit(0);
|
||||
if (simple)
|
||||
{
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (value & 6)
|
||||
{
|
||||
case 0: SetMirrorType(EMirrorType.Vertical); break;
|
||||
case 1: SetMirrorType(EMirrorType.Horizontal); break;
|
||||
case 2: SetMirroring(0, 1, 1, 1); break;
|
||||
case 3: SetMirrorType(EMirrorType.OneScreenA); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
int bank = prg & prg_bank_mask_32k;
|
||||
return ROM[addr | bank << 15];
|
||||
}
|
||||
public override byte ReadPPU(int addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
int idx = addr >> 11;
|
||||
// in addition to fixing V-mirroring, simple fixes us to 1 bank
|
||||
// this means for type C, simple has 1 8KiB chr bank
|
||||
int bank = chr[simple ? 0 : idx];
|
||||
// on the PCB, all of the CHR addr lines are shifted up,
|
||||
// while the low lines that were lost are connected directly to PPU A lines
|
||||
bank <<= shiftout;
|
||||
bank |= idx & shiftmask;
|
||||
bank &= chr_bank_mask_2k;
|
||||
return VROM[addr & 0x7ff | bank << 11];
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.ReadPPU(addr);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("port", ref port);
|
||||
ser.Sync("prg", ref prg);
|
||||
ser.Sync("chr", ref chr, false);
|
||||
ser.Sync("simple", ref simple);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// similar in some ways to 8259ABC, but different
|
||||
// fceumm combines the code to implement them; i think that's too messy
|
||||
|
||||
// this mapper is stupid and was most certainly made for 1 game. it has an awkward
|
||||
// chr mapping that can only support up to 32KiB chr rom, and it uses it to show
|
||||
// a few famous persons portraits while playing a stupid block game
|
||||
|
||||
// i think there's something wrong with the mapper implementation; but the game
|
||||
// sucks so hard, it's hard to tell
|
||||
public class Sachen8259D : NES.NESBoardBase
|
||||
{
|
||||
// config
|
||||
int prg_bank_mask_32k;
|
||||
int chr_bank_mask_1k;
|
||||
|
||||
// state
|
||||
int port;
|
||||
int prg;
|
||||
int[] chr = new int[8];
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
{
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
// only game i'm aware of is "The Great Wall"
|
||||
case "MAPPER137":
|
||||
case "UNIF_UNL-Sachen-8259D":
|
||||
case "SACHEN-8259D":
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
Cart.wram_size = 0; // cart responds to regs in 6000:7fff
|
||||
Cart.vram_size = 0;
|
||||
prg_bank_mask_32k = Cart.prg_size / 32 - 1;
|
||||
chr_bank_mask_1k = Cart.chr_size / 1 - 1;
|
||||
|
||||
// last 4k of chr is fixed
|
||||
chr[4] = 0x1c;
|
||||
chr[5] = 0x1d;
|
||||
chr[6] = 0x1e;
|
||||
chr[7] = 0x1f;
|
||||
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WriteEXP(int addr, byte value)
|
||||
{
|
||||
Write(addr, value);
|
||||
}
|
||||
public override void WriteWRAM(int addr, byte value)
|
||||
{
|
||||
Write(addr, value);
|
||||
}
|
||||
void Write(int addr, byte value)
|
||||
{
|
||||
addr &= 0x0101;
|
||||
if (addr == 0x100)
|
||||
{
|
||||
port = value & 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// low 3 bits
|
||||
chr[port] &= 0x18;
|
||||
chr[port] |= value & 7;
|
||||
break;
|
||||
case 4:
|
||||
// a single high bit for chr regs 1:3
|
||||
// note that this bit goes in bit #4, not #3
|
||||
chr[1] &= 0x0f;
|
||||
chr[1] |= (value & 1) << 4;
|
||||
chr[2] &= 0x0f;
|
||||
chr[2] |= (value & 2) << 3;
|
||||
chr[3] &= 0x0f;
|
||||
chr[3] |= (value & 4) << 2;
|
||||
break;
|
||||
case 5:
|
||||
prg = value & 7;
|
||||
break;
|
||||
case 6:
|
||||
// one more single bit of chr for 1 reg
|
||||
// so only chr[3] is 5 full bits
|
||||
chr[3] &= 0x17;
|
||||
chr[3] |= (value & 1) << 3;
|
||||
break;
|
||||
case 7:
|
||||
// as in A\B\C, but we don't need to store "simple"
|
||||
if (value.Bit(0))
|
||||
{
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (value & 6)
|
||||
{
|
||||
case 0: SetMirrorType(EMirrorType.Vertical); break;
|
||||
case 1: SetMirrorType(EMirrorType.Horizontal); break;
|
||||
case 2: SetMirroring(0, 1, 1, 1); break;
|
||||
case 3: SetMirrorType(EMirrorType.OneScreenA); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadPRG(int addr)
|
||||
{
|
||||
int bank = prg & prg_bank_mask_32k;
|
||||
return ROM[addr | bank << 15];
|
||||
}
|
||||
public override byte ReadPPU(int addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
int bank = chr[addr >> 10] & chr_bank_mask_1k;
|
||||
return VROM[addr & 0x3ff | bank << 10];
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.ReadPPU(addr);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("port", ref port);
|
||||
ser.Sync("prg", ref prg);
|
||||
ser.Sync("chr", ref chr, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue