NES: try implementing SEEPROM for BANDAI-FGC boards. Seems to work reading, but I can't get far enough into any of the games for writing. Like the rest of the mapper, only works with crc id because I don't know how to positively identify any of this from ines headers. Affected games:

24C01  http://bootgod.dyndns.org:7777/search.php?keywords=BANDAI-LZ93D50%2B24C01&kwtype=pcb
24C02  http://bootgod.dyndns.org:7777/search.php?keywords=BANDAI-LZ93D50%2B24C02&kwtype=pcb
This commit is contained in:
goyuken 2012-12-17 19:54:45 +00:00
parent 3d14e55297
commit 0aa5e2a512
3 changed files with 301 additions and 15 deletions

View File

@ -304,6 +304,7 @@
<Compile Include="Consoles\Nintendo\NES\Boards\NROM368.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\PxROM_FxROM.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" />
<Compile Include="Consoles\Nintendo\NES\Boards\Sunsoft2_m89.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\Sunsoft2_m93.cs" />

View File

@ -30,26 +30,26 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
//configuration
int prg_bank_mask_16k, chr_bank_mask_1k;
bool has_eprom = false;
//regenerable state
IntBuffer prg_banks_16k = new IntBuffer(2);
//state
int prg_reg_16k, eprom;
int prg_reg_16k;
ByteBuffer regs = new ByteBuffer(8);
bool irq_enabled;
ushort irq_counter;
SEEPROM eprom;
public override void SyncState(Serializer ser)
{
base.SyncState(ser);
ser.Sync("prg_reg_16k", ref prg_reg_16k);
ser.Sync("regs", ref regs);
ser.Sync("eprom", ref eprom);
ser.Sync("irq_counter", ref irq_counter);
ser.Sync("irq_enabled", ref irq_enabled);
if (eprom != null)
eprom.SyncState(ser);
SyncPRG();
}
@ -64,23 +64,31 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
switch (Cart.board_type)
{
case "BANDAI-FCG-1":
AssertPrg(128, 256, 512); AssertChr(128, 256); AssertWram(0, 8); AssertVram(0);
case "BANDAI-FCG-1": // no eprom
AssertPrg(128, 256, 512); AssertChr(128, 256); AssertWram(0); AssertVram(0);
break;
case "BANDAI-FCG-2":
case "BANDAI-FCG-2": // no eprom
AssertPrg(128); AssertChr(128); AssertWram(0); AssertVram(0);
break;
case "BANDAI-LZ93D50+24C01":
case "BANDAI-LZ93D50+24C01": // 1kbit eprom
AssertPrg(128, 256); AssertChr(128, 256); AssertWram(0); AssertVram(0);
eprom = new SEEPROM(false);
break;
case "BANDAI-LZ93D50+24C02":
AssertPrg(128, 256); AssertChr(128, 256); AssertWram(0, 8); AssertVram(0);
case "BANDAI-LZ93D50+24C02": // 2kbit eprom
AssertPrg(128, 256); AssertChr(128, 256); AssertWram(0); AssertVram(0);
eprom = new SEEPROM(true);
break;
/* if implementing NES mappers, a way must be found to reliably determine which
* eprom variety is in use
case "MAPPER016": // TEST TEST
Cart.wram_size = 0;
Cart.vram_size = 0;
eprom = new SEEPROM(false);
break;
*/
default:
return false;
}
if (Cart.mapper == 159)
has_eprom = true;
prg_bank_mask_16k = (Cart.prg_size / 16) - 1;
chr_bank_mask_1k = Cart.chr_size - 1;
@ -142,7 +150,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
irq_counter |= (ushort)(value << 8);
break;
case 0xD:
eprom = value;
if (eprom != null)
eprom.WriteByte(value);
break;
}
}
@ -163,8 +172,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public override byte ReadWRAM(int addr)
{
// reading any addr in 6000:7fff returns a single bit from the eeprom
// in bit 4. zeroing that bit seems sufficient for some games to boot
return (byte)(NES.DB & 0xef);
// in bit 4.
byte ret = (byte)(NES.DB & 0xef);
if (eprom != null && eprom.ReadBit(NES.DB.Bit(4)))
ret |= 0x10;
return ret;
}
public override void ClockCPU()
@ -205,5 +217,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo
else return base.ReadPPU(addr);
}
public override byte[] SaveRam
{
get
{
if (eprom != null)
return eprom.GetSaveRAM();
else
return null;
}
}
}
}

View File

