Merge pull request #2501 from elyosh/pitfast
PIT: add alternative faster PIT
This commit is contained in:
@@ -182,6 +182,7 @@ int confirm_reset = 1; /* (C) enable reset confirmation */
|
||||
int confirm_exit = 1; /* (C) enable exit confirmation */
|
||||
int confirm_save = 1; /* (C) enable save confirmation */
|
||||
int enable_discord = 0; /* (C) enable Discord integration */
|
||||
int pit_mode = -1; /* (C) force setting PIT mode */
|
||||
|
||||
/* Statistics. */
|
||||
extern int mmuflush;
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#
|
||||
|
||||
add_executable(86Box 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c
|
||||
dma.c ddma.c discord.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c
|
||||
dma.c ddma.c discord.c nmi.c pic.c pit.c pit_fast.c port_6x.c port_92.c ppi.c pci.c
|
||||
mca.c usb.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c machine_status.c)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
|
@@ -886,6 +886,8 @@ load_machine(void)
|
||||
} else
|
||||
time_sync = !!config_get_int(cat, "enable_sync", 1);
|
||||
|
||||
pit_mode = config_get_int(cat, "pit_mode", -1);
|
||||
|
||||
/* Remove this after a while.. */
|
||||
config_delete_var(cat, "nvr_path");
|
||||
config_delete_var(cat, "enable_sync");
|
||||
@@ -2479,6 +2481,11 @@ save_machine(void)
|
||||
else
|
||||
config_set_string(cat, "time_sync", "disabled");
|
||||
|
||||
if (pit_mode == -1)
|
||||
config_delete_var(cat, "pit_mode");
|
||||
else
|
||||
config_set_int(cat, "pit_mode", pit_mode);
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
|
||||
|
@@ -535,7 +535,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
if (speaker_enable)
|
||||
was_speaker_enable = 1;
|
||||
pit_ctr_set_gate(&pit->counters[2], val & 1);
|
||||
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1);
|
||||
|
||||
if (val & 0x80) {
|
||||
kbd->pa = 0;
|
||||
|
@@ -135,6 +135,7 @@ extern int is_pentium; /* TODO: Move back to cpu/cpu.h when it's figured out,
|
||||
how to remove that hack from the ET4000/W32p. */
|
||||
extern int fixed_size_x, fixed_size_y;
|
||||
extern double mouse_sensitivity; /* (C) Mouse sensitivity scale */
|
||||
extern int pit_mode; /* (C) force setting PIT mode */
|
||||
|
||||
|
||||
extern char exe_path[2048]; /* path (dir) of executable */
|
||||
|
@@ -58,9 +58,33 @@ typedef struct PIT {
|
||||
uint8_t ctrl;
|
||||
} pit_t;
|
||||
|
||||
enum {
|
||||
PIT_8253 = 0,
|
||||
PIT_8254,
|
||||
PIT_8253_FAST,
|
||||
PIT_8254_FAST
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t (*read)(uint16_t addr, void *priv);
|
||||
void (*write)(uint16_t addr, uint8_t val, void *priv);
|
||||
/* Gets a counter's count. */
|
||||
uint16_t (*get_count)(void *data, int counter_id);
|
||||
/* Sets a counter's GATE input. */
|
||||
void (*set_gate)(void *data, int counter_id, int gate);
|
||||
/* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */
|
||||
void(*set_using_timer)(void *data, int counter_id, int using_timer);
|
||||
/* Sets a counter's OUT output handler. */
|
||||
void (*set_out_func)(void *data, int counter_id, void (*func)(int new_out, int old_out));
|
||||
/* Sets a counter's load count handler. */
|
||||
void (*set_load_func)(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count));
|
||||
void (*ctr_clock)(void *data, int counter_id);
|
||||
void *data;
|
||||
} pit_intf_t;
|
||||
|
||||
extern pit_intf_t pit_devs[2];
|
||||
extern const pit_intf_t pit_classic_intf;
|
||||
|
||||
extern pit_t *pit,
|
||||
*pit2;
|
||||
|
||||
extern double SYSCLK, PCICLK, AGPCLK;
|
||||
|
||||
@@ -74,26 +98,13 @@ extern uint64_t PITCONST, ISACONST,
|
||||
|
||||
extern int refresh_at_enable;
|
||||
|
||||
|
||||
/* 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));
|
||||
extern pit_t * pit_ps2_init(void);
|
||||
extern pit_t * pit_ps2_init(int type);
|
||||
extern void pit_reset(pit_t *dev);
|
||||
|
||||
extern void pit_irq0_timer(int new_out, int old_out);
|
||||
extern void pit_irq0_timer_pcjr(int new_out, int old_out);
|
||||
extern void pit_irq0_timer_ps2(int new_out, int old_out);
|
||||
|
||||
extern void pit_refresh_timer_xt(int new_out, int old_out);
|
||||
|
72
src/include/86box/pit_fast.h
Normal file
72
src/include/86box/pit_fast.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Header of the implementation of the Intel 8253/8254
|
||||
* Programmable Interval Timer.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2019,2020 Miran Grca.
|
||||
*/
|
||||
|
||||
#ifndef EMU_PIT_FAST_H
|
||||
#define EMU_PIT_FAST_H
|
||||
|
||||
typedef struct {
|
||||
uint8_t m, ctrl,
|
||||
read_status, latch, bcd;
|
||||
|
||||
uint16_t rl;
|
||||
|
||||
int rm, wm, gate, out,
|
||||
newcount, clock, using_timer, latched,
|
||||
do_read_status;
|
||||
int enabled;
|
||||
int disabled;
|
||||
int initial;
|
||||
int thit;
|
||||
int running;
|
||||
int rereadlatch;
|
||||
|
||||
union {
|
||||
int count;
|
||||
struct {
|
||||
int units : 4;
|
||||
int tens : 4;
|
||||
int hundreds : 4;
|
||||
int thousands : 4;
|
||||
int myriads : 4;
|
||||
};
|
||||
};
|
||||
|
||||
uint32_t l;
|
||||
pc_timer_t timer;
|
||||
|
||||
void (*load_func)(uint8_t new_m, int new_count);
|
||||
void (*out_func)(int new_out, int old_out);
|
||||
} ctrf_t;
|
||||
|
||||
typedef struct {
|
||||
int flags;
|
||||
ctrf_t counters[3];
|
||||
|
||||
uint8_t ctrl;
|
||||
} pitf_t;
|
||||
|
||||
extern const pit_intf_t pit_fast_intf;
|
||||
|
||||
#ifdef EMU_DEVICE_H
|
||||
extern const device_t i8253_fast_device;
|
||||
extern const device_t i8254_fast_device;
|
||||
extern const device_t i8254_sec_fast_device;
|
||||
extern const device_t i8254_ext_io_fast_device;
|
||||
extern const device_t i8254_ps2_fast_device;
|
||||
#endif
|
||||
|
||||
#endif /*EMU_PIT_FAST_H*/
|
@@ -2059,7 +2059,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
|
||||
speaker_enable = val & 0x02;
|
||||
if (speaker_enable)
|
||||
was_speaker_enable = 1;
|
||||
pit_ctr_set_gate(&pit->counters[2], val & 0x01);
|
||||
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 0x01);
|
||||
|
||||
if (val & 0x80) {
|
||||
/* Keyboard enabled, so enable PA reading. */
|
||||
|
@@ -66,7 +66,7 @@ machine_at_common_init_ex(const machine_t *model, int type)
|
||||
machine_common_init(model);
|
||||
|
||||
refresh_at_enable = 1;
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_at);
|
||||
pic2_init();
|
||||
dma16_init();
|
||||
|
||||
|
@@ -718,7 +718,7 @@ machine_europc_init(const machine_t *model)
|
||||
return ret;
|
||||
|
||||
machine_common_init(model);
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
nmi_init();
|
||||
|
||||
|
@@ -627,7 +627,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
|
||||
speaker_enable = val & 2;
|
||||
if (speaker_enable)
|
||||
was_speaker_enable = 1;
|
||||
pit_ctr_set_gate(&pit->counters[2], val & 1);
|
||||
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1);
|
||||
sn76489_mute = speaker_mute = 1;
|
||||
switch (val & 0x60) {
|
||||
case 0x00:
|
||||
@@ -642,7 +642,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
case 0xa0:
|
||||
nmi_mask = val & 0x80;
|
||||
pit_ctr_set_using_timer(&pit->counters[1], !(val & 0x20));
|
||||
pit_devs[0].set_using_timer(pit_devs[0].data, 1, !(val & 0x20));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -770,6 +770,18 @@ speed_changed(void *priv)
|
||||
recalc_timings(pcjr);
|
||||
}
|
||||
|
||||
void
|
||||
pit_irq0_timer_pcjr(int new_out, int old_out)
|
||||
{
|
||||
if (new_out && !old_out) {
|
||||
picint(1);
|
||||
pit_devs[0].ctr_clock(pit_devs[0].data, 1);
|
||||
}
|
||||
|
||||
if (!new_out)
|
||||
picintc(1);
|
||||
}
|
||||
|
||||
static const device_config_t pcjr_config[] = {
|
||||
{
|
||||
.name = "display_type",
|
||||
|
@@ -327,7 +327,7 @@ ps1_common_init(const machine_t *model)
|
||||
machine_common_init(model);
|
||||
|
||||
refresh_at_enable = 1;
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_at);
|
||||
|
||||
dma16_init();
|
||||
pic2_init();
|
||||
|
@@ -190,7 +190,7 @@ ps2_isa_common_init(const machine_t *model)
|
||||
machine_common_init(model);
|
||||
|
||||
refresh_at_enable = 1;
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_at);
|
||||
|
||||
dma16_init();
|
||||
pic2_init();
|
||||
|
@@ -1363,7 +1363,8 @@ machine_ps2_common_init(const machine_t *model)
|
||||
device_add(&ps_no_nmi_nvr_device);
|
||||
pic2_init();
|
||||
|
||||
pit_ps2_init();
|
||||
int pit_type = ((pit_mode == -1 && is486) || pit_mode == 1) ? PIT_8254_FAST : PIT_8254;
|
||||
pit_ps2_init(pit_type);
|
||||
|
||||
nmi_mask = 0x80;
|
||||
|
||||
|
@@ -24,7 +24,7 @@ machine_xt_common_init(const machine_t *model)
|
||||
{
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
device_add(&fdc_xt_device);
|
||||
|
@@ -50,7 +50,7 @@ machine_xt_compaq_deskpro_init(const machine_t *model)
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
device_add(&keyboard_xt_compaq_device);
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
@@ -78,7 +78,7 @@ machine_xt_compaq_portable_init(const machine_t *model)
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
device_add(&keyboard_xt_compaq_device);
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
|
@@ -167,7 +167,7 @@ machine_xt_lxt3_init(const machine_t *model)
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
device_add(&keyboard_xt_lxt3_device);
|
||||
|
||||
|
@@ -241,7 +241,7 @@ m24_kbd_write(uint16_t port, uint8_t val, void *priv)
|
||||
speaker_enable = val & 2;
|
||||
if (speaker_enable)
|
||||
was_speaker_enable = 1;
|
||||
pit_ctr_set_gate(&pit->counters[2], val & 1);
|
||||
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -792,7 +792,7 @@ machine_xt_m240_init(const machine_t *model)
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
/* Address 66-67 = mainboard dip-switch settings */
|
||||
io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
@@ -846,7 +846,7 @@ machine_xt_m19_init(const machine_t *model)
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
/* On-board FDC cannot be disabled */
|
||||
device_add(&fdc_xt_device);
|
||||
|
@@ -152,7 +152,7 @@ machine_xt_philips_common_init(const machine_t *model)
|
||||
{
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
nmi_init();
|
||||
|
||||
|
@@ -911,7 +911,7 @@ machine_xt_t1000_init(const machine_t *model)
|
||||
|
||||
machine_common_init(model);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
device_add(&keyboard_xt_device);
|
||||
t1000.fdc = device_add(&fdc_xt_device);
|
||||
nmi_init();
|
||||
@@ -979,7 +979,7 @@ machine_xt_t1200_init(const machine_t *model)
|
||||
write_t1200_nvram, NULL, NULL,
|
||||
NULL, MEM_MAPPING_EXTERNAL, &t1000);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
device_add(&keyboard_xt_device);
|
||||
t1000.fdc = device_add(&fdc_xt_t1x00_device);
|
||||
nmi_init();
|
||||
|
@@ -122,7 +122,7 @@ machine_zenith_init(const machine_t *model){
|
||||
|
||||
device_add(&zenith_scratchpad_device);
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
|
||||
|
||||
device_add(&keyboard_xt_zenith_device);
|
||||
|
||||
|
@@ -161,6 +161,16 @@ machine_available(int m)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_irq0_timer(int new_out, int old_out)
|
||||
{
|
||||
if (new_out && !old_out)
|
||||
picint(1);
|
||||
|
||||
if (!new_out)
|
||||
picintc(1);
|
||||
}
|
||||
|
||||
void
|
||||
machine_common_init(const machine_t *model)
|
||||
{
|
||||
@@ -168,5 +178,10 @@ machine_common_init(const machine_t *model)
|
||||
pic_init();
|
||||
dma_init();
|
||||
|
||||
pit_common_init(!!IS_AT(machine), pit_irq0_timer, NULL);
|
||||
int pit_type = IS_AT(machine) ? PIT_8254 : PIT_8253;
|
||||
/* Select fast PIT if needed */
|
||||
if ((pit_mode == -1 && is486) || pit_mode == 1)
|
||||
pit_type += 2;
|
||||
|
||||
pit_common_init(pit_type, pit_irq0_timer, NULL);
|
||||
}
|
||||
|
@@ -750,8 +750,8 @@ picinterrupt()
|
||||
pic.interrupt |= 0x40; /* Mark slave pending. */
|
||||
}
|
||||
|
||||
if ((pic.interrupt == 0) && (pit2 != NULL))
|
||||
pit_ctr_set_gate(&pit2->counters[0], 0);
|
||||
if ((pic.interrupt == 0) && (pit_devs[1].data != NULL))
|
||||
pit_devs[1].set_gate(pit_devs[1].data, 0, 0);
|
||||
|
||||
/* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
168
src/pit.c
168
src/pit.c
@@ -34,14 +34,15 @@
|
||||
#include <86box/pic.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/pit.h>
|
||||
#include <86box/pit_fast.h>
|
||||
#include <86box/ppi.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/sound.h>
|
||||
#include <86box/snd_speaker.h>
|
||||
#include <86box/video.h>
|
||||
|
||||
pit_intf_t pit_devs[2];
|
||||
|
||||
pit_t *pit, *pit2;
|
||||
double cpuclock, PITCONSTD,
|
||||
SYSCLK,
|
||||
isa_timing,
|
||||
@@ -67,12 +68,6 @@ int64_t firsttime = 1;
|
||||
#define PIT_SECONDARY 128 /* The PIT is secondary (ports 0048-004B). */
|
||||
|
||||
|
||||
enum {
|
||||
PIT_8253 = 0,
|
||||
PIT_8254
|
||||
};
|
||||
|
||||
|
||||
#ifdef ENABLE_PIT_LOG
|
||||
int pit_do_log = ENABLE_PIT_LOG;
|
||||
|
||||
@@ -293,8 +288,11 @@ ctr_tick(ctr_t *ctr)
|
||||
|
||||
|
||||
static void
|
||||
ctr_clock(ctr_t *ctr)
|
||||
ctr_clock(void *data, int counter_id)
|
||||
{
|
||||
pit_t *pit = (pit_t *)data;
|
||||
ctr_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
/* FIXME: Is this even needed? */
|
||||
if ((ctr->state == 3) && (ctr->m != 2) && (ctr->m != 3))
|
||||
return;
|
||||
@@ -379,35 +377,47 @@ ctr_latch_count(ctr_t *ctr)
|
||||
|
||||
|
||||
uint16_t
|
||||
pit_ctr_get_count(ctr_t *ctr)
|
||||
pit_ctr_get_count(void *data, int counter_id)
|
||||
{
|
||||
pit_t *pit = (pit_t *)data;
|
||||
ctr_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
return (uint16_t) ctr->l;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count))
|
||||
pit_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count))
|
||||
{
|
||||
if (ctr == NULL)
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
pit_t *pit = (pit_t *)data;
|
||||
ctr_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
ctr->load_func = func;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out))
|
||||
pit_ctr_set_out_func(void *data, int counter_id, void (*func)(int new_out, int old_out))
|
||||
{
|
||||
if (ctr == NULL)
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
pit_t *pit = (pit_t *)data;
|
||||
ctr_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
ctr->out_func = func;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_gate(ctr_t *ctr, int gate)
|
||||
pit_ctr_set_gate(void *data, int counter_id, int gate)
|
||||
{
|
||||
pit_t *pit = (pit_t *)data;
|
||||
ctr_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
int old = ctr->gate;
|
||||
uint8_t mode = ctr->m & 3;
|
||||
|
||||
@@ -470,10 +480,12 @@ pit_ctr_set_clock(ctr_t *ctr, int clock)
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_using_timer(ctr_t *ctr, int using_timer)
|
||||
pit_ctr_set_using_timer(void *data, int counter_id, int using_timer)
|
||||
{
|
||||
timer_process();
|
||||
|
||||
if (tsc > 0)
|
||||
timer_process();
|
||||
pit_t *pit = (pit_t *)data;
|
||||
ctr_t *ctr = &pit->counters[counter_id];
|
||||
ctr->using_timer = using_timer;
|
||||
}
|
||||
|
||||
@@ -673,46 +685,19 @@ pit_read(uint16_t addr, void *priv)
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: Should be moved to machine.c (default for most machine). */
|
||||
void
|
||||
pit_irq0_timer(int new_out, int old_out)
|
||||
{
|
||||
if (new_out && !old_out)
|
||||
picint(1);
|
||||
|
||||
if (!new_out)
|
||||
picintc(1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_irq0_timer_pcjr(int new_out, int old_out)
|
||||
{
|
||||
if (new_out && !old_out) {
|
||||
picint(1);
|
||||
ctr_clock(&pit->counters[1]);
|
||||
}
|
||||
|
||||
if (!new_out)
|
||||
picintc(1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_irq0_timer_ps2(int new_out, int old_out)
|
||||
{
|
||||
ctr_t *ctr = &pit2->counters[0];
|
||||
|
||||
if (new_out && !old_out) {
|
||||
picint(1);
|
||||
pit_ctr_set_gate(ctr, 1);
|
||||
pit_devs[1].set_gate(pit_devs[1].data, 0, 1);
|
||||
}
|
||||
|
||||
if (!new_out)
|
||||
picintc(1);
|
||||
|
||||
if (!new_out && old_out)
|
||||
ctr_clock(ctr);
|
||||
pit_devs[1].ctr_clock(pit_devs[1].data, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -742,7 +727,8 @@ pit_speaker_timer(int new_out, int old_out)
|
||||
|
||||
speaker_update();
|
||||
|
||||
l = pit->counters[2].l ? pit->counters[2].l : 0x10000;
|
||||
uint16_t count = pit_devs[0].get_count(pit_devs[0].data, 2);
|
||||
l = count ? count : 0x10000;
|
||||
if (l < 25)
|
||||
speakon = 0;
|
||||
else
|
||||
@@ -809,11 +795,11 @@ pit_close(void *priv)
|
||||
{
|
||||
pit_t *dev = (pit_t *) priv;
|
||||
|
||||
if (dev == pit)
|
||||
pit = NULL;
|
||||
if (dev == pit_devs[0].data)
|
||||
pit_devs[0].data = NULL;
|
||||
|
||||
if (dev == pit2)
|
||||
pit2 = NULL;
|
||||
if (dev == pit_devs[1].data)
|
||||
pit_devs[1].data = NULL;
|
||||
|
||||
if (dev != NULL)
|
||||
free(dev);
|
||||
@@ -915,47 +901,83 @@ pit_t *
|
||||
pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out))
|
||||
{
|
||||
int i;
|
||||
void *pit;
|
||||
|
||||
pit_intf_t *pit_intf = &pit_devs[0];
|
||||
|
||||
switch (type) {
|
||||
case PIT_8253:
|
||||
default:
|
||||
pit = device_add(&i8253_device);
|
||||
*pit_intf = pit_classic_intf;
|
||||
break;
|
||||
case PIT_8254:
|
||||
pit = device_add(&i8254_device);
|
||||
*pit_intf = pit_classic_intf;
|
||||
break;
|
||||
case PIT_8253_FAST:
|
||||
pit = device_add(&i8253_fast_device);
|
||||
*pit_intf = pit_fast_intf;
|
||||
break;
|
||||
case PIT_8254_FAST:
|
||||
pit = device_add(&i8254_fast_device);
|
||||
*pit_intf = pit_fast_intf;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
pit_intf->data = pit;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
pit->counters[i].gate = 1;
|
||||
pit->counters[i].using_timer = 1;
|
||||
pit_intf->set_gate(pit_intf->data, i, 1);
|
||||
pit_intf->set_using_timer(pit_intf->data, i, 1);
|
||||
}
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[0], out0);
|
||||
pit_ctr_set_out_func(&pit->counters[1], out1);
|
||||
pit_ctr_set_out_func(&pit->counters[2], pit_speaker_timer);
|
||||
pit_ctr_set_load_func(&pit->counters[2], speaker_set_count);
|
||||
pit->counters[2].gate = 0;
|
||||
pit_intf->set_out_func(pit_intf->data, 0, out0);
|
||||
pit_intf->set_out_func(pit_intf->data, 1, out1);
|
||||
pit_intf->set_out_func(pit_intf->data, 2, pit_speaker_timer);
|
||||
pit_intf->set_load_func(pit_intf->data, 2, speaker_set_count);
|
||||
|
||||
pit_intf->set_gate(pit_intf->data, 2, 0);
|
||||
|
||||
return pit;
|
||||
}
|
||||
|
||||
|
||||
pit_t *
|
||||
pit_ps2_init(void)
|
||||
pit_ps2_init(int type)
|
||||
{
|
||||
pit2 = device_add(&i8254_ps2_device);
|
||||
void *pit;
|
||||
|
||||
pit_handler(1, 0x0044, 0x0001, pit2);
|
||||
pit_handler(1, 0x0047, 0x0001, pit2);
|
||||
pit_intf_t *ps2_pit = &pit_devs[1];
|
||||
|
||||
pit2->counters[0].gate = 0;
|
||||
pit2->counters[0].using_timer = pit2->counters[1].using_timer = pit2->counters[2].using_timer = 0;
|
||||
switch (type) {
|
||||
case PIT_8254:
|
||||
default:
|
||||
pit = device_add(&i8254_ps2_device);
|
||||
*ps2_pit = pit_classic_intf;
|
||||
break;
|
||||
|
||||
pit_ctr_set_out_func(&pit->counters[0], pit_irq0_timer_ps2);
|
||||
pit_ctr_set_out_func(&pit2->counters[0], pit_nmi_timer_ps2);
|
||||
case PIT_8254_FAST:
|
||||
pit = device_add(&i8254_ps2_fast_device);
|
||||
*ps2_pit = pit_fast_intf;
|
||||
break;
|
||||
}
|
||||
|
||||
return pit2;
|
||||
ps2_pit->data = pit;
|
||||
|
||||
ps2_pit->set_gate(ps2_pit->data, 0, 0);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ps2_pit->set_using_timer(ps2_pit->data, i, 0);
|
||||
}
|
||||
|
||||
io_sethandler(0x0044, 0x0001, ps2_pit->read, NULL, NULL, ps2_pit->write, NULL, NULL, pit);
|
||||
io_sethandler(0x0047, 0x0001, ps2_pit->read, NULL, NULL, ps2_pit->write, NULL, NULL, pit);
|
||||
|
||||
pit_devs[0].set_out_func(pit_devs[0].data, 0, pit_irq0_timer_ps2);
|
||||
ps2_pit->set_out_func(ps2_pit->data, 0, pit_nmi_timer_ps2);
|
||||
|
||||
return pit;
|
||||
}
|
||||
|
||||
|
||||
@@ -1063,3 +1085,15 @@ pit_set_clock(int clock)
|
||||
|
||||
device_speed_changed();
|
||||
}
|
||||
|
||||
const pit_intf_t pit_classic_intf = {
|
||||
&pit_read,
|
||||
&pit_write,
|
||||
&pit_ctr_get_count,
|
||||
&pit_ctr_set_gate,
|
||||
&pit_ctr_set_using_timer,
|
||||
&pit_ctr_set_out_func,
|
||||
&pit_ctr_set_load_func,
|
||||
&ctr_clock,
|
||||
NULL,
|
||||
};
|
706
src/pit_fast.c
Normal file
706
src/pit_fast.c
Normal file
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the Intel 8253/8254 Programmable Interval
|
||||
* Timer.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2019 Miran Grca.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/device.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/cassette.h>
|
||||
#include <86box/dma.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/nmi.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/pit.h>
|
||||
#include <86box/pit_fast.h>
|
||||
#include <86box/ppi.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/sound.h>
|
||||
#include <86box/snd_speaker.h>
|
||||
#include <86box/video.h>
|
||||
|
||||
#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. */
|
||||
#define PIT_SECONDARY 128 /* The PIT is secondary (ports 0048-004B). */
|
||||
|
||||
#ifdef ENABLE_PIT_LOG
|
||||
int pit_do_log = ENABLE_PIT_LOG;
|
||||
|
||||
static void
|
||||
pit_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (pit_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define pit_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
static void
|
||||
pitf_ctr_set_out(ctrf_t *ctr, int out)
|
||||
{
|
||||
if (ctr == NULL)
|
||||
return;
|
||||
|
||||
if (ctr->out_func != NULL)
|
||||
ctr->out_func(out, ctr->out);
|
||||
ctr->out = out;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count))
|
||||
{
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
pitf_t *pit = (pitf_t *)data;
|
||||
ctrf_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
ctr->load_func = func;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
pitf_ctr_get_count(void *data, int counter_id)
|
||||
{
|
||||
pitf_t *pit = (pitf_t *)data;
|
||||
ctrf_t *ctr = &pit->counters[counter_id];
|
||||
return (uint16_t) ctr->l;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_ctr_set_out_func(void *data, int counter_id, void (*func)(int new_out, int old_out))
|
||||
{
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
pitf_t *pit = (pitf_t *)data;
|
||||
ctrf_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
ctr->out_func = func;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_ctr_set_using_timer(void *data, int counter_id, int using_timer)
|
||||
{
|
||||
if (tsc > 0)
|
||||
timer_process();
|
||||
|
||||
pitf_t *pit = (pitf_t *)data;
|
||||
ctrf_t *ctr = &pit->counters[counter_id];
|
||||
ctr->using_timer = using_timer;
|
||||
}
|
||||
|
||||
static int
|
||||
pitf_read_timer(ctrf_t *ctr)
|
||||
{
|
||||
if (ctr->using_timer && !(ctr->m == 3 && !ctr->gate) && timer_is_enabled(&ctr->timer)) {
|
||||
int read = (int) ((timer_get_remaining_u64(&ctr->timer)) / PITCONST);
|
||||
if (ctr->m == 2)
|
||||
read++;
|
||||
if (read < 0)
|
||||
read = 0;
|
||||
if (read > 0x10000)
|
||||
read = 0x10000;
|
||||
if (ctr->m == 3)
|
||||
read <<= 1;
|
||||
return read;
|
||||
}
|
||||
if (ctr->m == 2)
|
||||
return ctr->count + 1;
|
||||
return ctr->count;
|
||||
}
|
||||
|
||||
/*Dump timer count back to pit->count[], and disable timer. This should be used
|
||||
when stopping a PIT timer, to ensure the correct value can be read back.*/
|
||||
static void
|
||||
pitf_dump_and_disable_timer(ctrf_t *ctr)
|
||||
{
|
||||
if (ctr->using_timer && timer_is_enabled(&ctr->timer)) {
|
||||
ctr->count = pitf_read_timer(ctr);
|
||||
timer_disable(&ctr->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_ctr_load(ctrf_t *ctr)
|
||||
{
|
||||
int l = ctr->l ? ctr->l : 0x10000;
|
||||
|
||||
ctr->newcount = 0;
|
||||
ctr->disabled = 0;
|
||||
|
||||
switch (ctr->m) {
|
||||
case 0: /*Interrupt on terminal count*/
|
||||
ctr->count = l;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
ctr->thit = 0;
|
||||
ctr->enabled = ctr->gate;
|
||||
break;
|
||||
case 1: /*Hardware retriggerable one-shot*/
|
||||
ctr->enabled = 1;
|
||||
break;
|
||||
case 2: /*Rate generator*/
|
||||
if (ctr->initial) {
|
||||
ctr->count = l - 1;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) ((l - 1) * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->thit = 0;
|
||||
}
|
||||
ctr->enabled = ctr->gate;
|
||||
break;
|
||||
case 3: /*Square wave mode*/
|
||||
if (ctr->initial) {
|
||||
ctr->count = l;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (((l + 1) >> 1) * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->thit = 0;
|
||||
}
|
||||
ctr->enabled = ctr->gate;
|
||||
break;
|
||||
case 4: /*Software triggered stobe*/
|
||||
if (!ctr->thit && !ctr->initial)
|
||||
ctr->newcount = 1;
|
||||
else {
|
||||
ctr->count = l;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
ctr->thit = 0;
|
||||
}
|
||||
ctr->enabled = ctr->gate;
|
||||
break;
|
||||
case 5: /*Hardware triggered stobe*/
|
||||
ctr->enabled = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctr->load_func != NULL)
|
||||
ctr->load_func(ctr->m, l);
|
||||
|
||||
ctr->initial = 0;
|
||||
ctr->running = ctr->enabled && ctr->using_timer && !ctr->disabled;
|
||||
if (ctr->using_timer && !ctr->running)
|
||||
pitf_dump_and_disable_timer(ctr);
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_set_gate_no_timer(ctrf_t *ctr, int gate)
|
||||
{
|
||||
int l = ctr->l ? ctr->l : 0x10000;
|
||||
|
||||
if (ctr->disabled) {
|
||||
ctr->gate = gate;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctr->m) {
|
||||
case 0: /*Interrupt on terminal count*/
|
||||
case 4: /*Software triggered stobe*/
|
||||
if (ctr->using_timer && !ctr->running)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
ctr->enabled = gate;
|
||||
break;
|
||||
case 1: /*Hardware retriggerable one-shot*/
|
||||
case 5: /*Hardware triggered stobe*/
|
||||
if (gate && !ctr->gate) {
|
||||
ctr->count = l;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
ctr->thit = 0;
|
||||
ctr->enabled = 1;
|
||||
}
|
||||
break;
|
||||
case 2: /*Rate generator*/
|
||||
if (gate && !ctr->gate) {
|
||||
ctr->count = l - 1;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->thit = 0;
|
||||
}
|
||||
ctr->enabled = gate;
|
||||
break;
|
||||
case 3: /*Square wave mode*/
|
||||
if (gate && !ctr->gate) {
|
||||
ctr->count = l;
|
||||
if (ctr->using_timer)
|
||||
timer_set_delay_u64(&ctr->timer, (uint64_t) (((l + 1) >> 1) * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->thit = 0;
|
||||
}
|
||||
ctr->enabled = gate;
|
||||
break;
|
||||
}
|
||||
ctr->gate = gate;
|
||||
ctr->running = ctr->enabled && ctr->using_timer && !ctr->disabled;
|
||||
if (ctr->using_timer && !ctr->running)
|
||||
pitf_dump_and_disable_timer(ctr);
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_ctr_set_gate(void *data, int counter_id, int gate)
|
||||
{
|
||||
pitf_t *pit = (pitf_t *)data;
|
||||
ctrf_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
if (ctr->disabled) {
|
||||
ctr->gate = gate;
|
||||
return;
|
||||
}
|
||||
|
||||
pitf_set_gate_no_timer(ctr, gate);
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_over(ctrf_t *ctr)
|
||||
{
|
||||
int l = ctr->l ? ctr->l : 0x10000;
|
||||
if (ctr->disabled) {
|
||||
ctr->count += 0xffff;
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctr->m) {
|
||||
case 0: /*Interrupt on terminal count*/
|
||||
case 1: /*Hardware retriggerable one-shot*/
|
||||
if (!ctr->thit)
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->thit = 1;
|
||||
ctr->count += 0xffff;
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST));
|
||||
break;
|
||||
case 2: /*Rate generator*/
|
||||
ctr->count += l;
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
break;
|
||||
case 3: /*Square wave mode*/
|
||||
if (ctr->out) {
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
ctr->count += (l >> 1);
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) ((l >> 1) * PITCONST));
|
||||
} else {
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->count += ((l + 1) >> 1);
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (((l + 1) >> 1) * PITCONST));
|
||||
}
|
||||
// if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST);
|
||||
break;
|
||||
case 4: /*Software triggered strove*/
|
||||
if (!ctr->thit) {
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
}
|
||||
if (ctr->newcount) {
|
||||
ctr->newcount = 0;
|
||||
ctr->count += l;
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (l * PITCONST));
|
||||
} else {
|
||||
ctr->thit = 1;
|
||||
ctr->count += 0xffff;
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST));
|
||||
}
|
||||
break;
|
||||
case 5: /*Hardware triggered strove*/
|
||||
if (!ctr->thit) {
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
}
|
||||
ctr->thit = 1;
|
||||
ctr->count += 0xffff;
|
||||
if (ctr->using_timer)
|
||||
timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST));
|
||||
break;
|
||||
}
|
||||
ctr->running = ctr->enabled && ctr->using_timer && !ctr->disabled;
|
||||
if (ctr->using_timer && !ctr->running)
|
||||
pitf_dump_and_disable_timer(ctr);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
pitf_ctr_latch_count(ctrf_t *ctr)
|
||||
{
|
||||
ctr->rl = pitf_read_timer(ctr);
|
||||
// pclog("Timer latch %f %04X %04X\n",pit->c[0],pit->rl[0],pit->l[0]);
|
||||
// pit->ctrl |= 0x30;
|
||||
ctr->rereadlatch = 0;
|
||||
ctr->rm = 3;
|
||||
ctr->latched = 1;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
pitf_ctr_latch_status(ctrf_t *ctr)
|
||||
{
|
||||
ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0);
|
||||
ctr->do_read_status = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
pitf_t *dev = (pitf_t *) priv;
|
||||
int t = (addr & 3);
|
||||
ctrf_t *ctr;
|
||||
|
||||
pit_log("[%04X:%08X] pit_write(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv);
|
||||
|
||||
switch (addr & 3) {
|
||||
case 3: /* control */
|
||||
t = val >> 6;
|
||||
|
||||
if (t == 3) {
|
||||
if (dev->flags & PIT_8254) {
|
||||
/* This is 8254-only. */
|
||||
if (!(val & 0x20)) {
|
||||
if (val & 2)
|
||||
pitf_ctr_latch_count(&dev->counters[0]);
|
||||
if (val & 4)
|
||||
pitf_ctr_latch_count(&dev->counters[1]);
|
||||
if (val & 8)
|
||||
pitf_ctr_latch_count(&dev->counters[2]);
|
||||
pit_log("PIT %i: Initiated readback command\n", t);
|
||||
}
|
||||
if (!(val & 0x10)) {
|
||||
if (val & 2)
|
||||
pitf_ctr_latch_status(&dev->counters[0]);
|
||||
if (val & 4)
|
||||
pitf_ctr_latch_status(&dev->counters[1]);
|
||||
if (val & 8)
|
||||
pitf_ctr_latch_status(&dev->counters[2]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dev->ctrl = val;
|
||||
ctr = &dev->counters[t];
|
||||
|
||||
if (!(dev->ctrl & 0x30)) {
|
||||
pitf_ctr_latch_count(ctr);
|
||||
dev->ctrl |= 0x30;
|
||||
pit_log("PIT %i: Initiated latched read, %i bytes latched\n",
|
||||
t, ctr->latched);
|
||||
} else {
|
||||
ctr->ctrl = val;
|
||||
ctr->rm = ctr->wm = (ctr->ctrl >> 4) & 3;
|
||||
ctr->m = (val >> 1) & 7;
|
||||
if (ctr->m > 5)
|
||||
ctr->m &= 3;
|
||||
if (!(ctr->rm)) {
|
||||
ctr->rm = 3;
|
||||
ctr->rl = pitf_read_timer(ctr);
|
||||
}
|
||||
ctr->rereadlatch = 1;
|
||||
ctr->initial = 1;
|
||||
if (!ctr->m)
|
||||
pitf_ctr_set_out(ctr, 0);
|
||||
else
|
||||
pitf_ctr_set_out(ctr, 1);
|
||||
ctr->disabled = 1;
|
||||
|
||||
pit_log("PIT %i: M = %i, RM/WM = %i, State = %i, Out = %i\n", t, ctr->m, ctr->rm, ctr->state, ctr->out);
|
||||
}
|
||||
ctr->thit = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 1:
|
||||
case 2: /* the actual timers */
|
||||
ctr = &dev->counters[t];
|
||||
|
||||
switch (ctr->wm) {
|
||||
case 1:
|
||||
ctr->l = val;
|
||||
pitf_ctr_load(ctr);
|
||||
break;
|
||||
case 2:
|
||||
ctr->l = (val << 8);
|
||||
pitf_ctr_load(ctr);
|
||||
break;
|
||||
case 0:
|
||||
ctr->l &= 0xFF;
|
||||
ctr->l |= (val << 8);
|
||||
pitf_ctr_load(ctr);
|
||||
ctr->wm = 3;
|
||||
break;
|
||||
case 3:
|
||||
ctr->l &= 0xFF00;
|
||||
ctr->l |= val;
|
||||
ctr->wm = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
pitf_read(uint16_t addr, void *priv)
|
||||
{
|
||||
pitf_t *dev = (pitf_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
int t = (addr & 3);
|
||||
ctrf_t *ctr;
|
||||
|
||||
switch (addr & 3) {
|
||||
case 3: /* Control. */
|
||||
/* This is 8254-only, 8253 returns 0x00. */
|
||||
ret = (dev->flags & PIT_8254) ? dev->ctrl : 0x00;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 1:
|
||||
case 2: /* The actual timers. */
|
||||
ctr = &dev->counters[t];
|
||||
|
||||
if (ctr->do_read_status) {
|
||||
ctr->do_read_status = 0;
|
||||
ret = ctr->read_status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctr->rereadlatch && !ctr->latched) {
|
||||
ctr->rereadlatch = 0;
|
||||
ctr->rl = pitf_read_timer(ctr);
|
||||
}
|
||||
switch (ctr->rm) {
|
||||
case 0:
|
||||
ret = ctr->rl >> 8;
|
||||
ctr->rm = 3;
|
||||
ctr->latched = 0;
|
||||
ctr->rereadlatch = 1;
|
||||
break;
|
||||
case 1:
|
||||
ret = (ctr->rl) & 0xFF;
|
||||
ctr->latched = 0;
|
||||
ctr->rereadlatch = 1;
|
||||
break;
|
||||
case 2:
|
||||
ret = (ctr->rl) >> 8;
|
||||
ctr->latched = 0;
|
||||
ctr->rereadlatch = 1;
|
||||
break;
|
||||
case 3:
|
||||
ret = (ctr->rl) & 0xFF;
|
||||
if (ctr->m & 0x80)
|
||||
ctr->m &= 7;
|
||||
else
|
||||
ctr->rm = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pit_log("[%04X:%08X] pit_read(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_timer_over(void *p)
|
||||
{
|
||||
ctrf_t *ctr = (ctrf_t *) p;
|
||||
pitf_over(ctr);
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_ctr_clock(void *data, int counter_id)
|
||||
{
|
||||
pitf_t *pit = (pitf_t *)data;
|
||||
ctrf_t *ctr = &pit->counters[counter_id];
|
||||
|
||||
if (ctr->thit || !ctr->enabled)
|
||||
return;
|
||||
|
||||
if (ctr->using_timer)
|
||||
return;
|
||||
|
||||
ctr->count -= (ctr->m == 3) ? 2 : 1;
|
||||
if (!ctr->count)
|
||||
pitf_over(ctr);
|
||||
}
|
||||
|
||||
static void
|
||||
ctr_reset(ctrf_t *ctr)
|
||||
{
|
||||
ctr->ctrl = 0;
|
||||
ctr->m = 0;
|
||||
ctr->gate = 0;
|
||||
ctr->l = 0xffff;
|
||||
ctr->thit = 1;
|
||||
ctr->using_timer = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_reset(pitf_t *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(dev, 0, sizeof(pitf_t));
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
ctr_reset(&dev->counters[i]);
|
||||
|
||||
/* Disable speaker gate. */
|
||||
dev->counters[2].gate = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pitf_close(void *priv)
|
||||
{
|
||||
pitf_t *dev = (pitf_t *) priv;
|
||||
|
||||
if (dev == pit_devs[0].data)
|
||||
pit_devs[0].data = NULL;
|
||||
|
||||
if (dev == pit_devs[1].data)
|
||||
pit_devs[1].data = NULL;
|
||||
|
||||
if (dev != NULL)
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static void *
|
||||
pitf_init(const device_t *info)
|
||||
{
|
||||
pitf_t *dev = (pitf_t *) malloc(sizeof(pitf_t));
|
||||
pitf_reset(dev);
|
||||
|
||||
dev->flags = info->local;
|
||||
|
||||
if (!(dev->flags & PIT_PS2) && !(dev->flags & PIT_CUSTOM_CLOCK)) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ctrf_t *ctr = &dev->counters[i];
|
||||
timer_add(&ctr->timer, pitf_timer_over, (void *)ctr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dev->flags & PIT_EXT_IO)) {
|
||||
io_sethandler((dev->flags & PIT_SECONDARY) ? 0x0048 : 0x0040, 0x0004,
|
||||
pitf_read, NULL, NULL, pitf_write, NULL, NULL, dev);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
const device_t i8253_fast_device = {
|
||||
.name = "Intel 8253/8253-5 Programmable Interval Timer",
|
||||
.internal_name = "i8253_fast",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = PIT_8253,
|
||||
.init = pitf_init,
|
||||
.close = pitf_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t i8254_fast_device = {
|
||||
.name = "Intel 8254 Programmable Interval Timer",
|
||||
.internal_name = "i8254_fast",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = PIT_8254,
|
||||
.init = pitf_init,
|
||||
.close = pitf_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t i8254_sec_fast_device = {
|
||||
.name = "Intel 8254 Programmable Interval Timer (Secondary)",
|
||||
.internal_name = "i8254_sec_fast",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = PIT_8254 | PIT_SECONDARY,
|
||||
.init = pitf_init,
|
||||
.close = pitf_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t i8254_ext_io_fast_device = {
|
||||
.name = "Intel 8254 Programmable Interval Timer (External I/O)",
|
||||
.internal_name = "i8254_ext_io_fast",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = PIT_8254 | PIT_EXT_IO,
|
||||
.init = pitf_init,
|
||||
.close = pitf_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t i8254_ps2_fast_device = {
|
||||
.name = "Intel 8254 Programmable Interval Timer (PS/2)",
|
||||
.internal_name = "i8254_ps2_fast",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = PIT_8254 | PIT_PS2 | PIT_EXT_IO,
|
||||
.init = pitf_init,
|
||||
.close = pitf_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const pit_intf_t pit_fast_intf = {
|
||||
&pitf_read,
|
||||
&pitf_write,
|
||||
&pitf_ctr_get_count,
|
||||
&pitf_ctr_set_gate,
|
||||
&pitf_ctr_set_using_timer,
|
||||
&pitf_ctr_set_out_func,
|
||||
&pitf_ctr_set_load_func,
|
||||
&pitf_ctr_clock,
|
||||
NULL,
|
||||
};
|
@@ -63,7 +63,7 @@ port_6x_write(uint16_t port, uint8_t val, void *priv)
|
||||
speaker_enable = val & 2;
|
||||
if (speaker_enable)
|
||||
was_speaker_enable = 1;
|
||||
pit_ctr_set_gate(&pit->counters[2], val & 1);
|
||||
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1);
|
||||
|
||||
if (dev->flags & PORT_6X_TURBO)
|
||||
xi8088_turbo_set(!!(val & 0x04));
|
||||
|
@@ -535,7 +535,7 @@ CXXFLAGS := $(CFLAGS)
|
||||
# Create the (final) list of objects to build. #
|
||||
#########################################################################
|
||||
MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \
|
||||
nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o fifo8.o \
|
||||
nmi.o pic.o pit.o pit_fast.o port_6x.o port_92.o ppi.o pci.o mca.o fifo8.o \
|
||||
usb.o device.o nvr.o nvr_at.o nvr_ps2.o machine_status.o \
|
||||
$(VNCOBJ)
|
||||
|
||||
|
Reference in New Issue
Block a user