OSDN Git Service

[VM] MEMORY:: class within some VM will change Foo_MEMORY:: to reduce misundestanding...
[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 bool RTC::process_state(FILEIO* state_fio, bool loading)
219 {
220         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
221                 return false;
222         }
223         if(!state_fio->StateCheckInt32(this_device_id)) {
224                 return false;
225         }
226         if(!cur_time.process_state((void *)state_fio, loading)) {
227                 return false;
228         }
229         state_fio->StateInt32(register_id);
230         state_fio->StateUint16(rtcmr);
231         state_fio->StateUint16(rtdsr);
232         state_fio->StateUint16(rtadr);
233         state_fio->StateUint16(rtobr);
234         state_fio->StateUint16(rtibr);
235         state_fio->StateBuffer(regs, sizeof(regs), 1);
236         return true;
237 }