@ -0,0 +1,263 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Consoles.Nintendo
{
/// <summary>
/// describes a 24C01 or 24C02 as connected to a BANDAI-FCG
/// </summary>
// http://pdf1.alldatasheet.com/datasheet-pdf/view/56094/ATMEL/24C01.html 24C01
// http://www.atmel.com/Images/doc0180.pdf 24C02 and others
public class SEEPROM
{
/// <summary>
/// true if 256byte
/// </summary>
bool Big;
byte[] rom;
/// <summary>aux circuitry? D7 of data byte</summary>
bool OutEnable = false;
/// <summary>asserted by master</summary>
bool SCK = false;
/// <summary>asserted by master</summary>
bool SDA = false;
/// <summary>true if the SEEPROM is trying to pull down the SDA line</summary>
bool PullDown = false;
/// <summary>number of bits left to send\recv of current byte</summary>
int BitsLeft;
/// <summary>current data byte in progress</summary>
byte Data;
/// <summary>current chip addr</summary>
byte Addr;
enum EState
{
Off, Select, Ignore, Address, Read, Write
};
EState State;
/// <summary>
/// called on the 9th bit of a write
/// </summary>
void ClockByteWrite()
{
if (State == EState.Write)
{
PullDown = true; // ack
// commit
Console.WriteLine("{1:x2} => rom[{0:x2}]", Addr, Data);
rom[Addr] = Data;
Addr++;
Addr &= (byte)(rom.Length - 1);
// next byte
BitsLeft = 8;
}
else if (State == EState.Select)
{
if (Big) // 24C02: select contains a device selector, plus mode
{
Console.WriteLine("256B Select: {0:x2}", Data);
// device selector byte should be 1010 000x
// x = 0: write. x = 1: read
if ((Data & 0xfe) != 0xa0)
{
Console.WriteLine("STATE: IGNORE");
State = EState.Ignore;
}
else
{
if (Data.Bit(0))
{
PullDown = true; // ack
Console.WriteLine("STATE: READ");
State = EState.Read;
BitsLeft = 8;
Data = rom[Addr];
}
else
{
PullDown = true; // ack
Console.WriteLine("STATE: ADDRESS");
State = EState.Address;
BitsLeft = 8;
}
}
}
else // 24C01: select contains a 7 bit address, plus mode
{
Addr = (byte)(Data >> 1);
Console.WriteLine("128B Addr: {0:x2}", Addr);
if (Data.Bit(0))
{
PullDown = true; // ack
Console.WriteLine("STATE: READ");
State = EState.Read;
BitsLeft = 8;
Data = rom[Addr];
}
else
{
PullDown = true; // ack
Console.WriteLine("STATE: WRITE");
State = EState.Write;
BitsLeft = 8;
}
}
}
else if (State == EState.Address) // (Only on 24C02): a byte of address
{
Addr = Data;
Console.WriteLine("256B Addr: {0:x2}", Data);
PullDown = true; // ack
Console.WriteLine("STATE: WRITE"); // to random read, the device will be set to read mode right after this
State = EState.Write;
BitsLeft = 8;
}
}
/// <summary>
/// called on rising edge of SCK. output bit, if any, can be set by PullDown
/// </summary>
/// <param name="bit">input bit</param>
void ClockBit(bool bit)
{
switch (State)
{
case EState.Off:
case EState.Ignore:
break;
case EState.Select:
case EState.Address:
case EState.Write:
if (BitsLeft > 0)
{
BitsLeft--;
if (bit)
Data |= (byte)(1 << BitsLeft);
else
Data &= (byte)~(1 << BitsLeft);
}
else // "9th" bit
ClockByteWrite();
break;
case EState.Read:
if (BitsLeft > 0)
{
BitsLeft--;
PullDown = !Data.Bit(BitsLeft);
}
else // 0 bits left: master acknowledges, and prepare another byte
{
if (bit)
{
// master didn't acknowledge. what to do?
}
Console.WriteLine("{1:x2} <= rom[{0:x2}]", Addr, Data);
Addr++;
Addr &= (byte)(rom.Length - 1);
Data = rom[Addr];
BitsLeft = 8;
}
break;
}
}
void ClockStart()
{
State = EState.Select;
BitsLeft = 8;
Console.WriteLine("STATE: SELECT");
}
void ClockStop()
{
State = EState.Off;
Console.WriteLine("STATE: OFF");
PullDown = false;
}
public void WriteByte(byte val)
{
OutEnable = val.Bit(7);
bool newSDA = val.Bit(6);
bool newSCK = val.Bit(5);
if (!newSCK) // falling or inactive SCK: cancel any active ack / readback
{
PullDown = false;
}
else
{
if (!SCK) // rising edge
{
ClockBit(newSDA);
}
else // clock stays high; look for changes in SDA
{
if (!SDA && newSDA)
{
ClockStop();
}
else if (SDA && !newSDA)
{
ClockStart();
}
}
}
SCK = newSCK;
SDA = newSDA;
}
/// <summary>
/// read a bit back from eprom, might be mapped in 6000:7fff
/// </summary>
/// <param name="deadbit">bit from NES.DB</param>
/// <returns></returns>
public bool ReadBit(bool deadbit)
{
if (!OutEnable)
return deadbit;
if (!SDA)
return false;
return !PullDown;
}
public byte[] GetSaveRAM() { return rom; }
/// <summary>
///
/// </summary>
/// <param name="Big">256 byte instead of 128 byte</param>
public SEEPROM(bool Big)
{
rom = new byte[Big ? 256 : 128];
this.Big = Big;
}
public void SyncState(Serializer ser)
{
ser.BeginSection("SEEPROM");
ser.Sync("rom", ref rom, false);
ser.Sync("OutEnable", ref OutEnable);
ser.Sync("SCK", ref SCK);
ser.Sync("SDA", ref SDA);
ser.Sync("PullDown", ref PullDown);
ser.Sync("BitsLeft", ref BitsLeft);
ser.Sync("Data", ref Data);
ser.Sync("Addr", ref Addr);
int tmp = (int)State;
ser.Sync("State", ref tmp);
State = (EState)tmp;
ser.EndSection();
}
}
}