From ac96bc4cc6a048cd4637c544791f7338d001d7bb Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 25 Mar 2020 01:23:22 +0100 Subject: [PATCH] Changed the GPL license of the azt2316a.c source file. Added F82C710 SIO to the super286tr. --- src/machine/m_at_286_386sx.c | 3 + src/sio.h | 3 +- src/sio_f82c710.c | 239 +++++++++++++++++++++++++++++++++++ src/sound/snd_azt2316a.c | 2 +- 4 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 src/sio_f82c710.c diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index b16382f78..a43efebe4 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -34,6 +34,7 @@ #include "fdd.h" #include "fdc.h" #include "hdc.h" +#include "sio.h" #include "video.h" #include "machine.h" @@ -293,6 +294,8 @@ machine_at_gw286ct_init(const machine_t *model) if (bios_only || !ret) return ret; + device_add(&f82c710_device); + machine_at_scat_init(model, 1); return ret; diff --git a/src/sio.h b/src/sio.h index 5888406c9..c38364504 100644 --- a/src/sio.h +++ b/src/sio.h @@ -8,7 +8,7 @@ * * Definitions for the Super I/O chips. * - * + * Version: @(#)sio.h 1.0.7 2020/01/25 * * Author: Fred N. van Kempen, * Copyright 2017-2020 Fred N. van Kempen. @@ -18,6 +18,7 @@ extern const device_t acc3221_device; +extern const device_t f82c710_device; extern const device_t fdc37c663_device; extern const device_t fdc37c665_device; extern const device_t fdc37c666_device; diff --git a/src/sio_f82c710.c b/src/sio_f82c710.c new file mode 100644 index 000000000..d6b988a97 --- /dev/null +++ b/src/sio_f82c710.c @@ -0,0 +1,239 @@ +/* + * 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 Chips & Technologies F82C710 Universal Peripheral Controller (UPC). + * + * Version: @(#)sio_f82c710.c 1.0.0 2020/03/12 + * + * Authors: Sarah Walker, + * Eluan Costa Miranda + * + * Copyright 2020 Sarah Walker. + * Copyright 2020 Eluan Costa Miranda. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "86box_io.h" +#include "timer.h" +#include "device.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + +typedef struct upc_t +{ + int configuration_state; /* state of algorithm to enter configuration mode */ + int configuration_mode; + uint16_t cri_addr; /* cri = configuration index register, addr is even */ + uint16_t cap_addr; /* cap = configuration access port, addr is odd and is cri_addr + 1 */ + uint8_t cri; /* currently indexed register */ + + /* these regs are not affected by reset */ + uint8_t regs[15]; /* there are 16 indexes, but there is no need to store the last one which is: R = cri_addr / 4, W = exit config mode */ + fdc_t *fdc; + serial_t *uart[2]; +} upc_t; + +static void +f82c710_update_ports(upc_t *upc) +{ + uint16_t com_addr = 0; + uint16_t lpt_addr = 0; + + serial_remove(upc->uart[0]); + serial_remove(upc->uart[1]); + lpt1_remove(); + lpt2_remove(); + fdc_remove(upc->fdc); + ide_pri_disable(); + + if (upc->regs[0] & 4) { + com_addr = upc->regs[4] * 4; + if (com_addr == SERIAL1_ADDR) { + serial_setup(upc->uart[0], com_addr, 4); + } else if (com_addr == SERIAL2_ADDR) { + serial_setup(upc->uart[1], com_addr, 3); + } + } + + + if (upc->regs[0] & 8) { + lpt_addr = upc->regs[6] * 4; + lpt1_init(lpt_addr); + if ((lpt_addr == 0x378) || (lpt_addr == 0x3bc)) { + lpt1_irq(7); + } else if (lpt_addr == 0x278) { + lpt1_irq(5); + } + } + + if (upc->regs[12] & 0x80) { + ide_pri_enable(); + } + + if (upc->regs[12] & 0x20) { + fdc_set_base(upc->fdc, 0x03f0); + } +} + +static uint8_t +f82c710_config_read(uint16_t port, void *priv) +{ + upc_t *upc = (upc_t *)priv; + uint8_t temp = 0xff; + + if (upc->configuration_mode) { + if (port == upc->cri_addr) { + temp = upc->cri; + } else if (port == upc->cap_addr) { + if (upc->cri == 0xf) + temp = upc->cri_addr / 4; + else + temp = upc->regs[upc->cri]; + } + } + + return temp; +} + +static void +f82c710_config_write(uint16_t port, uint8_t val, void *priv) +{ + upc_t *upc = (upc_t *)priv; + int configuration_state_event = 0; + + switch(port) { + case 0x2fa: + if (upc->configuration_state == 0 && val == 0x55) + configuration_state_event = 1; + else if (upc->configuration_state == 4) { + uint8_t addr_verify = upc->cri_addr / 4; + addr_verify += val; + if (addr_verify == 0xff) { + upc->configuration_mode = 1; + /* TODO: is the value of cri reset here or when exiting configuration mode? */ + io_sethandler(upc->cri_addr, 0x0002, f82c710_config_read, NULL, NULL, f82c710_config_write, NULL, NULL, upc); + } else { + upc->configuration_mode = 0; + } + } + break; + case 0x3fa: + if (upc->configuration_state == 1 && val == 0xaa) + configuration_state_event = 1; + else if (upc->configuration_state == 2 && val == 0x36) + configuration_state_event = 1; + else if (upc->configuration_state == 3) { + upc->cri_addr = val * 4; + upc->cap_addr = upc->cri_addr + 1; + configuration_state_event = 1; + } + break; + default: + break; + } + + if (upc->configuration_mode) { + if (port == upc->cri_addr) { + upc->cri = val & 0xf; + } else if (port == upc->cap_addr) { + if (upc->cri == 0xf) { + upc->configuration_mode = 0; + io_removehandler(upc->cri_addr, 0x0002, f82c710_config_read, NULL, NULL, f82c710_config_write, NULL, NULL, upc); + f82c710_update_ports(upc); /* TODO: any benefit in updating at each register write instead of when exiting config mode? */ + } else { + upc->regs[upc->cri] = val; + } + } + } + + /* TODO: is the state only reset when accessing 0x2fa and 0x3fa wrongly? */ + if ((port == 0x2fa || port == 0x3fa) && configuration_state_event) + upc->configuration_state++; + else + upc->configuration_state = 0; +} + + +static void +f82c710_reset(upc_t *upc) +{ + serial_remove(upc->uart[0]); + serial_setup(upc->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(upc->uart[1]); + serial_setup(upc->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt1_remove(); + lpt1_init(0x378); + lpt1_irq(7); + + fdc_reset(upc->fdc); +} + +static void * +f82c710_init(const device_t *info) +{ + upc_t *upc = (upc_t *) malloc(sizeof(upc_t)); + memset(upc, 0, sizeof(upc_t)); + + upc->fdc = device_add(&fdc_at_device); + + upc->uart[0] = device_add_inst(&ns16450_device, 1); + upc->uart[1] = device_add_inst(&ns16450_device, 2); + + io_sethandler(0x02fa, 0x0001, NULL, NULL, NULL, f82c710_config_write, NULL, NULL, upc); + io_sethandler(0x03fa, 0x0001, NULL, NULL, NULL, f82c710_config_write, NULL, NULL, upc); + + upc->regs[0] = 0x0c; + upc->regs[1] = 0x00; + upc->regs[2] = 0x00; + upc->regs[3] = 0x00; + upc->regs[4] = 0xfe; + upc->regs[5] = 0x00; + upc->regs[6] = 0x9e; + upc->regs[7] = 0x00; + upc->regs[8] = 0x00; + upc->regs[9] = 0xb0; + upc->regs[10] = 0x00; + upc->regs[11] = 0x00; + upc->regs[12] = 0xa0; + upc->regs[13] = 0x00; + upc->regs[14] = 0x00; + + f82c710_reset(upc); + + f82c710_update_ports(upc); + + return upc; +} + +static void +f82c710_close(void *priv) +{ + upc_t *upc = (upc_t *)priv; + + free(upc); +} + +const device_t f82c710_device = { + "F82C710 UPC Super I/O", + 0, + 0, + f82c710_init, f82c710_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index 3193f1af1..6131f7b8f 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -18,7 +18,7 @@ * * 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 - * the Free Software Foundation, either version 3 of the License, or + * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful,