OSDN Git Service

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