mirror of
https://github.com/86Box/86Box.git
synced 2025-01-24 02:02:12 -05:00
261 lines
5 KiB
C
261 lines
5 KiB
C
/*
|
|
* 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 Port 92 used by PS/2 machines and 386+
|
|
* clones.
|
|
*
|
|
*
|
|
*
|
|
* Authors: Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2019 Miran Grca.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include <86box/86box.h>
|
|
#include <86box/device.h>
|
|
#include "cpu.h"
|
|
#include <86box/timer.h>
|
|
#include <86box/io.h>
|
|
#include <86box/keyboard.h>
|
|
#include <86box/mem.h>
|
|
#include <86box/pit.h>
|
|
#include <86box/port_92.h>
|
|
|
|
|
|
#define PORT_92_INV 1
|
|
#define PORT_92_WORD 2
|
|
#define PORT_92_PCI 4
|
|
#define PORT_92_RESET 8
|
|
#define PORT_92_A20 16
|
|
|
|
|
|
static uint8_t
|
|
port_92_readb(uint16_t port, void *priv)
|
|
{
|
|
uint8_t ret = 0x00;
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
if (port == 0x92) {
|
|
/* Return bit 1 directly from mem_a20_alt, so the
|
|
pin can be reset independently of the device. */
|
|
ret = (dev->reg & ~0x03) | (mem_a20_alt & 2) |
|
|
(cpu_alt_reset & 1);
|
|
|
|
if (dev->flags & PORT_92_INV)
|
|
ret |= 0xfc;
|
|
else if (dev->flags & PORT_92_PCI)
|
|
ret |= 0x24; /* Intel SIO datasheet says bits 2 and 5 are always 1. */
|
|
} else if (dev->flags & PORT_92_INV)
|
|
ret = 0xff;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static uint16_t
|
|
port_92_readw(uint16_t port, void *priv)
|
|
{
|
|
uint16_t ret = 0xffff;
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
if (!(dev->flags & PORT_92_PCI))
|
|
ret = port_92_readb(port, priv);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void
|
|
port_92_pulse(void *priv)
|
|
{
|
|
resetx86();
|
|
cpu_set_edx();
|
|
}
|
|
|
|
|
|
static void
|
|
port_92_writeb(uint16_t port, uint8_t val, void *priv)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
if (port != 0x92)
|
|
return;
|
|
|
|
dev->reg = val & 0x03;
|
|
|
|
if ((mem_a20_alt ^ val) & 2) {
|
|
mem_a20_alt = (val & 2);
|
|
mem_a20_recalc();
|
|
}
|
|
|
|
if ((~cpu_alt_reset & val) & 1)
|
|
timer_set_delay_u64(&dev->pulse_timer, dev->pulse_period);
|
|
else if (!(val & 1))
|
|
timer_disable(&dev->pulse_timer);
|
|
|
|
cpu_alt_reset = (val & 1);
|
|
|
|
if (dev->flags & PORT_92_INV)
|
|
dev->reg |= 0xfc;
|
|
}
|
|
|
|
|
|
static void
|
|
port_92_writew(uint16_t port, uint16_t val, void *priv)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
if (!(dev->flags & PORT_92_PCI))
|
|
port_92_writeb(port, val & 0xff, priv);
|
|
}
|
|
|
|
|
|
void
|
|
port_92_set_period(void *priv, uint64_t pulse_period)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
dev->pulse_period = pulse_period;
|
|
}
|
|
|
|
|
|
void
|
|
port_92_set_features(void *priv, int reset, int a20)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
dev->flags &= ~(PORT_92_RESET | PORT_92_A20);
|
|
|
|
if (reset)
|
|
dev->flags |= PORT_92_RESET;
|
|
|
|
timer_disable(&dev->pulse_timer);
|
|
|
|
if (a20) {
|
|
dev->flags |= PORT_92_A20;
|
|
mem_a20_alt = (dev->reg & 2);
|
|
} else
|
|
mem_a20_alt = 0;
|
|
|
|
mem_a20_recalc();
|
|
}
|
|
|
|
|
|
void
|
|
port_92_add(void *priv)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
if (dev->flags & (PORT_92_WORD | PORT_92_PCI))
|
|
io_sethandler(0x0092, 2,
|
|
port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev);
|
|
else
|
|
io_sethandler(0x0092, 1,
|
|
port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev);
|
|
}
|
|
|
|
|
|
void
|
|
port_92_remove(void *priv)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
if (dev->flags & (PORT_92_WORD | PORT_92_PCI))
|
|
io_removehandler(0x0092, 2,
|
|
port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev);
|
|
else
|
|
io_removehandler(0x0092, 1,
|
|
port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev);
|
|
}
|
|
|
|
|
|
static void
|
|
port_92_close(void *priv)
|
|
{
|
|
port_92_t *dev = (port_92_t *) priv;
|
|
|
|
timer_disable(&dev->pulse_timer);
|
|
|
|
free(dev);
|
|
}
|
|
|
|
|
|
void *
|
|
port_92_init(const device_t *info)
|
|
{
|
|
port_92_t *dev = (port_92_t *) malloc(sizeof(port_92_t));
|
|
memset(dev, 0, sizeof(port_92_t));
|
|
|
|
dev->flags = info->local & 0xff;
|
|
|
|
timer_add(&dev->pulse_timer, port_92_pulse, dev, 0);
|
|
|
|
dev->reg = 0;
|
|
mem_a20_alt = 0;
|
|
mem_a20_recalc();
|
|
|
|
cpu_alt_reset = 0;
|
|
|
|
flushmmucache();
|
|
|
|
port_92_add(dev);
|
|
|
|
dev->pulse_period = (uint64_t) (4.0 * SYSCLK * (double)(1ULL << 32ULL));
|
|
|
|
dev->flags |= (PORT_92_RESET | PORT_92_A20);
|
|
|
|
return dev;
|
|
}
|
|
|
|
|
|
const device_t port_92_device = {
|
|
"Port 92 Register",
|
|
"port_92",
|
|
0,
|
|
0,
|
|
port_92_init, port_92_close, NULL,
|
|
{ NULL }, NULL, NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
const device_t port_92_inv_device = {
|
|
"Port 92 Register (inverted bits 2-7)",
|
|
"port_92_inv",
|
|
0,
|
|
PORT_92_INV,
|
|
port_92_init, port_92_close, NULL,
|
|
{ NULL }, NULL, NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
const device_t port_92_word_device = {
|
|
"Port 92 Register (16-bit)",
|
|
"port_92_word",
|
|
0,
|
|
PORT_92_WORD,
|
|
port_92_init, port_92_close, NULL,
|
|
{ NULL }, NULL, NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
const device_t port_92_pci_device = {
|
|
"Port 92 Register (PCI)",
|
|
"port_92_pci",
|
|
0,
|
|
PORT_92_PCI,
|
|
port_92_init, port_92_close, NULL,
|
|
{ NULL }, NULL, NULL,
|
|
NULL
|
|
};
|