2025-02-14 16:09:33 +08:00
|
|
|
|
using Essgee.Exceptions;
|
|
|
|
|
using Essgee.Utilities;
|
2025-02-17 17:48:48 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
2025-02-14 16:09:33 +08:00
|
|
|
|
|
|
|
|
|
namespace Essgee.Emulation.Peripherals
|
|
|
|
|
{
|
|
|
|
|
public class Intel8255 : IPeripheral
|
|
|
|
|
{
|
|
|
|
|
[StateRequired]
|
|
|
|
|
public byte PortAInput { get; set; }
|
|
|
|
|
[StateRequired]
|
|
|
|
|
public byte PortBInput { get; set; }
|
|
|
|
|
[StateRequired]
|
|
|
|
|
public byte PortCInput { get; set; }
|
|
|
|
|
[StateRequired]
|
|
|
|
|
public byte PortAOutput { get; set; }
|
|
|
|
|
[StateRequired]
|
|
|
|
|
public byte PortBOutput { get; set; }
|
|
|
|
|
[StateRequired]
|
|
|
|
|
public byte PortCOutput { get; set; }
|
|
|
|
|
|
|
|
|
|
[StateRequired]
|
|
|
|
|
byte configByte, setResetControlByte;
|
|
|
|
|
|
|
|
|
|
int operatingModeGroupA => ((configByte >> 5) & 0x03);
|
|
|
|
|
bool isPortAInput => ((configByte & 0x10) == 0x10);
|
|
|
|
|
bool isPortCUInput => ((configByte & 0x08) == 0x08);
|
|
|
|
|
int operatingModeGroupB => ((configByte >> 2) & 0x01);
|
|
|
|
|
bool isPortBInput => ((configByte & 0x02) == 0x02);
|
|
|
|
|
bool isPortCLInput => ((configByte & 0x01) == 0x01);
|
|
|
|
|
int bitToChange => ((setResetControlByte >> 1) & 0x07);
|
|
|
|
|
bool isSetBitOperation => ((setResetControlByte & 0x01) == 0x01);
|
|
|
|
|
|
|
|
|
|
public Intel8255() { }
|
|
|
|
|
|
2025-02-17 17:48:48 +08:00
|
|
|
|
|
|
|
|
|
#region AxiState
|
|
|
|
|
|
|
|
|
|
public virtual void LoadAxiStatus(AxiEssgssStatusData data)
|
|
|
|
|
{
|
|
|
|
|
PortAInput = data.MemberData[nameof(PortAInput)].First();
|
|
|
|
|
PortBInput = data.MemberData[nameof(PortBInput)].First();
|
|
|
|
|
PortCInput = data.MemberData[nameof(PortCInput)].First();
|
|
|
|
|
PortAOutput = data.MemberData[nameof(PortAOutput)].First();
|
|
|
|
|
PortBOutput = data.MemberData[nameof(PortBOutput)].First();
|
|
|
|
|
PortCOutput = data.MemberData[nameof(PortCOutput)].First();
|
|
|
|
|
configByte = data.MemberData[nameof(configByte)].First();
|
|
|
|
|
setResetControlByte = data.MemberData[nameof(setResetControlByte)].First();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual AxiEssgssStatusData SaveAxiStatus()
|
|
|
|
|
{
|
|
|
|
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
|
|
|
|
PortAInput = data.MemberData[nameof(PortAInput)].First();
|
|
|
|
|
PortBInput = data.MemberData[nameof(PortBInput)].First();
|
|
|
|
|
PortCInput = data.MemberData[nameof(PortCInput)].First();
|
|
|
|
|
data.MemberData[nameof(PortAInput)] = BitConverter.GetBytes(PortAInput);
|
|
|
|
|
data.MemberData[nameof(PortBInput)] = BitConverter.GetBytes(PortBInput);
|
|
|
|
|
data.MemberData[nameof(PortCInput)] = BitConverter.GetBytes(PortCInput);
|
|
|
|
|
data.MemberData[nameof(PortAOutput)] = BitConverter.GetBytes(PortAOutput);
|
|
|
|
|
data.MemberData[nameof(PortBOutput)] = BitConverter.GetBytes(PortBOutput);
|
|
|
|
|
data.MemberData[nameof(PortCOutput)] = BitConverter.GetBytes(PortCOutput);
|
|
|
|
|
data.MemberData[nameof(configByte)] = BitConverter.GetBytes(configByte);
|
|
|
|
|
data.MemberData[nameof(setResetControlByte)] = BitConverter.GetBytes(setResetControlByte);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2025-02-14 16:09:33 +08:00
|
|
|
|
public void Startup()
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Shutdown()
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Reset()
|
|
|
|
|
{
|
|
|
|
|
PortAInput = PortAOutput = 0x00;
|
|
|
|
|
PortBInput = PortBOutput = 0x00;
|
|
|
|
|
PortCInput = PortCOutput = 0x00;
|
|
|
|
|
|
|
|
|
|
WritePort(0x03, 0x9B);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte ReadPort(byte port)
|
|
|
|
|
{
|
|
|
|
|
switch (port & 0x03)
|
|
|
|
|
{
|
|
|
|
|
case 0x00: return (isPortAInput ? PortAInput : PortAOutput);
|
|
|
|
|
case 0x01: return (isPortBInput ? PortBInput : PortBOutput);
|
|
|
|
|
case 0x02: return (byte)(((isPortCUInput ? PortCInput : PortCOutput) & 0xF0) | (isPortCLInput ? PortCInput : PortCOutput) & 0x0F);
|
|
|
|
|
case 0x03: return 0xFF; /* Cannot read control port */
|
|
|
|
|
|
|
|
|
|
default: throw new EmulationException(string.Format("i8255: Unsupported read from port 0x{0:X2}", port));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WritePort(byte port, byte value)
|
|
|
|
|
{
|
|
|
|
|
switch (port & 0x03)
|
|
|
|
|
{
|
|
|
|
|
case 0x00: PortAOutput = value; break;
|
|
|
|
|
case 0x01: PortBOutput = value; break;
|
|
|
|
|
case 0x02: PortCOutput = value; break;
|
|
|
|
|
|
|
|
|
|
case 0x03:
|
|
|
|
|
/* Control port */
|
|
|
|
|
if ((value & 0x80) == 0x80)
|
|
|
|
|
{
|
|
|
|
|
configByte = value;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
setResetControlByte = value;
|
|
|
|
|
|
|
|
|
|
byte mask = (byte)(1 << bitToChange);
|
|
|
|
|
if (isSetBitOperation) PortCOutput |= mask;
|
|
|
|
|
else PortCOutput &= (byte)~mask;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: throw new EmulationException(string.Format("i8255: Unsupported write to port 0x{0:X2}, value 0x{1:X2}", port, value));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|