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:
parent
3d14e55297
commit
0aa5e2a512
|
@ -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" />
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue