Solved the IRQ mess of ESDI MCA.

This should also fix the timing/fatal's on ramdisk speeds using said controller on NT and OS/2 on MCA.
This commit is contained in:
TC1995
2024-03-11 21:39:16 +01:00
parent 1dc908de83
commit 3aa81066d3

View File

@@ -92,7 +92,7 @@
#define BIOS_FILE_L "roms/hdd/esdi/90x8969.bin" #define BIOS_FILE_L "roms/hdd/esdi/90x8969.bin"
#define BIOS_FILE_H "roms/hdd/esdi/90x8970.bin" #define BIOS_FILE_H "roms/hdd/esdi/90x8970.bin"
#define ESDI_TIME 512.0 #define ESDI_TIME 500.0
#define CMD_ADAPTER 0 #define CMD_ADAPTER 0
typedef struct esdi_drive_t { typedef struct esdi_drive_t {
@@ -113,6 +113,7 @@ typedef struct esdi_t {
uint8_t basic_ctrl; uint8_t basic_ctrl;
uint8_t status; uint8_t status;
uint8_t irq_status; uint8_t irq_status;
int irq_ena_disable;
int irq_in_progress; int irq_in_progress;
int cmd_req_in_progress; int cmd_req_in_progress;
int cmd_pos; int cmd_pos;
@@ -218,14 +219,26 @@ esdi_mca_log(const char *fmt, ...)
static __inline void static __inline void
set_irq(esdi_t *dev) set_irq(esdi_t *dev)
{ {
dev->irq_ena_disable = 1;
esdi_mca_log("Set IRQ 14: bit=%x, cmd=%02x.\n", dev->basic_ctrl & CTRL_IRQ_ENA, dev->command);
if (dev->basic_ctrl & CTRL_IRQ_ENA) if (dev->basic_ctrl & CTRL_IRQ_ENA)
picint(1 << 14); picint_common(1 << ESDI_IRQCHAN, PIC_IRQ_EDGE, 1, NULL);
} }
static __inline void static __inline void
clear_irq(UNUSED(esdi_t *dev)) clear_irq(esdi_t *dev)
{ {
picintc(1 << 14); dev->irq_ena_disable = 0;
esdi_mca_log("Clear IRQ 14: bit=%x, cmd=%02x.\n", dev->basic_ctrl & CTRL_IRQ_ENA, dev->command);
if (dev->basic_ctrl & CTRL_IRQ_ENA)
picint_common(1 << ESDI_IRQCHAN, PIC_IRQ_EDGE, 0, NULL);
}
static __inline void
update_irq(esdi_t *dev)
{
uint8_t set = (dev->basic_ctrl & CTRL_IRQ_ENA) && dev->irq_ena_disable;
picint_common(1 << ESDI_IRQCHAN, PIC_IRQ_EDGE, set, NULL);
} }
static void static void
@@ -235,10 +248,11 @@ esdi_mca_set_callback(esdi_t *dev, double callback)
return; return;
} }
if (callback) { if (callback == 0.0) {
timer_on_auto(&dev->timer, callback); esdi_mca_log("Callback Stopped.\n");
} else {
timer_stop(&dev->timer); timer_stop(&dev->timer);
} else {
timer_on_auto(&dev->timer, callback);
} }
} }
@@ -317,9 +331,9 @@ complete_command_status(esdi_t *dev)
{ {
dev->status_len = 7; dev->status_len = 7;
if (dev->cmd_dev == ATTN_DEVICE_0) if (dev->cmd_dev == ATTN_DEVICE_0)
dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(0); dev->status_data[0] = dev->command | STATUS_LEN(7) | STATUS_DEVICE(0);
else else
dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(1); dev->status_data[0] = dev->command | STATUS_LEN(7) | STATUS_DEVICE(1);
dev->status_data[1] = 0x0000; /*Error bits*/ dev->status_data[1] = 0x0000; /*Error bits*/
dev->status_data[2] = 0x1900; /*Device status*/ dev->status_data[2] = 0x1900; /*Device status*/
dev->status_data[3] = 0; /*Number of blocks left to do*/ dev->status_data[3] = 0; /*Number of blocks left to do*/
@@ -330,15 +344,12 @@ complete_command_status(esdi_t *dev)
} }
#define ESDI_ADAPTER_ONLY() \ #define ESDI_ADAPTER_ONLY() \
do { \
if (dev->cmd_dev != ATTN_HOST_ADAPTER) { \ if (dev->cmd_dev != ATTN_HOST_ADAPTER) { \
cmd_unsupported(dev); \ cmd_unsupported(dev); \
return; \ return; \
} \ }
} while (0)
#define ESDI_DRIVE_ONLY() \ #define ESDI_DRIVE_ONLY() \
do { \
if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) { \ if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) { \
cmd_unsupported(dev); \ cmd_unsupported(dev); \
return; \ return; \
@@ -346,8 +357,7 @@ complete_command_status(esdi_t *dev)
if (dev->cmd_dev == ATTN_DEVICE_0) \ if (dev->cmd_dev == ATTN_DEVICE_0) \
drive = &dev->drives[0]; \ drive = &dev->drives[0]; \
else \ else \
drive = &dev->drives[1]; \ drive = &dev->drives[1];
} while (0)
static void static void
esdi_callback(void *priv) esdi_callback(void *priv)
@@ -357,19 +367,19 @@ esdi_callback(void *priv)
int val; int val;
double cmd_time = 0.0; double cmd_time = 0.0;
esdi_mca_set_callback(dev, 0);
/* If we are returning from a RESET, handle this first. */ /* If we are returning from a RESET, handle this first. */
if (dev->in_reset) { if (dev->in_reset) {
esdi_mca_log("ESDI reset.\n");
dev->in_reset = 0; dev->in_reset = 0;
dev->status = STATUS_IRQ; dev->status = STATUS_IRQ;
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_RESET_COMPLETE; dev->irq_status = IRQ_HOST_ADAPTER | IRQ_RESET_COMPLETE;
return; return;
} }
esdi_mca_log("Command=%02x.\n", dev->command);
switch (dev->command) { switch (dev->command) {
case CMD_READ: case CMD_READ:
case 0x15:
ESDI_DRIVE_ONLY(); ESDI_DRIVE_ONLY();
if (!drive->present) { if (!drive->present) {
@@ -379,6 +389,7 @@ esdi_callback(void *priv)
switch (dev->cmd_state) { switch (dev->cmd_state) {
case 0: case 0:
if (dev->command == CMD_READ)
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
dev->sector_pos = 0; dev->sector_pos = 0;
@@ -873,7 +884,7 @@ static uint8_t
esdi_read(uint16_t port, void *priv) esdi_read(uint16_t port, void *priv)
{ {
esdi_t *dev = (esdi_t *) priv; esdi_t *dev = (esdi_t *) priv;
uint8_t ret = 0xff; uint8_t ret = 0x00;
switch (port & 7) { switch (port & 7) {
case 2: /*Basic status register*/ case 2: /*Basic status register*/
@@ -890,6 +901,7 @@ esdi_read(uint16_t port, void *priv)
break; break;
} }
esdi_mca_log("ESDI: rr(%04x, %02x)\n", port & 7, ret);
return ret; return ret;
} }
@@ -897,6 +909,7 @@ static void
esdi_write(uint16_t port, uint8_t val, void *priv) esdi_write(uint16_t port, uint8_t val, void *priv)
{ {
esdi_t *dev = (esdi_t *) priv; esdi_t *dev = (esdi_t *) priv;
uint8_t old;
esdi_mca_log("ESDI: wr(%04x, %02x)\n", port & 7, val); esdi_mca_log("ESDI: wr(%04x, %02x)\n", port & 7, val);
@@ -906,11 +919,14 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
dev->in_reset = 1; dev->in_reset = 1;
esdi_mca_set_callback(dev, ESDI_TIME * 50); esdi_mca_set_callback(dev, ESDI_TIME * 50);
dev->status = STATUS_BUSY; dev->status = STATUS_BUSY;
} else if (!(dev->basic_ctrl & CTRL_RESET) && (val & CTRL_RESET)) {
esdi_mca_set_callback(dev, 0.0);
dev->status = STATUS_BUSY;
} }
old = dev->basic_ctrl;
dev->basic_ctrl = val; dev->basic_ctrl = val;
if ((val & CTRL_IRQ_ENA) && !(old & CTRL_IRQ_ENA))
if (!(dev->basic_ctrl & CTRL_IRQ_ENA)) update_irq(dev);
picintc(1 << 14);
break; break;
case 3: /*Attention register*/ case 3: /*Attention register*/
@@ -945,6 +961,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
break; break;
case ATTN_DEVICE_0: case ATTN_DEVICE_0:
esdi_mca_log("ATTN Device 0.\n");
switch (val & ATTN_REQ_MASK) { switch (val & ATTN_REQ_MASK) {
case ATTN_CMD_REQ: case ATTN_CMD_REQ:
if (dev->cmd_req_in_progress) if (dev->cmd_req_in_progress)
@@ -957,6 +974,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
break; break;
case ATTN_EOI: case ATTN_EOI:
esdi_mca_log("EOI.\n");
dev->irq_in_progress = 0; dev->irq_in_progress = 0;
dev->status &= ~STATUS_IRQ; dev->status &= ~STATUS_IRQ;
clear_irq(dev); clear_irq(dev);
@@ -1112,15 +1130,40 @@ esdi_mca_write(int port, uint8_t val, void *priv)
break; break;
} }
if (!(dev->pos_regs[3] & 8)) {
switch (dev->pos_regs[3] & 7) {
case 2:
dev->bios = 0xc8000;
break;
case 3:
dev->bios = 0xcc000;
break;
case 4:
dev->bios = 0xd0000;
break;
case 5:
dev->bios = 0xd4000;
break;
case 6:
dev->bios = 0xd8000;
break;
case 7:
dev->bios = 0xdc000;
break;
default:
break;
}
} else
dev->bios = 0;
if (dev->pos_regs[2] & 1) { if (dev->pos_regs[2] & 1) {
io_sethandler(ESDI_IOADDR_PRI, 8, io_sethandler(ESDI_IOADDR_PRI, 8,
esdi_read, esdi_readw, NULL, esdi_read, esdi_readw, NULL,
esdi_write, esdi_writew, NULL, dev); esdi_write, esdi_writew, NULL, dev);
if (!(dev->pos_regs[3] & 8)) { if (dev->bios) {
mem_mapping_enable(&dev->bios_rom.mapping); mem_mapping_enable(&dev->bios_rom.mapping);
mem_mapping_set_addr(&dev->bios_rom.mapping, mem_mapping_set_addr(&dev->bios_rom.mapping, dev->bios, 0x4000);
((dev->pos_regs[3] & 7) * 0x4000) + 0xc0000, 0x4000);
} }
/* Say hello. */ /* Say hello. */