-/*\r
- Skelton for retropc emulator\r
-\r
- Author : Takeda.Toshiya\r
- Date : 2008.04.19-\r
-\r
- [ uPD1990A / uPD4990A ]\r
-*/\r
-\r
-#include "upd1990a.h"\r
-#include "../fileio.h"\r
-\r
-#define EVENT_1SEC 0\r
-#define EVENT_TP 1\r
-\r
-void UPD1990A::initialize()\r
-{\r
- // initialize rtc\r
- emu->get_host_time(&cur_time);\r
- \r
- // register events\r
- register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec);\r
- register_id_tp = -1;\r
-}\r
-\r
-void UPD1990A::write_signal(int id, uint32 data, uint32 mask)\r
-{\r
- if(id == SIG_UPD1990A_CLK) {\r
- bool next = ((data & mask) != 0);\r
- if(!clk && next) {\r
- if((mode & 0x0f) == 1) {\r
- uint64 bit = 1;\r
-#ifdef HAS_UPD4990A\r
- if(mode & 0x80) {\r
- bit <<= (52 - 1);\r
- } else {\r
-#endif\r
- bit <<= (40 - 1);\r
-#ifdef HAS_UPD4990A\r
- }\r
-#endif\r
- shift_data >>= 1;\r
- if(din) {\r
- shift_data |= bit;\r
- } else {\r
- shift_data &= ~bit;\r
- }\r
- // output LSB\r
- dout = (uint32)(shift_data & 1);\r
- dout_changed = true;\r
- write_signals(&outputs_dout, (shift_data & 1) ? 0xffffffff : 0);\r
- }\r
-#ifdef HAS_UPD4990A\r
- shift_cmd = (shift_cmd >> 1) | (din ? 8 : 0);\r
-#endif\r
- }\r
- clk = next;\r
- } else if(id == SIG_UPD1990A_STB) {\r
- bool next = ((data & mask) != 0);\r
- if(!stb && next && !clk) {\r
-#ifdef HAS_UPD4990A\r
- if(cmd == 7) {\r
- mode = shift_cmd | 0x80;\r
- } else {\r
-#endif\r
- mode = cmd;\r
-#ifdef HAS_UPD4990A\r
- }\r
-#endif\r
- switch(mode & 0x0f) {\r
- case 0x02:\r
- {\r
- uint64 tmp = shift_data;\r
- cur_time.second = FROM_BCD(tmp);\r
- tmp >>= 8;\r
- cur_time.minute = FROM_BCD(tmp);\r
- tmp >>= 8;\r
- cur_time.hour = FROM_BCD(tmp);\r
- tmp >>= 8;\r
- cur_time.day = FROM_BCD(tmp);\r
- tmp >>= 8;\r
- cur_time.day_of_week = tmp & 0x0f;\r
- tmp >>= 4;\r
- cur_time.month = tmp & 0x0f;\r
-#ifdef HAS_UPD4990A\r
- if(mode & 0x80) {\r
- tmp >>= 4;\r
- cur_time.year = FROM_BCD(tmp);\r
- cur_time.update_year();\r
- cur_time.update_day_of_week();\r
- }\r
-#endif\r
- }\r
- hold = true;\r
- break;\r
- case 0x03:\r
- // after all bits are read, lsb of second data can be read\r
- shift_data = TO_BCD(cur_time.second);\r
- //shift_data = 0;\r
-#ifdef HAS_UPD4990A\r
- if(mode & 0x80) {\r
- shift_data <<= 8;\r
- shift_data |= TO_BCD(cur_time.year);\r
- }\r
-#endif\r
- shift_data <<= 4;\r
- shift_data |= cur_time.month;\r
- shift_data <<= 4;\r
- shift_data |= cur_time.day_of_week;\r
- shift_data <<= 8;\r
- shift_data |= TO_BCD(cur_time.day);\r
- shift_data <<= 8;\r
- shift_data |= TO_BCD(cur_time.hour);\r
- shift_data <<= 8;\r
- shift_data |= TO_BCD(cur_time.minute);\r
- shift_data <<= 8;\r
- shift_data |= TO_BCD(cur_time.second);\r
- // output LSB\r
- dout = (uint32)(shift_data & 1);\r
- dout_changed = true;\r
- write_signals(&outputs_dout, (shift_data & 1) ? 0xffffffff : 0);\r
- break;\r
- case 0x04:\r
- case 0x05:\r
- case 0x06:\r
-#ifdef HAS_UPD4990A\r
- case 0x07:\r
- case 0x08:\r
- case 0x09:\r
- case 0x0a:\r
- case 0x0b:\r
-#endif\r
- if(tpmode != (mode & 0x0f)) {\r
- if(outputs_tp.count != 0) {\r
- static const double tbl[] = {\r
- 1000000.0 / 128.0, // 64Hz\r
- 1000000.0 / 512.0, // 256Hz\r
- 1000000.0 / 2048.0, // 2048Hz\r
-#ifdef HAS_UPD4990A\r
- 1000000.0 / 4098.0, // 4096Hz\r
- 1000000.0, // 1sec\r
- 1000000.0 * 10, // 10sec\r
- 1000000.0 * 30, // 30sec\r
- 1000000.0 * 60 // 60sec\r
-#endif\r
- };\r
- if(register_id_tp != -1) {\r
- cancel_event(this, register_id_tp);\r
- register_id_tp = -1;\r
- }\r
- register_event(this, EVENT_TP, tbl[(mode & 0x0f) - 4], true, ®ister_id_tp);\r
- }\r
- tpmode = mode & 0x0f;\r
- }\r
- break;\r
- }\r
- // reset counter hold\r
- switch(mode & 0x0f) {\r
- case 0x00:\r
- case 0x01:\r
- case 0x03:\r
- if(hold) {\r
- // restart event\r
- cancel_event(this, register_id_1sec);\r
- register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec);\r
- hold = false;\r
- }\r
- break;\r
- }\r
- }\r
- stb = next;\r
- } else if(id == SIG_UPD1990A_CMD) {\r
- cmd = (cmd & ~mask) | (data & mask);\r
- cmd &= 7;\r
- } else if(id == SIG_UPD1990A_C0) {\r
- cmd = (cmd & ~1) | (data & mask ? 1 : 0);\r
- cmd &= 7;\r
- } else if(id == SIG_UPD1990A_C1) {\r
- cmd = (cmd & ~2) | (data & mask ? 2 : 0);\r
- cmd &= 7;\r
- } else if(id == SIG_UPD1990A_C2) {\r
- cmd = (cmd & ~4) | (data & mask ? 4 : 0);\r
- cmd &= 7;\r
- } else if(id == SIG_UPD1990A_DIN) {\r
- din = ((data & mask) != 0);\r
- }\r
-}\r
-\r
-void UPD1990A::event_callback(int event_id, int err)\r
-{\r
- if(event_id == EVENT_1SEC) {\r
- if(cur_time.initialized) {\r
- if(!hold) {\r
- cur_time.increment();\r
- }\r
- if(dout_changed) {\r
- dout_changed = false;\r
- } else {\r
- dout = cur_time.second & 1;\r
- write_signals(&outputs_dout, (cur_time.second & 1) ? 0xffffffff : 0);\r
- }\r
- } else {\r
- emu->get_host_time(&cur_time); // resync\r
- cur_time.initialized = true;\r
- }\r
- } else if(event_id == EVENT_TP) {\r
- write_signals(&outputs_tp, tp ? 0xffffffff : 0);\r
- tp = !tp;\r
- }\r
-}\r
-\r
-#define STATE_VERSION 2\r
-\r
-void UPD1990A::save_state(FILEIO* state_fio)\r
-{\r
- state_fio->FputUint32(STATE_VERSION);\r
- state_fio->FputInt32(this_device_id);\r
- \r
- cur_time.save_state((void *)state_fio);\r
- state_fio->FputInt32(register_id_1sec);\r
- state_fio->FputUint8(cmd);\r
- state_fio->FputUint8(mode);\r
- state_fio->FputUint8(tpmode);\r
- state_fio->FputUint64(shift_data);\r
- state_fio->FputBool(clk);\r
- state_fio->FputBool(stb);\r
- state_fio->FputBool(din);\r
- state_fio->FputBool(hold);\r
- state_fio->FputBool(tp);\r
- state_fio->FputUint32(dout);\r
- state_fio->FputBool(dout_changed);\r
- state_fio->FputInt32(register_id_tp);\r
-#ifdef HAS_UPD4990A\r
- state_fio->FputUint8(shift_cmd);\r
-#endif\r
-}\r
-\r
-bool UPD1990A::load_state(FILEIO* state_fio)\r
-{\r
- if(state_fio->FgetUint32() != STATE_VERSION) {\r
- return false;\r
- }\r
- if(state_fio->FgetInt32() != this_device_id) {\r
- return false;\r
- }\r
- if(!cur_time.load_state((void *)state_fio)) {\r
- return false;\r
- }\r
- register_id_1sec = state_fio->FgetInt32();\r
- cmd = state_fio->FgetUint8();\r
- mode = state_fio->FgetUint8();\r
- tpmode = state_fio->FgetUint8();\r
- shift_data = state_fio->FgetUint64();\r
- clk = state_fio->FgetBool();\r
- stb = state_fio->FgetBool();\r
- din = state_fio->FgetBool();\r
- hold = state_fio->FgetBool();\r
- tp = state_fio->FgetBool();\r
- dout = state_fio->FgetUint32();\r
- dout_changed = state_fio->FgetBool();\r
- register_id_tp = state_fio->FgetInt32();\r
-#ifdef HAS_UPD4990A\r
- shift_cmd = state_fio->FgetUint8();\r
-#endif\r
- return true;\r
-}\r
-\r
+/*
+ Skelton for retropc emulator
+
+ Author : Takeda.Toshiya
+ Date : 2008.04.19-
+
+ [ uPD1990A / uPD4990A ]
+*/
+
+#include "upd1990a.h"
+
+#define EVENT_1SEC 0
+#define EVENT_TP 1
+
+void UPD1990A::initialize()
+{
+ // initialize rtc
+ get_host_time(&cur_time);
+
+ // register events
+ register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec);
+ register_id_tp = -1;
+}
+
+void UPD1990A::write_signal(int id, uint32 data, uint32 mask)
+{
+ if(id == SIG_UPD1990A_CLK) {
+ bool next = ((data & mask) != 0);
+ if(!clk && next) {
+ if((mode & 0x0f) == 1) {
+ uint64 bit = 1;
+#ifdef HAS_UPD4990A
+ if(mode & 0x80) {
+ bit <<= (52 - 1);
+ } else {
+#endif
+ bit <<= (40 - 1);
+#ifdef HAS_UPD4990A
+ }
+#endif
+ shift_data >>= 1;
+ if(din) {
+ shift_data |= bit;
+ } else {
+ shift_data &= ~bit;
+ }
+ // output LSB
+ dout = (uint32)(shift_data & 1);
+ dout_changed = true;
+ write_signals(&outputs_dout, (shift_data & 1) ? 0xffffffff : 0);
+ }
+#ifdef HAS_UPD4990A
+ shift_cmd = (shift_cmd >> 1) | (din ? 8 : 0);
+#endif
+ }
+ clk = next;
+ } else if(id == SIG_UPD1990A_STB) {
+ bool next = ((data & mask) != 0);
+ if(!stb && next && !clk) {
+#ifdef HAS_UPD4990A
+ if(cmd == 7) {
+ mode = shift_cmd | 0x80;
+ } else {
+#endif
+ mode = cmd;
+#ifdef HAS_UPD4990A
+ }
+#endif
+ switch(mode & 0x0f) {
+ case 0x02:
+ {
+ uint64 tmp = shift_data;
+ cur_time.second = FROM_BCD(tmp);
+ tmp >>= 8;
+ cur_time.minute = FROM_BCD(tmp);
+ tmp >>= 8;
+ cur_time.hour = FROM_BCD(tmp);
+ tmp >>= 8;
+ cur_time.day = FROM_BCD(tmp);
+ tmp >>= 8;
+ cur_time.day_of_week = tmp & 0x0f;
+ tmp >>= 4;
+ cur_time.month = tmp & 0x0f;
+#ifdef HAS_UPD4990A
+ if(mode & 0x80) {
+ tmp >>= 4;
+ cur_time.year = FROM_BCD(tmp);
+ cur_time.update_year();
+ cur_time.update_day_of_week();
+ }
+#endif
+ }
+ hold = true;
+ break;
+ case 0x03:
+ // after all bits are read, lsb of second data can be read
+ shift_data = TO_BCD(cur_time.second);
+ //shift_data = 0;
+#ifdef HAS_UPD4990A
+ if(mode & 0x80) {
+ shift_data <<= 8;
+ shift_data |= TO_BCD(cur_time.year);
+ }
+#endif
+ shift_data <<= 4;
+ shift_data |= cur_time.month;
+ shift_data <<= 4;
+ shift_data |= cur_time.day_of_week;
+ shift_data <<= 8;
+ shift_data |= TO_BCD(cur_time.day);
+ shift_data <<= 8;
+ shift_data |= TO_BCD(cur_time.hour);
+ shift_data <<= 8;
+ shift_data |= TO_BCD(cur_time.minute);
+ shift_data <<= 8;
+ shift_data |= TO_BCD(cur_time.second);
+ // output LSB
+ dout = (uint32)(shift_data & 1);
+ dout_changed = true;
+ write_signals(&outputs_dout, (shift_data & 1) ? 0xffffffff : 0);
+ break;
+ case 0x04:
+ case 0x05:
+ case 0x06:
+#ifdef HAS_UPD4990A
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+#endif
+ if(tpmode != (mode & 0x0f)) {
+ if(outputs_tp.count != 0) {
+ static const double tbl[] = {
+ 1000000.0 / 128.0, // 64Hz
+ 1000000.0 / 512.0, // 256Hz
+ 1000000.0 / 2048.0, // 2048Hz
+#ifdef HAS_UPD4990A
+ 1000000.0 / 4098.0, // 4096Hz
+ 1000000.0, // 1sec
+ 1000000.0 * 10, // 10sec
+ 1000000.0 * 30, // 30sec
+ 1000000.0 * 60 // 60sec
+#endif
+ };
+ if(register_id_tp != -1) {
+ cancel_event(this, register_id_tp);
+ register_id_tp = -1;
+ }
+ register_event(this, EVENT_TP, tbl[(mode & 0x0f) - 4], true, ®ister_id_tp);
+ }
+ tpmode = mode & 0x0f;
+ }
+ break;
+ }
+ // reset counter hold
+ switch(mode & 0x0f) {
+ case 0x00:
+ case 0x01:
+ case 0x03:
+ if(hold) {
+ // restart event
+ cancel_event(this, register_id_1sec);
+ register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec);
+ hold = false;
+ }
+ break;
+ }
+ }
+ stb = next;
+ } else if(id == SIG_UPD1990A_CMD) {
+ cmd = (cmd & ~mask) | (data & mask);
+ cmd &= 7;
+ } else if(id == SIG_UPD1990A_C0) {
+ cmd = (cmd & ~1) | (data & mask ? 1 : 0);
+ cmd &= 7;
+ } else if(id == SIG_UPD1990A_C1) {
+ cmd = (cmd & ~2) | (data & mask ? 2 : 0);
+ cmd &= 7;
+ } else if(id == SIG_UPD1990A_C2) {
+ cmd = (cmd & ~4) | (data & mask ? 4 : 0);
+ cmd &= 7;
+ } else if(id == SIG_UPD1990A_DIN) {
+ din = ((data & mask) != 0);
+ }
+}
+
+void UPD1990A::event_callback(int event_id, int err)
+{
+ if(event_id == EVENT_1SEC) {
+ if(cur_time.initialized) {
+ if(!hold) {
+ cur_time.increment();
+ }
+ if(dout_changed) {
+ dout_changed = false;
+ } else {
+ dout = cur_time.second & 1;
+ write_signals(&outputs_dout, (cur_time.second & 1) ? 0xffffffff : 0);
+ }
+ } else {
+ get_host_time(&cur_time); // resync
+ cur_time.initialized = true;
+ }
+ } else if(event_id == EVENT_TP) {
+ write_signals(&outputs_tp, tp ? 0xffffffff : 0);
+ tp = !tp;
+ }
+}
+
+#define STATE_VERSION 2
+
+void UPD1990A::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ cur_time.save_state((void *)state_fio);
+ state_fio->FputInt32(register_id_1sec);
+ state_fio->FputUint8(cmd);
+ state_fio->FputUint8(mode);
+ state_fio->FputUint8(tpmode);
+ state_fio->FputUint64(shift_data);
+ state_fio->FputBool(clk);
+ state_fio->FputBool(stb);
+ state_fio->FputBool(din);
+ state_fio->FputBool(hold);
+ state_fio->FputBool(tp);
+ state_fio->FputUint32(dout);
+ state_fio->FputBool(dout_changed);
+ state_fio->FputInt32(register_id_tp);
+#ifdef HAS_UPD4990A
+ state_fio->FputUint8(shift_cmd);
+#endif
+}
+
+bool UPD1990A::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ if(!cur_time.load_state((void *)state_fio)) {
+ return false;
+ }
+ register_id_1sec = state_fio->FgetInt32();
+ cmd = state_fio->FgetUint8();
+ mode = state_fio->FgetUint8();
+ tpmode = state_fio->FgetUint8();
+ shift_data = state_fio->FgetUint64();
+ clk = state_fio->FgetBool();
+ stb = state_fio->FgetBool();
+ din = state_fio->FgetBool();
+ hold = state_fio->FgetBool();
+ tp = state_fio->FgetBool();
+ dout = state_fio->FgetUint32();
+ dout_changed = state_fio->FgetBool();
+ register_id_tp = state_fio->FgetInt32();
+#ifdef HAS_UPD4990A
+ shift_cmd = state_fio->FgetUint8();
+#endif
+ return true;
+}
+