2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
10 #include "hd146818p.h"
16 static const int periodic_intr_rate[3][16] = {
17 {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384}, // 4.194304 MHz
18 {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384}, // 1.048576 MHz
19 {0, 128, 256, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384} // 32.768kHz
22 DLL_PREFIX_I struct cur_time_s cur_time;
25 void HD146818P::initialize()
29 memset(regs, 0, sizeof(regs));
32 // FIXME: we need to consider the multiple chips case
33 FILEIO* fio = new FILEIO();
34 if(fio->Fopen(create_local_path(_T("HD146818P.BIN")), FILEIO_READ_BINARY)) {
35 fio->Fread(regs + 14, 50, 1);
45 get_host_time(&cur_time);
49 register_event(this, EVENT_1SEC, 1000000, true, ®ister_id_1sec);
52 void HD146818P::release()
55 // FIXME: we need to consider the multiple chips case
56 FILEIO* fio = new FILEIO();
57 if(fio->Fopen(create_local_path(_T("HD146818P.BIN")), FILEIO_WRITE_BINARY)) {
58 fio->Fwrite(regs + 14, 50, 1);
65 void HD146818P::reset()
71 void HD146818P::write_io8(uint32_t addr, uint32_t data)
78 if(!(ch == 1 || ch == 3 || ch == 5)) {
85 } else if(ch == 0x0a) {
87 int dv = (data >> 4) & 7, next = 0;
89 next = periodic_intr_rate[dv][data & 0x0f];
92 if(register_id_sqw != -1) {
93 cancel_event(this, register_id_sqw);
97 // raise event twice per one period
98 register_event(this, EVENT_SQW, 1000000.0 / 65536.0 * next, true, ®ister_id_sqw);
102 regs[ch] = data & 0x7f; // always UIP=0
103 } else if(ch == 0x0b) {
104 if((regs[0x0b] & 8) && !(data & 8)) {
105 // keep sqw = L when sqwe = 0
106 write_signals(&outputs_sqw, 0);
108 bool tmp = (((regs[ch] ^ data) & 4) != 0);
111 read_from_cur_time();
115 } else if(ch > 0x0d) {
117 if(regs[ch] != data) {
125 uint32_t HD146818P::read_io8(uint32_t addr)
130 uint8_t val = regs[ch];
139 #define TO_BCD_BIN(v) ((regs[0x0b] & 4) ? (v) : TO_BCD(v))
140 #define FROM_BCD_BIN(v) ((regs[0x0b] & 4) ? (v) : FROM_BCD(v))
142 void HD146818P::event_callback(int event_id, int err)
144 if(event_id == EVENT_1SEC) {
145 if(cur_time.initialized) {
146 cur_time.increment();
148 get_host_time(&cur_time); // resync
149 cur_time.initialized = true;
151 read_from_cur_time();
152 regs[0x0c] |= 0x10; // updated
155 } else if(event_id == EVENT_SQW) {
156 // periodic interrupt
158 if(sqw) { // OK? 20180516 K.Ohta
164 // output sqw when sqwe = 1
165 write_signals(&outputs_sqw, sqw ? 0xffffffff : 0);
170 void HD146818P::read_from_cur_time()
172 int hour = (regs[0x0b] & 2) ? cur_time.hour : (cur_time.hour % 12);
173 int ampm = (regs[0x0b] & 2) ? 0 : (cur_time.hour > 11) ? 0x80 : 0;
175 regs[0] = TO_BCD_BIN(cur_time.second);
176 regs[2] = TO_BCD_BIN(cur_time.minute);
177 regs[4] = TO_BCD_BIN(hour) | ampm;
178 regs[6] = cur_time.day_of_week + 1;
179 regs[7] = TO_BCD_BIN(cur_time.day);
180 regs[8] = TO_BCD_BIN(cur_time.month);
181 regs[9] = TO_BCD_BIN(cur_time.year);
184 void HD146818P::write_to_cur_time()
186 cur_time.second = FROM_BCD_BIN(regs[0] & 0x7f);
187 cur_time.minute = FROM_BCD_BIN(regs[2] & 0x7f);
189 cur_time.hour = FROM_BCD_BIN(regs[4] & 0x3f);
191 cur_time.hour = FROM_BCD_BIN(regs[4] & 0x1f);
196 // cur_time.day_of_week = regs[6] - 1;
197 cur_time.day = FROM_BCD_BIN(regs[7]);
198 cur_time.month = FROM_BCD_BIN(regs[8]);
199 cur_time.year = FROM_BCD_BIN(regs[9]);
200 cur_time.update_year();
201 cur_time.update_day_of_week();
204 cancel_event(this, register_id_1sec);
205 register_event(this, EVENT_1SEC, 1000000, true, ®ister_id_1sec);
208 void HD146818P::check_alarm()
210 if(regs[0] == regs[1] && regs[2] == regs[3] && regs[4] == regs[5]) {
215 void HD146818P::update_intr()
217 bool next = ((regs[0x0b] & regs[0x0c] & 0x70) != 0);
219 write_signals(&outputs_intr, next ? 0xffffffff : 0);
224 #define STATE_VERSION 1
226 #include "../statesub.h"
228 void HD146818P::decl_state()
230 enter_decl_state(STATE_VERSION);
232 DECL_STATE_ENTRY_INT32(register_id_1sec);
233 DECL_STATE_ENTRY_1D_ARRAY(regs, sizeof(regs));
234 DECL_STATE_ENTRY_INT32(ch);
235 DECL_STATE_ENTRY_INT32(period);
236 DECL_STATE_ENTRY_INT32(register_id_sqw);
237 DECL_STATE_ENTRY_BOOL(intr);
238 DECL_STATE_ENTRY_BOOL(sqw);
239 DECL_STATE_ENTRY_BOOL(modified);
244 void HD146818P::save_state(FILEIO* state_fio)
246 //state_fio->FputUint32(STATE_VERSION);
247 //state_fio->FputInt32(this_device_id);
249 if(state_entry != NULL) {
250 state_entry->save_state(state_fio);
252 cur_time.save_state((void *)state_fio);
253 //state_fio->FputInt32(register_id_1sec);
254 //state_fio->Fwrite(regs, sizeof(regs), 1);
255 //state_fio->FputInt32(ch);
256 //state_fio->FputInt32(period);
257 //state_fio->FputInt32(register_id_sqw);
258 //state_fio->FputBool(intr);
259 //state_fio->FputBool(sqw);
260 //state_fio->FputBool(modified);
263 bool HD146818P::load_state(FILEIO* state_fio)
266 if(state_entry != NULL) {
267 mb = state_entry->load_state(state_fio);
269 if(!mb) return false;
270 //if(state_fio->FgetUint32() != STATE_VERSION) {
273 //if(state_fio->FgetInt32() != this_device_id) {
276 if(!cur_time.load_state((void *)state_fio)) {
279 //register_id_1sec = state_fio->FgetInt32();
280 //state_fio->Fread(regs, sizeof(regs), 1);
281 //ch = state_fio->FgetInt32();
282 //period = state_fio->FgetInt32();
283 //register_id_sqw = state_fio->FgetInt32();
284 //intr = state_fio->FgetBool();
285 //sqw = state_fio->FgetBool();
286 //modified = state_fio->FgetBool();