Added the C&T 82C100 chipset needed by the Victor V86P.
This commit is contained in:
parent
c107fde4e5
commit
0c4003caa3
352
src/chipset/82c100.c
Normal file
352
src/chipset/82c100.c
Normal 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
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user