Added the C&T 82C100 chipset needed by the Victor V86P.

This commit is contained in:
OBattler 2021-09-07 23:41:17 +02:00
parent c107fde4e5
commit 0c4003caa3
8 changed files with 409 additions and 4 deletions

352
src/chipset/82c100.c Normal file
View File

@ -0,0 +1,352 @@
/*
* 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 Chips&Technology's 82C100 chipset.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2021 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 "x86.h"
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/nmi.h>
#include <86box/port_92.h>
#include <86box/rom.h>
#include <86box/chipset.h>
typedef struct
{
int enabled;
uint32_t virt, phys;
} ems_page_t;
typedef struct
{
uint8_t index, access;
uint16_t ems_io_base;
uint32_t ems_window_base;
uint8_t ems_page_regs[4],
regs[256];
ems_page_t ems_pages[4];
mem_mapping_t ems_mappings[4];
} ct_82c100_t;
static void
ct_82c100_ems_pages_recalc(ct_82c100_t *dev)
{
int i;
uint32_t page_base;
for (i = 0; i < 4; i++) {
page_base = dev->ems_window_base + (i << 14);
if (dev->ems_page_regs[i] & 0x80) {
dev->ems_pages[i].virt = page_base;
dev->ems_pages[i].phys = 0xa0000 + (((uint32_t) (dev->ems_page_regs[4] & 0x7f)) << 14);
mem_mapping_set_addr(&(dev->ems_mappings[i]), dev->ems_pages[i].virt, 0x4000);
mem_mapping_set_exec(&(dev->ems_mappings[i]), &(ram[dev->ems_pages[i].phys]));
mem_set_mem_state_both(page_base, 0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
} else {
mem_mapping_disable(&(dev->ems_mappings[i]));
mem_set_mem_state_both(page_base, 0x00004000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
}
}
}
static void
ct_82c100_ems_out(uint16_t port, uint8_t val, void *priv)
{
ct_82c100_t *dev = (ct_82c100_t *) priv;
dev->ems_page_regs[port >> 14] = val;
ct_82c100_ems_pages_recalc(dev);
}
static uint8_t
ct_82c100_ems_in(uint16_t port, void *priv)
{
ct_82c100_t *dev = (ct_82c100_t *) priv;
uint8_t ret = 0xff;
ret = dev->ems_page_regs[port >> 14];
return ret;
}
static void
ct_82c100_ems_update(ct_82c100_t *dev)
{
int i;
for (i = 0; i < 4; i++) {
io_handler(0, dev->ems_io_base + (i << 14), 1,
ct_82c100_ems_in, NULL, NULL, ct_82c100_ems_out, NULL, NULL, dev);
}
dev->ems_io_base = 0x0208 + (dev->regs[0x4c] & 0xf0);
for (i = 0; i < 4; i++) {
io_handler(1, dev->ems_io_base + (i << 14), 1,
ct_82c100_ems_in, NULL, NULL, ct_82c100_ems_out, NULL, NULL, dev);
}
dev->ems_window_base = 0xc0000 + (((uint32_t) (dev->regs[0x4c] & 0x0f)) << 14);
ct_82c100_ems_pages_recalc(dev);
}
static void
ct_82c100_reset(void *priv)
{
ct_82c100_t *dev = (ct_82c100_t *) priv;
memset(dev->regs, 0x00, sizeof(dev->regs));
memset(dev->ems_page_regs, 0x00, sizeof(dev->ems_page_regs));
dev->index = dev->access = 0x00;
/* INTERNAL CONFIGURATION/CONTROL REGISTERS */
dev->regs[0x40] = 0x01; /* Defaults to 8086/V30 mode. */
dev->regs[0x43] = 0x30;
dev->regs[0x48] = 0x01;
use_custom_nmi_vector = 0;
ct_82c100_ems_update(dev);
/* ADDITIONAL I/O REGISTERS */
}
static void
ct_82c100_out(uint16_t port, uint8_t val, void *priv)
{
ct_82c100_t *dev = (ct_82c100_t *) priv;
if (port == 0x0022) {
dev->index = val;
dev->access = 1;
} else if (port == 0x0023) {
if (dev->access) {
switch (dev->index) {
/* INTERNAL CONFIGURATION/CONTROL REGISTERS */
case 0x40:
dev->regs[0x40] = val & 0xc7;
/* TODO: Clock stuff - needs CPU speed change functionality that's
going to be implemented in 86box v4.0.
Bit 0 is 0 for 8088/V20 and 1 for 8086/V30. */
break;
case 0x41:
dev->regs[0x41] = val & 0xed;
/* TODO: Where is the Software Reset Function that's enabled by
setting bit 6 to 1? */
break;
case 0x42:
dev->regs[0x42] = val & 0x01;
break;
case 0x43:
dev->regs[0x43] = val;
break;
case 0x44:
dev->regs[0x44] = val;
custom_nmi_vector = (custom_nmi_vector & 0xffffff00) | ((uint32_t) val);
break;
case 0x45:
dev->regs[0x45] = val;
custom_nmi_vector = (custom_nmi_vector & 0xffff00ff) | (((uint32_t) val) << 8);
break;
case 0x46:
dev->regs[0x46] = val;
custom_nmi_vector = (custom_nmi_vector & 0xff00ffff) | (((uint32_t) val) << 16);
break;
case 0x47:
dev->regs[0x47] = val;
custom_nmi_vector = (custom_nmi_vector & 0x00ffffff) | (((uint32_t) val) << 24);
break;
case 0x48: case 0x49:
dev->regs[dev->index] = val;
break;
case 0x4b:
dev->regs[0x4b] = val;
use_custom_nmi_vector = !!(val & 0x40);
break;
case 0x4c:
dev->regs[0x4c] = val;
ct_82c100_ems_update(dev);
break;
}
dev->access = 0;
}
} else if (port == 0x72)
dev->regs[0x72] = val & 0x7e;
else if (port == 0x7e)
dev->regs[0x7e] = val;
else if (port == 0x7f) {
/* Bit 3 is Software Controlled Reset, asserted if set. Will be
done in the feature/machine_and_kb branch using hardresetx86(). */
dev->regs[0x7f] = val;
if ((dev->regs[0x41] & 0x40) && (val & 0x08)) {
softresetx86();
cpu_set_edx();
ct_82c100_reset(dev);
}
}
}
static uint8_t
ct_82c100_in(uint16_t port, void *priv)
{
ct_82c100_t *dev = (ct_82c100_t *) priv;
uint8_t ret = 0xff;
if (port == 0x0022)
ret = dev->index;
else if (port == 0x0023) {
if (dev->access) {
switch (dev->index) {
/* INTERNAL CONFIGURATION/CONTROL REGISTERS */
case 0x40 ... 0x49:
case 0x4b: case 0x4c:
ret = dev->regs[dev->index];
break;
}
dev->access = 0;
}
} else if (port == 0x72)
ret = dev->regs[0x72];
else if (port == 0x7e)
ret = dev->regs[0x7e];
else if (port == 0x7f)
ret = dev->regs[0x7f];
return ret;
}
static uint8_t
mem_read_emsb(uint32_t addr, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
uint8_t val = 0xff;
addr = addr - page->virt + page->phys;
if (addr < ((uint32_t)mem_size << 10))
val = ram[addr];
return val;
}
static uint16_t
mem_read_emsw(uint32_t addr, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
uint16_t val = 0xffff;
addr = addr - page->virt + page->phys;
if (addr < ((uint32_t)mem_size << 10))
val = *(uint16_t *)&ram[addr];
return val;
}
static void
mem_write_emsb(uint32_t addr, uint8_t val, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
addr = addr - page->virt + page->phys;
if (addr < ((uint32_t)mem_size << 10))
ram[addr] = val;
}
static void
mem_write_emsw(uint32_t addr, uint16_t val, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
addr = addr - page->virt + page->phys;
if (addr < ((uint32_t)mem_size << 10))
*(uint16_t *)&ram[addr] = val;
}
static void
ct_82c100_close(void *priv)
{
ct_82c100_t *dev = (ct_82c100_t *) priv;
free(dev);
}
static void *
ct_82c100_init(const device_t *info)
{
ct_82c100_t *dev;
uint32_t i;
dev = (ct_82c100_t *)malloc(sizeof(ct_82c100_t));
memset(dev, 0x00, sizeof(ct_82c100_t));
ct_82c100_reset(dev);
io_sethandler(0x0022, 2,
ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev);
io_sethandler(0x0072, 1,
ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev);
io_sethandler(0x007e, 2,
ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev);
for (i = 0; i < 4; i++) {
mem_mapping_add(&(dev->ems_mappings[i]), (i + 28) << 14, 0x04000,
mem_read_emsb, mem_read_emsw, NULL,
mem_write_emsb, mem_write_emsw, NULL,
ram + 0xa0000 + (i << 14), MEM_MAPPING_INTERNAL, &dev->ems_pages[i]);
mem_mapping_disable(&(dev->ems_mappings[i]));
}
mem_mapping_disable(&ram_mid_mapping);
device_add(&port_92_device);
return(dev);
}
const device_t ct_82c100_device = {
"C&T 82C100",
0,
0,
ct_82c100_init, ct_82c100_close, ct_82c100_reset,
{ NULL }, NULL, NULL,
NULL
};

