From 4e67a4fdd32b9e6e6e1e8f554a9df7eefc487c26 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 13 May 2024 00:57:53 +0200 Subject: [PATCH] DMA speed fixes in place on the 53c400. See above, so that the CD-ROM speed is accurate enough on both ends (T13B and the MMIO variants) and, at the same time, not timing out abnormally. --- src/scsi/scsi_ncr53c400.c | 66 ++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index 1ed8e520e..6576e79ab 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -103,6 +103,18 @@ ncr53c400_log(const char *fmt, ...) # define ncr53c400_log(fmt, ...) #endif +static void +ncr53c400_timer_on_auto(void *ext_priv, double period) +{ + ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; + + ncr53c400_log("53c400: PERIOD=%lf, timer=%x.\n", period, timer_is_enabled(&ncr400->timer)); + if (period <= 0.0) + timer_stop(&ncr400->timer); + else if ((period > 0.0) && !timer_is_enabled(&ncr400->timer)) + timer_on_auto(&ncr400->timer, period); +} + /* Memory-mapped I/O WRITE handler. */ static void ncr53c400_write(uint32_t addr, uint8_t val, void *priv) @@ -110,7 +122,6 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; - int actual_block = 0; addr &= 0x3fff; @@ -135,6 +146,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr400->busy = 1; + if (!(ncr->mode & MODE_MONITOR_BUSY)) + timer_on_auto(&ncr400->timer, ncr->period / 280.0); } } break; @@ -165,19 +178,13 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) ncr400->buffer_host_pos = 0; ncr400->status_ctrl &= ~STATUS_BUFFER_NOT_READY; } - if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0) && !timer_is_on(&ncr400->timer)) { + if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); - ncr53c400_log("DMA timer on, callback=%lf, scsi buflen=%d.\n", scsi_device_get_callback(dev), dev->buffer_length); - actual_block = ncr400->block_count; - if (!actual_block) - actual_block = 256; - - /*Sometimes the actual block count doesn't match the SCSI buffer length / 128.*/ - if (actual_block != (dev->buffer_length / 128)) { - /*FIXME: To be improved further, this is just to workaround callback de-syncs when split transfers occur.*/ - timer_on_auto(&ncr400->timer, (ncr->period / ((double)(actual_block * 40.0)))); - } else + if (ncr->mode & MODE_MONITOR_BUSY) timer_on_auto(&ncr400->timer, ncr->period); + else + timer_on_auto(&ncr400->timer, 40.0); + ncr53c400_log("DMA timer on, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_complete, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); } break; @@ -232,6 +239,8 @@ ncr53c400_read(uint32_t addr, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl); + if (!(ncr->mode & MODE_MONITOR_BUSY)) + timer_on_auto(&ncr400->timer, ncr->period / 280.0); } } break; @@ -258,8 +267,7 @@ ncr53c400_read(uint32_t addr, void *priv) break; case 0x3982: /* switch register read */ - ret = 0xf8; - ret |= (ncr->irq & 0x07); + ret = 0xff; ncr53c400_log("Switches read=%02x.\n", ret); break; @@ -392,24 +400,13 @@ ncr53c400_dma_mode_ext(void *priv, void *ext_priv) ncr_t *ncr = (ncr_t *) priv; /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - if (!ncr400->block_count_loaded && !(ncr->mode & MODE_DMA)) { + if (!(ncr->mode & MODE_DMA)) { ncr53c400_log("No DMA mode\n"); ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->isr &= ~STATUS_END_OF_DMA; ncr->dma_mode = DMA_IDLE; - } -} - -static void -ncr53c400_timer_on_auto(void *ext_priv, double period) -{ - ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; - - ncr53c400_log("53c400: PERIOD=%lf, timer=%x.\n", period, !!timer_is_on(&ncr400->timer)); - if (period == 0.0) - timer_stop(&ncr400->timer); - else - timer_on_auto(&ncr400->timer, period); + } else + ncr53c400_log("Continuing DMA, mode bit=%02x, block loaded=%d, waitcomplete=%d.\n", ncr->mode, ncr400->block_count_loaded, ncr->wait_complete); } static void @@ -428,16 +425,10 @@ ncr53c400_callback(void *priv) if (ncr->data_wait & 1) { ncr->clear_req = 3; ncr->data_wait &= ~1; - if (ncr->dma_mode == DMA_IDLE) { - timer_stop(&ncr400->timer); - return; - } } - if (ncr->dma_mode == DMA_IDLE) { - timer_stop(&ncr400->timer); + if (ncr->dma_mode == DMA_IDLE) return; - } switch (ncr->dma_mode) { case DMA_SEND: @@ -462,7 +453,6 @@ ncr53c400_callback(void *priv) if (ncr->cur_bus & BUS_REQ) break; } - /* Data ready. */ temp = ncr400->buffer[ncr400->buffer_pos]; @@ -487,7 +477,6 @@ ncr53c400_callback(void *priv) ncr53c400_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; ncr->isr |= STATUS_END_OF_DMA; - timer_stop(&ncr400->timer); if (ncr->mode & MODE_ENA_EOP_INT) { ncr53c400_log("NCR 53c400 write irq\n"); ncr5380_irq(ncr, 1); @@ -518,7 +507,6 @@ ncr53c400_callback(void *priv) if (ncr->cur_bus & BUS_REQ) break; } - /* Data ready. */ ncr5380_bus_read(ncr); temp = BUS_GETDATA(ncr->cur_bus); @@ -541,7 +529,6 @@ ncr53c400_callback(void *priv) ncr400->block_count_loaded = 0; ncr53c400_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; - timer_stop(&ncr400->timer); if (ncr->mode & MODE_ENA_EOP_INT) { ncr53c400_log("NCR read irq\n"); ncr5380_irq(ncr, 1); @@ -562,6 +549,7 @@ ncr53c400_callback(void *priv) ncr53c400_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; ncr->dma_mode = DMA_IDLE; + ncr400->block_count_loaded = 0; } }