From 0f7699d0370df22af68435fff3e221aff7cec783 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 17 Jan 2020 06:36:15 +0100 Subject: [PATCH] Split PIT timer from the counter CLOCK input handling, exposed a function to set a counter's CLOCK input, and implemented BCD mode. --- src/pit.c | 133 ++++++++++++++++++++++++++++++++++++++---------------- src/pit.h | 13 ++++-- 2 files changed, 104 insertions(+), 42 deletions(-) diff --git a/src/pit.c b/src/pit.c index 3fe4fb1dd..eaab7a4e3 100644 --- a/src/pit.c +++ b/src/pit.c @@ -57,8 +57,9 @@ int io_delay = 5; int64_t firsttime = 1; -#define PIT_PS2 16 -#define PIT_EXT_IO 32 +#define PIT_PS2 16 /* The PIT is the PS/2's second PIT. */ +#define PIT_EXT_IO 32 /* The PIT has externally specified port I/O. */ +#define PIT_CUSTOM_CLOCK 64 /* The PIT uses custom clock inputs provided by another provider. */ enum { @@ -99,6 +100,55 @@ ctr_set_out(ctr_t *ctr, int out) } +static void +ctr_decrease_count(ctr_t *ctr) +{ + uint8_t units, tens, hundreds, thousands, myriads; + int dec_cnt = 1; + + if (ctr->ctrl & 0x01) { + units = ctr->count & 0x0f; + tens = (ctr->count >> 4) & 0x0f; + hundreds = (ctr->count >> 8) & 0x0f; + thousands = (ctr->count >> 12) & 0x0f; + myriads = (ctr->count >> 16) & 0x0f; + + dec_cnt -= units; + units = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; /* The +9 is so we get a carry if dec_cnt % 10 was not a 0. */ + if (dec_cnt <= tens) + tens -= dec_cnt; + else { + dec_cnt -= tens; + tens = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; + if (dec_cnt <= hundreds) + hundreds -= dec_cnt; + else { + dec_cnt -= hundreds; + hundreds = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; + if (dec_cnt <= thousands) + thousands -= dec_cnt; + else { + dec_cnt -= thousands; + thousands = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; + myriads = (10 + myriads - dec_cnt % 10) % 10; + } + } + } + + ctr->count = (myriads << 16) | (thousands << 12) | (hundreds << 8) | (tens << 4) | units; + } else + ctr->count = (ctr->count - 1) & 0xffff; +} + + static void ctr_load_count(ctr_t *ctr) { @@ -124,7 +174,7 @@ ctr_tick(ctr_t *ctr) break; case 2: if (ctr->gate && (ctr->count >= 1)) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 1) { ctr->state = 3; ctr_set_out(ctr, 1); @@ -132,7 +182,7 @@ ctr_tick(ctr_t *ctr) } break; case 3: - ctr->count = (ctr->count - 1) & 0xffff; + ctr_decrease_count(ctr); break; } break; @@ -146,7 +196,7 @@ ctr_tick(ctr_t *ctr) break; case 2: if (ctr->count >= 1) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 1) { ctr->state = 3; ctr_set_out(ctr, 1); @@ -154,7 +204,7 @@ ctr_tick(ctr_t *ctr) } break; case 3: - ctr->count = (ctr->count - 1) & 0xffff; + ctr_decrease_count(ctr); break; } break; @@ -171,7 +221,7 @@ ctr_tick(ctr_t *ctr) if (ctr->gate == 0) break; else if (ctr->count >= 2) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 2) { ctr->state = 3; ctr_set_out(ctr, 0); @@ -221,7 +271,7 @@ ctr_tick(ctr_t *ctr) if ((ctr->gate != 0) || (ctr->m != 4)) { switch(ctr->state) { case 0: - ctr->count--; + ctr_decrease_count(ctr); break; case 1: ctr_load_count(ctr); @@ -229,7 +279,7 @@ ctr_tick(ctr_t *ctr) break; case 2: if (ctr->count >= 1) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 1) { ctr->state = 3; ctr_set_out(ctr, 0); @@ -406,6 +456,38 @@ pit_ctr_set_gate(ctr_t *ctr, int gate) } +void +pit_ctr_set_clock(ctr_t *ctr, int clock) +{ + int old = ctr->clock; + + ctr->clock = clock; + + if (ctr->using_timer && ctr->latch) { + if (old && !ctr->clock) { + ctr_set_state_1(ctr); + ctr->latch = 0; + } + } else if (ctr->using_timer && !ctr->latch) { + if (ctr->state == 1) { + if (!old && ctr->clock) + ctr->s1_det = 1; /* Rising edge. */ + else if (old && !ctr->clock) { + ctr->s1_det++; /* Falling edge. */ + if (ctr->s1_det != 2) + ctr->s1_det = 0; + } + + if (ctr->s1_det == 2) { + ctr->s1_det = 0; + ctr_tick(ctr); + } + } else if (old && !ctr->clock) + ctr_tick(ctr); + } +} + + void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer) { @@ -420,38 +502,11 @@ pit_timer_over(void *p) { pit_t *dev = (pit_t *) p; int i; - ctr_t *ctr; - int old; - old = dev->clock; dev->clock ^= 1; - for (i = 0; i < 3; i++) { - ctr = &dev->counters[i]; - - if (ctr->using_timer && ctr->latch) { - if (old && !dev->clock) { - ctr_set_state_1(ctr); - ctr->latch = 0; - } - } else if (ctr->using_timer && !ctr->latch) { - if (ctr->state == 1) { - if (!old && dev->clock) - ctr->s1_det = 1; /* Rising edge. */ - else if (old && !dev->clock) { - ctr->s1_det++; /* Falling edge. */ - if (ctr->s1_det != 2) - ctr->s1_det = 0; - } - - if (ctr->s1_det == 2) { - ctr->s1_det = 0; - ctr_tick(ctr); - } - } else if (old && !dev->clock) - ctr_tick(ctr); - } - } + for (i = 0; i < 3; i++) + pit_ctr_set_clock(&dev->counters[i], dev->clock); timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL); } @@ -780,7 +835,7 @@ pit_init(const device_t *info) pit_t *dev = (pit_t *) malloc(sizeof(pit_t)); pit_reset(dev); - if (!(dev->flags & PIT_PS2)) { + if (!(dev->flags & PIT_PS2) && !(dev->flags & PIT_CUSTOM_CLOCK)) { timer_add(&dev->callback_timer, pit_timer_over, (void *) dev, 0); timer_set_delay_u64(&dev->callback_timer, PITCONST >> 1ULL); } diff --git a/src/pit.h b/src/pit.h index e0a4a42ff..f019327a6 100644 --- a/src/pit.h +++ b/src/pit.h @@ -9,10 +9,10 @@ * Header of the implementation of the Intel 8253/8254 * Programmable Interval Timer. * - * Version: @(#)pit.h 1.0.0 2019/12/02 + * Version: @(#)pit.h 1.0.1 2020/01/17 * * Author: Miran Grca, - * Copyright 2019 Miran Grca. + * Copyright 2019,2020 Miran Grca. */ #ifndef EMU_PIT_H # define EMU_PIT_H @@ -27,7 +27,7 @@ typedef struct { int rm, wm, gate, out, newcount, count, using_timer, latched, - state, null_count, do_read_status, pad1; + state, null_count, do_read_status, clock; uint32_t l; @@ -60,10 +60,17 @@ extern uint64_t PITCONST, ISACONST, RTCCONST; +/* Gets a counter's count. */ extern uint16_t pit_ctr_get_count(ctr_t *ctr); +/* Sets a counter's load count handler. */ extern void pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count)); +/* Sets a counter's OUT output handler. */ extern void pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out)); +/* Sets a counter's GATE input. */ extern void pit_ctr_set_gate(ctr_t *ctr, int gate); +/* Sets a counter's CLOCK input. */ +extern void pit_ctr_set_clock(ctr_t *ctr, int clock); +/* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */ extern void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer); extern pit_t * pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out));