BizHawk/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs

234 lines
5.2 KiB
C#

using System;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
class EEPROM93c46
{
enum EEPROMWriteMode
{
Instruction,
WriteData,
WriteAll,
Read
}
enum EEPROMReadMode
{
ReadNew,
ReadOld,
Hold
}
[Flags]
enum EEPROMFlags : byte
{
Ready = 1,
Clock = 2,
ChipSelect = 4
}
ushort Address = 0;
ushort Value = 0;
int BitsWritten = 0;
int BitsRead = 0;
bool WriteEnable = false;
EEPROMWriteMode WriteMode = EEPROMWriteMode.Instruction;
EEPROMReadMode ReadMode = EEPROMReadMode.Hold;
EEPROMFlags Flags = 0;
public byte Read(byte[] saveRAM)
{
switch (ReadMode)
{
case EEPROMReadMode.ReadNew:
// A new value clocking out
ReadMode = EEPROMReadMode.ReadOld;
byte ret = Read(saveRAM);
if (++BitsRead == 8)
{
// Increment address
BitsRead = 0;
++Address;
if(Address % 2 == 0)
{
WriteMode = EEPROMWriteMode.Instruction;
ReadMode = EEPROMReadMode.Hold;
BitsWritten = 0;
Value = 0;
}
}
return ret;
case EEPROMReadMode.ReadOld:
// repeat old value
byte bit = (byte)((saveRAM[Address % saveRAM.Length] >> (7 - BitsRead)) & 1);
return (byte)((byte)(Flags | EEPROMFlags.Clock) | bit);
default:
// ready/busy flag is always ready in this emulation
return (byte)(Flags | EEPROMFlags.Clock | EEPROMFlags.Ready);
}
}
public void Write(byte bit, byte[] saveRAM)
{
// new instruction?
if ((bit & 4) == 0)
{
WriteMode = EEPROMWriteMode.Instruction;
ReadMode = EEPROMReadMode.Hold;
BitsWritten = 0;
Value = 0;
Flags = (EEPROMFlags)bit & ~EEPROMFlags.Ready;
return;
}
// clock low to high?
if ((bit & (byte)EEPROMFlags.Clock) != 0 && (Flags & EEPROMFlags.Clock) == 0)
{
// all modes shift in a larger value
Value = (ushort)((Value << 1) | (bit & 1));
++BitsWritten;
switch (WriteMode)
{
case EEPROMWriteMode.Instruction:
// Process opcode including start bit
// check start bit
if ((Value & 0x100) == 0)
return;
byte op = (byte)Value;
Value = 0;
BitsWritten = 0;
switch (op & 0xC0)
{
case 0x00:
// non-addressed commands
switch (op & 0xF0)
{
case 0x00:
// EWDS: write disable
WriteEnable = false;
return;
case 0x10:
// WRAL: write to all addresses (silly)
WriteMode = EEPROMWriteMode.WriteAll;
ReadMode = EEPROMReadMode.Hold;
return;
case 0x20:
// ERAL: erase all addresses
if (WriteEnable)
{
for (int i = 0; i < saveRAM.Length; ++i)
{
saveRAM[i] = 0xFF;
}
}
ReadMode = EEPROMReadMode.Hold;
return;
case 0x30:
// EWEN: write enable
WriteEnable = true;
return;
default:
// impossible
return;
}
case 0x40:
// WRITE
Address = (ushort)((op & 0x3F) << 1);
WriteMode = EEPROMWriteMode.WriteData;
ReadMode = EEPROMReadMode.Hold;
return;
case 0x80:
// READ
Address = (ushort)((op & 0x3F) << 1);
ReadMode = EEPROMReadMode.Hold;
WriteMode = EEPROMWriteMode.Read;
BitsRead = 0;
return;
case 0xC0:
// ERASE
Address = (ushort)((op & 0x3F) << 1);
if (WriteEnable)
{
saveRAM[Address % saveRAM.Length] = 0xFF;
saveRAM[(Address + 1) % saveRAM.Length] = 0xFF;
}
ReadMode = EEPROMReadMode.Hold;
return;
default:
// impossible
return;
}
case EEPROMWriteMode.WriteData:
// Write bits
if (BitsWritten < 16)
return;
if (WriteEnable)
{
saveRAM[Address % saveRAM.Length] = (byte)(Value >> 8);
saveRAM[(Address + 1) % saveRAM.Length] = (byte)Value;
}
WriteMode = EEPROMWriteMode.Instruction;
Value = 0;
BitsWritten = 0;
return;
case EEPROMWriteMode.WriteAll:
// write to ALL addresses
if (BitsWritten < 16)
return;
Value = 0;
BitsWritten = 0;
if (WriteEnable)
{
for (int i = 0; i < saveRAM.Length; i += 2)
{
saveRAM[i % saveRAM.Length] = (byte)Value;
saveRAM[(i + 1) % saveRAM.Length] = (byte)(Value >> 8);
}
}
WriteMode = EEPROMWriteMode.Instruction;
return;
case EEPROMWriteMode.Read:
// Clock a new value out
ReadMode = EEPROMReadMode.ReadNew;
return;
}
}
Flags = (EEPROMFlags)bit & ~EEPROMFlags.Ready;
}
public void SyncState(Serializer ser)
{
ser.BeginSection("93c46");
ser.Sync(nameof(Address), ref Address);
ser.Sync(nameof(Value), ref Value);
ser.Sync(nameof(BitsWritten), ref BitsWritten);
ser.Sync(nameof(BitsRead), ref BitsRead);
ser.Sync(nameof(WriteEnable), ref WriteEnable);
ser.SyncEnum(nameof(WriteMode), ref WriteMode);
ser.SyncEnum(nameof(ReadMode), ref ReadMode);
ser.SyncEnum(nameof(Flags), ref Flags);
ser.EndSection();
}
}
}