Merge pull request #4448 from 86Box/tc1995

DMA speed fixes in place on the 53c400.
This commit is contained in:
Miran Grča
2024-05-13 00:59:21 +02:00
committed by GitHub

View File

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