2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 void I8253::initialize()
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;
30 // 8254 read-back command
31 counter[ch].null_count = true;
32 counter[ch].status_latched = false;
39 for(int ch = 0; ch < 3; ch++) {
40 counter[ch].register_id = -1;
44 #define COUNT_VALUE(n) ((counter[n].count_reg == 0) ? 0x10000 : (counter[n].mode == 3 && counter[n].count_reg == 1) ? 0x10001 : counter[n].count_reg)
46 void I8253::write_io8(uint32_t addr, uint32_t data)
54 // write count register
55 if(!counter[ch].low_write && !counter[ch].high_write) {
56 if(counter[ch].ctrl_reg & 0x10) {
57 counter[ch].low_write = true;
59 if(counter[ch].ctrl_reg & 0x20) {
60 counter[ch].high_write = true;
63 if(counter[ch].low_write) {
64 counter[ch].count_reg = data;
65 counter[ch].low_write = false;
66 } else if(counter[ch].high_write) {
67 if((counter[ch].ctrl_reg & 0x30) == 0x20) {
68 counter[ch].count_reg = data << 8;
70 counter[ch].count_reg |= data << 8;
72 counter[ch].high_write = false;
75 counter[ch].null_count = true;
78 if(counter[ch].mode == 0) {
79 set_signal(ch, false);
84 if(counter[ch].mode == 0 || counter[ch].mode == 4) {
85 // restart with new count
87 counter[ch].delay = true;
89 } else if(counter[ch].mode == 2 || counter[ch].mode == 3) {
90 // start with new counter after the current count is finished
91 if(!counter[ch].start) {
92 counter[ch].delay = true;
99 if((data & 0xc0) == 0xc0) {
101 // i8254 read-back command
102 if(device_model == INTEL_8254) {
103 for(ch = 0; ch < 3; ch++) {
104 uint8_t bit = 2 << ch;
105 if(!(data & 0x10) && !counter[ch].status_latched) {
106 counter[ch].status = counter[ch].ctrl_reg & 0x3f;
107 if(counter[ch].prev_out) {
108 counter[ch].status |= 0x80;
110 if(counter[ch].null_count) {
111 counter[ch].status |= 0x40;
113 counter[ch].status_latched = true;
115 if(!(data & 0x20) && !counter[ch].count_latched) {
123 ch = (data >> 6) & 3;
126 static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
127 // int prev = counter[ch].mode;
128 counter[ch].mode = modes[(data >> 1) & 7];
129 counter[ch].count_latched = false;
130 counter[ch].low_read = counter[ch].high_read = false;
131 counter[ch].low_write = counter[ch].high_write = false;
132 counter[ch].ctrl_reg = data;
134 if(counter[ch].mode == 0) {
135 set_signal(ch, false);
137 set_signal(ch, true);
140 // if(counter[ch].mode != prev || counter[ch].mode == 0 || counter[ch].mode == 4) {
142 counter[ch].count_reg = 0;
145 counter[ch].null_count = true;
147 } else if(!counter[ch].count_latched) {
154 uint32_t I8253::read_io8(uint32_t addr)
163 if(device_model == INTEL_8254) {
164 if(counter[ch].status_latched) {
165 counter[ch].status_latched = false;
166 return counter[ch].status;
170 // if not latched, through current count
171 if(!counter[ch].count_latched) {
172 if(!counter[ch].low_read && !counter[ch].high_read) {
176 // return latched count
177 if(counter[ch].low_read) {
178 counter[ch].low_read = false;
179 if(!counter[ch].high_read) {
180 counter[ch].count_latched = false;
182 return counter[ch].latch & 0xff;
183 } else if(counter[ch].high_read) {
184 counter[ch].high_read = false;
185 counter[ch].count_latched = false;
186 return (counter[ch].latch >> 8) & 0xff;
192 void I8253::event_callback(int event_id, int err)
195 counter[ch].register_id = -1;
196 input_clock(ch, counter[ch].input_clk);
198 // register next event
199 if(counter[ch].freq && counter[ch].start) {
200 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
201 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq + err);
202 counter[ch].prev_clk = get_current_clock() + err;
203 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
207 void I8253::write_signal(int id, uint32_t data, uint32_t mask)
209 bool next = ((data & mask) != 0);
212 case SIG_I8253_CLOCK_0:
213 if(counter[0].prev_in && !next) {
216 counter[0].prev_in = next;
218 case SIG_I8253_CLOCK_1:
219 if(counter[1].prev_in && !next) {
222 counter[1].prev_in = next;
224 case SIG_I8253_CLOCK_2:
225 if(counter[2].prev_in && !next) {
228 counter[2].prev_in = next;
230 case SIG_I8253_GATE_0:
233 case SIG_I8253_GATE_1:
236 case SIG_I8253_GATE_2:
242 void I8253::input_clock(int ch, int clock)
244 if(!(counter[ch].start && clock)) {
247 if(counter[ch].delay) {
249 counter[ch].delay = false;
250 counter[ch].count = COUNT_VALUE(ch);
252 counter[ch].null_count = false;
257 counter[ch].count -= clock;
258 int32_t tmp = COUNT_VALUE(ch);
260 if(counter[ch].mode == 3) {
261 int32_t half = tmp >> 1;
262 set_signal(ch, counter[ch].count > half);
264 if(counter[ch].count <= 1) {
265 if(counter[ch].mode == 2 || counter[ch].mode == 4 || counter[ch].mode == 5) {
266 set_signal(ch, false);
269 if(counter[ch].count <= 0) {
270 set_signal(ch, true);
273 if(counter[ch].count <= 0) {
274 if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) {
275 counter[ch].count += tmp;
277 counter[ch].null_count = false;
281 counter[ch].start = false;
282 counter[ch].count = 0x10000;
287 void I8253::input_gate(int ch, bool signal)
289 bool prev = counter[ch].gate;
290 counter[ch].gate = signal;
292 if(prev && !signal) {
294 if(!(counter[ch].mode == 1 || counter[ch].mode == 5)) {
298 if(counter[ch].mode == 2 || counter[ch].mode == 3) {
299 set_signal(ch, true);
301 } else if(!prev && signal) {
304 if(!(counter[ch].mode == 0 || counter[ch].mode == 4)) {
305 counter[ch].delay = true;
309 if(counter[ch].mode == 1) {
310 set_signal(ch, false);
315 void I8253::start_count(int ch)
317 if(counter[ch].low_write || counter[ch].high_write) {
320 if(!counter[ch].gate) {
323 counter[ch].start = true;
326 if(counter[ch].freq) {
327 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
328 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq);
329 counter[ch].prev_clk = get_current_clock();
330 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
334 void I8253::stop_count(int ch)
336 counter[ch].start = false;
339 if(counter[ch].register_id != -1) {
340 cancel_event(this, counter[ch].register_id);
342 counter[ch].register_id = -1;
345 void I8253::latch_count(int ch)
347 if(counter[ch].register_id != -1) {
349 int passed = get_passed_clock(counter[ch].prev_clk);
350 uint32_t input = (uint32_t)(counter[ch].freq * passed / cpu_clocks);
352 bool expired = (counter[ch].input_clk <= input);
353 input_clock(ch, input);
354 // cancel and re-register event
356 cancel_event(this, counter[ch].register_id);
357 if(counter[ch].freq && counter[ch].start) {
358 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
359 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq);
360 counter[ch].prev_clk = get_current_clock();
361 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
364 cancel_event(this, counter[ch].register_id);
365 counter[ch].input_clk -= input;
366 counter[ch].period -= passed;
367 counter[ch].prev_clk = get_current_clock();
368 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
373 counter[ch].latch = (uint16_t)counter[ch].count;
374 counter[ch].count_latched = true;
375 if((counter[ch].ctrl_reg & 0x30) == 0x10) {
377 counter[ch].low_read = true;
378 counter[ch].high_read = false;
379 } else if((counter[ch].ctrl_reg & 0x30) == 0x20) {
381 counter[ch].low_read = false;
382 counter[ch].high_read = true;
385 counter[ch].low_read = counter[ch].high_read = true;
389 void I8253::set_signal(int ch, bool signal)
391 bool prev = counter[ch].prev_out;
392 counter[ch].prev_out = signal;
394 if(prev && !signal) {
396 write_signals(&counter[ch].outputs, 0);
397 } else if(!prev && signal) {
399 write_signals(&counter[ch].outputs, 0xffffffff);
403 int I8253::get_next_count(int ch)
405 if(counter[ch].mode == 2 || counter[ch].mode == 4 || counter[ch].mode == 5) {
406 return (counter[ch].count > 1) ? counter[ch].count - 1 : 1;
408 if(counter[ch].mode == 3) {
409 int32_t half = COUNT_VALUE(ch) >> 1;
410 return (counter[ch].count > half) ? counter[ch].count - half : counter[ch].count;
412 return counter[ch].count;
415 bool I8253::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
417 _TCHAR regs1[3][1024];
418 for(int ch = 0; ch < 3; ch++) {
419 memset(regs1[ch], 0x00, sizeof(_TCHAR) * 1024);
420 my_sprintf_s(regs1[ch], 1024 -1,
422 _T("MODE=%d DELAY=%s START=%s ")
423 _T("CTRL=%02X COUNT_REG=%04X COUNT=%d ")
424 _T("GATE=%s PREV_IN=%s PREV_OUT=%s ")
427 ch, counter[ch].freq,
428 counter[ch].mode, (counter[ch].delay) ? _T("YES") : _T("NO "), (counter[ch].start) ? _T("YES") : _T("NO "),
429 counter[ch].ctrl_reg, counter[ch].count_reg, counter[ch].count,
430 (counter[ch].gate) ? _T("YES") : _T("NO "), (counter[ch].prev_in) ? _T("YES") : _T("NO "), (counter[ch].prev_out) ? _T("YES") : _T("NO "));
432 const _TCHAR *model = _T("i8253");
433 switch(device_model) {
440 my_sprintf_s(buffer, buffer_len, _T("TYPE=%s\n%s%s%s"),
442 regs1[0], regs1[1], regs1[2]
447 #define STATE_VERSION 2
449 bool I8253::process_state(FILEIO* state_fio, bool loading)
451 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
454 if(!state_fio->StateCheckInt32(this_device_id)) {
457 for(int i = 0; i < 3; i++) {
458 state_fio->StateValue(counter[i].prev_out);
459 state_fio->StateValue(counter[i].prev_in);
460 state_fio->StateValue(counter[i].gate);
461 state_fio->StateValue(counter[i].count);
462 state_fio->StateValue(counter[i].latch);
463 state_fio->StateValue(counter[i].count_reg);
464 state_fio->StateValue(counter[i].ctrl_reg);
465 state_fio->StateValue(counter[i].count_latched);
466 state_fio->StateValue(counter[i].low_read);
467 state_fio->StateValue(counter[i].high_read);
468 state_fio->StateValue(counter[i].low_write);
469 state_fio->StateValue(counter[i].high_write);
470 state_fio->StateValue(counter[i].mode);
471 state_fio->StateValue(counter[i].delay);
472 state_fio->StateValue(counter[i].start);
474 state_fio->StateValue(counter[i].null_count);
475 state_fio->StateValue(counter[i].status_latched);
476 state_fio->StateValue(counter[i].status);
478 state_fio->StateValue(counter[i].freq);
479 state_fio->StateValue(counter[i].register_id);
480 state_fio->StateValue(counter[i].input_clk);
481 state_fio->StateValue(counter[i].period);
482 state_fio->StateValue(counter[i].prev_clk);
484 state_fio->StateValue(cpu_clocks);