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