From a838e8548fe06350d189be5551782424d59758bf Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 2 Dec 2019 07:05:12 +0100 Subject: [PATCH] PIT rewrite. --- src/keyboard_at.c | 4 +- src/keyboard_xt.c | 4 +- src/lpt.c | 1 - src/machine/m_amstrad.c | 4 +- src/machine/m_at.c | 10 +- src/machine/m_europc.c | 4 +- src/machine/m_olivetti_m24.c | 4 +- src/machine/m_pcjr.c | 9 +- src/machine/m_ps1.c | 4 +- src/machine/m_ps2_isa.c | 15 +- src/machine/m_xt.c | 22 +- src/machine/m_xt_compaq.c | 8 +- src/machine/m_xt_laserxt.c | 2 +- src/machine/m_xt_t1000.c | 12 +- src/machine/m_xt_zenith.c | 8 +- src/machine/machine.c | 4 +- src/pc.c | 10 +- src/pic.c | 6 +- src/pit.c | 1191 ++++++++++++++++++++-------------- src/pit.h | 104 +-- src/printer/prt_devs.h | 3 +- src/sound/snd_speaker.c | 59 +- src/sound/snd_speaker.h | 30 +- src/win/Makefile.mingw | 2 +- src/win/Makefile_ndr.mingw | 2 +- 25 files changed, 887 insertions(+), 635 deletions(-) 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 \