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:
133
src/pit.c
133
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);
|
||||
}
|
||||
|
13
src/pit.h
13
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, <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));
|
||||
|
Reference in New Issue
Block a user