View File

@ -13,7 +13,7 @@
# Copyright 2020,2021 David Hrdlička.
#
add_library(chipset OBJECT acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c et6000.c headland.c
add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1217.c ali1429.c ali1489.c et6000.c headland.c
intel_82335.c cs4031.c intel_420ex.c intel_4x0.c intel_sio.c intel_piix.c ../ioapic.c
neat.c opti283.c opti291.c opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c
sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c sis_5598.c

View File

@ -38,6 +38,10 @@
/* Is the CPU 8088 or 8086. */
int is8086 = 0;
uint8_t use_custom_nmi_vector = 0;
uint32_t custom_nmi_vector = 0x00000000;
/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */
static uint8_t pfq[6];
@ -578,6 +582,9 @@ reset_808x(int hard)
prefetching = 1;
cpu_alu_op = 0;
use_custom_nmi_vector = 0x00;
custom_nmi_vector = 0x00000000;
}
@ -943,6 +950,41 @@ interrupt(uint16_t addr)
}
static void
custom_nmi(void)
{
uint16_t old_cs, old_ip;
uint16_t new_cs, new_ip;
uint16_t tempf;
cpu_state.eaaddr = 0x0002;
old_cs = CS;
access(5, 16);
(void) readmemw(0, cpu_state.eaaddr);
new_ip = custom_nmi_vector & 0xffff;
wait(1, 0);
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
access(6, 16);
(void) readmemw(0, cpu_state.eaaddr);
new_cs = custom_nmi_vector >> 16;
prefetching = 0;
pfq_clear();
ovr_seg = NULL;
access(39, 16);
tempf = cpu_state.flags & 0x0fd7;
push(&tempf);
cpu_state.flags &= ~(I_FLAG | T_FLAG);
access(40, 16);
push(&old_cs);
old_ip = cpu_state.pc;
load_cs(new_cs);
access(68, 16);
set_ip(new_ip);
access(41, 16);
push(&old_ip);
}
static int
irq_pending(void)
{
@ -967,7 +1009,10 @@ check_interrupts(void)
}
if (nmi && nmi_enable && nmi_mask) {
nmi_enable = 0;
interrupt(2);
if (use_custom_nmi_vector)
custom_nmi();
else
interrupt(2);
#ifndef OLD_NMI_BEHAVIOR
nmi = 0;
#endif

View File

@ -715,6 +715,9 @@ extern int reset_on_hlt, hlt_reset_pending;
extern cyrix_t cyrix;
extern uint8_t use_custom_nmi_vector;
extern uint32_t custom_nmi_vector;
extern void (*cpu_exec)(int cycs);
extern uint8_t do_translate, do_translate2;

View File

@ -37,6 +37,7 @@ extern const device_t ali6117d_device;
extern const device_t amd640_device;
/* C&T */
extern const device_t ct_82c100_device;
extern const device_t neat_device;
extern const device_t scat_device;
extern const device_t scat_4_device;
@ -65,6 +66,7 @@ extern const device_t i420zx_device;
extern const device_t i430lx_device;
extern const device_t i430nx_device;
extern const device_t i430fx_device;
extern const device_t i430fx_old_device;
extern const device_t i430fx_rev02_device;
extern const device_t i430hx_device;
extern const device_t i430vx_device;
@ -84,6 +86,7 @@ extern const device_t sio_device;
extern const device_t sio_zb_device;
extern const device_t piix_device;
extern const device_t piix_old_device;
extern const device_t piix_rev02_device;
extern const device_t piix3_device;
extern const device_t piix4_device;

View File

@ -43,6 +43,7 @@
#include <86box/fdc.h>
#include <86box/fdc_ext.h>
#include <86box/keyboard.h>
#include <86box/chipset.h>
#include <86box/sio.h>
#include <86box/video.h>
@ -69,6 +70,7 @@ machine_v86p_init(const machine_t *model)
machine_common_init(model);
device_add(&ct_82c100_device);
device_add(&f82c606_device);
device_add(&keyboard_xt_device);

View File

@ -20,6 +20,6 @@ void nmi_write(uint16_t port, uint8_t val, void *p)
void nmi_init(void)
{
io_sethandler(0x00a0, 0x0001, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL);
io_sethandler(0x00a0, 0x000f, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL);
nmi_mask = 0;
}

View File

@ -620,7 +620,7 @@ CPUOBJ := $(DYNARECOBJ) \
808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o \
x86seg.o x87.o x87_timings.o
CHIPSETOBJ := acc2168.o cs8230.o ali1217.o ali1429.o ali1489.o et6000.o headland.o intel_82335.o cs4031.o \
CHIPSETOBJ := 82c100.o acc2168.o cs8230.o ali1217.o ali1429.o ali1489.o et6000.o headland.o intel_82335.o cs4031.o \
intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \
neat.o opti495.o opti822.o opti895.o opti5x7.o scamp.o scat.o via_vt82c49x.o via_vt82c505.o \
gc100.o \