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:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
372
src/sio/sio_gm82c803ab.c
Normal 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
382
src/sio/sio_gm82c803c.c
Normal 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
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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,
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
@@ -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:
|
||||
|
||||
@@ -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
475
src/sio/sio_w837x7.c
Normal 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
|
||||
};
|
||||
@@ -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
1340
src/sio/sio_w83977.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
};
|
||||
Reference in New Issue
Block a user