OSDN Git Service

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