234 lines
5.2 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|