OSDN Git Service

[VM] Add PC-8001/mk2/8801/mk2.
[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         DEVICE::initialize();
15         // initialize rtc
16         memset(regs, 0, sizeof(regs));
17         ctrl1 = ctrl2 = mode = 0;
18         
19         get_host_time(&cur_time);
20         read_from_cur_time();
21         
22         // register event
23         register_event(this, 0, 1000000.0, true, &register_id);
24 }
25
26 void UPD4991A::write_io8(uint32_t addr, uint32_t data)
27 {
28         addr &= 0x0f;
29         if(addr <= 12) {
30                 if(mode == 0 || mode == 3) {
31                         if(regs[0][addr] != data) {
32                                 regs[0][addr] = data;
33                                 write_to_cur_time();
34                         }
35                 } else if(mode == 1) {
36                         regs[1][addr] = data;
37                 } else if(mode == 2) {
38                         uint8_t tmp = regs[2][addr] ^ data;
39                         regs[2][addr] = data;
40                         // am/pm is changed ?
41                         if(addr == 12 && (tmp & 8)) {
42                                 read_from_cur_time();
43                         }
44                 } else {
45                 }
46         } else if(addr == 13) {
47                 ctrl1 = data;
48         } else if(addr == 14) {
49                 ctrl2 = data;
50         } else if(addr == 15) {
51                 mode = data & 0x0b;
52         }
53 }
54
55 uint32_t UPD4991A::read_io8(uint32_t addr)
56 {
57         addr &= 0x0f;
58         if(addr <= 12) {
59                 if(mode == 0 || mode == 3) {
60                         return regs[0][addr];
61                 } else if(mode == 1 || mode == 2) {
62                         return regs[mode][addr];
63                 }
64         } else if(addr == 14) {
65                 return ctrl2;
66         }
67         return 0x0f;
68 }
69
70 void UPD4991A::event_callback(int event_id, int err)
71 {
72         // update clock
73         if(cur_time.initialized) {
74                 cur_time.increment();
75         } else {
76                 get_host_time(&cur_time);       // resync
77                 cur_time.initialized = true;
78         }
79         
80         if(!(ctrl1 & 8)) {
81                 read_from_cur_time();
82         }
83 }
84
85 #define MODE_12H !(regs[2][12] & 8)
86
87 void UPD4991A::read_from_cur_time()
88 {
89         int hour = MODE_12H ? (cur_time.hour % 12) : cur_time.hour;
90         int ampm = (MODE_12H && cur_time.hour >= 12) ? 4 : 0;
91         
92         regs[0][ 0] = TO_BCD_LO(cur_time.second);
93         regs[0][ 1] = TO_BCD_HI(cur_time.second);
94         regs[0][ 2] = TO_BCD_LO(cur_time.minute);
95         regs[0][ 3] = TO_BCD_HI(cur_time.minute);
96         regs[0][ 4] = TO_BCD_LO(hour);
97         regs[0][ 5] = TO_BCD_HI(hour) | ampm;
98         regs[0][ 6] = cur_time.day_of_week;
99         regs[0][ 7] = TO_BCD_LO(cur_time.day);
100         regs[0][ 8] = TO_BCD_HI(cur_time.day);
101         regs[0][ 9] = TO_BCD_LO(cur_time.month);
102         regs[0][10] = TO_BCD_HI(cur_time.month);
103         regs[0][11] = TO_BCD_LO(cur_time.year);
104         regs[0][12] = TO_BCD_HI(cur_time.year);
105         
106         // TODO: check alarm
107 }
108
109 void UPD4991A::write_to_cur_time()
110 {
111         cur_time.second = regs[0][0] + (regs[0][1] & 7) * 10;
112         cur_time.minute = regs[0][2] + (regs[0][3] & 7) * 10;
113         if(MODE_12H) {
114                 cur_time.hour = regs[0][4] + (regs[0][5] & 1) * 10 + (regs[0][5] & 4 ? 12 : 0);
115         } else {
116                 cur_time.hour = regs[0][4] + (regs[0][5] & 3) * 10;
117         }
118 //      cur_time.day_of_week = regs[0][6];
119         cur_time.day = regs[0][7] + (regs[0][8] & 3) * 10;
120         cur_time.month = regs[0][9] + (regs[0][10] & 1) * 10;
121         cur_time.year = regs[0][11] + regs[0][12] * 10;
122         cur_time.update_year();
123         cur_time.update_day_of_week();
124         
125         // restart event
126         cancel_event(this, register_id);
127         register_event(this, 0, 1000000.0, true, &register_id);
128 }
129
130 #define STATE_VERSION   1
131
132 bool UPD4991A::process_state(FILEIO* state_fio, bool loading)
133 {
134         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
135                 return false;
136         }
137         if(!state_fio->StateCheckInt32(this_device_id)) {
138                 return false;
139         }
140         if(!cur_time.process_state((void *)state_fio, loading)) {
141                 return false;
142         }
143         state_fio->StateValue(register_id);
144         state_fio->StateArray(&regs[0][0], sizeof(regs), 1);
145         state_fio->StateValue(ctrl1);
146         state_fio->StateValue(ctrl2);
147         state_fio->StateValue(mode);
148         return true;
149 }
150