2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 void I8253::initialize()
15 __HAS_I8254 = osd->check_feature(_T("HAS_I8254"));
16 for(int ch = 0; ch < 3; ch++) {
17 counter[ch].prev_out = true;
18 counter[ch].prev_in = false;
19 counter[ch].gate = true;
20 counter[ch].count = 0x10000;
21 counter[ch].count_reg = 0;
22 counter[ch].ctrl_reg = 0x34;
24 counter[ch].count_latched = false;
25 counter[ch].low_read = counter[ch].high_read = false;
26 counter[ch].low_write = counter[ch].high_write = false;
27 counter[ch].delay = false;
28 counter[ch].start = false;
31 // 8254 read-back command
32 counter[ch].null_count = true;
33 counter[ch].status_latched = false;
41 for(int ch = 0; ch < 3; ch++) {
42 counter[ch].register_id = -1;
46 #define COUNT_VALUE(n) ((counter[n].count_reg == 0) ? 0x10000 : (counter[n].mode == 3 && counter[n].count_reg == 1) ? 0x10001 : counter[n].count_reg)
48 void I8253::write_io8(uint32_t addr, uint32_t data)
56 // write count register
57 if(!counter[ch].low_write && !counter[ch].high_write) {
58 if(counter[ch].ctrl_reg & 0x10) {
59 counter[ch].low_write = true;
61 if(counter[ch].ctrl_reg & 0x20) {
62 counter[ch].high_write = true;
65 if(counter[ch].low_write) {
66 counter[ch].count_reg = data;
67 counter[ch].low_write = false;
68 } else if(counter[ch].high_write) {
69 if((counter[ch].ctrl_reg & 0x30) == 0x20) {
70 counter[ch].count_reg = data << 8;
72 counter[ch].count_reg |= data << 8;
74 counter[ch].high_write = false;
77 if(__HAS_I8254) counter[ch].null_count = true;
80 if(counter[ch].mode == 0) {
81 set_signal(ch, false);
86 if(counter[ch].mode == 0 || counter[ch].mode == 4) {
87 // restart with new count
89 counter[ch].delay = true;
91 } else if(counter[ch].mode == 2 || counter[ch].mode == 3) {
92 // start with new counter after the current count is finished
93 if(!counter[ch].start) {
94 counter[ch].delay = true;
101 if((data & 0xc0) == 0xc0) {
104 // i8254 read-back command
105 for(ch = 0; ch < 3; ch++) {
106 uint8_t bit = 2 << ch;
107 if(!(data & 0x10) && !counter[ch].status_latched) {
108 counter[ch].status = counter[ch].ctrl_reg & 0x3f;
109 if(counter[ch].prev_out) {
110 counter[ch].status |= 0x80;
112 if(counter[ch].null_count) {
113 counter[ch].status |= 0x40;
115 counter[ch].status_latched = true;
117 if(!(data & 0x20) && !counter[ch].count_latched) {
125 ch = (data >> 6) & 3;
128 static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
129 // int prev = counter[ch].mode;
130 counter[ch].mode = modes[(data >> 1) & 7];
131 counter[ch].count_latched = false;
132 counter[ch].low_read = counter[ch].high_read = false;
133 counter[ch].low_write = counter[ch].high_write = false;
134 counter[ch].ctrl_reg = data;
136 if(counter[ch].mode == 0) {
137 set_signal(ch, false);
139 set_signal(ch, true);
142 // if(counter[ch].mode != prev || counter[ch].mode == 0 || counter[ch].mode == 4) {
144 counter[ch].count_reg = 0;
147 if(__HAS_I8254) counter[ch].null_count = true;
149 } else if(!counter[ch].count_latched) {
156 uint32_t I8253::read_io8(uint32_t addr)
166 if(counter[ch].status_latched) {
167 counter[ch].status_latched = false;
168 return counter[ch].status;
172 // if not latched, through current count
173 if(!counter[ch].count_latched) {
174 if(!counter[ch].low_read && !counter[ch].high_read) {
178 // return latched count
179 if(counter[ch].low_read) {
180 counter[ch].low_read = false;
181 if(!counter[ch].high_read) {
182 counter[ch].count_latched = false;
184 return counter[ch].latch & 0xff;
185 } else if(counter[ch].high_read) {
186 counter[ch].high_read = false;
187 counter[ch].count_latched = false;
188 return (counter[ch].latch >> 8) & 0xff;
194 void I8253::event_callback(int event_id, int err)
197 counter[ch].register_id = -1;
198 input_clock(ch, counter[ch].input_clk);
200 // register next event
201 if(counter[ch].freq && counter[ch].start) {
202 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
203 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq + err);
204 counter[ch].prev_clk = get_current_clock() + err;
205 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
209 void I8253::write_signal(int id, uint32_t data, uint32_t mask)
211 bool next = ((data & mask) != 0);
214 case SIG_I8253_CLOCK_0:
215 if(counter[0].prev_in && !next) {
218 counter[0].prev_in = next;
220 case SIG_I8253_CLOCK_1:
221 if(counter[1].prev_in && !next) {
224 counter[1].prev_in = next;
226 case SIG_I8253_CLOCK_2:
227 if(counter[2].prev_in && !next) {
230 counter[2].prev_in = next;
232 case SIG_I8253_GATE_0:
235 case SIG_I8253_GATE_1:
238 case SIG_I8253_GATE_2:
244 void I8253::input_clock(int ch, int clock)
246 if(!(counter[ch].start && clock)) {
249 if(counter[ch].delay) {
251 counter[ch].delay = false;
252 counter[ch].count = COUNT_VALUE(ch);
254 if(__HAS_I8254) counter[ch].null_count = false;
259 counter[ch].count -= clock;
260 int32_t tmp = COUNT_VALUE(ch);
262 if(counter[ch].mode == 3) {
263 int32_t half = tmp >> 1;
264 set_signal(ch, counter[ch].count > half);
266 if(counter[ch].count <= 1) {
267 if(counter[ch].mode == 2 || counter[ch].mode == 4 || counter[ch].mode == 5) {
268 set_signal(ch, false);
271 if(counter[ch].count <= 0) {
272 set_signal(ch, true);
275 if(counter[ch].count <= 0) {
276 if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) {
277 counter[ch].count += tmp;
279 if(__HAS_I8254) counter[ch].null_count = false;
283 counter[ch].start = false;
284 counter[ch].count = 0x10000;
289 void I8253::input_gate(int ch, bool signal)
291 bool prev = counter[ch].gate;
292 counter[ch].gate = signal;
294 if(prev && !signal) {
296 if(!(counter[ch].mode == 1 || counter[ch].mode == 5)) {
300 if(counter[ch].mode == 2 || counter[ch].mode == 3) {
301 set_signal(ch, true);
303 } else if(!prev && signal) {
306 if(!(counter[ch].mode == 0 || counter[ch].mode == 4)) {
307 counter[ch].delay = true;
311 if(counter[ch].mode == 1) {
312 set_signal(ch, false);
317 void I8253::start_count(int ch)
319 if(counter[ch].low_write || counter[ch].high_write) {
322 if(!counter[ch].gate) {
325 counter[ch].start = true;
328 if(counter[ch].freq) {
329 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
330 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq);
331 counter[ch].prev_clk = get_current_clock();
332 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
336 void I8253::stop_count(int ch)
338 counter[ch].start = false;
341 if(counter[ch].register_id != -1) {
342 cancel_event(this, counter[ch].register_id);
344 counter[ch].register_id = -1;
347 void I8253::latch_count(int ch)
349 if(counter[ch].register_id != -1) {
351 int passed = get_passed_clock(counter[ch].prev_clk);
352 uint32_t input = (uint32_t)(counter[ch].freq * passed / cpu_clocks);
354 bool expired = (counter[ch].input_clk <= input);
355 input_clock(ch, input);
356 // cancel and re-register event
358 cancel_event(this, counter[ch].register_id);
359 if(counter[ch].freq && counter[ch].start) {
360 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
361 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq);
362 counter[ch].prev_clk = get_current_clock();
363 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
366 cancel_event(this, counter[ch].register_id);
367 counter[ch].input_clk -= input;
368 counter[ch].period -= passed;
369 counter[ch].prev_clk = get_current_clock();
370 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
375 counter[ch].latch = (uint16_t)counter[ch].count;
376 counter[ch].count_latched = true;
377 if((counter[ch].ctrl_reg & 0x30) == 0x10) {
379 counter[ch].low_read = true;
380 counter[ch].high_read = false;
381 } else if((counter[ch].ctrl_reg & 0x30) == 0x20) {
383 counter[ch].low_read = false;
384 counter[ch].high_read = true;
387 counter[ch].low_read = counter[ch].high_read = true;
391 void I8253::set_signal(int ch, bool signal)
393 bool prev = counter[ch].prev_out;
394 counter[ch].prev_out = signal;
396 if(prev && !signal) {
398 write_signals(&counter[ch].outputs, 0);
399 } else if(!prev && signal) {
401 write_signals(&counter[ch].outputs, 0xffffffff);
405 int I8253::get_next_count(int ch)
407 if(counter[ch].mode == 2 || counter[ch].mode == 4 || counter[ch].mode == 5) {
408 return (counter[ch].count > 1) ? counter[ch].count - 1 : 1;
410 if(counter[ch].mode == 3) {
411 int32_t half = COUNT_VALUE(ch) >> 1;
412 return (counter[ch].count > half) ? counter[ch].count - half : counter[ch].count;
414 return counter[ch].count;
417 #define STATE_VERSION 1
419 bool I8253::process_state(FILEIO* state_fio, bool loading)
421 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
424 if(!state_fio->StateCheckInt32(this_device_id)) {
427 for(int i = 0; i < 3; i++) {
428 state_fio->StateBool(counter[i].prev_out);
429 state_fio->StateBool(counter[i].prev_in);
430 state_fio->StateBool(counter[i].gate);
431 state_fio->StateInt32(counter[i].count);
432 state_fio->StateUint16(counter[i].latch);
433 state_fio->StateUint16(counter[i].count_reg);
434 state_fio->StateUint8(counter[i].ctrl_reg);
435 state_fio->StateBool(counter[i].count_latched);
436 state_fio->StateBool(counter[i].low_read);
437 state_fio->StateBool(counter[i].high_read);
438 state_fio->StateBool(counter[i].low_write);
439 state_fio->StateBool(counter[i].high_write);
440 state_fio->StateInt32(counter[i].mode);
441 state_fio->StateBool(counter[i].delay);
442 state_fio->StateBool(counter[i].start);
444 state_fio->StateBool(counter[i].null_count);
445 state_fio->StateBool(counter[i].status_latched);
446 state_fio->StateUint8(counter[i].status);
448 state_fio->StateUint64(counter[i].freq);
449 state_fio->StateInt32(counter[i].register_id);
450 state_fio->StateUint32(counter[i].input_clk);
451 state_fio->StateInt32(counter[i].period);
452 state_fio->StateUint32(counter[i].prev_clk);
454 state_fio->StateUint64(cpu_clocks);