Added the IBM 5161 ISA expansion for PC and XT;

Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g  / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
This commit is contained in:
OBattler
2019-09-20 14:02:30 +02:00
parent b06296bbf6
commit 552a87ea3d
524 changed files with 129555 additions and 21862 deletions

171
src/chipset/acc2168.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* 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 ACC 2168 chipset
* used by the Packard Bell Legend 760 Supreme (PB410A or PB430).
*
* Version: @(#)acc2168.c 1.0.0 2019/05/13
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
*
* Copyright 2019 Sarah Walker.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../timer.h"
#include "../device.h"
#include "../keyboard.h"
#include "../io.h"
#include "../mem.h"
#include "../mouse.h"
#include "../port_92.h"
#include "../sio.h"
#include "../disk/hdc.h"
#include "../video/video.h"
#include "../video/vid_ht216.h"
#include "chipset.h"
typedef struct acc2168_t
{
int reg_idx;
uint8_t regs[256];
uint8_t port_78;
} acc2168_t;
static void
acc2168_shadow_recalc(acc2168_t *dev)
{
if (dev->regs[0x02] & 8) {
switch (dev->regs[0x02] & 0x30) {
case 0x00:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 0x10:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
case 0x20:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 0x30:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
}
} else
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
if (dev->regs[0x02] & 4) {
switch (dev->regs[0x02] & 0x30) {
case 0x00:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 0x10:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
case 0x20:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 0x30:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
}
} else
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
static void
acc2168_write(uint16_t addr, uint8_t val, void *p)
{
acc2168_t *dev = (acc2168_t *)p;
if (!(addr & 1))
dev->reg_idx = val;
else {
dev->regs[dev->reg_idx] = val;
switch (dev->reg_idx) {
case 0x02:
acc2168_shadow_recalc(dev);
break;
}
}
}
static uint8_t
acc2168_read(uint16_t addr, void *p)
{
acc2168_t *dev = (acc2168_t *)p;
if (!(addr & 1))
return dev->reg_idx;
return dev->regs[dev->reg_idx];
}
/*
Bit 7 = Super I/O chip: 1 = enabled, 0 = disabled;
Bit 6 = Graphics card: 1 = standalone, 0 = on-board;
Bit 5 = ???? (if 1, siren and hangs).
*/
static uint8_t
acc2168_port_78_read(uint16_t addr, void *p)
{
acc2168_t *dev = (acc2168_t *)p;
return dev->port_78;
}
static void
acc2168_close(void *priv)
{
acc2168_t *dev = (acc2168_t *) priv;
free(dev);
}
static void *
acc2168_init(const device_t *info)
{
acc2168_t *dev = (acc2168_t *)malloc(sizeof(acc2168_t));
memset(dev, 0, sizeof(acc2168_t));
io_sethandler(0x00f2, 0x0002,
acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, dev);
io_sethandler(0x0078, 0x0001,
acc2168_port_78_read, NULL, NULL, NULL, NULL, NULL, dev);
device_add(&port_92_inv_device);
if (gfxcard != VID_INTERNAL)
dev->port_78 = 0x40;
else
dev->port_78 = 0;
return dev;
}
const device_t acc2168_device = {
"ACC 2168",
0,
0,
acc2168_init, acc2168_close, NULL,
NULL, NULL, NULL,
NULL
};

97
src/chipset/acer_m3a.c Normal file
View File

@@ -0,0 +1,97 @@
/*
* 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 Acer M3A and V35N ports EAh and EBh.
*
* Version: @(#)acer_m3a.c 1.0.0 2019/05/13
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../mem.h"
#include "../io.h"
#include "../rom.h"
#include "../pci.h"
#include "../device.h"
#include "../keyboard.h"
#include "chipset.h"
typedef struct
{
int index;
} acerm3a_t;
static void
acerm3a_out(uint16_t port, uint8_t val, void *p)
{
acerm3a_t *dev = (acerm3a_t *) p;
if (port == 0xea)
dev->index = val;
}
static uint8_t
acerm3a_in(uint16_t port, void *p)
{
acerm3a_t *dev = (acerm3a_t *) p;
if (port == 0xeb) {
switch (dev->index) {
case 2:
return 0xfd;
}
}
return 0xff;
}
static void
acerm3a_close(void *p)
{
acerm3a_t *dev = (acerm3a_t *)p;
free(dev);
}
static void
*acerm3a_init(const device_t *info)
{
acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t));
memset(acerm3a, 0, sizeof(acerm3a_t));
io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a);
return acerm3a;
}
const device_t acerm3a_device =
{
"Acer M3A Register",
0,
0,
acerm3a_init,
acerm3a_close,
NULL,
NULL,
NULL,
NULL,
NULL
};

146
src/chipset/ali1429.c Normal file
View File

@@ -0,0 +1,146 @@
/*
* 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 ALi M-1429/1431 chipset.
*
* Version: @(#)ali1429.c 1.0.8 2019/04/08
*
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../timer.h"
#include "../io.h"
#include "../mem.h"
#include "../device.h"
#include "../keyboard.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../disk/hdc.h"
#include "../disk/hdc_ide.h"
#include "../timer.h"
#include "../port_92.h"
#include "chipset.h"
typedef struct
{
uint8_t cur_reg,
regs[256];
} ali1429_t;
static void
ali1429_recalc(ali1429_t *dev)
{
uint32_t base;
uint32_t i, shflags = 0;
shadowbios = 0;
shadowbios_write = 0;
for (i = 0; i < 8; i++) {
base = 0xc0000 + (i << 15);
if (dev->regs[0x13] & (1 << i)) {
shadowbios |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x01);
shadowbios_write |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x02);
shflags = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL;
shflags |= !(dev->regs[0x14] & 0x02) ? MEM_WRITE_EXTERNAL : MEM_WRITE_INTERNAL;
mem_set_mem_state(base, 0x8000, shflags);
} else
mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
flushmmucache();
}
static void
ali1429_write(uint16_t port, uint8_t val, void *priv)
{
ali1429_t *dev = (ali1429_t *) priv;
if (port & 1) {
dev->regs[dev->cur_reg] = val;
switch (dev->cur_reg) {
case 0x13:
ali1429_recalc(dev);
break;
case 0x14:
ali1429_recalc(dev);
break;
}
} else
dev->cur_reg = val;
}
static uint8_t
ali1429_read(uint16_t port, void *priv)
{
uint8_t ret = 0xff;
ali1429_t *dev = (ali1429_t *) priv;
if (!(port & 1))
ret = dev->cur_reg;
else if (((dev->cur_reg >= 0xc0) || (dev->cur_reg == 0x20)) && cpu_iscyrix)
ret = 0xff; /*Don't conflict with Cyrix config registers*/
else
ret = dev->regs[dev->cur_reg];
return ret;
}
static void
ali1429_close(void *priv)
{
ali1429_t *dev = (ali1429_t *) priv;
free(dev);
}
static void *
ali1429_init(const device_t *info)
{
ali1429_t *dev = (ali1429_t *) malloc(sizeof(ali1429_t));
memset(dev, 0, sizeof(ali1429_t));
memset(dev->regs, 0xff, 256);
dev->regs[0x13] = dev->regs[0x14] = 0x00;
io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev);
ali1429_recalc(dev);
device_add(&port_92_device);
return dev;
}
const device_t ali1429_device = {
"ALi-M1429",
0,
0,
ali1429_init, ali1429_close, NULL,
NULL, NULL, NULL,
NULL
};

