MAME.Core/MAME.Unity/Assets/Plugins/UMAME/emu/Pd4900a.cs
2025-01-16 11:51:17 +08:00

360 lines
12 KiB
C#

using System.IO;
namespace MAME.Core
{
public class Pd4900a
{
public struct pd4990a_s
{
public int seconds;
public int minutes;
public int hours;
public int days;
public int month;
public int year;
public int weekday;
}
public static pd4990a_s pd4990a;
public static uint shiftlo, shifthi;
public static int retraces = 0; /* Assumes 60 retraces a second */
public static int testwaits = 0;
public static int maxwaits = 1; /*switch test every frame*/
public static int testbit = 0; /* Pulses a bit in order to simulate */
public static int outputbit = 0;
public static int bitno = 0;
public static byte reading = 0;
public static byte writting = 0;
public static int clock_line = 0;
public static int command_line = 0; //??
public static void pd4990a_init()
{
pd4990a.seconds = 0x00; /* seconds BCD */
pd4990a.minutes = 0x00; /* minutes BCD */
pd4990a.hours = 0x00; /* hours BCD */
pd4990a.days = 0x09; /* days BCD */
pd4990a.month = 9; /* month Hexadecimal form */
pd4990a.year = 0x73; /* year BCD */
pd4990a.weekday = 1; /* weekday BCD */
}
public static void pd4990a_addretrace()
{
++testwaits;
if (testwaits >= maxwaits)
{
testbit ^= 1;
testwaits = 0;
}
retraces++;
if (retraces < 60)
return;
retraces = 0;
pd4990a.seconds++;
if ((pd4990a.seconds & 0x0f) < 10)
return;
pd4990a.seconds &= 0xf0;
pd4990a.seconds += 0x10;
if (pd4990a.seconds < 0x60)
return;
pd4990a.seconds = 0;
pd4990a.minutes++;
if ((pd4990a.minutes & 0x0f) < 10)
return;
pd4990a.minutes &= 0xf0;
pd4990a.minutes += 0x10;
if (pd4990a.minutes < 0x60)
return;
pd4990a.minutes = 0;
pd4990a.hours++;
if ((pd4990a.hours & 0x0f) < 10)
return;
pd4990a.hours &= 0xf0;
pd4990a.hours += 0x10;
if (pd4990a.hours < 0x24)
return;
pd4990a.hours = 0;
pd4990a_increment_day();
}
private static void pd4990a_increment_day()
{
int real_year;
pd4990a.days++;
if ((pd4990a.days & 0x0f) >= 10)
{
pd4990a.days &= 0xf0;
pd4990a.days += 0x10;
}
pd4990a.weekday++;
if (pd4990a.weekday == 7)
pd4990a.weekday = 0;
switch (pd4990a.month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (pd4990a.days == 0x32)
{
pd4990a.days = 1;
pd4990a_increment_month();
}
break;
case 2:
real_year = (pd4990a.year >> 4) * 10 + (pd4990a.year & 0xf);
if ((real_year % 4) != 0 && ((real_year % 100) == 0 || (real_year % 400) != 0))
{
if (pd4990a.days == 0x29)
{
pd4990a.days = 1;
pd4990a_increment_month();
}
}
else
{
if (pd4990a.days == 0x30)
{
pd4990a.days = 1;
pd4990a_increment_month();
}
}
break;
case 4:
case 6:
case 9:
case 11:
if (pd4990a.days == 0x31)
{
pd4990a.days = 1;
pd4990a_increment_month();
}
break;
}
}
private static void pd4990a_increment_month()
{
pd4990a.month++;
if (pd4990a.month == 13)
{
pd4990a.month = 1;
pd4990a.year++;
if ((pd4990a.year & 0x0f) >= 10)
{
pd4990a.year &= 0xf0;
pd4990a.year += 0x10;
}
if (pd4990a.year == 0xA0)
pd4990a.year = 0;
}
}
private static void pd4990a_readbit()
{
switch (bitno)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
outputbit = (pd4990a.seconds >> bitno) & 0x01;
break;
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
outputbit = (pd4990a.minutes >> (bitno - 0x08)) & 0x01;
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
outputbit = (pd4990a.hours >> (bitno - 0x10)) & 0x01;
break;
case 0x18:
case 0x19:
case 0x1a:
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
outputbit = (pd4990a.days >> (bitno - 0x18)) & 0x01;
break;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
outputbit = (pd4990a.weekday >> (bitno - 0x20)) & 0x01;
break;
case 0x24:
case 0x25:
case 0x26:
case 0x27:
outputbit = (pd4990a.month >> (bitno - 0x24)) & 0x01;
break;
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
outputbit = (pd4990a.year >> (bitno - 0x28)) & 0x01;
break;
case 0x30:
case 0x31:
case 0x32:
case 0x33:
//unknown
break;
}
}
private static void pd4990a_resetbitstream()
{
shiftlo = 0;
shifthi = 0;
bitno = 0;
}
private static void pd4990a_writebit(byte bit)
{
if (bitno <= 31) //low part
shiftlo |= (uint)(bit << bitno);
else //high part
shifthi |= (uint)(bit << (bitno - 32));
}
private static void pd4990a_nextbit()
{
++bitno;
if (reading != 0)
pd4990a_readbit();
if (reading != 0 && bitno == 0x34)
{
reading = 0;
pd4990a_resetbitstream();
}
}
private static byte pd4990a_getcommand()
{
//Warning: problems if the 4 bits are in different
//parts, It's very strange that this case could happen.
if (bitno <= 31)
return (byte)(shiftlo >> (bitno - 4));
else
return (byte)(shifthi >> (bitno - 32 - 4));
}
private static void pd4990a_update_date()
{
pd4990a.seconds = (int)((shiftlo >> 0) & 0xff);
pd4990a.minutes = (int)((shiftlo >> 8) & 0xff);
pd4990a.hours = (int)((shiftlo >> 16) & 0xff);
pd4990a.days = (int)((shiftlo >> 24) & 0xff);
pd4990a.weekday = (int)((shifthi >> 0) & 0x0f);
pd4990a.month = (int)((shifthi >> 4) & 0x0f);
pd4990a.year = (int)((shifthi >> 8) & 0xff);
}
private static void pd4990a_process_command()
{
switch (pd4990a_getcommand())
{
case 0x1: //load output register
bitno = 0;
if (reading != 0)
pd4990a_readbit(); //prepare first bit
shiftlo = 0;
shifthi = 0;
break;
case 0x2:
writting = 0; //store register to current date
pd4990a_update_date();
break;
case 0x3: //start reading
reading = 1;
break;
case 0x7: //switch testbit every frame
maxwaits = 1;
break;
case 0x8: //switch testbit every half-second
maxwaits = 30;
break;
}
pd4990a_resetbitstream();
}
private static void pd4990a_serial_control(byte data)
{
//Check for command end
if (command_line != 0 && (data & 4) == 0) //end of command
{
pd4990a_process_command();
}
command_line = data & 4;
if (clock_line != 0 && (data & 2) == 0) //clock lower edge
{
pd4990a_writebit((byte)(data & 1));
pd4990a_nextbit();
}
clock_line = data & 2;
}
public static void pd4990a_control_16_w(byte data)
{
pd4990a_serial_control((byte)(data & 0x7));
}
public static void SaveStateBinary(BinaryWriter writer)
{
writer.Write(pd4990a.seconds);
writer.Write(pd4990a.minutes);
writer.Write(pd4990a.hours);
writer.Write(pd4990a.days);
writer.Write(pd4990a.month);
writer.Write(pd4990a.year);
writer.Write(pd4990a.weekday);
writer.Write(shiftlo);
writer.Write(shifthi);
writer.Write(retraces);
writer.Write(testwaits);
writer.Write(maxwaits);
writer.Write(testbit);
writer.Write(outputbit);
writer.Write(bitno);
writer.Write(reading);
writer.Write(writting);
writer.Write(clock_line);
writer.Write(command_line);
}
public static void LoadStateBinary(BinaryReader reader)
{
pd4990a.seconds = reader.ReadInt32();
pd4990a.minutes = reader.ReadInt32();
pd4990a.hours = reader.ReadInt32();
pd4990a.days = reader.ReadInt32();
pd4990a.month = reader.ReadInt32();
pd4990a.year = reader.ReadInt32();
pd4990a.weekday = reader.ReadInt32();
shiftlo = reader.ReadUInt32();
shifthi = reader.ReadUInt32();
retraces = reader.ReadInt32();
testwaits = reader.ReadInt32();
maxwaits = reader.ReadInt32();
testbit = reader.ReadInt32();
outputbit = reader.ReadInt32();
bitno = reader.ReadInt32();
reading = reader.ReadByte();
writting = reader.ReadByte();
clock_line = reader.ReadInt32();
command_line = reader.ReadInt32();
}
}
}