Fixed CD-ROM timings on the NCR 53x8xx SCSI controllers, the IDE_TIME, CDROM_TIME, and ZIP_TIME values, and the delay added to the CD-ROM READ SUBCHANNEL command, fixes slowdowns on several games that use CD Audio, such as Tomb Raider II.

This commit is contained in:
OBattler
2019-11-19 04:35:54 +01:00
parent 841a1f67da
commit e4408bc84d
7 changed files with 97 additions and 58 deletions

View File

@@ -9,7 +9,7 @@
* Implementation of the IDE emulation for hard disks and ATAPI * Implementation of the IDE emulation for hard disks and ATAPI
* CD-ROM devices. * CD-ROM devices.
* *
* Version: @(#)hdc_ide.c 1.0.64 2019/11/06 * Version: @(#)hdc_ide.c 1.0.65 2019/11/19
* *
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/> * Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com> * Miran Grca, <mgrca8@gmail.com>
@@ -109,7 +109,7 @@
#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd #define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd
#define FEATURE_DISABLE_IRQ_SERVICE 0xde #define FEATURE_DISABLE_IRQ_SERVICE 0xde
#define IDE_TIME 20.0 / 3.0 #define IDE_TIME 10.0
typedef struct { typedef struct {
@@ -175,70 +175,72 @@ ide_get_drive(int ch)
double double
ide_get_period(ide_t *ide, int size) ide_get_period(ide_t *ide, int size)
{ {
double period = 10.0 / 3.0; double period = (10.0 / 3.0);
/* We assume that 1 MB = 1000000 B in this case, so we have as
many B/us as there are MB/s because 1 s = 1000000 us. */
switch(ide->mdma_mode & 0x300) { switch(ide->mdma_mode & 0x300) {
case 0x000: /* PIO */ case 0x000: /* PIO */
switch(ide->mdma_mode & 0xff) { switch(ide->mdma_mode & 0xff) {
case 0: case 0:
period = 10.0 / 3.0; period = (10.0 / 3.0);
break; break;
case 1: case 1:
period = (period * 600.0) / 383.0; period = (20.0 / 3.83);
break; break;
case 2: case 2:
period = 25.0 / 3.0; period = (25.0 / 3.0);
break; break;
case 3: case 3:
period = 100.0 / 9.0; period = (100.0 / 9.0);
break; break;
case 4: case 4:
period = 50.0 / 3.0; period = (50.0 / 3.0);
break; break;
} }
break; break;
case 0x100: /* Single Word DMA */ case 0x100: /* Single Word DMA */
switch(ide->mdma_mode & 0xff) { switch(ide->mdma_mode & 0xff) {
case 0: case 0:
period = 25.0 / 12.0; period = (25.0 / 12.0);
break; break;
case 1: case 1:
period = 25.0 / 6.0; period = (25.0 / 6.0);
break; break;
case 2: case 2:
period = 25.0 / 3.0; period = (25.0 / 3.0);
break; break;
} }
break; break;
case 0x200: /* Multiword DMA */ case 0x200: /* Multiword DMA */
switch(ide->mdma_mode & 0xff) { switch(ide->mdma_mode & 0xff) {
case 0: case 0:
period = 25.0 / 6.0; period = (25.0 / 6.0);
break; break;
case 1: case 1:
period = 40.0 / 3.0; period = (40.0 / 3.0);
break; break;
case 2: case 2:
period = 50.0 / 3.0; period = (50.0 / 3.0);
break; break;
} }
break; break;
case 0x300: /* Ultra DMA */ case 0x300: /* Ultra DMA */
switch(ide->mdma_mode & 0xff) { switch(ide->mdma_mode & 0xff) {
case 0: case 0:
period = 50.0 / 3.0; period = (50.0 / 3.0);
break; break;
case 1: case 1:
period = 25.0; period = 25.0;
break; break;
case 2: case 2:
period = 100.0 / 3.0; period = (100.0 / 3.0);
break; break;
case 3: case 3:
period = 400.0 / 9.0; period = (400.0 / 9.0);
break; break;
case 4: case 4:
period = 200.0 / 3.0; period = (200.0 / 3.0);
break; break;
case 5: case 5:
period = 100.0; period = 100.0;
@@ -247,9 +249,26 @@ ide_get_period(ide_t *ide, int size)
break; break;
} }
period *= 1048576.0; /* period * MB - get bytes per second */ period = (10.0 / 3.0);
period = ((double) size) / period; /* size / period to get seconds */
return period * 1000000.0; /* return seconds * 1000000 to convert to us */ period = (1.0 / period); /* get us for 1 byte */
return period * ((double) size); /* multiply by bytes to get period for the entire transfer */
}
double
ide_atapi_get_period(uint8_t channel)
{
ide_t *ide = ide_drives[channel];
ide_log("ide_atapi_get_period(%i)\n", channel);
if (!ide) {
ide_log("Get period failed\n");
return -1.0;
}
return ide_get_period(ide, 1);
} }

View File

@@ -9,12 +9,12 @@
* Implementation of the IDE emulation for hard disks and ATAPI * Implementation of the IDE emulation for hard disks and ATAPI
* CD-ROM devices. * CD-ROM devices.
* *
* Version: @(#)hdd_ide.h 1.0.15 2018/10/31 * Version: @(#)hdd_ide.h 1.0.16 2019/11/19
* *
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/> * Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com> * Miran Grca, <mgrca8@gmail.com>
* Copyright 2008-2018 Sarah Walker. * Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2018 Miran Grca. * Copyright 2016-2019 Miran Grca.
*/ */
#ifndef EMU_IDE_H #ifndef EMU_IDE_H
# define EMU_IDE_H # define EMU_IDE_H
@@ -130,6 +130,7 @@ extern void ide_pri_disable(void);
extern void ide_sec_enable(void); extern void ide_sec_enable(void);
extern void ide_sec_disable(void); extern void ide_sec_disable(void);
extern double ide_atapi_get_period(uint8_t channel);
extern void ide_set_callback(uint8_t channel, double callback); extern void ide_set_callback(uint8_t channel, double callback);
extern void ide_padstr(char *str, const char *src, int len); extern void ide_padstr(char *str, const char *src, int len);

View File

@@ -9,11 +9,11 @@
* Implementation of the Iomega ZIP drive with SCSI(-like) * Implementation of the Iomega ZIP drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage. * commands, for both ATAPI and SCSI usage.
* *
* Version: @(#)zip.c 1.0.37 2018/11/02 * Version: @(#)zip.c 1.0.38 2019/11/19
* *
* Author: Miran Grca, <mgrca8@gmail.com> * Author: Miran Grca, <mgrca8@gmail.com>
* *
* Copyright 2018 Miran Grca. * Copyright 2018,2019 Miran Grca.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@@ -854,6 +854,26 @@ zip_update_request_length(zip_t *dev, int len, int block_len)
} }
static double
zip_bus_speed(zip_t *dev)
{
double ret = -1.0;
if (dev->drv->bus_type == ZIP_BUS_SCSI) {
dev->callback = -1.0; /* Speed depends on SCSI controller */
return 0.0;
} else {
if (dev && dev->drv)
ret = ide_atapi_get_period(dev->drv->ide_channel);
if (ret == -1.0) {
dev->callback = -1.0;
return 0.0;
} else
return ret * 1000000.0;
}
}
static void static void
zip_command_common(zip_t *dev) zip_command_common(zip_t *dev)
{ {
@@ -868,12 +888,8 @@ zip_command_common(zip_t *dev)
if (dev->drv->bus_type == ZIP_BUS_SCSI) { if (dev->drv->bus_type == ZIP_BUS_SCSI) {
dev->callback = -1.0; /* Speed depends on SCSI controller */ dev->callback = -1.0; /* Speed depends on SCSI controller */
return; return;
} else { } else
if (zip_current_mode(dev) == 2) bytes_per_second = zip_bus_speed(dev);
bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */
else
bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */
}
period = 1000000.0 / bytes_per_second; period = 1000000.0 / bytes_per_second;
dev->callback = period * (double) (dev->packet_len); dev->callback = period * (double) (dev->packet_len);

View File

@@ -9,11 +9,11 @@
* Implementation of the Iomega ZIP drive with SCSI(-like) * Implementation of the Iomega ZIP drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage. * commands, for both ATAPI and SCSI usage.
* *
* Version: @(#)zip.h 1.0.9 2018/10/31 * Version: @(#)zip.h 1.0.10 2019/11/19
* *
* Author: Miran Grca, <mgrca8@gmail.com> * Author: Miran Grca, <mgrca8@gmail.com>
* *
* Copyright 2018 Miran Grca. * Copyright 2018,2019 Miran Grca.
*/ */
#ifndef EMU_ZIP_H #ifndef EMU_ZIP_H
#define EMU_ZIP_H #define EMU_ZIP_H
@@ -23,7 +23,7 @@
#define BUF_SIZE 32768 #define BUF_SIZE 32768
#define ZIP_TIME 500.0 #define ZIP_TIME 10.0
#define ZIP_SECTORS (96*2048) #define ZIP_SECTORS (96*2048)

View File

@@ -9,7 +9,7 @@
* Implementation of the CD-ROM drive with SCSI(-like) * Implementation of the CD-ROM drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage. * commands, for both ATAPI and SCSI usage.
* *
* Version: @(#)scsi_cdrom.c 1.0.71 2019/09/26 * Version: @(#)scsi_cdrom.c 1.0.72 2019/11/19
* *
* Author: Miran Grca, <mgrca8@gmail.com> * Author: Miran Grca, <mgrca8@gmail.com>
* *
@@ -604,15 +604,19 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len)
static double static double
scsi_cdrom_bus_speed(scsi_cdrom_t *dev) scsi_cdrom_bus_speed(scsi_cdrom_t *dev)
{ {
double ret = -1.0;
if (dev->drv->bus_type == CDROM_BUS_SCSI) { if (dev->drv->bus_type == CDROM_BUS_SCSI) {
dev->callback = -1.0; /* Speed depends on SCSI controller */ dev->callback = -1.0; /* Speed depends on SCSI controller */
return 0.0; return 0.0;
} else { } else {
/* TODO: Get the actual selected speed from IDE. */ if (dev && dev->drv)
if (scsi_cdrom_current_mode(dev) == 2) ret = ide_atapi_get_period(dev->drv->ide_channel);
return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ if (ret == -1.0) {
else dev->callback = -1.0;
return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ return 0.0;
} else
return ret * 1000000.0;
} }
} }
@@ -663,7 +667,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev)
case 0xb9: case 0xb9:
case 0xbe: case 0xbe:
if (dev->current_cdb[0] == 0x42) if (dev->current_cdb[0] == 0x42)
dev->callback += 200.0 * CDROM_TIME; dev->callback += 40.0;
/* Account for seek time. */ /* Account for seek time. */
bytes_per_second = 176.0 * 1024.0; bytes_per_second = 176.0 * 1024.0;
bytes_per_second *= (double) dev->drv->cur_speed; bytes_per_second *= (double) dev->drv->cur_speed;

View File

@@ -9,17 +9,17 @@
* Implementation of the CD-ROM drive with SCSI(-like) * Implementation of the CD-ROM drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage. * commands, for both ATAPI and SCSI usage.
* *
* Version: @(#)scsi_cdrom.h 1.0.1 2018/10/17 * Version: @(#)scsi_cdrom.h 1.0.2 2019/11/19
* *
* Author: Miran Grca, <mgrca8@gmail.com> * Author: Miran Grca, <mgrca8@gmail.com>
* *
* Copyright 2018 Miran Grca. * Copyright 2018,2019 Miran Grca.
*/ */
#ifndef EMU_SCSI_CDROM_H #ifndef EMU_SCSI_CDROM_H
#define EMU_SCSI_CDROM_H #define EMU_SCSI_CDROM_H
#define CDROM_TIME 500.0 #define CDROM_TIME 10.0
#ifdef SCSI_DEVICE_H #ifdef SCSI_DEVICE_H

View File

@@ -13,7 +13,7 @@
* To do: Identify the type of serial EEPROM used and its * To do: Identify the type of serial EEPROM used and its
* interface. * interface.
* *
* Version: @(#)scsi_ncr53c8xx.c 1.0.17 2018/10/30 * Version: @(#)scsi_ncr53c8xx.c 1.0.18 2019/11/19
* *
* Authors: Paul Brook (QEMU) * Authors: Paul Brook (QEMU)
* Artyom Tarasenko (QEMU) * Artyom Tarasenko (QEMU)
@@ -705,10 +705,12 @@ ncr53c8xx_add_msg_byte(ncr53c8xx_t *dev, uint8_t data)
static void static void
ncr53c8xx_timer_on(ncr53c8xx_t *dev, scsi_device_t *sd, double p) ncr53c8xx_timer_on(ncr53c8xx_t *dev, scsi_device_t *sd, double p)
{ {
if (p <= 0) double period;
timer_on_auto(&dev->timer, ((double) sd->buffer_length) * 0.1); /* Fast SCSI: 10000000 bytes per second */
else /* Fast SCSI: 10000000 bytes per second */
timer_on_auto(&dev->timer, p); period = (p > 0.0) ? p : (((double) sd->buffer_length) * 0.1);
timer_on_auto(&dev->timer, period + 40.0);
} }
@@ -1023,11 +1025,12 @@ again:
/* If we receive an empty opcode increment the DSP by 4 bytes /* If we receive an empty opcode increment the DSP by 4 bytes
instead of 8 and execute the next opcode at that location */ instead of 8 and execute the next opcode at that location */
dev->dsp += 4; dev->dsp += 4;
timer_on_auto(&dev->timer, 10.0);
if (insn_processed < 100) if (insn_processed < 100)
goto again; goto again;
else else {
timer_on_auto(&dev->timer, 10.0);
return; return;
}
} }
addr = read_dword(dev, dev->dsp + 4); addr = read_dword(dev, dev->dsp + 4);
ncr53c8xx_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); ncr53c8xx_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr);
@@ -1093,8 +1096,6 @@ again:
dev->dfifo = dev->dbc & 0xff; dev->dfifo = dev->dbc & 0xff;
dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3);
timer_on_auto(&dev->timer, 40.0);
if (dev->dcntl & NCR_DCNTL_SSM) if (dev->dcntl & NCR_DCNTL_SSM)
ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI);
return; return;
@@ -1363,8 +1364,6 @@ again:
ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30));
} }
timer_on_auto(&dev->timer, 40.0);
ncr53c8xx_log("instructions processed %i\n", insn_processed); ncr53c8xx_log("instructions processed %i\n", insn_processed);
if (insn_processed > 10000 && !dev->waiting) { if (insn_processed > 10000 && !dev->waiting) {
/* Some windows drivers make the device spin waiting for a memory /* Some windows drivers make the device spin waiting for a memory
@@ -1393,6 +1392,8 @@ again:
ncr53c8xx_log("NCR 810: SCRIPTS: Waiting\n"); ncr53c8xx_log("NCR 810: SCRIPTS: Waiting\n");
} }
timer_on_auto(&dev->timer, 40.0);
ncr53c8xx_log("SCRIPTS execution stopped\n"); ncr53c8xx_log("SCRIPTS execution stopped\n");
} }
@@ -1419,8 +1420,6 @@ ncr53c8xx_callback(void *p)
if (dev->sstop) if (dev->sstop)
timer_stop(&dev->timer); timer_stop(&dev->timer);
else
timer_on_auto(&dev->timer, 10.0);
} }