Hook up Bidirectional LPT, EPP, and ECP to all Super I/O chips (missing is vendor-specific Configuration Register B behavior but that's next on my list), fixed Super I/O chip mistakes for a number of machines, split 286/386SX/M6117D machines into three separate files and reordered them as well.

This commit is contained in:
OBattler
2025-08-11 16:36:30 +02:00
parent 42fa1dbe54
commit dbd748636e
51 changed files with 5062 additions and 4463 deletions

View File

@@ -16,29 +16,28 @@
#
add_library(sio OBJECT
sio_82091aa.c
sio_acc3221.c
sio_ali5123.c
sio_gm82c803ab.c
sio_gm82c803c.c
sio_f82c606.c
sio_f82c710.c
sio_82091aa.c
sio_fdc37c6xx.c
sio_fdc37c67x.c
sio_fdc37c669.c
sio_fdc37c93x.c
sio_fdc37m60x.c
sio_it86x1f.c
sio_pc87310.c
sio_pc873xx.c
sio_pc87306.c
sio_pc87307.c
sio_pc87309.c
sio_pc87310.c
sio_pc87311.c
sio_pc87332.c
sio_prime3b.c
sio_prime3c.c
sio_w83787f.c
sio_w83877f.c
sio_w83977f.c
sio_um8663f.c
sio_w837x7.c
sio_w83877.c
sio_w83977.c
sio_um866x.c
sio_um8669f.c
sio_vl82c113.c
sio_vt82c686.c

View File

@@ -57,9 +57,34 @@ static void
lpt_handler(i82091aa_t *dev)
{
uint16_t lpt_port = LPT1_ADDR;
int enable = (dev->regs[0x20] & 0x01);
lpt_port_remove(dev->lpt);
lpt_set_fifo_threshold(dev->lpt, (dev->regs[0x20] & 0x80) ? 15 : 8);
switch (dev->regs[0x20] & 0x60) {
default:
case 0x00:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
case 0x20:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 1);
break;
case 0x40:
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
case 0x60:
enable = 0;
break;
}
switch ((dev->regs[0x20] >> 1) & 0x03) {
case 0x00:
lpt_port = LPT1_ADDR;
@@ -78,7 +103,7 @@ lpt_handler(i82091aa_t *dev)
break;
}
if ((dev->regs[0x20] & 0x01) && lpt_port)
if (enable && lpt_port)
lpt_port_setup(dev->lpt, lpt_port);
lpt_port_irq(dev->lpt, (dev->regs[0x20] & 0x08) ? LPT1_IRQ : LPT2_IRQ);
@@ -176,7 +201,7 @@ i82091aa_write(uint16_t port, uint8_t val, void *priv)
break;
case 0x20:
*reg = (val & 0xef);
if (valxor & 0x07)
if (valxor & 0xe8)
lpt_handler(dev);
break;
case 0x21:
@@ -218,6 +243,8 @@ i82091aa_read(uint16_t port, void *priv)
if (index)
ret = dev->cur_reg;
else if (dev->cur_reg == 0x20)
ret = dev->regs[dev->cur_reg] | lpt_read_ecp_mode(dev->lpt);
else if (dev->cur_reg < 0x51)
ret = dev->regs[dev->cur_reg];
@@ -266,6 +293,7 @@ i82091aa_init(const device_t *info)
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_cnfga_readout(dev->lpt, 0x90);
dev->has_ide = (info->local >> 9) & 0x03;
@@ -288,63 +316,7 @@ const device_t i82091aa_device = {
.name = "Intel 82091AA Super I/O",
.internal_name = "i82091aa",
.flags = 0,
.local = 0x40,
.init = i82091aa_init,
.close = i82091aa_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t i82091aa_26e_device = {
.name = "Intel 82091AA Super I/O (Port 26Eh)",
.internal_name = "i82091aa_26e",
.flags = 0,
.local = 0x140,
.init = i82091aa_init,
.close = i82091aa_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t i82091aa_398_device = {
.name = "Intel 82091AA Super I/O (Port 398h)",
.internal_name = "i82091aa_398",
.flags = 0,
.local = 0x148,
.init = i82091aa_init,
.close = i82091aa_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t i82091aa_ide_pri_device = {
.name = "Intel 82091AA Super I/O (With Primary IDE)",
.internal_name = "i82091aa_ide",
.flags = 0,
.local = 0x240,
.init = i82091aa_init,
.close = i82091aa_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t i82091aa_ide_device = {
.name = "Intel 82091AA Super I/O (With IDE)",
.internal_name = "i82091aa_ide",
.flags = 0,
.local = 0x440,
.local = 0,
.init = i82091aa_init,
.close = i82091aa_close,
.reset = NULL,

View File

@@ -37,7 +37,10 @@
typedef struct fdc37c669_t {
uint8_t id;
uint8_t tries;
uint8_t regs[42];
uint8_t has_ide;
uint8_t dma_map[4];
uint8_t irq_map[10];
uint8_t regs[256];
int locked;
int rw_locked;
int cur_reg;
@@ -70,6 +73,7 @@ static void
fdc37c669_fdc_handler(fdc37c669_t *dev)
{
fdc_remove(dev->fdc);
if (dev->regs[0x20] & 0xc0)
fdc_set_base(dev->fdc, ((uint16_t) dev->regs[0x20]) << 2);
}
@@ -82,6 +86,7 @@ fdc37c669_uart_handler(fdc37c669_t *dev, uint8_t uart)
uint8_t uart_shift = ((uart ^ 1) << 2);
serial_remove(dev->uart[uart]);
if ((dev->regs[0x02] & pwrdn_mask) && (dev->regs[uart_reg] & 0xc0))
serial_setup(dev->uart[0], ((uint16_t) dev->regs[0x24]) << 2,
(dev->regs[0x28] >> uart_shift) & 0x0f);
@@ -107,10 +112,41 @@ fdc37c669_lpt_handler(fdc37c669_t *dev)
uint8_t mask = ~(dev->regs[0x04] & 0x01);
lpt_port_remove(dev->lpt);
if (dev->regs[0x01] & 0x08) {
lpt_set_ext(dev->lpt, 0);
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
} else {
lpt_set_ext(dev->lpt, 1);
lpt_set_epp(dev->lpt, dev->regs[0x04] & 0x01);
lpt_set_ecp(dev->lpt, dev->regs[0x04] & 0x02);
}
lpt_set_fifo_threshold(dev->lpt, dev->regs[0x0a] & 0x0f);
if ((dev->regs[0x01] & 0x04) && (dev->regs[0x23] >= 0x40))
lpt_port_setup(dev->lpt, ((uint16_t) (dev->regs[0x23] & mask)) << 2);
}
static void
ide_handler(fdc37c669_t *dev)
{
if (dev->has_ide > 0) {
int ide_id = dev->has_ide - 1;
ide_handlers(ide_id, 0);
ide_set_base_addr(ide_id, 0, ((uint16_t) (dev->regs[0x21] & 0xfc)) << 2);
ide_set_base_addr(ide_id, 1, (((uint16_t) (dev->regs[0x22] & 0xfc)) << 2) | 0x0006);
if ((dev->regs[0x00] & 0x03) == 0x02)
ide_handlers(ide_id, 1);
}
}
static void
fdc37c669_write(uint16_t port, uint8_t val, void *priv)
{
@@ -139,12 +175,14 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
} else if (!dev->rw_locked || (dev->cur_reg > 0x0f)) switch (dev->cur_reg) {
case 0x00:
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x74) | (val & 0x8b);
if (!dev->id && (valxor & 8))
if (!dev->id && (valxor & 0x08))
fdc_set_power_down(dev->fdc, !(val & 0x08));
if (!dev->id && (valxor & 0x03))
ide_handler(dev);
break;
case 0x01:
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x73) | (val & 0x8c);
if (valxor & 0x04)
if (valxor & 0x0c)
fdc37c669_lpt_handler(dev);
if (valxor & 0x80)
dev->rw_locked = !(val & 0x80);
@@ -158,6 +196,17 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
break;
case 0x03:
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x08) | (val & 0xf7);
if ((valxor & 0x60) && (dev->fdc != NULL)) {
fdc_clear_flags(dev->fdc, FDC_FLAG_PS2 | FDC_FLAG_PS2_MCA);
switch (val & 0x0c) {
case 0x00:
fdc_set_flags(dev->fdc, FDC_FLAG_PS2);
break;
case 0x20:
fdc_set_flags(dev->fdc, FDC_FLAG_PS2_MCA);
break;
}
}
if (!dev->id && (valxor & 0x02))
fdc_update_enh_mode(dev->fdc, !!(val & 0x02));
break;
@@ -191,6 +240,8 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
break;
case 0x0a:
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0xf0) | (val & 0x0f);
if (valxor & 0x0f)
fdc37c669_lpt_handler(dev);
break;
case 0x0b:
dev->regs[dev->cur_reg] = val;
@@ -223,9 +274,13 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
break;
case 0x21:
dev->regs[dev->cur_reg] = val & 0xfc;
if (!dev->id && (valxor & 0xfc))
ide_handler(dev);
break;
case 0x22:
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x03) | (val & 0xfc);
if (!dev->id && (valxor & 0xfc))
ide_handler(dev);
break;
case 0x23:
dev->regs[dev->cur_reg] = val;
@@ -246,6 +301,8 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
dev->regs[dev->cur_reg] = val;
if (valxor & 0xf0)
fdc_set_dma_ch(dev->fdc, val >> 4);
if (valxor & 0x0f)
lpt_port_dma(dev->lpt, val & 0x0f);
break;
case 0x27:
dev->regs[dev->cur_reg] = val;
@@ -306,9 +363,13 @@ fdc37c669_reset(void *priv)
dev->regs[0x21] = 0x3c;
dev->regs[0x22] = 0x3d;
if (dev->id != 1) {
if (!dev->id) {
fdc_reset(dev->fdc);
fdc37c669_fdc_handler(dev);
fdc_clear_flags(dev->fdc, FDC_FLAG_PS2 | FDC_FLAG_PS2_MCA);
ide_handler(dev);
}
fdc37c669_uart_handler(dev, 0);
@@ -340,17 +401,34 @@ fdc37c669_init(const device_t *info)
dev->id = next_id;
if (next_id != 1)
dev->fdc = device_add(&fdc_at_smc_device);
if (next_id != 1) {
dev->fdc = device_add(&fdc_at_smc_device);
dev->has_ide = (info->local >> 8) & 0xff;
}
dev->uart[0] = device_add_inst(&ns16550_device, (next_id << 1) + 1);
dev->uart[1] = device_add_inst(&ns16550_device, (next_id << 1) + 2);
dev->lpt = device_add_inst(&lpt_port_device, next_id + 1);
io_sethandler(info->local ? FDC_SECONDARY_ADDR : (next_id ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR),
io_sethandler((info->local & FDC37C6XX_370) ? FDC_SECONDARY_ADDR : (next_id ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR),
0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev);
dev->dma_map[0] = 4;
for (int i = 1; i < 4; i++)
dev->dma_map[i] = i;
memset(dev->irq_map, 0xff, 16);
dev->irq_map[0] = 0xff;
for (int i = 1; i < 7; i++)
dev->irq_map[i] = i;
dev->irq_map[1] = 5;
dev->irq_map[5] = 7;
dev->irq_map[7] = 0xff; /* Reserved. */
dev->irq_map[8] = 10;
dev->irq_map[9] = 9; /* This is used by the Acrosser PJ-A511M for IRQ 9. */
dev->irq_map[11] = 11; /* This is used by the Acrosser PJ-A511M for IRQ 11. */
fdc37c669_reset(dev);
next_id++;
@@ -371,17 +449,3 @@ const device_t fdc37c669_device = {
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c669_370_device = {
.name = "SMC FDC37C669 Super I/O (Port 370h)",
.internal_name = "fdc37c669_370",
.flags = 0,
.local = 1,
.init = fdc37c669_init,
.close = fdc37c669_close,
.reset = fdc37c669_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -437,7 +437,6 @@ fdc37c67x_write(uint16_t port, uint8_t val, void *priv)
fdc_set_flags(dev->fdc, FDC_FLAG_PS2_MCA);
break;
}
fdc_update_enh_mode(dev->fdc, val & 0x01);
}
if (valxor & 0x10)
fdc_set_swap(dev->fdc, (val & 0x10) >> 4);

View File

@@ -9,11 +9,9 @@
* Implementation of the SMC FDC37C663 and FDC37C665 Super
* I/O Chips.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2016-2020 Miran Grca.
* Copyright 2016-2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
@@ -113,8 +111,6 @@ lpt_handler(fdc37c6xx_t *dev)
uint16_t mask = 0xfffc;
uint8_t local_enable = 1;
uint8_t lpt_irq = LPT1_IRQ;
/* DMA is guesswork - what channel do boards actually use? */
uint8_t lpt_dma = 3;
uint8_t lpt_ext = !(dev->regs[1] & 0x08);
uint8_t lpt_mode = (dev->chip_id >= 0x65) ? (dev->regs[4] & 0x03) : 0x00;
@@ -140,9 +136,6 @@ lpt_handler(fdc37c6xx_t *dev)
if (lpt_irq > 15)
lpt_irq = 0xff;
if (lpt_dma >= 4)
lpt_dma = 0xff;
lpt_port_remove(dev->lpt);
lpt_set_fifo_threshold(dev->lpt, dev->regs[0x0a] & 0x0f);
if (lpt_ext) switch (lpt_mode) {
@@ -192,19 +185,16 @@ fdc_handler(fdc37c6xx_t *dev)
static void
ide_handler(fdc37c6xx_t *dev)
{
/* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */
if (dev->has_ide == 2) {
ide_sec_disable();
ide_set_base(1, (dev->regs[0x05] & 0x02) ? 0x170 : 0x1f0);
ide_set_side(1, (dev->regs[0x05] & 0x02) ? 0x376 : 0x3f6);
if (dev->has_ide > 0) {
int ide_id = dev->has_ide - 1;
ide_handlers(ide_id, 0);
ide_set_base_addr(ide_id, 0, (dev->regs[0x05] & 0x02) ? 0x0170 : 0x01f0);
ide_set_base_addr(ide_id, 1, (dev->regs[0x05] & 0x02) ? 0x0376 : 0x03f6);
if (dev->regs[0x00] & 0x01)
ide_sec_enable();
} else if (dev->has_ide == 1) {
ide_pri_disable();
ide_set_base(0, (dev->regs[0x05] & 0x02) ? 0x170 : 0x1f0);
ide_set_side(0, (dev->regs[0x05] & 0x02) ? 0x376 : 0x3f6);
if (dev->regs[0x00] & 0x01)
ide_pri_enable();
ide_handlers(ide_id, 1);
}
}
@@ -228,14 +218,14 @@ fdc37c6xx_write(uint16_t port, uint8_t val, void *priv)
dev->regs[dev->cur_reg] = val;
switch (dev->cur_reg) {
case 0:
case 0x00:
if (dev->has_ide && (valxor & 0x01))
ide_handler(dev);
if (valxor & 0x10)
fdc_handler(dev);
break;
case 1:
if (valxor & 3)
case 0x01:
if (valxor & 0x03)
lpt_handler(dev);
if (valxor & 0x60) {
set_com34_addr(dev);
@@ -243,23 +233,23 @@ fdc37c6xx_write(uint16_t port, uint8_t val, void *priv)
set_serial_addr(dev, 1);
}
break;
case 2:
if (valxor & 7)
case 0x02:
if (valxor & 0x07)
set_serial_addr(dev, 0);
if (valxor & 0x70)
set_serial_addr(dev, 1);
break;
case 3:
if (valxor & 2)
fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 2) ? 1 : 0);
case 0x03:
if (valxor & 0x02)
fdc_update_enh_mode(dev->fdc, !!(dev->regs[0x03] & 0x02));
break;
case 4:
case 0x04:
if (valxor & 0x10)
set_serial_addr(dev, 0);
if (valxor & 0x20)
set_serial_addr(dev, 1);
break;
case 5:
case 0x05:
if (valxor & 0x01)
fdc_handler(dev);
if (dev->has_ide && (valxor & 0x02))
@@ -285,7 +275,7 @@ fdc37c6xx_read(uint16_t port, void *priv)
uint8_t ret = 0xff;
if (dev->tries == 2) {
if ((port == 0x3f1) && (dev->cur_reg <= dev->max_reg))
if ((port == 0x03f1) && (dev->cur_reg <= dev->max_reg))
ret = dev->regs[dev->cur_reg];
}
@@ -385,175 +375,23 @@ fdc37c6xx_init(const device_t *info)
dev->lpt = device_add_inst(&lpt_port_device, 1);
io_sethandler(FDC_PRIMARY_ADDR, 0x0002,
fdc37c6xx_read, NULL, NULL, fdc37c6xx_write, NULL, NULL, dev);
if (info->local & FDC37C6XX_370)
io_sethandler(FDC_SECONDARY_ADDR, 0x0002,
fdc37c6xx_read, NULL, NULL, fdc37c6xx_write, NULL, NULL, dev);
else
io_sethandler(FDC_PRIMARY_ADDR, 0x0002,
fdc37c6xx_read, NULL, NULL, fdc37c6xx_write, NULL, NULL, dev);
fdc37c6xx_reset(dev);
return dev;
}
/* The three appear to differ only in the chip ID, if I
understood their datasheets correctly. */
const device_t fdc37c651_device = {
.name = "SMC FDC37C651 Super I/O",
.internal_name = "fdc37c651",
const device_t fdc37c6xx_device = {
.name = "SMC FDC37C6xx Super I/O",
.internal_name = "fdc37c6xx",
.flags = 0,
.local = 0x51,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c651_ide_device = {
.name = "SMC FDC37C651 Super I/O (With IDE)",
.internal_name = "fdc37c651_ide",
.flags = 0,
.local = 0x151,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c661_device = {
.name = "SMC FDC37C661 Super I/O",
.internal_name = "fdc37c661",
.flags = 0,
.local = 0x61,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c661_ide_device = {
.name = "SMC FDC37C661 Super I/O (With IDE)",
.internal_name = "fdc37c661_ide",
.flags = 0,
.local = 0x161,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c661_ide_sec_device = {
.name = "SMC FDC37C661 Super I/O (With Secondary IDE)",
.internal_name = "fdc37c661_ide_sec",
.flags = 0,
.local = 0x261,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c663_device = {
.name = "SMC FDC37C663 Super I/O",
.internal_name = "fdc37c663",
.flags = 0,
.local = 0x63,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c663_ide_device = {
.name = "SMC FDC37C663 Super I/O (With IDE)",
.internal_name = "fdc37c663_ide",
.flags = 0,
.local = 0x163,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c665_device = {
.name = "SMC FDC37C665 Super I/O",
.internal_name = "fdc37c665",
.flags = 0,
.local = 0x65,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c665_ide_device = {
.name = "SMC FDC37C665 Super I/O (With IDE)",
.internal_name = "fdc37c665_ide",
.flags = 0,
.local = 0x265,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c665_ide_pri_device = {
.name = "SMC FDC37C665 Super I/O (With Primary IDE)",
.internal_name = "fdc37c665_ide_pri",
.flags = 0,
.local = 0x165,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c665_ide_sec_device = {
.name = "SMC FDC37C665 Super I/O (With Secondary IDE)",
.internal_name = "fdc37c665_ide_sec",
.flags = 0,
.local = 0x265,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc37c666_device = {
.name = "SMC FDC37C666 Super I/O",
.internal_name = "fdc37c666",
.flags = 0,
.local = 0x66,
.local = 0,
.init = fdc37c6xx_init,
.close = fdc37c6xx_close,
.reset = NULL,

View File

@@ -906,9 +906,11 @@ fdc37c93x_nvr_pri_handler(const fdc37c93x_t *dev)
if (dev->chip_id != 0x02)
local_enable &= ((dev->ld_regs[6][0xf0] & 0x90) != 0x80);
nvr_at_handler(0, 0x70, dev->nvr);
if (local_enable)
nvr_at_handler(1, 0x70, dev->nvr);
if (dev->has_nvr) {
nvr_at_handler(0, 0x70, dev->nvr);
if (local_enable)
nvr_at_handler(1, 0x70, dev->nvr);
}
}
static void
@@ -926,12 +928,12 @@ fdc37c93x_nvr_sec_handler(fdc37c93x_t *dev)
dev->nvr_sec_base = make_port_sec(dev, 6) & 0xfffe;
if (dev->nvr_sec_base != old_base) {
if ((old_base > 0x0000) && (old_base <= 0x0ffe))
if (dev->has_nvr && (old_base > 0x0000) && (old_base <= 0x0ffe))
nvr_at_sec_handler(0, dev->nvr_sec_base, dev->nvr);
/* Datasheet erratum: First it says minimum address is 0x0100, but later implies that it's 0x0000
and that default is 0x0070, same as (unrelocatable) primary NVR. */
if ((dev->nvr_sec_base > 0x0000) && (dev->nvr_sec_base <= 0x0ffe))
if (dev->has_nvr && (dev->nvr_sec_base > 0x0000) && (dev->nvr_sec_base <= 0x0ffe))
nvr_at_sec_handler(1, dev->nvr_sec_base, dev->nvr);
}
}
@@ -1181,7 +1183,6 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv)
fdc_set_flags(dev->fdc, FDC_FLAG_PS2_MCA);
break;
}
fdc_update_enh_mode(dev->fdc, val & 0x01);
}
if (valxor & 0x10)
fdc_set_swap(dev->fdc, (val & 0x10) >> 4);
@@ -1365,7 +1366,7 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv)
else
dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x8f;
if (valxor) {
if (dev->has_nvr && valxor) {
nvr_lock_set(0x80, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x01), dev->nvr);
nvr_lock_set(0xa0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x02), dev->nvr);
nvr_lock_set(0xc0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x04), dev->nvr);

View File

@@ -347,7 +347,6 @@ fdc37m60x_write(uint16_t port, uint8_t val, void *priv)
fdc_set_flags(dev->fdc, FDC_FLAG_PS2_MCA);
break;
}
fdc_update_enh_mode(dev->fdc, val & 0x01);
}
if (valxor & 0x10)
fdc_set_swap(dev->fdc, (val & 0x10) >> 4);

372
src/sio/sio_gm82c803ab.c Normal file
View File

@@ -0,0 +1,372 @@
/*
* 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 GoldStar GM82C803 A andB Super I/O
* Chips.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/pci.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sio.h>
typedef struct gm82c803ab_t {
uint8_t type;
uint8_t tries;
uint8_t has_ide;
uint8_t regs[16];
int cur_reg;
int com3_addr;
int com4_addr;
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
} gm82c803ab_t;
#ifdef ENABLE_GM82C803AB_LOG
int gm82c803ab_do_log = ENABLE_GM82C803AB_LOG;
static void
gm82c803ab_log(const char *fmt, ...)
{
va_list ap;
if (gm82c803ab_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define gm82c803ab_log(fmt, ...)
#endif
static void
ide_handler(gm82c803ab_t *dev)
{
if (dev->has_ide > 0) {
int ide_id = dev->has_ide - 1;
ide_handlers(ide_id, 0);
ide_set_base_addr(ide_id, 0, (dev->regs[0xa1] & 0x80) ? 0x0170 : 0x01f0);
ide_set_base_addr(ide_id, 1, (dev->regs[0xa1] & 0x80) ? 0x0376 : 0x03f6);
if (dev->regs[0xa0] & 0x20)
ide_handlers(ide_id, 1);
}
}
static void
fdc_handler(gm82c803ab_t *dev)
{
fdc_remove(dev->fdc);
if (dev->regs[0xa0] & 0x10)
fdc_set_base(dev->fdc, (dev->regs[0xa1] & 0x40) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
}
static void
set_com34_addr(gm82c803ab_t *dev)
{
switch (dev->regs[0xa4] & 0xc0) {
case 0x00:
dev->com3_addr = COM3_ADDR;
dev->com4_addr = COM4_ADDR;
break;
case 0x40:
dev->com3_addr = 0x338;
dev->com4_addr = 0x238;
break;
case 0x80:
dev->com3_addr = COM3_ADDR;
dev->com4_addr = 0x2e0;
break;
case 0xc0:
dev->com3_addr = 0x220;
dev->com4_addr = 0x228;
break;
default:
break;
}
}
static void
set_serial_addr(gm82c803ab_t *dev, int port)
{
uint8_t shift = 2 + (port << 1);
double clock_src = 24000000.0 / 13.0;
if (dev->regs[0xa4] & (1 << (4 + port)))
clock_src = 24000000.0 / 12.0;
serial_remove(dev->uart[port]);
if (dev->regs[0xa0] & (0x04 << port)) {
switch ((dev->regs[0xa1] >> shift) & 0x03) {
case 0x00:
serial_setup(dev->uart[port], COM1_ADDR, COM1_IRQ);
break;
case 0x01:
serial_setup(dev->uart[port], COM2_ADDR, COM2_IRQ);
break;
case 0x02:
serial_setup(dev->uart[port], dev->com3_addr, COM3_IRQ);
break;
case 0x03:
serial_setup(dev->uart[port], dev->com4_addr, COM4_IRQ);
break;
default:
break;
}
}
serial_set_clock_src(dev->uart[port], clock_src);
}
static void
lpt_handler(gm82c803ab_t *dev)
{
uint16_t lpt_port = 0x0000;
uint16_t mask = 0xfffc;
uint8_t local_enable = 1;
uint8_t lpt_irq = LPT1_IRQ;
uint8_t lpt_mode = (dev->regs[0xa0] & 0x03);
switch (lpt_mode) {
default:
local_enable = 0;
break;
case 0x00:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 1);
break;
case 0x01:
if (dev->type == GM82C803B) {
lpt_set_epp(dev->lpt, !!(dev->regs[0xa5] & 0x20));
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
} else
local_enable = 0;
break;
case 0x02:
if (dev->type == GM82C803B) {
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, !!(dev->regs[0xa5] & 0x20));
lpt_set_ext(dev->lpt, 0);
} else
local_enable = 0;
break;
}
switch (dev->regs[0xa1] & 0x03) {
default:
lpt_port = LPT_MDA_ADDR;
lpt_irq = LPT_MDA_IRQ;
break;
case 0x00:
lpt_port = LPT1_ADDR;
lpt_irq = LPT1_IRQ /*LPT2_IRQ*/;
break;
case 0x01:
lpt_port = LPT2_ADDR;
lpt_irq = LPT1_IRQ /*LPT2_IRQ*/;
break;
}
if (lpt_irq > 15)
lpt_irq = 0xff;
lpt_port_remove(dev->lpt);
lpt_set_fifo_threshold(dev->lpt, dev->regs[0x0a] & 0x0f);
if (local_enable && (lpt_port >= 0x0100) && (lpt_port <= (0x0ffc & mask)))
lpt_port_setup(dev->lpt, lpt_port);
lpt_port_irq(dev->lpt, lpt_irq);
}
static void
gm82c803ab_write(uint16_t port, uint8_t val, void *priv)
{
gm82c803ab_t *dev = (gm82c803ab_t *) priv;
uint8_t valxor = 0;
if (dev->tries == 2) {
if (port == 0x0398) {
if (val == 0xcc)
dev->tries = 0;
else
dev->cur_reg = val;
} else {
if ((dev->cur_reg < 0xa0) || (dev->cur_reg > 0xa5))
return;
valxor = val ^ dev->regs[dev->cur_reg];
dev->regs[dev->cur_reg] = val;
switch (dev->cur_reg) {
default:
break;
case 0xa0: /* Function Selection Register (FSR) */
if (valxor & 0x20)
ide_handler(dev);
if (valxor & 0x10)
fdc_handler(dev);
if (valxor & 0x08)
set_serial_addr(dev, 1);
if (valxor & 0x04)
set_serial_addr(dev, 0);
if (valxor & 0x03)
lpt_handler(dev);
break;
case 0xa1: /* Address Selection Register (ASR) */
if (valxor & 0x80)
ide_handler(dev);
if (valxor & 0x40)
fdc_handler(dev);
if (valxor & 0x30)
set_serial_addr(dev, 1);
if (valxor & 0x0c)
set_serial_addr(dev, 0);
if (valxor & 0x03)
lpt_handler(dev);
break;
case 0xa4: /* Miscellaneous Function Register */
if (valxor & 0xc0) {
set_com34_addr(dev);
set_serial_addr(dev, 0);
set_serial_addr(dev, 1);
}
if (valxor & 0x20)
set_serial_addr(dev, 1);
if (valxor & 0x10)
set_serial_addr(dev, 0);
if (valxor & 0x01)
fdc_set_swap(dev->fdc, val & 0x01);
break;
case 0xa5: /* ECP Register */
if (valxor & 0x20)
lpt_handler(dev);
break;
}
}
} else if ((port == 0x0398) && (val == 0x33))
dev->tries++;
}
static uint8_t
gm82c803ab_read(uint16_t port, void *priv)
{
const gm82c803ab_t *dev = (gm82c803ab_t *) priv;
uint8_t ret = 0xff;
if (dev->tries == 2) {
if ((port == 0x0399) && (dev->cur_reg >= 0xa0) && (dev->cur_reg <= 0xa1))
ret = dev->regs[dev->cur_reg];
}
return ret;
}
static void
gm82c803ab_reset(gm82c803ab_t *dev)
{
dev->com3_addr = 0x338;
dev->com4_addr = 0x238;
serial_remove(dev->uart[0]);
serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ);
serial_remove(dev->uart[1]);
serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ);
lpt_port_remove(dev->lpt);
lpt_port_setup(dev->lpt, LPT1_ADDR);
fdc_reset(dev->fdc);
fdc_remove(dev->fdc);
dev->tries = 0;
memset(dev->regs, 0, 256);
dev->regs[0xa0] = 0xff;
set_serial_addr(dev, 0);
set_serial_addr(dev, 1);
lpt_handler(dev);
fdc_handler(dev);
if (dev->has_ide)
ide_handler(dev);
}
static void
gm82c803ab_close(void *priv)
{
gm82c803ab_t *dev = (gm82c803ab_t *) priv;
free(dev);
}
static void *
gm82c803ab_init(const device_t *info)
{
gm82c803ab_t *dev = (gm82c803ab_t *) calloc(1, sizeof(gm82c803ab_t));
dev->fdc = device_add(&fdc_at_smc_device);
dev->type = info->local & 0xff;
dev->has_ide = (info->local >> 8) & 0xff;
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
io_sethandler(0x0398, 0x0002,
gm82c803ab_read, NULL, NULL, gm82c803ab_write, NULL, NULL, dev);
gm82c803ab_reset(dev);
return dev;
}
const device_t gm82c803ab_device = {
.name = "Goldstar GMC82C803A/B",
.internal_name = "gm82c803ab",
.flags = 0,
.local = 0,
.init = gm82c803ab_init,
.close = gm82c803ab_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

382
src/sio/sio_gm82c803c.c Normal file
View File

@@ -0,0 +1,382 @@
/*
* 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 GoldStar GM82C803C Super I/O Chip.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/pci.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sio.h>
typedef struct gm82c803c_t {
uint8_t tries;
uint8_t has_ide;
uint8_t dma_map[4];
uint8_t irq_map[10];
uint8_t regs[16];
int cur_reg;
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
} gm82c803c_t;
#ifdef ENABLE_GM82C803C_LOG
int gm82c803c_do_log = ENABLE_GM82C803C_LOG;
static void
gm82c803c_log(const char *fmt, ...)
{
va_list ap;
if (gm82c803c_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define gm82c803c_log(fmt, ...)
#endif
static void
ide_handler(gm82c803c_t *dev)
{
uint16_t ide_port = 0x0000;
if (dev->has_ide > 0) {
int ide_id = dev->has_ide - 1;
ide_handlers(ide_id, 0);
ide_port = (dev->regs[0xc4] << 2) & 0xfff0;
ide_set_base_addr(ide_id, 0, ide_port);
ide_port = ((dev->regs[0xc5] << 2) & 0xfff0) | 0x0006;
ide_set_base_addr(ide_id, 1, ide_port);
if (dev->regs[0xc2] & 0x20)
ide_handlers(ide_id, 1);
}
}
static void
fdc_handler(gm82c803c_t *dev)
{
uint16_t fdc_port = 0x0000;
uint8_t fdc_irq = 6;
uint8_t fdc_dma = 2;
fdc_port = (dev->regs[0xc3] << 2) & 0xfff0;
fdc_irq = dev->irq_map[dev->regs[0xca] >> 4];
fdc_dma = dev->dma_map[(dev->regs[0xc9] >> 4) & 0x03];
fdc_set_irq(dev->fdc, fdc_irq);
fdc_set_dma_ch(dev->fdc, fdc_dma);
fdc_remove(dev->fdc);
if (dev->regs[0xc2] & 0x10)
fdc_set_base(dev->fdc, fdc_port);
}
static void
set_serial_addr(gm82c803c_t *dev, int port)
{
uint16_t serial_port = 0x0000;
uint8_t serial_irq = COM1_IRQ;
double clock_src = 24000000.0 / 13.0;
if (dev->regs[0xce] & (1 << (6 + port)))
clock_src = 24000000.0 / 3.0;
else if (dev->regs[0xd1] & (1 << port))
clock_src = 24000000.0 / 12.0;
serial_remove(dev->uart[port]);
if (dev->regs[0xc2] & (0x04 << port)) {
serial_port = (dev->regs[0xc7 + port] << 2) & 0xfff8;
serial_irq = dev->irq_map[dev->regs[0xcb] >> ((port ^ 1) * 0xff)];
serial_setup(dev->uart[port], serial_port, serial_irq);
}
serial_set_clock_src(dev->uart[port], clock_src);
}
static void
lpt_handler(gm82c803c_t *dev)
{
uint16_t lpt_port = 0x0000;
uint16_t mask = 0xfffc;
uint8_t local_enable = 1;
uint8_t lpt_irq = LPT1_IRQ;
uint8_t lpt_dma = 3;
uint8_t lpt_mode = (dev->regs[0xc2] & 0x03);
switch (lpt_mode) {
default:
local_enable = 0;
break;
case 0x00:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 1);
break;
case 0x01:
lpt_set_epp(dev->lpt, !!(dev->regs[0xd0] & 0x20));
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
case 0x02:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, !!(dev->regs[0xd0] & 0x20));
lpt_set_ext(dev->lpt, 0);
break;
}
lpt_port = ((dev->regs[0xc6] << 2) & 0xfffc) & mask;
lpt_irq = dev->irq_map[dev->regs[0xca] & 0x0f];
lpt_dma = dev->dma_map[dev->regs[0xc9] & 0x03];
if (lpt_irq > 15)
lpt_irq = 0xff;
lpt_port_remove(dev->lpt);
lpt_set_fifo_threshold(dev->lpt, dev->regs[0x0a] & 0x0f);
if (local_enable && (lpt_port >= 0x0100) && (lpt_port <= (0x0ffc & mask)))
lpt_port_setup(dev->lpt, lpt_port);
lpt_port_irq(dev->lpt, lpt_irq);
lpt_port_dma(dev->lpt, lpt_dma);
}
static void
gm82c803c_write(uint16_t port, uint8_t val, void *priv)
{
gm82c803c_t *dev = (gm82c803c_t *) priv;
uint8_t valxor = 0;
if (dev->tries == 2) {
if (port == 0x0398) {
if (val == 0xcc)
dev->tries = 0;
else
dev->cur_reg = val;
} else {
if ((dev->cur_reg < 0xc2) || (dev->cur_reg > 0xd8))
return;
valxor = val ^ dev->regs[dev->cur_reg];
dev->regs[dev->cur_reg] = val;
switch (dev->cur_reg) {
default:
break;
case 0xc2:
if (valxor & 0x20)
ide_handler(dev);
if (valxor & 0x10)
fdc_handler(dev);
if (valxor & 0x08)
set_serial_addr(dev, 1);
if (valxor & 0x04)
set_serial_addr(dev, 0);
if (valxor & 0x03)
lpt_handler(dev);
break;
case 0xc3:
if (valxor)
fdc_handler(dev);
break;
case 0xc4: case 0xc5:
if (valxor)
ide_handler(dev);
break;
case 0xc6:
if (valxor)
lpt_handler(dev);
break;
case 0xc7:
if (valxor)
set_serial_addr(dev, 0);
case 0xc8:
if (valxor)
set_serial_addr(dev, 1);
case 0xc9:
if (valxor & 0xf0)
fdc_handler(dev);
if (valxor & 0x0f)
lpt_handler(dev);
break;
case 0xca:
if (valxor & 0xf0)
fdc_handler(dev);
if (valxor & 0x0f)
lpt_handler(dev);
break;
case 0xcb:
if (valxor & 0xf0)
set_serial_addr(dev, 0);
if (valxor & 0x0f)
set_serial_addr(dev, 1);
break;
case 0xce:
if (valxor & 0x80)
set_serial_addr(dev, 1);
if (valxor & 0x40)
set_serial_addr(dev, 0);
break;
case 0xd0:
if (valxor & 0x20)
lpt_handler(dev);
break;
case 0xd1:
if (valxor & 0x02)
set_serial_addr(dev, 1);
if (valxor & 0x01)
set_serial_addr(dev, 0);
break;
if (valxor & 0x20)
ide_handler(dev);
if (valxor & 0x08)
set_serial_addr(dev, 1);
if (valxor & 0x04)
set_serial_addr(dev, 0);
break;
}
}
} else if ((port == 0x0398) && (val == 0x33))
dev->tries++;
}
static uint8_t
gm82c803c_read(uint16_t port, void *priv)
{
const gm82c803c_t *dev = (gm82c803c_t *) priv;
uint8_t ret = 0xff;
if (dev->tries == 2) {
if ((port == 0x0399) && (dev->cur_reg >= 0xa0) && (dev->cur_reg <= 0xa1))
ret = dev->regs[dev->cur_reg];
}
return ret;
}
static void
gm82c803c_reset(gm82c803c_t *dev)
{
serial_remove(dev->uart[0]);
serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ);
serial_remove(dev->uart[1]);
serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ);
lpt_port_remove(dev->lpt);
lpt_port_setup(dev->lpt, LPT1_ADDR);
fdc_reset(dev->fdc);
fdc_remove(dev->fdc);
dev->tries = 0;
memset(dev->regs, 0, 256);
dev->regs[0xc0] = 0x3c;
dev->regs[0xc2] = 0x03;
dev->regs[0xc3] = 0x3c;
dev->regs[0xc4] = 0x3c;
dev->regs[0xc5] = 0x3d;
dev->regs[0xd5] = 0x3c;
set_serial_addr(dev, 0);
set_serial_addr(dev, 1);
lpt_handler(dev);
fdc_handler(dev);
if (dev->has_ide)
ide_handler(dev);
}
static void
gm82c803c_close(void *priv)
{
gm82c803c_t *dev = (gm82c803c_t *) priv;
free(dev);
}
static void *
gm82c803c_init(const device_t *info)
{
gm82c803c_t *dev = (gm82c803c_t *) calloc(1, sizeof(gm82c803c_t));
dev->fdc = device_add(&fdc_at_smc_device);
dev->has_ide = (info->local >> 8) & 0xff;
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
io_sethandler(0x0398, 0x0002,
gm82c803c_read, NULL, NULL, gm82c803c_write, NULL, NULL, dev);
dev->dma_map[0] = 4;
for (int i = 1; i < 4; i++)
dev->dma_map[i] = i;
memset(dev->irq_map, 0xff, 16);
dev->irq_map[0] = 0xff;
for (int i = 1; i < 7; i++)
dev->irq_map[i] = i;
dev->irq_map[1] = 5;
dev->irq_map[5] = 7;
dev->irq_map[7] = 0xff; /* Reserved. */
dev->irq_map[8] = 10;
gm82c803c_reset(dev);
return dev;
}
const device_t gm82c803c_device = {
.name = "Goldstar GM82C803C",
.internal_name = "gm82c803c",
.flags = 0,
.local = 0,
.init = gm82c803c_init,
.close = gm82c803c_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -296,6 +296,9 @@ it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
it86x1f_log("IT86x1F: LPT enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq);
lpt_port_setup(dev->lpt, config->io[0].base);
lpt_port_irq(dev->lpt, config->irq[0].irq);
lpt_port_dma(dev->lpt, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma);
} else {
it86x1f_log("IT86x1F: LPT disabled\n");
}
@@ -466,6 +469,13 @@ it86x1f_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv)
case 0x0f0:
dev->ldn_regs[ld][reg & 0x0f] = val & 0x0f;
fdc_set_swwp(dev->fdc, !!(val & 0x01));
if (val & 0x02) {
for (int i = 0; i < 4; i++)
fdc_update_drvrate(dev->fdc, i, 1);
} else {
for (int i = 0; i < 4; i++)
fdc_update_drvrate(dev->fdc, i, 0);
}
fdc_set_swap(dev->fdc, !!(val & 0x04));
break;
@@ -484,6 +494,8 @@ it86x1f_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv)
case 0x3f0:
dev->ldn_regs[ld][reg & 0x0f] = val & 0x07;
lpt_set_epp(dev->lpt, val & 0x01);
lpt_set_ecp(dev->lpt, val & 0x02);
break;
case 0x4f0:
@@ -772,6 +784,9 @@ it86x1f_reset(it86x1f_t *dev)
{
it86x1f_log("IT86x1F: reset()\n");
for (int i = 0; i < 4; i++)
fdc_update_drvrate(dev->fdc, i, 0);
fdc_reset(dev->fdc);
serial_remove(dev->uart[0]);
@@ -780,6 +795,9 @@ it86x1f_reset(it86x1f_t *dev)
lpt_port_remove(dev->lpt);
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE);
dev->locked = 1;
@@ -824,6 +842,7 @@ it86x1f_init(UNUSED(const device_t *info))
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_ext(dev->lpt, 1);
dev->gameport = gameport_add(&gameport_sio_device);

View File

@@ -125,13 +125,9 @@ lpt_handler(pc87306_t *dev)
uint16_t lptba;
uint16_t lpt_port = LPT1_ADDR;
uint8_t lpt_irq = LPT2_IRQ;
uint8_t lpt_dma = ((dev->regs[0x18] & 0x06) >> 1);
lpt_port_remove(dev->lpt);
if (lpt_dma == 0x00)
lpt_dma = 0xff;
temp = dev->regs[0x01] & 3;
lptba = ((uint16_t) dev->regs[0x19]) << 2;
@@ -172,8 +168,6 @@ lpt_handler(pc87306_t *dev)
lpt_port_setup(dev->lpt, lpt_port);
lpt_port_irq(dev->lpt, lpt_irq);
lpt_port_dma(dev->lpt, lpt_dma);
}
static void
@@ -374,6 +368,8 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
fdc_update_enh_mode(dev->fdc, (val & 4) ? 1 : 0);
fdc_update_densel_polarity(dev->fdc, (val & 0x40) ? 1 : 0);
}
if (valxor & 0x20)
lpt_set_cnfga_readout(dev->lpt, (val & 0x20) ? 0x18 : 0x10);
break;
case 0x0f:
if (valxor)
@@ -470,6 +466,7 @@ pc87306_reset_common(void *priv)
0 = 360 rpm @ 500 kbps for 3.5"
1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5"
*/
lpt_set_cnfga_readout(dev->lpt, 0x10);
lpt_port_remove(dev->lpt);
lpt_handler(dev);
serial_remove(dev->uart[0x00]);
@@ -517,6 +514,7 @@ pc87306_init(UNUSED(const device_t *info))
dev->uart[0x01] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_cnfga_readout(dev->lpt, 0x10);
dev->nvr = device_add(&at_mb_nvr_device);

View File

@@ -267,6 +267,7 @@ fdc_handler(pc87307_t *dev)
uint8_t active = (dev->ld_regs[LD_FDC][0x00] & 0x01) &&
(dev->pm[0x00] & 0x08);
uint8_t irq = (dev->ld_regs[LD_FDC][0x40] & 0x0f);
uint8_t dma = (dev->ld_regs[LD_FDC][0x44] & 0x0f);
uint16_t addr = ((dev->ld_regs[LD_FDC][0x30] << 8) |
dev->ld_regs[LD_FDC][0x31]) & 0xfff8;
@@ -274,6 +275,7 @@ fdc_handler(pc87307_t *dev)
pc87307_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq);
fdc_set_base(dev->fdc, addr);
fdc_set_irq(dev->fdc, irq);
fdc_set_dma_ch(dev->fdc, dma);
}
}
@@ -283,16 +285,61 @@ lpt_handler(pc87307_t *dev)
uint8_t active = (dev->ld_regs[LD_LPT][0x00] & 0x01) &&
(dev->pm[0x00] & 0x10);
uint8_t irq = (dev->ld_regs[LD_LPT][0x40] & 0x0f);
uint8_t dma = (dev->ld_regs[LD_LPT][0x44] & 0x0f);
uint16_t addr = (dev->ld_regs[LD_LPT][0x30] << 8) |
dev->ld_regs[LD_LPT][0x31];
uint8_t mode = (dev->ld_regs[LD_LPT][0xf0] >> 7);
uint16_t mask = 0xfffc;
if (active && (addr <= 0xfffc)) {
if (irq > 15)
irq = 0xff;
if (dma >= 4)
dma = 0xff;
lpt_port_remove(dev->lpt);
switch (mode) {
default:
case 0x00:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 0);
break;
case 0x01:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 1);
break;
case 0x02: case 0x03:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 0);
break;
case 0x04:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
case 0x07:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
}
lpt_set_cfg_regs_enabled(dev->lpt, !!(dev->ld_regs[LD_LPT][0xf0] & 0x10));
if (active && (addr <= (0xfffc & mask))) {
pc87307_log("Enabling LPT1 on %04X...\n", addr);
lpt_port_setup(dev->lpt, addr);
lpt_port_setup(dev->lpt, addr & mask);
} else
lpt_port_setup(dev->lpt, 0xffff);
lpt_port_irq(dev->lpt, irq);
lpt_port_dma(dev->lpt, dma);
}
static void
@@ -852,6 +899,7 @@ pc87307_init(const device_t *info)
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_cnfga_readout(dev->lpt, 0x14);
switch (info->local & PCX730X_KBC) {
default:

View File

@@ -183,6 +183,7 @@ fdc_handler(pc87309_t *dev)
uint8_t active = (dev->ld_regs[LD_FDC][0x00] & 0x01) &&
(dev->pm[0x00] & 0x08);
uint8_t irq = (dev->ld_regs[LD_FDC][0x40] & 0x0f);
uint8_t dma = (dev->ld_regs[LD_FDC][0x44] & 0x0f);
uint16_t addr = ((dev->ld_regs[LD_FDC][0x30] << 8) |
dev->ld_regs[LD_FDC][0x31]) & 0xfff8;
@@ -190,6 +191,7 @@ fdc_handler(pc87309_t *dev)
pc87309_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq);
fdc_set_base(dev->fdc, addr);
fdc_set_irq(dev->fdc, irq);
fdc_set_dma_ch(dev->fdc, dma);
}
}
@@ -199,16 +201,61 @@ lpt_handler(pc87309_t *dev)
uint8_t active = (dev->ld_regs[LD_LPT][0x00] & 0x01) &&
(dev->pm[0x00] & 0x10);
uint8_t irq = (dev->ld_regs[LD_LPT][0x40] & 0x0f);
uint8_t dma = (dev->ld_regs[LD_LPT][0x44] & 0x0f);
uint16_t addr = (dev->ld_regs[LD_LPT][0x30] << 8) |
dev->ld_regs[LD_LPT][0x31];
uint8_t mode = (dev->ld_regs[LD_LPT][0xf0] >> 7);
uint16_t mask = 0xfffc;
if (active && (addr <= 0xfffc)) {
if (irq > 15)
irq = 0xff;
if (dma >= 4)
dma = 0xff;
lpt_port_remove(dev->lpt);
switch (mode) {
default:
case 0x00:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 0);
break;
case 0x01:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 1);
break;
case 0x02: case 0x03:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 0);
break;
case 0x04:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
case 0x07:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
}
lpt_set_cfg_regs_enabled(dev->lpt, !!(dev->ld_regs[LD_LPT][0xf0] & 0x10));
if (active && (addr <= (0xfffc & mask))) {
pc87309_log("Enabling LPT1 on %04X...\n", addr);
lpt_port_setup(dev->lpt, addr);
lpt_port_setup(dev->lpt, addr & mask);
} else
lpt_port_setup(dev->lpt, 0xffff);
lpt_port_irq(dev->lpt, irq);
lpt_port_dma(dev->lpt, dma);
}
static void
@@ -687,6 +734,7 @@ pc87309_init(const device_t *info)
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_cnfga_readout(dev->lpt, 0x14);
switch (info->local & PCX730X_KBC) {
default:

View File

@@ -85,16 +85,16 @@ lpt_handler(pc87310_t *dev)
lpt_port_remove(dev->lpt);
switch (temp) {
case 0:
case 0x00:
lpt_port = LPT1_ADDR;
break;
case 1:
case 0x01:
lpt_port = LPT_MDA_ADDR;
break;
case 2:
case 0x02:
lpt_port = LPT2_ADDR;
break;
case 3:
case 0x03:
lpt_port = 0x000;
lpt_irq = 0xff;
break;
@@ -195,15 +195,15 @@ pc87310_write(UNUSED(uint16_t port), uint8_t val, void *priv)
serial_handler(dev);
/* Reconfigure IDE controller. */
if ((dev->flags & PC87310_IDE) && (valxor & 0x20)) {
if ((dev->flags & PCX73XX_IDE) && (valxor & 0x20)) {
pc87310_log("SIO: HDC disabled\n");
ide_pri_disable();
/* Bit 5: 1 = Disable IDE controller. */
if (!(val & 0x20)) {
pc87310_log("SIO: HDC enabled\n");
ide_set_base(0, 0x1f0);
ide_set_side(0, 0x3f6);
ide_pri_enable();
ide_set_side(0, 0x3f6);
ide_pri_enable();
}
}
@@ -256,7 +256,7 @@ pc87310_reset(pc87310_t *dev)
lpt_handler(dev);
serial_handler(dev);
if (dev->flags & PC87310_IDE) {
if (dev->flags & PCX73XX_IDE) {
ide_pri_disable();
ide_pri_enable();
}
@@ -285,17 +285,18 @@ pc87310_init(const device_t *info)
dev->uart[1] = device_add_inst(&ns16450_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_ext(dev->lpt, 1);
if (dev->flags & PC87310_IDE)
if (dev->flags & PCX73XX_IDE)
device_add((dev->flags & PC87310_ALI) ? &ide_vlb_device : &ide_isa_device);
pc87310_reset(dev);
io_sethandler(0x3f3, 0x0001,
io_sethandler(0x03f3, 0x0001,
pc87310_read, NULL, NULL, pc87310_write, NULL, NULL, dev);
if (dev->flags & PC87310_ALI)
io_sethandler(0x3f1, 0x0001,
io_sethandler(0x03f1, 0x0001,
pc87310_read, NULL, NULL, pc87310_write, NULL, NULL, dev);
return dev;

View File

@@ -1,319 +0,0 @@
/*
* 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 National Semiconductor PC87311 Super I/O
*
*
*
* Authors: Tiseno100
*
* Copyright 2020 Tiseno100
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sio.h>
#include <86box/plat_unused.h>
#define HAS_IDE_FUNCTIONALITY dev->ide_function
/* Basic Functionalities */
#define FUNCTION_ENABLE dev->regs[0x00]
#define FUNCTION_ADDRESS dev->regs[0x01]
#define POWER_TEST dev->regs[0x02]
/* Base Addresses */
#define LPT_BA (FUNCTION_ADDRESS & 0x03)
#define UART1_BA ((FUNCTION_ADDRESS >> 2) & 0x03)
#define UART2_BA ((FUNCTION_ADDRESS >> 4) & 0x03)
#define COM_BA ((FUNCTION_ADDRESS >> 6) & 0x03)
#ifdef ENABLE_PC87311_LOG
int pc87311_do_log = ENABLE_PC87311_LOG;
static void
pc87311_log(const char *fmt, ...)
{
va_list ap;
if (pc87311_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define pc87311_log(fmt, ...)
#endif
typedef struct pc87311_t {
uint8_t index;
uint8_t regs[256];
uint8_t cfg_lock;
uint8_t ide_function;
uint16_t base;
uint16_t irq;
fdc_t *fdc_controller;
serial_t *uart[2];
lpt_t *lpt;
} pc87311_t;
void pc87311_fdc_handler(pc87311_t *dev);
void pc87311_uart_handler(uint8_t num, pc87311_t *dev);
void pc87311_lpt_handler(pc87311_t *dev);
void pc87311_ide_handler(pc87311_t *dev);
void pc87311_enable(pc87311_t *dev);
static void
pc87311_write(uint16_t addr, uint8_t val, void *priv)
{
pc87311_t *dev = (pc87311_t *) priv;
switch (addr) {
case 0x398:
case 0x26e:
dev->index = val;
break;
case 0x399:
case 0x26f:
switch (dev->index) {
case 0x00:
FUNCTION_ENABLE = val;
break;
case 0x01:
FUNCTION_ADDRESS = val;
break;
case 0x02:
POWER_TEST = val;
break;
default:
break;
}
break;
default:
break;
}
pc87311_enable(dev);
}
static uint8_t
pc87311_read(UNUSED(uint16_t addr), void *priv)
{
const pc87311_t *dev = (pc87311_t *) priv;
return dev->regs[dev->index];
}
void
pc87311_fdc_handler(pc87311_t *dev)
{
fdc_remove(dev->fdc_controller);
fdc_set_base(dev->fdc_controller, (FUNCTION_ENABLE & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
pc87311_log("PC87311-FDC: BASE %04x\n", (FUNCTION_ENABLE & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
}
uint16_t
com3(pc87311_t *dev)
{
switch (COM_BA) {
case 0:
return COM3_ADDR;
case 1:
return 0x0338;
case 2:
return COM4_ADDR;
case 3:
return 0x0220;
default:
return COM3_ADDR;
}
}
uint16_t
com4(pc87311_t *dev)
{
switch (COM_BA) {
case 0:
return COM4_ADDR;
case 1:
return 0x0238;
case 2:
return 0x02e0;
case 3:
return 0x0228;
default:
return COM4_ADDR;
}
}
void
pc87311_uart_handler(uint8_t num, pc87311_t *dev)
{
serial_remove(dev->uart[num & 1]);
switch (!(num & 1) ? UART1_BA : UART2_BA) {
case 0:
dev->base = COM1_ADDR;
dev->irq = COM1_IRQ;
break;
case 1:
dev->base = COM2_ADDR;
dev->irq = COM2_IRQ;
break;
case 2:
dev->base = com3(dev);
dev->irq = COM3_IRQ;
break;
case 3:
dev->base = com4(dev);
dev->irq = COM4_IRQ;
break;
default:
break;
}
serial_setup(dev->uart[num & 1], dev->base, dev->irq);
pc87311_log("PC87311-UART%01x: BASE %04x IRQ %01x\n", num & 1, dev->base, dev->irq);
}
void
pc87311_lpt_handler(pc87311_t *dev)
{
lpt_port_remove(dev->lpt);
switch (LPT_BA) {
case 0:
dev->base = LPT1_ADDR;
dev->irq = (POWER_TEST & 0x08) ? LPT1_IRQ : LPT2_IRQ;
break;
case 1:
dev->base = LPT_MDA_ADDR;
dev->irq = LPT_MDA_IRQ;
break;
case 2:
dev->base = LPT2_ADDR;
dev->irq = LPT2_IRQ;
break;
default:
break;
}
lpt_port_setup(dev->lpt, dev->base);
lpt_port_irq(dev->lpt, dev->irq);
pc87311_log("PC87311-LPT: BASE %04x IRQ %01x\n", dev->base, dev->irq);
}
void
pc87311_ide_handler(pc87311_t *dev)
{
ide_pri_disable();
ide_sec_disable();
ide_set_base(0, 0x1f0);
ide_set_side(0, 0x3f6);
ide_pri_enable();
if (FUNCTION_ENABLE & 0x80) {
ide_set_base(1, 0x170);
ide_set_side(1, 0x376);
ide_sec_enable();
}
pc87311_log("PC87311-IDE: PRI %01x SEC %01x\n", (FUNCTION_ENABLE >> 6) & 1, (FUNCTION_ENABLE >> 7) & 1);
}
void
pc87311_enable(pc87311_t *dev)
{
(FUNCTION_ENABLE & 0x01) ? pc87311_lpt_handler(dev) : lpt_port_remove(dev->lpt);
(FUNCTION_ENABLE & 0x02) ? pc87311_uart_handler(0, dev) : serial_remove(dev->uart[0]);
(FUNCTION_ENABLE & 0x04) ? pc87311_uart_handler(1, dev) : serial_remove(dev->uart[1]);
(FUNCTION_ENABLE & 0x08) ? pc87311_fdc_handler(dev) : fdc_remove(dev->fdc_controller);
if (FUNCTION_ENABLE & 0x20)
pc87311_fdc_handler(dev);
if (HAS_IDE_FUNCTIONALITY) {
(FUNCTION_ENABLE & 0x40) ? pc87311_ide_handler(dev) : ide_pri_disable();
(FUNCTION_ADDRESS & 0x80) ? pc87311_ide_handler(dev) : ide_sec_disable();
}
}
static void
pc87311_close(void *priv)
{
pc87311_t *dev = (pc87311_t *) priv;
free(dev);
}
static void *
pc87311_init(const device_t *info)
{
pc87311_t *dev = (pc87311_t *) calloc(1, sizeof(pc87311_t));
/* Avoid conflicting with machines that make no use of the PC87311 Internal IDE */
HAS_IDE_FUNCTIONALITY = info->local;
dev->fdc_controller = device_add(&fdc_at_nsc_device);
dev->uart[0] = device_add_inst(&ns16450_device, 1);
dev->uart[1] = device_add_inst(&ns16450_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
if (HAS_IDE_FUNCTIONALITY)
device_add(&ide_isa_2ch_device);
io_sethandler(0x0398, 0x0002, pc87311_read, NULL, NULL, pc87311_write, NULL, NULL, dev);
io_sethandler(0x026e, 0x0002, pc87311_read, NULL, NULL, pc87311_write, NULL, NULL, dev);
pc87311_enable(dev);
return dev;
}
const device_t pc87311_device = {
.name = "National Semiconductor PC87311",
.internal_name = "pc87311",
.flags = 0,
.local = 0,
.init = pc87311_init,
.close = pc87311_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t pc87311_ide_device = {
.name = "National Semiconductor PC87311 with IDE functionality",
.internal_name = "pc87311_ide",
.flags = 0,
.local = 1,
.init = pc87311_init,
.close = pc87311_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -6,9 +6,7 @@
*
* This file is part of the 86Box distribution.
*
* Emulation of the NatSemi PC87332 Super I/O chip.
*
*
* Emulation of the NatSemi PC87311 and PC87332 Super I/O chips.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
@@ -35,40 +33,50 @@
#include <86box/fdc.h>
#include <86box/sio.h>
typedef struct pc87332_t {
typedef struct pc873xx_t {
uint8_t baddr;
uint8_t is_332;
uint8_t tries;
uint8_t has_ide;
uint8_t fdc_on;
uint8_t regs[15];
uint16_t base_addr;
int cur_reg;
int max_reg;
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
} pc87332_t;
} pc873xx_t;
static void
lpt_handler(pc87332_t *dev)
lpt_handler(pc873xx_t *dev)
{
int temp;
uint16_t lpt_port = LPT1_ADDR;
uint8_t lpt_irq = LPT2_IRQ;
uint8_t lpt_irq = LPT2_IRQ;
uint8_t lpt_dma = ((dev->regs[0x18] & 0x06) >> 1);
temp = dev->regs[0x01] & 3;
lpt_port_remove(dev->lpt);
if (lpt_dma == 0x00)
lpt_dma = 0xff;
temp = dev->regs[0x01] & 0x03;
switch (temp) {
case 0:
case 0x00:
lpt_port = LPT1_ADDR;
lpt_irq = (dev->regs[0x02] & 0x08) ? LPT1_IRQ : LPT2_IRQ;
break;
case 1:
case 0x01:
lpt_port = LPT_MDA_ADDR;
lpt_irq = LPT_MDA_IRQ;
lpt_irq = LPT_MDA_IRQ;
break;
case 2:
case 0x02:
lpt_port = LPT2_ADDR;
lpt_irq = LPT2_IRQ;
break;
case 3:
case 0x03:
lpt_port = 0x000;
lpt_irq = 0xff;
break;
@@ -77,6 +85,15 @@ lpt_handler(pc87332_t *dev)
break;
}
lpt_set_ext(dev->lpt, !!(dev->regs[0x02] & 0x80));
if (dev->is_332) {
lpt_set_epp(dev->lpt, !!(dev->regs[0x04] & 0x01));
lpt_set_ecp(dev->lpt, !!(dev->regs[0x04] & 0x04));
lpt_port_dma(dev->lpt, lpt_dma);
}
if (lpt_port)
lpt_port_setup(dev->lpt, lpt_port);
@@ -84,7 +101,7 @@ lpt_handler(pc87332_t *dev)
}
static void
serial_handler(pc87332_t *dev, int uart)
serial_handler(pc873xx_t *dev, int uart)
{
int temp;
@@ -142,7 +159,7 @@ serial_handler(pc87332_t *dev, int uart)
}
static void
ide_handler(pc87332_t *dev)
ide_handler(pc873xx_t *dev)
{
/* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */
if (dev->has_ide == 2) {
@@ -161,9 +178,9 @@ ide_handler(pc87332_t *dev)
}
static void
pc87332_write(uint16_t port, uint8_t val, void *priv)
pc873xx_write(uint16_t port, uint8_t val, void *priv)
{
pc87332_t *dev = (pc87332_t *) priv;
pc873xx_t *dev = (pc873xx_t *) priv;
uint8_t index;
uint8_t valxor;
@@ -177,7 +194,7 @@ pc87332_write(uint16_t port, uint8_t val, void *priv)
if (dev->tries) {
valxor = val ^ dev->regs[dev->cur_reg];
dev->tries = 0;
if ((dev->cur_reg <= 14) && (dev->cur_reg != 8))
if ((dev->cur_reg <= dev->max_reg) && (dev->cur_reg != 8))
dev->regs[dev->cur_reg] = val;
else
return;
@@ -187,69 +204,83 @@ pc87332_write(uint16_t port, uint8_t val, void *priv)
}
}
switch (dev->cur_reg) {
case 0:
if (valxor & 1) {
if (dev->cur_reg <= dev->max_reg) switch (dev->cur_reg) {
case 0x00:
if (valxor & 0x01) {
lpt_port_remove(dev->lpt);
if ((val & 1) && !(dev->regs[2] & 1))
if ((val & 0x01) && !(dev->regs[0x02] & 0x01))
lpt_handler(dev);
}
if (valxor & 2) {
if (valxor & 0x02) {
serial_remove(dev->uart[0]);
if ((val & 2) && !(dev->regs[2] & 1))
if ((val & 0x02) && !(dev->regs[0x02] & 0x01))
serial_handler(dev, 0);
}
if (valxor & 4) {
if (valxor & 0x04) {
serial_remove(dev->uart[1]);
if ((val & 4) && !(dev->regs[2] & 1))
if ((val & 0x04) && !(dev->regs[0x02] & 0x01))
serial_handler(dev, 1);
}
if (valxor & 0x28) {
fdc_remove(dev->fdc);
if ((val & 8) && !(dev->regs[2] & 1))
if ((val & 0x08) && !(dev->regs[0x02] & 0x01))
fdc_set_base(dev->fdc, (val & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
}
if (dev->has_ide && (valxor & 0xc0))
ide_handler(dev);
break;
case 1:
if (valxor & 3) {
case 0x01:
if (valxor & 0x03) {
lpt_port_remove(dev->lpt);
if ((dev->regs[0] & 1) && !(dev->regs[2] & 1))
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
lpt_handler(dev);
}
if (valxor & 0xcc) {
serial_remove(dev->uart[0]);
if ((dev->regs[0] & 2) && !(dev->regs[2] & 1))
if ((dev->regs[0x00] & 0x02) && !(dev->regs[0x02] & 0x01))
serial_handler(dev, 0);
}
if (valxor & 0xf0) {
serial_remove(dev->uart[1]);
if ((dev->regs[0] & 4) && !(dev->regs[2] & 1))
if ((dev->regs[0x00] & 0x04) && !(dev->regs[0x02] & 0x01))
serial_handler(dev, 1);
}
break;
case 2:
if (valxor & 1) {
case 0x02:
if (valxor & 0x01) {
lpt_port_remove(dev->lpt);
serial_remove(dev->uart[0]);
serial_remove(dev->uart[1]);
fdc_remove(dev->fdc);
if (!(val & 1)) {
if (dev->regs[0] & 1)
if (!(val & 0x01)) {
if (dev->regs[0x00] & 0x01)
lpt_handler(dev);
if (dev->regs[0] & 2)
if (dev->regs[0x00] & 0x02)
serial_handler(dev, 0);
if (dev->regs[0] & 4)
if (dev->regs[0x00] & 0x04)
serial_handler(dev, 1);
if (dev->regs[0] & 8)
fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
if (dev->regs[0x00] & 0x08)
fdc_set_base(dev->fdc, (dev->regs[0x00] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
}
}
if (valxor & 8) {
if (valxor & 0x88) {
lpt_port_remove(dev->lpt);
if ((dev->regs[0] & 1) && !(dev->regs[2] & 1))
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
lpt_handler(dev);
}
break;
case 0x04:
if (valxor & 0x05) {
lpt_port_remove(dev->lpt);
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
lpt_handler(dev);
}
break;
case 0x06:
if (valxor & 0x08) {
lpt_port_remove(dev->lpt);
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
lpt_handler(dev);
}
break;
@@ -260,9 +291,9 @@ pc87332_write(uint16_t port, uint8_t val, void *priv)
}
uint8_t
pc87332_read(uint16_t port, void *priv)
pc873xx_read(uint16_t port, void *priv)
{
pc87332_t *dev = (pc87332_t *) priv;
pc873xx_t *dev = (pc873xx_t *) priv;
uint8_t ret = 0xff;
uint8_t index;
@@ -283,7 +314,7 @@ pc87332_read(uint16_t port, void *priv)
}
void
pc87332_reset(pc87332_t *dev)
pc873xx_reset(pc873xx_t *dev)
{
memset(dev->regs, 0, 15);
@@ -314,17 +345,17 @@ pc87332_reset(pc87332_t *dev)
}
static void
pc87332_close(void *priv)
pc873xx_close(void *priv)
{
pc87332_t *dev = (pc87332_t *) priv;
pc873xx_t *dev = (pc873xx_t *) priv;
free(dev);
}
static void *
pc87332_init(const device_t *info)
pc873xx_init(const device_t *info)
{
pc87332_t *dev = (pc87332_t *) calloc(1, sizeof(pc87332_t));
pc873xx_t *dev = (pc873xx_t *) calloc(1, sizeof(pc873xx_t));
dev->fdc = device_add(&fdc_at_nsc_device);
@@ -333,84 +364,45 @@ pc87332_init(const device_t *info)
dev->lpt = device_add_inst(&lpt_port_device, 1);
dev->has_ide = (info->local >> 8) & 0xff;
dev->fdc_on = (info->local >> 16) & 0xff;
pc87332_reset(dev);
dev->is_332 = !!(info->local & PC87332);
dev->max_reg = dev->is_332 ? 0x08 : 0x02;
if ((info->local & 0xff) == 0x01) {
io_sethandler(0x398, 0x0002,
pc87332_read, NULL, NULL, pc87332_write, NULL, NULL, dev);
} else {
io_sethandler(0x02e, 0x0002,
pc87332_read, NULL, NULL, pc87332_write, NULL, NULL, dev);
dev->has_ide = info->local & (PCX73XX_IDE_PRI | PCX73XX_IDE_SEC);
dev->fdc_on = info->local & PCX73XX_FDC_ON;
dev->baddr = (info->local & PCX730X_BADDR) >> PCX730X_BADDR_SHIFT;
pc873xx_reset(dev);
switch (dev->baddr) {
default:
case 0x00:
dev->base_addr = 0x0398;
break;
case 0x01:
dev->base_addr = 0x026e;
break;
case 0x02:
dev->base_addr = 0x015c;
break;
case 0x03:
/* Our PC87332 machine use this unless otherwise specified. */
dev->base_addr = 0x002e;
break;
}
io_sethandler(dev->base_addr, 0x0002,
pc873xx_read, NULL, NULL, pc873xx_write, NULL, NULL, dev);
return dev;
}
const device_t pc87332_device = {
.name = "National Semiconductor PC87332 Super I/O",
.internal_name = "pc87332",
const device_t pc873xx_device = {
.name = "National Semiconductor PC873xx Super I/O",
.internal_name = "pc873xx",
.flags = 0,
.local = 0x00,
.init = pc87332_init,
.close = pc87332_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t pc87332_398_device = {
.name = "National Semiconductor PC87332 Super I/O (Port 398h)",
.internal_name = "pc87332_398",
.flags = 0,
.local = 0x01,
.init = pc87332_init,
.close = pc87332_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t pc87332_398_ide_device = {
.name = "National Semiconductor PC87332 Super I/O (Port 398h) (With IDE)",
.internal_name = "pc87332_398_ide",
.flags = 0,
.local = 0x101,
.init = pc87332_init,
.close = pc87332_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t pc87332_398_ide_sec_device = {
.name = "National Semiconductor PC87332 Super I/O (Port 398h) (With Secondary IDE)",
.internal_name = "pc87332_398_ide_sec",
.flags = 0,
.local = 0x201,
.init = pc87332_init,
.close = pc87332_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t pc87332_398_ide_fdcon_device = {
.name = "National Semiconductor PC87332 Super I/O (Port 398h) (With IDE and FDC on)",
.internal_name = "pc87332_398_ide_fdcon",
.flags = 0,
.local = 0x10101,
.init = pc87332_init,
.close = pc87332_close,
.init = pc873xx_init,
.close = pc873xx_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,

View File

@@ -1,312 +0,0 @@
/*
* 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 Goldstar Prime3B Super I/O
*
*
*
* Authors: Tiseno100
*
* Copyright 2021 Tiseno100
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sio.h>
#include <86box/plat_unused.h>
#define FSR dev->regs[0xa0]
#define ASR dev->regs[0xa1]
#define PDR dev->regs[0xa2]
#define HAS_IDE_FUNCTIONALITY dev->ide_function
#ifdef ENABLE_PRIME3B_LOG
int prime3b_do_log = ENABLE_PRIME3B_LOG;
static void
prime3b_log(const char *fmt, ...)
{
va_list ap;
if (prime3b_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define prime3b_log(fmt, ...)
#endif
typedef struct prime3b_t {
uint8_t index;
uint8_t regs[256];
uint8_t cfg_lock;
uint8_t ide_function;
uint16_t com3_addr;
uint16_t com4_addr;
fdc_t *fdc_controller;
serial_t *uart[2];
lpt_t *lpt;
} prime3b_t;
void prime3b_fdc_handler(prime3b_t *dev);
void prime3b_uart_handler(uint8_t num, prime3b_t *dev);
void prime3b_lpt_handler(prime3b_t *dev);
void prime3b_ide_handler(prime3b_t *dev);
void prime3b_enable(prime3b_t *dev);
void prime3b_powerdown(prime3b_t *dev);
static void
prime3b_write(uint16_t addr, uint8_t val, void *priv)
{
prime3b_t *dev = (prime3b_t *) priv;
if (addr == 0x398) {
dev->index = val;
/* Enter/Escape Configuration Mode */
if (val == 0x33)
dev->cfg_lock = 0;
else if (val == 0xcc)
dev->cfg_lock = 1;
} else if ((addr == 0x399) && !dev->cfg_lock) {
switch (dev->index) {
case 0xa0: /* Function Selection Register (FSR) */
FSR = val;
prime3b_enable(dev);
break;
case 0xa1: /* Address Selection Register (ASR) */
ASR = val;
prime3b_enable(dev);
break;
case 0xa2: /* Power Down Register (PDR) */
dev->regs[0xa2] = val;
break;
case 0xa3: /* Test Mode Register (TMR) */
dev->regs[0xa3] = val;
break;
case 0xa4: /* Miscellaneous Function Register */
dev->regs[0xa4] = val;
switch ((dev->regs[0xa4] >> 6) & 3) {
case 0:
dev->com3_addr = COM3_ADDR;
dev->com4_addr = COM4_ADDR;
break;
case 1:
dev->com3_addr = 0x338;
dev->com4_addr = 0x238;
break;
case 2:
dev->com3_addr = COM4_ADDR;
dev->com4_addr = 0x2e0;
break;
case 3:
dev->com3_addr = 0x220;
dev->com4_addr = 0x228;
break;
default:
break;
}
break;
case 0xa5: /* ECP Register */
dev->regs[0xa5] = val;
break;
default:
break;
}
}
}
static uint8_t
prime3b_read(UNUSED(uint16_t addr), void *priv)
{
const prime3b_t *dev = (prime3b_t *) priv;
return dev->regs[dev->index];
}
void
prime3b_fdc_handler(prime3b_t *dev)
{
uint16_t fdc_base = !(ASR & 0x40) ? FDC_PRIMARY_ADDR : FDC_SECONDARY_ADDR;
fdc_remove(dev->fdc_controller);
fdc_set_base(dev->fdc_controller, fdc_base);
prime3b_log("Prime3B-FDC: Enabled with base %03x\n", fdc_base);
}
void
prime3b_uart_handler(uint8_t num, prime3b_t *dev)
{
uint16_t uart_base;
if ((ASR >> (3 + 2 * num)) & 1)
uart_base = !((ASR >> (2 + 2 * num)) & 1) ? dev->com3_addr : dev->com4_addr;
else
uart_base = !((ASR >> (2 + 2 * num)) & 1) ? COM1_ADDR : COM2_ADDR;
serial_remove(dev->uart[num]);
serial_setup(dev->uart[num], uart_base, 4 - num);
prime3b_log("Prime3B-UART%d: Enabled with base %03x\n", num, uart_base);
}
void
prime3b_lpt_handler(prime3b_t *dev)
{
uint16_t lpt_base = (ASR & 2) ? LPT_MDA_ADDR : (!(ASR & 1) ? LPT1_ADDR : LPT2_ADDR);
lpt_port_remove(dev->lpt);
lpt_port_setup(dev->lpt, lpt_base);
lpt_port_irq(dev->lpt, LPT1_IRQ);
prime3b_log("Prime3B-LPT: Enabled with base %03x\n", lpt_base);
}
void
prime3b_ide_handler(prime3b_t *dev)
{
ide_pri_disable();
uint16_t ide_base = !(ASR & 0x80) ? 0x1f0 : 0x170;
uint16_t ide_side = ide_base + 0x206;
ide_set_base(0, ide_base);
ide_set_side(0, ide_side);
prime3b_log("Prime3B-IDE: Enabled with base %03x and side %03x\n", ide_base, ide_side);
}
void
prime3b_enable(prime3b_t *dev)
{
/*
Simulate a device enable/disable scenario
Register A0: Function Selection Register (FSR)
Bit 7: Gameport
Bit 6: 4 FDD Enable
Bit 5: IDE
Bit 4: FDC
Bit 3: UART 2
Bit 2: UART 1
Bit 1/0: PIO (0/0 Bidirectional , 0/1 ECP, 1/0 EPP, 1/1 Disabled)
Note: 86Box LPT is simplistic and can't do ECP or EPP.
*/
!(FSR & 3) ? prime3b_lpt_handler(dev) : lpt_port_remove(dev->lpt);
(FSR & 4) ? prime3b_uart_handler(0, dev) : serial_remove(dev->uart[0]);
(FSR & 8) ? prime3b_uart_handler(1, dev) : serial_remove(dev->uart[1]);
(FSR & 0x10) ? prime3b_fdc_handler(dev) : fdc_remove(dev->fdc_controller);
if (HAS_IDE_FUNCTIONALITY)
(FSR & 0x20) ? prime3b_ide_handler(dev) : ide_pri_disable();
}
void
prime3b_powerdown(prime3b_t *dev)
{
/* Note: It can be done more efficiently for sure */
uint8_t old_base = PDR;
if (PDR & 1)
PDR |= 0x1e;
if (PDR & 0x40)
io_removehandler(0x0398, 0x0002, prime3b_read, NULL, NULL, prime3b_write, NULL, NULL, dev);
if (PDR & 2)
fdc_remove(dev->fdc_controller);
if (PDR & 4)
serial_remove(dev->uart[0]);
if (PDR & 8)
serial_remove(dev->uart[1]);
if (PDR & 0x10)
lpt_port_remove(dev->lpt);
if (PDR & 1)
PDR = old_base;
}
static void
prime3b_close(void *priv)
{
prime3b_t *dev = (prime3b_t *) priv;
free(dev);
}
static void *
prime3b_init(const device_t *info)
{
prime3b_t *dev = (prime3b_t *) calloc(1, sizeof(prime3b_t));
/* Avoid conflicting with machines that make no use of the Prime3B Internal IDE */
HAS_IDE_FUNCTIONALITY = info->local;
dev->regs[0xa0] = 3;
dev->fdc_controller = device_add(&fdc_at_device);
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
if (HAS_IDE_FUNCTIONALITY)
device_add(&ide_isa_device);
dev->com3_addr = COM3_ADDR;
dev->com4_addr = COM4_ADDR;
fdc_reset(dev->fdc_controller);
prime3b_enable(dev);
io_sethandler(0x0398, 0x0002, prime3b_read, NULL, NULL, prime3b_write, NULL, NULL, dev);
return dev;
}
const device_t prime3b_device = {
.name = "Goldstar Prime3B",
.internal_name = "prime3b",
.flags = 0,
.local = 0,
.init = prime3b_init,
.close = prime3b_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t prime3b_ide_device = {
.name = "Goldstar Prime3B with IDE functionality",
.internal_name = "prime3b_ide",
.flags = 0,
.local = 1,
.init = prime3b_init,
.close = prime3b_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -1,358 +0,0 @@
/*
* 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 LG Prime3C Super I/O
*
*
*
* Authors: Tiseno100
*
* Copyright 2020 Tiseno100
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sio.h>
#include <86box/plat_unused.h>
#ifdef ENABLE_PRIME3C_LOG
int prime3c_do_log = ENABLE_PRIME3C_LOG;
static void
prime3c_log(const char *fmt, ...)
{
va_list ap;
if (prime3c_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define prime3c_log(fmt, ...)
#endif
/* Function Select(Note on prime3c_enable) */
#define FUNCTION_SELECT dev->regs[0xc2]
/* Base Address Registers */
#define FDC_BASE_ADDRESS dev->regs[0xc3]
#define IDE_BASE_ADDRESS dev->regs[0xc4]
#define IDE_SIDE_ADDRESS dev->regs[0xc5]
#define LPT_BASE_ADDRESS dev->regs[0xc6]
#define UART1_BASE_ADDRESS dev->regs[0xc7]
#define UART2_BASE_ADDRESS dev->regs[0xc8]
/* FDC/LPT Configuration */
#define FDC_LPT_DMA dev->regs[0xc9]
#define FDC_LPT_IRQ dev->regs[0xca]
/* UART 1/2 Configuration */
#define UART_IRQ dev->regs[0xcb]
/* Miscellaneous Configuration*/
#define FDC_SWAP (dev->regs[0xd6] & 0x01)
/* IDE functionality(Note on Init) */
#define HAS_IDE_FUNCTIONALITY dev->ide_function
typedef struct prime3c_t {
uint8_t index;
uint8_t regs[256];
uint8_t cfg_lock;
uint8_t ide_function;
fdc_t *fdc_controller;
serial_t *uart[2];
lpt_t *lpt;
} prime3c_t;
void prime3c_fdc_handler(prime3c_t *dev);
void prime3c_uart_handler(uint8_t num, prime3c_t *dev);
void prime3c_lpt_handler(prime3c_t *dev);
void prime3c_ide_handler(prime3c_t *dev);
void prime3c_enable(prime3c_t *dev);
static void
prime3c_write(uint16_t addr, uint8_t val, void *priv)
{
prime3c_t *dev = (prime3c_t *) priv;
switch (addr) {
case 0x398:
dev->index = val;
/* Enter/Escape Configuration Mode */
if (val == 0x33)
dev->cfg_lock = 0;
else if (val == 0x55)
dev->cfg_lock = 1;
break;
case 0x399:
if (!dev->cfg_lock) {
switch (dev->index) {
case 0xc2:
FUNCTION_SELECT = val & 0xbf;
prime3c_enable(dev);
break;
case 0xc3:
FDC_BASE_ADDRESS = val & 0xfc;
prime3c_fdc_handler(dev);
break;
case 0xc4:
IDE_BASE_ADDRESS = val & 0xfc;
if (HAS_IDE_FUNCTIONALITY)
prime3c_ide_handler(dev);
break;
case 0xc5:
IDE_SIDE_ADDRESS = (val & 0xfc) | 0x02;
if (HAS_IDE_FUNCTIONALITY)
prime3c_ide_handler(dev);
break;
case 0xc6:
LPT_BASE_ADDRESS = val;
break;
case 0xc7:
UART1_BASE_ADDRESS = val & 0xfe;
prime3c_uart_handler(0, dev);
break;
case 0xc8:
UART2_BASE_ADDRESS = val & 0xfe;
prime3c_uart_handler(1, dev);
break;
case 0xc9:
FDC_LPT_DMA = val;
prime3c_fdc_handler(dev);
break;
case 0xca:
FDC_LPT_IRQ = val;
prime3c_fdc_handler(dev);
prime3c_lpt_handler(dev);
break;
case 0xcb:
UART_IRQ = val;
prime3c_uart_handler(0, dev);
prime3c_uart_handler(1, dev);
break;
case 0xcd:
case 0xce:
dev->regs[dev->index] = val;
break;
case 0xcf:
dev->regs[dev->index] = val & 0x3f;
break;
case 0xd0:
dev->regs[dev->index] = val & 0xfc;
break;
case 0xd1:
dev->regs[dev->index] = val & 0x3f;
break;
case 0xd3:
dev->regs[dev->index] = val & 0x7c;
break;
case 0xd5:
case 0xd6:
case 0xd7:
case 0xd8:
dev->regs[dev->index] = val;
break;
default:
break;
}
}
break;
default:
break;
}
}
static uint8_t
prime3c_read(UNUSED(uint16_t addr), void *priv)
{
const prime3c_t *dev = (prime3c_t *) priv;
return dev->regs[dev->index];
}
void
prime3c_fdc_handler(prime3c_t *dev)
{
fdc_remove(dev->fdc_controller);
if (FUNCTION_SELECT & 0x10) {
fdc_set_base(dev->fdc_controller, FDC_BASE_ADDRESS << 2);
fdc_set_irq(dev->fdc_controller, (FDC_LPT_IRQ >> 4) & 0xf);
fdc_set_dma_ch(dev->fdc_controller, (FDC_LPT_DMA >> 4) & 0xf);
fdc_set_swap(dev->fdc_controller, FDC_SWAP);
prime3c_log("Prime3C-FDC: BASE %04x IRQ %01x DMA %01x\n", FDC_BASE_ADDRESS << 2, (FDC_LPT_IRQ >> 4) & 0xf, (FDC_LPT_DMA >> 4) & 0xf);
}
}
void
prime3c_uart_handler(uint8_t num, prime3c_t *dev)
{
serial_remove(dev->uart[num & 1]);
if (FUNCTION_SELECT & (!(num & 1) ? 0x04 : 0x08)) {
serial_setup(dev->uart[num & 1], (!(num & 1) ? UART1_BASE_ADDRESS : UART2_BASE_ADDRESS) << 2, (UART_IRQ >> (!(num & 1) ? 4 : 0)) & 0xf);
prime3c_log("Prime3C-UART%01x: BASE %04x IRQ %01x\n", num & 1, (!(num & 1) ? UART1_BASE_ADDRESS : UART2_BASE_ADDRESS) << 2, (UART_IRQ >> (!(num & 1) ? 4 : 0)) & 0xf);
}
}
void
prime3c_lpt_handler(prime3c_t *dev)
{
lpt_port_remove(dev->lpt);
if (!(FUNCTION_SELECT & 0x03)) {
lpt_port_setup(dev->lpt, LPT_BASE_ADDRESS << 2);
lpt_port_irq(dev->lpt, FDC_LPT_IRQ & 0xf);
prime3c_log("Prime3C-LPT: BASE %04x IRQ %02x\n", LPT_BASE_ADDRESS << 2, FDC_LPT_IRQ & 0xf);
}
}
void
prime3c_ide_handler(prime3c_t *dev)
{
ide_pri_disable();
if (FUNCTION_SELECT & 0x20) {
ide_set_base(0, IDE_BASE_ADDRESS << 2);
ide_set_side(0, IDE_SIDE_ADDRESS << 2);
ide_pri_enable();
prime3c_log("Prime3C-IDE: BASE %04x SIDE %04x\n", IDE_BASE_ADDRESS << 2, IDE_SIDE_ADDRESS << 2);
}
}
void
prime3c_enable(prime3c_t *dev)
{
/*
Simulate a device enable/disable scenario
Register C2: Function Select
Bit 7: Gameport
Bit 6: Reserved
Bit 5: IDE
Bit 4: FDC
Bit 3: UART 2
Bit 2: UART 1
Bit 1/0: PIO (0/0 Unidirectional , 0/1 ECP, 1/0 EPP, 1/1 Disabled)
Note: 86Box LPT is simplistic and can't do ECP or EPP.
*/
!(FUNCTION_SELECT & 0x03) ? prime3c_lpt_handler(dev) : lpt_port_remove(dev->lpt);
(FUNCTION_SELECT & 0x04) ? prime3c_uart_handler(0, dev) : serial_remove(dev->uart[0]);
(FUNCTION_SELECT & 0x08) ? prime3c_uart_handler(1, dev) : serial_remove(dev->uart[1]);
(FUNCTION_SELECT & 0x10) ? prime3c_fdc_handler(dev) : fdc_remove(dev->fdc_controller);
if (HAS_IDE_FUNCTIONALITY)
(FUNCTION_SELECT & 0x20) ? prime3c_ide_handler(dev) : ide_pri_disable();
}
static void
prime3c_close(void *priv)
{
prime3c_t *dev = (prime3c_t *) priv;
free(dev);
}
static void *
prime3c_init(const device_t *info)
{
prime3c_t *dev = (prime3c_t *) calloc(1, sizeof(prime3c_t));
/* Avoid conflicting with machines that make no use of the Prime3C Internal IDE */
HAS_IDE_FUNCTIONALITY = info->local;
dev->regs[0xc0] = 0x3c;
dev->regs[0xc2] = 0x03;
dev->regs[0xc3] = 0x3c;
dev->regs[0xc4] = 0x3c;
dev->regs[0xc5] = 0x3d;
dev->regs[0xd5] = 0x3c;
dev->fdc_controller = device_add(&fdc_at_device);
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
if (HAS_IDE_FUNCTIONALITY)
device_add(&ide_isa_device);
prime3c_fdc_handler(dev);
prime3c_uart_handler(0, dev);
prime3c_uart_handler(1, dev);
prime3c_lpt_handler(dev);
if (HAS_IDE_FUNCTIONALITY)
prime3c_ide_handler(dev);
io_sethandler(0x0398, 0x0002, prime3c_read, NULL, NULL, prime3c_write, NULL, NULL, dev);
return dev;
}
const device_t prime3c_device = {
.name = "Goldstar Prime3C",
.internal_name = "prime3c",
.flags = 0,
.local = 0,
.init = prime3c_init,
.close = prime3c_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t prime3c_ide_device = {
.name = "Goldstar Prime3C with IDE functionality",
.internal_name = "prime3c_ide",
.flags = 0,
.local = 1,
.init = prime3c_init,
.close = prime3c_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -92,7 +92,8 @@ static uint8_t um8669f_pnp_rom[] = {
0x15, 0x41, 0xd0, 0x04, 0x00, 0x01, /* logical device PNP0400, can participate in boot */
0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x06, 0x00, 0x01, /* logical device PNP0600, can participate in boot */
0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */
@@ -120,7 +121,8 @@ static const isapnp_device_config_t um8669f_pnp_defaults[] = {
}, {
.activate = 1,
.io = { { .base = LPT1_ADDR }, },
.irq = { { .irq = LPT1_IRQ }, }
.irq = { { .irq = LPT1_IRQ }, },
.dma = { { .dma = 3 }, }
}, {
.activate = 0,
.io = { { .base = 0x1f0 }, },
@@ -268,6 +270,9 @@ um8669f_write(uint16_t port, uint8_t val, void *priv)
if (dev->cur_reg == 0xc1) {
um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis");
isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE);
} else if (dev->cur_reg == 0xc0) {
lpt_set_epp(dev->lpt, val & 0x08);
lpt_set_ecp(dev->lpt, val & 0x10);
}
}
}
@@ -304,6 +309,9 @@ um8669f_reset(um8669f_t *dev)
lpt_port_remove(dev->lpt);
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
if (dev->ide < IDE_BUS_MAX)
ide_remove_handlers(dev->ide);
@@ -341,8 +349,9 @@ um8669f_init(const device_t *info)
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
lpt_set_ext(dev->lpt, 1);
dev->ide = info->local;
dev->ide = (uint8_t) (info->local - 1);
if (dev->ide < IDE_BUS_MAX)
device_add(&ide_isa_device);
@@ -360,20 +369,6 @@ const device_t um8669f_device = {
.name = "UMC UM8669F Super I/O",
.internal_name = "um8669f",
.flags = 0,
.local = 0xff,
.init = um8669f_init,
.close = um8669f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8669f_ide_device = {
.name = "UMC UM8669F Super I/O (With IDE)",
.internal_name = "um8669f_ide",
.flags = 0,
.local = 0,
.init = um8669f_init,
.close = um8669f_close,
@@ -383,17 +378,3 @@ const device_t um8669f_ide_device = {
.force_redraw = NULL,
.config = NULL
};
const device_t um8669f_ide_sec_device = {
.name = "UMC UM8669F Super I/O (With Secondary IDE)",
.internal_name = "um8669f_ide_sec",
.flags = 0,
.local = 1,
.init = um8669f_init,
.close = um8669f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -6,7 +6,8 @@
*
* This file is part of the 86Box distribution.
*
* Implementation of the UMC UMF8663F Super I/O chip.
* Implementation of the UMC UM82C862F, UM82C863F, UM86863F,
* and UM8663BF Super I/O chips.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
@@ -35,25 +36,25 @@
#include <86box/random.h>
#include <86box/plat_unused.h>
#ifdef ENABLE_UM8663F_LOG
int um8663f_do_log = ENABLE_UM8663F_LOG;
#ifdef ENABLE_UM866X_LOG
int um866x_do_log = ENABLE_UM866X_LOG;
static void
um8663f_log(const char *fmt, ...)
um866x_log(const char *fmt, ...)
{
va_list ap;
if (um8663f_do_log) {
if (um866x_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define um8663f_log(fmt, ...)
# define um866x_log(fmt, ...)
#endif
typedef struct um8663f_t {
typedef struct um866x_t {
uint8_t max_reg;
uint8_t ide;
uint8_t locked;
@@ -64,10 +65,10 @@ typedef struct um8663f_t {
serial_t *uart[2];
lpt_t * lpt;
} um8663f_t;
} um866x_t;
static void
um8663f_fdc_handler(um8663f_t *dev)
um866x_fdc_handler(um866x_t *dev)
{
fdc_remove(dev->fdc);
if (dev->regs[0] & 0x01)
@@ -75,7 +76,7 @@ um8663f_fdc_handler(um8663f_t *dev)
}
static void
um8663f_uart_handler(um8663f_t *dev, int port)
um866x_uart_handler(um866x_t *dev, int port)
{
uint8_t shift = (port + 1);
@@ -102,10 +103,32 @@ um8663f_uart_handler(um8663f_t *dev, int port)
}
static void
um8663f_lpt_handler(um8663f_t *dev)
um866x_lpt_handler(um866x_t *dev)
{
int enabled = (dev->regs[0] & 0x08);
lpt_port_remove(dev->lpt);
if (dev->regs[0] & 0x08) {
switch(dev->regs[1] & 0xc0) {
case 0x00:
enabled = 0;
break;
case 0x40:
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 0);
break;
case 0x80:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 1);
break;
case 0xc0:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
}
if (enabled) {
switch ((dev->regs[1] >> 3) & 0x01) {
case 0x01:
lpt_port_setup(dev->lpt, LPT1_ADDR);
@@ -123,7 +146,7 @@ um8663f_lpt_handler(um8663f_t *dev)
}
static void
um8663f_ide_handler(um8663f_t *dev)
um866x_ide_handler(um866x_t *dev)
{
int board = dev->ide - 1;
@@ -137,12 +160,12 @@ um8663f_ide_handler(um8663f_t *dev)
}
static void
um8663f_write(uint16_t port, uint8_t val, void *priv)
um866x_write(uint16_t port, uint8_t val, void *priv)
{
um8663f_t *dev = (um8663f_t *) priv;
um866x_t *dev = (um866x_t *) priv;
uint8_t valxor;
um8663f_log("UM8663F: write(%04X, %02X)\n", port, val);
um866x_log("UM866X: write(%04X, %02X)\n", port, val);
if (dev->locked) {
if ((port == 0x108) && (val == 0xaa))
@@ -160,15 +183,15 @@ um8663f_write(uint16_t port, uint8_t val, void *priv)
/* Port enable register. */
case 0x00:
if (valxor & 0x10)
um8663f_ide_handler(dev);
um866x_ide_handler(dev);
if (valxor & 0x08)
um8663f_lpt_handler(dev);
um866x_lpt_handler(dev);
if (valxor & 0x04)
um8663f_uart_handler(dev, 1);
um866x_uart_handler(dev, 1);
if (valxor & 0x02)
um8663f_uart_handler(dev, 0);
um866x_uart_handler(dev, 0);
if (valxor & 0x01)
um8663f_fdc_handler(dev);
um866x_fdc_handler(dev);
break;
/*
Port configuration register:
@@ -184,16 +207,16 @@ um8663f_write(uint16_t port, uint8_t val, void *priv)
- Bit 0 = 0 = FDC is 370h, 1 = UART 2 is 3f0h.
*/
case 0x01:
if (valxor & 0xc8)
um866x_lpt_handler(dev);
if (valxor & 0x10)
um8663f_ide_handler(dev);
if (valxor & 0x08)
um8663f_lpt_handler(dev);
um866x_ide_handler(dev);
if (valxor & 0x04)
um8663f_uart_handler(dev, 1);
um866x_uart_handler(dev, 1);
if (valxor & 0x02)
um8663f_uart_handler(dev, 0);
um866x_uart_handler(dev, 0);
if (valxor & 0x01)
um8663f_fdc_handler(dev);
um866x_fdc_handler(dev);
break;
}
}
@@ -201,9 +224,9 @@ um8663f_write(uint16_t port, uint8_t val, void *priv)
}
static uint8_t
um8663f_read(uint16_t port, void *priv)
um866x_read(uint16_t port, void *priv)
{
const um8663f_t *dev = (um8663f_t *) priv;
const um866x_t *dev = (um866x_t *) priv;
uint8_t ret = 0xff;
if (!dev->locked) {
@@ -216,15 +239,15 @@ um8663f_read(uint16_t port, void *priv)
}
}
um8663f_log("UM8663F: read(%04X) = %02X\n", port, ret);
um866x_log("UM866X: read(%04X) = %02X\n", port, ret);
return ret;
}
static void
um8663f_reset(void *priv)
um866x_reset(void *priv)
{
um8663f_t *dev = (um8663f_t *) priv;
um866x_t *dev = (um866x_t *) priv;
serial_remove(dev->uart[0]);
serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ);
@@ -243,27 +266,27 @@ um8663f_reset(void *priv)
dev->regs[0x00] = (dev->ide > 0) ? 0x1f : 0x0f;
dev->regs[0x01] = (dev->ide == 2) ? 0x0f : 0x1f;
um8663f_fdc_handler(dev);
um8663f_uart_handler(dev, 0);
um8663f_uart_handler(dev, 1);
um8663f_lpt_handler(dev);
um8663f_ide_handler(dev);
um866x_fdc_handler(dev);
um866x_uart_handler(dev, 0);
um866x_uart_handler(dev, 1);
um866x_lpt_handler(dev);
um866x_ide_handler(dev);
dev->locked = 1;
}
static void
um8663f_close(void *priv)
um866x_close(void *priv)
{
um8663f_t *dev = (um8663f_t *) priv;
um866x_t *dev = (um866x_t *) priv;
free(dev);
}
static void *
um8663f_init(UNUSED(const device_t *info))
um866x_init(UNUSED(const device_t *info))
{
um8663f_t *dev = (um8663f_t *) calloc(1, sizeof(um8663f_t));
um866x_t *dev = (um866x_t *) calloc(1, sizeof(um866x_t));
dev->fdc = device_add(&fdc_at_smc_device);
@@ -279,147 +302,21 @@ um8663f_init(UNUSED(const device_t *info))
dev->max_reg = info->local >> 8;
if (dev->max_reg != 0x00)
io_sethandler(0x0108, 0x0002, um8663f_read, NULL, NULL, um8663f_write, NULL, NULL, dev);
io_sethandler(0x0108, 0x0002, um866x_read, NULL, NULL, um866x_write, NULL, NULL, dev);
um8663f_reset(dev);
um866x_reset(dev);
return dev;
}
const device_t um82c862f_device = {
.name = "UMC UM82C862F Super I/O",
.internal_name = "um82c862f",
const device_t um866x_device = {
.name = "UMC UM82C86x/866x Super I/O",
.internal_name = "um866x",
.flags = 0,
.local = 0x0000,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um82c862f_ide_device = {
.name = "UMC UM82C862F Super I/O (With IDE)",
.internal_name = "um82c862f_ide",
.flags = 0,
.local = 0x0001,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um82c863f_device = {
.name = "UMC UM82C863F Super I/O",
.internal_name = "um82c863f",
.flags = 0,
.local = 0xc100,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um82c863f_ide_device = {
.name = "UMC UM82C863F Super I/O (With IDE)",
.internal_name = "um82c863f_ide",
.flags = 0,
.local = 0xc101,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8663af_device = {
.name = "UMC UM8663AF Super I/O",
.internal_name = "um8663af",
.flags = 0,
.local = 0xc300,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8663af_ide_device = {
.name = "UMC UM8663AF Super I/O (With IDE)",
.internal_name = "um8663af_ide",
.flags = 0,
.local = 0xc301,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8663af_ide_sec_device = {
.name = "UMC UM8663AF Super I/O (With Secondary IDE)",
.internal_name = "um8663af_ide_sec",
.flags = 0,
.local = 0xc302,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8663bf_device = {
.name = "UMC UM8663BF Super I/O",
.internal_name = "um8663bf",
.flags = 0,
.local = 0xc400,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8663bf_ide_device = {
.name = "UMC UM8663BF Super I/O (With IDE)",
.internal_name = "um8663bf_ide",
.flags = 0,
.local = 0xc401,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8663bf_ide_sec_device = {
.name = "UMC UM8663BF Super I/O (With Secondary IDE)",
.internal_name = "um8663bf_ide_sec",
.flags = 0,
.local = 0xc402,
.init = um8663f_init,
.close = um8663f_close,
.reset = um8663f_reset,
.local = 0,
.init = um866x_init,
.close = um866x_close,
.reset = um866x_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,

View File

@@ -86,14 +86,28 @@ vt82c686_lpt_handler(vt82c686_t *dev)
lpt_port_remove(dev->lpt);
lpt_set_ext(dev->lpt, !!(dev->regs[0x10] & 0x80));
switch (dev->regs[0x10] & 0x03) {
case 0x01:
lpt_set_epp(dev->lpt, !!(dev->regs[0x10] & 0x20));
lpt_set_ecp(dev->lpt, 1);
break;
case 0x02:
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, !!(dev->regs[0x10] & 0x20));
break;
}
if (((dev->regs[0x02] & 0x03) != 0x03) && !(dev->regs[0x0f] & 0x11) && (io_base >= 0x100) && (io_base <= io_mask))
lpt_port_setup(dev->lpt, io_base);
if (dev->lpt_irq) {
if (dev->lpt_irq)
lpt_port_irq(dev->lpt, dev->lpt_irq);
} else {
else
lpt_port_irq(dev->lpt, 0xff);
}
lpt_port_dma(dev->lpt, dev->lpt_dma);
}
static void
@@ -178,6 +192,7 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv)
case 0x10:
dev->regs[reg] &= 0xf4;
vt82c686_lpt_handler(dev);
break;
case 0x11:

View File

@@ -1,539 +0,0 @@
/*
* 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 Winbond W83787F/IF Super I/O Chip.
*
* Winbond W83787F Super I/O Chip
* Used by the Award 430HX
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Copyright 2020 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/gameport.h>
#include <86box/sio.h>
#ifdef ENABLE_W83787_LOG
int w83787_do_log = ENABLE_W83787_LOG;
static void
w83787_log(const char *fmt, ...)
{
va_list ap;
if (w83787_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define w83787_log(fmt, ...)
#endif
#define FDDA_TYPE (dev->regs[7] & 3)
#define FDDB_TYPE ((dev->regs[7] >> 2) & 3)
#define FDDC_TYPE ((dev->regs[7] >> 4) & 3)
#define FDDD_TYPE ((dev->regs[7] >> 6) & 3)
#define FD_BOOT (dev->regs[8] & 3)
#define SWWP ((dev->regs[8] >> 4) & 1)
#define DISFDDWR ((dev->regs[8] >> 5) & 1)
#define EN3MODE ((dev->regs[9] >> 5) & 1)
#define DRV2EN_NEG (dev->regs[0xB] & 1) /* 0 = drive 2 installed */
#define INVERTZ ((dev->regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */
#define IDENT ((dev->regs[0xB] >> 3) & 1)
#define HEFERE ((dev->regs[0xC] >> 5) & 1)
#define HAS_IDE_FUNCTIONALITY dev->ide_function
typedef struct w83787f_t {
uint8_t tries;
uint8_t regs[42];
uint16_t reg_init;
int locked;
int rw_locked;
int cur_reg;
int key;
int ide_function;
int ide_start;
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
void *gameport;
} w83787f_t;
static void w83787f_write(uint16_t port, uint8_t val, void *priv);
static uint8_t w83787f_read(uint16_t port, void *priv);
static void
w83787f_remap(w83787f_t *dev)
{
io_removehandler(0x250, 0x0004,
w83787f_read, NULL, NULL, w83787f_write, NULL, NULL, dev);
io_sethandler(0x250, 0x0004,
w83787f_read, NULL, NULL, w83787f_write, NULL, NULL, dev);
dev->key = 0x88 | HEFERE;
}
#ifdef FIXME
/* FIXME: Implement EPP (and ECP) parallel port modes. */
static uint8_t
get_lpt_length(w83787f_t *dev)
{
uint8_t length = 4;
if (dev->regs[9] & 0x80) {
if (dev->regs[0] & 0x04)
length = 8; /* EPP mode. */
if (dev->regs[0] & 0x08)
length |= 0x80; /* ECP mode. */
}
return length;
}
#endif
static void
w83787f_serial_handler(w83787f_t *dev, int uart)
{
int urs0 = !!(dev->regs[1] & (1 << uart));
int urs1 = !!(dev->regs[1] & (4 << uart));
int urs2 = !!(dev->regs[3] & (8 >> uart));
int urs;
int irq = COM1_IRQ;
uint16_t addr = COM1_ADDR;
uint16_t enable = 1;
urs = (urs1 << 1) | urs0;
if (urs2) {
addr = uart ? COM1_ADDR : COM2_ADDR;
irq = uart ? COM1_IRQ : COM2_IRQ;
} else {
switch (urs) {
case 0:
addr = uart ? COM3_ADDR : COM4_ADDR;
irq = uart ? COM3_IRQ : COM4_IRQ;
break;
case 1:
addr = uart ? COM4_ADDR : COM3_ADDR;
irq = uart ? COM4_IRQ : COM3_IRQ;
break;
case 2:
addr = uart ? COM2_ADDR : COM1_ADDR;
irq = uart ? COM2_IRQ : COM1_IRQ;
break;
case 3:
default:
enable = 0;
break;
}
}
if (dev->regs[4] & (0x20 >> uart))
enable = 0;
serial_remove(dev->uart[uart]);
if (enable)
serial_setup(dev->uart[uart], addr, irq);
}
static void
w83787f_lpt_handler(w83787f_t *dev)
{
int ptras = (dev->regs[1] >> 4) & 0x03;
int irq = LPT1_IRQ;
uint16_t addr = LPT1_ADDR;
uint16_t enable = 1;
switch (ptras) {
case 0x00:
addr = LPT_MDA_ADDR;
irq = LPT_MDA_IRQ;
break;
case 0x01:
addr = LPT2_ADDR;
irq = LPT2_IRQ;
break;
case 0x02:
addr = LPT1_ADDR;
irq = LPT1_IRQ;
break;
case 0x03:
default:
enable = 0;
break;
}
if (dev->regs[4] & 0x80)
enable = 0;
lpt_port_remove(dev->lpt);
if (enable) {
lpt_port_setup(dev->lpt, addr);
lpt_port_irq(dev->lpt, irq);
}
}
static void
w83787f_gameport_handler(w83787f_t *dev)
{
if (!(dev->regs[3] & 0x40) && !(dev->regs[4] & 0x40))
gameport_remap(dev->gameport, 0x201);
else
gameport_remap(dev->gameport, 0);
}
static void
w83787f_fdc_handler(w83787f_t *dev)
{
fdc_remove(dev->fdc);
if (!(dev->regs[0] & 0x20))
fdc_set_base(dev->fdc, (dev->regs[0] & 0x10) ? FDC_PRIMARY_ADDR : FDC_SECONDARY_ADDR);
fdc_set_power_down(dev->fdc, !!(dev->regs[6] & 0x08));
}
static void
w83787f_ide_handler(w83787f_t *dev)
{
if (dev->ide_function & 0x20) {
ide_sec_disable();
if (!(dev->regs[0] & 0x80)) {
ide_set_base(1, (dev->regs[0] & 0x40) ? 0x1f0 : 0x170);
ide_set_side(1, (dev->regs[0] & 0x40) ? 0x3f6 : 0x376);
ide_sec_enable();
}
} else {
ide_pri_disable();
if (!(dev->regs[0] & 0x80)) {
ide_set_base(0, (dev->regs[0] & 0x40) ? 0x1f0 : 0x170);
ide_set_side(0, (dev->regs[0] & 0x40) ? 0x3f6 : 0x376);
ide_pri_enable();
}
}
}
static void
w83787f_write(uint16_t port, uint8_t val, void *priv)
{
w83787f_t *dev = (w83787f_t *) priv;
uint8_t valxor = 0;
uint8_t max = 0x15;
if (port == 0x250) {
if (val == dev->key)
dev->locked = 1;
else
dev->locked = 0;
return;
} else if (port == 0x251) {
if (val <= max)
dev->cur_reg = val;
return;
} else {
if (dev->locked) {
if (dev->rw_locked && (dev->cur_reg <= 0x0b))
return;
if (dev->cur_reg == 6)
val &= 0xFB;
valxor = val ^ dev->regs[dev->cur_reg];
dev->regs[dev->cur_reg] = val;
} else
return;
}
switch (dev->cur_reg) {
case 0:
w83787_log("REG 00: %02X\n", val);
if ((valxor & 0xc0) && (HAS_IDE_FUNCTIONALITY))
w83787f_ide_handler(dev);
if (valxor & 0x30)
w83787f_fdc_handler(dev);
if (valxor & 0x0c)
w83787f_lpt_handler(dev);
break;
case 1:
if (valxor & 0x80)
fdc_set_swap(dev->fdc, (dev->regs[1] & 0x80) ? 1 : 0);
if (valxor & 0x30)
w83787f_lpt_handler(dev);
if (valxor & 0x0a)
w83787f_serial_handler(dev, 1);
if (valxor & 0x05)
w83787f_serial_handler(dev, 0);
break;
case 3:
if (valxor & 0x80)
w83787f_lpt_handler(dev);
if (valxor & 0x40)
w83787f_gameport_handler(dev);
if (valxor & 0x08)
w83787f_serial_handler(dev, 0);
if (valxor & 0x04)
w83787f_serial_handler(dev, 1);
break;
case 4:
if (valxor & 0x10)
w83787f_serial_handler(dev, 1);
if (valxor & 0x20)
w83787f_serial_handler(dev, 0);
if (valxor & 0x80)
w83787f_lpt_handler(dev);
if (valxor & 0x40)
w83787f_gameport_handler(dev);
break;
case 6:
if (valxor & 0x08)
w83787f_fdc_handler(dev);
break;
case 7:
if (valxor & 0x03)
fdc_update_rwc(dev->fdc, 0, FDDA_TYPE);
if (valxor & 0x0c)
fdc_update_rwc(dev->fdc, 1, FDDB_TYPE);
if (valxor & 0x30)
fdc_update_rwc(dev->fdc, 2, FDDC_TYPE);
if (valxor & 0xc0)
fdc_update_rwc(dev->fdc, 3, FDDD_TYPE);
break;
case 8:
if (valxor & 0x03)
fdc_update_boot_drive(dev->fdc, FD_BOOT);
if (valxor & 0x10)
fdc_set_swwp(dev->fdc, SWWP ? 1 : 0);
if (valxor & 0x20)
fdc_set_diswr(dev->fdc, DISFDDWR ? 1 : 0);
break;
case 9:
if (valxor & 0x20)
fdc_update_enh_mode(dev->fdc, EN3MODE ? 1 : 0);
if (valxor & 0x40)
dev->rw_locked = (val & 0x40) ? 1 : 0;
if (valxor & 0x80)
w83787f_lpt_handler(dev);
break;
case 0xB:
w83787_log("Writing %02X to CRB\n", val);
break;
case 0xC:
if (valxor & 0x20)
w83787f_remap(dev);
break;
default:
break;
}
}
static uint8_t
w83787f_read(uint16_t port, void *priv)
{
w83787f_t *dev = (w83787f_t *) priv;
uint8_t ret = 0xff;
if (dev->locked) {
if (port == 0x251)
ret = dev->cur_reg;
else if (port == 0x252) {
if (dev->cur_reg == 7)
ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2));
else if (!dev->rw_locked || (dev->cur_reg > 0x0b))
ret = dev->regs[dev->cur_reg];
}
}
return ret;
}
static void
w83787f_reset(w83787f_t *dev)
{
uint16_t hefere = dev->reg_init & 0x0100;
lpt_port_remove(dev->lpt);
lpt_port_setup(dev->lpt, LPT1_ADDR);
lpt_port_irq(dev->lpt, LPT1_IRQ);
memset(dev->regs, 0, 0x2A);
if (HAS_IDE_FUNCTIONALITY) {
if (dev->ide_function & 0x20) {
dev->regs[0x00] = 0x90;
ide_sec_disable();
ide_set_base(1, 0x170);
ide_set_side(1, 0x376);
} else {
dev->regs[0x00] = 0xd0;
ide_pri_disable();
ide_set_base(0, 0x1f0);
ide_set_side(0, 0x3f6);
}
if (dev->ide_start) {
dev->regs[0x00] &= 0x7f;
if (dev->ide_function & 0x20)
ide_sec_enable();
else
ide_pri_enable();
}
} else
dev->regs[0x00] = 0xd0;
fdc_reset(dev->fdc);
w83787f_fdc_handler(dev);
dev->regs[0x01] = 0x2C;
dev->regs[0x03] = 0x70;
dev->regs[0x07] = 0xF5;
dev->regs[0x09] = dev->reg_init & 0xff;
dev->regs[0x0a] = 0x1F;
dev->regs[0x0c] = 0x0C | (hefere >> 3);
dev->regs[0x0d] = 0xA3;
gameport_remap(dev->gameport, 0);
serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ);
serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ);
w83787f_lpt_handler(dev);
dev->key = 0x88 | (hefere >> 8);
w83787f_remap(dev);
dev->locked = 0;
dev->rw_locked = 0;
}
static void
w83787f_close(void *priv)
{
w83787f_t *dev = (w83787f_t *) priv;
free(dev);
}
static void *
w83787f_init(const device_t *info)
{
w83787f_t *dev = (w83787f_t *) calloc(1, sizeof(w83787f_t));
HAS_IDE_FUNCTIONALITY = (info->local & 0x30);
dev->fdc = device_add(&fdc_at_winbond_device);
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
dev->gameport = gameport_add(&gameport_sio_1io_device);
if ((dev->ide_function & 0x30) == 0x10)
device_add(&ide_isa_device);
dev->ide_start = !!(info->local & 0x40);
dev->reg_init = info->local & 0x010f;
w83787f_reset(dev);
return dev;
}
const device_t w83787f_88h_device = {
.name = "Winbond W83787F/IF Super I/O",
.internal_name = "w83787f",
.flags = 0,
.local = 0x0009,
.init = w83787f_init,
.close = w83787f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83787f_device = {
.name = "Winbond W83787F/IF Super I/O",
.internal_name = "w83787f",
.flags = 0,
.local = 0x0109,
.init = w83787f_init,
.close = w83787f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83787f_ide_device = {
.name = "Winbond W83787F/IF Super I/O (With IDE)",
.internal_name = "w83787f_ide",
.flags = 0,
.local = 0x0119,
.init = w83787f_init,
.close = w83787f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83787f_ide_en_device = {
.name = "Winbond W83787F/IF Super I/O (With IDE Enabled)",
.internal_name = "w83787f_ide_en",
.flags = 0,
.local = 0x0159,
.init = w83787f_init,
.close = w83787f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83787f_ide_sec_device = {
.name = "Winbond W83787F/IF Super I/O (With Secondary IDE)",
.internal_name = "w83787f_ide_sec",
.flags = 0,
.local = 0x0139,
.init = w83787f_init,
.close = w83787f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

475
src/sio/sio_w837x7.c Normal file
View File

@@ -0,0 +1,475 @@
/*
* 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 Winbond W837x7F/IF Super I/O Chip.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Copyright 2020-2025 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/gameport.h>
#include <86box/sio.h>
#define FDDA_TYPE (dev->regs[7] & 3)
#define FDDB_TYPE ((dev->regs[7] >> 2) & 3)
#define FDDC_TYPE ((dev->regs[7] >> 4) & 3)
#define FDDD_TYPE ((dev->regs[7] >> 6) & 3)
#define FD_BOOT (dev->regs[8] & 3)
#define SWWP ((dev->regs[8] >> 4) & 1)
#define DISFDDWR ((dev->regs[8] >> 5) & 1)
#define EN3MODE ((dev->regs[9] >> 5) & 1)
#define DRV2EN_NEG (dev->regs[0xB] & 1) /* 0 = drive 2 installed */
#define INVERTZ ((dev->regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */
#define IDENT ((dev->regs[0xB] >> 3) & 1)
#define HEFERE ((dev->regs[0xC] >> 5) & 1)
typedef struct w837x7_t {
uint8_t tries;
uint8_t has_ide;
uint8_t type;
uint8_t hefere;
uint8_t max_reg;
uint8_t regs[256];
int locked;
int rw_locked;
int cur_reg;
int key;
int ide_start;
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
void *gameport;
} w837x7_t;
#ifdef ENABLE_W837X7_LOG
int w837x7_do_log = ENABLE_W837X7_LOG;
static void
w837x7_log(const char *fmt, ...)
{
va_list ap;
if (w837x7_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define w837x7_log(fmt, ...)
#endif
static void
w837x7_serial_handler(w837x7_t *dev, int uart)
{
int urs0 = !!(dev->regs[0x01] & (0x01 << uart));
int urs1 = !!(dev->regs[0x01] & (0x04 << uart));
int urs2 = !!(dev->regs[0x03] & (0x08 >> uart));
int urs;
int irq = COM1_IRQ;
uint16_t addr = COM1_ADDR;
uint16_t enable = 1;
double clock_src = 24000000.0 / 13.0;
if (dev->regs[0x03] & (1 << (1 - uart)))
clock_src = 24000000.0 / 12.0;
urs = (urs1 << 1) | urs0;
if (urs2) {
addr = uart ? COM1_ADDR : COM2_ADDR;
irq = uart ? COM1_IRQ : COM2_IRQ;
} else {
switch (urs) {
case 0x00:
addr = uart ? COM3_ADDR : COM4_ADDR;
irq = uart ? COM3_IRQ : COM4_IRQ;
break;
case 0x01:
addr = uart ? COM4_ADDR : COM3_ADDR;
irq = uart ? COM4_IRQ : COM3_IRQ;
break;
case 0x02:
addr = uart ? COM2_ADDR : COM1_ADDR;
irq = uart ? COM2_IRQ : COM1_IRQ;
break;
case 0x03:
default:
enable = 0;
break;
}
}
if (dev->regs[0x04] & (0x20 >> uart))
enable = 0;
serial_remove(dev->uart[uart]);
if (enable)
serial_setup(dev->uart[uart], addr, irq);
serial_set_clock_src(dev->uart[uart], clock_src);
}
static void
w837x7_lpt_handler(w837x7_t *dev)
{
int ptras = (dev->regs[1] >> 4) & 0x03;
uint16_t lpt_port = 0x0000;
uint16_t mask = 0xfffc;
uint8_t local_enable = 1;
uint8_t lpt_irq = LPT1_IRQ;
uint8_t lpt_mode = (dev->regs[0x09] & 0x80) | (dev->regs[0x00] & 0x0c);
switch (ptras) {
case 0x01:
lpt_port = LPT_MDA_ADDR;
lpt_irq = LPT_MDA_IRQ;
break;
case 0x02:
lpt_port = LPT1_ADDR;
lpt_irq = LPT1_IRQ /*LPT2_IRQ*/;
break;
case 0x03:
lpt_port = LPT2_ADDR;
lpt_irq = LPT1_IRQ /*LPT2_IRQ*/;
break;
default:
local_enable = 0;
break;
}
if (dev->regs[0x04] & 0x80)
local_enable = 0;
if (lpt_irq > 15)
lpt_irq = 0xff;
lpt_port_remove(dev->lpt);
lpt_set_fifo_threshold(dev->lpt, dev->regs[0x05] & 0x0f);
switch (lpt_mode) {
default:
local_enable = 0;
break;
case 0x00:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 1);
break;
case 0x84:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 0);
lpt_set_ext(dev->lpt, 0);
break;
case 0x88:
lpt_set_epp(dev->lpt, 0);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
case 0x8c:
mask = 0xfff8;
lpt_set_epp(dev->lpt, 1);
lpt_set_ecp(dev->lpt, 1);
lpt_set_ext(dev->lpt, 0);
break;
}
if (local_enable && (lpt_port >= 0x0100) && (lpt_port <= (0x0ffc & mask)))
lpt_port_setup(dev->lpt, lpt_port);
lpt_port_irq(dev->lpt, lpt_irq);
}
static void
w837x7_gameport_handler(w837x7_t *dev)
{
if (!(dev->regs[3] & 0x40) && !(dev->regs[4] & 0x40))
gameport_remap(dev->gameport, 0x201);
else
gameport_remap(dev->gameport, 0);
}
static void
w837x7_fdc_handler(w837x7_t *dev)
{
fdc_remove(dev->fdc);
if (!(dev->regs[0] & 0x20))
fdc_set_base(dev->fdc, (dev->regs[0] & 0x10) ? FDC_PRIMARY_ADDR : FDC_SECONDARY_ADDR);
fdc_set_power_down(dev->fdc, !!(dev->regs[6] & 0x08));
}
static void
w837x7_ide_handler(w837x7_t *dev)
{
if (dev->has_ide > 0) {
int ide_id = dev->has_ide - 1;
ide_handlers(ide_id, 0);
ide_set_base_addr(ide_id, 0, (dev->regs[0x00] & 0x40) ? 0x0170 : 0x01f0);
ide_set_base_addr(ide_id, 1, (dev->regs[0x00] & 0x40) ? 0x0376 : 0x03f6);
if (!(dev->regs[0x00] & 0x80))
ide_handlers(ide_id, 1);
}
}
static void
w837x7_write(uint16_t port, uint8_t val, void *priv)
{
w837x7_t *dev = (w837x7_t *) priv;
uint8_t valxor = 0;
if (port == 0x0250) {
if (val == dev->key)
dev->locked = 1;
else
dev->locked = 0;
return;
} else if (port == 0x0251) {
dev->cur_reg = val;
return;
} else {
if (dev->locked) {
if (dev->rw_locked && (dev->cur_reg <= 0x0b))
return;
valxor = val ^ dev->regs[dev->cur_reg];
dev->regs[dev->cur_reg] = val;
} else
return;
}
if (dev->cur_reg <= dev->max_reg) switch (dev->cur_reg) {
case 0x00:
w837x7_log("REG 00: %02X\n", val);
if (valxor & 0xc0)
w837x7_ide_handler(dev);
if (valxor & 0x30)
w837x7_fdc_handler(dev);
if (valxor & 0x0c)
w837x7_lpt_handler(dev);
break;
case 0x01:
if (valxor & 0x80)
fdc_set_swap(dev->fdc, (dev->regs[1] & 0x80) ? 1 : 0);
if (valxor & 0x30)
w837x7_lpt_handler(dev);
if (valxor & 0x0a)
w837x7_serial_handler(dev, 1);
if (valxor & 0x05)
w837x7_serial_handler(dev, 0);
break;
case 0x03:
if (valxor & 0x80)
w837x7_lpt_handler(dev);
if (valxor & 0x40)
w837x7_gameport_handler(dev);
if (valxor & 0x0a)
w837x7_serial_handler(dev, 0);
if (valxor & 0x05)
w837x7_serial_handler(dev, 1);
break;
case 0x04:
if (valxor & 0x10)
w837x7_serial_handler(dev, 1);
if (valxor & 0x20)
w837x7_serial_handler(dev, 0);
if (valxor & 0x80)
w837x7_lpt_handler(dev);
if (valxor & 0x40)
w837x7_gameport_handler(dev);
break;
case 0x05:
if (valxor & 0x0f)
w837x7_lpt_handler(dev);
break;
case 0x06:
if (valxor & 0x08)
w837x7_fdc_handler(dev);
break;
case 0x07:
if (valxor & 0x03)
fdc_update_rwc(dev->fdc, 0, FDDA_TYPE);
if (valxor & 0x0c)
fdc_update_rwc(dev->fdc, 1, FDDB_TYPE);
if (valxor & 0x30)
fdc_update_rwc(dev->fdc, 2, FDDC_TYPE);
if (valxor & 0xc0)
fdc_update_rwc(dev->fdc, 3, FDDD_TYPE);
break;
case 0x08:
if (valxor & 0x03)
fdc_update_boot_drive(dev->fdc, FD_BOOT);
if (valxor & 0x10)
fdc_set_swwp(dev->fdc, SWWP ? 1 : 0);
if (valxor & 0x20)
fdc_set_diswr(dev->fdc, DISFDDWR ? 1 : 0);
break;
case 0x09:
if (valxor & 0x20)
fdc_update_enh_mode(dev->fdc, EN3MODE ? 1 : 0);
if (valxor & 0x40)
dev->rw_locked = (val & 0x40) ? 1 : 0;
if (valxor & 0x80)
w837x7_lpt_handler(dev);
break;
case 0x0b:
if ((valxor & 0x0c) && (dev->type == W83777F)) {
fdc_clear_flags(dev->fdc, FDC_FLAG_PS2 | FDC_FLAG_PS2_MCA);
switch (val & 0x0c) {
case 0x00:
fdc_set_flags(dev->fdc, FDC_FLAG_PS2);
break;
case 0x04:
fdc_set_flags(dev->fdc, FDC_FLAG_PS2_MCA);
break;
}
}
break;
case 0x0c:
if (dev->type == W83787IF)
dev->key = 0x88 | HEFERE;
break;
default:
break;
}
}
static uint8_t
w837x7_read(uint16_t port, void *priv)
{
w837x7_t *dev = (w837x7_t *) priv;
uint8_t ret = 0xff;
if (dev->locked) {
if (port == 0x0251)
ret = dev->cur_reg;
else if (port == 0x0252) {
if (dev->cur_reg == 7)
ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2));
else if (!dev->rw_locked || (dev->cur_reg > 0x0b))
ret = dev->regs[dev->cur_reg];
}
}
return ret;
}
static void
w837x7_reset(w837x7_t *dev)
{
memset(dev->regs, 0x00, dev->max_reg + 1);
if (dev->has_ide == 0x02)
dev->regs[0x00] = 0x90;
else if (dev->has_ide == 0x01)
dev->regs[0x00] = 0xd0;
if (dev->ide_start)
dev->regs[0x00] &= 0x7f;
dev->regs[0x01] = 0x2c;
dev->regs[0x03] = 0x30;
dev->regs[0x09] = dev->type;
dev->regs[0x0a] = 0x1f;
if (dev->type == W83787IF) {
dev->regs[0x0c] = 0x0c | dev->hefere;
dev->regs[0x0d] = 0x03;
} else
dev->regs[0x0c] = dev->hefere;
dev->key = 0x88 | HEFERE;
fdc_reset(dev->fdc);
fdc_clear_flags(dev->fdc, FDC_FLAG_PS2 | FDC_FLAG_PS2_MCA);
w837x7_fdc_handler(dev);
w837x7_lpt_handler(dev);
w837x7_serial_handler(dev, 0);
w837x7_serial_handler(dev, 0);
w837x7_gameport_handler(dev);
w837x7_ide_handler(dev);
dev->locked = 0;
dev->rw_locked = 0;
}
static void
w837x7_close(void *priv)
{
w837x7_t *dev = (w837x7_t *) priv;
free(dev);
}
static void *
w837x7_init(const device_t *info)
{
w837x7_t *dev = (w837x7_t *) calloc(1, sizeof(w837x7_t));
dev->type = info->local & 0x0f;
dev->hefere = info->local & W837X7_KEY_89;
dev->max_reg = (dev->type == W83787IF) ? 0x15 : ((dev->type == W83787F) ? 0x0a : 0x0b);
dev->has_ide = (info->local >> 16) & 0xff;
dev->ide_start = !!(info->local & W837X7_IDE_START);
dev->fdc = device_add(&fdc_at_winbond_device);
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
dev->gameport = gameport_add(&gameport_sio_1io_device);
w837x7_reset(dev);
io_sethandler(0x250, 0x0004,
w837x7_read, NULL, NULL, w837x7_write, NULL, NULL, dev);
return dev;
}
const device_t w837x7_device = {
.name = "Winbond W837x7 Super I/O",
.internal_name = "w837x7",
.flags = 0,
.local = 0,
.init = w837x7_init,
.close = w837x7_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -6,15 +6,10 @@
*
* This file is part of the 86Box distribution.
*
* Emulation of the Winbond W83877F Super I/O Chip.
*
* Winbond W83877F Super I/O Chip
* Used by the Award 430HX
*
*
* Emulation of the Winbond W83877 family of Super I/O Chips.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Copyright 2016-2020 Miran Grca.
* Copyright 2016-2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
@@ -30,35 +25,41 @@
#include <86box/rom.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/machine.h>
#include <86box/sio.h>
#define FDDA_TYPE (dev->regs[7] & 3)
#define FDDB_TYPE ((dev->regs[7] >> 2) & 3)
#define FDDC_TYPE ((dev->regs[7] >> 4) & 3)
#define FDDD_TYPE ((dev->regs[7] >> 6) & 3)
#define FDDA_TYPE (dev->regs[0x07] & 3)
#define FDDB_TYPE ((dev->regs[0x07] >> 2) & 3)
#define FDDC_TYPE ((dev->regs[0x07] >> 4) & 3)
#define FDDD_TYPE ((dev->regs[0x07] >> 6) & 3)
#define FD_BOOT (dev->regs[8] & 3)
#define SWWP ((dev->regs[8] >> 4) & 1)
#define DISFDDWR ((dev->regs[8] >> 5) & 1)
#define FD_BOOT (dev->regs[0x08] & 3)
#define SWWP ((dev->regs[0x08] >> 4) & 1)
#define DISFDDWR ((dev->regs[0x08] >> 5) & 1)
#define EN3MODE ((dev->regs[9] >> 5) & 1)
#define EN3MODE ((dev->regs[0x09] >> 5) & 1)
#define DRV2EN_NEG (dev->regs[0xB] & 1) /* 0 = drive 2 installed */
#define INVERTZ ((dev->regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */
#define IDENT ((dev->regs[0xB] >> 3) & 1)
#define DRV2EN_NEG (dev->regs[0x0b] & 1) /* 0 = drive 2 installed */
#define INVERTZ ((dev->regs[0x0b] >> 1) & 1) /* 0 = invert DENSEL polarity */
#define IDENT ((dev->regs[0x0b] >> 3) & 1)
#define HEFERE ((dev->regs[0xC] >> 5) & 1)
#define HEFERE ((dev->regs[0x0c] >> 5) & 1)
#define HEFRAS (dev->regs[0x16] & 1)
#define PRTIQS (dev->regs[0x27] & 0x0f)
#define ECPIRQ ((dev->regs[0x27] >> 5) & 0x07)
typedef struct w83877f_t {
typedef struct w83877_t {
uint8_t tries;
uint8_t regs[42];
uint8_t has_ide;
uint8_t dma_map[4];
uint8_t irq_map[10];
uint8_t regs[256];
uint16_t reg_init;
int locked;
int rw_locked;
@@ -69,36 +70,36 @@ typedef struct w83877f_t {
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
} w83877f_t;
} w83877_t;
static void w83877f_write(uint16_t port, uint8_t val, void *priv);
static uint8_t w83877f_read(uint16_t port, void *priv);
static void w83877_write(uint16_t port, uint8_t val, void *priv);
static uint8_t w83877_read(uint16_t port, void *priv);
static void
w83877f_remap(w83877f_t *dev)
w83877_remap(w83877_t *dev)
{
uint8_t hefras = HEFRAS;
io_removehandler(0x250, 0x0003,
w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev);
w83877_read, NULL, NULL, w83877_write, NULL, NULL, dev);
io_removehandler(FDC_PRIMARY_ADDR, 0x0002,
w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev);
w83877_read, NULL, NULL, w83877_write, NULL, NULL, dev);
dev->base_address = (hefras ? FDC_PRIMARY_ADDR : 0x250);
io_sethandler(dev->base_address, hefras ? 0x0002 : 0x0003,
w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev);
w83877_read, NULL, NULL, w83877_write, NULL, NULL, dev);
dev->key_times = hefras + 1;
dev->key = (hefras ? 0x86 : 0x88) | HEFERE;
}
static uint8_t
get_lpt_length(w83877f_t *dev)
get_lpt_length(w83877_t *dev)
{
uint8_t length = 4;
if (dev->regs[9] & 0x80) {
if (dev->regs[0] & 0x04)
if (dev->regs[0x09] & 0x80) {
if (dev->regs[0x00] & 0x04)
length = 8; /* EPP mode. */
if (dev->regs[0] & 0x08)
if (dev->regs[0x00] & 0x08)
length |= 0x80; /* ECP mode. */
}
@@ -106,7 +107,7 @@ get_lpt_length(w83877f_t *dev)
}
static uint16_t
make_port(w83877f_t *dev, uint8_t reg)
make_port(w83877_t *dev, uint8_t reg)
{
uint16_t p = 0;
uint8_t l;
@@ -114,34 +115,31 @@ make_port(w83877f_t *dev, uint8_t reg)
switch (reg) {
case 0x20:
p = ((uint16_t) (dev->regs[reg] & 0xfc)) << 2;
p &= 0xFF0;
if ((p < 0x100) || (p > 0x3F0))
p = 0x3F0;
p &= 0x0ff0;
if ((p < 0x0100) || (p > 0x03f0))
p = 0x03f0;
break;
case 0x23:
l = get_lpt_length(dev);
p = ((uint16_t) (dev->regs[reg] & 0xff)) << 2;
/* 8 ports in EPP mode, 4 in non-EPP mode. */
if ((l & 0x0f) == 8)
p &= 0x3F8;
p &= 0x03f8;
else
p &= 0x3FC;
if ((p < 0x100) || (p > 0x3FF))
p &= 0x03fc;
if ((p < 0x0100) || (p > 0x03ff))
p = LPT1_ADDR;
/* In ECP mode, A10 is active. */
if (l & 0x80)
p |= 0x400;
break;
case 0x24:
p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2;
p &= 0xFF8;
if ((p < 0x100) || (p > 0x3F8))
p &= 0x0ff8;
if ((p < 0x0100) || (p > 0x03f8))
p = COM1_ADDR;
break;
case 0x25:
p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2;
p &= 0xFF8;
if ((p < 0x100) || (p > 0x3F8))
p &= 0x0ff8;
if ((p < 0x0100) || (p > 0x03f8))
p = COM2_ADDR;
break;
@@ -153,35 +151,60 @@ make_port(w83877f_t *dev, uint8_t reg)
}
static void
w83877f_fdc_handler(w83877f_t *dev)
w83877_ide_handler(w83877_t *dev)
{
uint16_t ide_port = 0x0000;
if (dev->has_ide > 0) {
int ide_id = dev->has_ide - 1;
ide_handlers(ide_id, 0);
ide_port = (dev->regs[0x21] << 2) & 0xfff0;
ide_set_base_addr(ide_id, 0, ide_port);
ide_port = ((dev->regs[0x22] << 2) & 0xfff0) | 0x0006;
ide_set_base_addr(ide_id, 1, ide_port);
if (!(dev->regs[0x06] & 0x04))
ide_handlers(ide_id, 1);
}
}
static void
w83877_fdc_handler(w83877_t *dev)
{
fdc_remove(dev->fdc);
if (dev->regs[0x20] & 0xc0)
if (!(dev->regs[0x06] & 0x08) && (dev->regs[0x20] & 0xc0))
fdc_set_base(dev->fdc, make_port(dev, 0x20));
fdc_set_power_down(dev->fdc, !!(dev->regs[6] & 0x08));
fdc_set_irq(dev->fdc, dev->irq_map[dev->regs[0x29] >> 4]);
fdc_set_dma_ch(dev->fdc, dev->dma_map[(dev->regs[0x26] >> 4) & 0x03]);
fdc_set_power_down(dev->fdc, !!(dev->regs[0x06] & 0x08));
}
static void
w83877f_lpt_handler(w83877f_t *dev)
w83877_lpt_handler(w83877_t *dev)
{
uint8_t lpt_irq;
uint8_t lpt_irqs[8] = { 0, 7, 9, 10, 11, 14, 15, 5 };
const uint8_t lpt_irq = dev->irq_map[PRTIQS];
lpt_port_remove(dev->lpt);
if (!(dev->regs[4] & 0x80) && (dev->regs[0x23] & 0xc0))
lpt_set_ext(dev->lpt, 1);
lpt_set_epp(dev->lpt, (dev->regs[0x09] & 0x80) && (dev->regs[0x00] & 0x04));
lpt_set_ecp(dev->lpt, (dev->regs[0x09] & 0x80) && (dev->regs[0x00] & 0x08));
lpt_set_fifo_threshold(dev->lpt, dev->regs[0x05] & 0x0f);
if (!(dev->regs[0x04] & 0x80) && (dev->regs[0x23] & 0xc0))
lpt_port_setup(dev->lpt, make_port(dev, 0x23));
lpt_irq = 0xff;
lpt_irq = lpt_irqs[ECPIRQ];
if (lpt_irq == 0)
lpt_irq = PRTIQS;
lpt_port_irq(dev->lpt, lpt_irq);
lpt_port_dma(dev->lpt, dev->dma_map[dev->regs[0x26] & 0x03]);
}
static void
w83877f_serial_handler(w83877f_t *dev, int uart)
w83877_serial_handler(w83877_t *dev, int uart)
{
int reg_mask = uart ? 0x10 : 0x20;
int reg_id = uart ? 0x25 : 0x24;
@@ -191,7 +214,7 @@ w83877f_serial_handler(w83877f_t *dev, int uart)
serial_remove(dev->uart[uart]);
if (!(dev->regs[4] & reg_mask) && (dev->regs[reg_id] & 0xc0))
serial_setup(dev->uart[uart], make_port(dev, reg_id), (dev->regs[0x28] & irq_mask) >> irq_shift);
serial_setup(dev->uart[uart], make_port(dev, reg_id), dev->irq_map[(dev->regs[0x28] & irq_mask) >> irq_shift]);
if (dev->regs[0x19] & (0x02 >> uart)) {
clock_src = 14769000.0;
@@ -205,21 +228,19 @@ w83877f_serial_handler(w83877f_t *dev, int uart)
}
static void
w83877f_write(uint16_t port, uint8_t val, void *priv)
w83877_write(uint16_t port, uint8_t val, void *priv)
{
w83877f_t *dev = (w83877f_t *) priv;
w83877_t *dev = (w83877_t *) priv;
uint8_t valxor = 0;
uint8_t max = 0x2A;
if (port == 0x250) {
if (port == 0x0250) {
if (val == dev->key)
dev->locked = 1;
else
dev->locked = 0;
return;
} else if (port == 0x251) {
if (val <= max)
dev->cur_reg = val;
} else if (port == 0x0251) {
dev->cur_reg = val;
return;
} else if (port == FDC_PRIMARY_ADDR) {
if ((val == dev->key) && !dev->locked) {
@@ -235,8 +256,8 @@ w83877f_write(uint16_t port, uint8_t val, void *priv)
}
} else {
if (dev->locked) {
if (val < max)
dev->cur_reg = val;
dev->cur_reg = val;
if (val == 0xaa)
dev->locked = 0;
} else {
@@ -245,16 +266,10 @@ w83877f_write(uint16_t port, uint8_t val, void *priv)
}
}
return;
} else if ((port == 0x252) || (port == 0x3f1)) {
} else if ((port == 0x0252) || (port == 0x03f1)) {
if (dev->locked) {
if (dev->rw_locked)
return;
if ((dev->cur_reg >= 0x26) && (dev->cur_reg <= 0x27))
return;
if (dev->cur_reg == 0x29)
return;
if (dev->cur_reg == 6)
val &= 0xFB;
valxor = val ^ dev->regs[dev->cur_reg];
dev->regs[dev->cur_reg] = val;
} else
@@ -262,33 +277,39 @@ w83877f_write(uint16_t port, uint8_t val, void *priv)
}
switch (dev->cur_reg) {
case 0:
case 0x00:
if (valxor & 0x0c)
w83877f_lpt_handler(dev);
w83877_lpt_handler(dev);
break;
case 1:
case 0x01:
if (valxor & 0x80)
fdc_set_swap(dev->fdc, (dev->regs[1] & 0x80) ? 1 : 0);
fdc_set_swap(dev->fdc, (dev->regs[0x01] & 0x80) ? 1 : 0);
break;
case 3:
case 0x03:
if (valxor & 0x02)
w83877f_serial_handler(dev, 0);
w83877_serial_handler(dev, 0);
if (valxor & 0x01)
w83877f_serial_handler(dev, 1);
w83877_serial_handler(dev, 1);
break;
case 4:
case 0x04:
if (valxor & 0x10)
w83877f_serial_handler(dev, 1);
w83877_serial_handler(dev, 1);
if (valxor & 0x20)
w83877f_serial_handler(dev, 0);
w83877_serial_handler(dev, 0);
if (valxor & 0x80)
w83877f_lpt_handler(dev);
w83877_lpt_handler(dev);
break;
case 6:
case 0x05:
if (valxor & 0x0f)
w83877_lpt_handler(dev);
break;
case 0x06:
if (valxor & 0x08)
w83877f_fdc_handler(dev);
w83877_fdc_handler(dev);
if (valxor & 0x04)
w83877_ide_handler(dev);
break;
case 7:
case 0x07:
if (valxor & 0x03)
fdc_update_rwc(dev->fdc, 0, FDDA_TYPE);
if (valxor & 0x0c)
@@ -298,7 +319,7 @@ w83877f_write(uint16_t port, uint8_t val, void *priv)
if (valxor & 0xc0)
fdc_update_rwc(dev->fdc, 3, FDDD_TYPE);
break;
case 8:
case 0x08:
if (valxor & 0x03)
fdc_update_boot_drive(dev->fdc, FD_BOOT);
if (valxor & 0x10)
@@ -306,66 +327,106 @@ w83877f_write(uint16_t port, uint8_t val, void *priv)
if (valxor & 0x20)
fdc_set_diswr(dev->fdc, DISFDDWR ? 1 : 0);
break;
case 9:
case 0x09:
if (valxor & 0x20)
fdc_update_enh_mode(dev->fdc, EN3MODE ? 1 : 0);
if (valxor & 0x40)
dev->rw_locked = (val & 0x40) ? 1 : 0;
if (valxor & 0x80)
w83877f_lpt_handler(dev);
w83877_lpt_handler(dev);
break;
case 0xB:
if (valxor & 1)
fdc_update_drv2en(dev->fdc, DRV2EN_NEG ? 0 : 1);
if (valxor & 2)
case 0x0b:
if (valxor & 0x0c) {
fdc_clear_flags(dev->fdc, FDC_FLAG_PS2 | FDC_FLAG_PS2_MCA);
switch (val & 0x0c) {
case 0x00:
fdc_set_flags(dev->fdc, FDC_FLAG_PS2);
break;
case 0x04:
fdc_set_flags(dev->fdc, FDC_FLAG_PS2_MCA);
break;
}
}
if (valxor & 0x02)
fdc_update_densel_polarity(dev->fdc, INVERTZ ? 1 : 0);
if (valxor & 0x01)
fdc_update_drv2en(dev->fdc, DRV2EN_NEG ? 0 : 1);
break;
case 0xC:
case 0x0c:
if (valxor & 0x20)
w83877f_remap(dev);
w83877_remap(dev);
break;
case 0x16:
if (valxor & 1)
w83877f_remap(dev);
if (valxor & 0x02) {
dev->regs[0x1e] = (val & 0x02) ? 0x81 : 0x00;
dev->regs[0x20] = (val & 0x02) ? 0xfc : 0x00;
dev->regs[0x21] = (val & 0x02) ? 0x7c : 0x00;
dev->regs[0x22] = (val & 0x02) ? 0xfd : 0x00;
dev->regs[0x23] = (val & 0x02) ? 0xde : 0x00;
dev->regs[0x24] = (val & 0x02) ? 0xfe : 0x00;
dev->regs[0x25] = (val & 0x02) ? 0xbe : 0x00;
dev->regs[0x26] = (val & 0x02) ? 0x23 : 0x00;
dev->regs[0x27] = (val & 0x02) ? 0x65 : 0x00;
dev->regs[0x28] = (val & 0x02) ? 0x43 : 0x00;
dev->regs[0x29] = (val & 0x02) ? 0x62 : 0x00;
w83877_fdc_handler(dev);
w83877_lpt_handler(dev);
w83877_serial_handler(dev, 0);
w83877_serial_handler(dev, 1);
}
if (valxor & 0x01)
w83877_remap(dev);
break;
case 0x19:
if (valxor & 0x02)
w83877f_serial_handler(dev, 0);
w83877_serial_handler(dev, 0);
if (valxor & 0x01)
w83877f_serial_handler(dev, 1);
w83877_serial_handler(dev, 1);
break;
case 0x20:
if (valxor)
w83877f_fdc_handler(dev);
w83877_fdc_handler(dev);
break;
case 0x21: case 0x22:
if (valxor)
w83877_ide_handler(dev);
break;
case 0x23:
if (valxor)
w83877f_lpt_handler(dev);
w83877_lpt_handler(dev);
break;
case 0x24:
if (valxor & 0xfe)
w83877f_serial_handler(dev, 0);
w83877_serial_handler(dev, 0);
break;
case 0x25:
if (valxor & 0xfe)
w83877f_serial_handler(dev, 1);
w83877_serial_handler(dev, 1);
break;
case 0x26:
if (valxor & 0x0f)
w83877_lpt_handler(dev);
break;
case 0x27:
if (valxor & 0xef)
w83877f_lpt_handler(dev);
w83877_lpt_handler(dev);
break;
case 0x28:
if (valxor & 0xf) {
if (valxor & 0x0f) {
if ((dev->regs[0x28] & 0x0f) == 0)
dev->regs[0x28] |= 0x03;
w83877f_serial_handler(dev, 1);
w83877_serial_handler(dev, 1);
}
if (valxor & 0xf0) {
if ((dev->regs[0x28] & 0xf0) == 0)
dev->regs[0x28] |= 0x40;
w83877f_serial_handler(dev, 0);
w83877_serial_handler(dev, 0);
}
break;
case 0x29:
if (valxor & 0xf0)
w83877_fdc_handler(dev);
break;
default:
break;
@@ -373,9 +434,9 @@ w83877f_write(uint16_t port, uint8_t val, void *priv)
}
static uint8_t
w83877f_read(uint16_t port, void *priv)
w83877_read(uint16_t port, void *priv)
{
w83877f_t *dev = (w83877f_t *) priv;
w83877_t *dev = (w83877_t *) priv;
uint8_t ret = 0xff;
if (dev->locked) {
@@ -393,7 +454,7 @@ w83877f_read(uint16_t port, void *priv)
}
static void
w83877f_reset(w83877f_t *dev)
w83877_reset(w83877_t *dev)
{
fdc_reset(dev->fdc);
@@ -405,47 +466,40 @@ w83877f_reset(w83877f_t *dev)
dev->regs[0x0c] = 0x28;
dev->regs[0x0d] = 0xA3;
dev->regs[0x16] = dev->reg_init & 0xff;
dev->regs[0x1e] = 0x81;
dev->regs[0x20] = (FDC_PRIMARY_ADDR >> 2) & 0xfc;
dev->regs[0x21] = (0x1f0 >> 2) & 0xfc;
dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1;
dev->regs[0x23] = (LPT1_ADDR >> 2);
dev->regs[0x24] = (COM1_ADDR >> 2) & 0xfe;
dev->regs[0x25] = (COM2_ADDR >> 2) & 0xfe;
dev->regs[0x26] = (2 << 4) | 4;
dev->regs[0x27] = (2 << 4) | 5;
dev->regs[0x28] = (4 << 4) | 3;
dev->regs[0x29] = 0x62;
w83877f_fdc_handler(dev);
w83877_fdc_handler(dev);
fdc_clear_flags(dev->fdc, FDC_FLAG_PS2 | FDC_FLAG_PS2_MCA);
w83877f_lpt_handler(dev);
w83877_lpt_handler(dev);
w83877f_serial_handler(dev, 0);
w83877f_serial_handler(dev, 1);
w83877_serial_handler(dev, 0);
w83877_serial_handler(dev, 1);
if (dev->has_ide)
w83877_ide_handler(dev);
dev->base_address = FDC_PRIMARY_ADDR;
dev->key = 0x89;
dev->key_times = 1;
w83877f_remap(dev);
w83877_remap(dev);
dev->locked = 0;
dev->rw_locked = 0;
}
static void
w83877f_close(void *priv)
w83877_close(void *priv)
{
w83877f_t *dev = (w83877f_t *) priv;
w83877_t *dev = (w83877_t *) priv;
free(dev);
}
static void *
w83877f_init(const device_t *info)
w83877_init(const device_t *info)
{
w83877f_t *dev = (w83877f_t *) calloc(1, sizeof(w83877f_t));
w83877_t *dev = (w83877_t *) calloc(1, sizeof(w83877_t));
dev->fdc = device_add(&fdc_at_winbond_device);
@@ -456,60 +510,40 @@ w83877f_init(const device_t *info)
dev->reg_init = info->local;
w83877f_reset(dev);
dev->has_ide = (info->local >> 16) & 0xff;
if (!strcmp(machine_get_internal_name(), "ficpa2012")) {
dev->dma_map[0] = 4;
dev->dma_map[1] = 3;
dev->dma_map[2] = 1;
dev->dma_map[3] = 2;
} else {
dev->dma_map[0] = 4;
for (int i = 1; i < 4; i++)
dev->dma_map[i] = i;
}
memset(dev->irq_map, 0xff, 16);
dev->irq_map[0] = 0xff;
for (int i = 1; i < 7; i++)
dev->irq_map[i] = i;
dev->irq_map[1] = 5;
dev->irq_map[5] = 7;
dev->irq_map[7] = 9; /* Guesswork, I can't find a single BIOS that lets me assign IRQ_G to something. */
dev->irq_map[8] = 10;
w83877_reset(dev);
return dev;
}
const device_t w83877f_device = {
const device_t w83877_device = {
.name = "Winbond W83877F Super I/O",
.internal_name = "w83877f",
.internal_name = "w83877",
.flags = 0,
.local = 0x0a05,
.init = w83877f_init,
.close = w83877f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83877f_president_device = {
.name = "Winbond W83877F Super I/O (President)",
.internal_name = "w83877f_president",
.flags = 0,
.local = 0x0a04,
.init = w83877f_init,
.close = w83877f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83877tf_device = {
.name = "Winbond W83877TF Super I/O",
.internal_name = "w83877tf",
.flags = 0,
.local = 0x0c04,
.init = w83877f_init,
.close = w83877f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83877tf_acorp_device = {
.name = "Winbond W83877TF Super I/O",
.internal_name = "w83877tf_acorp",
.flags = 0,
.local = 0x0c05,
.init = w83877f_init,
.close = w83877f_close,
.local = 0,
.init = w83877_init,
.close = w83877_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,

1340
src/sio/sio_w83977.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,680 +0,0 @@
/*
* 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 Winbond W83977F Super I/O Chip.
*
* Winbond W83977F Super I/O Chip
* Used by the Award 430TX
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Copyright 2016-2020 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/pci.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sio.h>
#define HEFRAS (dev->regs[0x26] & 0x40)
typedef struct w83977f_t {
uint8_t id;
uint8_t tries;
uint8_t regs[48];
uint8_t dev_regs[256][208];
int locked;
int rw_locked;
int cur_reg;
int base_address;
int type;
int hefras;
fdc_t *fdc;
lpt_t *lpt;
serial_t *uart[2];
} w83977f_t;
static int next_id = 0;
static void w83977f_write(uint16_t port, uint8_t val, void *priv);
static uint8_t w83977f_read(uint16_t port, void *priv);
static void
w83977f_remap(w83977f_t *dev)
{
io_removehandler(FDC_PRIMARY_ADDR, 0x0002,
w83977f_read, NULL, NULL, w83977f_write, NULL, NULL, dev);
io_removehandler(FDC_SECONDARY_ADDR, 0x0002,
w83977f_read, NULL, NULL, w83977f_write, NULL, NULL, dev);
dev->base_address = (HEFRAS ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
io_sethandler(dev->base_address, 0x0002,
w83977f_read, NULL, NULL, w83977f_write, NULL, NULL, dev);
}
static uint8_t
get_lpt_length(w83977f_t *dev)
{
uint8_t length = 4;
if (((dev->dev_regs[1][0xc0] & 0x07) != 0x00) && ((dev->dev_regs[1][0xc0] & 0x07) != 0x02) && ((dev->dev_regs[1][0xc0] & 0x07) != 0x04))
length = 8;
return length;
}
static void
w83977f_fdc_handler(w83977f_t *dev)
{
uint16_t io_base = (dev->dev_regs[0][0x30] << 8) | dev->dev_regs[0][0x31];
if (dev->id == 1)
return;
fdc_remove(dev->fdc);
if ((dev->dev_regs[0][0x00] & 0x01) && (dev->regs[0x22] & 0x01) && (io_base >= 0x100) && (io_base <= 0xff8))
fdc_set_base(dev->fdc, io_base);
fdc_set_irq(dev->fdc, dev->dev_regs[0][0x40] & 0x0f);
}
static void
w83977f_lpt_handler(w83977f_t *dev)
{
uint16_t io_mask;
uint16_t io_base = (dev->dev_regs[1][0x30] << 8) | dev->dev_regs[1][0x31];
int io_len = get_lpt_length(dev);
io_base &= (0xff8 | io_len);
io_mask = 0xffc;
if (io_len == 8)
io_mask = 0xff8;
lpt_port_remove(dev->lpt);
if ((dev->dev_regs[1][0x00] & 0x01) && (dev->regs[0x22] & 0x08) && (io_base >= 0x100) && (io_base <= io_mask))
lpt_port_setup(dev->lpt, io_base);
lpt_port_irq(dev->lpt, dev->dev_regs[1][0x40] & 0x0f);
}
static void
w83977f_serial_handler(w83977f_t *dev, int uart)
{
uint16_t io_base = (dev->dev_regs[2 + uart][0x30] << 8) | dev->dev_regs[2 + uart][0x31];
double clock_src = 24000000.0 / 13.0;
serial_remove(dev->uart[uart]);
if ((dev->dev_regs[2 + uart][0x00] & 0x01) && (dev->regs[0x22] & (0x10 << uart)) && (io_base >= 0x100) && (io_base <= 0xff8))
serial_setup(dev->uart[uart], io_base, dev->dev_regs[2 + uart][0x40] & 0x0f);
switch (dev->dev_regs[2 + uart][0xc0] & 0x03) {
case 0x00:
clock_src = 24000000.0 / 13.0;
break;
case 0x01:
clock_src = 24000000.0 / 12.0;
break;
case 0x02:
clock_src = 24000000.0 / 1.0;
break;
case 0x03:
clock_src = 24000000.0 / 1.625;
break;
default:
break;
}
serial_set_clock_src(dev->uart[uart], clock_src);
}
static void
w83977f_write(uint16_t port, uint8_t val, void *priv)
{
w83977f_t *dev = (w83977f_t *) priv;
uint8_t index = (port & 1) ? 0 : 1;
uint8_t valxor = 0;
uint8_t ld = dev->regs[7];
if (index) {
if ((val == 0x87) && !dev->locked) {
if (dev->tries) {
dev->locked = 1;
dev->tries = 0;
} else
dev->tries++;
} else {
if (dev->locked) {
if (val == 0xaa)
dev->locked = 0;
else
dev->cur_reg = val;
} else {
if (dev->tries)
dev->tries = 0;
}
}
return;
} else {
if (dev->locked) {
if (dev->rw_locked)
return;
if (dev->cur_reg >= 0x30) {
valxor = val ^ dev->dev_regs[ld][dev->cur_reg - 0x30];
dev->dev_regs[ld][dev->cur_reg - 0x30] = val;
} else {
valxor = val ^ dev->regs[dev->cur_reg];
dev->regs[dev->cur_reg] = val;
}
} else
return;
}
switch (dev->cur_reg) {
case 0x02:
#if 0
if (valxor & 0x02)
softresetx86();
#endif
break;
case 0x22:
if (valxor & 0x20)
w83977f_serial_handler(dev, 1);
if (valxor & 0x10)
w83977f_serial_handler(dev, 0);
if (valxor & 0x08)
w83977f_lpt_handler(dev);
if (valxor & 0x01)
w83977f_fdc_handler(dev);
break;
case 0x26:
if (valxor & 0x40)
w83977f_remap(dev);
if (valxor & 0x20)
dev->rw_locked = (val & 0x20) ? 1 : 0;
break;
case 0x30:
if (valxor & 0x01)
switch (ld) {
case 0x00:
w83977f_fdc_handler(dev);
break;
case 0x01:
w83977f_lpt_handler(dev);
break;
case 0x02:
case 0x03:
w83977f_serial_handler(dev, ld - 2);
break;
default:
break;
}
break;
case 0x60:
case 0x61:
if (valxor & 0xff)
switch (ld) {
case 0x00:
w83977f_fdc_handler(dev);
break;
case 0x01:
w83977f_lpt_handler(dev);
break;
case 0x02:
case 0x03:
w83977f_serial_handler(dev, ld - 2);
break;
default:
break;
}
break;
case 0x70:
if (valxor & 0x0f)
switch (ld) {
case 0x00:
w83977f_fdc_handler(dev);
break;
case 0x01:
w83977f_lpt_handler(dev);
break;
case 0x02:
case 0x03:
w83977f_serial_handler(dev, ld - 2);
break;
default:
break;
}
break;
case 0xf0:
switch (ld) {
case 0x00:
if (dev->id == 1)
break;
if (!dev->id && (valxor & 0x20))
fdc_update_drv2en(dev->fdc, (val & 0x20) ? 0 : 1);
if (!dev->id && (valxor & 0x10))
fdc_set_swap(dev->fdc, (val & 0x10) ? 1 : 0);
if (!dev->id && (valxor & 0x01))
fdc_update_enh_mode(dev->fdc, (val & 0x01) ? 1 : 0);
break;
case 0x01:
if (valxor & 0x07)
w83977f_lpt_handler(dev);
break;
case 0x02:
case 0x03:
if (valxor & 0x03)
w83977f_serial_handler(dev, ld - 2);
break;
default:
break;
}
break;
case 0xf1:
switch (ld) {
case 0x00:
if (dev->id == 1)
break;
if (!dev->id && (valxor & 0xc0))
fdc_update_boot_drive(dev->fdc, (val & 0xc0) >> 6);
if (!dev->id && (valxor & 0x0c))
fdc_update_densel_force(dev->fdc, (val & 0x0c) >> 2);
if (!dev->id && (valxor & 0x02))
fdc_set_diswr(dev->fdc, (val & 0x02) ? 1 : 0);
if (!dev->id && (valxor & 0x01))
fdc_set_swwp(dev->fdc, (val & 0x01) ? 1 : 0);
break;
default:
break;
}
break;
case 0xf2:
switch (ld) {
case 0x00:
if (dev->id == 1)
break;
if (!dev->id && (valxor & 0xc0))
fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6);
if (!dev->id && (valxor & 0x30))
fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4);
if (!dev->id && (valxor & 0x0c))
fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2);
if (!dev->id && (valxor & 0x03))
fdc_update_rwc(dev->fdc, 0, val & 0x03);
break;
default:
break;
}
break;
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
switch (ld) {
case 0x00:
if (dev->id == 1)
break;
if (!dev->id && (valxor & 0x18))
fdc_update_drvrate(dev->fdc, dev->cur_reg & 0x03, (val & 0x18) >> 3);
break;
default:
break;
}
break;
default:
break;
}
}
static uint8_t
w83977f_read(uint16_t port, void *priv)
{
w83977f_t *dev = (w83977f_t *) priv;
uint8_t ret = 0xff;
uint8_t index = (port & 1) ? 0 : 1;
uint8_t ld = dev->regs[7];
if (dev->locked) {
if (index)
ret = dev->cur_reg;
else {
if (!dev->rw_locked) {
if (!dev->id && ((dev->cur_reg == 0xf2) && (ld == 0x00)))
ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6));
else if (dev->cur_reg >= 0x30)
ret = dev->dev_regs[ld][dev->cur_reg - 0x30];
else
ret = dev->regs[dev->cur_reg];
}
}
}
return ret;
}
static void
w83977f_reset(w83977f_t *dev)
{
memset(dev->regs, 0, 48);
for (uint16_t i = 0; i < 256; i++)
memset(dev->dev_regs[i], 0, 208);
if (dev->type < 2) {
dev->regs[0x20] = 0x97;
dev->regs[0x21] = dev->type ? 0x73 : 0x71;
} else {
dev->regs[0x20] = 0x52;
dev->regs[0x21] = 0xf0;
}
dev->regs[0x22] = 0xff;
dev->regs[0x24] = dev->type ? 0x84 : 0xa4;
dev->regs[0x26] = dev->hefras;
/* WARNING: Array elements are register - 0x30. */
/* Logical Device 0 (FDC) */
dev->dev_regs[0][0x00] = 0x01;
if (!dev->type)
dev->dev_regs[0][0x01] = 0x02;
if (next_id == 1) {
dev->dev_regs[0][0x30] = 0x03;
dev->dev_regs[0][0x31] = 0x70;
} else {
dev->dev_regs[0][0x30] = 0x03;
dev->dev_regs[0][0x31] = 0xf0;
}
dev->dev_regs[0][0x40] = 0x06;
if (!dev->type)
dev->dev_regs[0][0x41] = 0x02; /* Read-only */
dev->dev_regs[0][0x44] = 0x02;
dev->dev_regs[0][0xc0] = 0x0e;
/* Logical Device 1 (Parallel Port) */
dev->dev_regs[1][0x00] = 0x01;
if (!dev->type)
dev->dev_regs[1][0x01] = 0x02;
if (next_id == 1) {
dev->dev_regs[1][0x30] = 0x02;
dev->dev_regs[1][0x31] = 0x78;
dev->dev_regs[1][0x40] = 0x05;
} else {
dev->dev_regs[1][0x30] = 0x03;
dev->dev_regs[1][0x31] = 0x78;
dev->dev_regs[1][0x40] = 0x07;
}
if (!dev->type)
dev->dev_regs[1][0x41] = 0x01 /*0x02*/; /* Read-only */
dev->dev_regs[1][0x44] = 0x04;
dev->dev_regs[1][0xc0] = 0x3c; /* The datasheet says default is 3f, but also default is printer mode. */
/* Logical Device 2 (UART A) */
dev->dev_regs[2][0x00] = 0x01;
if (!dev->type)
dev->dev_regs[2][0x01] = 0x02;
if (next_id == 1) {
dev->dev_regs[2][0x30] = 0x03;
dev->dev_regs[2][0x31] = 0xe8;
} else {
dev->dev_regs[2][0x30] = 0x03;
dev->dev_regs[2][0x31] = 0xf8;
}
dev->dev_regs[2][0x40] = 0x04;
if (!dev->type)
dev->dev_regs[2][0x41] = 0x02; /* Read-only */
/* Logical Device 3 (UART B) */
dev->dev_regs[3][0x00] = 0x01;
if (!dev->type)
dev->dev_regs[3][0x01] = 0x02;
if (next_id == 1) {
dev->dev_regs[3][0x30] = 0x02;
dev->dev_regs[3][0x31] = 0xe8;
} else {
dev->dev_regs[3][0x30] = 0x02;
dev->dev_regs[3][0x31] = 0xf8;
}
dev->dev_regs[3][0x40] = 0x03;
if (!dev->type)
dev->dev_regs[3][0x41] = 0x02; /* Read-only */
/* Logical Device 4 (RTC) */
if (!dev->type) {
dev->dev_regs[4][0x00] = 0x01;
dev->dev_regs[4][0x01] = 0x02;
dev->dev_regs[4][0x30] = 0x00;
dev->dev_regs[4][0x31] = 0x70;
dev->dev_regs[4][0x40] = 0x08;
dev->dev_regs[4][0x41] = 0x02; /* Read-only */
}
/* Logical Device 5 (KBC) */
dev->dev_regs[5][0x00] = 0x01;
if (!dev->type)
dev->dev_regs[5][0x01] = 0x02;
dev->dev_regs[5][0x30] = 0x00;
dev->dev_regs[5][0x31] = 0x60;
dev->dev_regs[5][0x32] = 0x00;
dev->dev_regs[5][0x33] = 0x64;
dev->dev_regs[5][0x40] = 0x01;
if (!dev->type)
dev->dev_regs[5][0x41] = 0x02; /* Read-only */
dev->dev_regs[5][0x42] = 0x0c;
if (!dev->type)
dev->dev_regs[5][0x43] = 0x02; /* Read-only? */
dev->dev_regs[5][0xc0] = dev->type ? 0x83 : 0x40;
/* Logical Device 6 (IR) = UART C */
if (!dev->type) {
dev->dev_regs[6][0x01] = 0x02;
dev->dev_regs[6][0x41] = 0x02; /* Read-only */
dev->dev_regs[6][0x44] = 0x04;
dev->dev_regs[6][0x45] = 0x04;
}
/* Logical Device 7 (Auxiliary I/O Part I) */
if (!dev->type)
dev->dev_regs[7][0x01] = 0x02;
if (!dev->type)
dev->dev_regs[7][0x41] = 0x02; /* Read-only */
if (!dev->type)
dev->dev_regs[7][0x43] = 0x02; /* Read-only? */
dev->dev_regs[7][0xb0] = 0x01;
dev->dev_regs[7][0xb1] = 0x01;
dev->dev_regs[7][0xb2] = 0x01;
dev->dev_regs[7][0xb3] = 0x01;
dev->dev_regs[7][0xb4] = 0x01;
dev->dev_regs[7][0xb5] = 0x01;
dev->dev_regs[7][0xb6] = 0x01;
if (dev->type)
dev->dev_regs[7][0xb7] = 0x01;
/* Logical Device 8 (Auxiliary I/O Part II) */
if (!dev->type)
dev->dev_regs[8][0x01] = 0x02;
if (!dev->type)
dev->dev_regs[8][0x41] = 0x02; /* Read-only */
if (!dev->type)
dev->dev_regs[8][0x43] = 0x02; /* Read-only? */
dev->dev_regs[8][0xb8] = 0x01;
dev->dev_regs[8][0xb9] = 0x01;
dev->dev_regs[8][0xba] = 0x01;
dev->dev_regs[8][0xbb] = 0x01;
dev->dev_regs[8][0xbc] = 0x01;
dev->dev_regs[8][0xbd] = 0x01;
dev->dev_regs[8][0xbe] = 0x01;
dev->dev_regs[8][0xbf] = 0x01;
/* Logical Device 9 (Auxiliary I/O Part III) */
if (dev->type) {
dev->dev_regs[9][0xb0] = 0x01;
dev->dev_regs[9][0xb1] = 0x01;
dev->dev_regs[9][0xb2] = 0x01;
dev->dev_regs[9][0xb3] = 0x01;
dev->dev_regs[9][0xb4] = 0x01;
dev->dev_regs[9][0xb5] = 0x01;
dev->dev_regs[9][0xb6] = 0x01;
dev->dev_regs[9][0xb7] = 0x01;
dev->dev_regs[10][0xc0] = 0x8f;
}
if (dev->id == 1) {
serial_setup(dev->uart[0], COM3_ADDR, COM3_IRQ);
serial_setup(dev->uart[1], COM4_ADDR, COM4_IRQ);
} else {
fdc_reset(dev->fdc);
serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ);
serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ);
w83977f_fdc_handler(dev);
}
w83977f_lpt_handler(dev);
w83977f_serial_handler(dev, 0);
w83977f_serial_handler(dev, 1);
w83977f_remap(dev);
dev->locked = 0;
dev->rw_locked = 0;
}
static void
w83977f_close(void *priv)
{
w83977f_t *dev = (w83977f_t *) priv;
next_id = 0;
free(dev);
}
static void *
w83977f_init(const device_t *info)
{
w83977f_t *dev = (w83977f_t *) calloc(1, sizeof(w83977f_t));
dev->type = info->local & 0x0f;
dev->hefras = info->local & 0x40;
dev->id = next_id;
if (next_id == 1)
dev->hefras ^= 0x40;
else
dev->fdc = device_add(&fdc_at_smc_device);
dev->uart[0] = device_add_inst(&ns16550_device, (next_id << 1) + 1);
dev->uart[1] = device_add_inst(&ns16550_device, (next_id << 1) + 2);
dev->lpt = device_add_inst(&lpt_port_device, next_id + 1);
w83977f_reset(dev);
next_id++;
return dev;
}
const device_t w83977f_device = {
.name = "Winbond W83977F Super I/O",
.internal_name = "w83977f",
.flags = 0,
.local = 0,
.init = w83977f_init,
.close = w83977f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83977f_370_device = {
.name = "Winbond W83977F Super I/O (Port 370h)",
.internal_name = "w83977f_370",
.flags = 0,
.local = 0x40,
.init = w83977f_init,
.close = w83977f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83977tf_device = {
.name = "Winbond W83977TF Super I/O",
.internal_name = "w83977tf",
.flags = 0,
.local = 1,
.init = w83977f_init,
.close = w83977f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83977ef_device = {
.name = "Winbond W83977TF Super I/O",
.internal_name = "w83977ef",
.flags = 0,
.local = 2,
.init = w83977f_init,
.close = w83977f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t w83977ef_370_device = {
.name = "Winbond W83977TF Super I/O (Port 370h)",
.internal_name = "w83977ef_370",
.flags = 0,
.local = 0x42,
.init = w83977f_init,
.close = w83977f_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};