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

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

View File

@@ -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
};