diff --git a/src/keyboard_at.c b/src/keyboard_at.c
index 34b8cbcd5..b001b1815 100644
--- a/src/keyboard_at.c
+++ b/src/keyboard_at.c
@@ -8,7 +8,7 @@
*
* Intel 8042 (AT keyboard controller) emulation.
*
- * Version: @(#)keyboard_at.c 1.0.44 2019/10/30
+ * Version: @(#)keyboard_at.c 1.0.45 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -2013,7 +2013,7 @@ do_command:
speaker_enable = val & 2;
if (speaker_enable)
was_speaker_enable = 1;
- pit_set_gate(&pit, 2, val & 1);
+ pit_ctr_set_gate(&pit->counters[2], val & 1);
if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088)
#ifdef USE_NEW_STUFF
diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c
index 554b35b56..7f8be716c 100644
--- a/src/keyboard_xt.c
+++ b/src/keyboard_xt.c
@@ -8,7 +8,7 @@
*
* Implementation of the XT-style keyboard.
*
- * Version: @(#)keyboard_xt.c 1.0.18 2019/11/14
+ * Version: @(#)keyboard_xt.c 1.0.19 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -500,7 +500,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
}
if (speaker_enable)
was_speaker_enable = 1;
- pit_set_gate(&pit, 2, val & 1);
+ pit_ctr_set_gate(&pit->counters[2], val & 1);
if (val & 0x80) {
kbd->pa = 0;
diff --git a/src/lpt.c b/src/lpt.c
index f67eba3cc..761554b82 100644
--- a/src/lpt.c
+++ b/src/lpt.c
@@ -30,7 +30,6 @@ static const struct
{"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device},
{"Generic Text Printer", "text_prt", &lpt_prt_text_device},
{"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device},
- {"Generic PostScript Printer", "postscript", &lpt_prt_ps_device},
{"", "", NULL}
};
diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c
index 6491d9e44..6a9b56b1c 100644
--- a/src/machine/m_amstrad.c
+++ b/src/machine/m_amstrad.c
@@ -29,7 +29,7 @@
* All models: The internal mouse controller does not work correctly with
* version 7.04 of the mouse driver.
*
- * Version: @(#)m_amstrad.c 1.0.20 2019/03/09
+ * Version: @(#)m_amstrad.c 1.0.21 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -2153,7 +2153,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
speaker_enable = val & 0x02;
if (speaker_enable)
was_speaker_enable = 1;
- pit_set_gate(&pit, 2, val & 0x01);
+ pit_ctr_set_gate(&pit->counters[2], val & 0x01);
if (val & 0x80) {
/* Keyboard enabled, so enable PA reading. */
diff --git a/src/machine/m_at.c b/src/machine/m_at.c
index 8c775ef0f..af9bc2d32 100644
--- a/src/machine/m_at.c
+++ b/src/machine/m_at.c
@@ -8,15 +8,15 @@
*
* Standard PC/AT implementation.
*
- * Version: @(#)m_at.c 1.0.10 2018/10/06
+ * Version: @(#)m_at.c 1.0.11 2019/11/15
*
* Authors: Fred N. van Kempen,
* Miran Grca,
* Sarah Walker,
*
- * Copyright 2017,2018 Fred N. van Kempen.
- * Copyright 2016-2018 Miran Grca.
- * Copyright 2008-2018 Sarah Walker.
+ * Copyright 2017-2019 Fred N. van Kempen.
+ * Copyright 2016-2019 Miran Grca.
+ * Copyright 2008-2019 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -63,7 +63,7 @@ machine_at_common_init_ex(const machine_t *model, int is_ibm)
{
machine_common_init(model);
- pit_set_out_func(&pit, 1, pit_refresh_timer_at);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at);
pic2_init();
dma16_init();
diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c
index 0aa24a4b0..04e464726 100644
--- a/src/machine/m_europc.c
+++ b/src/machine/m_europc.c
@@ -68,7 +68,7 @@
*
* WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK.
*
- * Version: @(#)europc.c 1.0.11 2019/09/27
+ * Version: @(#)europc.c 1.0.12 2019/11/15
*
* Author: Fred N. van Kempen,
*
@@ -717,7 +717,7 @@ machine_europc_init(const machine_t *model)
return ret;
machine_common_init(model);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
nmi_init();
diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c
index 0ac039a82..694fec24c 100644
--- a/src/machine/m_olivetti_m24.c
+++ b/src/machine/m_olivetti_m24.c
@@ -8,7 +8,7 @@
*
* Emulation of the Olivetti M24.
*
- * Version: @(#)m_olivetti_m24.c 1.0.20 2018/10/08
+ * Version: @(#)m_olivetti_m24.c 1.0.21 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -658,7 +658,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
speaker_enable = val & 2;
if (speaker_enable)
was_speaker_enable = 1;
- pit_set_gate(&pit, 2, val & 1);
+ pit_ctr_set_gate(&pit->counters[2], val & 1);
break;
}
}
diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c
index 14f36e6b6..a5ff9cc8b 100644
--- a/src/machine/m_pcjr.c
+++ b/src/machine/m_pcjr.c
@@ -8,7 +8,7 @@
*
* Emulation of the IBM PCjr.
*
- * Version: @(#)m_pcjr.c 1.0.13 2019/10/11
+ * Version: @(#)m_pcjr.c 1.0.14 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -621,7 +621,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
speaker_enable = val & 2;
if (speaker_enable)
was_speaker_enable = 1;
- pit_set_gate(&pit, 2, val & 1);
+ pit_ctr_set_gate(&pit->counters[2], val & 1);
sn76489_mute = speaker_mute = 1;
switch (val & 0x60) {
case 0x00:
@@ -636,7 +636,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
case 0xa0:
nmi_mask = val & 0x80;
- pit_set_using_timer(&pit, 1, !(val & 0x20));
+ pit_ctr_set_using_timer(&pit->counters[1], !(val & 0x20));
break;
}
}
@@ -821,8 +821,7 @@ machine_pcjr_init(const machine_t *model)
pcjr->composite = (display_type != PCJR_RGB);
pic_init_pcjr();
- pit_init();
- pit_set_out_func(&pit, 0, pit_irq0_timer_pcjr);
+ pit_common_init(0, pit_irq0_timer_pcjr, NULL);
cpu_set();
diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c
index c58ccccec..2bfd6e7f7 100644
--- a/src/machine/m_ps1.c
+++ b/src/machine/m_ps1.c
@@ -22,7 +22,7 @@
* The reserved 384K is remapped to the top of extended memory.
* If this is not done then you get an error on startup.
*
- * Version: @(#)m_ps1.c 1.0.16 2019/11/01
+ * Version: @(#)m_ps1.c 1.0.17 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -515,7 +515,7 @@ ps1_common_init(const machine_t *model)
mem_remap_top(384);
- pit_set_out_func(&pit, 1, pit_refresh_timer_at);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at);
dma16_init();
pic2_init();
diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c
index 9c0f6e8a1..a713278d9 100644
--- a/src/machine/m_ps2_isa.c
+++ b/src/machine/m_ps2_isa.c
@@ -58,7 +58,7 @@ static uint8_t ps2_read(uint16_t port, void *p)
case 0x190:
return ps2_190;
-#ifdef FIXME
+#ifdef FIXME
case 0x322:
temp = ps2_hd.status;
break;
@@ -67,7 +67,7 @@ static uint8_t ps2_read(uint16_t port, void *p)
ps2_hd.int_status &= ~0x02;
break;
#endif
-
+
default:
temp = 0xff;
break;
@@ -118,8 +118,8 @@ static void ps2_write(uint16_t port, uint8_t val, void *p)
case 0x190:
ps2_190 = val;
break;
-
-#ifdef FIXME
+
+#ifdef FIXME
case 0x322:
ps2_hd.ctrl = val;
if (val & 0x80)
@@ -146,7 +146,7 @@ static void ps2board_init(void)
io_sethandler(0x0322, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL);
io_sethandler(0x0324, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL);
#endif
-
+
device_add(&port_92_device);
ps2_190 = 0;
@@ -173,9 +173,12 @@ machine_ps2_m30_286_init(const machine_t *model)
return ret;
machine_common_init(model);
+
+ mem_remap_top(384);
+
device_add(&fdc_at_ps1_device);
- pit_set_out_func(&pit, 1, pit_refresh_timer_at);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at);
dma16_init();
device_add(&keyboard_ps2_ps2_device);
device_add(&ps_nvr_device);
diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c
index ba9127327..22a01c882 100644
--- a/src/machine/m_xt.c
+++ b/src/machine/m_xt.c
@@ -22,7 +22,7 @@ machine_xt_common_init(const machine_t *model)
{
machine_common_init(model);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
device_add(&fdc_xt_device);
nmi_init();
@@ -52,10 +52,10 @@ machine_pc_init(const machine_t *model)
if (bios_only || !ret)
return ret;
- machine_xt_common_init(model);
-
device_add(&keyboard_pc_device);
+ machine_xt_common_init(model);
+
return ret;
}
@@ -85,11 +85,11 @@ machine_pc82_init(const machine_t *model)
if (bios_only || !ret)
return ret;
- machine_xt_common_init(model);
-
device_add(&keyboard_pc82_device);
device_add(&ibm_5161_device);
+ machine_xt_common_init(model);
+
return ret;
}
@@ -97,9 +97,9 @@ machine_pc82_init(const machine_t *model)
static void
machine_xt_init_ex(const machine_t *model)
{
- machine_xt_common_init(model);
-
device_add(&keyboard_xt_device);
+
+ machine_xt_common_init(model);
}
@@ -166,11 +166,11 @@ machine_xt86_init(const machine_t *model)
if (bios_only || !ret)
return ret;
- machine_xt_common_init(model);
-
device_add(&keyboard_xt86_device);
device_add(&ibm_5161_device);
+ machine_xt_common_init(model);
+
return ret;
}
@@ -178,9 +178,9 @@ machine_xt86_init(const machine_t *model)
static void
machine_xt_clone_init(const machine_t *model)
{
- machine_xt_common_init(model);
-
device_add(&keyboard_xt86_device);
+
+ machine_xt_common_init(model);
}
diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c
index 02af39d67..6af9079fa 100644
--- a/src/machine/m_xt_compaq.c
+++ b/src/machine/m_xt_compaq.c
@@ -8,14 +8,14 @@
*
* Emulation of various Compaq XT-class PC's.
*
- * Version: @(#)m_xt_compaq.c 1.0.4 2018/03/18
+ * Version: @(#)m_xt_compaq.c 1.0.5 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
* TheCollector1995,
*
- * Copyright 2008-2018 Sarah Walker.
- * Copyright 2016-2018 Miran Grca.
+ * Copyright 2008-2019 Sarah Walker.
+ * Copyright 2016-2019 Miran Grca.
*/
#include
#include
@@ -50,7 +50,7 @@ machine_xt_compaq_init(const machine_t *model)
machine_common_init(model);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
device_add(&keyboard_xt_compaq_device);
device_add(&fdc_xt_device);
diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c
index 9caa2e41b..0b06a238b 100644
--- a/src/machine/m_xt_laserxt.c
+++ b/src/machine/m_xt_laserxt.c
@@ -166,7 +166,7 @@ machine_xt_lxt3_init(const machine_t *model)
machine_common_init(model);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
device_add(&keyboard_xt_lxt3_device);
device_add(&fdc_xt_device);
diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c
index f6a6bd8df..3471b0c12 100644
--- a/src/machine/m_xt_t1000.c
+++ b/src/machine/m_xt_t1000.c
@@ -51,15 +51,15 @@
* NOTE: Still need to figure out a way to load/save ConfigSys and
* HardRAM stuff. Needs to be linked in to the NVR code.
*
- * Version: @(#)m_xt_t1000.c 1.0.13 2018/10/22
+ * Version: @(#)m_xt_t1000.c 1.0.14 2019/11/15
*
* Authors: Fred N. van Kempen,
* Miran Grca,
* Sarah Walker,
*
- * Copyright 2018 Fred N. van Kempen.
- * Copyright 2018 Miran Grca.
- * Copyright 2018 Sarah Walker.
+ * Copyright 2018,2019 Fred N. van Kempen.
+ * Copyright 2018,2019 Miran Grca.
+ * Copyright 2018,2019 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -917,7 +917,7 @@ machine_xt_t1000_init(const machine_t *model)
machine_common_init(model);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
device_add(&keyboard_xt_device);
t1000.fdc = device_add(&fdc_xt_device);
nmi_init();
@@ -985,7 +985,7 @@ machine_xt_t1200_init(const machine_t *model)
write_t1200_nvram, NULL, NULL,
NULL, 0, &t1000);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
device_add(&keyboard_xt_device);
t1000.fdc = device_add(&fdc_xt_t1x00_device);
nmi_init();
diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c
index 033c8b77a..23b44199d 100644
--- a/src/machine/m_xt_zenith.c
+++ b/src/machine/m_xt_zenith.c
@@ -9,14 +9,14 @@
* Emulation of various Zenith PC compatible machines.
* Currently only the Zenith Data Systems Supersport is emulated.
*
- * Version: @(#)m_xt_compaq.c 1.0.0 2019/01/13
+ * Version: @(#)m_xt_compaq.c 1.0.1 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
* TheCollector1995,
*
- * Copyright 2008-2018 Sarah Walker.
- * Copyright 2016-2018 Miran Grca.
+ * Copyright 2008-2019 Sarah Walker.
+ * Copyright 2016-2019 Miran Grca.
*/
#include
#include
@@ -124,7 +124,7 @@ machine_xt_zenith_init(const machine_t *model)
device_add(&i8250_device);
serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */
device_add(&zenith_scratchpad_device);
- pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
+ pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt);
device_add(&keyboard_xt_compaq_device);
nmi_init();
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 80f34fa5b..c2f19bd47 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -8,7 +8,7 @@
*
* Handling of the emulated machines.
*
- * Version: @(#)machine.c 1.0.37 2018/11/12
+ * Version: @(#)machine.c 1.0.38 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -128,5 +128,5 @@ machine_common_init(const machine_t *model)
cpu_set();
- pit_init();
+ pit_common_init(!!AT, pit_irq0_timer, NULL);
}
diff --git a/src/pc.c b/src/pc.c
index 4616050a1..2882e211e 100644
--- a/src/pc.c
+++ b/src/pc.c
@@ -8,15 +8,15 @@
*
* Main emulator module where most things are controlled.
*
- * Version: @(#)pc.c 1.0.91 2018/11/14
+ * Version: @(#)pc.c 1.0.92 2018/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
* Fred N. van Kempen,
*
- * Copyright 2008-2018 Sarah Walker.
- * Copyright 2016-2018 Miran Grca.
- * Copyright 2017,2018 Fred N. van Kempen.
+ * Copyright 2008-2019 Sarah Walker.
+ * Copyright 2016-2019 Miran Grca.
+ * Copyright 2017-2019 Fred N. van Kempen.
*/
#include
#include
@@ -49,10 +49,10 @@
#include "pci.h"
#include "pic.h"
#include "timer.h"
+#include "device.h"
#include "pit.h"
#include "random.h"
#include "timer.h"
-#include "device.h"
#include "nvr.h"
#include "machine/machine.h"
#include "bugger.h"
diff --git a/src/pic.c b/src/pic.c
index 816929460..60297734c 100644
--- a/src/pic.c
+++ b/src/pic.c
@@ -498,6 +498,8 @@ pic_process_interrupt(PIC* target_pic, int c)
if ((pending & pic_int_num) && !in_service) {
if (!((pic_current & (1 << c)) && picint_is_level(c)))
target_pic->pend &= ~pic_int_num;
+ else if (!picint_is_level(c))
+ target_pic->pend &= ~pic_int_num;
target_pic->ins |= pic_int_num;
pic_update_mask(&target_pic->mask2, target_pic->ins);
@@ -513,8 +515,8 @@ pic_process_interrupt(PIC* target_pic, int c)
if (target_pic->icw4 & 0x02)
(AT && (c >= 8)) ? pic2_autoeoi() : pic_autoeoi();
- if (!c)
- pit_set_gate(&pit2, 0, 0);
+ if (!c && (pit2 != NULL))
+ pit_ctr_set_gate(&pit2->counters[0], 0);
ret = pic_int + target_pic->vector;
}
diff --git a/src/pit.c b/src/pit.c
index 1011334e9..3fe4fb1dd 100644
--- a/src/pit.c
+++ b/src/pit.c
@@ -1,17 +1,32 @@
-/*IBM AT -
- Write B0
- Write aa55
- Expects aa55 back*/
+/*
+ * 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.
+ *
+ * Version: @(#)pit.c 1.0.0 2019/12/02
+ *
+ * Author: Miran Grca,
+ * Copyright 2019 Miran Grca.
+ */
#include
-#if 1
#include
-#endif
+#include
#include
#include
+#include
#include
#include
+#define HAVE_STDARG_H
#include "86box.h"
#include "cpu/cpu.h"
+#include "device.h"
+#include "timer.h"
#include "dma.h"
#include "io.h"
#include "nmi.h"
@@ -19,15 +34,13 @@
#include "timer.h"
#include "pit.h"
#include "ppi.h"
-#include "device.h"
-#include "timer.h"
#include "machine/machine.h"
#include "sound/sound.h"
#include "sound/snd_speaker.h"
#include "video/video.h"
-PIT pit, pit2;
+pit_t *pit, *pit2;
double cpuclock, PITCONSTD,
SYSCLK,
isa_timing, bus_timing;
@@ -44,373 +57,504 @@ int io_delay = 5;
int64_t firsttime = 1;
-static void pit_dump_and_disable_timer(PIT *pit, int t);
+#define PIT_PS2 16
+#define PIT_EXT_IO 32
+
+
+enum {
+ PIT_8253 = 0,
+ PIT_8254
+};
+
+
+#ifdef ENABLE_PIT_LOG
+int pit_do_log = ENABLE_PIT_LOG;
static void
-pit_set_out(PIT *pit, int t, int out)
+pit_log(const char *fmt, ...)
{
- pit->set_out_funcs[t](out, pit->out[t]);
- pit->out[t] = out;
+ 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
-pit_set_gate_no_timer(PIT *pit, int t, int gate)
+ctr_set_out(ctr_t *ctr, int out)
{
- int64_t l = pit->l[t] ? pit->l[t] : 0x10000LL;
-
- if (pit->disabled[t]) {
- pit->gate[t] = gate;
+ if (ctr == NULL)
return;
- }
- switch (pit->m[t]) {
- case 0: /*Interrupt on terminal count*/
- case 4: /*Software triggered strobe*/
- if (pit->using_timer[t] && !pit->running[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- pit->enabled[t] = gate;
- break;
- case 1: /*Hardware retriggerable one-shot*/
- case 5: /*Hardware triggered stobe*/
- if (gate && !pit->gate[t]) {
- pit->count[t] = l;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- pit_set_out(pit, t, 0);
- pit->thit[t] = 0;
- pit->enabled[t] = 1;
- }
- break;
- case 2: /*Rate generator*/
- if (gate && !pit->gate[t]) {
- pit->count[t] = l - 1;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- pit_set_out(pit, t, 1);
- pit->thit[t] = 0;
- }
- pit->enabled[t] = gate;
- break;
- case 3: /*Square wave mode*/
- if (gate && !pit->gate[t]) {
- pit->count[t] = l;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST));
- pit_set_out(pit, t, 1);
- pit->thit[t] = 0;
- }
- pit->enabled[t] = gate;
- break;
- }
-
- pit->gate[t] = gate;
- pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
- if (pit->using_timer[t] && !pit->running[t])
- pit_dump_and_disable_timer(pit, t);
+ if (ctr->out_func != NULL)
+ ctr->out_func(out, ctr->out);
+ ctr->out = out;
}
static void
-pit_over(PIT *pit, int t)
+ctr_load_count(ctr_t *ctr)
{
- int64_t l = pit->l[t] ? pit->l[t] : 0x10000;
+ int l = ctr->l ? ctr->l : 0x10000;
- if (pit->disabled[t]) {
- pit->count[t] += 0xffff;
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
+ ctr->count = l;
+ pit_log("ctr->count = %i\n", l);
+ ctr->null_count = 0;
+ ctr->newcount = !!(l & 1);
+}
+
+
+static void
+ctr_tick(ctr_t *ctr)
+{
+ switch(ctr->m & 0x07) {
+ case 0:
+ /*Interrupt on terminal count*/
+ switch (ctr->state) {
+ case 1:
+ ctr_load_count(ctr);
+ ctr->state = 2;
+ break;
+ case 2:
+ if (ctr->gate && (ctr->count >= 1)) {
+ ctr->count--;
+ if (ctr->count < 1) {
+ ctr->state = 3;
+ ctr_set_out(ctr, 1);
+ }
+ }
+ break;
+ case 3:
+ ctr->count = (ctr->count - 1) & 0xffff;
+ break;
+ }
+ break;
+ case 1:
+ /*Hardware retriggerable one-shot*/
+ switch (ctr->state) {
+ case 1:
+ ctr_load_count(ctr);
+ ctr->state = 2;
+ ctr_set_out(ctr, 0);
+ break;
+ case 2:
+ if (ctr->count >= 1) {
+ ctr->count--;
+ if (ctr->count < 1) {
+ ctr->state = 3;
+ ctr_set_out(ctr, 1);
+ }
+ }
+ break;
+ case 3:
+ ctr->count = (ctr->count - 1) & 0xffff;
+ break;
+ }
+ break;
+ case 2: case 6:
+ /*Rate generator*/
+ switch (ctr->state) {
+ case 1: case 3:
+ ctr_load_count(ctr);
+ if (ctr->state == 3)
+ ctr_set_out(ctr, 1);
+ ctr->state = 2;
+ break;
+ case 2:
+ if (ctr->gate == 0)
+ break;
+ else if (ctr->count >= 2) {
+ ctr->count--;
+ if (ctr->count < 2) {
+ ctr->state = 3;
+ ctr_set_out(ctr, 0);
+ }
+ }
+ break;
+ }
+ break;
+ case 3: case 7:
+ /*Square wave mode*/
+ switch (ctr->state) {
+ case 1:
+ ctr_load_count(ctr);
+ ctr->state = 2;
+ break;
+ case 2:
+ if (ctr->gate == 0)
+ break;
+ else if (ctr->count >= 0) {
+ ctr->count -= (ctr->newcount ? 1 : 2);
+ if (ctr->count < 0) {
+ ctr_load_count(ctr);
+ ctr->state = 3;
+ ctr_set_out(ctr, 0);
+ } else if (ctr->newcount)
+ ctr->newcount = 0;
+ }
+ break;
+ case 3:
+ if (ctr->gate == 0)
+ break;
+ else if (ctr->count >= 0) {
+ ctr->count -= (ctr->newcount ? 3 : 2);
+ if (ctr->count < 0) {
+ ctr_load_count(ctr);
+ ctr->state = 2;
+ ctr_set_out(ctr, 1);
+ } else if (ctr->newcount)
+ ctr->newcount = 0;
+ }
+ break;
+ }
+ break;
+ case 4: case 5:
+ /*Software triggered strobe*/
+ /*Hardware triggered strobe*/
+ if ((ctr->gate != 0) || (ctr->m != 4)) {
+ switch(ctr->state) {
+ case 0:
+ ctr->count--;
+ break;
+ case 1:
+ ctr_load_count(ctr);
+ ctr->state = 2;
+ break;
+ case 2:
+ if (ctr->count >= 1) {
+ ctr->count--;
+ if (ctr->count < 1) {
+ ctr->state = 3;
+ ctr_set_out(ctr, 0);
+ }
+ }
+ break;
+ case 3:
+ ctr->state = 0;
+ ctr_set_out(ctr, 1);
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+ctr_clock(ctr_t *ctr)
+{
+ /* FIXME: Is this even needed? */
+ if ((ctr->state == 3) && (ctr->m != 2) && (ctr->m != 3))
return;
- }
- switch (pit->m[t]) {
- case 0: /*Interrupt on terminal count*/
- case 1: /*Hardware retriggerable one-shot*/
- if (!pit->thit[t])
- pit_set_out(pit, t, 1);
- pit->thit[t] = 1;
- pit->count[t] += 0xffff;
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
- break;
- case 2: /*Rate generator*/
- pit->count[t] += l;
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- pit_set_out(pit, t, 0);
- pit_set_out(pit, t, 1);
- break;
- case 3: /*Square wave mode*/
- if (pit->out[t]) {
- pit_set_out(pit, t, 0);
- pit->count[t] += (l >> 1);
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)((l >> 1) * PITCONST));
- } else {
- pit_set_out(pit, t, 1);
- pit->count[t] += ((l + 1) >> 1);
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST));
- }
- break;
- case 4: /*Software triggered strobe*/
- if (!pit->thit[t]) {
- pit_set_out(pit, t, 0);
- pit_set_out(pit, t, 1);
- }
- if (pit->newcount[t]) {
- pit->newcount[t] = 0;
- pit->count[t] += l;
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- } else {
- pit->thit[t] = 1;
- pit->count[t] += 0xffff;
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
- }
- break;
- case 5: /*Hardware triggered strobe*/
- if (!pit->thit[t]) {
- pit_set_out(pit, t, 0);
- pit_set_out(pit, t, 1);
- }
- pit->thit[t] = 1;
- pit->count[t] += 0xffff;
- if (pit->using_timer[t])
- timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
- break;
- }
+ if (ctr->using_timer)
+ return;
- pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
- if (pit->using_timer[t] && !pit->running[t])
- pit_dump_and_disable_timer(pit, t);
+ ctr_tick(ctr);
}
static void
-pit_clock(PIT *pit, int t)
+ctr_set_state_1(ctr_t *ctr)
{
- if (pit->thit[t] || !pit->enabled[t]) return;
+ switch (ctr->m) {
+ case 0: case 4:
+ /*Interrupt on terminal count*/
+ ctr->state = 1;
+ break;
+ case 2: case 3:
+ /*Rate generator*/
+ /*Square wave mode*/
+ if (ctr->state == 0)
+ ctr->state = 1;
+ break;
+ }
+}
- if (pit->using_timer[t]) return;
- pit->count[t] -= (pit->m[t] == 3) ? 2 : 1;
- if (pit->count[t] == 0)
- pit_over(pit, t);
+static void
+ctr_load(ctr_t *ctr)
+{
+ if (ctr->l == 1) {
+ /* Count of 1 is illegal in modes 2 and 3. What happens here was
+ determined experimentally. */
+ if (ctr->m == 2)
+ ctr->l = 2;
+ else if (ctr->m == 3)
+ ctr->l = 0;
+ }
+
+ if (ctr->using_timer)
+ ctr->latch = 1;
+ else
+ ctr_set_state_1(ctr);
+
+ if (ctr->load_func != NULL)
+ ctr->load_func(ctr->m, ctr->l ? ctr->l : 0x10000);
+
+ pit_log("Counter loaded, state = %i, gate = %i\n", ctr->state, ctr->gate);
+}
+
+
+static void
+ctr_latch_status(ctr_t *ctr)
+{
+ ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0) | (ctr->null_count ? 0x40 : 0);
+ ctr->do_read_status = 1;
+}
+
+
+static void
+ctr_latch_count(ctr_t *ctr)
+{
+ int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count;
+
+ switch (ctr->rm & 0x03) {
+ case 0x00:
+ /* This should never happen. */
+ break;
+ case 0x01:
+ /* Latch bits 0-7 only. */
+ ctr->rl = ((count << 8) & 0xff00) | (count & 0xff);
+ ctr->latched = 1;
+ break;
+ case 0x02:
+ /* Latch bit 8-15 only. */
+ ctr->rl = (count & 0xff00) | ((count >> 8) & 0xff);
+ ctr->latched = 1;
+ break;
+ case 0x03:
+ /* Latch all 16 bits. */
+ ctr->rl = count;
+ ctr->latched = 2;
+ break;
+ }
+
+ pit_log("latched counter = %04X\n", ctr->rl & 0xffff);
+}
+
+
+uint16_t
+pit_ctr_get_count(ctr_t *ctr)
+{
+ return (uint16_t) ctr->l;
+}
+
+
+void
+pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count))
+{
+ if (ctr == NULL)
+ return;
+
+ ctr->load_func = func;
+}
+
+
+void
+pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out))
+{
+ if (ctr == NULL)
+ return;
+
+ ctr->out_func = func;
+}
+
+
+void
+pit_ctr_set_gate(ctr_t *ctr, int gate)
+{
+ int old = ctr->gate;
+
+ ctr->gate = gate;
+
+ switch (ctr->m & 0x07) {
+ case 1: case 2: case 3: case 5: case 6: case 7:
+ if (!old && gate) {
+ /* Here we handle the rising edges. */
+ switch (ctr->m) {
+ case 1:
+ ctr->state = 1;
+ break;
+ case 2: case 6:
+ ctr->state = 3;
+ break;
+ case 3: case 5: case 7:
+ ctr_set_out(ctr, 1);
+ ctr->state = 1;
+ break;
+ }
+ } else if (old && !gate) {
+ /* Here we handle the lowering edges. */
+ switch (ctr->m) {
+ case 2: case 3: case 6: case 7:
+ ctr_set_out(ctr, 1);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+
+void
+pit_ctr_set_using_timer(ctr_t *ctr, int using_timer)
+{
+ timer_process();
+
+ ctr->using_timer = using_timer;
}
static void
pit_timer_over(void *p)
{
- PIT_nr *pit_nr = (PIT_nr *)p;
- PIT *pit = pit_nr->pit;
- int t = pit_nr->nr;
+ pit_t *dev = (pit_t *) p;
+ int i;
+ ctr_t *ctr;
+ int old;
- pit_over(pit, t);
-}
+ old = dev->clock;
+ dev->clock ^= 1;
+ for (i = 0; i < 3; i++) {
+ ctr = &dev->counters[i];
-static int
-pit_read_timer(PIT *pit, int t)
-{
- int read;
-
- if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t]) && timer_is_enabled(&pit->timer[t])) {
- // read = (int)((timer_get_remaining_u64(&pit->timer[t])) / PITCONST);
- read = (int) round(((double) timer_get_remaining_u64(&pit->timer[t])) / (PITCONSTD * 4294967296.0));
- if (pit->m[t] == 2)
- read++;
- if (read < 0)
- read = 0;
- if (read > 0x10000)
- read = 0x10000;
- if (pit->m[t] == 3)
- read <<= 1;
- return read;
- }
- if (pit->m[t] == 2)
- return pit->count[t] + 1;
- return pit->count[t];
-}
-
-
-/*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
-pit_dump_and_disable_timer(PIT *pit, int t)
-{
- if (pit->using_timer[t] && timer_is_enabled(&pit->timer[t])) {
- pit->count[t] = pit_read_timer(pit, t);
- timer_disable(&pit->timer[t]);
- }
-}
-
-
-static void
-pit_load(PIT *pit, int t)
-{
- int l = pit->l[t] ? pit->l[t] : 0x10000;
-
- pit->newcount[t] = 0;
- pit->disabled[t] = 0;
-
- switch (pit->m[t]) {
- case 0: /*Interrupt on terminal count*/
- pit->count[t] = l;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- pit_set_out(pit, t, 0);
- pit->thit[t] = 0;
- pit->enabled[t] = pit->gate[t];
- break;
- case 1: /*Hardware retriggerable one-shot*/
- pit->enabled[t] = 1;
- break;
- case 2: /*Rate generator*/
- if (pit->initial[t]) {
- pit->count[t] = l - 1;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)((l - 1) * PITCONST));
- pit_set_out(pit, t, 1);
- pit->thit[t] = 0;
+ if (ctr->using_timer && ctr->latch) {
+ if (old && !dev->clock) {
+ ctr_set_state_1(ctr);
+ ctr->latch = 0;
}
- pit->enabled[t] = pit->gate[t];
- break;
- case 3: /*Square wave mode*/
- if (pit->initial[t]) {
- pit->count[t] = l;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST));
- pit_set_out(pit, t, 1);
- pit->thit[t] = 0;
- }
- pit->enabled[t] = pit->gate[t];
- break;
- case 4: /*Software triggered strobe*/
- if (!pit->thit[t] && !pit->initial[t])
- pit->newcount[t] = 1;
- else {
- pit->count[t] = l;
- if (pit->using_timer[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
- pit_set_out(pit, t, 0);
- pit->thit[t] = 0;
- }
- pit->enabled[t] = pit->gate[t];
- break;
- case 5: /*Hardware triggered strobe*/
- pit->enabled[t] = 1;
- break;
+ } 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);
+ }
}
- pit->initial[t] = 0;
- pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
- if (pit->using_timer[t] && !pit->running[t])
- pit_dump_and_disable_timer(pit, t);
+ timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL);
}
static void
pit_write(uint16_t addr, uint8_t val, void *priv)
{
- PIT *pit = (PIT *)priv;
- double sv = 0.0;
- int t;
+ pit_t *dev = (pit_t *)priv;
+ int t = (addr & 3);
+ ctr_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 */
- if ((val & 0xC0) == 0xC0) {
+ t = val >> 6;
+
+ if (t == 3) {
+ if (!(dev->flags & PIT_8254))
+ break;
+
+ /* This is 8254-only. */
if (!(val & 0x20)) {
if (val & 2)
- pit->rl[0] = (uint32_t)pit_read_timer(pit, 0);
+ ctr_latch_count(&dev->counters[0]);
if (val & 4)
- pit->rl[1] = (uint32_t)pit_read_timer(pit, 1);
+ ctr_latch_count(&dev->counters[1]);
if (val & 8)
- pit->rl[2] = (uint32_t)pit_read_timer(pit, 2);
+ ctr_latch_count(&dev->counters[2]);
+ pit_log("PIT %i: Initiated readback command\n", t);
}
if (!(val & 0x10)) {
- if (val & 2) {
- pit->read_status[0] = (pit->ctrls[0] & 0x3f) | (pit->out[0] ? 0x80 : 0);
- pit->do_read_status[0] = 1;
- }
- if (val & 4) {
- pit->read_status[1] = (pit->ctrls[1] & 0x3f) | (pit->out[1] ? 0x80 : 0);
- pit->do_read_status[1] = 1;
- }
- if (val & 8) {
- pit->read_status[2] = (pit->ctrls[2] & 0x3f) | (pit->out[2] ? 0x80 : 0);
- pit->do_read_status[2] = 1;
- }
+ if (val & 2)
+ ctr_latch_status(&dev->counters[0]);
+ if (val & 4)
+ ctr_latch_status(&dev->counters[1]);
+ if (val & 8)
+ ctr_latch_status(&dev->counters[2]);
}
- return;
- }
- t = val >> 6;
- pit->ctrl = val;
- if ((val >> 7) == 3)
- return;
-
- if (!(pit->ctrl & 0x30)) {
- pit->rl[t] = (uint32_t)pit_read_timer(pit, t);
- pit->ctrl |= 0x30;
- pit->rereadlatch[t] = 0;
- pit->rm[t] = 3;
- pit->latched[t] = 1;
} else {
- pit->ctrls[t] = val;
- pit->rm[t] = pit->wm[t] = (pit->ctrl >> 4) & 3;
- pit->m[t] = (val >> 1) & 7;
- if (pit->m[t] > 5)
- pit->m[t] &= 3;
- if (!(pit->rm[t])) {
- pit->rm[t] = 3;
- pit->rl[t] = (uint32_t)pit_read_timer(pit, t);
+ dev->ctrl = val;
+ ctr = &dev->counters[t];
+
+ if (!(dev->ctrl & 0x30)) {
+ ctr_latch_count(ctr);
+ 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;
+ ctr->null_count = 1;
+ ctr_set_out(ctr, !!ctr->m);
+ ctr->state = 0;
+ pit_log("PIT %i: M = %i, RM/WM = %i, State = %i, Out = %i\n", t, ctr->m, ctr->rm, ctr->state, ctr->out);
}
- pit->rereadlatch[t] = 1;
- pit->initial[t] = 1;
- if (!pit->m[t])
- pit_set_out(pit, t, 0);
- else
- pit_set_out(pit, t, 1);
- pit->disabled[t] = 1;
}
- pit->wp = 0;
- pit->thit[t] = 0;
break;
case 0:
case 1:
case 2: /* the actual timers */
- t = addr & 3;
- switch (pit->wm[t]) {
+ ctr = &dev->counters[t];
+
+ switch (ctr->wm) {
case 0:
- pit->l[t] &= 0xff;
- pit->l[t] |= (val << 8);
- pit_load(pit, t);
- pit->wm[t] = 3;
+ /* This should never happen. */
break;
case 1:
- pit->l[t] = val;
- pit_load(pit, t);
+ ctr->l = val;
+ if (ctr->m == 0)
+ ctr_set_out(ctr, 0);
+ ctr_load(ctr);
break;
case 2:
- pit->l[t] = (val << 8);
- pit_load(pit, t);
+ ctr->l = (val << 8);
+ if (ctr->m == 0)
+ ctr_set_out(ctr, 0);
+ ctr_load(ctr);
break;
- case 3:
- pit->l[t] &= 0xFF00;
- pit->l[t] |= val;
- pit->wm[t] = 0;
+ case 3: case 0x83:
+ if (ctr->wm & 0x80) {
+ ctr->l = (ctr->l & 0x00ff) | (val << 8);
+ pit_log("PIT %i: Written high byte %02X, latch now %04X\n", t, val, ctr->l);
+ ctr_load(ctr);
+ } else {
+ ctr->l = (ctr->l & 0xff00) | val;
+ pit_log("PIT %i: Written low byte %02X, latch now %04X\n", t, val, ctr->l);
+ if (ctr->m == 0) {
+ ctr->state = 0;
+ ctr_set_out(ctr, 0);
+ }
+ }
+
+ if (ctr->wm & 0x80)
+ ctr->wm &= ~0x80;
+ else
+ ctr->wm |= 0x80;
break;
}
-
- /* PIT latches are in fractions of 60 ms, so convert to sample using the formula below. */
- sv = (((double) pit->l[2]) / 60.0) * 16384.0;
- speakval = ((int) sv) - 0x2000;
- if (speakval > 0x2000)
- speakval = 0x2000;
break;
}
}
@@ -419,72 +563,75 @@ pit_write(uint16_t addr, uint8_t val, void *priv)
static uint8_t
pit_read(uint16_t addr, void *priv)
{
- PIT *pit = (PIT *)priv;
- uint8_t temp = 0xff;
- int t;
+ pit_t *dev = (pit_t *)priv;
+ uint8_t ret = 0xff;
+ int count, t = (addr & 3);
+ ctr_t *ctr;
switch (addr & 3) {
- case 3: /* control */
- temp = pit->ctrl;
+ 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 */
- t = addr & 3;
- if (pit->do_read_status[t]) {
- pit->do_read_status[t] = 0;
- temp = pit->read_status[t];
+ 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 (pit->rereadlatch[addr & 3] && !pit->latched[addr & 3]) {
- pit->rereadlatch[addr & 3] = 0;
- pit->rl[t] = pit_read_timer(pit, t);
- }
- switch (pit->rm[addr & 3]) {
- case 0:
- temp = pit->rl[addr & 3] >> 8;
- pit->rm[addr & 3] = 3;
- pit->latched[addr & 3] = 0;
- pit->rereadlatch[addr & 3] = 1;
+
+ count = (ctr->state == 1) ? ctr->l : ctr->count;
+
+ if (ctr->latched) {
+ ret = (ctr->rl) >> ((ctr->rm & 0x80) ? 8 : 0);
+
+ if (ctr->rm & 0x80)
+ ctr->rm &= ~0x80;
+ else
+ ctr->rm |= 0x80;
+
+ ctr->latched--;
+ } else switch (ctr->rm) {
+ case 0: case 0x80:
+ ret = 0x00;
break;
case 1:
- temp = (pit->rl[addr & 3]) & 0xff;
- pit->latched[addr & 3] = 0;
- pit->rereadlatch[addr & 3] = 1;
+ ret = count & 0xff;
break;
case 2:
- temp = (pit->rl[addr & 3]) >> 8;
- pit->latched[addr & 3] = 0;
- pit->rereadlatch[addr & 3] = 1;
+ ret = count >> 8;
break;
- case 3:
- temp = (pit->rl[addr & 3]) & 0xff;
- if (pit->m[addr & 3] & 0x80)
- pit->m[addr & 3] &= 7;
+ case 3: case 0x83:
+ if (ctr->wm & 0x80)
+ ret = ~(ctr->l & 0xff);
else
- pit->rm[addr & 3] = 0;
+ ret = count >> ((ctr->rm & 0x80) ? 8 : 0);
+
+ if (ctr->rm & 0x80)
+ ctr->rm &= ~0x80;
+ else
+ ctr->rm |= 0x80;
break;
}
break;
}
- return temp;
-}
+ pit_log("[%04X:%08X] pit_read(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret);
-
-/* FIXME: Should be removed. */
-static void
-pit_null_timer(int new_out, int old_out)
-{
+ return ret;
}
/* FIXME: Should be moved to machine.c (default for most machine). */
-static void
+void
pit_irq0_timer(int new_out, int old_out)
{
if (new_out && !old_out)
@@ -495,14 +642,61 @@ pit_irq0_timer(int new_out, int old_out)
}
-static void
+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);
+ }
+
+ if (!new_out)
+ picintc(1);
+
+ if (!new_out && old_out)
+ ctr_clock(ctr);
+}
+
+
+void
+pit_refresh_timer_xt(int new_out, int old_out)
+{
+ if (new_out && !old_out)
+ dma_channel_read(0);
+}
+
+
+void
+pit_refresh_timer_at(int new_out, int old_out)
+{
+ if (new_out && !old_out)
+ ppi.pb ^= 0x10;
+}
+
+
+void
pit_speaker_timer(int new_out, int old_out)
{
int l;
speaker_update();
- l = pit.l[2] ? pit.l[2] : 0x10000;
+ l = pit->counters[2].l ? pit->counters[2].l : 0x10000;
if (l < 25)
speakon = 0;
else
@@ -513,54 +707,7 @@ pit_speaker_timer(int new_out, int old_out)
void
-pit_init(void)
-{
- int i;
-
- pit_reset(&pit);
-
- for (i = 0; i < 3; i++) {
- pit.pit_nr[i].nr = i;
- pit.pit_nr[i].pit = &pit;
-
- pit.gate[i] = 1;
- pit.using_timer[i] = 1;
-
- timer_add(&pit.timer[i], pit_timer_over, (void *)&pit.pit_nr[i], 0);
- }
-
- io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit);
-
- /* Timer 0: The TOD clock. */
- pit_set_out_func(&pit, 0, pit_irq0_timer);
-
- /* Timer 1: Unused. */
- pit_set_out_func(&pit, 1, pit_null_timer);
-
- /* Timer 2: speaker and cassette. */
- pit_set_out_func(&pit, 2, pit_speaker_timer);
- pit.gate[2] = 0;
-}
-
-
-static void
-pit_irq0_ps2(int new_out, int old_out)
-{
- if (new_out && !old_out) {
- picint(1);
- pit_set_gate_no_timer(&pit2, 0, 1);
- }
-
- if (!new_out)
- picintc(1);
-
- if (!new_out && old_out)
- pit_clock(&pit2, 0);
-}
-
-
-static void
-pit_nmi_ps2(int new_out, int old_out)
+pit_nmi_timer_ps2(int new_out, int old_out)
{
nmi = new_out;
@@ -569,49 +716,173 @@ pit_nmi_ps2(int new_out, int old_out)
}
-void
-pit_ps2_init()
+static void
+ctr_reset(ctr_t *ctr)
{
- pit_reset(&pit2);
+ ctr->ctrl = 0;
+ ctr->m = 0;
+ ctr->gate = 0;
+ ctr->l = 0xffff;
+ ctr->using_timer = 1;
+ ctr->state = 0;
+ ctr->null_count = 1;
- pit2.gate[0] = 0;
- pit2.using_timer[0] = 0;
- pit2.disabled[0] = 1;
+ ctr->latch = 0;
- pit2.pit_nr[0].nr = 0;
- pit2.pit_nr[0].pit = &pit2;
-
- timer_add(&pit2.timer[0], pit_timer_over, (void *)&pit2.pit_nr[0], 0);
-
- io_sethandler(0x0044, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2);
- io_sethandler(0x0047, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2);
-
- pit_set_out_func(&pit, 0, pit_irq0_ps2);
- pit_set_out_func(&pit2, 0, pit_nmi_ps2);
+ ctr->s1_det = 0;
+ ctr->l_det = 0;
}
void
-pit_reset(PIT *pit)
+pit_reset(pit_t *dev)
{
int i;
- memset(pit, 0, sizeof(PIT));
+ memset(dev, 0, sizeof(pit_t));
- for (i = 0; i < 3; i++) {
- pit->ctrls[i] = 0;
- pit->thit[i] = 0; /* Should be only thit[0]? */
+ dev->clock = 0;
- pit->m[i] = 0;
- pit->gate[i] = 1;
- pit->l[i] = 0xffff;
- pit->using_timer[i] = 1;
- }
-
- pit->thit[0] = 1;
+ for (i = 0; i < 3; i++)
+ ctr_reset(&dev->counters[i]);
/* Disable speaker gate. */
- pit->gate[2] = 0;
+ dev->counters[2].gate = 0;
+}
+
+
+void
+pit_handler(int set, uint16_t base, int size, void *priv)
+{
+ io_handler(set, base, size, pit_read, NULL, NULL, pit_write, NULL, NULL, priv);
+}
+
+
+static void
+pit_close(void *priv)
+{
+ pit_t *dev = (pit_t *) priv;
+
+ if (dev == pit)
+ pit = NULL;
+
+ if (dev == pit2)
+ pit2 = NULL;
+
+ if (dev != NULL)
+ free(dev);
+}
+
+
+static void *
+pit_init(const device_t *info)
+{
+ pit_t *dev = (pit_t *) malloc(sizeof(pit_t));
+ pit_reset(dev);
+
+ if (!(dev->flags & PIT_PS2)) {
+ timer_add(&dev->callback_timer, pit_timer_over, (void *) dev, 0);
+ timer_set_delay_u64(&dev->callback_timer, PITCONST >> 1ULL);
+ }
+
+ dev->flags = info->local;
+
+ if (!(dev->flags & PIT_EXT_IO))
+ io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, dev);
+
+ return dev;
+}
+
+
+const device_t i8253_device =
+{
+ "Intel 8253/8253-5 Programmable Interval Timer",
+ DEVICE_ISA,
+ PIT_8253,
+ pit_init, pit_close, NULL,
+ NULL, NULL, NULL,
+ NULL
+};
+
+
+const device_t i8254_device =
+{
+ "Intel 8254 Programmable Interval Timer",
+ DEVICE_ISA,
+ PIT_8254,
+ pit_init, pit_close, NULL,
+ NULL, NULL, NULL,
+ NULL
+};
+
+
+const device_t i8254_ext_io_device =
+{
+ "Intel 8254 Programmable Interval Timer (External I/O)",
+ DEVICE_ISA,
+ PIT_8254 | PIT_EXT_IO,
+ pit_init, pit_close, NULL,
+ NULL, NULL, NULL,
+ NULL
+};
+
+
+const device_t i8254_ps2_device =
+{
+ "Intel 8254 Programmable Interval Timer (PS/2)",
+ DEVICE_ISA,
+ PIT_8254 | PIT_PS2 | PIT_EXT_IO,
+ pit_init, pit_close, NULL,
+ NULL, NULL, NULL,
+ NULL
+};
+
+
+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;
+
+ switch (type) {
+ case PIT_8253:
+ default:
+ pit = device_add(&i8253_device);
+ break;
+ case PIT_8254:
+ pit = device_add(&i8254_device);
+ break;
+ }
+
+ for (i = 0; i < 3; i++) {
+ pit->counters[i].gate = 1;
+ pit->counters[i].using_timer = 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;
+
+ return pit;
+}
+
+
+pit_t *
+pit_ps2_init(void)
+{
+ pit2 = device_add(&i8254_ps2_device);
+
+ pit_handler(1, 0x0044, 0x0001, pit2);
+ pit_handler(1, 0x0047, 0x0001, pit2);
+
+ pit2->counters[0].gate = 0;
+ pit2->counters[0].using_timer = pit2->counters[1].using_timer = pit2->counters[2].using_timer = 0;
+
+ pit_ctr_set_out_func(&pit->counters[0], pit_irq0_timer_ps2);
+ pit_ctr_set_out_func(&pit2->counters[0], pit_nmi_timer_ps2);
+
+ return pit2;
}
@@ -709,77 +980,3 @@ pit_set_clock(int clock)
device_speed_changed();
}
-
-
-void
-clearpit(void)
-{
- // pit.c[0] = (pit.l[0] << 2);
-}
-
-
-void
-pit_set_gate(PIT *pit, int t, int gate)
-{
- if (pit->disabled[t]) {
- pit->gate[t] = gate;
- return;
- }
-
- pit_set_gate_no_timer(pit, t, gate);
-}
-
-
-void
-pit_set_using_timer(PIT *pit, int t, int using_timer)
-{
- timer_process();
-
- if (pit->using_timer[t] && !using_timer)
- pit->count[t] = pit_read_timer(pit, t);
-
- pit->running[t] = pit->enabled[t] && using_timer && !pit->disabled[t];
-
- if (!pit->using_timer[t] && using_timer && pit->running[t])
- timer_set_delay_u64(&pit->timer[t], (uint64_t)(pit->count[t] * PITCONST));
- else if (!pit->running[t])
- timer_disable(&pit->timer[t]);
-
- pit->using_timer[t] = using_timer;
-}
-
-
-void
-pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out))
-{
- pit->set_out_funcs[t] = func;
-}
-
-
-void
-pit_irq0_timer_pcjr(int new_out, int old_out)
-{
- if (new_out && !old_out) {
- picint(1);
- pit_clock(&pit, 1);
- }
-
- if (!new_out)
- picintc(1);
-}
-
-
-void
-pit_refresh_timer_xt(int new_out, int old_out)
-{
- if (new_out && !old_out)
- dma_channel_read(0);
-}
-
-
-void
-pit_refresh_timer_at(int new_out, int old_out)
-{
- if (new_out && !old_out)
- ppi.pb ^= 0x10;
-}
diff --git a/src/pit.h b/src/pit.h
index 17585cf71..e0a4a42ff 100644
--- a/src/pit.h
+++ b/src/pit.h
@@ -1,47 +1,53 @@
+/*
+ * 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.
+ *
+ * Version: @(#)pit.h 1.0.0 2019/12/02
+ *
+ * Author: Miran Grca,
+ * Copyright 2019 Miran Grca.
+ */
#ifndef EMU_PIT_H
# define EMU_PIT_H
typedef struct {
- int nr;
- struct PIT *pit;
-} PIT_nr;
+ uint8_t m, ctrl,
+ read_status, latch,
+ s1_det, l_det;
+
+ uint16_t rl;
+
+ int rm, wm, gate, out,
+ newcount, count, using_timer, latched,
+ state, null_count, do_read_status, pad1;
+
+ uint32_t l;
+
+ void (*load_func)(uint8_t new_m, int new_count);
+ void (*out_func)(int new_out, int old_out);
+} ctr_t;
+
typedef struct PIT {
- uint32_t l[3];
- pc_timer_t timer[3];
- uint8_t m[3];
- uint8_t ctrl,
- ctrls[3];
- int wp,
- rm[3],
- wm[3];
- uint16_t rl[3];
- int thit[3];
- int delay[3];
- int rereadlatch[3];
- int gate[3];
- int out[3];
- int running[3];
- int enabled[3];
- int newcount[3];
- int count[3];
- int using_timer[3];
- int initial[3];
- int latched[3];
- int disabled[3];
+ int flags, clock;
+ pc_timer_t callback_timer;
- uint8_t read_status[3];
- int do_read_status[3];
+ ctr_t counters[3];
- PIT_nr pit_nr[3];
-
- void (*set_out_funcs[3])(int new_out, int old_out);
-} PIT;
+ uint8_t ctrl;
+} pit_t;
-extern PIT pit,
- pit2;
+extern pit_t *pit,
+ *pit2;
extern double SYSCLK;
@@ -54,19 +60,37 @@ extern uint64_t PITCONST, ISACONST,
RTCCONST;
-extern void pit_init(void);
-extern void pit_ps2_init(void);
-extern void pit_reset(PIT *pit);
-extern void pit_set_gate(PIT *pit, int channel, int gate);
-extern void pit_set_using_timer(PIT *pit, int t, int using_timer);
-extern void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out));
+extern uint16_t pit_ctr_get_count(ctr_t *ctr);
+extern void pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count));
+extern void pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out));
+extern void pit_ctr_set_gate(ctr_t *ctr, int gate);
+extern void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer);
-extern float pit_timer0_freq(void);
+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 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);
extern void pit_refresh_timer_at(int new_out, int old_out);
+extern void pit_speaker_timer(int new_out, int old_out);
+
+extern void pit_nmi_timer_ps2(int new_out, int old_out);
+
extern void pit_set_clock(int clock);
+extern void pit_handler(int set, uint16_t base, int size, void *priv);
+
+
+#ifdef EMU_DEVICE_H
+extern const device_t i8253_device;
+extern const device_t i8254_device;
+extern const device_t i8254_ext_io_device;
+extern const device_t i8254_ps2_device;
+#endif
#endif /*EMU_PIT_H*/
diff --git a/src/printer/prt_devs.h b/src/printer/prt_devs.h
index 7ef25e5cd..e43ec67cc 100644
--- a/src/printer/prt_devs.h
+++ b/src/printer/prt_devs.h
@@ -1,3 +1,2 @@
extern const lpt_device_t lpt_prt_text_device;
-extern const lpt_device_t lpt_prt_escp_device;
-extern const lpt_device_t lpt_prt_ps_device;
\ No newline at end of file
+extern const lpt_device_t lpt_prt_escp_device;
\ No newline at end of file
diff --git a/src/sound/snd_speaker.c b/src/sound/snd_speaker.c
index 799614fea..c6b9b1a8a 100644
--- a/src/sound/snd_speaker.c
+++ b/src/sound/snd_speaker.c
@@ -8,7 +8,7 @@
*
* Emulation of the PC speaker.
*
- * Version: @(#)snd_speaker.c 1.0.0 2019/11/11
+ * Version: @(#)snd_speaker.c 1.0.1 2019/11/15
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -30,47 +30,56 @@
int speaker_mute = 0, speaker_gated = 0;
int speaker_enable = 0, was_speaker_enable = 0;
-int gated,speakval,speakon;
+int gated, speakval, speakon;
static int32_t speaker_buffer[SOUNDBUFLEN];
static int speaker_pos = 0;
+static uint8_t speaker_mode = 0;
+static double speaker_count = 65535.0;
+
+
+void
+speaker_set_count(uint8_t new_m, int new_count)
+{
+ speaker_mode = new_m;
+ speaker_count = (double) new_count;
+}
+
void
speaker_update(void)
{
int32_t val;
- double timer2_count, amplitude;
+ double amplitude;
- timer2_count = pit.l[2] ? ((double) pit.l[2]) : 65536.0;
- amplitude = ((timer2_count / 64.0) * 10240.0) - 5120.0;
+ amplitude = ((speaker_count / 64.0) * 10240.0) - 5120.0;
if (amplitude > 5120.0)
amplitude = 5120.0;
- if (speaker_pos >= sound_pos_global)
- return;
+ if (speaker_pos < sound_pos_global) {
+ for (; speaker_pos < sound_pos_global; speaker_pos++) {
+ if (speaker_gated && was_speaker_enable) {
+ if ((speaker_mode == 0) || (speaker_mode == 4))
+ val = (int32_t) amplitude;
+ else if (speaker_count < 64.0)
+ val = 0xa00;
+ else
+ val = speakon ? 0x1400 : 0;
+ } else {
+ if (speaker_mode == 1)
+ val = was_speaker_enable ? (int32_t) amplitude : 0;
+ else
+ val = was_speaker_enable ? 0x1400 : 0;
+ }
- for (; speaker_pos < sound_pos_global; speaker_pos++) {
- if (speaker_gated && was_speaker_enable) {
- if ((pit.m[2] == 0) || (pit.m[2] == 4))
- val = (int32_t) amplitude;
- else if (pit.l[2] < 0x40)
- val = 0xa00;
- else
- val = speakon ? 0x1400 : 0;
- } else {
- if (pit.m[2] == 1)
- val = was_speaker_enable ? (int32_t) amplitude : 0;
- else
- val = was_speaker_enable ? 0x1400 : 0;
- }
+ if (!speaker_enable)
+ was_speaker_enable = 0;
- if (!speaker_enable)
- was_speaker_enable = 0;
-
- speaker_buffer[speaker_pos] = val;
+ speaker_buffer[speaker_pos] = val;
+ }
}
}
diff --git a/src/sound/snd_speaker.h b/src/sound/snd_speaker.h
index 409a7c4e6..c27869f64 100644
--- a/src/sound/snd_speaker.h
+++ b/src/sound/snd_speaker.h
@@ -1,8 +1,28 @@
-void speaker_init();
+/*
+ * 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 emulation of the PC speaker.
+ *
+ * Version: @(#)snd_speaker.h 1.0.0 2019/11/15
+ *
+ * Authors: Sarah Walker,
+ * Miran Grca,
+ *
+ * Copyright 2008-2019 Sarah Walker.
+ * Copyright 2016-2019 Miran Grca.
+ */
+extern int speaker_mute;
-extern int speaker_mute;
+extern int speaker_gated;
+extern int speaker_enable, was_speaker_enable;
-extern int speaker_gated;
-extern int speaker_enable, was_speaker_enable;
-void speaker_update();
+extern void speaker_init();
+
+extern void speaker_set_count(uint8_t new_m, int new_count);
+extern void speaker_update(void);
diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw
index d160e2a38..8e6f39e38 100644
--- a/src/win/Makefile.mingw
+++ b/src/win/Makefile.mingw
@@ -610,7 +610,7 @@ NETOBJ := network.o \
net_wd8003.o
PRINTOBJ := png.o prt_cpmap.o \
- prt_escp.o prt_text.o prt_ps.o
+ prt_escp.o prt_text.o
SNDOBJ := sound.o \
openal.o \
diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw
index 3fb154281..04a328752 100644
--- a/src/win/Makefile_ndr.mingw
+++ b/src/win/Makefile_ndr.mingw
@@ -616,7 +616,7 @@ NETOBJ := network.o \
net_wd8003.o
PRINTOBJ := png.o prt_cpmap.o \
- prt_escp.o prt_text.o prt_ps.o
+ prt_escp.o prt_text.o
SNDOBJ := sound.o \
openal.o \