OSDN Git Service

[VM][Qt][OSD][Genaral] Sync to upstream ; phase 1: Merege upstream 20151217.
[csp-qt/common_source_project-fm7.git] / source / src / vm / msm58321.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2008.05.02-
6
7         [ MSM58321/MSM5832 ]
8 */
9
10 #include "msm58321.h"
11
12 #define EVENT_BUSY      0
13 #define EVENT_INC       1
14 #define EVENT_PULSE     2
15
16 #ifndef MSM58321_START_DAY
17 #define MSM58321_START_DAY 0
18 #endif
19 #ifndef MSM58321_START_YEAR
20 #define MSM58321_START_YEAR 0
21 #endif
22
23 void MSM58321::initialize()
24 {
25         // init rtc
26         memset(regs, 0, sizeof(regs));
27         regs[5] = 8; // 24h
28         regs[15] = 0x0f;
29         wreg = regnum = 0;
30         cs = true;
31         rd = wr = addr_wr = busy = hold = false;
32         count_1024hz = count_1s = count_1m = count_1h = 0;
33         
34         get_host_time(&cur_time);
35         read_from_cur_time();
36         
37         // register events
38 #ifdef HAS_MSM5832
39         register_event(this, EVENT_INC, 1000000.0, true, &register_id);
40 #else
41         register_event(this, EVENT_BUSY, 1000000.0, true, &register_id);
42 #endif
43         register_event(this, EVENT_PULSE, 1000000.0 / 8192.0, true, NULL);      // 122.1 usec
44 }
45
46 void MSM58321::event_callback(int event_id, int err)
47 {
48         if(event_id == EVENT_BUSY) {
49                 set_busy(true);
50                 register_event(this, EVENT_INC, 430, false, NULL);
51         } else if(event_id == EVENT_INC) {
52                 if(cur_time.initialized) {
53                         cur_time.increment();
54                 } else {
55                         get_host_time(&cur_time);       // resync
56                         cur_time.initialized = true;
57                 }
58                 if(!hold) {
59                         read_from_cur_time();
60                         if(regnum <= 12) {
61                                 output_data();
62                         }
63                 }
64                 set_busy(false);
65         } else if(event_id == EVENT_PULSE) {
66                 if(++count_1024hz == 4) {
67                         count_1024hz = 0;
68                         regs[15] ^= 1;
69                 }
70                 if(++count_1s = 8192) {
71                         count_1s = 0;
72                         regs[15] &= ~2;
73                 } else {
74                         regs[15] |= 2;
75                 }
76                 if(++count_1m = 60 * 8192) {
77                         count_1m = 0;
78                         regs[15] &= ~4;
79                 } else {
80                         regs[15] |= 4;
81                 }
82                 if(++count_1h = 3600 * 8192) {
83                         count_1h = 0;
84                         regs[15] &= ~8;
85                 } else {
86                         regs[15] |= 8;
87                 }
88                 regs[14] = regs[15];
89                 if(regnum == 14 || regnum == 15) {
90                         output_data();
91                 }
92         }
93 }
94
95 void MSM58321::read_from_cur_time()
96 {
97         // update clock
98         int hour = (regs[5] & 8) ? cur_time.hour : (cur_time.hour % 12);
99         int ampm = (cur_time.hour > 11) ? 4 : 0;
100         
101         regs[ 0] = TO_BCD_LO(cur_time.second);
102         regs[ 1] = TO_BCD_HI(cur_time.second);
103         regs[ 2] = TO_BCD_LO(cur_time.minute);
104         regs[ 3] = TO_BCD_HI(cur_time.minute);
105         regs[ 4] = TO_BCD_LO(hour);
106         regs[ 5] = TO_BCD_HI(hour) | ampm | (regs[5] & 8);
107         regs[ 6] = cur_time.day_of_week;
108         regs[ 7] = TO_BCD_LO(cur_time.day - MSM58321_START_DAY);
109         regs[ 8] = TO_BCD_HI(cur_time.day - MSM58321_START_DAY) | (regs[8] & 0x0c);
110         regs[ 9] = TO_BCD_LO(cur_time.month);
111         regs[10] = TO_BCD_HI(cur_time.month);
112         regs[11] = TO_BCD_LO(cur_time.year - MSM58321_START_YEAR);
113         regs[12] = TO_BCD_HI(cur_time.year - MSM58321_START_YEAR);
114 }
115
116 void MSM58321::write_to_cur_time()
117 {
118         cur_time.second = regs[0] + (regs[1] & 7) * 10;
119         cur_time.minute = regs[2] + (regs[3] & 7) * 10;
120         cur_time.hour = regs[4] + (regs[5] & 3) * 10;
121         if(!(regs[5] & 8)) {
122                 cur_time.hour %= 12;
123                 if(regs[5] & 4) {
124                         cur_time.hour += 12;
125                 }
126         }
127 //      cur_time.day_of_week = regs[6] & 7;
128         cur_time.day = regs[7] + (regs[8] & 3) * 10;
129         cur_time.day += MSM58321_START_DAY;
130         cur_time.month = regs[9] + (regs[10] & 1) * 10;
131         cur_time.year = regs[11] + regs[12] * 10;
132         cur_time.year += MSM58321_START_YEAR;
133         cur_time.update_year();
134         cur_time.update_day_of_week();
135         
136         // restart event
137         cancel_event(this, register_id);
138 #ifdef HAS_MSM5832
139         register_event(this, EVENT_INC, 1000000.0, true, &register_id);
140 #else
141         register_event(this, EVENT_BUSY, 1000000.0, true, &register_id);
142 #endif
143 }
144
145 void MSM58321::write_signal(int id, uint32 data, uint32 mask)
146 {
147         if(id == SIG_MSM58321_DATA) {
148                 wreg = (data & mask) | (wreg & ~mask);
149         } else if(id == SIG_MSM58321_CS) {
150                 bool next = ((data & mask) != 0);
151 //              if(!cs && next) {
152 //                      if(wr) {
153 //                              regs[regnum] = wreg & 0x0f;
154 //                              if(regnum <= 12) {
155 //                                      write_to_cur_time();
156 //                              }
157 //                      }
158 //                      if(addr_wr) {
159 //                              regnum = wreg & 0x0f;
160 //                      }
161 //              }
162                 cs = next;
163                 output_data();
164         } else if(id == SIG_MSM58321_READ) {
165                 rd = ((data & mask) != 0);
166                 output_data();
167         } else if(id == SIG_MSM58321_WRITE) {
168                 bool next = ((data & mask) != 0);
169                 if(!wr && next && cs) {
170                         regs[regnum] = wreg & 0x0f;
171                         if(regnum <= 12) {
172                                 write_to_cur_time();
173                         }
174                 }
175                 wr = next;
176         } else if(id == SIG_MSM58321_ADDR_WRITE) {
177                 bool next = ((data & mask) != 0);
178                 if(addr_wr && !next && cs) {
179                         regnum = wreg & 0x0f;
180                         output_data();
181                 }
182                 addr_wr = next;
183         } else if(id == SIG_MSM5832_ADDR) {
184                 regnum = (data & mask) | (regnum & ~mask);
185                 output_data();
186         } else if(id == SIG_MSM5832_HOLD) {
187                 hold = ((data & mask) != 0);
188         }
189 }
190
191 void MSM58321::output_data()
192 {
193         if(cs && rd) {
194                 write_signals(&outputs_data, regs[regnum]);
195         }
196 }
197
198 void MSM58321::set_busy(bool val)
199 {
200 #ifndef HAS_MSM5832
201         if(busy != val) {
202                 write_signals(&outputs_busy, busy ? 0 : 0xffffffff);    // negative
203         }
204 #endif
205         busy = val;
206 }
207
208 #define STATE_VERSION   1
209
210 void MSM58321::save_state(FILEIO* state_fio)
211 {
212         state_fio->FputUint32(STATE_VERSION);
213         state_fio->FputInt32(this_device_id);
214         
215         cur_time.save_state((void *)state_fio);
216         state_fio->FputInt32(register_id);
217         state_fio->Fwrite(regs, sizeof(regs), 1);
218         state_fio->FputUint8(wreg);
219         state_fio->FputUint8(regnum);
220         state_fio->FputBool(cs);
221         state_fio->FputBool(rd);
222         state_fio->FputBool(wr);
223         state_fio->FputBool(addr_wr);
224         state_fio->FputBool(busy);
225         state_fio->FputBool(hold);
226         state_fio->FputInt32(count_1024hz);
227         state_fio->FputInt32(count_1s);
228         state_fio->FputInt32(count_1m);
229         state_fio->FputInt32(count_1h);
230 }
231
232 bool MSM58321::load_state(FILEIO* state_fio)
233 {
234         if(state_fio->FgetUint32() != STATE_VERSION) {
235                 return false;
236         }
237         if(state_fio->FgetInt32() != this_device_id) {
238                 return false;
239         }
240         if(!cur_time.load_state((void *)state_fio)) {
241                 return false;
242         }
243         register_id = state_fio->FgetInt32();
244         state_fio->Fread(regs, sizeof(regs), 1);
245         wreg = state_fio->FgetUint8();
246         regnum = state_fio->FgetUint8();
247         cs = state_fio->FgetBool();
248         rd = state_fio->FgetBool();
249         wr = state_fio->FgetBool();
250         addr_wr = state_fio->FgetBool();
251         busy = state_fio->FgetBool();
252         hold = state_fio->FgetBool();
253         count_1024hz = state_fio->FgetInt32();
254         count_1s = state_fio->FgetInt32();
255         count_1m = state_fio->FgetInt32();
256         count_1h = state_fio->FgetInt32();
257         return true;
258 }
259