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 / fmr30 / rtc.cpp
1 /*\r
2         FUJITSU FMR-30 Emulator 'eFMR-30'\r
3 \r
4         Author : Takeda.Toshiya\r
5         Date   : 2008.12.30 -\r
6 \r
7         [ rtc ]\r
8 */\r
9 \r
10 #include "rtc.h"\r
11 #include "../i8259.h"\r
12 #include "../../fileio.h"\r
13 \r
14 #define EVENT_1HZ       0\r
15 #define EVENT_32HZ      1\r
16 #define EVENT_DONE      2\r
17 \r
18 #define POWON   8\r
19 #define TCNT    34\r
20 #define CKHM    35\r
21 #define CKL     36\r
22 #define POWOF   36\r
23 #define POFMI   37\r
24 #define POFH    38\r
25 #define POFD    39\r
26 \r
27 void RTC::initialize()\r
28 {\r
29         // load rtc regs image\r
30         memset(regs, 0, sizeof(regs));\r
31         regs[POWON] = 0x10;     // cleared\r
32         \r
33         FILEIO* fio = new FILEIO();\r
34         if(fio->Fopen(emu->bios_path(_T("RTC.BIN")), FILEIO_READ_BINARY)) {\r
35                 fio->Fread(regs + 8, 32, 1);\r
36                 fio->Fclose();\r
37         }\r
38         delete fio;\r
39         \r
40         // init registers\r
41 //      regs[POWON] &= 0x1f;    // local power on\r
42 //      regs[POWOF] = 0x80;     // program power off\r
43         regs[POWON] = 0x10;     // cleared\r
44         regs[POWOF] = 0x20;     // illegal power off\r
45         regs[TCNT] = 0;\r
46         update_checksum();\r
47         \r
48         rtcmr = rtdsr = 0;\r
49         \r
50         // update calendar\r
51         emu->get_host_time(&cur_time);\r
52         read_from_cur_time();\r
53         \r
54         // register event\r
55         register_event_by_clock(this, EVENT_1HZ, CPU_CLOCKS, true, &register_id);\r
56         register_event_by_clock(this, EVENT_32HZ, CPU_CLOCKS >> 5, true, NULL);\r
57 }\r
58 \r
59 void RTC::release()\r
60 {\r
61         // set power off time\r
62         regs[POFMI] = TO_BCD(cur_time.minute);\r
63         regs[POFH] = TO_BCD(cur_time.hour);\r
64         regs[POFD] = TO_BCD(cur_time.day);\r
65         \r
66         // save rtc regs image\r
67         FILEIO* fio = new FILEIO();\r
68         if(fio->Fopen(emu->bios_path(_T("RTC.BIN")), FILEIO_WRITE_BINARY)) {\r
69                 fio->Fwrite(regs + 8, 32, 1);\r
70                 fio->Fclose();\r
71         }\r
72         delete fio;\r
73 }\r
74 \r
75 void RTC::write_io16(uint32 addr, uint32 data)\r
76 {\r
77         switch(addr) {\r
78         case 0:\r
79                 rtcmr = data;\r
80                 break;\r
81         case 2:\r
82                 // echo reset\r
83                 rtdsr &= ~(data & 0xe);\r
84                 update_intr();\r
85                 break;\r
86         case 4:\r
87                 if(!(rtdsr & 1)) {\r
88                         rtadr = data;\r
89                         rtdsr |= 1;\r
90                         // register event\r
91                         register_event(this, EVENT_DONE, 100, false, NULL);\r
92                 }\r
93                 break;\r
94         case 6:\r
95                 rtobr = data;\r
96                 break;\r
97         }\r
98 }\r
99 \r
100 uint32 RTC::read_io16(uint32 addr)\r
101 {\r
102         switch(addr) {\r
103         case 2:\r
104                 return rtdsr;\r
105         case 6:\r
106                 return rtibr;\r
107         }\r
108         return 0xffff;\r
109 }\r
110 \r
111 void RTC::event_callback(int event_id, int err)\r
112 {\r
113         if(event_id == EVENT_1HZ) {\r
114                 // update calendar\r
115                 if(cur_time.initialized) {\r
116                         cur_time.increment();\r
117                 } else {\r
118                         emu->get_host_time(&cur_time);  // resync\r
119                         cur_time.initialized = true;\r
120                 }\r
121                 read_from_cur_time();\r
122                 \r
123                 // 1sec interrupt\r
124                 rtdsr |= 4;\r
125                 update_intr();\r
126         } else if(event_id == EVENT_32HZ) {\r
127                 // update tcnt\r
128                 regs[TCNT]++;\r
129         } else if(event_id == EVENT_DONE) {\r
130                 int ch = (rtadr >> 1) & 0x3f;\r
131                 if(rtadr & 1) {\r
132                         // invalid address\r
133                 } else if(rtadr & 0x80) {\r
134                         // write\r
135                         if(ch <= 6) {\r
136                                 regs[ch] = (uint8)rtobr;\r
137                                 write_to_cur_time();\r
138                         } else if(ch == POWON) {\r
139                                 regs[ch] = (regs[ch] & 0xe0) | (rtobr & 0x1f);\r
140                                 if((rtobr & 0xe0) == 0xc0) {\r
141                                         // reipl\r
142                                         regs[ch] = (regs[ch] & 0x1f) | 0xc0;\r
143                                         vm->reset();\r
144                                 } else if((rtobr & 0xe0) == 0xe0) {\r
145                                         // power off\r
146                                         emu->power_off();\r
147                                 }\r
148                                 update_checksum();\r
149                         } else if(7 <= ch && ch < 32) {\r
150                                 regs[ch] = (uint8)rtobr;\r
151                                 update_checksum();\r
152                         }\r
153                 } else {\r
154                         // read\r
155                         if(ch < 40) {\r
156                                 rtibr = regs[ch];\r
157                         }\r
158                 }\r
159                 // update flags\r
160                 rtdsr &= ~1;\r
161                 rtdsr |= 2;\r
162                 update_intr();\r
163         }\r
164 }\r
165 \r
166 void RTC::read_from_cur_time()\r
167 {\r
168         regs[0] = TO_BCD(cur_time.second);\r
169         regs[1] = TO_BCD(cur_time.minute);\r
170         regs[2] = TO_BCD(cur_time.hour);\r
171         regs[3] = cur_time.day_of_week;\r
172         regs[4] = TO_BCD(cur_time.day);\r
173         regs[5] = TO_BCD(cur_time.month);\r
174         regs[6] = TO_BCD(cur_time.year);\r
175 }\r
176 \r
177 void RTC::write_to_cur_time()\r
178 {\r
179         cur_time.second = FROM_BCD(regs[0]);\r
180         cur_time.minute = FROM_BCD(regs[1]);\r
181         cur_time.hour = FROM_BCD(regs[2]);\r
182 //      cur_time.day_of_week = regs[3];\r
183         cur_time.day = FROM_BCD(regs[4]);\r
184         cur_time.month = FROM_BCD(regs[5]);\r
185         cur_time.year = FROM_BCD(regs[6]);\r
186         cur_time.update_year();\r
187         cur_time.update_day_of_week();\r
188         \r
189         // restart event\r
190         cancel_event(this, register_id);\r
191         register_event_by_clock(this, EVENT_1HZ, CPU_CLOCKS, true, &register_id);\r
192 }\r
193 \r
194 void RTC::update_checksum()\r
195 {\r
196         int sum = 0;\r
197         for(int i = 8; i < 32; i++) {\r
198                 sum += regs[i] & 0xf;\r
199                 sum += (regs[i] >> 4) & 0xf;\r
200         }\r
201         uint8 ckh = (sum >> 6) & 0xf;\r
202         uint8 ckm = (sum >> 2) & 0xf;\r
203         uint8 ckl = (sum >> 0) & 3;\r
204         \r
205         regs[CKHM] = ckh | (ckm << 4);\r
206         regs[CKL] = (regs[CKL] & 0xf0) | ckl | 0xc;\r
207 }\r
208 \r
209 void RTC::update_intr()\r
210 {\r
211         d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, (rtcmr & rtdsr & 0xe) ? 1 : 0, 1);\r
212 }\r