68
src/chipset/chipset.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* 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.
*
* Handling of the emulated chipsets.
*
* Version: @(#)machine.h 1.0.0 2019/05/13
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2019 Miran Grca.
*/
#ifndef EMU_CHIPSET_H
# define EMU_CHIPSET_H
/* ACC */
extern const device_t acc2168_device;
/* Acer M3A and V35N */
extern const device_t acerm3a_device;
/* ALi */
extern const device_t ali1429_device;
/* Headland */
extern const device_t headland_device;
extern const device_t headland_386_device;
/* Intel 4x0xX */
extern const device_t i420tx_device;
extern const device_t i430lx_device;
extern const device_t i430nx_device;
extern const device_t i430fx_device;
extern const device_t i430fx_pb640_device;
extern const device_t i430hx_device;
extern const device_t i430vx_device;
#if defined(DEV_BRANCH) && defined(USE_I686)
extern const device_t i440fx_device;
#endif
/* NEAT */
extern const device_t neat_device;
/* OPTi */
extern const device_t opti495_device;
/* SCAT */
extern const device_t scat_device;
extern const device_t scat_4_device;
extern const device_t scat_sx_device;
/* SiS */
extern const device_t sis_85c471_device;
extern const device_t sis_85c496_device;
#if defined(DEV_BRANCH) && defined(USE_SIS_85C50X)
extern const device_t sis_85c50x_device;
#endif
/* WD */
extern const device_t wd76c10_device;
#endif /*EMU_CHIPSET_H*/

635
src/chipset/headland.c Normal file
View File

@@ -0,0 +1,635 @@
/*
* 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 HEADLAND AT286 chipset.
*
* Version: @(#)headland.c 1.0.0 2019/05/14
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Fred N. van Kempen, <decwiz@yahoo.com>
* Original by GreatPsycho for PCem.
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2010-2019 Sarah Walker.
* Copyright 2017-2019 Fred N. van Kempen.
* Copyright 2017,2018 Miran Grca.
* Copyright 2017,2018 GreatPsycho.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../cpu/x86.h"
#include "../timer.h"
#include "../io.h"
#include "../mem.h"
#include "../rom.h"
#include "../device.h"
#include "../keyboard.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../port_92.h"
#include "chipset.h"
typedef struct {
uint8_t valid, pad;
uint16_t mr;
struct headland_t * headland;
} headland_mr_t;
typedef struct headland_t {
uint8_t type;
uint8_t cri;
uint8_t cr[8];
uint8_t indx;
uint8_t regs[256];
uint8_t ems_mar;
headland_mr_t null_mr,
ems_mr[64];
rom_t vid_bios;
mem_mapping_t low_mapping;
mem_mapping_t ems_mapping[64];
mem_mapping_t mid_mapping;
mem_mapping_t high_mapping;
mem_mapping_t upper_mapping[24];
} headland_t;
/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet,
so memory configuration is hardcoded now. */
static const int mem_conf_cr0[41] = {
0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0,
0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0,
0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0,
0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0,
0xE0
};
static const int mem_conf_cr1[41] = {
0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x40
};
static uint32_t
get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr)
{
if (mr && mr->valid && (dev->cr[0] & 2) && (mr->mr & 0x200)) {
addr = (addr & 0x3fff) | ((mr->mr & 0x1F) << 14);
if (dev->cr[1] & 0x40) {
if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) {
if (dev->cr[0] & 0x80) {
addr |= (mr->mr & 0x60) << 14;
if (mr->mr & 0x100)
addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x80) << 15);
else
addr += (mr->mr & 0x80) << 14;
} else if (mr->mr & 0x100)
addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x20) << 15);
else
addr += (mr->mr & 0x80) << 12;
} else if (dev->cr[0] & 0x80)
addr |= (mr->mr & 0x100) ? ((mr->mr & 0x80) + 0x400) << 12 : (mr->mr & 0xE0) << 14;
else
addr |= (mr->mr & 0x100) ? ((mr->mr & 0xE0) + 0x40) << 14 : (mr->mr & 0x80) << 12;
} else {
if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) {
if (dev->cr[0] & 0x80) {
addr |= ((mr->mr & 0x60) << 14);
if (mr->mr & 0x180)
addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x180) - 0x60) << 16);
} else
addr |= ((mr->mr & 0x60) << 14) | ((mr->mr & 0x180) << 16) | ((mr->mr & 0xC00) << 13);
} else if (dev->cr[0] & 0x80)
addr |= (mr->mr & 0x1E0) << 14;
else
addr |= (mr->mr & 0x180) << 12;
}
} else if ((mr == NULL) && ((dev->cr[0] & 4) == 0) && (mem_size >= 1024) && (addr >= 0x100000))
addr -= 0x60000;
return addr;
}
static void
set_global_EMS_state(headland_t *dev, int state)
{
uint32_t base_addr, virt_addr;
int i;
for (i = 0; i < 32; i++) {
base_addr = (i + 16) << 14;
if (i >= 24)
base_addr += 0x20000;
if ((state & 2) && (dev->ems_mr[((state & 1) << 5) | i].mr & 0x200)) {
virt_addr = get_addr(dev, base_addr, &dev->ems_mr[((state & 1) << 5) | i]);
if (i < 24)
mem_mapping_disable(&dev->upper_mapping[i]);
mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]);
mem_mapping_enable(&dev->ems_mapping[((state & 1) << 5) | i]);
if (virt_addr < ((uint32_t)mem_size << 10))
mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + virt_addr);
else
mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], NULL);
} else {
mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + base_addr);
mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]);
mem_mapping_disable(&dev->ems_mapping[((state & 1) << 5) | i]);
if (i < 24)
mem_mapping_enable(&dev->upper_mapping[i]);
}
}
flushmmucache();
}
static void
memmap_state_update(headland_t *dev)
{
uint32_t addr;
int i;
for (i = 0; i < 24; i++) {
addr = get_addr(dev, 0x40000 + (i << 14), NULL);
mem_mapping_set_exec(&dev->upper_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL);
}
mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
if (mem_size > 640) {
if ((dev->cr[0] & 4) == 0) {
mem_mapping_set_addr(&dev->mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10);
mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000);
if (mem_size > 1024) {
mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10);
mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000);
}
} else {
mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10);
mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000);
if (mem_size > 1024) {
mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10);
mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000);
}
}
}
set_global_EMS_state(dev, dev->cr[0] & 3);
}
static void
hl_write(uint16_t addr, uint8_t val, void *priv)
{
headland_t *dev = (headland_t *)priv;
uint32_t base_addr, virt_addr;
uint8_t old_val, indx;
switch(addr) {
case 0x0022:
dev->indx = val;
break;
case 0x0023:
old_val = dev->regs[dev->indx];
if ((dev->indx == 0xc1) && !is486)
val = 0;
dev->regs[dev->indx] = val;
if (dev->indx == 0x82) {
shadowbios = val & 0x10;
shadowbios_write = !(val & 0x10);
if (shadowbios)
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
else
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
} else if (dev->indx == 0x87) {
if ((val & 1) && !(old_val & 1))
softresetx86();
}
break;
case 0x01ec:
dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00;
indx = dev->ems_mar & 0x1f;
base_addr = (indx + 16) << 14;
if (indx >= 24)
base_addr += 0x20000;
if ((dev->cr[0] & 2) && ((dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5))) {
virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3F]);
if (indx < 24)
mem_mapping_disable(&dev->upper_mapping[indx]);
if (virt_addr < ((uint32_t)mem_size << 10))
mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr);
else
mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL);
mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]);
flushmmucache();
}
if (dev->ems_mar & 0x80)
dev->ems_mar++;
break;
case 0x01ed:
dev->cri = val;
break;
case 0x01ee:
dev->ems_mar = val;
break;
case 0x01ef:
old_val = dev->cr[dev->cri];
switch(dev->cri) {
case 0:
dev->cr[0] = (val & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
mem_set_mem_state(0xe0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED);
mem_set_mem_state(0xf0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED);
memmap_state_update(dev);
break;
case 1:
dev->cr[1] = (val & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
memmap_state_update(dev);
break;
case 2:
case 3:
case 5:
dev->cr[dev->cri] = val;
memmap_state_update(dev);
break;
case 4:
dev->cr[4] = (dev->cr[4] & 0xf0) | (val & 0x0f);
if (val & 1) {
mem_mapping_set_addr(&bios_mapping, 0x000f0000, 0x10000);
mem_mapping_set_exec(&bios_mapping, &(rom[0x10000]));
} else {
mem_mapping_set_addr(&bios_mapping, 0x000e0000, 0x20000);
mem_mapping_set_exec(&bios_mapping, rom);
}
break;
case 6:
if (dev->cr[4] & 0x80) {
dev->cr[dev->cri] = (val & 0xfe) | (mem_size > 8192 ? 1 : 0);
memmap_state_update(dev);
}
break;
default:
break;
}
break;
default:
break;
}
}
static void
hl_writew(uint16_t addr, uint16_t val, void *priv)
{
headland_t *dev = (headland_t *)priv;
uint32_t base_addr, virt_addr;
uint8_t indx;
switch(addr) {
case 0x01ec:
dev->ems_mr[dev->ems_mar & 0x3f].mr = val;
indx = dev->ems_mar & 0x1f;
base_addr = (indx + 16) << 14;
if (indx >= 24)
base_addr += 0x20000;
if ((dev->cr[0] & 2) && (dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5)) {
if (val & 0x200) {
virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3f]);
if (indx < 24)
mem_mapping_disable(&dev->upper_mapping[indx]);
if (virt_addr < ((uint32_t)mem_size << 10))
mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr);
else
mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL);
mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]);
} else {
mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + base_addr);
mem_mapping_disable(&dev->ems_mapping[dev->ems_mar & 0x3f]);
if (indx < 24)
mem_mapping_enable(&dev->upper_mapping[indx]);
}
flushmmucache();
}
if (dev->ems_mar & 0x80)
dev->ems_mar++;
break;
default:
break;
}
}
static uint8_t
hl_read(uint16_t addr, void *priv)
{
headland_t *dev = (headland_t *)priv;
uint8_t ret = 0xff;
switch(addr) {
case 0x0022:
ret = dev->indx;
break;
case 0x0023:
if ((dev->indx >= 0xc0 || dev->indx == 0x20) && cpu_iscyrix)
ret = 0xff; /*Don't conflict with Cyrix config registers*/
else
ret = dev->regs[dev->indx];
break;
case 0x01ec:
ret = (uint8_t)dev->ems_mr[dev->ems_mar & 0x3f].mr;
if (dev->ems_mar & 0x80)
dev->ems_mar++;
break;
case 0x01ed:
ret = dev->cri;
break;
case 0x01ee:
ret = dev->ems_mar;
break;
case 0x01ef:
switch(dev->cri) {
case 0:
ret = (dev->cr[0] & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
break;
case 1:
ret = (dev->cr[1] & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
break;
case 6:
if (dev->cr[4] & 0x80)
ret = (dev->cr[6] & 0xfe) | (mem_size > 8192 ? 1 : 0);
else
ret = 0;
break;
default:
ret = dev->cr[dev->cri];
break;
}
break;
default:
break;
}
return ret;
}
static uint16_t
hl_readw(uint16_t addr, void *priv)
{
headland_t *dev = (headland_t *)priv;
uint16_t ret = 0xffff;
switch(addr) {
case 0x01ec:
ret = dev->ems_mr[dev->ems_mar & 0x3f].mr | ((dev->cr[4] & 0x80) ? 0xf000 : 0xfc00);
if (dev->ems_mar & 0x80)
dev->ems_mar++;
break;
default:
break;
}
return ret;
}
static uint8_t
mem_read_b(uint32_t addr, void *priv)
{
headland_mr_t *mr = (headland_mr_t *) priv;
headland_t *dev = mr->headland;
uint8_t ret = 0xff;
addr = get_addr(dev, addr, mr);
if (addr < ((uint32_t)mem_size << 10))
ret = ram[addr];
return ret;
}
static uint16_t
mem_read_w(uint32_t addr, void *priv)
{
headland_mr_t *mr = (headland_mr_t *) priv;
headland_t *dev = mr->headland;
uint16_t ret = 0xffff;
addr = get_addr(dev, addr, mr);
if (addr < ((uint32_t)mem_size << 10))
ret = *(uint16_t *)&ram[addr];
return ret;
}
static uint32_t
mem_read_l(uint32_t addr, void *priv)
{
headland_mr_t *mr = (headland_mr_t *) priv;
headland_t *dev = mr->headland;
uint32_t ret = 0xffffffff;
addr = get_addr(dev, addr, mr);
if (addr < ((uint32_t)mem_size << 10))
ret = *(uint32_t *)&ram[addr];
return ret;
}
static void
mem_write_b(uint32_t addr, uint8_t val, void *priv)
{
headland_mr_t *mr = (headland_mr_t *) priv;
headland_t *dev = mr->headland;
addr = get_addr(dev, addr, mr);
if (addr < ((uint32_t)mem_size << 10))
ram[addr] = val;
}
static void
mem_write_w(uint32_t addr, uint16_t val, void *priv)
{
headland_mr_t *mr = (headland_mr_t *) priv;
headland_t *dev = mr->headland;
addr = get_addr(dev, addr, mr);
if (addr < ((uint32_t)mem_size << 10))
*(uint16_t *)&ram[addr] = val;
}
static void
mem_write_l(uint32_t addr, uint32_t val, void *priv)
{
headland_mr_t *mr = (headland_mr_t *) priv;
headland_t *dev = mr->headland;
addr = get_addr(dev, addr, mr);
if (addr < ((uint32_t)mem_size << 10))
*(uint32_t *)&ram[addr] = val;
}
static void
headland_close(void *priv)
{
headland_t *dev = (headland_t *)priv;
free(dev);
}
static void *
headland_init(const device_t *info)
{
headland_t *dev;
int ht386;
uint32_t i;
dev = (headland_t *) malloc(sizeof(headland_t));
memset(dev, 0x00, sizeof(headland_t));
dev->type = info->local;
ht386 = (dev->type == 32) ? 1 : 0;
for (i = 0; i < 8; i++)
dev->cr[i] = 0x00;
dev->cr[0] = 0x04;
if (ht386) {
dev->cr[4] = 0x20;
device_add(&port_92_inv_device);
} else
dev->cr[4] = 0x00;
io_sethandler(0x01ec, 1,
hl_read,hl_readw,NULL, hl_write,hl_writew,NULL, dev);
io_sethandler(0x01ed, 3, hl_read,NULL,NULL, hl_write,NULL,NULL, dev);
dev->ems_mr[i].valid = 0;
dev->ems_mr[i].mr = 0xff;
dev->ems_mr[i].headland = dev;
for (i = 0; i < 64; i++) {
dev->ems_mr[i].valid = 1;
dev->ems_mr[i].mr = 0x00;
dev->ems_mr[i].headland = dev;
}
/* Turn off mem.c mappings. */
mem_mapping_disable(&ram_low_mapping);
mem_mapping_disable(&ram_mid_mapping);
mem_mapping_disable(&ram_high_mapping);
mem_mapping_add(&dev->low_mapping, 0, 0x40000,
mem_read_b, mem_read_w, mem_read_l,
mem_write_b, mem_write_w, mem_write_l,
ram, MEM_MAPPING_INTERNAL, &dev->null_mr);
if (mem_size > 640) {
mem_mapping_add(&dev->mid_mapping, 0xa0000, 0x60000,
mem_read_b, mem_read_w, mem_read_l,
mem_write_b, mem_write_w, mem_write_l,
ram + 0xa0000, MEM_MAPPING_INTERNAL, &dev->null_mr);
mem_mapping_enable(&dev->mid_mapping);
}
if (mem_size > 1024) {
mem_mapping_add(&dev->high_mapping, 0x100000, ((mem_size-1024)*1024),
mem_read_b, mem_read_w, mem_read_l,
mem_write_b, mem_write_w, mem_write_l,
ram + 0x100000, MEM_MAPPING_INTERNAL, &dev->null_mr);
mem_mapping_enable(&dev->high_mapping);
}
for (i = 0; i < 24; i++) {
mem_mapping_add(&dev->upper_mapping[i],
0x40000 + (i << 14), 0x4000,
mem_read_b, mem_read_w, mem_read_l,
mem_write_b, mem_write_w, mem_write_l,
mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL,
MEM_MAPPING_INTERNAL, &dev->null_mr);
mem_mapping_enable(&dev->upper_mapping[i]);
}
for (i = 0; i < 64; i++) {
dev->ems_mr[i].mr = 0x00;
mem_mapping_add(&dev->ems_mapping[i],
((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000,
mem_read_b, mem_read_w, mem_read_l,
mem_write_b, mem_write_w, mem_write_l,
ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14),
0, &dev->ems_mr[i]);
}
memmap_state_update(dev);
return(dev);
}
const device_t headland_device = {
"Headland 286",
0,
0,
headland_init, headland_close, NULL,
NULL, NULL, NULL,
NULL
};
const device_t headland_386_device = {
"Headland 386",
0,
32,
headland_init, headland_close, NULL,
NULL, NULL, NULL,
NULL
};

433
src/chipset/intel_4x0.c Normal file
View File

@@ -0,0 +1,433 @@
/*
* 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 Intel PCISet chips from 420TX to 440FX.
*
* Version: @(#)intel_4x0.c 1.0.0 2019/05/13
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../mem.h"
#include "../io.h"
#include "../rom.h"
#include "../pci.h"
#include "../device.h"
#include "../keyboard.h"
#include "chipset.h"
enum
{
INTEL_420TX,
INTEL_430LX,
INTEL_430NX,
INTEL_430FX,
INTEL_430FX_PB640,
INTEL_430HX,
INTEL_430VX
#if defined(DEV_BRANCH) && defined(USE_I686)
,INTEL_440FX
#endif
};
typedef struct
{
uint8_t regs[256];
int type;
} i4x0_t;
static void
i4x0_map(uint32_t addr, uint32_t size, int state)
{
switch (state & 3) {
case 0:
mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 1:
mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
case 2:
mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
flushmmucache_nopc();
}
static void
i4x0_write(int func, int addr, uint8_t val, void *priv)
{
i4x0_t *dev = (i4x0_t *) priv;
if (func)
return;
if ((addr >= 0x10) && (addr < 0x4f))
return;
switch (addr) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0e:
return;
case 0x04: /*Command register*/
if (dev->type >= INTEL_430FX) {
if (dev->type == INTEL_430FX_PB640)
val &= 0x06;
else
val &= 0x02;
} else
val &= 0x42;
val |= 0x04;
break;
case 0x05:
if (dev->type >= INTEL_430FX)
val = 0;
else
val &= 0x01;
break;
case 0x06: /*Status*/
val = 0;
break;
case 0x07:
if (dev->type >= INTEL_430HX) {
val &= 0x80;
val |= 0x02;
} else {
val = 0x02;
if (dev->type == INTEL_430FX_PB640)
val |= 0x20;
}
break;
case 0x59: /*PAM0*/
if ((dev->regs[0x59] ^ val) & 0xf0) {
i4x0_map(0xf0000, 0x10000, val >> 4);
shadowbios = (val & 0x10);
}
break;
case 0x5a: /*PAM1*/
if ((dev->regs[0x5a] ^ val) & 0x0f)
i4x0_map(0xc0000, 0x04000, val & 0xf);
if ((dev->regs[0x5a] ^ val) & 0xf0)
i4x0_map(0xc4000, 0x04000, val >> 4);
break;
case 0x5b: /*PAM2*/
if ((dev->regs[0x5b] ^ val) & 0x0f)
i4x0_map(0xc8000, 0x04000, val & 0xf);
if ((dev->regs[0x5b] ^ val) & 0xf0)
i4x0_map(0xcc000, 0x04000, val >> 4);
break;
case 0x5c: /*PAM3*/
if ((dev->regs[0x5c] ^ val) & 0x0f)
i4x0_map(0xd0000, 0x04000, val & 0xf);
if ((dev->regs[0x5c] ^ val) & 0xf0)
i4x0_map(0xd4000, 0x04000, val >> 4);
break;
case 0x5d: /*PAM4*/
if ((dev->regs[0x5d] ^ val) & 0x0f)
i4x0_map(0xd8000, 0x04000, val & 0xf);
if ((dev->regs[0x5d] ^ val) & 0xf0)
i4x0_map(0xdc000, 0x04000, val >> 4);
break;
case 0x5e: /*PAM5*/
if ((dev->regs[0x5e] ^ val) & 0x0f)
i4x0_map(0xe0000, 0x04000, val & 0xf);
if ((dev->regs[0x5e] ^ val) & 0xf0)
i4x0_map(0xe4000, 0x04000, val >> 4);
break;
case 0x5f: /*PAM6*/
if ((dev->regs[0x5f] ^ val) & 0x0f)
i4x0_map(0xe8000, 0x04000, val & 0xf);
if ((dev->regs[0x5f] ^ val) & 0xf0)
i4x0_map(0xec000, 0x04000, val >> 4);
break;
case 0x72: /*SMRAM*/
if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48))
i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0);
else if ((dev->type < INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x20))
i4x0_map(0xa0000, 0x20000, ((val & 0x20) == 0x20) ? 3 : 0);
break;
}
dev->regs[addr] = val;
}
static uint8_t
i4x0_read(int func, int addr, void *priv)
{
i4x0_t *dev = (i4x0_t *) priv;
if (func)
return 0xff;
return dev->regs[addr];
}
static void
i4x0_reset(void *priv)
{
i4x0_t *i4x0 = (i4x0_t *)priv;
i4x0_write(0, 0x59, 0x00, priv);
if (i4x0->type >= INTEL_430FX)
i4x0_write(0, 0x72, 0x02, priv);
}
static void
i4x0_close(void *p)
{
i4x0_t *i4x0 = (i4x0_t *)p;
free(i4x0);
}
static void
*i4x0_init(const device_t *info)
{
i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t));
memset(i4x0, 0, sizeof(i4x0_t));
i4x0->type = info->local;
i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/
switch(i4x0->type) {
case INTEL_420TX:
i4x0->regs[0x02] = 0x83; i4x0->regs[0x03] = 0x04; /*82424TX/ZX*/
i4x0->regs[0x08] = 0x03; /*A3 stepping*/
i4x0->regs[0x50] = 0x80;
i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/
break;
case INTEL_430LX:
i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/
i4x0->regs[0x08] = 0x03; /*A3 stepping*/
i4x0->regs[0x50] = 0x80;
i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/
break;
case INTEL_430NX:
i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/
i4x0->regs[0x08] = 0x10; /*A0 stepping*/
i4x0->regs[0x50] = 0xA0;
i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/
i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02;
break;
case INTEL_430FX:
case INTEL_430FX_PB640:
i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/
if (i4x0->type == INTEL_430FX_PB640)
i4x0->regs[0x08] = 0x02; /*???? stepping*/
else
i4x0->regs[0x08] = 0x00; /*A0 stepping*/
i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/
break;
case INTEL_430HX:
i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/
i4x0->regs[0x08] = 0x00; /*A0 stepping*/
i4x0->regs[0x51] = 0x20;
i4x0->regs[0x52] = 0xB5; /*512kb cache*/
i4x0->regs[0x56] = 0x52; /*DRAM control*/
i4x0->regs[0x59] = 0x40;
i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44;
i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44;
i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02;
i4x0->regs[0x68] = 0x11;
break;
case INTEL_430VX:
i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/
i4x0->regs[0x08] = 0x00; /*A0 stepping*/
i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/
i4x0->regs[0x53] = 0x14;
i4x0->regs[0x56] = 0x52; /*DRAM control*/
i4x0->regs[0x67] = 0x11;
i4x0->regs[0x69] = 0x03;
i4x0->regs[0x70] = 0x20;
i4x0->regs[0x74] = 0x0e;
i4x0->regs[0x78] = 0x23;
break;
#if defined(DEV_BRANCH) && defined(USE_I686)
case INTEL_440FX:
i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/
i4x0->regs[0x08] = 0x02; /*A0 stepping*/
i4x0->regs[0x2c] = 0xf4;
i4x0->regs[0x2d] = 0x1a;
i4x0->regs[0x2f] = 0x11;
i4x0->regs[0x51] = 0x01;
i4x0->regs[0x53] = 0x80;
i4x0->regs[0x58] = 0x10;
i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11;
i4x0->regs[0x5e] = 0x11;
i4x0->regs[0x5f] = 0x31;
break;
#endif
}
i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00;
#if defined(DEV_BRANCH) && defined(USE_I686)
if (i4x0->type == INTEL_440FX)
i4x0->regs[0x06] = 0x80;
#endif
if (i4x0->type == INTEL_430FX)
i4x0->regs[0x07] = 0x82;
#if defined(DEV_BRANCH) && defined(USE_I686)
else if (i4x0->type != INTEL_440FX)
#else
else
#endif
i4x0->regs[0x07] = 0x02;
i4x0->regs[0x0b] = 0x06;
if (i4x0->type >= INTEL_430FX)
i4x0->regs[0x57] = 0x01;
else
i4x0->regs[0x57] = 0x31;
i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02;
i4x0->regs[0x64] = 0x02;
if (i4x0->type >= INTEL_430FX)
i4x0->regs[0x72] = 0x02;
pci_add_card(0, i4x0_read, i4x0_write, i4x0);
return i4x0;
}
const device_t i420tx_device =
{
"Intel 82424TX",
DEVICE_PCI,
INTEL_420TX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
const device_t i430lx_device =
{
"Intel 82434LX",
DEVICE_PCI,
INTEL_430LX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
const device_t i430nx_device =
{
"Intel 82434NX",
DEVICE_PCI,
INTEL_430NX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
const device_t i430fx_device =
{
"Intel SB82437FX-66",
DEVICE_PCI,
INTEL_430FX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
const device_t i430fx_pb640_device =
{
"Intel SB82437FX-66 (PB640)",
DEVICE_PCI,
INTEL_430FX_PB640,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
const device_t i430hx_device =
{
"Intel 82439HX",
DEVICE_PCI,
INTEL_430HX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
const device_t i430vx_device =
{
"Intel 82437VX",
DEVICE_PCI,
INTEL_430VX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
#if defined(DEV_BRANCH) && defined(USE_I686)
const device_t i440fx_device =
{
"Intel 82441FX",
DEVICE_PCI,
INTEL_440FX,
i4x0_init,
i4x0_close,
i4x0_reset,
NULL,
NULL,
NULL,
NULL
};
#endif

861
src/chipset/neat.c Normal file
View File

@@ -0,0 +1,861 @@
/*
* 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.
*
* Emulation of C&T CS8121 ("NEAT") 82C206/211/212/215 chipset.
*
* Note: The datasheet mentions that the chipset supports up to 8MB
* of DRAM. This is intepreted as 'being able to refresh up to
* 8MB of DRAM chips', because it works fine with bus-based
* memory expansion.
*
* Version: @(#)m_at_neat.c 1.0.5 2018/10/22
*
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2018 Fred N. van Kempen.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../device.h"
#include "../timer.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../keyboard.h"
#include "../io.h"
#include "../mem.h"
#include "../nmi.h"
#include "chipset.h"
#define NEAT_DEBUG 0
#define EMS_MAXPAGE 4
#define EMS_PGSIZE 16384
/* CS8221 82C211 controller registers. */
#define REG_RA0 0x60 /* PROCCLK selector */
# define RA0_MASK 0x34 /* RR11 X1XR */
# define RA0_READY 0x01 /* local bus READY timeout */
# define RA0_RDYNMIEN 0x04 /* local bus READY tmo NMI enable */
# define RA0_PROCCLK 0x10 /* PROCCLK=BCLK (1) or CLK2IN (0) */
# define RA0_ALTRST 0x20 /* alternate CPU reset (1) */
# define RA0_REV 0xc0 /* chip revision ID */
# define RA0_REV_SH 6
# define RA0_REV_ID 2 /* faked revision# for 82C211 */
#define REG_RA1 0x61 /* Command Delay */
# define RA1_MASK 0xff /* 1111 1111 */
# define RA1_BUSDLY 0x03 /* AT BUS command delay */
# define RA1_BUSDLY_SH 0
# define RA1_BUS8DLY 0x0c /* AT BUS 8bit command delay */
# define RA1_BUS8DLY_SH 2
# define RA1_MEMDLY 0x30 /* AT BUS 16bit memory delay */
# define RA1_MEMDLY_SH 4
# define RA1_QUICKEN 0x40 /* Quick Mode enable */
# define RA1_HOLDDLY 0x80 /* Hold Time Delay */
#define REG_RA2 0x62 /* Wait State / BCLK selector */
# define RA2_MASK 0x3f /* XX11 1111 */
# define RA2_BCLK 0x03 /* BCLK select */
# define RA2_BCLK_SH 0
# define BCLK_IN2 0 /* BCLK = CLK2IN/2 */
# define BCLK_IN 1 /* BCLK = CLK2IN */
# define BCLK_AT 2 /* BCLK = ATCLK */
# define RA2_AT8WS 0x0c /* AT 8-bit wait states */
# define RA2_AT8WS_SH 2
# define AT8WS_2 0 /* 2 wait states */
# define AT8WS_3 1 /* 3 wait states */
# define AT8WS_4 2 /* 4 wait states */
# define AT8WS_5 4 /* 5 wait states */
# define RA2_ATWS 0x30 /* AT 16-bit wait states */
# define RA2_ATWS_SH 4
# define ATWS_2 0 /* 2 wait states */
# define ATWS_3 1 /* 3 wait states */
# define ATWS_4 2 /* 4 wait states */
# define ATWS_5 4 /* 5 wait states */
/* CS8221 82C212 controller registers. */
#define REG_RB0 0x64 /* Version ID */
# define RB0_MASK 0x60 /* R11X XXXX */
# define RB0_REV 0x60 /* Chip revsion number */
# define RB0_REV_SH 5
# define RB0_REV_ID 2 /* faked revision# for 82C212 */
# define RB0_VERSION 0x80 /* Chip version (0=82C212) */
#define REG_RB1 0x65 /* ROM configuration */
# define RB1_MASK 0xff /* 1111 1111 */
# define RB1_ROMF0 0x01 /* ROM F0000 enabled (0) */
# define RB1_ROME0 0x02 /* ROM E0000 disabled (1) */
# define RB1_ROMD0 0x04 /* ROM D0000 disabled (1) */
# define RB1_ROMC0 0x08 /* ROM C0000 disabled (1) */
# define RB1_SHADOWF0 0x10 /* Shadow F0000 R/W (0) */
# define RB1_SHADOWE0 0x20 /* Shadow E0000 R/W (0) */
# define RB1_SHADOWD0 0x40 /* Shadow D0000 R/W (0) */
# define RB1_SHADOWC0 0x80 /* Shadow C0000 R/W (0) */
#define REG_RB2 0x66 /* Memory Enable 1 */
# define RB2_MASK 0x80 /* 1XXX XXXX */
# define RB2_TOP128 0x80 /* top 128K is on sysboard (1) */
#define REG_RB3 0x67 /* Memory Enable 2 */
# define RB3_MASK 0xff /* 1111 1111 */
# define RB3_SHENB0 0x01 /* enable B0000-B3FFF shadow (1) */
# define RB3_SHENB4 0x02 /* enable B4000-B7FFF shadow (1) */
# define RB3_SHENB8 0x04 /* enable B8000-BBFFF shadow (1) */
# define RB3_SHENBC 0x08 /* enable BC000-BFFFF shadow (1) */
# define RB3_SHENA0 0x10 /* enable A0000-A3FFF shadow (1) */
# define RB3_SHENA4 0x20 /* enable A4000-A7FFF shadow (1) */
# define RB3_SHENA8 0x40 /* enable A8000-ABFFF shadow (1) */
# define RB3_SHENAC 0x80 /* enable AC000-AFFFF shadow (1) */
#define REG_RB4 0x68 /* Memory Enable 3 */
# define RB4_MASK 0xff /* 1111 1111 */
# define RB4_SHENC0 0x01 /* enable C0000-C3FFF shadow (1) */
# define RB4_SHENC4 0x02 /* enable C4000-C7FFF shadow (1) */
# define RB4_SHENC8 0x04 /* enable C8000-CBFFF shadow (1) */
# define RB4_SHENCC 0x08 /* enable CC000-CFFFF shadow (1) */
# define RB4_SHEND0 0x10 /* enable D0000-D3FFF shadow (1) */
# define RB4_SHEND4 0x20 /* enable D4000-D7FFF shadow (1) */
# define RB4_SHEND8 0x40 /* enable D8000-DBFFF shadow (1) */
# define RB4_SHENDC 0x80 /* enable DC000-DFFFF shadow (1) */
#define REG_RB5 0x69 /* Memory Enable 4 */
# define RB5_MASK 0xff /* 1111 1111 */
# define RB5_SHENE0 0x01 /* enable E0000-E3FFF shadow (1) */
# define RB5_SHENE4 0x02 /* enable E4000-E7FFF shadow (1) */
# define RB5_SHENE8 0x04 /* enable E8000-EBFFF shadow (1) */
# define RB5_SHENEC 0x08 /* enable EC000-EFFFF shadow (1) */
# define RB5_SHENF0 0x10 /* enable F0000-F3FFF shadow (1) */
# define RB5_SHENF4 0x20 /* enable F4000-F7FFF shadow (1) */
# define RB5_SHENF8 0x40 /* enable F8000-FBFFF shadow (1) */
# define RB5_SHENFC 0x80 /* enable FC000-FFFFF shadow (1) */
#define REG_RB6 0x6a /* Bank 0/1 Enable */
# define RB6_MASK 0xe0 /* 111R RRRR */
# define RB6_BANKS 0x20 /* #banks used (1=two) */
# define RB6_RTYPE 0xc0 /* DRAM chip size used */
# define RTYPE_SH 6
# define RTYPE_NONE 0 /* Disabled */
# define RTYPE_MIXED 1 /* 64K/256K mixed (for 640K) */
# define RTYPE_256K 2 /* 256K (default) */
# define RTYPE_1M 3 /* 1M */
#define REG_RB7 0x6b /* DRAM configuration */
# define RB7_MASK 0xff /* 1111 1111 */
# define RB7_ROMWS 0x03 /* ROM access wait states */
# define RB7_ROMWS_SH 0
# define ROMWS_0 0 /* 0 wait states */
# define ROMWS_1 1 /* 1 wait states */
# define ROMWS_2 2 /* 2 wait states */
# define ROMWS_3 3 /* 3 wait states (default) */
# define RB7_EMSWS 0x0c /* EMS access wait states */
# define RB7_EMSWS_SH 2
# define EMSWS_0 0 /* 0 wait states */
# define EMSWS_1 1 /* 1 wait states */
# define EMSWS_2 2 /* 2 wait states */
# define EMSWS_3 3 /* 3 wait states (default) */
# define RB7_EMSEN 0x10 /* enable EMS (1=on) */
# define RB7_RAMWS 0x20 /* RAM access wait state (1=1ws) */
# define RB7_UMAREL 0x40 /* relocate 640-1024K to 1M */
# define RB7_PAGEEN 0x80 /* enable Page/Interleaved mode */
#define REG_RB8 0x6c /* Bank 2/3 Enable */
# define RB8_MASK 0xf0 /* 1111 RRRR */
# define RB8_4WAY 0x10 /* enable 4-way interleave mode */
# define RB8_BANKS 0x20 /* enable 2 banks (1) */
# define RB8_RTYPE 0xc0 /* DRAM chip size used */
# define RB8_RTYPE_SH 6
#define REG_RB9 0x6d /* EMS base address */
# define RB9_MASK 0xff /* 1111 1111 */
# define RB9_BASE 0x0f /* I/O base address selection */
# define RB9_BASE_SH 0
# define RB9_FRAME 0xf0 /* frame address selection */
# define RB9_FRAME_SH 4
#define REG_RB10 0x6e /* EMS address extension */
# define RB10_MASK 0xff /* 1111 1111 */
# define RB10_P3EXT 0x03 /* page 3 extension */
# define RB10_P3EXT_SH 0
# define PEXT_0M 0 /* page is at 0-2M */
# define PEXT_2M 1 /* page is at 2-4M */
# define PEXT_4M 2 /* page is at 4-6M */
# define PEXT_6M 3 /* page is at 6-8M */
# define RB10_P2EXT 0x0c /* page 2 extension */
# define RB10_P2EXT_SH 2
# define RB10_P1EXT 0x30 /* page 1 extension */
# define RB10_P1EXT_SH 4
# define RB10_P0EXT 0xc0 /* page 0 extension */
# define RB10_P0EXT_SH 6
#define REG_RB11 0x6f /* Miscellaneous */
# define RB11_MASK 0xe6 /* 111R R11R */
# define RB11_GA20 0x02 /* gate for A20 */
# define RB11_RASTMO 0x04 /* enable RAS timeout counter */
# define RB11_EMSLEN 0xe0 /* EMS memory chunk size */
# define RB11_EMSLEN_SH 5
typedef struct {
int8_t enabled; /* 1=ENABLED */
char pad;
uint16_t page; /* selected page in EMS block */
uint32_t start; /* start of EMS in RAM */
uint8_t *addr; /* start addr in EMS RAM */
mem_mapping_t mapping; /* mapping entry for page */
} emspage_t;
typedef struct {
uint8_t regs[128]; /* all the CS8221 registers */
uint8_t indx; /* programmed index into registers */
char pad;
uint16_t ems_base, /* configured base address */
ems_oldbase;
uint32_t ems_frame, /* configured frame address */
ems_oldframe;
uint16_t ems_size, /* EMS size in KB */
ems_pages; /* EMS size in pages */
emspage_t ems[EMS_MAXPAGE]; /* EMS page registers */
} neat_t;
#ifdef ENABLE_NEAT_LOG
int neat_do_log = ENABLE_NEAT_LOG;
static void
neat_log(const char *fmt, ...)
{
va_list ap;
if (neat_do_log)
{
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define neat_log(fmt, ...)
#endif
/* Read one byte from paged RAM. */
static uint8_t
ems_readb(uint32_t addr, void *priv)
{
mem_mapping_t *map = (mem_mapping_t *)priv;
neat_t *dev = (neat_t *)map->dev;
uint8_t ret = 0xff;
int vpage;
/* Get the viewport page number. */
vpage = ((addr & 0xffff) / EMS_PGSIZE);
/* Grab the data. */
ret = *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base));
return(ret);
}
/* Read one word from paged RAM. */
static uint16_t
ems_readw(uint32_t addr, void *priv)
{
mem_mapping_t *map = (mem_mapping_t *)priv;
neat_t *dev = (neat_t *)map->dev;
uint16_t ret = 0xffff;
int vpage;
/* Get the viewport page number. */
vpage = ((addr & 0xffff) / EMS_PGSIZE);
/* Grab the data. */
ret = *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base));
return(ret);
}
/* Write one byte to paged RAM. */
static void
ems_writeb(uint32_t addr, uint8_t val, void *priv)
{
mem_mapping_t *map = (mem_mapping_t *)priv;
neat_t *dev = (neat_t *)map->dev;
int vpage;
/* Get the viewport page number. */
vpage = ((addr & 0xffff) / EMS_PGSIZE);
/* Write the data. */
*(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = val;
}
/* Write one word to paged RAM. */
static void
ems_writew(uint32_t addr, uint16_t val, void *priv)
{
mem_mapping_t *map = (mem_mapping_t *)priv;
neat_t *dev = (neat_t *)map->dev;
int vpage;
/* Get the viewport page number. */
vpage = ((addr & 0xffff) / EMS_PGSIZE);
/* Write the data. */
*(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val;
}
/* Re-calculate the active-page physical address. */
static void
ems_recalc(neat_t *dev, emspage_t *ems)
{
if (ems->page >= dev->ems_pages) {
/* That page does not exist. */
ems->enabled = 0;
}
/* Pre-calculate the page address in EMS RAM. */
ems->addr = ram + ems->start + (ems->page * EMS_PGSIZE);
if (ems->enabled) {
/* Update the EMS RAM address for this page. */
mem_mapping_set_exec(&ems->mapping, ems->addr);
/* Enable this page. */
mem_mapping_enable(&ems->mapping);
#if NEAT_DEBUG > 1
neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n",
ems->page, ems->addr-ram, ems->enabled?"en":"dis");
#endif
} else {
/* Disable this page. */
mem_mapping_disable(&ems->mapping);
}
}
static void
ems_write(uint16_t port, uint8_t val, void *priv)
{
neat_t *dev = (neat_t *)priv;
emspage_t *ems;
int vpage;
#if NEAT_DEBUG > 1
neat_log("NEAT: ems_write(%04x, %02x)\n", port, val);
#endif
/* Get the viewport page number. */
vpage = (port / EMS_PGSIZE);
ems = &dev->ems[vpage];
switch(port & 0x000f) {
case 0x0008:
case 0x0009:
ems->enabled = !!(val & 0x80);
ems->page &= 0x0180; /* clear lower bits */
ems->page |= (val & 0x7f); /* add new bits */
ems_recalc(dev, ems);
break;
}
}
static uint8_t
ems_read(uint16_t port, void *priv)
{
neat_t *dev = (neat_t *)priv;
uint8_t ret = 0xff;
int vpage;
/* Get the viewport page number. */
vpage = (port / EMS_PGSIZE);
switch(port & 0x000f) {
case 0x0008: /* page number register */
ret = dev->ems[vpage].page & 0x7f;
if (dev->ems[vpage].enabled)
ret |= 0x80;
break;
}
#if NEAT_DEBUG > 1
neat_log("NEAT: ems_read(%04x) = %02x\n", port, ret);
#endif
return(ret);
}
/* Initialize the EMS module. */
static void
ems_init(neat_t *dev, int en)
{
int i;
/* Remove if needed. */
if (! en) {
if (dev->ems_base > 0) for (i = 0; i < EMS_MAXPAGE; i++) {
/* Disable for now. */
mem_mapping_disable(&dev->ems[i].mapping);
/* Remove I/O handler. */
io_removehandler(dev->ems_base + (i * EMS_PGSIZE), 2,
ems_read,NULL,NULL, ems_write,NULL,NULL, dev);
}
#ifdef ENABLE_NEAT_LOG
neat_log("NEAT: EMS disabled\n");
#endif
return;
}
/* Get configured I/O address. */
i = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH;
dev->ems_base = 0x0208 + (0x10 * i);
/* Get configured frame address. */
i = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH;
dev->ems_frame = 0xC0000 + (EMS_PGSIZE * i);
/*
* For each supported page (we can have a maximum of 4),
* create, initialize and disable the mappings, and set
* up the I/O control handler.
*/
for (i = 0; i < EMS_MAXPAGE; i++) {
/* Create and initialize a page mapping. */
mem_mapping_add(&dev->ems[i].mapping,
dev->ems_frame + (EMS_PGSIZE*i), EMS_PGSIZE,
ems_readb, ems_readw, NULL,
ems_writeb, ems_writew, NULL,
ram, MEM_MAPPING_EXTERNAL,
&dev->ems[i].mapping);
mem_mapping_set_dev(&dev->ems[i].mapping, dev);
/* Disable for now. */
mem_mapping_disable(&dev->ems[i].mapping);
/* Set up an I/O port handler. */
io_sethandler(dev->ems_base + (i * EMS_PGSIZE), 2,
ems_read,NULL,NULL, ems_write,NULL,NULL, dev);
/*
* TODO: update the 'high_mem' mapping to reflect that we now
* have NN MB less extended memory available..
*/
}
neat_log("NEAT: EMS enabled, I/O=%04xH, Frame=%05XH\n",
dev->ems_base, dev->ems_frame);
}
static void
neat_write(uint16_t port, uint8_t val, void *priv)
{
neat_t *dev = (neat_t *)priv;
uint8_t xval, *reg;
int i;
#if NEAT_DEBUG > 2
neat_log("NEAT: write(%04x, %02x)\n", port, val);
#endif
switch (port) {
case 0x22:
dev->indx = val;
break;
case 0x23:
reg = &dev->regs[dev->indx];
xval = *reg ^ val;
switch (dev->indx) {
case REG_RA0:
val &= RA0_MASK;
*reg = (*reg & ~RA0_MASK) | val | \
(RA0_REV_ID << RA0_REV_SH);
#if NEAT_DEBUG > 1
neat_log("NEAT: RA0=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RA1:
val &= RA1_MASK;
*reg = (*reg & ~RA1_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RA1=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RA2:
val &= RA2_MASK;
*reg = (*reg & ~RA2_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RA2=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB0:
val &= RB0_MASK;
*reg = (*reg & ~RB0_MASK) | val | \
(RB0_REV_ID << RB0_REV_SH);
#if NEAT_DEBUG > 1
neat_log("NEAT: RB0=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB1:
val &= RB1_MASK;
*reg = (*reg & ~RB1_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB2:
val &= RB2_MASK;
*reg = (*reg & ~RB2_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB3:
val &= RB3_MASK;
*reg = (*reg & ~RB3_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB4:
val &= RB4_MASK;
*reg = (*reg & ~RB4_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB5:
val &= RB5_MASK;
*reg = (*reg & ~RB5_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB6:
val &= RB6_MASK;
*reg = (*reg & ~RB6_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB6=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB7:
val &= RB7_MASK;
*reg = (*reg & ~RB7_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg);
#endif
if (val & RB7_EMSEN)
ems_init(dev, 1);
else if (xval & RB7_EMSEN)
ems_init(dev, 0);
if (xval & RB7_UMAREL) {
if (val & RB7_UMAREL)
mem_remap_top(384);
else
mem_remap_top(0);
}
break;
case REG_RB8:
val &= RB8_MASK;
*reg = (*reg & ~RB8_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB8=%02x(%02x)\n", val, *reg);
#endif
break;
case REG_RB9:
val &= RB9_MASK;
*reg = (*reg & ~RB9_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg);
#endif
if (dev->regs[REG_RB7] & RB7_EMSEN) {
ems_init(dev, 0);
ems_init(dev, 1);
}
break;
case REG_RB10:
val &= RB10_MASK;
*reg = (*reg & ~RB10_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg);
#endif
dev->ems[3].start = ((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21;
dev->ems[2].start = ((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21;
dev->ems[1].start = ((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21;
dev->ems[0].start = ((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21;
for (i = 0; i < EMS_MAXPAGE; i++)
ems_recalc(dev, &dev->ems[i]);
break;
case REG_RB11:
val &= RB11_MASK;
*reg = (*reg & ~RB11_MASK) | val;
#if NEAT_DEBUG > 1
neat_log("NEAT: RB11=%02x(%02x)\n", val, *reg);
#endif
i = (val & RB11_EMSLEN) >> RB11_EMSLEN_SH;
switch(i) {
case 0: /* "less than 2MB" */
dev->ems_size = 512;
break;
case 1: /* 1 MB */
case 2: /* 2 MB */
case 3: /* 3 MB */
case 4: /* 4 MB */
case 5: /* 5 MB */
case 6: /* 6 MB */
case 7: /* 7 MB */
dev->ems_size = i << 10;
break;
}
dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE;
if (dev->regs[REG_RB7] & RB7_EMSEN) {
neat_log("NEAT: EMS %iKB (%i pages)\n",
dev->ems_size, dev->ems_pages);
}
break;
default:
neat_log("NEAT: inv write to reg %02x (%02x)\n",
dev->indx, val);
break;
}
break;
}
}
static uint8_t
neat_read(uint16_t port, void *priv)
{
neat_t *dev = (neat_t *)priv;
uint8_t ret = 0xff;
switch (port) {
case 0x22:
ret = dev->indx;
break;
case 0x23:
ret = dev->regs[dev->indx];
break;
default:
break;
}
#if NEAT_DEBUG > 2
neat_log("NEAT: read(%04x) = %02x\n", port, ret);
#endif
return(ret);
}
static void
neat_close(void *priv)
{
neat_t *dev = (neat_t *) priv;
free(dev);
}
static void *
neat_init(const device_t *info)
{
neat_t *dev;
int i;
/* Create an instance. */
dev = (neat_t *)malloc(sizeof(neat_t));
memset(dev, 0x00, sizeof(neat_t));
/* Initialize some of the registers to specific defaults. */
for (i = REG_RA0; i <= REG_RB11; i++) {
dev->indx = i;
neat_write(0x0023, 0x00, dev);
}
/*
* Based on the value of mem_size, we have to set up
* a proper DRAM configuration (so that EMS works.)
*
* TODO: We might also want to set 'valid' waitstate
* bits, based on our cpu speed.
*/
i = 0;
switch(mem_size) {
case 512: /* 512KB */
/* 256K, 0, 0, 0 */
dev->regs[REG_RB6] &= ~RB6_BANKS; /* one bank */
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
i = 2;
break;
case 640: /* 640KB */
/* 256K, 64K, 0, 0 */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_MIXED<<RTYPE_SH); /* mixed */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
i = 4;
break;
case 1024: /* 1MB */
/* 256K, 256K, 0, 0 */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
i = 5;
break;
case 1536: /* 1.5MB */
/* 256K, 256K, 256K, 0 */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
i = 7;
break;
case 1664: /* 1.64MB */
/* 256K, 64K, 256K, 256K */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_MIXED<<RTYPE_SH); /* mixed */
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
dev->regs[REG_RB8] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
i = 10;
break;
case 2048: /* 2MB */
#if 1
/* 256K, 256K, 256K, 256K */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
dev->regs[REG_RB8] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] |= RB8_4WAY; /* 4way intl */
i = 11;
#else
/* 1M, 0, 0, 0 */
dev->regs[REG_RB6] &= ~RB6_BANKS; /* one bank */
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
i = 3;
#endif
break;
case 3072: /* 3MB */
/* 256K, 256K, 1M, 0 */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
i = 8;
break;
case 4096: /* 4MB */
/* 1M, 1M, 0, 0 */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
i = 6;
break;
case 4224: /* 4.64MB */
/* 256K, 64K, 1M, 1M */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_MIXED<<RTYPE_SH); /* mixed */
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
i = 12;
break;
case 5120: /* 5MB */
/* 256K, 256K, 1M, 1M */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
i = 13;
break;
case 6144: /* 6MB */
/* 1M, 1M, 1M, 0 */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
i = 9;
break;
case 8192: /* 8MB */
/* 1M, 1M, 1M, 1M */
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
dev->regs[REG_RB8] |= RB8_4WAY; /* 4way intl */
i = 14;
break;
default:
neat_log("NEAT: **INVALID DRAM SIZE %iKB !**\n", mem_size);
}
if (i > 0) {
neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", i, mem_size);
}
/* Set up an I/O handler for the chipset. */
io_sethandler(0x0022, 2,
neat_read,NULL,NULL, neat_write,NULL,NULL, dev);
return dev;
}
const device_t neat_device = {
"C&T CS8121 (NEAT)",
0,
0,
neat_init, neat_close, NULL,
NULL, NULL, NULL,
NULL
};

369
src/chipset/opti495.c Normal file
View File

@@ -0,0 +1,369 @@
/*OPTi 82C495 emulation
This is the chipset used in the AMI386 model
Details for the chipset from Ralph Brown's interrupt list
This describes the OPTi 82C493, the 82C495 seems similar except there is one
more register (2C)
----------P00220024--------------------------
PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS
Desc: The OPTi 486SXWB contains three chips and is designed for systems
running at 20, 25 and 33MHz. The chipset includes an 82C493 System
Controller (SYSC), the 82C392 Data Buffer Controller, and the
82C206 Integrated peripheral Controller (IPC).
Note: every access to PORT 0024h must be preceded by a write to PORT 0022h,
even if the same register is being accessed a second time
SeeAlso: PORT 0022h"82C206"
0022 ?W configuration register index (see #P0178)
0024 RW configuration register data
(Table P0178)
Values for OPTi 82C493 System Controller configuration register index:
20h Control Register 1 (see #P0179)
21h Control Register 2 (see #P0180)
22h Shadow RAM Control Register 1 (see #P0181)
23h Shadow RAM Control Register 2 (see #P0182)
24h DRAM Control Register 1 (see #P0183)
25h DRAM Control Register 2 (see #P0184)
26h Shadow RAM Control Register 3 (see #P0185)
27h Control Register 3 (see #P0186)
28h Non-cachable Block 1 Register 1 (see #P0187)
29h Non-cachable Block 1 Register 2 (see #P0188)
2Ah Non-cachable Block 2 Register 1 (see #P0187)
2Bh Non-cachable Block 2 Register 2 (see #P0188)
Bitfields for OPTi-82C493 Control Register 1:
Bit(s) Description (Table P0179)
7-6 Revision of 82C493 (readonly) (default=01)
5 Burst wait state control
1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2
0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default)
(if bit 5 is set to 1, bit 4 must be set to 0)
4 Cache memory data buffer output enable control
0 = disable (default)
1 = enable
(must be disabled for frequency <= 33Mhz)
3 Single Address Latch Enable (ALE)
0 = disable (default)
1 = enable
(if enabled, SYSC will activate single ALE rather than multiples
during bus conversion cycles)
2 enable Extra AT Cycle Wait State (default is 0 = disabled)
1 Emulation keyboard Reset Control
0 = disable (default)
1 = enable
Note: This bit must be enabled in BIOS default value; enabling this
bit requires HALT instruction to be executed before SYSC
generates processor reset (CPURST)
0 enable Alternative Fast Reset (default is 0 = disabled)
SeeAlso: #P0180,#P0186
Bitfields for OPTi-82C493 Control Register 2:
Bit(s) Description (Table P0180)
7 Master Mode Byte Swap Enable
0 = disable (default)
1 = enable
6 Emulation Keyboard Reset Delay Control
0 = Generate reset pulse 2us later (default)
1 = Generate reset pulse immediately
5 disable Parity Check (default is 0 = enabled)
4 Cache Enable
0 = Cache disabled and DRAM burst mode enabled (default)
1 = Cache enabled and DRAM burst mode disabled
3-2 Cache Size
00 64KB (default)
01 128KB
10 256KB
11 512KB
1 Secondary Cache Read Burst Cycles Control
0 = 3-1-1-1 cycle (default)
1 = 2-1-1-1 cycle
0 Cache Write Wait State Control
0 = 1 wait state (default)
1 = 0 wait state
SeeAlso: #P0179,#P0186
Bitfields for OPTi-82C493 Shadow RAM Control Register 1:
Bit(s) Description (Table P0181)
7 ROM(F0000h - FFFFFh) Enable
0 = read/write on write-protected DRAM
1 = read from ROM, write to DRAM (default)
6 Shadow RAM at D0000h - EFFFFh Area
0 = disable (default)
1 = enable
5 Shadow RAM at E0000h - EFFFFh Area
0 = disable shadow RAM (default)
E0000h - EFFFFh ROM is defaulted to reside on XD bus
1 = enable shadow RAM
4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area
0 = disable (default)
1 = enable
3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area
0 = disable (default)
1 = enable
2 Hidden refresh enable (with holding CPU)
(Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used)
1 = disable (default)
0 = enable
1 unused
0 enable Slow Refresh (four times slower than normal refresh)
(default is 0 = disable)
SeeAlso: #P0182
Bitfields for OPTi-82C493 Shadow RAM Control Register 2:
Bit(s) Description (Table P0182)
7 enable Shadow RAM at EC000h - EFFFFh area
6 enable Shadow RAM at E8000h - EBFFFh area
5 enable Shadow RAM at E4000h - E7FFFh area
4 enable Shadow RAM at E0000h - E3FFFh area
3 enable Shadow RAM at DC000h - DFFFFh area
2 enable Shadow RAM at D8000h - DBFFFh area
1 enable Shadow RAM at D4000h - D7FFFh area
0 enable Shadow RAM at D0000h - D3FFFh area
Note: the default is disabled (0) for all areas
Bitfields for OPTi-82C493 DRAM Control Register 1:
Bit(s) Description (Table P0183)
7 DRAM size
0 = 256K DRAM mode
1 = 1M and 4M DRAM mode
6-4 DRAM types used for bank0 and bank1
bits 7-4 Bank0 Bank1
0000 256K x
0001 256K 256K
0010 256K 1M
0011 x x
01xx x x
1000 1M x (default)
1001 1M 1M
1010 1M 4M
1011 4M 1M
1100 4M x
1101 4M 4M
111x x x
3 unused
2-0 DRAM types used for bank2 and bank3
bits 7,2-0 Bank2 Bank3
x000 1M x
x001 1M 1M
x010 x x
x011 4M 1M
x100 4M x
x101 4M 4M
x11x x x (default)
SeeAlso: #P0184
Bitfields for OPTi-82C493 DRAM Control Register 2:
Bit(s) Description (Table P0184)
7-6 Read cycle additional wait states
00 not used
01 = 0
10 = 1
11 = 2 (default)
5-4 Write cycle additional wait states
00 = 0
01 = 1
10 = 2
11 = 3 (default)
3 Fast decode enable
0 = disable fast decode. DRAM base wait states not changed (default)
1 = enable fast decode. DRAM base wait state is decreased by 1
Note: This function may be enabled in 20/25Mhz operation to speed up
DRAM access. If bit 4 of index register 21h (cache enable
bit) is enabled, this bit is automatically disabled--even if
set to 1
2 unused
1-0 ATCLK selection
00 ATCLK = CLKI/6 (default)
01 ATCLK = CLKI/4 (default)
10 ATCLK = CLKI/3
11 ATCLK = CLK2I/5 (CLKI * 2 /5)
Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be
set to 0 when 82C493 is reset.
SeeAlso: #P0183,#P0185
Bitfields for OPTi-82C493 Shadow RAM Control Register 3:
Bit(s) Description (Table P0185)
7 unused
6 Shadow RAM copy enable for address C0000h - CFFFFh
0 = Read/write at AT bus (default)
1 = Read from AT bus and write into shadow RAM
5 Shadow write protect at address C0000h - CFFFFh
0 = Write protect disable (default)
1 = Write protect enable
4 enable Shadow RAM at C0000h - CFFFFh
3 enable Shadow RAM at CC000h - CFFFFh
2 enable Shadow RAM at C8000h - CBFFFh
1 enable Shadow RAM at C4000h - C7FFFh
0 enable Shadow RAM at C0000h - C3FFFh
Note: the default is disabled (0) for bits 4-0
SeeAlso: #P0183,#P0184
Bitfields for OPTi-82C493 Control Register 3:
Bit(s) Description (Table P0186)
7 enable NCA# pin to low state (default is 1 = enabled)
6-5 unused
4 Video BIOS at C0000h - C8000h non-cacheable
0 = cacheable
1 = non-cacheable (default)
3-0 Cacheable address range for local memory
0000 0 - 64MB
0001 0 - 4MB (default)
0010 0 - 8MB
0011 0 - 12MB
0100 0 - 16MB
0101 0 - 20MB
0110 0 - 24MB
0111 0 - 28MB
1000 0 - 32MB
1001 0 - 36MB
1010 0 - 40MB
1011 0 - 44MB
1100 0 - 48MB
1101 0 - 52MB
1110 0 - 56MB
1111 0 - 60MB
Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or
0-2 MB and independent of the value of bits 3-0
SeeAlso: #P0179,#P0180
Bitfields for OPTi-82C493 Non-cacheable Block Register 1:
Bit(s) Description (Table P0187)
7-5 Size of non-cachable memory block
000 64K
001 128K
010 256K
011 512K
1xx disabled (default)
4-2 unused
1-0 Address bits 25 and 24 of non-cachable memory block (default = 00)
Note: this register is used together with configuration register 29h
(non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to
define a non-cacheable block. The starting address must be a
multiple of the block size
SeeAlso: #P0178,#P0188
Bitfields for OPTi-82C493 Non-cacheable Block Register 2:
Bit(s) Description (Table P0188)
7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx)
Note: the block address is forced to be a multiple of the block size by
ignoring the appropriate number of the least-significant bits
SeeAlso: #P0178,#P0187
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../timer.h"
#include "../io.h"
#include "../device.h"
#include "../keyboard.h"
#include "../mem.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "chipset.h"
typedef struct
{
uint8_t cur_reg,
regs[16],
scratch[2];
} opti495_t;
static void
opti495_write(uint16_t addr, uint8_t val, void *priv)
{
opti495_t *dev = (opti495_t *) priv;
switch (addr) {
case 0x22:
dev->cur_reg = val;
break;
case 0x24:
if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) {
dev->regs[dev->cur_reg - 0x20] = val;
if (dev->cur_reg == 0x21) {
cpu_cache_ext_enabled = val & 0x10;
cpu_update_waitstates();
}
if (dev->cur_reg == 0x22) {
if (!(val & 0x80))
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
else
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
}
}
break;
case 0xe1:
case 0xe2:
dev->scratch[addr - 0xe1] = val;
break;
}
}
static uint8_t
opti495_read(uint16_t addr, void *priv)
{
uint8_t ret = 0xff;
opti495_t *dev = (opti495_t *) priv;
switch (addr) {
case 0x24:
if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C))
ret = dev->regs[dev->cur_reg - 0x20];
break;
case 0xe1:
case 0xe2:
ret = dev->scratch[addr - 0xe1];
break;
}
return ret;
}
static void
opti495_close(void *priv)
{
opti495_t *dev = (opti495_t *) priv;
free(dev);
}
static void *
opti495_init(const device_t *info)
{
opti495_t *dev = (opti495_t *) malloc(sizeof(opti495_t));
memset(dev, 0, sizeof(opti495_t));
io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev);
io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev);
dev->scratch[0] = dev->scratch[1] = 0xff;
io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev);
dev->regs[0x22 - 0x20] = 0x80;
return dev;
}
const device_t opti495_device = {
"OPTi 82C495",
0,
0,
opti495_init, opti495_close, NULL,
NULL, NULL, NULL,
NULL
};

1630
src/chipset/scat.c Normal file

File diff suppressed because it is too large Load Diff

1642
src/chipset/scat_varcem.c Normal file

File diff suppressed because it is too large Load Diff

289
src/chipset/sis_85c471.c Normal file
View File

@@ -0,0 +1,289 @@
/*
* 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.
*
* Emulation of the SiS 85c471 chip.
*
* SiS sis85c471 Super I/O Chip
* Used by DTK PKM-0038S E-2
*
* Version: @(#)sis_85c471.c 1.0.0 2019/05/13
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <http://pcem-emulator.co.uk/>
*
* Copyright 2019 Miran Grca.
* Copyright 2008-2019 Sarah Walker.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../mem.h"
#include "../io.h"
#include "../lpt.h"
#include "../rom.h"
#include "../pci.h"
#include "../device.h"
#include "../disk/hdc_ide.h"
#include "../keyboard.h"
#include "../timer.h"
#include "../port_92.h"
#include "../serial.h"
#include "../machine/machine.h"
#include "chipset.h"
typedef struct {
uint8_t cur_reg,
regs[39],
scratch[2];
port_92_t * port_92;
} sis_85c471_t;
static void
sis_85c471_recalcmapping(sis_85c471_t *dev)
{
uint32_t base;
uint32_t i, shflags = 0;
shadowbios = 0;
shadowbios_write = 0;
for (i = 0; i < 8; i++) {
base = 0xc0000 + (i << 15);
if ((i > 5) || (dev->regs[0x02] & (1 << i))) {
shadowbios |= (base >= 0xe0000) && (dev->regs[0x02] & 0x80);
shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40);
shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL;
shflags |= (dev->regs[0x02] & 0x40) ? MEM_WRITE_EXTERNAL : MEM_WRITE_INTERNAL;
mem_set_mem_state(base, 0x8000, shflags);
} else
mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
flushmmucache();
}
static void
sis_85c471_write(uint16_t port, uint8_t val, void *priv)
{
sis_85c471_t *dev = (sis_85c471_t *) priv;
uint8_t valxor = 0x00;
if (port == 0x22) {
if ((val >= 0x50) && (val <= 0x76))
dev->cur_reg = val;
return;
} else if (port == 0x23) {
if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76))
return;
valxor = val ^ dev->regs[dev->cur_reg - 0x50];
dev->regs[dev->cur_reg - 0x50] = val;
} else if ((port == 0xe1) || (port == 0xe2)) {
dev->scratch[port - 0xe1] = val;
return;
}
switch(dev->cur_reg) {
case 0x52:
sis_85c471_recalcmapping(dev);
break;
case 0x57:
if (valxor & 0x12)
port_92_set_features(dev->port_92, !!(val & 0x10), !!(val & 0x02));
if (valxor & 0x08) {
if (val & 0x08)
port_92_set_period(dev->port_92, 6ULL * TIMER_USEC);
else
port_92_set_period(dev->port_92, 2ULL * TIMER_USEC);
}
break;
case 0x5b:
if (valxor & 0x02) {
if (val & 0x02)
mem_remap_top(0);
else
mem_remap_top(256);
}
break;
case 0x63:
if (valxor & 0x10) {
if (dev->regs[0x13] & 0x10)
mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
else
mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
break;
case 0x72:
if (valxor & 0x01) {
port_92_remove(dev->port_92);
if (val & 0x01)
port_92_add(dev->port_92);
}
break;
}
dev->cur_reg = 0;
}
static uint8_t
sis_85c471_read(uint16_t port, void *priv)
{
sis_85c471_t *dev = (sis_85c471_t *) priv;
uint8_t ret = 0xff;
if (port == 0x22)
ret = dev->cur_reg;
else if (port == 0x23) {
if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) {
ret = dev->regs[dev->cur_reg - 0x50];
if (dev->cur_reg == 0x58)
ret &= 0xf7;
dev->cur_reg = 0;
}
} else if ((port == 0xe1) || (port == 0xe2))
ret = dev->scratch[port - 0xe1];
return ret;
}
static void
sis_85c471_close(void *priv)
{
sis_85c471_t *dev = (sis_85c471_t *) priv;
free(dev);
}
static void *
sis_85c471_init(const device_t *info)
{
int mem_size_mb, i = 0;
sis_85c471_t *dev = (sis_85c471_t *) malloc(sizeof(sis_85c471_t));
memset(dev, 0, sizeof(sis_85c471_t));
dev->cur_reg = 0;
for (i = 0; i < 0x27; i++)
dev->regs[i] = 0x00;
dev->regs[9] = 0x40;
mem_size_mb = mem_size >> 10;
switch (mem_size_mb) {
case 0: case 1:
dev->regs[9] |= 0;
break;
case 2: case 3:
dev->regs[9] |= 1;
break;
case 4:
dev->regs[9] |= 2;
break;
case 5:
dev->regs[9] |= 0x20;
break;
case 6: case 7:
dev->regs[9] |= 9;
break;
case 8: case 9:
dev->regs[9] |= 4;
break;
case 10: case 11:
dev->regs[9] |= 5;
break;
case 12: case 13: case 14: case 15:
dev->regs[9] |= 0xB;
break;
case 16:
dev->regs[9] |= 0x13;
break;
case 17:
dev->regs[9] |= 0x21;
break;
case 18: case 19:
dev->regs[9] |= 6;
break;
case 20: case 21: case 22: case 23:
dev->regs[9] |= 0xD;
break;
case 24: case 25: case 26: case 27:
case 28: case 29: case 30: case 31:
dev->regs[9] |= 0xE;
break;
case 32: case 33: case 34: case 35:
dev->regs[9] |= 0x1B;
break;
case 36: case 37: case 38: case 39:
dev->regs[9] |= 0xF;
break;
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47:
dev->regs[9] |= 0x17;
break;
case 48:
dev->regs[9] |= 0x1E;
break;
default:
if (mem_size_mb < 64)
dev->regs[9] |= 0x1E;
else if ((mem_size_mb >= 65) && (mem_size_mb < 68))
dev->regs[9] |= 0x22;
else
dev->regs[9] |= 0x24;
break;
}
dev->regs[0x11] = 9;
dev->regs[0x12] = 0xFF;
dev->regs[0x1f] = 0x20; /* Video access enabled. */
dev->regs[0x23] = 0xF0;
dev->regs[0x26] = 1;
if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed < 25000000)
dev->regs[0x08] |= 0x80;
io_sethandler(0x0022, 0x0002,
sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev);
dev->scratch[0] = dev->scratch[1] = 0xff;
io_sethandler(0x00e1, 0x0002,
sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev);
dev->port_92 = device_add(&port_92_device);
port_92_set_period(dev->port_92, 2ULL * TIMER_USEC);
port_92_set_features(dev->port_92, 0, 0);
sis_85c471_recalcmapping(dev);
return dev;
}
const device_t sis_85c471_device = {
"SiS 85c471",
0,
0,
sis_85c471_init, sis_85c471_close, NULL,
NULL, NULL, NULL,
NULL
};

335
src/chipset/sis_85c496.c Normal file
View File

@@ -0,0 +1,335 @@
/*
* 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 SiS 85c496/85c497 chip.
*
* Version: @(#)sis_85c496.c 1.0.0 2019/05/13
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../mem.h"
#include "../io.h"
#include "../rom.h"
#include "../pci.h"
#include "../device.h"
#include "../keyboard.h"
#include "../timer.h"
#include "../port_92.h"
#include "../disk/hdc_ide.h"
#include "../machine/machine.h"
#include "chipset.h"
typedef struct sis_85c496_t
{
uint8_t cur_reg,
regs[127],
pci_conf[256];
port_92_t * port_92;
} sis_85c496_t;
static void
sis_85c497_write(uint16_t port, uint8_t val, void *priv)
{
sis_85c496_t *dev = (sis_85c496_t *) priv;
uint8_t index = (port & 1) ? 0 : 1;
if (index) {
if ((val != 0x01) || ((val >= 0x70) && (val <= 0x76)))
dev->cur_reg = val;
} else {
if (((dev->cur_reg < 0x70) && (dev->cur_reg != 0x01)) || (dev->cur_reg > 0x76))
return;
dev->regs[dev->cur_reg] = val;
dev->cur_reg = 0;
}
}
static uint8_t
sis_85c497_read(uint16_t port, void *priv)
{
sis_85c496_t *dev = (sis_85c496_t *) priv;
uint8_t index = (port & 1) ? 0 : 1;
uint8_t ret = 0xff;
if (index)
ret = dev->cur_reg;
else {
if ((dev->cur_reg != 0x01) || ((dev->cur_reg >= 0x70) && (dev->cur_reg <= 0x76))) {
ret = dev->regs[dev->cur_reg];
dev->cur_reg = 0;
}
}
return ret;
}
static void
sis_85c496_recalcmapping(sis_85c496_t *dev)
{
uint32_t base;
uint32_t i, shflags = 0;
shadowbios = 0;
shadowbios_write = 0;
for (i = 0; i < 8; i++) {
base = 0xc0000 + (i << 15);
if (dev->pci_conf[0x44] & (1 << i)) {
shadowbios |= (base >= 0xe0000) && (dev->pci_conf[0x45] & 0x02);
shadowbios_write |= (base >= 0xe0000) && !(dev->pci_conf[0x45] & 0x01);
shflags = (dev->pci_conf[0x45] & 0x02) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL;
shflags |= (dev->pci_conf[0x45] & 0x01) ? MEM_WRITE_EXTERNAL : MEM_WRITE_INTERNAL;
mem_set_mem_state(base, 0x8000, shflags);
} else
mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
flushmmucache();
}
/* 00 - 3F = PCI Configuration, 40 - 7F = 85C496, 80 - FF = 85C497 */
static void
sis_85c496_write(int func, int addr, uint8_t val, void *priv)
{
sis_85c496_t *dev = (sis_85c496_t *) priv;
uint8_t old = dev->pci_conf[addr];
uint8_t valxor;
if ((addr >= 4 && addr < 8) || addr >= 0x40)
dev->pci_conf[addr] = val;
valxor = old ^ val;
switch (addr) {
case 0x44: /*Shadow configure*/
if (valxor & 0xff)
sis_85c496_recalcmapping(dev);
break;
case 0x45: /*Shadow configure*/
if (valxor & 0x03)
sis_85c496_recalcmapping(dev);
break;
case 0x56:
if (valxor & 0x02) {
port_92_remove(dev->port_92);
if (val & 0x02)
port_92_add(dev->port_92);
pclog("Port 92: %sabled\n", (val & 0x02) ? "En" : "Dis");
}
break;
case 0x59:
if (valxor & 0x02) {
if (val & 0x02) {
ide_set_base(0, 0x0170);
ide_set_side(0, 0x0376);
ide_set_base(1, 0x01f0);
ide_set_side(1, 0x03f6);
} else {
ide_set_base(0, 0x01f0);
ide_set_side(0, 0x03f6);
ide_set_base(1, 0x0170);
ide_set_side(1, 0x0376);
}
}
break;
case 0x58:
if (valxor & 0x80) {
if (dev->pci_conf[0x59] & 0x02) {
ide_sec_disable();
if (val & 0x80)
ide_sec_enable();
} else {
ide_pri_disable();
if (val & 0x80)
ide_pri_enable();
}
}
if (valxor & 0x40) {
if (dev->pci_conf[0x59] & 0x02) {
ide_pri_disable();
if (val & 0x40)
ide_pri_enable();
} else {
ide_sec_disable();
if (val & 0x40)
ide_sec_enable();
}
}
break;
case 0x5a:
if (valxor & 0x04) {
if (val & 0x04)
mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
else
mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
break;
case 0x67:
if (valxor & 0x60) {
port_92_set_features(dev->port_92, !!(val & 0x20), !!(val & 0x40));
pclog("[Port 92] Set features: %sreset, %sA20\n", !!(val & 0x20) ? "" : "no ", !!(val & 0x40) ? "" : "no ");
}
break;
case 0x82:
sis_85c497_write(0x22, val, priv);
break;
case 0xc0:
if (val & 0x80)
pci_set_irq_routing(PCI_INTA, val & 0xf);
else
pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED);
break;
case 0xc1:
if (val & 0x80)
pci_set_irq_routing(PCI_INTB, val & 0xf);
else
pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED);
break;
case 0xc2:
if (val & 0x80)
pci_set_irq_routing(PCI_INTC, val & 0xf);
else
pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED);
break;
case 0xc3:
if (val & 0x80)
pci_set_irq_routing(PCI_INTD, val & 0xf);
else
pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED);
break;
}
}
static uint8_t
sis_85c496_read(int func, int addr, void *priv)
{
sis_85c496_t *dev = (sis_85c496_t *) priv;
switch (addr) {
case 0x82: /*Port 22h Mirror*/
return inb(0x22);
case 0x70: /*Port 70h Mirror*/
return inb(0x70);
}
return dev->pci_conf[addr];
}
static void
sis_85c497_reset(sis_85c496_t *dev)
{
memset(dev->regs, 0, sizeof(dev->regs));
dev->regs[0x01] = 0xc0;
dev->regs[0x71] = 0x01;
dev->regs[0x72] = 0xff;
io_removehandler(0x0022, 0x0002,
sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev);
io_sethandler(0x0022, 0x0002,
sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev);
}
static void
sis_85c496_reset(void *priv)
{
sis_85c496_t *dev = (sis_85c496_t *) priv;
sis_85c497_reset(dev);
}
static void
sis_85c496_close(void *p)
{
sis_85c496_t *sis_85c496 = (sis_85c496_t *)p;
free(sis_85c496);
}
static void
*sis_85c496_init(const device_t *info)
{
sis_85c496_t *dev = malloc(sizeof(sis_85c496_t));
memset(dev, 0, sizeof(sis_85c496_t));
dev->pci_conf[0x00] = 0x39; /*SiS*/
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x96; /*496/497*/
dev->pci_conf[0x03] = 0x04;
dev->pci_conf[0x04] = 7;
dev->pci_conf[0x05] = 0;
dev->pci_conf[0x06] = 0x80;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 2; /*Device revision*/
dev->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/
dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x0e] = 0x00; /*Single function device*/
dev->pci_conf[0xd0] = 0x78; /* ROM at E0000-FFFFF, Flash enable. */
dev->pci_conf[0xd1] = 0xff;
pci_add_card(5, sis_85c496_read, sis_85c496_write, dev);
sis_85c497_reset(dev);
dev->port_92 = device_add(&port_92_device);
port_92_set_period(dev->port_92, 2ULL * TIMER_USEC);
port_92_set_features(dev->port_92, 0, 0);
sis_85c496_recalcmapping(dev);
return dev;
}
const device_t sis_85c496_device =
{
"SiS 85c496/85c497",
DEVICE_PCI,
0,
sis_85c496_init,
sis_85c496_close,
sis_85c496_reset,
NULL,
NULL,
NULL,
NULL
};

441
src/chipset/sis_85c50x.c Normal file
View File

@@ -0,0 +1,441 @@
/*
* 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 SiS 85c501/85c503 chip.
*
* Version: @(#)sis_85c50x.c 1.0.0 2019/05/13
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../mem.h"
#include "../io.h"
#include "../rom.h"
#include "../pci.h"
#include "../device.h"
#include "../keyboard.h"
#include "../port_92.h"
#include "chipset.h"
typedef struct sis_85c501_t
{
/* 85c501 */
uint8_t turbo_reg;
/* 85c503 */
/* Registers */
uint8_t pci_conf[2][256];
/* 85c50x ISA */
uint8_t cur_reg,
regs[39];
} sis_85c50x_t;
static void
sis_85c501_recalcmapping(sis_85c50x_t *dev)
{
int c, d;
uint32_t base;
for (c = 0; c < 1; c++) {
for (d = 0; d < 4; d++) {
base = 0xe0000 + (d << 14);
if (dev->pci_conf[0][0x54 + c] & (1 << (d + 4))) {
switch (dev->pci_conf[0][0x53] & 0x60) {
case 0x00:
mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 0x20:
mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 0x40:
mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
case 0x60:
mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
}
} else
mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
}
flushmmucache();
shadowbios = 1;
}
static void
sis_85c501_write(int func, int addr, uint8_t val, void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
if (func)
return;
if ((addr >= 0x10) && (addr < 0x4f))
return;
switch (addr) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0e:
return;
case 0x04: /*Command register*/
val &= 0x42;
val |= 0x04;
break;
case 0x05:
val &= 0x01;
break;
case 0x06: /*Status*/
val = 0;
break;
case 0x07:
val = 0x02;
break;
case 0x54: /*Shadow configure*/
if ((dev->pci_conf[0][0x54] & val) ^ 0xf0) {
dev->pci_conf[0][0x54] = val;
sis_85c501_recalcmapping(dev);
}
break;
}
dev->pci_conf[0][addr] = val;
}
static void
sis_85c503_write(int func, int addr, uint8_t val, void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
if (func > 0)
return;
if (addr >= 0x0f && addr < 0x41)
return;
switch(addr) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0e:
return;
case 0x04: /*Command register*/
val &= 0x08;
val |= 0x07;
break;
case 0x05:
val = 0;
break;
case 0x06: /*Status*/
val = 0;
break;
case 0x07:
val = 0x02;
break;
case 0x41:
if (val & 0x80)
pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED);
else
pci_set_irq_routing(PCI_INTA, val & 0xf);
break;
case 0x42:
if (val & 0x80)
pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED);
else
pci_set_irq_routing(PCI_INTC, val & 0xf);
break;
case 0x43:
if (val & 0x80)
pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED);
else
pci_set_irq_routing(PCI_INTB, val & 0xf);
break;
case 0x44:
if (val & 0x80)
pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED);
else
pci_set_irq_routing(PCI_INTD, val & 0xf);
break;
}
dev->pci_conf[1][addr] = val;
}
static void
sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
if (port & 1) {
if (dev->cur_reg <= 0x1a)
dev->regs[dev->cur_reg] = val;
} else
dev->cur_reg = val;
}
static uint8_t
sis_85c501_read(int func, int addr, void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
if (func)
return 0xff;
return dev->pci_conf[0][addr];
}
static uint8_t
sis_85c503_read(int func, int addr, void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
if (func > 0)
return 0xff;
return dev->pci_conf[1][addr];
}
static uint8_t
sis_85c50x_isa_read(uint16_t port, void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
if (port & 1) {
if (dev->cur_reg <= 0x1a)
return dev->regs[dev->cur_reg];
else
return 0xff;
} else
return dev->cur_reg;
}
static void
sis_85c50x_isa_reset(sis_85c50x_t *dev)
{
int mem_size_mb, i = 0;
memset(dev->regs, 0, sizeof(dev->regs));
dev->cur_reg = 0;
for (i = 0; i < 0x27; i++)
dev->regs[i] = 0x00;
dev->regs[9] = 0x40;
mem_size_mb = mem_size >> 10;
switch (mem_size_mb) {
case 0: case 1:
dev->regs[9] |= 0;
break;
case 2: case 3:
dev->regs[9] |= 1;
break;
case 4:
dev->regs[9] |= 2;
break;
case 5:
dev->regs[9] |= 0x20;
break;
case 6: case 7:
dev->regs[9] |= 9;
break;
case 8: case 9:
dev->regs[9] |= 4;
break;
case 10: case 11:
dev->regs[9] |= 5;
break;
case 12: case 13: case 14: case 15:
dev->regs[9] |= 0xB;
break;
case 16:
dev->regs[9] |= 0x13;
break;
case 17:
dev->regs[9] |= 0x21;
break;
case 18: case 19:
dev->regs[9] |= 6;
break;
case 20: case 21: case 22: case 23:
dev->regs[9] |= 0xD;
break;
case 24: case 25: case 26: case 27:
case 28: case 29: case 30: case 31:
dev->regs[9] |= 0xE;
break;
case 32: case 33: case 34: case 35:
dev->regs[9] |= 0x1B;
break;
case 36: case 37: case 38: case 39:
dev->regs[9] |= 0xF;
break;
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47:
dev->regs[9] |= 0x17;
break;
case 48:
dev->regs[9] |= 0x1E;
break;
default:
if (mem_size_mb < 64)
dev->regs[9] |= 0x1E;
else if ((mem_size_mb >= 65) && (mem_size_mb < 68))
dev->regs[9] |= 0x22;
else
dev->regs[9] |= 0x24;
break;
}
dev->regs[0x11] = 9;
dev->regs[0x12] = 0xFF;
dev->regs[0x23] = 0xF0;
dev->regs[0x26] = 1;
io_removehandler(0x22, 0x0002,
sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev);
io_sethandler(0x22, 0x0002,
sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev);
}
static void
sis_85c50x_reset(void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
uint8_t val = 0;
val = sis_85c501_read(0, 0x54, priv); /* Read current value of 0x44. */
sis_85c501_write(0, 0x54, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */
sis_85c50x_isa_reset(dev);
}
static void
sis_85c50x_setup(sis_85c50x_t *dev)
{
memset(dev, 0, sizeof(sis_85c50x_t));
/* 85c501 */
dev->pci_conf[0][0x00] = 0x39; /*SiS*/
dev->pci_conf[0][0x01] = 0x10;
dev->pci_conf[0][0x02] = 0x06; /*501/502*/
dev->pci_conf[0][0x03] = 0x04;
dev->pci_conf[0][0x04] = 7;
dev->pci_conf[0][0x05] = 0;
dev->pci_conf[0][0x06] = 0x80;
dev->pci_conf[0][0x07] = 0x02;
dev->pci_conf[0][0x08] = 0; /*Device revision*/
dev->pci_conf[0][0x09] = 0x00; /*Device class (PCI bridge)*/
dev->pci_conf[0][0x0a] = 0x00;
dev->pci_conf[0][0x0b] = 0x06;
dev->pci_conf[0][0x0e] = 0x00; /*Single function device*/
dev->pci_conf[0][0x50] = 0xbc;
dev->pci_conf[0][0x51] = 0xfb;
dev->pci_conf[0][0x52] = 0xad;
dev->pci_conf[0][0x53] = 0xfe;
shadowbios = 1;
/* 85c503 */
dev->pci_conf[1][0x00] = 0x39; /*SiS*/
dev->pci_conf[1][0x01] = 0x10;
dev->pci_conf[1][0x02] = 0x08; /*503*/
dev->pci_conf[1][0x03] = 0x00;
dev->pci_conf[1][0x04] = 7;
dev->pci_conf[1][0x05] = 0;
dev->pci_conf[1][0x06] = 0x80;
dev->pci_conf[1][0x07] = 0x02;
dev->pci_conf[1][0x08] = 0; /*Device revision*/
dev->pci_conf[1][0x09] = 0x00; /*Device class (PCI bridge)*/
dev->pci_conf[1][0x0a] = 0x01;
dev->pci_conf[1][0x0b] = 0x06;
dev->pci_conf[1][0x0e] = 0x00; /*Single function device*/
dev->pci_conf[1][0x41] = dev->pci_conf[1][0x42] =
dev->pci_conf[1][0x43] = dev->pci_conf[1][0x44] = 0x80;
}
static void
sis_85c50x_close(void *priv)
{
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
free(dev);
}
static void *
sis_85c50x_init(const device_t *info)
{
sis_85c50x_t *dev = (sis_85c50x_t *) malloc(sizeof(sis_85c50x_t));
pci_add_card(0, sis_85c501_read, sis_85c501_write, dev);
pci_add_card(5, sis_85c503_read, sis_85c503_write, dev);
sis_85c50x_setup(dev);
sis_85c50x_isa_reset(dev);
device_add(&port_92_pci_device);
return dev;
}
const device_t sis_85c50x_device =
{
"SiS 85c501/85c503",
DEVICE_PCI,
0,
sis_85c50x_init,
sis_85c50x_close,
sis_85c50x_reset,
NULL,
NULL,
NULL,
NULL
};

View File

@@ -0,0 +1,196 @@
/*
* 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 WD76C10 System Controller chip.
*
* Version: @(#)wd76c10.c 1.0.0 2019/05/14
*
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
* Copyright 2017-2019 Fred N. van Kempen.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../device.h"
#include "../timer.h"
#include "../io.h"
#include "../keyboard.h"
#include "../mem.h"
#include "../port_92.h"
#include "../serial.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../video/vid_paradise.h"
#include "chipset.h"
typedef struct {
int type;
uint16_t reg_0092;
uint16_t reg_2072;
uint16_t reg_2872;
uint16_t reg_5872;
serial_t *uart[2];
fdc_t *fdc;
} wd76c10_t;
static uint16_t
wd76c10_read(uint16_t port, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
int16_t ret = 0xffff;
switch (port) {
case 0x2072:
ret = dev->reg_2072;
break;
case 0x2872:
ret = dev->reg_2872;
break;
case 0x5872:
ret = dev->reg_5872;
break;
}
return(ret);
}
static void
wd76c10_write(uint16_t port, uint16_t val, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
switch (port) {
case 0x2072:
dev->reg_2072 = val;
serial_remove(dev->uart[0]);
if (!(val & 0x10))
{
switch ((val >> 5) & 7)
{
case 1: serial_setup(dev->uart[0], 0x3f8, 4); break;
case 2: serial_setup(dev->uart[0], 0x2f8, 4); break;
case 3: serial_setup(dev->uart[0], 0x3e8, 4); break;
case 4: serial_setup(dev->uart[0], 0x2e8, 4); break;
default: break;
}
}
serial_remove(dev->uart[1]);
if (!(val & 0x01))
{
switch ((val >> 1) & 7)
{
case 1: serial_setup(dev->uart[1], 0x3f8, 3); break;
case 2: serial_setup(dev->uart[1], 0x2f8, 3); break;
case 3: serial_setup(dev->uart[1], 0x3e8, 3); break;
case 4: serial_setup(dev->uart[1], 0x2e8, 3); break;
default: break;
}
}
break;
case 0x2872:
dev->reg_2872 = val;
fdc_remove(dev->fdc);
if (! (val & 1))
fdc_set_base(dev->fdc, 0x03f0);
break;
case 0x5872:
dev->reg_5872 = val;
break;
}
}
static uint8_t
wd76c10_readb(uint16_t port, void *priv)
{
if (port & 1)
return(wd76c10_read(port & ~1, priv) >> 8);
return(wd76c10_read(port, priv) & 0xff);
}
static void
wd76c10_writeb(uint16_t port, uint8_t val, void *priv)
{
uint16_t temp = wd76c10_read(port, priv);
if (port & 1)
wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv);
else
wd76c10_write(port , (temp & 0xff00) | val, priv);
}
static void
wd76c10_close(void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
free(dev);
}
static void *
wd76c10_init(const device_t *info)
{
wd76c10_t *dev;
dev = (wd76c10_t *) malloc(sizeof(wd76c10_t));
memset(dev, 0x00, sizeof(wd76c10_t));
dev->type = info->local;
dev->fdc = (fdc_t *)device_add(&fdc_at_device);
dev->uart[0] = device_add_inst(&i8250_device, 1);
dev->uart[1] = device_add_inst(&i8250_device, 2);
device_add(&port_92_word_device);
io_sethandler(0x2072, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
io_sethandler(0x2872, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
io_sethandler(0x5872, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
return(dev);
}
const device_t wd76c10_device = {
"WD 76C10",
0,
0,
wd76c10_init, wd76c10_close, NULL,
NULL, NULL, NULL,
NULL
};

292
src/chipset/wd76c10.c Normal file
View File

@@ -0,0 +1,292 @@
/*
* 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 WD76C10 System Controller chip.
*
* Version: @(#)wd76c10.c 1.0.0 2019/05/14
*
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
* Copyright 2017-2019 Fred N. van Kempen.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../device.h"
#include "../timer.h"
#include "../io.h"
#include "../keyboard.h"
#include "../mem.h"
#include "../port_92.h"
#include "../serial.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../video/vid_paradise.h"
#include "chipset.h"
typedef struct {
int type;
uint16_t reg_0092;
uint16_t reg_2072;
uint16_t reg_2872;
uint16_t reg_5872;
uint16_t reg_f872;
serial_t *uart[2];
fdc_t *fdc;
mem_mapping_t extram_mapping;
uint8_t extram[65536];
} wd76c10_t;
static uint16_t
wd76c10_read(uint16_t port, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
int16_t ret = 0xffff;
switch (port) {
case 0x2072:
ret = dev->reg_2072;
break;
case 0x2872:
ret = dev->reg_2872;
break;
case 0x5872:
ret = dev->reg_5872;
break;
case 0xf872:
ret = dev->reg_f872;
break;
}
return(ret);
}
static void
wd76c10_write(uint16_t port, uint16_t val, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
switch (port) {
case 0x2072:
dev->reg_2072 = val;
serial_remove(dev->uart[0]);
if (!(val & 0x10))
{
switch ((val >> 5) & 7)
{
case 1: serial_setup(dev->uart[0], 0x3f8, 4); break;
case 2: serial_setup(dev->uart[0], 0x2f8, 4); break;
case 3: serial_setup(dev->uart[0], 0x3e8, 4); break;
case 4: serial_setup(dev->uart[0], 0x2e8, 4); break;
default: break;
}
}
serial_remove(dev->uart[1]);
if (!(val & 0x01))
{
switch ((val >> 1) & 7)
{
case 1: serial_setup(dev->uart[1], 0x3f8, 3); break;
case 2: serial_setup(dev->uart[1], 0x2f8, 3); break;
case 3: serial_setup(dev->uart[1], 0x3e8, 3); break;
case 4: serial_setup(dev->uart[1], 0x2e8, 3); break;
default: break;
}
}
break;
case 0x2872:
dev->reg_2872 = val;
fdc_remove(dev->fdc);
if (! (val & 1))
fdc_set_base(dev->fdc, 0x03f0);
break;
case 0x5872:
dev->reg_5872 = val;
break;
case 0xf872:
dev->reg_f872 = val;
switch (val & 3) {
case 0:
mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 1:
mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
case 2:
mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
flushmmucache_nopc();
if (val & 4)
mem_mapping_enable(&dev->extram_mapping);
else
mem_mapping_disable(&dev->extram_mapping);
flushmmucache_nopc();
break;
}
}
static uint8_t
wd76c10_readb(uint16_t port, void *priv)
{
if (port & 1)
return(wd76c10_read(port & ~1, priv) >> 8);
return(wd76c10_read(port, priv) & 0xff);
}
static void
wd76c10_writeb(uint16_t port, uint8_t val, void *priv)
{
uint16_t temp = wd76c10_read(port, priv);
if (port & 1)
wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv);
else
wd76c10_write(port , (temp & 0xff00) | val, priv);
}
uint8_t
wd76c10_read_extram(uint32_t addr, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
return dev->extram[addr & 0xffff];
}
uint16_t
wd76c10_read_extramw(uint32_t addr, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
return *(uint16_t *)&dev->extram[addr & 0xffff];
}
uint32_t
wd76c10_read_extraml(uint32_t addr, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
return *(uint32_t *)&dev->extram[addr & 0xffff];
}
void
wd76c10_write_extram(uint32_t addr, uint8_t val, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
dev->extram[addr & 0xffff] = val;
}
void
wd76c10_write_extramw(uint32_t addr, uint16_t val, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
*(uint16_t *)&dev->extram[addr & 0xffff] = val;
}
void
wd76c10_write_extraml(uint32_t addr, uint32_t val, void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
*(uint32_t *)&dev->extram[addr & 0xffff] = val;
}
static void
wd76c10_close(void *priv)
{
wd76c10_t *dev = (wd76c10_t *)priv;
free(dev);
}
static void *
wd76c10_init(const device_t *info)
{
wd76c10_t *dev;
dev = (wd76c10_t *) malloc(sizeof(wd76c10_t));
memset(dev, 0x00, sizeof(wd76c10_t));
dev->type = info->local;
dev->fdc = (fdc_t *)device_add(&fdc_at_device);
dev->uart[0] = device_add_inst(&i8250_device, 1);
dev->uart[1] = device_add_inst(&i8250_device, 2);
device_add(&port_92_word_device);
io_sethandler(0x2072, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
io_sethandler(0x2872, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
io_sethandler(0x5872, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
io_sethandler(0xf872, 2,
wd76c10_readb,wd76c10_read,NULL,
wd76c10_writeb,wd76c10_write,NULL, dev);
mem_mapping_add(&dev->extram_mapping, 0xd0000, 0x10000,
wd76c10_read_extram,wd76c10_read_extramw,wd76c10_read_extraml,
wd76c10_write_extram,wd76c10_write_extramw,wd76c10_write_extraml,
dev->extram, MEM_MAPPING_EXTERNAL, dev);
mem_mapping_disable(&dev->extram_mapping);
return(dev);
}
const device_t wd76c10_device = {
"WD 76C10",
0,
0,
wd76c10_init, wd76c10_close, NULL,
NULL, NULL, NULL,
NULL
};