Merge pull request #1676 from 86Box/master

Bring the branch up to par with master.
This commit is contained in:
Miran Grča
2021-09-08 00:08:23 +02:00
committed by GitHub
26 changed files with 1576 additions and 196 deletions

View File

@@ -6,13 +6,23 @@
*
* This file is part of the 86Box distribution.
*
* Implementation of the Chips & Technologies F82C710 Universal Peripheral Controller (UPC).
* Implementation of the Chips & Technologies F82C710 Universal Peripheral
* Controller (UPC) and 82C606 CHIPSpak Multifunction Controller.
*
* Relevant literature:
*
* [1] Chips and Technologies, Inc.,
* 82C605/82C606 CHIPSpak/CHIPSport MULTIFUNCTION CONTROLLERS,
* PRELIMINARY Data Sheet, Revision 1, May 1987.
* <https://archive.org/download/82C606/82C606.pdf>
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Eluan Costa Miranda <eluancm@gmail.com>
* Lubomir Rintel <lkundrak@v3.sk>
*
* Copyright 2020 Sarah Walker.
* Copyright 2020 Eluan Costa Miranda.
* Copyright 2021 Lubomir Rintel.
*/
#include <stdio.h>
#include <stdint.h>
@@ -25,14 +35,17 @@
#include <86box/device.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/gameport.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/nvr.h>
#include <86box/sio.h>
typedef struct upc_t
{
uint32_t local;
int configuration_state; /* state of algorithm to enter configuration mode */
int configuration_mode;
uint16_t cri_addr; /* cri = configuration index register, addr is even */
@@ -42,6 +55,8 @@ typedef struct upc_t
/* 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;
nvr_t *nvr;
void *gameport;
serial_t *uart[2];
} upc_t;
@@ -87,6 +102,66 @@ f82c710_update_ports(upc_t *upc)
}
}
static void
f82c606_update_ports(upc_t *upc)
{
uint8_t uart1_int = 0xff;
uint8_t uart2_int = 0xff;
uint8_t lpt1_int = 0xff;
int nvr_int = -1;
serial_remove(upc->uart[0]);
serial_remove(upc->uart[1]);
lpt1_remove();
lpt2_remove();
nvr_at_handler(0, upc->regs[3] * 4, upc->nvr);
nvr_at_handler(0, 0x70, upc->nvr);
switch (upc->regs[8] & 0xc0) {
case 0x40: nvr_int = 4; break;
case 0x80: uart1_int = 4; break;
case 0xc0: uart2_int = 4; break;
}
switch (upc->regs[8] & 0x30) {
case 0x10: nvr_int = 3; break;
case 0x20: uart1_int = 3; break;
case 0x30: uart2_int = 3; break;
}
switch (upc->regs[8] & 0x0c) {
case 0x04: nvr_int = 5; break;
case 0x08: uart1_int = 5; break;
case 0x0c: lpt1_int = 5; break;
}
switch (upc->regs[8] & 0x03) {
case 0x01: nvr_int = 7; break;
case 0x02: uart2_int = 7; break;
case 0x03: lpt1_int = 7; break;
}
if (upc->regs[0] & 1)
gameport_remap(upc->gameport, upc->regs[7] * 4);
else
gameport_remap(upc->gameport, 0);
if (upc->regs[0] & 2)
serial_setup(upc->uart[0], upc->regs[4] * 4, uart1_int);
if (upc->regs[0] & 4)
serial_setup(upc->uart[1], upc->regs[5] * 4, uart2_int);
if (upc->regs[0] & 8) {
lpt1_init(upc->regs[6] * 4);
lpt1_irq(lpt1_int);
}
nvr_at_handler(1, upc->regs[3] * 4, upc->nvr);
nvr_irq_set(nvr_int, upc->nvr);
}
static uint8_t
f82c710_config_read(uint16_t port, void *priv)
{
@@ -151,7 +226,11 @@ f82c710_config_write(uint16_t port, uint8_t val, void *priv)
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? */
/* TODO: any benefit in updating at each register write instead of when exiting config mode? */
if (upc->local == 710)
f82c710_update_ports(upc);
if (upc->local == 606)
f82c606_update_ports(upc);
} else {
upc->regs[upc->cri] = val;
}
@@ -179,7 +258,8 @@ f82c710_reset(upc_t *upc)
lpt1_init(0x378);
lpt1_irq(7);
fdc_reset(upc->fdc);
if (upc->local == 710)
fdc_reset(upc->fdc);
}
static void *
@@ -187,8 +267,43 @@ f82c710_init(const device_t *info)
{
upc_t *upc = (upc_t *) malloc(sizeof(upc_t));
memset(upc, 0, sizeof(upc_t));
upc->local = info->local;
upc->fdc = device_add(&fdc_at_device);
if (upc->local == 710) {
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;
upc->fdc = device_add(&fdc_at_device);
}
if (upc->local == 606) {
/* Set power-on defaults. */
upc->regs[0] = 0x00; /* Enable */
upc->regs[1] = 0x00; /* Configuration Register */
upc->regs[2] = 0x00; /* Ext Baud Rate Select */
upc->regs[3] = 0xb0; /* RTC Base */
upc->regs[4] = 0xfe; /* UART1 Base */
upc->regs[5] = 0xbe; /* UART2 Base */
upc->regs[6] = 0x9e; /* Parallel Base */
upc->regs[7] = 0x80; /* Game Base */
upc->regs[8] = 0xec; /* Interrupt Select */
upc->nvr = device_add(&at_nvr_old_device);
upc->gameport = gameport_add(&gameport_sio_device);
}
upc->uart[0] = device_add_inst(&ns16450_device, 1);
upc->uart[1] = device_add_inst(&ns16450_device, 2);
@@ -196,25 +311,12 @@ f82c710_init(const device_t *info)
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);
if (upc->local == 710)
f82c710_update_ports(upc);
if (upc->local == 606)
f82c606_update_ports(upc);
return upc;
}
@@ -227,10 +329,19 @@ f82c710_close(void *priv)
free(upc);
}
const device_t f82c710_device = {
"F82C710 UPC Super I/O",
0,
const device_t f82c606_device = {
"82C606 CHIPSpak Multifunction Controller",
0,
606,
f82c710_init, f82c710_close, NULL,
{ NULL }, NULL, NULL,
NULL
};
const device_t f82c710_device = {
"F82C710 UPC Super I/O",
0,
710,
f82c710_init, f82c710_close, NULL,
{ NULL }, NULL, NULL,
NULL