OSDN Git Service

[VM][General][WIP] Syncing to UPSTREAM 2015-01-21 , work-in-progress.
[csp-qt/common_source_project-fm7.git] / source / src / vm / upd4991a.cpp
1 /*\r
2         Skelton for retropc emulator\r
3 \r
4         Author : Takeda.Toshiya\r
5         Date   : 2008.06.10-\r
6 \r
7         [ uPD4991A ]\r
8 */\r
9 \r
10 #include "upd4991a.h"\r
11 #include "../fileio.h"\r
12 \r
13 void UPD4991A::initialize()\r
14 {\r
15         // initialize rtc\r
16         memset(regs, 0, sizeof(regs));\r
17         ctrl1 = ctrl2 = mode = 0;\r
18         \r
19         emu->get_host_time(&cur_time);\r
20         read_from_cur_time();\r
21         \r
22         // register event\r
23         register_event(this, 0, 1000000.0, true, &register_id);\r
24 }\r
25 \r
26 void UPD4991A::write_io8(uint32 addr, uint32 data)\r
27 {\r
28         addr &= 0x0f;\r
29         if(addr <= 12) {\r
30                 if(mode == 0 || mode == 3) {\r
31                         if(regs[0][addr] != data) {\r
32                                 regs[0][addr] = data;\r
33                                 write_to_cur_time();\r
34                         }\r
35                 } else if(mode == 1) {\r
36                         regs[1][addr] = data;\r
37                 } else if(mode == 2) {\r
38                         uint8 tmp = regs[2][addr] ^ data;\r
39                         regs[2][addr] = data;\r
40                         // am/pm is changed ?\r
41                         if(addr == 12 && (tmp & 8)) {\r
42                                 read_from_cur_time();\r
43                         }\r
44                 } else {\r
45                 }\r
46         } else if(addr == 13) {\r
47                 ctrl1 = data;\r
48         } else if(addr == 14) {\r
49                 ctrl2 = data;\r
50         } else if(addr == 15) {\r
51                 mode = data & 0x0b;\r
52         }\r
53 }\r
54 \r
55 uint32 UPD4991A::read_io8(uint32 addr)\r
56 {\r
57         addr &= 0x0f;\r
58         if(addr <= 12) {\r
59                 if(mode == 0 || mode == 3) {\r
60                         return regs[0][addr];\r
61                 } else if(mode == 1 || mode == 2) {\r
62                         return regs[mode][addr];\r
63                 }\r
64         } else if(addr == 14) {\r
65                 return ctrl2;\r
66         }\r
67         return 0x0f;\r
68 }\r
69 \r
70 void UPD4991A::event_callback(int event_id, int err)\r
71 {\r
72         // update clock\r
73         if(cur_time.initialized) {\r
74                 cur_time.increment();\r
75         } else {\r
76                 emu->get_host_time(&cur_time);  // resync\r
77                 cur_time.initialized = true;\r
78         }\r
79         \r
80         if(!(ctrl1 & 8)) {\r
81                 read_from_cur_time();\r
82         }\r
83 }\r
84 \r
85 #define MODE_12H !(regs[2][12] & 8)\r
86 \r
87 void UPD4991A::read_from_cur_time()\r
88 {\r
89         int hour = MODE_12H ? (cur_time.hour % 12) : cur_time.hour;\r
90         int ampm = (MODE_12H && cur_time.hour >= 12) ? 4 : 0;\r
91         \r
92         regs[0][ 0] = TO_BCD_LO(cur_time.second);\r
93         regs[0][ 1] = TO_BCD_HI(cur_time.second);\r
94         regs[0][ 2] = TO_BCD_LO(cur_time.minute);\r
95         regs[0][ 3] = TO_BCD_HI(cur_time.minute);\r
96         regs[0][ 4] = TO_BCD_LO(hour);\r
97         regs[0][ 5] = TO_BCD_HI(hour) | ampm;\r
98         regs[0][ 6] = cur_time.day_of_week;\r
99         regs[0][ 7] = TO_BCD_LO(cur_time.day);\r
100         regs[0][ 8] = TO_BCD_HI(cur_time.day);\r
101         regs[0][ 9] = TO_BCD_LO(cur_time.month);\r
102         regs[0][10] = TO_BCD_HI(cur_time.month);\r
103         regs[0][11] = TO_BCD_LO(cur_time.year);\r
104         regs[0][12] = TO_BCD_HI(cur_time.year);\r
105         \r
106         // TODO: check alarm\r
107 }\r
108 \r
109 void UPD4991A::write_to_cur_time()\r
110 {\r
111         cur_time.second = regs[0][0] + (regs[0][1] & 7) * 10;\r
112         cur_time.minute = regs[0][2] + (regs[0][3] & 7) * 10;\r
113         if(MODE_12H) {\r
114                 cur_time.hour = regs[0][4] + (regs[0][5] & 1) * 10 + (regs[0][5] & 4 ? 12 : 0);\r
115         } else {\r
116                 cur_time.hour = regs[0][4] + (regs[0][5] & 3) * 10;\r
117         }\r
118 //      cur_time.day_of_week = regs[0][6];\r
119         cur_time.day = regs[0][7] + (regs[0][8] & 3) * 10;\r
120         cur_time.month = regs[0][9] + (regs[0][10] & 1) * 10;\r
121         cur_time.year = regs[0][11] + regs[0][12] * 10;\r
122         cur_time.update_year();\r
123         cur_time.update_day_of_week();\r
124         \r
125         // restart event\r
126         cancel_event(this, register_id);\r
127         register_event(this, 0, 1000000.0, true, &register_id);\r
128 }\r
129 \r
130 \r
131 #define STATE_VERSION   1\r
132 \r
133 void UPD4991A::save_state(FILEIO* state_fio)\r
134 {\r
135         state_fio->FputUint32(STATE_VERSION);\r
136         state_fio->FputInt32(this_device_id);\r
137         \r
138         cur_time.save_state((void *)state_fio);\r
139         state_fio->FputInt32(register_id);\r
140         state_fio->Fwrite(regs, sizeof(regs), 1);\r
141         state_fio->FputUint8(ctrl1);\r
142         state_fio->FputUint8(ctrl2);\r
143         state_fio->FputUint8(mode);\r
144 }\r
145 \r
146 bool UPD4991A::load_state(FILEIO* state_fio)\r
147 {\r
148         if(state_fio->FgetUint32() != STATE_VERSION) {\r
149                 return false;\r
150         }\r
151         if(state_fio->FgetInt32() != this_device_id) {\r
152                 return false;\r
153         }\r
154         if(!cur_time.load_state((void *)state_fio)) {\r
155                 return false;\r
156         }\r
157         register_id = state_fio->FgetInt32();\r
158         state_fio->Fread(regs, sizeof(regs), 1);\r
159         ctrl1 = state_fio->FgetUint8();\r
160         ctrl2 = state_fio->FgetUint8();\r
161         mode = state_fio->FgetUint8();\r
162         return true;\r
163 }\r
164 \r