Split PIT timer from the counter CLOCK input handling, exposed a function to set a counter's CLOCK input, and implemented BCD mode.

This commit is contained in:
OBattler
2020-01-17 06:36:15 +01:00
parent 7bef50b782
commit 0f7699d037
2 changed files with 104 additions and 42 deletions

133
src/pit.c
View File

@@ -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);
}

View File

@@ -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, <mgrca8@gmail.com>
* 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));