OSDN Git Service

4824606198f5abb7d4e2615816d8c899091fb897
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmr30 / rtc.cpp
1 /*
2         FUJITSU FMR-30 Emulator 'eFMR-30'
3
4         Author : Takeda.Toshiya
5         Date   : 2008.12.30 -
6
7         [ rtc ]
8 */
9
10 #include "rtc.h"
11 #include "../i8259.h"
12
13 #define EVENT_1HZ       0
14 #define EVENT_32HZ      1
15 #define EVENT_DONE      2
16
17 #define POWON   8
18 #define TCNT    34
19 #define CKHM    35
20 #define CKL     36
21 #define POWOF   36
22 #define POFMI   37
23 #define POFH    38
24 #define POFD    39
25 #if defined(Q_OS_WIN)
26 DLL_PREFIX_I struct cur_time_s cur_time;
27 #endif
28
29 void RTC::initialize()
30 {
31         // load rtc regs image
32         memset(regs, 0, sizeof(regs));
33         regs[POWON] = 0x10;     // cleared
34         
35         FILEIO* fio = new FILEIO();
36         if(fio->Fopen(create_local_path(_T("RTC.BIN")), FILEIO_READ_BINARY)) {
37                 fio->Fread(regs + 8, 32, 1);
38                 fio->Fclose();
39         }
40         delete fio;
41         
42         // init registers
43 //      regs[POWON] &= 0x1f;    // local power on
44 //      regs[POWOF] = 0x80;     // program power off
45         regs[POWON] = 0x10;     // cleared
46         regs[POWOF] = 0x20;     // illegal power off
47         regs[TCNT] = 0;
48         update_checksum();
49         
50         rtcmr = rtdsr = 0;
51         
52         // update calendar
53         get_host_time(&cur_time);
54         read_from_cur_time();
55         
56         // register event
57         register_event_by_clock(this, EVENT_1HZ, CPU_CLOCKS, true, &register_id);
58         register_event_by_clock(this, EVENT_32HZ, CPU_CLOCKS >> 5, true, NULL);
59 }
60
61 void RTC::release()
62 {
63         // set power off time
64         regs[POFMI] = TO_BCD(cur_time.minute);
65         regs[POFH] = TO_BCD(cur_time.hour);
66         regs[POFD] = TO_BCD(cur_time.day);
67         
68         // save rtc regs image
69         FILEIO* fio = new FILEIO();
70         if(fio->Fopen(create_local_path(_T("RTC.BIN")), FILEIO_WRITE_BINARY)) {
71                 fio->Fwrite(regs + 8, 32, 1);
72                 fio->Fclose();
73         }
74         delete fio;
75 }
76
77 void RTC::write_io16(uint32_t addr, uint32_t data)
78 {
79         switch(addr) {
80         case 0:
81                 rtcmr = data;
82                 break;
83         case 2:
84                 // echo reset
85                 rtdsr &= ~(data & 0xe);
86                 update_intr();
87                 break;
88         case 4:
89                 if(!(rtdsr & 1)) {
90                         rtadr = data;
91                         rtdsr |= 1;
92                         // register event
93                         register_event(this, EVENT_DONE, 100, false, NULL);
94                 }
95                 break;
96         case 6:
97                 rtobr = data;
98                 break;
99         }
100 }
101
102 uint32_t RTC::read_io16(uint32_t addr)
103 {
104         switch(addr) {
105         case 2:
106                 return rtdsr;
107         case 6:
108                 return rtibr;
109         }
110         return 0xffff;
111 }
112
113 void RTC::event_callback(int event_id, int err)
114 {
115         if(event_id == EVENT_1HZ) {
116                 // update calendar
117                 if(cur_time.initialized) {
118                         cur_time.increment();
119                 } else {
120                         get_host_time(&cur_time);       // resync
121                         cur_time.initialized = true;
122                 }
123                 read_from_cur_time();
124                 
125                 // 1sec interrupt
126                 rtdsr |= 4;
127                 update_intr();
128         } else if(event_id == EVENT_32HZ) {
129                 // update tcnt
130                 regs[TCNT]++;
131         } else if(event_id == EVENT_DONE) {
132                 int ch = (rtadr >> 1) & 0x3f;
133                 if(rtadr & 1) {
134                         // invalid address
135                 } else if(rtadr & 0x80) {
136                         // write
137                         if(ch <= 6) {
138                                 regs[ch] = (uint8_t)rtobr;
139                                 write_to_cur_time();
140                         } else if(ch == POWON) {
141                                 regs[ch] = (regs[ch] & 0xe0) | (rtobr & 0x1f);
142                                 if((rtobr & 0xe0) == 0xc0) {
143                                         // reipl
144                                         regs[ch] = (regs[ch] & 0x1f) | 0xc0;
145                                         vm->reset();
146                                 } else if((rtobr & 0xe0) == 0xe0) {
147                                         // power off
148                                         emu->power_off();
149                                 }
150                                 update_checksum();
151                         } else if(7 <= ch && ch < 32) {
152                                 regs[ch] = (uint8_t)rtobr;
153                                 update_checksum();
154                         }
155                 } else {
156                         // read
157                         if(ch < 40) {
158                                 rtibr = regs[ch];
159                         }
160                 }
161                 // update flags
162                 rtdsr &= ~1;
163                 rtdsr |= 2;
164                 update_intr();
165         }
166 }
167
168 void RTC::read_from_cur_time()
169 {
170         regs[0] = TO_BCD(cur_time.second);
171         regs[1] = TO_BCD(cur_time.minute);
172         regs[2] = TO_BCD(cur_time.hour);
173         regs[3] = cur_time.day_of_week;
174         regs[4] = TO_BCD(cur_time.day);
175         regs[5] = TO_BCD(cur_time.month);
176         regs[6] = TO_BCD(cur_time.year);
177 }
178
179 void RTC::write_to_cur_time()
180 {
181         cur_time.second = FROM_BCD(regs[0]);
182         cur_time.minute = FROM_BCD(regs[1]);
183         cur_time.hour = FROM_BCD(regs[2]);
184 //      cur_time.day_of_week = regs[3];
185         cur_time.day = FROM_BCD(regs[4]);
186         cur_time.month = FROM_BCD(regs[5]);
187         cur_time.year = FROM_BCD(regs[6]);
188         cur_time.update_year();
189         cur_time.update_day_of_week();
190         
191         // restart event
192         cancel_event(this, register_id);
193         register_event_by_clock(this, EVENT_1HZ, CPU_CLOCKS, true, &register_id);
194 }
195
196 void RTC::update_checksum()
197 {
198         int sum = 0;
199         for(int i = 8; i < 32; i++) {
200                 sum += regs[i] & 0xf;
201                 sum += (regs[i] >> 4) & 0xf;
202         }
203         uint8_t ckh = (sum >> 6) & 0xf;
204         uint8_t ckm = (sum >> 2) & 0xf;
205         uint8_t ckl = (sum >> 0) & 3;
206         
207         regs[CKHM] = ckh | (ckm << 4);
208         regs[CKL] = (regs[CKL] & 0xf0) | ckl | 0xc;
209 }
210
211 void RTC::update_intr()
212 {
213         d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, (rtcmr & rtdsr & 0xe) ? 1 : 0, 1);
214 }
215
216 #define STATE_VERSION   1
217
218 #include "../../statesub.h"
219
220 void RTC::decl_state()
221 {
222         enter_decl_state(STATE_VERSION);
223
224         DECL_STATE_ENTRY_CUR_TIME_T(cur_time);
225         DECL_STATE_ENTRY_INT32(register_id);
226         DECL_STATE_ENTRY_UINT16(rtcmr);
227         DECL_STATE_ENTRY_UINT16(rtdsr);
228         DECL_STATE_ENTRY_UINT16(rtadr);
229         DECL_STATE_ENTRY_UINT16(rtobr);
230         DECL_STATE_ENTRY_UINT16(rtibr);
231         DECL_STATE_ENTRY_1D_ARRAY(regs, sizeof(regs));
232
233         leave_decl_state();
234 }
235
236 void RTC::save_state(FILEIO* state_fio)
237 {
238         if(state_entry != NULL) {
239                 state_entry->save_state(state_fio);
240         }
241
242 //      state_fio->FputUint32(STATE_VERSION);
243 //      state_fio->FputInt32(this_device_id);
244         
245 //      cur_time.save_state((void *)state_fio);
246 //      state_fio->FputInt32(register_id);
247 //      state_fio->FputUint16(rtcmr);
248 //      state_fio->FputUint16(rtdsr);
249 //      state_fio->FputUint16(rtadr);
250 //      state_fio->FputUint16(rtobr);
251 //      state_fio->FputUint16(rtibr);
252 //      state_fio->Fwrite(regs, sizeof(regs), 1);
253 }
254
255 bool RTC::load_state(FILEIO* state_fio)
256 {
257         bool mb = false;
258         if(state_entry != NULL) {
259                 mb = state_entry->load_state(state_fio);
260         }
261         if(!mb) {
262                 return false;
263         }
264
265 //      if(state_fio->FgetUint32() != STATE_VERSION) {
266 //              return false;
267 //      }
268 //      if(state_fio->FgetInt32() != this_device_id) {
269 //              return false;
270 //      }
271 //      if(!cur_time.load_state((void *)state_fio)) {
272 //              return false;
273 //      }
274 //      register_id = state_fio->FgetInt32();
275 //      rtcmr = state_fio->FgetUint16();
276 //      rtdsr = state_fio->FgetUint16();
277 //      rtadr = state_fio->FgetUint16();
278 //      rtobr = state_fio->FgetUint16();
279 //      rtibr = state_fio->FgetUint16();
280 //      state_fio->Fread(regs, sizeof(regs), 1);
281         return true;
282 }
283