OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / upd1990a.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2008.04.19-
6
7         [ uPD1990A / uPD4990A ]
8 */
9
10 #include "upd1990a.h"
11
12 #define EVENT_1SEC      0
13 #define EVENT_TP        1
14 #if defined(Q_OS_WIN)
15 DLL_PREFIX_I struct cur_time_s cur_time;
16 #endif
17
18 void UPD1990A::initialize()
19 {
20         DEVICE::initialize();
21         __HAS_UPD4990A = osd->check_feature(_T("HAS_UPD4990A"));
22         if(__HAS_UPD4990A) set_device_name(_T("uPD4990A_RTC"));
23         // initialize rtc
24         get_host_time(&cur_time);
25         
26         // register events
27         register_event(this, EVENT_1SEC, 1000000.0, true, &register_id_1sec);
28         tp_usec = 1.0e6 / 128.0; // 64Hz
29         register_id_tp = -1;
30 }
31
32 void UPD1990A::write_signal(int id, uint32_t data, uint32_t mask)
33 {
34         static const double tbl[] = {
35                 1000000.0 / 128.0,      // 64Hz
36                 1000000.0 / 512.0,      // 256Hz
37                 1000000.0 / 2048.0,     // 2048Hz
38 //#ifdef HAS_UPD4990A
39                 1000000.0 / 4096.0,     // 4096Hz
40                 1000000.0,              // 1sec
41                 1000000.0 * 10,         // 10sec
42                 1000000.0 * 30,         // 30sec
43                 1000000.0 * 60          // 60sec
44 //#endif
45         };
46         if(id == SIG_UPD1990A_CLK) {
47                 bool next = ((data & mask) != 0);
48                 if(!clk && next) {
49                         if((mode & 0x0f) == 1) {
50                                 uint64_t bit = 1;
51 //#ifdef HAS_UPD4990A
52                                 if(__HAS_UPD4990A) {
53                                         if(mode & 0x80) {
54                                                 bit <<= (52 - 1);
55                                         } else {
56 //#endif
57                                                 bit <<= (40 - 1);
58 //#ifdef HAS_UPD4990A
59                                         }
60                                 } else {
61 //#endif
62                                         bit <<= (40 - 1);
63                                 }                                       
64                                 shift_data >>= 1;
65                                 if(din) {
66                                         shift_data |= bit;
67                                 } else {
68                                         shift_data &= ~bit;
69                                 }
70                                 // output LSB
71                                 dout = (uint32_t)(shift_data & 1);
72                                 dout_changed = true;
73                                 write_signals(&outputs_dout, (shift_data & 1) ? 0xffffffff : 0);
74                         }
75 //#ifdef HAS_UPD4990A
76                         if(__HAS_UPD4990A) shift_cmd = (shift_cmd >> 1) | (din ? 8 : 0);
77 //#endif
78                 }
79                 clk = next;
80         } else if(id == SIG_UPD1990A_STB) {
81                 bool next = ((data & mask) != 0);
82                 if(!stb && next/* && !clk*/) {
83 //#ifdef HAS_UPD4990A
84                         if(__HAS_UPD4990A) {
85                                 if(cmd == 7) {
86                                         mode = shift_cmd | 0x80;
87                                 } else {
88 //#endif
89                                         mode = cmd & 0x07;
90 //#ifdef HAS_UPD4990A
91                                 }
92                         } else {
93                                 mode = cmd & 7;
94                         }
95 //#endif
96                         switch(mode & 0x0f) {
97                         case 0x02:
98                                 {
99                                         // Time set
100                                         uint64_t tmp = shift_data;
101                                         cur_time.second = FROM_BCD(tmp);
102                                         tmp >>= 8;
103                                         cur_time.minute = FROM_BCD(tmp);
104                                         tmp >>= 8;
105                                         cur_time.hour = FROM_BCD(tmp);
106                                         tmp >>= 8;
107                                         cur_time.day = FROM_BCD(tmp);
108                                         tmp >>= 8;
109                                         cur_time.day_of_week = tmp & 0x0f;
110                                         tmp >>= 4;
111                                         cur_time.month = tmp & 0x0f;
112 //#ifdef HAS_UPD4990A
113                                         if(__HAS_UPD4990A) {
114                                                 if(mode & 0x80) {
115                                                         tmp >>= 4;
116                                                         cur_time.year = FROM_BCD(tmp);
117                                                         cur_time.update_year();
118                                                         cur_time.update_day_of_week();
119                                                 }
120                                         }
121 //#endif
122                                 }
123                                 hold = true;
124                                 break;
125                         case 0x03:
126                                 // after all bits are read, lsb of second data can be read
127                            shift_data = 0;
128 //#ifdef HAS_UPD4990A
129                                 if(__HAS_UPD4990A) {
130                                         if(mode & 0x80) {
131                                                 shift_data <<= 8;
132                                                 shift_data |= TO_BCD(cur_time.year);
133                                         }
134                                 }
135 //#endif
136                                 shift_data <<= 4;
137                                 shift_data |= cur_time.month;
138                                 shift_data <<= 4;
139                                 shift_data |= cur_time.day_of_week;
140                                 shift_data <<= 8;
141                                 shift_data |= TO_BCD(cur_time.day);
142                                 shift_data <<= 8;
143                                 shift_data |= TO_BCD(cur_time.hour);
144                                 shift_data <<= 8;
145                                 shift_data |= TO_BCD(cur_time.minute);
146                                 shift_data <<= 8;
147                                 shift_data |= TO_BCD(cur_time.second);
148                                 // output LSB
149                                 dout = (uint32_t)(shift_data & 1);
150                                 dout_changed = true;
151                                 write_signals(&outputs_dout, (shift_data & 1) ? 0xffffffff : 0);
152                                 break;
153                         case 0x04:
154                         case 0x05:
155                         case 0x06:
156 //#ifdef HAS_UPD4990A
157                         case 0x07:
158                         case 0x08:
159                         case 0x09:
160                         case 0x0a:
161                         case 0x0b:
162 //#endif
163                                 if(!(__HAS_UPD4990A) && ((mode & 0x07) == 0x07)) break;
164                                 if(tpmode != (mode & 0x0f)) {
165                                         if(outputs_tp.count != 0) {
166                                                 if(register_id_tp != -1) {
167                                                         cancel_event(this, register_id_tp);
168                                                         register_id_tp = -1;
169                                                 }
170                                                 if(!(__HAS_UPD4990A) || ((mode & 0x80) == 0)) {
171                                                         tp_usec = tbl[(mode & 0x07) - 4];
172                                                 } else { // uPD4990A
173                                                         tp_usec = tbl[(mode & 0x0f) - 4];
174                                                 }                                                       
175                                                 register_event(this, EVENT_TP, tp_usec, true, &register_id_tp);
176                                         }
177                                         tpmode = mode & 0x0f;
178                                 }
179                                 break;
180                                 // Below are extra commands.
181                         case 0x0c: // Int reset
182                                 tp = false;
183                                 write_signals(&outputs_tp, 0);
184                                 break;
185                         case 0x0d: // Int Start
186                                 if(register_id_tp == -1) {
187                                         tp = false;
188                                         register_event(this, EVENT_TP, tp_usec, true, &register_id_tp);
189                                 }
190                                 break;
191                         case 0x0e: // Int Stop
192                                 if(register_id_tp != -1) {
193                                         cancel_event(this, register_id_tp);
194                                         register_id_tp = -1;
195                                         tp = false;
196                                 }
197                                 break;
198                         case 0x0f:
199                                 // TEST: ToDo
200                                 break;
201                         default:
202                                 break;
203                         }
204                         // reset counter hold
205                         switch(mode & 0x0f) {
206                         case 0x00:
207                         case 0x01:
208                         case 0x03:
209                                 if(hold) {
210                                         // restart event
211                                         cancel_event(this, register_id_1sec);
212                                         register_event(this, EVENT_1SEC, 1000000.0, true, &register_id_1sec);
213                                         hold = false;
214                                 }
215                                 break;
216                         }
217                 }
218                 stb = next;
219         } else if(id == SIG_UPD1990A_CMD) {
220                 cmd = (cmd & ~mask) | (data & mask);
221                 cmd &= 7;
222         } else if(id == SIG_UPD1990A_C0) {
223                 cmd = (cmd & ~1) | (data & mask ? 1 : 0);
224                 cmd &= 7;
225         } else if(id == SIG_UPD1990A_C1) {
226                 cmd = (cmd & ~2) | (data & mask ? 2 : 0);
227                 cmd &= 7;
228         } else if(id == SIG_UPD1990A_C2) {
229                 cmd = (cmd & ~4) | (data & mask ? 4 : 0);
230                 cmd &= 7;
231         } else if(id == SIG_UPD1990A_DIN) {
232                 din = ((data & mask) != 0);
233         }
234 }
235
236 void UPD1990A::event_callback(int event_id, int err)
237 {
238         if(event_id == EVENT_1SEC) {
239                 if(cur_time.initialized) {
240                         if(!hold) {
241                                 cur_time.increment();
242                         }
243                         if(dout_changed) {
244                                 dout_changed = false;
245                         } else {
246                                 dout = cur_time.second & 1;
247                                 write_signals(&outputs_dout, (cur_time.second & 1) ? 0xffffffff : 0);
248                         }
249                 } else {
250                         get_host_time(&cur_time);       // resync
251                         cur_time.initialized = true;
252                 }
253         } else if(event_id == EVENT_TP) {
254                 write_signals(&outputs_tp, tp ? 0xffffffff : 0);
255                 tp = !tp;
256         }
257 }
258
259 #define STATE_VERSION   3
260
261 bool UPD1990A::process_state(FILEIO* state_fio, bool loading)
262 {
263         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
264                 return false;
265         }
266         if(!state_fio->StateCheckInt32(this_device_id)) {
267                 return false;
268         }
269         if(!cur_time.process_state((void *)state_fio, loading)) {
270                 return false;
271         }
272         state_fio->StateValue(register_id_1sec);
273         state_fio->StateValue(cmd);
274         state_fio->StateValue(mode);
275         state_fio->StateValue(tpmode);
276         state_fio->StateValue(shift_data);
277         state_fio->StateValue(clk);
278         state_fio->StateValue(stb);
279         state_fio->StateValue(din);
280         state_fio->StateValue(hold);
281         state_fio->StateValue(tp);
282         state_fio->StateValue(dout);
283         state_fio->StateValue(dout_changed);
284         state_fio->StateValue(register_id_tp);
285         if(__HAS_UPD4990A) {
286                 state_fio->StateValue(shift_cmd);
287         }
288         state_fio->StateValue(tp_usec);
289         return true;
290 }