Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port; Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX); Finished the 586MC1; Added 8087 emulation; Moved Cyrix 6x86'es to the Dev branch; Sanitized/cleaned up memregs.c/h and intel.c/h; Split the chipsets from machines and sanitized Port 92 emulation; Added support for the 15bpp mode to the Compaq ATI 28800; Moved the MR 386DX and 486 machines to the Dev branch; Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00; Ported the new timer code from PCem; Cleaned up the CPU table of unused stuff and better optimized its structure; Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch; Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem; Added the AHA-1540A and the BusTek BT-542B; Moved the Sumo SCSI-AT to the Dev branch; Minor IDE, FDC, and floppy drive code clean-ups; Made NCR 5380/53C400-based cards' BIOS address configurable; Got rid of the legacy romset variable; Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit; Added the Amstead PPC512 per PCem patch by John Elliott; Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages); Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing; Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem; Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit; Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement; Amstrad MegaPC does now works correctly with non-internal graphics card; The SLiRP code no longer casts a packed struct type to a non-packed struct type; The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present; The S3 Virge on BeOS is no longer broken (was broken by build #1591); OS/2 2.0 build 6.167 now sees key presses again; Xi8088 now work on CGA again; 86F images converted from either the old or new variants of the HxC MFM format now work correctly; Hardware interrupts with a vector of 0xFF are now handled correctly; OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct; Fixed VNC keyboard input bugs; Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver; Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly; Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4; Compaq Portable now works with all graphics cards; Fixed various MDSI Genius bugs; Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly; Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355; OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400. Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391. Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389. Fixed a minor IDE timing bug, fixes #388. Fixed Toshiba T1000 RAM issues, fixes #379. Fixed EGA/(S)VGA overscan border handling, fixes #378; Got rid of the now long useless IDE channel 2 auto-removal, fixes #370; Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366; Ported the Unicode CD image file name fix from VARCem, fixes #365; Fixed high density floppy disks on the Xi8088, fixes #359; Fixed some bugs in the Hercules emulation, fixes #346, fixes #358; Fixed the SCSI hard disk mode sense pages, fixes #356; Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349; Fixed bugs in the serial mouse emulation, fixes #344; Compiled 86Box binaries now include all the required .DLL's, fixes #341; Made some combo boxes in the Settings dialog slightly wider, fixes #276.
This commit is contained in:
@@ -104,14 +104,26 @@ static const struct {
|
||||
{ "Internal Controller", "internal",
|
||||
&inthdc_device },
|
||||
|
||||
{ "[ISA] [MFM] IBM PC Fixed Disk Adapter", "mfm_xt",
|
||||
&mfm_xt_xebec_device },
|
||||
{ "[ISA] [MFM] IBM PC Fixed Disk Adapter", "st506_xt",
|
||||
&st506_xt_xebec_device },
|
||||
|
||||
{ "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "mfm_dtc5150x",
|
||||
&mfm_xt_dtc5150x_device },
|
||||
{ "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "st506_xt_dtc5150x",
|
||||
&st506_xt_dtc5150x_device },
|
||||
|
||||
{ "[ISA] [MFM] IBM PC/AT Fixed Disk Adapter", "mfm_at",
|
||||
&mfm_at_wd1003_device },
|
||||
{ "[ISA] [MFM] ST-11M Fixed Disk Adapter", "st506_xt_st11_m",
|
||||
&st506_xt_st11_m_device },
|
||||
|
||||
{ "[ISA] [MFM] WD1002A-WX1 Fixed Disk Adapter", "st506_xt_wd1002a_wx1",
|
||||
&st506_xt_wd1002a_wx1_device },
|
||||
|
||||
{ "[ISA] [MFM/RLL] IBM PC/AT Fixed Disk Adapter", "st506_at",
|
||||
&st506_at_wd1003_device },
|
||||
|
||||
{ "[ISA] [RLL] ST-11R Fixed Disk Adapter", "st506_xt_st11_r",
|
||||
&st506_xt_st11_r_device },
|
||||
|
||||
{ "[ISA] [RLL] WD1002A-27X Fixed Disk Adapter", "st506_xt_wd1002a_27x",
|
||||
&st506_xt_wd1002a_27x_device },
|
||||
|
||||
{ "[ISA] [ESDI] PC/AT ESDI Fixed Disk Adapter", "esdi_at",
|
||||
&esdi_at_wd1007vse1_device },
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
*
|
||||
* Definitions for the common disk controller handler.
|
||||
*
|
||||
* Version: @(#)hdc.h 1.0.10 2018/11/18
|
||||
* Version: @(#)hdc.h 1.0.11 2019/03/03
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*/
|
||||
#ifndef EMU_HDC_H
|
||||
# define EMU_HDC_H
|
||||
@@ -31,9 +31,13 @@
|
||||
extern int hdc_current;
|
||||
|
||||
|
||||
extern const device_t mfm_xt_xebec_device; /* mfm_xt_xebec */
|
||||
extern const device_t mfm_xt_dtc5150x_device; /* mfm_xt_dtc */
|
||||
extern const device_t mfm_at_wd1003_device; /* mfm_at_wd1003 */
|
||||
extern const device_t st506_xt_xebec_device; /* st506_xt_xebec */
|
||||
extern const device_t st506_xt_dtc5150x_device; /* st506_xt_dtc */
|
||||
extern const device_t st506_xt_st11_m_device; /* st506_xt_st11_m */
|
||||
extern const device_t st506_xt_st11_r_device; /* st506_xt_st11_m */
|
||||
extern const device_t st506_xt_wd1002a_wx1_device; /* st506_xt_wd1002a_wx1 */
|
||||
extern const device_t st506_xt_wd1002a_27x_device; /* st506_xt_wd1002a_27x */
|
||||
extern const device_t st506_at_wd1003_device; /* st506_at_wd1003 */
|
||||
|
||||
extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */
|
||||
extern const device_t esdi_ps2_device; /* esdi_mca */
|
||||
|
||||
@@ -98,7 +98,8 @@ typedef struct {
|
||||
uint16_t buffer[256];
|
||||
int irqstat;
|
||||
|
||||
int64_t callback;
|
||||
uint64_t callback;
|
||||
pc_timer_t timer;
|
||||
|
||||
drive_t drives[2];
|
||||
|
||||
@@ -208,6 +209,21 @@ next_sector(esdi_t *esdi)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
esdi_set_callback(esdi_t *esdi, uint64_t callback)
|
||||
{
|
||||
if (!esdi) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
esdi->callback = callback;
|
||||
timer_set_delay_u64(&esdi->timer, esdi->callback);
|
||||
} else {
|
||||
esdi->callback = 0;
|
||||
timer_disable(&esdi->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
@@ -220,10 +236,8 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
if (esdi->pos >= 512) {
|
||||
esdi->pos = 0;
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
|
||||
esdi->callback = (3125LL * TIMER_USEC) / 8LL;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, (3125 * TIMER_USEC) / 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,26 +295,20 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
case CMD_RESTORE:
|
||||
esdi->command &= ~0x0f; /*mask off step rate*/
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case CMD_SEEK:
|
||||
esdi->command &= ~0x0f; /*mask off step rate*/
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (val) {
|
||||
case CMD_NOP:
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case CMD_READ:
|
||||
@@ -313,9 +321,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
case 0xa0:
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case CMD_WRITE:
|
||||
@@ -333,9 +339,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
case CMD_VERIFY+1:
|
||||
esdi->command &= ~0x01;
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case CMD_FORMAT:
|
||||
@@ -345,33 +349,25 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 30LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 30 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case CMD_DIAGNOSE: /* Execute Drive Diagnostics */
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case 0xe0: /*???*/
|
||||
case CMD_READ_PARAMETERS:
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
|
||||
default:
|
||||
esdi_at_log("WD1007: bad command %02X\n", val);
|
||||
case 0xe8: /*???*/
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
esdi->callback = 200LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 200 * HDC_TIME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -379,18 +375,14 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
case 0x3f6: /* Device control */
|
||||
if ((esdi->fdisk & 0x04) && !(val & 0x04)) {
|
||||
timer_clock();
|
||||
esdi->callback = 500LL*HDC_TIME;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 500 * HDC_TIME);
|
||||
esdi->reset = 1;
|
||||
esdi->status = STAT_BUSY;
|
||||
}
|
||||
|
||||
if (val & 0x04) {
|
||||
/*Drive held in reset*/
|
||||
timer_clock();
|
||||
esdi->callback = 0LL;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, 0);
|
||||
esdi->status = STAT_BUSY;
|
||||
}
|
||||
esdi->fdisk = val;
|
||||
@@ -419,10 +411,8 @@ esdi_readw(uint16_t port, void *priv)
|
||||
if (esdi->secount) {
|
||||
next_sector(esdi);
|
||||
esdi->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
|
||||
esdi->callback = (3125LL * TIMER_USEC) / 8LL;
|
||||
timer_update_outstanding();
|
||||
esdi_set_callback(esdi, (3125 * TIMER_USEC) / 8);
|
||||
} else {
|
||||
ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0);
|
||||
}
|
||||
@@ -487,7 +477,8 @@ esdi_callback(void *priv)
|
||||
drive_t *drive = &esdi->drives[esdi->drive_sel];
|
||||
off64_t addr;
|
||||
|
||||
esdi->callback = 0LL;
|
||||
esdi_set_callback(esdi, 0);
|
||||
|
||||
if (esdi->reset) {
|
||||
esdi->status = STAT_READY|STAT_DSC;
|
||||
esdi->error = 1;
|
||||
@@ -602,7 +593,7 @@ esdi_callback(void *priv)
|
||||
next_sector(esdi);
|
||||
esdi->secount = (esdi->secount - 1) & 0xff;
|
||||
if (esdi->secount)
|
||||
esdi->callback = 6LL*HDC_TIME;
|
||||
esdi_set_callback(esdi, 6 * HDC_TIME);
|
||||
else {
|
||||
esdi->pos = 0;
|
||||
esdi->status = STAT_READY|STAT_DSC;
|
||||
@@ -811,7 +802,7 @@ wd1007vse1_init(const device_t *info)
|
||||
io_sethandler(0x03f6, 1, NULL, NULL, NULL,
|
||||
esdi_write, NULL, NULL, esdi);
|
||||
|
||||
timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi);
|
||||
timer_add(&esdi->timer, esdi_callback, esdi, 0);
|
||||
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
#define BIOS_FILE_H L"roms/hdd/esdi/90x8970.bin"
|
||||
|
||||
|
||||
#define ESDI_TIME (200LL*TIMER_USEC)
|
||||
#define ESDI_TIME (200*TIMER_USEC)
|
||||
#define CMD_ADAPTER 0
|
||||
|
||||
|
||||
@@ -134,7 +134,8 @@ typedef struct esdi {
|
||||
int cmd_state;
|
||||
|
||||
int in_reset;
|
||||
int64_t callback;
|
||||
uint64_t callback;
|
||||
pc_timer_t timer;
|
||||
|
||||
uint32_t rba;
|
||||
|
||||
@@ -188,6 +189,8 @@ typedef struct esdi {
|
||||
#define CMD_GET_DEV_STATUS 0x08
|
||||
#define CMD_GET_DEV_CONFIG 0x09
|
||||
#define CMD_GET_POS_INFO 0x0a
|
||||
#define CMD_FORMAT_UNIT 0x16
|
||||
#define CMD_FORMAT_PREPARE 0x17
|
||||
|
||||
#define STATUS_LEN(x) ((x) << 8)
|
||||
#define STATUS_DEVICE(x) ((x) << 5)
|
||||
@@ -228,6 +231,21 @@ clear_irq(esdi_t *dev)
|
||||
picintc(1 << 14);
|
||||
}
|
||||
|
||||
static void
|
||||
esdi_mca_set_callback(esdi_t *dev, uint64_t callback)
|
||||
{
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
dev->callback = callback;
|
||||
timer_set_delay_u64(&dev->timer, dev->callback);
|
||||
} else {
|
||||
dev->callback = 0;
|
||||
timer_disable(&dev->timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
@@ -339,7 +357,7 @@ esdi_callback(void *priv)
|
||||
drive_t *drive;
|
||||
int val;
|
||||
|
||||
dev->callback = 0LL;
|
||||
esdi_mca_set_callback(dev, 0);
|
||||
|
||||
/* If we are returning from a RESET, handle this first. */
|
||||
if (dev->in_reset) {
|
||||
@@ -377,13 +395,13 @@ esdi_callback(void *priv)
|
||||
set_irq(dev);
|
||||
|
||||
dev->cmd_state = 1;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
dev->data_pos = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!(dev->basic_ctrl & CTRL_DMA_ENA)) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -399,7 +417,7 @@ esdi_callback(void *priv)
|
||||
val = dma_channel_write(dev->dma, dev->data[dev->data_pos]);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -413,7 +431,7 @@ esdi_callback(void *priv)
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -452,13 +470,13 @@ esdi_callback(void *priv)
|
||||
set_irq(dev);
|
||||
|
||||
dev->cmd_state = 1;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
dev->data_pos = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (! (dev->basic_ctrl & CTRL_DMA_ENA)) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -467,7 +485,7 @@ esdi_callback(void *priv)
|
||||
val = dma_channel_read(dev->dma);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -487,7 +505,7 @@ esdi_callback(void *priv)
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -630,13 +648,13 @@ esdi_callback(void *priv)
|
||||
set_irq(dev);
|
||||
|
||||
dev->cmd_state = 1;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
dev->data_pos = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (! (dev->basic_ctrl & CTRL_DMA_ENA)) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
while (dev->sector_pos < dev->sector_count) {
|
||||
@@ -644,7 +662,7 @@ esdi_callback(void *priv)
|
||||
val = dma_channel_read(dev->dma);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -657,7 +675,7 @@ esdi_callback(void *priv)
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -684,13 +702,13 @@ esdi_callback(void *priv)
|
||||
set_irq(dev);
|
||||
|
||||
dev->cmd_state = 1;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
dev->data_pos = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (! (dev->basic_ctrl & CTRL_DMA_ENA)) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -701,7 +719,7 @@ esdi_callback(void *priv)
|
||||
val = dma_channel_write(dev->dma, dev->data[dev->data_pos]);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -713,7 +731,7 @@ esdi_callback(void *priv)
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -740,6 +758,59 @@ esdi_callback(void *priv)
|
||||
set_irq(dev);
|
||||
break;
|
||||
|
||||
case CMD_FORMAT_UNIT:
|
||||
case CMD_FORMAT_PREPARE:
|
||||
ESDI_DRIVE_ONLY();
|
||||
|
||||
if (! drive->present) {
|
||||
device_not_present(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->cmd_state) {
|
||||
case 0:
|
||||
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
|
||||
|
||||
dev->sector_count = dev->cmd_data[1];
|
||||
|
||||
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {
|
||||
rba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ;
|
||||
dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
|
||||
dev->cmd_state = 1;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!(dev->basic_ctrl & CTRL_DMA_ENA)) {
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
complete_command_status(dev);
|
||||
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("BAD COMMAND %02x %i\n", dev->command, dev->cmd_dev);
|
||||
}
|
||||
@@ -781,7 +852,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
case 2: /*Basic control register*/
|
||||
if ((dev->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) {
|
||||
dev->in_reset = 1;
|
||||
dev->callback = ESDI_TIME * 50LL;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME * 50);
|
||||
dev->status = STATUS_BUSY;
|
||||
}
|
||||
dev->basic_ctrl = val;
|
||||
@@ -812,7 +883,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
case ATTN_RESET:
|
||||
dev->in_reset = 1;
|
||||
dev->callback = ESDI_TIME * 50LL;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME * 50);
|
||||
dev->status = STATUS_BUSY;
|
||||
break;
|
||||
|
||||
@@ -923,7 +994,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
if ((dev->cmd_data[0] & CMD_DEVICE_SEL) != dev->cmd_dev)
|
||||
fatal("Command device mismatch with attn\n");
|
||||
dev->command = dev->cmd_data[0] & CMD_MASK;
|
||||
dev->callback = ESDI_TIME;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
dev->status = STATUS_BUSY;
|
||||
dev->data_pos = 0;
|
||||
}
|
||||
@@ -1007,6 +1078,15 @@ esdi_mca_write(int port, uint8_t val, void *priv)
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
esdi_mca_feedb(void *priv)
|
||||
{
|
||||
esdi_t *dev = (esdi_t *)priv;
|
||||
|
||||
return (dev->pos_regs[2] & 1);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
esdi_init(const device_t *info)
|
||||
{
|
||||
@@ -1059,15 +1139,15 @@ esdi_init(const device_t *info)
|
||||
dev->pos_regs[1] = 0xdd;
|
||||
|
||||
/* Enable the device. */
|
||||
mca_add(esdi_mca_read, esdi_mca_write, dev);
|
||||
mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, dev);
|
||||
|
||||
/* Mark for a reset. */
|
||||
dev->in_reset = 1;
|
||||
dev->callback = ESDI_TIME * 50LL;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME * 50);
|
||||
dev->status = STATUS_BUSY;
|
||||
|
||||
/* Set the reply timer. */
|
||||
timer_add(esdi_callback, &dev->callback, &dev->callback, dev);
|
||||
timer_add(&dev->timer, esdi_callback, dev, 0);
|
||||
|
||||
return(dev);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -94,16 +94,11 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
extern int ideboard;
|
||||
extern int ide_ter_enabled, ide_qua_enabled;
|
||||
|
||||
#ifdef SCSI_DEVICE_H
|
||||
extern ide_t *ide_drives[IDE_NUM];
|
||||
#endif
|
||||
extern int64_t idecallback[5];
|
||||
|
||||
|
||||
#ifdef SCSI_DEVICE_H
|
||||
extern ide_t * ide_get_drive(int ch);
|
||||
extern void ide_irq_raise(ide_t *ide);
|
||||
extern void ide_irq_lower(ide_t *ide);
|
||||
extern void ide_allocate_buffer(ide_t *dev);
|
||||
@@ -120,23 +115,22 @@ extern uint8_t ide_readb(uint16_t addr, void *priv);
|
||||
extern uint8_t ide_read_alt_status(uint16_t addr, void *priv);
|
||||
extern uint16_t ide_readw(uint16_t addr, void *priv);
|
||||
|
||||
extern void ide_set_bus_master(int (*dmna)(int channel, uint8_t *data, int transfer_length, int out, void *priv),
|
||||
void (*set_irq)(int channel, void *priv),
|
||||
void *priv0, void *priv1);
|
||||
extern void ide_set_bus_master(int board,
|
||||
int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv),
|
||||
void (*set_irq)(int channel, void *priv), void *priv);
|
||||
|
||||
extern void win_cdrom_eject(uint8_t id);
|
||||
extern void win_cdrom_reload(uint8_t id);
|
||||
|
||||
extern void ide_set_base(int controller, uint16_t port);
|
||||
extern void ide_set_side(int controller, uint16_t port);
|
||||
extern void ide_set_base(int board, uint16_t port);
|
||||
extern void ide_set_side(int board, uint16_t port);
|
||||
|
||||
extern void ide_pri_enable(void);
|
||||
extern void ide_pri_disable(void);
|
||||
extern void ide_sec_enable(void);
|
||||
extern void ide_sec_disable(void);
|
||||
|
||||
extern void ide_set_callback(uint8_t channel, int64_t callback);
|
||||
extern void secondary_ide_check(void);
|
||||
extern void ide_set_callback(uint8_t channel, double callback);
|
||||
|
||||
extern void ide_padstr(char *str, const char *src, int len);
|
||||
extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src);
|
||||
@@ -145,7 +139,5 @@ extern int (*ide_bus_master_dma)(int channel, uint8_t *data, int transfer_length
|
||||
extern void (*ide_bus_master_set_irq)(int channel, void *priv);
|
||||
extern void *ide_bus_master_priv[2];
|
||||
|
||||
extern void ide_enable_pio_override(void);
|
||||
|
||||
|
||||
#endif /*EMU_IDE_H*/
|
||||
|
||||
471
src/disk/hdc_ide_sff8038i.c
Normal file
471
src/disk/hdc_ide_sff8038i.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* Emulation of the SFF-8038i IDE Bus Master.
|
||||
*
|
||||
* PRD format :
|
||||
* word 0 - base address
|
||||
* word 1 - bits 1-15 = byte count, bit 31 = end of transfer
|
||||
*
|
||||
* Version: @(#)hdc_ide_sff8038i.c 1.0.0 2019/05/12
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../cdrom/cdrom.h"
|
||||
#include "../scsi/scsi_device.h"
|
||||
#include "../scsi/scsi_cdrom.h"
|
||||
#include "../dma.h"
|
||||
#include "../io.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../mem.h"
|
||||
#include "../pci.h"
|
||||
#include "../pic.h"
|
||||
#include "hdc.h"
|
||||
#include "hdc_ide.h"
|
||||
#include "hdc_ide_sff8038i.h"
|
||||
#include "zip.h"
|
||||
|
||||
|
||||
static int next_id = 0;
|
||||
|
||||
|
||||
static uint8_t sff_bus_master_read(uint16_t port, void *priv);
|
||||
static uint16_t sff_bus_master_readw(uint16_t port, void *priv);
|
||||
static uint32_t sff_bus_master_readl(uint16_t port, void *priv);
|
||||
static void sff_bus_master_write(uint16_t port, uint8_t val, void *priv);
|
||||
static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv);
|
||||
static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv);
|
||||
|
||||
|
||||
#ifdef ENABLE_SFF_LOG
|
||||
int sff_do_log = ENABLE_SFF_LOG;
|
||||
|
||||
|
||||
static void
|
||||
sff_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (sff_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define sff_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
sff_bus_master_handlers(sff8038i_t *dev, uint16_t old_base, uint16_t new_base, int enabled)
|
||||
{
|
||||
io_removehandler(old_base, 0x08,
|
||||
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
|
||||
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
|
||||
dev);
|
||||
|
||||
if (enabled && new_base) {
|
||||
io_sethandler(new_base, 0x08,
|
||||
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
|
||||
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
|
||||
dev);
|
||||
}
|
||||
|
||||
dev->enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sff_bus_master_next_addr(sff8038i_t *dev)
|
||||
{
|
||||
DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4);
|
||||
DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4);
|
||||
sff_log("SFF-8038i Bus master DWORDs: %08X %08X\n", dev->addr, dev->count);
|
||||
dev->eot = dev->count >> 31;
|
||||
dev->count &= 0xfffe;
|
||||
if (!dev->count)
|
||||
dev->count = 65536;
|
||||
dev->addr &= 0xfffffffe;
|
||||
dev->ptr_cur += 8;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sff_bus_master_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
#ifdef ENABLE_SFF_LOG
|
||||
int channel = (port & 8) ? 1 : 0;
|
||||
#endif
|
||||
|
||||
sff_log("SFF-8038i Bus master BYTE write: %04X %02X\n", port, val);
|
||||
|
||||
switch (port & 7) {
|
||||
case 0:
|
||||
sff_log("sff Cmd : val = %02X, old = %02X\n", val, dev->command);
|
||||
if ((val & 1) && !(dev->command & 1)) { /*Start*/
|
||||
sff_log("sff Bus Master start on channel %i\n", channel);
|
||||
dev->ptr_cur = dev->ptr;
|
||||
sff_bus_master_next_addr(dev);
|
||||
dev->status |= 1;
|
||||
}
|
||||
if (!(val & 1) && (dev->command & 1)) { /*Stop*/
|
||||
sff_log("sff Bus Master stop on channel %i\n", channel);
|
||||
dev->status &= ~1;
|
||||
}
|
||||
|
||||
dev->command = val;
|
||||
break;
|
||||
case 2:
|
||||
sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status);
|
||||
dev->status &= 0x07;
|
||||
dev->status |= (val & 0x60);
|
||||
if (val & 0x04)
|
||||
dev->status &= ~0x04;
|
||||
if (val & 0x02)
|
||||
dev->status &= ~0x02;
|
||||
break;
|
||||
case 4:
|
||||
dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
dev->ptr0 = val;
|
||||
break;
|
||||
case 5:
|
||||
dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
break;
|
||||
case 6:
|
||||
dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
break;
|
||||
case 7:
|
||||
dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sff_bus_master_writew(uint16_t port, uint16_t val, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
|
||||
sff_log("SFF-8038i Bus master WORD write: %04X %04X\n", port, val);
|
||||
|
||||
switch (port & 7) {
|
||||
case 0:
|
||||
case 2:
|
||||
sff_bus_master_write(port, val & 0xff, priv);
|
||||
break;
|
||||
case 4:
|
||||
dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
dev->ptr0 = val & 0xff;
|
||||
break;
|
||||
case 6:
|
||||
dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sff_bus_master_writel(uint16_t port, uint32_t val, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
|
||||
sff_log("SFF-8038i Bus master DWORD write: %04X %08X\n", port, val);
|
||||
|
||||
switch (port & 7) {
|
||||
case 0:
|
||||
case 2:
|
||||
sff_bus_master_write(port, val & 0xff, priv);
|
||||
break;
|
||||
case 4:
|
||||
dev->ptr = (val & 0xfffffffc);
|
||||
dev->ptr %= (mem_size * 1024);
|
||||
dev->ptr0 = val & 0xff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
sff_bus_master_read(uint16_t port, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch (port & 7) {
|
||||
case 0:
|
||||
ret = dev->command;
|
||||
break;
|
||||
case 2:
|
||||
ret = dev->status & 0x67;
|
||||
break;
|
||||
case 4:
|
||||
ret = dev->ptr0;
|
||||
break;
|
||||
case 5:
|
||||
ret = dev->ptr >> 8;
|
||||
break;
|
||||
case 6:
|
||||
ret = dev->ptr >> 16;
|
||||
break;
|
||||
case 7:
|
||||
ret = dev->ptr >> 24;
|
||||
break;
|
||||
}
|
||||
|
||||
sff_log("SFF-8038i Bus master BYTE read : %04X %02X\n", port, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t
|
||||
sff_bus_master_readw(uint16_t port, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
|
||||
uint16_t ret = 0xffff;
|
||||
|
||||
switch (port & 7) {
|
||||
case 0:
|
||||
case 2:
|
||||
ret = (uint16_t) sff_bus_master_read(port, priv);
|
||||
break;
|
||||
case 4:
|
||||
ret = dev->ptr0 | (dev->ptr & 0xff00);
|
||||
break;
|
||||
case 6:
|
||||
ret = dev->ptr >> 16;
|
||||
break;
|
||||
}
|
||||
|
||||
sff_log("SFF-8038i Bus master WORD read : %04X %04X\n", port, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t
|
||||
sff_bus_master_readl(uint16_t port, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
|
||||
uint32_t ret = 0xffffffff;
|
||||
|
||||
switch (port & 7) {
|
||||
case 0:
|
||||
case 2:
|
||||
ret = (uint32_t) sff_bus_master_read(port, priv);
|
||||
break;
|
||||
case 4:
|
||||
ret = dev->ptr0 | (dev->ptr & 0xffffff00);
|
||||
break;
|
||||
}
|
||||
|
||||
sff_log("sff Bus master DWORD read : %04X %08X\n", port, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
#ifdef ENABLE_SFF_LOG
|
||||
char *sop;
|
||||
#endif
|
||||
|
||||
int force_end = 0, buffer_pos = 0;
|
||||
|
||||
#ifdef ENABLE_SFF_LOG
|
||||
sop = out ? "Read" : "Writ";
|
||||
#endif
|
||||
|
||||
if (!(dev->status & 1))
|
||||
return 2; /*DMA disabled*/
|
||||
|
||||
sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length);
|
||||
|
||||
while (1) {
|
||||
if (dev->count <= transfer_length) {
|
||||
sff_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr);
|
||||
if (out)
|
||||
DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count);
|
||||
else
|
||||
DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count);
|
||||
transfer_length -= dev->count;
|
||||
buffer_pos += dev->count;
|
||||
} else {
|
||||
sff_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr);
|
||||
if (out)
|
||||
DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length);
|
||||
else
|
||||
DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length);
|
||||
/* Increase addr and decrease count so that resumed transfers do not mess up. */
|
||||
dev->addr += transfer_length;
|
||||
dev->count -= transfer_length;
|
||||
transfer_length = 0;
|
||||
force_end = 1;
|
||||
}
|
||||
|
||||
if (force_end) {
|
||||
sff_log("Total transfer length smaller than sum of all blocks, partial block\n");
|
||||
dev->status &= ~2;
|
||||
return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */
|
||||
} else {
|
||||
if (!transfer_length && !dev->eot) {
|
||||
sff_log("Total transfer length smaller than sum of all blocks, full block\n");
|
||||
dev->status &= ~2;
|
||||
return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */
|
||||
} else if (transfer_length && dev->eot) {
|
||||
sff_log("Total transfer length greater than sum of all blocks\n");
|
||||
dev->status |= 2;
|
||||
return 0; /* There is data left to transfer but we have reached EOT - return with error. */
|
||||
} else if (dev->eot) {
|
||||
sff_log("Regular EOT\n");
|
||||
dev->status &= ~3;
|
||||
return 1; /* We have regularly reached EOT - clear status and break. */
|
||||
} else {
|
||||
/* We have more to transfer and there are blocks left, get next block. */
|
||||
sff_bus_master_next_addr(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sff_bus_master_set_irq(int channel, void *priv)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) priv;
|
||||
dev->status &= ~4;
|
||||
dev->status |= (channel >> 4);
|
||||
|
||||
channel &= 0x01;
|
||||
if (dev->status & 0x04) {
|
||||
if (channel && pci_use_mirq(0))
|
||||
pci_set_mirq(0);
|
||||
else
|
||||
picint(1 << (14 + channel));
|
||||
} else {
|
||||
if ((channel & 1) && pci_use_mirq(0))
|
||||
pci_clear_mirq(0);
|
||||
else
|
||||
picintc(1 << (14 + channel));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base)
|
||||
{
|
||||
if (dev->enabled) {
|
||||
io_removehandler(old_base, 0x08,
|
||||
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
|
||||
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
|
||||
dev);
|
||||
|
||||
dev->enabled = 0;
|
||||
}
|
||||
|
||||
dev->command = 0x00;
|
||||
dev->status = 0x00;
|
||||
dev->ptr = dev->ptr_cur = 0x00000000;
|
||||
dev->addr = 0x00000000;
|
||||
dev->ptr0 = 0x00;
|
||||
dev->count = dev->eot = 0x00000000;
|
||||
|
||||
ide_pri_disable();
|
||||
ide_sec_disable();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sff_reset(void *p)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < CDROM_NUM; i++) {
|
||||
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) &&
|
||||
(cdrom[i].ide_channel < 4) && cdrom[i].priv)
|
||||
scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
|
||||
}
|
||||
for (i = 0; i < ZIP_NUM; i++) {
|
||||
if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) &&
|
||||
(zip_drives[i].ide_channel < 4) && zip_drives[i].priv)
|
||||
zip_reset((scsi_common_t *) zip_drives[i].priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sff_close(void *p)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *)p;
|
||||
|
||||
free(dev);
|
||||
|
||||
next_id--;
|
||||
if (next_id < 0)
|
||||
next_id = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
*sff_init(const device_t *info)
|
||||
{
|
||||
sff8038i_t *dev = (sff8038i_t *) malloc(sizeof(sff8038i_t));
|
||||
memset(dev, 0, sizeof(sff8038i_t));
|
||||
|
||||
/* Make sure to only add IDE once. */
|
||||
if (next_id == 0)
|
||||
device_add(&ide_pci_2ch_device);
|
||||
|
||||
ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev);
|
||||
|
||||
next_id++;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
const device_t sff8038i_device =
|
||||
{
|
||||
"SFF-8038i IDE Bus Master",
|
||||
DEVICE_PCI,
|
||||
0,
|
||||
sff_init,
|
||||
sff_close,
|
||||
sff_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
38
src/disk/hdc_ide_sff8038i.h
Normal file
38
src/disk/hdc_ide_sff8038i.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* Emulation of the SFF-8038i IDE Bus Master.
|
||||
*
|
||||
* Emulation core dispatcher.
|
||||
*
|
||||
* Version: @(#)hdc_ide_sff8038i.h 1.0.0 2019/05/12
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t command, status,
|
||||
ptr0, enabled;
|
||||
uint32_t ptr, ptr_cur,
|
||||
addr;
|
||||
int count, eot;
|
||||
} sff8038i_t;
|
||||
|
||||
|
||||
extern const device_t sff8038i_device;
|
||||
|
||||
extern void sff_bus_master_handlers(sff8038i_t *dev, uint16_t old_base, uint16_t new_base, int enabled);
|
||||
|
||||
extern int sff_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv);
|
||||
extern int sff_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv);
|
||||
|
||||
extern void sff_bus_master_set_irq(int channel, void *priv);
|
||||
|
||||
extern void sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base);
|
||||
@@ -1,949 +0,0 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Driver for the IBM PC-XT Fixed Disk controller.
|
||||
*
|
||||
* The original controller shipped by IBM was made by Xebec, and
|
||||
* several variations had been made:
|
||||
*
|
||||
* #1 Original, single drive (ST412), 10MB, 2 heads.
|
||||
* #2 Update, single drive (ST412) but with option for a
|
||||
* switch block that can be used to 'set' the actual
|
||||
* drive type. Four switches are define, where switches
|
||||
* 1 and 2 define drive0, and switches 3 and 4 drive1.
|
||||
*
|
||||
* 0 ON ON 306 2 0
|
||||
* 1 ON OFF 375 8 0
|
||||
* 2 OFF ON 306 6 256
|
||||
* 3 OFF OFF 306 4 0
|
||||
*
|
||||
* The latter option is the default, in use on boards
|
||||
* without the switch block option.
|
||||
*
|
||||
* #3 Another updated board, mostly to accomodate the new
|
||||
* 20MB disk now being shipped. The controller can have
|
||||
* up to 2 drives, the type of which is set using the
|
||||
* switch block:
|
||||
*
|
||||
* SW1 SW2 CYLS HD SPT WPC
|
||||
* 0 ON ON 306 4 17 0
|
||||
* 1 ON OFF 612 4 17 0 (type 16)
|
||||
* 2 OFF ON 615 4 17 300 (Seagate ST-225, 2)
|
||||
* 3 OFF OFF 306 8 17 128 (IBM WD25, 13)
|
||||
*
|
||||
* Examples of #3 are IBM/Xebec, WD10004A-WX1 and ST11R.
|
||||
*
|
||||
* Since all controllers (including the ones made by DTC) use
|
||||
* (mostly) the same API, we keep them all in this module.
|
||||
*
|
||||
* Version: @(#)hdc_mfm_xt.c 1.0.18 2018/10/17
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
*/
|
||||
#define __USE_LARGEFILE64
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../dma.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../pic.h"
|
||||
#include "../rom.h"
|
||||
#include "../timer.h"
|
||||
#include "../plat.h"
|
||||
#include "../ui.h"
|
||||
#include "hdc.h"
|
||||
#include "hdd.h"
|
||||
|
||||
|
||||
// #define MFM_TIME (2000LL*TIMER_USEC)
|
||||
#define MFM_TIME (50LL*TIMER_USEC)
|
||||
#define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin"
|
||||
#define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin"
|
||||
|
||||
|
||||
enum {
|
||||
STATE_IDLE,
|
||||
STATE_RECEIVE_COMMAND,
|
||||
STATE_START_COMMAND,
|
||||
STATE_RECEIVE_DATA,
|
||||
STATE_RECEIVED_DATA,
|
||||
STATE_SEND_DATA,
|
||||
STATE_SENT_DATA,
|
||||
STATE_COMPLETION_BYTE,
|
||||
STATE_DUNNO
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
int spt, hpc;
|
||||
int tracks;
|
||||
int cfg_spt;
|
||||
int cfg_hpc;
|
||||
int cfg_cyl;
|
||||
int current_cylinder;
|
||||
int present;
|
||||
int hdd_num;
|
||||
} drive_t;
|
||||
|
||||
typedef struct {
|
||||
rom_t bios_rom;
|
||||
int64_t callback;
|
||||
int state;
|
||||
uint8_t status;
|
||||
uint8_t command[6];
|
||||
int command_pos;
|
||||
uint8_t data[512];
|
||||
int data_pos, data_len;
|
||||
uint8_t sector_buf[512];
|
||||
uint8_t irq_dma_mask;
|
||||
uint8_t completion_byte;
|
||||
uint8_t error;
|
||||
int drive_sel;
|
||||
drive_t drives[2];
|
||||
int sector, head, cylinder;
|
||||
int sector_count;
|
||||
uint8_t switches;
|
||||
} mfm_t;
|
||||
|
||||
#define STAT_IRQ 0x20
|
||||
#define STAT_DRQ 0x10
|
||||
#define STAT_BSY 0x08
|
||||
#define STAT_CD 0x04
|
||||
#define STAT_IO 0x02
|
||||
#define STAT_REQ 0x01
|
||||
|
||||
#define IRQ_ENA 0x02
|
||||
#define DMA_ENA 0x01
|
||||
|
||||
#define CMD_TEST_DRIVE_READY 0x00
|
||||
#define CMD_RECALIBRATE 0x01
|
||||
#define CMD_READ_STATUS 0x03
|
||||
#define CMD_VERIFY_SECTORS 0x05
|
||||
#define CMD_FORMAT_TRACK 0x06
|
||||
#define CMD_READ_SECTORS 0x08
|
||||
#define CMD_WRITE_SECTORS 0x0a
|
||||
#define CMD_SEEK 0x0b
|
||||
#define CMD_INIT_DRIVE_PARAMS 0x0c
|
||||
#define CMD_WRITE_SECTOR_BUFFER 0x0f
|
||||
#define CMD_BUFFER_DIAGNOSTIC 0xe0
|
||||
#define CMD_CONTROLLER_DIAGNOSTIC 0xe4
|
||||
#define CMD_DTC_GET_DRIVE_PARAMS 0xfb
|
||||
#define CMD_DTC_SET_STEP_RATE 0xfc
|
||||
#define CMD_DTC_SET_GEOMETRY 0xfe
|
||||
#define CMD_DTC_GET_GEOMETRY 0xff
|
||||
|
||||
#define ERR_NOT_READY 0x04
|
||||
#define ERR_SEEK_ERROR 0x15
|
||||
#define ERR_ILLEGAL_SECTOR_ADDRESS 0x21
|
||||
|
||||
|
||||
#ifdef ENABLE_MFM_XT_LOG
|
||||
int mfm_xt_do_log = ENABLE_MFM_XT_LOG;
|
||||
|
||||
|
||||
static void
|
||||
mfm_xt_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (mfm_xt_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define mfm_xt_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static uint8_t
|
||||
mfm_read(uint16_t port, void *priv)
|
||||
{
|
||||
mfm_t *mfm = (mfm_t *)priv;
|
||||
uint8_t temp = 0xff;
|
||||
|
||||
switch (port) {
|
||||
case 0x320: /*Read data*/
|
||||
mfm->status &= ~STAT_IRQ;
|
||||
switch (mfm->state) {
|
||||
case STATE_COMPLETION_BYTE:
|
||||
if ((mfm->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY))
|
||||
fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status);
|
||||
|
||||
temp = mfm->completion_byte;
|
||||
mfm->status = 0;
|
||||
mfm->state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_SEND_DATA:
|
||||
if ((mfm->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY))
|
||||
fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status);
|
||||
if (mfm->data_pos >= mfm->data_len)
|
||||
fatal("Data write with full data!\n");
|
||||
temp = mfm->data[mfm->data_pos++];
|
||||
if (mfm->data_pos == mfm->data_len) {
|
||||
mfm->status = STAT_BSY;
|
||||
mfm->state = STATE_SENT_DATA;
|
||||
mfm->callback = MFM_TIME;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Read data register - %i, %02x\n", mfm->state, mfm->status);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x321: /*Read status*/
|
||||
temp = mfm->status;
|
||||
break;
|
||||
|
||||
case 0x322: /*Read option jumpers*/
|
||||
temp = mfm->switches;
|
||||
break;
|
||||
}
|
||||
|
||||
return(temp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mfm_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
mfm_t *mfm = (mfm_t *)priv;
|
||||
|
||||
switch (port) {
|
||||
case 0x320: /*Write data*/
|
||||
switch (mfm->state) {
|
||||
case STATE_RECEIVE_COMMAND:
|
||||
if ((mfm->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ))
|
||||
fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", mfm->status);
|
||||
if (mfm->command_pos >= 6)
|
||||
fatal("Command write with full command!\n");
|
||||
/*Command data*/
|
||||
mfm->command[mfm->command_pos++] = val;
|
||||
if (mfm->command_pos == 6) {
|
||||
mfm->status = STAT_BSY;
|
||||
mfm->state = STATE_START_COMMAND;
|
||||
mfm->callback = MFM_TIME;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_RECEIVE_DATA:
|
||||
if ((mfm->status & 0xf) != (STAT_BSY | STAT_REQ))
|
||||
fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", mfm->status);
|
||||
if (mfm->data_pos >= mfm->data_len)
|
||||
fatal("Data write with full data!\n");
|
||||
/*Command data*/
|
||||
mfm->data[mfm->data_pos++] = val;
|
||||
if (mfm->data_pos == mfm->data_len) {
|
||||
mfm->status = STAT_BSY;
|
||||
mfm->state = STATE_RECEIVED_DATA;
|
||||
mfm->callback = MFM_TIME;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Write data unknown state - %i %02x\n", mfm->state, mfm->status);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x321: /*Controller reset*/
|
||||
mfm->status = 0;
|
||||
break;
|
||||
|
||||
case 0x322: /*Generate controller-select-pulse*/
|
||||
mfm->status = STAT_BSY | STAT_CD | STAT_REQ;
|
||||
mfm->command_pos = 0;
|
||||
mfm->state = STATE_RECEIVE_COMMAND;
|
||||
break;
|
||||
|
||||
case 0x323: /*DMA/IRQ mask register*/
|
||||
mfm->irq_dma_mask = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mfm_complete(mfm_t *mfm)
|
||||
{
|
||||
mfm->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY;
|
||||
mfm->state = STATE_COMPLETION_BYTE;
|
||||
|
||||
if (mfm->irq_dma_mask & IRQ_ENA) {
|
||||
mfm->status |= STAT_IRQ;
|
||||
picint(1 << 5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mfm_error(mfm_t *mfm, uint8_t error)
|
||||
{
|
||||
mfm->completion_byte |= 0x02;
|
||||
mfm->error = error;
|
||||
|
||||
mfm_xt_log("mfm_error - %02x\n", mfm->error);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_sector(mfm_t *mfm, off64_t *addr)
|
||||
{
|
||||
drive_t *drive = &mfm->drives[mfm->drive_sel];
|
||||
int heads = drive->cfg_hpc;
|
||||
|
||||
if (drive->current_cylinder != mfm->cylinder) {
|
||||
mfm_xt_log("mfm_get_sector: wrong cylinder\n");
|
||||
mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS;
|
||||
return(1);
|
||||
}
|
||||
if (mfm->head > heads) {
|
||||
mfm_xt_log("mfm_get_sector: past end of configured heads\n");
|
||||
mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS;
|
||||
return(1);
|
||||
}
|
||||
if (mfm->head > drive->hpc) {
|
||||
mfm_xt_log("mfm_get_sector: past end of heads\n");
|
||||
mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS;
|
||||
return(1);
|
||||
}
|
||||
if (mfm->sector >= 17) {
|
||||
mfm_xt_log("mfm_get_sector: past end of sectors\n");
|
||||
mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS;
|
||||
return(1);
|
||||
}
|
||||
|
||||
*addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) *
|
||||
17) + mfm->sector;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
next_sector(mfm_t *mfm)
|
||||
{
|
||||
drive_t *drive = &mfm->drives[mfm->drive_sel];
|
||||
|
||||
mfm->sector++;
|
||||
if (mfm->sector >= 17) {
|
||||
mfm->sector = 0;
|
||||
mfm->head++;
|
||||
if (mfm->head >= drive->cfg_hpc) {
|
||||
mfm->head = 0;
|
||||
mfm->cylinder++;
|
||||
drive->current_cylinder++;
|
||||
if (drive->current_cylinder >= drive->cfg_cyl)
|
||||
drive->current_cylinder = drive->cfg_cyl-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mfm_callback(void *priv)
|
||||
{
|
||||
mfm_t *mfm = (mfm_t *)priv;
|
||||
drive_t *drive;
|
||||
off64_t addr;
|
||||
|
||||
mfm->callback = 0LL;
|
||||
|
||||
mfm->drive_sel = (mfm->command[1] & 0x20) ? 1 : 0;
|
||||
mfm->completion_byte = mfm->drive_sel & 0x20;
|
||||
drive = &mfm->drives[mfm->drive_sel];
|
||||
|
||||
switch (mfm->command[0]) {
|
||||
case CMD_TEST_DRIVE_READY:
|
||||
if (!drive->present)
|
||||
mfm_error(mfm, ERR_NOT_READY);
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case CMD_RECALIBRATE:
|
||||
if (!drive->present)
|
||||
mfm_error(mfm, ERR_NOT_READY);
|
||||
else {
|
||||
mfm->cylinder = 0;
|
||||
drive->current_cylinder = 0;
|
||||
}
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case CMD_READ_STATUS:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->state = STATE_SEND_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 4;
|
||||
mfm->status = STAT_BSY | STAT_IO | STAT_REQ;
|
||||
mfm->data[0] = mfm->error;
|
||||
mfm->data[1] = mfm->drive_sel ? 0x20 : 0;
|
||||
mfm->data[2] = mfm->data[3] = 0;
|
||||
mfm->error = 0;
|
||||
break;
|
||||
|
||||
case STATE_SENT_DATA:
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_VERIFY_SECTORS:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2);
|
||||
drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder;
|
||||
mfm->head = mfm->command[1] & 0x1f;
|
||||
mfm->sector = mfm->command[2] & 0x1f;
|
||||
mfm->sector_count = mfm->command[4];
|
||||
do {
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm_xt_log("get_sector failed\n");
|
||||
mfm_error(mfm, mfm->error);
|
||||
mfm_complete(mfm);
|
||||
return;
|
||||
}
|
||||
|
||||
next_sector(mfm);
|
||||
|
||||
mfm->sector_count = (mfm->sector_count-1) & 0xff;
|
||||
} while (mfm->sector_count);
|
||||
|
||||
mfm_complete(mfm);
|
||||
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("CMD_VERIFY_SECTORS: bad state %i\n", mfm->state);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_FORMAT_TRACK:
|
||||
mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2);
|
||||
drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder;
|
||||
mfm->head = mfm->command[1] & 0x1f;
|
||||
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm_xt_log("get_sector failed\n");
|
||||
mfm_error(mfm, mfm->error);
|
||||
mfm_complete(mfm);
|
||||
return;
|
||||
}
|
||||
|
||||
hdd_image_zero(drive->hdd_num, addr, 17);
|
||||
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case CMD_READ_SECTORS:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2);
|
||||
drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder;
|
||||
mfm->head = mfm->command[1] & 0x1f;
|
||||
mfm->sector = mfm->command[2] & 0x1f;
|
||||
mfm->sector_count = mfm->command[4];
|
||||
mfm->state = STATE_SEND_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 512;
|
||||
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm_error(mfm, mfm->error);
|
||||
mfm_complete(mfm);
|
||||
return;
|
||||
}
|
||||
|
||||
hdd_image_read(drive->hdd_num, addr, 1,
|
||||
(uint8_t *) mfm->sector_buf);
|
||||
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1);
|
||||
|
||||
if (mfm->irq_dma_mask & DMA_ENA)
|
||||
mfm->callback = MFM_TIME;
|
||||
else {
|
||||
mfm->status = STAT_BSY | STAT_IO | STAT_REQ;
|
||||
memcpy(mfm->data, mfm->sector_buf, 512);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SEND_DATA:
|
||||
mfm->status = STAT_BSY;
|
||||
if (mfm->irq_dma_mask & DMA_ENA) {
|
||||
for (; mfm->data_pos < 512; mfm->data_pos++) {
|
||||
int val = dma_channel_write(3, mfm->sector_buf[mfm->data_pos]);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
mfm_xt_log("CMD_READ_SECTORS out of data!\n");
|
||||
mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ;
|
||||
mfm->callback = MFM_TIME;
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfm->state = STATE_SENT_DATA;
|
||||
mfm->callback = MFM_TIME;
|
||||
} else
|
||||
fatal("Read sectors no DMA! - shouldn't get here\n");
|
||||
break;
|
||||
|
||||
case STATE_SENT_DATA:
|
||||
next_sector(mfm);
|
||||
|
||||
mfm->data_pos = 0;
|
||||
|
||||
mfm->sector_count = (mfm->sector_count-1) & 0xff;
|
||||
|
||||
if (mfm->sector_count) {
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm_error(mfm, mfm->error);
|
||||
mfm_complete(mfm);
|
||||
return;
|
||||
}
|
||||
|
||||
hdd_image_read(drive->hdd_num, addr, 1,
|
||||
(uint8_t *) mfm->sector_buf);
|
||||
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1);
|
||||
|
||||
mfm->state = STATE_SEND_DATA;
|
||||
|
||||
if (mfm->irq_dma_mask & DMA_ENA)
|
||||
mfm->callback = MFM_TIME;
|
||||
else {
|
||||
mfm->status = STAT_BSY | STAT_IO | STAT_REQ;
|
||||
memcpy(mfm->data, mfm->sector_buf, 512);
|
||||
}
|
||||
} else {
|
||||
mfm_complete(mfm);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("CMD_READ_SECTORS: bad state %i\n", mfm->state);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_WRITE_SECTORS:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2);
|
||||
drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder;
|
||||
mfm->head = mfm->command[1] & 0x1f;
|
||||
mfm->sector = mfm->command[2] & 0x1f;
|
||||
mfm->sector_count = mfm->command[4];
|
||||
mfm->state = STATE_RECEIVE_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 512;
|
||||
if (mfm->irq_dma_mask & DMA_ENA)
|
||||
mfm->callback = MFM_TIME;
|
||||
else
|
||||
mfm->status = STAT_BSY | STAT_REQ;
|
||||
break;
|
||||
|
||||
case STATE_RECEIVE_DATA:
|
||||
mfm->status = STAT_BSY;
|
||||
if (mfm->irq_dma_mask & DMA_ENA) {
|
||||
for (; mfm->data_pos < 512; mfm->data_pos++) {
|
||||
int val = dma_channel_read(3);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
mfm_xt_log("CMD_WRITE_SECTORS out of data!\n");
|
||||
mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ;
|
||||
mfm->callback = MFM_TIME;
|
||||
return;
|
||||
}
|
||||
|
||||
mfm->sector_buf[mfm->data_pos] = val & 0xff;
|
||||
}
|
||||
|
||||
mfm->state = STATE_RECEIVED_DATA;
|
||||
mfm->callback = MFM_TIME;
|
||||
} else
|
||||
fatal("Write sectors no DMA! - should never get here\n");
|
||||
break;
|
||||
|
||||
case STATE_RECEIVED_DATA:
|
||||
if (! (mfm->irq_dma_mask & DMA_ENA))
|
||||
memcpy(mfm->sector_buf, mfm->data, 512);
|
||||
|
||||
if (get_sector(mfm, &addr))
|
||||
{
|
||||
mfm_error(mfm, mfm->error);
|
||||
mfm_complete(mfm);
|
||||
return;
|
||||
}
|
||||
|
||||
hdd_image_write(drive->hdd_num, addr, 1,
|
||||
(uint8_t *) mfm->sector_buf);
|
||||
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1);
|
||||
|
||||
next_sector(mfm);
|
||||
mfm->data_pos = 0;
|
||||
mfm->sector_count = (mfm->sector_count-1) & 0xff;
|
||||
|
||||
if (mfm->sector_count) {
|
||||
mfm->state = STATE_RECEIVE_DATA;
|
||||
if (mfm->irq_dma_mask & DMA_ENA)
|
||||
mfm->callback = MFM_TIME;
|
||||
else
|
||||
mfm->status = STAT_BSY | STAT_REQ;
|
||||
} else
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("CMD_WRITE_SECTORS: bad state %i\n", mfm->state);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_SEEK:
|
||||
if (! drive->present)
|
||||
mfm_error(mfm, ERR_NOT_READY);
|
||||
else {
|
||||
int cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2);
|
||||
|
||||
drive->current_cylinder = (cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : cylinder;
|
||||
|
||||
if (cylinder != drive->current_cylinder)
|
||||
mfm_error(mfm, ERR_SEEK_ERROR);
|
||||
}
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case CMD_INIT_DRIVE_PARAMS:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->state = STATE_RECEIVE_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 8;
|
||||
mfm->status = STAT_BSY | STAT_REQ;
|
||||
break;
|
||||
|
||||
case STATE_RECEIVED_DATA:
|
||||
drive->cfg_cyl = mfm->data[1] | (mfm->data[0] << 8);
|
||||
drive->cfg_hpc = mfm->data[2];
|
||||
mfm_xt_log("Drive %i: cylinders=%i, heads=%i\n", mfm->drive_sel, drive->cfg_cyl, drive->cfg_hpc);
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_WRITE_SECTOR_BUFFER:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->state = STATE_RECEIVE_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 512;
|
||||
if (mfm->irq_dma_mask & DMA_ENA)
|
||||
mfm->callback = MFM_TIME;
|
||||
else
|
||||
mfm->status = STAT_BSY | STAT_REQ;
|
||||
break;
|
||||
|
||||
case STATE_RECEIVE_DATA:
|
||||
if (mfm->irq_dma_mask & DMA_ENA) {
|
||||
mfm->status = STAT_BSY;
|
||||
|
||||
for (; mfm->data_pos < 512; mfm->data_pos++) {
|
||||
int val = dma_channel_read(3);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
mfm_xt_log("CMD_WRITE_SECTOR_BUFFER out of data!\n");
|
||||
mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ;
|
||||
mfm->callback = MFM_TIME;
|
||||
return;
|
||||
}
|
||||
|
||||
mfm->data[mfm->data_pos] = val & 0xff;
|
||||
}
|
||||
|
||||
mfm->state = STATE_RECEIVED_DATA;
|
||||
mfm->callback = MFM_TIME;
|
||||
} else
|
||||
fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n");
|
||||
break;
|
||||
|
||||
case STATE_RECEIVED_DATA:
|
||||
memcpy(mfm->sector_buf, mfm->data, 512);
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", mfm->state);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_BUFFER_DIAGNOSTIC:
|
||||
case CMD_CONTROLLER_DIAGNOSTIC:
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case 0xfa:
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case CMD_DTC_SET_STEP_RATE:
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
case CMD_DTC_GET_DRIVE_PARAMS:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->state = STATE_SEND_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 4;
|
||||
mfm->status = STAT_BSY | STAT_IO | STAT_REQ;
|
||||
memset(mfm->data, 0, 4);
|
||||
mfm->data[0] = drive->tracks & 0xff;
|
||||
mfm->data[1] = 17 | ((drive->tracks >> 2) & 0xc0);
|
||||
mfm->data[2] = drive->hpc-1;
|
||||
mfm_xt_log("Get drive params %02x %02x %02x %i\n", mfm->data[0], mfm->data[1], mfm->data[2], drive->tracks);
|
||||
break;
|
||||
|
||||
case STATE_SENT_DATA:
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_DTC_GET_GEOMETRY:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->state = STATE_SEND_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 16;
|
||||
mfm->status = STAT_BSY | STAT_IO | STAT_REQ;
|
||||
memset(mfm->data, 0, 16);
|
||||
mfm->data[0x4] = drive->tracks & 0xff;
|
||||
mfm->data[0x5] = (drive->tracks >> 8) & 0xff;
|
||||
mfm->data[0xa] = drive->hpc;
|
||||
break;
|
||||
|
||||
case STATE_SENT_DATA:
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_DTC_SET_GEOMETRY:
|
||||
switch (mfm->state) {
|
||||
case STATE_START_COMMAND:
|
||||
mfm->state = STATE_RECEIVE_DATA;
|
||||
mfm->data_pos = 0;
|
||||
mfm->data_len = 16;
|
||||
mfm->status = STAT_BSY | STAT_REQ;
|
||||
break;
|
||||
|
||||
case STATE_RECEIVED_DATA:
|
||||
/*Bit of a cheat here - we always report the actual geometry of the drive in use*/
|
||||
mfm_complete(mfm);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n",
|
||||
mfm->command[0], mfm->command[1],
|
||||
mfm->command[2], mfm->command[3],
|
||||
mfm->command[4], mfm->command[5]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn)
|
||||
{
|
||||
drive_t *drive = &mfm->drives[d];
|
||||
|
||||
if (! hdd_image_load(c)) {
|
||||
drive->present = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
drive->spt = hdd[c].spt;
|
||||
drive->hpc = hdd[c].hpc;
|
||||
drive->tracks = hdd[c].tracks;
|
||||
drive->hdd_num = c;
|
||||
drive->present = 1;
|
||||
}
|
||||
|
||||
|
||||
static struct {
|
||||
int tracks, hpc;
|
||||
} hd_types[4] = {
|
||||
{ 306, 4 }, /* Type 0 */
|
||||
{ 612, 4 }, /* Type 16 */
|
||||
{ 615, 4 }, /* Type 2 */
|
||||
{ 306, 8 } /* Type 13 */
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
mfm_set_switches(mfm_t *mfm)
|
||||
{
|
||||
int c, d;
|
||||
|
||||
mfm->switches = 0;
|
||||
|
||||
for (d=0; d<2; d++) {
|
||||
drive_t *drive = &mfm->drives[d];
|
||||
|
||||
if (! drive->present) continue;
|
||||
|
||||
for (c=0; c<4; c++) {
|
||||
if (drive->spt == 17 &&
|
||||
drive->hpc == hd_types[c].hpc &&
|
||||
drive->tracks == hd_types[c].tracks) {
|
||||
mfm->switches |= (c << (d ? 0 : 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 4)
|
||||
mfm_xt_log("WARNING: Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
xebec_init(const device_t *info)
|
||||
{
|
||||
int i, c = 0;
|
||||
|
||||
mfm_t *xebec = malloc(sizeof(mfm_t));
|
||||
memset(xebec, 0x00, sizeof(mfm_t));
|
||||
|
||||
mfm_xt_log("MFM: looking for disks..\n");
|
||||
for (i=0; i<HDD_NUM; i++) {
|
||||
if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) {
|
||||
mfm_xt_log("Found MFM hard disk on channel %i\n", hdd[i].mfm_channel);
|
||||
loadhd(xebec, i, hdd[i].mfm_channel, hdd[i].fn);
|
||||
|
||||
if (++c > MFM_NUM) break;
|
||||
}
|
||||
}
|
||||
mfm_xt_log("MFM: %d disks loaded.\n", c);
|
||||
|
||||
mfm_set_switches(xebec);
|
||||
|
||||
rom_init(&xebec->bios_rom, XEBEC_BIOS_FILE,
|
||||
0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
io_sethandler(0x0320, 4,
|
||||
mfm_read, NULL, NULL, mfm_write, NULL, NULL, xebec);
|
||||
|
||||
timer_add(mfm_callback, &xebec->callback, &xebec->callback, xebec);
|
||||
|
||||
return(xebec);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mfm_close(void *priv)
|
||||
{
|
||||
mfm_t *mfm = (mfm_t *)priv;
|
||||
int d;
|
||||
|
||||
for (d=0; d<2; d++) {
|
||||
drive_t *drive = &mfm->drives[d];
|
||||
|
||||
hdd_image_close(drive->hdd_num);
|
||||
}
|
||||
|
||||
free(mfm);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
xebec_available(void)
|
||||
{
|
||||
return(rom_present(XEBEC_BIOS_FILE));
|
||||
}
|
||||
|
||||
|
||||
const device_t mfm_xt_xebec_device = {
|
||||
"IBM PC Fixed Disk Adapter",
|
||||
DEVICE_ISA,
|
||||
0,
|
||||
xebec_init, mfm_close, NULL,
|
||||
xebec_available, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
static void *
|
||||
dtc5150x_init(const device_t *info)
|
||||
{
|
||||
int i, c = 0;
|
||||
|
||||
mfm_t *dtc = malloc(sizeof(mfm_t));
|
||||
memset(dtc, 0x00, sizeof(mfm_t));
|
||||
|
||||
mfm_xt_log("MFM: looking for disks..\n");
|
||||
for (i=0; i<HDD_NUM; i++) {
|
||||
if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) {
|
||||
mfm_xt_log("Found MFM hard disk on channel %i (%ls)\n", hdd[i].mfm_channel, hdd[i].fn);
|
||||
loadhd(dtc, i, hdd[i].mfm_channel, hdd[i].fn);
|
||||
|
||||
if (++c > MFM_NUM) break;
|
||||
}
|
||||
}
|
||||
mfm_xt_log("MFM: %d disks loaded.\n", c);
|
||||
|
||||
dtc->switches = 0xff;
|
||||
|
||||
dtc->drives[0].cfg_cyl = dtc->drives[0].tracks;
|
||||
dtc->drives[0].cfg_hpc = dtc->drives[0].hpc;
|
||||
dtc->drives[1].cfg_cyl = dtc->drives[1].tracks;
|
||||
dtc->drives[1].cfg_hpc = dtc->drives[1].hpc;
|
||||
|
||||
rom_init(&dtc->bios_rom, DTC_BIOS_FILE,
|
||||
0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
io_sethandler(0x0320, 4,
|
||||
mfm_read, NULL, NULL, mfm_write, NULL, NULL, dtc);
|
||||
|
||||
timer_add(mfm_callback, &dtc->callback, &dtc->callback, dtc);
|
||||
|
||||
return(dtc);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dtc5150x_available(void)
|
||||
{
|
||||
return(rom_present(DTC_BIOS_FILE));
|
||||
}
|
||||
|
||||
|
||||
const device_t mfm_xt_dtc5150x_device = {
|
||||
"DTC 5150X",
|
||||
DEVICE_ISA,
|
||||
0,
|
||||
dtc5150x_init, mfm_close, NULL,
|
||||
dtc5150x_available, NULL, NULL, NULL
|
||||
};
|
||||
@@ -12,13 +12,13 @@
|
||||
* based design. Most cards were WD1003-WA2 or -WAH, where the
|
||||
* -WA2 cards had a floppy controller as well (to save space.)
|
||||
*
|
||||
* Version: @(#)hdc_mfm_at.c 1.0.18 2018/10/17
|
||||
* Version: @(#)hdc_st506_at.c 1.0.19 2019/03/03
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*/
|
||||
#define __USE_LARGEFILE64
|
||||
#define _LARGEFILE_SOURCE
|
||||
@@ -43,7 +43,15 @@
|
||||
#include "hdd.h"
|
||||
|
||||
|
||||
#define MFM_TIME (TIMER_USEC*10LL)
|
||||
#define MFM_TIME (TIMER_USEC*10)
|
||||
|
||||
/*Rough estimate - MFM drives spin at 3600 RPM, with 17 sectors per track,
|
||||
meaning (3600/60)*17 = 1020 sectors per second, or 980us per sector.
|
||||
|
||||
This is required for OS/2 on slow 286 systems, as the hard drive formatter
|
||||
will crash with 'internal processing error' if write sector interrupts are too
|
||||
close in time*/
|
||||
#define SECTOR_TIME (TIMER_USEC * 980)
|
||||
|
||||
#define STAT_ERR 0x01
|
||||
#define STAT_INDEX 0x02
|
||||
@@ -104,7 +112,8 @@ typedef struct {
|
||||
pad;
|
||||
|
||||
int pos; /* offset within data buffer */
|
||||
int64_t callback; /* callback delay timer */
|
||||
uint64_t callback; /* callback delay timer */
|
||||
pc_timer_t timer;
|
||||
|
||||
uint16_t buffer[256]; /* data buffer (16b wide) */
|
||||
|
||||
@@ -112,23 +121,23 @@ typedef struct {
|
||||
} mfm_t;
|
||||
|
||||
|
||||
#ifdef ENABLE_MFM_AT_LOG
|
||||
int mfm_at_do_log = ENABLE_MFM_AT_LOG;
|
||||
#ifdef ENABLE_ST506_AT_LOG
|
||||
int mfm_at_do_log = ENABLE_ST506_AT_LOG;
|
||||
|
||||
|
||||
static void
|
||||
mfm_at_log(const char *fmt, ...)
|
||||
st506_at_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (mfm_at_do_log) {
|
||||
if (st506_at_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define mfm_at_log(fmt, ...)
|
||||
#define st506_at_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -172,31 +181,31 @@ get_sector(mfm_t *mfm, off64_t *addr)
|
||||
drive_t *drive = &mfm->drives[mfm->drvsel];
|
||||
|
||||
if (drive->curcyl != mfm->cylinder) {
|
||||
mfm_at_log("WD1003(%d) sector: wrong cylinder\n");
|
||||
st506_at_log("WD1003(%d) sector: wrong cylinder\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (mfm->head > drive->cfg_hpc) {
|
||||
mfm_at_log("WD1003(%d) get_sector: past end of configured heads\n",
|
||||
mfm->drvsel);
|
||||
st506_at_log("WD1003(%d) get_sector: past end of configured heads\n",
|
||||
mfm->drvsel);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (mfm->sector >= drive->cfg_spt+1) {
|
||||
mfm_at_log("WD1003(%d) get_sector: past end of configured sectors\n",
|
||||
mfm->drvsel);
|
||||
st506_at_log("WD1003(%d) get_sector: past end of configured sectors\n",
|
||||
mfm->drvsel);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* We should check this in the SET_DRIVE_PARAMETERS command! --FvK */
|
||||
if (mfm->head > drive->hpc) {
|
||||
mfm_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel);
|
||||
st506_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (mfm->sector >= drive->spt+1) {
|
||||
mfm_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel);
|
||||
st506_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel);
|
||||
return(1);
|
||||
}
|
||||
#endif
|
||||
@@ -225,6 +234,20 @@ next_sector(mfm_t *mfm)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mfm_set_callback(mfm_t *mfm, uint64_t callback)
|
||||
{
|
||||
if (!mfm)
|
||||
return;
|
||||
|
||||
if (callback) {
|
||||
mfm->callback = callback;
|
||||
timer_set_delay_u64(&mfm->timer, mfm->callback);
|
||||
} else {
|
||||
mfm->callback = 0ULL;
|
||||
timer_disable(&mfm->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
@@ -233,14 +256,11 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
|
||||
if (! drive->present) {
|
||||
/* This happens if sofware polls all drives. */
|
||||
mfm_at_log("WD1003(%d) command %02x on non-present drive\n",
|
||||
mfm->drvsel, val);
|
||||
st506_at_log("WD1003(%d) command %02x on non-present drive\n",
|
||||
mfm->drvsel, val);
|
||||
mfm->command = 0xff;
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
mfm->callback = 200LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
|
||||
mfm_set_callback(mfm, 200 * MFM_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -251,8 +271,8 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
switch (val & 0xf0) {
|
||||
case CMD_RESTORE:
|
||||
drive->steprate = (val & 0x0f);
|
||||
mfm_at_log("WD1003(%d) restore, step=%d\n",
|
||||
mfm->drvsel, drive->steprate);
|
||||
st506_at_log("WD1003(%d) restore, step=%d\n",
|
||||
mfm->drvsel, drive->steprate);
|
||||
drive->curcyl = 0;
|
||||
mfm->status = STAT_READY|STAT_DSC;
|
||||
mfm->command &= 0xf0;
|
||||
@@ -263,9 +283,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
drive->steprate = (val & 0x0f);
|
||||
mfm->command &= 0xf0;
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
mfm->callback = 200LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 200 * MFM_TIME);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -275,23 +293,21 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
case CMD_READ+1:
|
||||
case CMD_READ+2:
|
||||
case CMD_READ+3:
|
||||
mfm_at_log("WD1003(%d) read, opt=%d\n",
|
||||
mfm->drvsel, val&0x03);
|
||||
st506_at_log("WD1003(%d) read, opt=%d\n",
|
||||
mfm->drvsel, val&0x03);
|
||||
mfm->command &= 0xfc;
|
||||
if (val & 2)
|
||||
fatal("WD1003: READ with ECC\n");
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
mfm->callback = 200LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 200 * MFM_TIME);
|
||||
break;
|
||||
|
||||
case CMD_WRITE:
|
||||
case CMD_WRITE+1:
|
||||
case CMD_WRITE+2:
|
||||
case CMD_WRITE+3:
|
||||
mfm_at_log("WD1003(%d) write, opt=%d\n",
|
||||
mfm->drvsel, val & 0x03);
|
||||
st506_at_log("WD1003(%d) write, opt=%d\n",
|
||||
mfm->drvsel, val & 0x03);
|
||||
mfm->command &= 0xfc;
|
||||
if (val & 2)
|
||||
fatal("WD1003: WRITE with ECC\n");
|
||||
@@ -303,9 +319,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
case CMD_VERIFY+1:
|
||||
mfm->command &= 0xfe;
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
mfm->callback = 200LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 200 * MFM_TIME);
|
||||
break;
|
||||
|
||||
case CMD_FORMAT:
|
||||
@@ -315,9 +329,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
|
||||
case CMD_DIAGNOSE:
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
mfm->callback = 200LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 200 * MFM_TIME);
|
||||
break;
|
||||
|
||||
case CMD_SET_PARAMETERS:
|
||||
@@ -341,13 +353,13 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
/* Only accept after RESET or DIAG. */
|
||||
drive->cfg_spt = mfm->secount;
|
||||
drive->cfg_hpc = mfm->head+1;
|
||||
mfm_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n",
|
||||
mfm->drvsel, drive->tracks,
|
||||
drive->cfg_spt, drive->cfg_hpc);
|
||||
st506_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n",
|
||||
mfm->drvsel, drive->tracks,
|
||||
drive->cfg_spt, drive->cfg_hpc);
|
||||
} else {
|
||||
mfm_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n",
|
||||
mfm->drvsel, drive->tracks,
|
||||
drive->cfg_spt, drive->cfg_hpc);
|
||||
st506_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n",
|
||||
mfm->drvsel, drive->tracks,
|
||||
drive->cfg_spt, drive->cfg_hpc);
|
||||
}
|
||||
mfm->command = 0x00;
|
||||
mfm->status = STAT_READY|STAT_DSC;
|
||||
@@ -356,11 +368,9 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
|
||||
break;
|
||||
|
||||
default:
|
||||
mfm_at_log("WD1003: bad command %02X\n", val);
|
||||
st506_at_log("WD1003: bad command %02X\n", val);
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
mfm->callback = 200LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 200 * MFM_TIME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -378,11 +388,7 @@ mfm_writew(uint16_t port, uint16_t val, void *priv)
|
||||
if (mfm->pos >= 512) {
|
||||
mfm->pos = 0;
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
/* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */
|
||||
mfm->callback = ((3125LL * TIMER_USEC) / 4LL);
|
||||
/* mfm->callback = 10LL * MFM_TIME; */
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, SECTOR_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +398,7 @@ mfm_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
mfm_t *mfm = (mfm_t *)priv;
|
||||
|
||||
mfm_at_log("WD1003 write(%04x, %02x)\n", port, val);
|
||||
st506_at_log("WD1003 write(%04x, %02x)\n", port, val);
|
||||
|
||||
switch (port) {
|
||||
case 0x01f0: /* data */
|
||||
@@ -435,18 +441,14 @@ mfm_write(uint16_t port, uint8_t val, void *priv)
|
||||
case 0x03f6: /* device control */
|
||||
val &= 0x0f;
|
||||
if ((mfm->fdisk & 0x04) && !(val & 0x04)) {
|
||||
timer_clock();
|
||||
mfm->callback = 500LL*MFM_TIME;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 500 * MFM_TIME);
|
||||
mfm->reset = 1;
|
||||
mfm->status = STAT_BUSY;
|
||||
}
|
||||
|
||||
if (val & 0x04) {
|
||||
/* Drive held in reset. */
|
||||
timer_clock();
|
||||
mfm->callback = 0LL;
|
||||
timer_update_outstanding();
|
||||
mfm_set_callback(mfm, 0);
|
||||
mfm->status = STAT_BUSY;
|
||||
}
|
||||
mfm->fdisk = val;
|
||||
@@ -474,14 +476,9 @@ mfm_readw(uint16_t port, void *priv)
|
||||
if (mfm->secount) {
|
||||
next_sector(mfm);
|
||||
mfm->status = STAT_BUSY;
|
||||
timer_clock();
|
||||
/* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */
|
||||
mfm->callback = ((3125LL * TIMER_USEC) / 4LL);
|
||||
/* mfm->callback = 10LL * MFM_TIME; */
|
||||
timer_update_outstanding();
|
||||
} else {
|
||||
mfm_set_callback(mfm, SECTOR_TIME);
|
||||
} else
|
||||
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,7 +530,7 @@ mfm_read(uint16_t port, void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
mfm_at_log("WD1003 read(%04x) = %02x\n", port, ret);
|
||||
st506_at_log("WD1003 read(%04x) = %02x\n", port, ret);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
@@ -544,8 +541,8 @@ do_seek(mfm_t *mfm)
|
||||
{
|
||||
drive_t *drive = &mfm->drives[mfm->drvsel];
|
||||
|
||||
mfm_at_log("WD1003(%d) seek(%d) max=%d\n",
|
||||
mfm->drvsel,mfm->cylinder,drive->tracks);
|
||||
st506_at_log("WD1003(%d) seek(%d) max=%d\n",
|
||||
mfm->drvsel,mfm->cylinder,drive->tracks);
|
||||
|
||||
if (mfm->cylinder < drive->tracks)
|
||||
drive->curcyl = mfm->cylinder;
|
||||
@@ -561,9 +558,9 @@ do_callback(void *priv)
|
||||
drive_t *drive = &mfm->drives[mfm->drvsel];
|
||||
off64_t addr;
|
||||
|
||||
mfm->callback = 0LL;
|
||||
mfm_set_callback(mfm, 0);
|
||||
if (mfm->reset) {
|
||||
mfm_at_log("WD1003(%d) reset\n", mfm->drvsel);
|
||||
st506_at_log("WD1003(%d) reset\n", mfm->drvsel);
|
||||
|
||||
mfm->status = STAT_READY|STAT_DSC;
|
||||
mfm->error = 1;
|
||||
@@ -584,16 +581,16 @@ do_callback(void *priv)
|
||||
|
||||
switch (mfm->command) {
|
||||
case CMD_SEEK:
|
||||
mfm_at_log("WD1003(%d) seek, step=%d\n",
|
||||
mfm->drvsel, drive->steprate);
|
||||
st506_at_log("WD1003(%d) seek, step=%d\n",
|
||||
mfm->drvsel, drive->steprate);
|
||||
do_seek(mfm);
|
||||
mfm->status = STAT_READY|STAT_DSC;
|
||||
irq_raise(mfm);
|
||||
break;
|
||||
|
||||
case CMD_READ:
|
||||
mfm_at_log("WD1003(%d) read(%d,%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector);
|
||||
st506_at_log("WD1003(%d) read(%d,%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector);
|
||||
do_seek(mfm);
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm->error = ERR_ID_NOT_FOUND;
|
||||
@@ -611,8 +608,8 @@ do_callback(void *priv)
|
||||
break;
|
||||
|
||||
case CMD_WRITE:
|
||||
mfm_at_log("WD1003(%d) write(%d,%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector);
|
||||
st506_at_log("WD1003(%d) write(%d,%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector);
|
||||
do_seek(mfm);
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm->error = ERR_ID_NOT_FOUND;
|
||||
@@ -637,8 +634,8 @@ do_callback(void *priv)
|
||||
break;
|
||||
|
||||
case CMD_VERIFY:
|
||||
mfm_at_log("WD1003(%d) verify(%d,%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector);
|
||||
st506_at_log("WD1003(%d) verify(%d,%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector);
|
||||
do_seek(mfm);
|
||||
mfm->pos = 0;
|
||||
mfm->status = STAT_READY|STAT_DSC;
|
||||
@@ -647,8 +644,8 @@ do_callback(void *priv)
|
||||
break;
|
||||
|
||||
case CMD_FORMAT:
|
||||
mfm_at_log("WD1003(%d) format(%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head);
|
||||
st506_at_log("WD1003(%d) format(%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head);
|
||||
do_seek(mfm);
|
||||
if (get_sector(mfm, &addr)) {
|
||||
mfm->error = ERR_ID_NOT_FOUND;
|
||||
@@ -665,7 +662,7 @@ do_callback(void *priv)
|
||||
break;
|
||||
|
||||
case CMD_DIAGNOSE:
|
||||
mfm_at_log("WD1003(%d) diag\n", mfm->drvsel);
|
||||
st506_at_log("WD1003(%d) diag\n", mfm->drvsel);
|
||||
drive->steprate = 0x0f;
|
||||
mfm->error = 1;
|
||||
mfm->status = STAT_READY|STAT_DSC;
|
||||
@@ -673,8 +670,8 @@ do_callback(void *priv)
|
||||
break;
|
||||
|
||||
default:
|
||||
mfm_at_log("WD1003(%d) callback on unknown command %02x\n",
|
||||
mfm->drvsel, mfm->command);
|
||||
st506_at_log("WD1003(%d) callback on unknown command %02x\n",
|
||||
mfm->drvsel, mfm->command);
|
||||
mfm->status = STAT_READY|STAT_ERR|STAT_DSC;
|
||||
mfm->error = ERR_ABRT;
|
||||
irq_raise(mfm);
|
||||
@@ -708,7 +705,7 @@ mfm_init(const device_t *info)
|
||||
mfm_t *mfm;
|
||||
int c, d;
|
||||
|
||||
mfm_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n");
|
||||
st506_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n");
|
||||
mfm = malloc(sizeof(mfm_t));
|
||||
memset(mfm, 0x00, sizeof(mfm_t));
|
||||
|
||||
@@ -717,8 +714,8 @@ mfm_init(const device_t *info)
|
||||
if ((hdd[d].bus == HDD_BUS_MFM) && (hdd[d].mfm_channel < MFM_NUM)) {
|
||||
loadhd(mfm, hdd[d].mfm_channel, d, hdd[d].fn);
|
||||
|
||||
mfm_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn,
|
||||
(int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt);
|
||||
st506_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn,
|
||||
(int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt);
|
||||
|
||||
if (++c >= MFM_NUM) break;
|
||||
}
|
||||
@@ -734,7 +731,7 @@ mfm_init(const device_t *info)
|
||||
io_sethandler(0x03f6, 1,
|
||||
NULL, NULL, NULL, mfm_write, NULL, NULL, mfm);
|
||||
|
||||
timer_add(do_callback, &mfm->callback, &mfm->callback, mfm);
|
||||
timer_add(&mfm->timer, do_callback, mfm, 0);
|
||||
|
||||
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0);
|
||||
|
||||
@@ -760,7 +757,7 @@ mfm_close(void *priv)
|
||||
}
|
||||
|
||||
|
||||
const device_t mfm_at_wd1003_device = {
|
||||
const device_t st506_at_wd1003_device = {
|
||||
"WD1003 AT MFM/RLL Controller",
|
||||
DEVICE_ISA | DEVICE_AT,
|
||||
0,
|
||||
1919
src/disk/hdc_st506_xt.c
Normal file
1919
src/disk/hdc_st506_xt.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -257,7 +257,8 @@ typedef struct {
|
||||
uint8_t sense; /* current SENSE ERROR value */
|
||||
uint8_t status; /* current operational status */
|
||||
uint8_t intr;
|
||||
int64_t callback;
|
||||
uint64_t callback;
|
||||
pc_timer_t timer;
|
||||
|
||||
/* Data transfer. */
|
||||
int16_t buf_idx, /* buffer index and pointer */
|
||||
@@ -357,6 +358,22 @@ next_sector(hdc_t *dev, drive_t *drive)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xta_set_callback(hdc_t *dev, uint64_t callback)
|
||||
{
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
dev->callback = callback;
|
||||
timer_set_delay_u64(&dev->timer, dev->callback);
|
||||
} else {
|
||||
dev->callback = 0;
|
||||
timer_disable(&dev->timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Perform the seek operation. */
|
||||
static void
|
||||
@@ -456,7 +473,7 @@ hdc_callback(void *priv)
|
||||
int val;
|
||||
|
||||
/* Cancel timer. */
|
||||
dev->callback = 0;
|
||||
xta_set_callback(dev, 0);
|
||||
|
||||
drive = &dev->drives[dcb->drvsel];
|
||||
dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00;
|
||||
@@ -553,12 +570,12 @@ do_send:
|
||||
dev->buf_idx = 0;
|
||||
if (no_data) {
|
||||
/* Delay a bit, no actual transfer. */
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
} else {
|
||||
if (dev->intr & DMA_ENA) {
|
||||
/* DMA enabled. */
|
||||
dev->buf_ptr = dev->sector_buf;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
} else {
|
||||
/* Copy from sector to data. */
|
||||
memcpy(dev->data,
|
||||
@@ -581,14 +598,14 @@ do_send:
|
||||
xta_log("%s: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len);
|
||||
|
||||
dev->status |= (STAT_CD | STAT_IO| STAT_REQ);
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
return;
|
||||
}
|
||||
dev->buf_ptr++;
|
||||
dev->buf_idx++;
|
||||
}
|
||||
}
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
dev->state = STATE_SDONE;
|
||||
break;
|
||||
|
||||
@@ -651,12 +668,12 @@ do_recv:
|
||||
dev->buf_idx = 0;
|
||||
if (no_data) {
|
||||
/* Delay a bit, no actual transfer. */
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
} else {
|
||||
if (dev->intr & DMA_ENA) {
|
||||
/* DMA enabled. */
|
||||
dev->buf_ptr = dev->sector_buf;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
} else {
|
||||
/* No DMA, do PIO. */
|
||||
dev->buf_ptr = dev->data;
|
||||
@@ -676,7 +693,7 @@ do_recv:
|
||||
|
||||
xta_log("%s: CMD_WRITE_SECTORS out of data!\n", dev->name);
|
||||
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -684,7 +701,7 @@ do_recv:
|
||||
dev->buf_idx++;
|
||||
}
|
||||
dev->state = STATE_RDONE;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -783,7 +800,7 @@ do_recv:
|
||||
dev->state = STATE_RDATA;
|
||||
if (dev->intr & DMA_ENA) {
|
||||
dev->buf_ptr = dev->sector_buf;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
} else {
|
||||
dev->buf_ptr = dev->data;
|
||||
dev->status |= STAT_REQ;
|
||||
@@ -798,7 +815,7 @@ do_recv:
|
||||
if (val == DMA_NODATA) {
|
||||
xta_log("%s: CMD_WRITE_BUFFER out of data!\n", dev->name);
|
||||
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -806,7 +823,7 @@ do_recv:
|
||||
dev->buf_idx++;
|
||||
}
|
||||
dev->state = STATE_RDONE;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -823,7 +840,7 @@ do_recv:
|
||||
switch(dev->state) {
|
||||
case STATE_IDLE:
|
||||
dev->state = STATE_RDONE;
|
||||
dev->callback = 5*HDC_TIME;
|
||||
xta_set_callback(dev, 5 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case STATE_RDONE:
|
||||
@@ -837,7 +854,7 @@ do_recv:
|
||||
case STATE_IDLE:
|
||||
if (drive->present) {
|
||||
dev->state = STATE_RDONE;
|
||||
dev->callback = 5*HDC_TIME;
|
||||
xta_set_callback(dev, 5 * HDC_TIME);
|
||||
} else {
|
||||
dev->comp |= COMP_ERR;
|
||||
dev->sense = ERR_NOTRDY;
|
||||
@@ -855,7 +872,7 @@ do_recv:
|
||||
switch(dev->state) {
|
||||
case STATE_IDLE:
|
||||
dev->state = STATE_RDONE;
|
||||
dev->callback = 10*HDC_TIME;
|
||||
xta_set_callback(dev, 10 * HDC_TIME);
|
||||
break;
|
||||
|
||||
case STATE_RDONE:
|
||||
@@ -898,7 +915,7 @@ hdc_read(uint16_t port, void *priv)
|
||||
/* All data sent. */
|
||||
dev->status &= ~STAT_REQ;
|
||||
dev->state = STATE_SDONE;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
}
|
||||
} else if (dev->state == STATE_COMPL) {
|
||||
xta_log("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->comp);
|
||||
@@ -954,7 +971,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
|
||||
else
|
||||
dev->state = STATE_IDLE;
|
||||
dev->status &= ~STAT_CD;
|
||||
dev->callback = HDC_TIME;
|
||||
xta_set_callback(dev, HDC_TIME);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -981,6 +998,13 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
xta_available(void)
|
||||
{
|
||||
return(rom_present(WD_BIOS_FILE));
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
xta_init(const device_t *info)
|
||||
{
|
||||
@@ -1063,7 +1087,7 @@ xta_init(const device_t *info)
|
||||
dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
/* Create a timer for command delays. */
|
||||
timer_add(hdc_callback, &dev->callback, &dev->callback, dev);
|
||||
timer_add(&dev->timer, hdc_callback, dev, 0);
|
||||
|
||||
return(dev);
|
||||
}
|
||||
@@ -1146,7 +1170,7 @@ const device_t xta_wdxt150_device = {
|
||||
DEVICE_ISA,
|
||||
0,
|
||||
xta_init, xta_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
xta_available, NULL, NULL,
|
||||
wdxt150_config
|
||||
};
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ const device_t xtide_acculogic_device = {
|
||||
|
||||
const device_t xtide_at_ps2_device = {
|
||||
"XTIDE (AT) (1.1.5)",
|
||||
DEVICE_ISA | DEVICE_PS2,
|
||||
DEVICE_AT,
|
||||
0,
|
||||
xtide_at_ps2_init, xtide_at_close, NULL,
|
||||
xtide_at_ps2_available, NULL, NULL,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../plat.h"
|
||||
#include "../ui.h"
|
||||
#include "hdd.h"
|
||||
#include "../cdrom/cdrom.h"
|
||||
|
||||
|
||||
hard_disk_t hdd[HDD_NUM];
|
||||
@@ -92,6 +93,9 @@ no_cdrom:
|
||||
if (! strcmp(str, "scsi"))
|
||||
return(HDD_BUS_SCSI);
|
||||
|
||||
if (! strcmp(str, "scsi_chinon"))
|
||||
return(CDROM_BUS_SCSI_CHINON);
|
||||
|
||||
if (! strcmp(str, "usb"))
|
||||
ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4110);
|
||||
|
||||
@@ -128,6 +132,10 @@ hdd_bus_to_string(int bus, int cdrom)
|
||||
case HDD_BUS_SCSI:
|
||||
s = "scsi";
|
||||
break;
|
||||
|
||||
case CDROM_BUS_SCSI_CHINON:
|
||||
s = "scsi_chinon";
|
||||
break;
|
||||
}
|
||||
|
||||
return(s);
|
||||
|
||||
@@ -748,9 +748,17 @@ hdd_image_seek(uint8_t id, uint32_t sector)
|
||||
void
|
||||
hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
|
||||
{
|
||||
hdd_images[id].pos = sector;
|
||||
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
|
||||
fread(buffer, 1, count << 9, hdd_images[id].file);
|
||||
int i;
|
||||
|
||||
fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (feof(hdd_images[id].file))
|
||||
break;
|
||||
|
||||
hdd_images[id].pos = sector + i;
|
||||
fread(buffer + (i << 9), 1, 512, hdd_images[id].file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -782,9 +790,17 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
|
||||
void
|
||||
hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
|
||||
{
|
||||
hdd_images[id].pos = sector;
|
||||
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
|
||||
fwrite(buffer, count << 9, 1, hdd_images[id].file);
|
||||
int i;
|
||||
|
||||
fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (feof(hdd_images[id].file))
|
||||
break;
|
||||
|
||||
hdd_images[id].pos = sector + i;
|
||||
fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -810,11 +826,17 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
|
||||
hdd_images[id].pos = sector;
|
||||
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
|
||||
memset(empty_sector, 0, 512);
|
||||
for (i = 0; i < count; i++)
|
||||
|
||||
fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (feof(hdd_images[id].file))
|
||||
break;
|
||||
|
||||
hdd_images[id].pos = sector + i;
|
||||
fwrite(empty_sector, 512, 1, hdd_images[id].file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../timer.h"
|
||||
#include "../config.h"
|
||||
#include "../timer.h"
|
||||
#include "../device.h"
|
||||
@@ -857,16 +858,15 @@ static void
|
||||
zip_command_common(zip_t *dev)
|
||||
{
|
||||
double bytes_per_second, period;
|
||||
double dusec;
|
||||
|
||||
dev->status = BUSY_STAT;
|
||||
dev->phase = 1;
|
||||
dev->pos = 0;
|
||||
if (dev->packet_status == PHASE_COMPLETE)
|
||||
dev->callback = 0LL;
|
||||
dev->callback = 0.0;
|
||||
else {
|
||||
if (dev->drv->bus_type == ZIP_BUS_SCSI) {
|
||||
dev->callback = -1LL; /* Speed depends on SCSI controller */
|
||||
dev->callback = -1.0; /* Speed depends on SCSI controller */
|
||||
return;
|
||||
} else {
|
||||
if (zip_current_mode(dev) == 2)
|
||||
@@ -876,9 +876,7 @@ zip_command_common(zip_t *dev)
|
||||
}
|
||||
|
||||
period = 1000000.0 / bytes_per_second;
|
||||
dusec = (double) TIMER_USEC;
|
||||
dusec = dusec * period * (double) (dev->packet_len);
|
||||
dev->callback = ((int64_t) dusec);
|
||||
dev->callback = period * (double) (dev->packet_len);
|
||||
}
|
||||
|
||||
zip_set_callback(dev);
|
||||
@@ -998,7 +996,7 @@ zip_cmd_error(zip_t *dev)
|
||||
dev->phase = 3;
|
||||
dev->pos = 0;
|
||||
dev->packet_status = PHASE_ERROR;
|
||||
dev->callback = 50LL * ZIP_TIME;
|
||||
dev->callback = 50.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq);
|
||||
}
|
||||
@@ -1015,7 +1013,7 @@ zip_unit_attention(zip_t *dev)
|
||||
dev->phase = 3;
|
||||
dev->pos = 0;
|
||||
dev->packet_status = PHASE_ERROR;
|
||||
dev->callback = 50LL * ZIP_TIME;
|
||||
dev->callback = 50.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
zip_log("ZIP %i: UNIT ATTENTION\n", dev->id);
|
||||
}
|
||||
@@ -1138,6 +1136,7 @@ static int
|
||||
zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out)
|
||||
{
|
||||
*len = 0;
|
||||
int i;
|
||||
|
||||
if (!dev->sector_len) {
|
||||
zip_command_complete(dev);
|
||||
@@ -1154,11 +1153,17 @@ zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out)
|
||||
|
||||
*len = dev->requested_blocks << 9;
|
||||
|
||||
fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9), SEEK_SET);
|
||||
if (out)
|
||||
fwrite(dev->buffer, 1, *len, dev->drv->f);
|
||||
else
|
||||
fread(dev->buffer, 1, *len, dev->drv->f);
|
||||
for (i = 0; i < dev->requested_blocks; i++) {
|
||||
fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9) + (i << 9), SEEK_SET);
|
||||
|
||||
if (feof(dev->drv->f))
|
||||
break;
|
||||
|
||||
if (out)
|
||||
fwrite(dev->buffer + (i << 9), 1, 512, dev->drv->f);
|
||||
else
|
||||
fread(dev->buffer + (i << 9), 1, 512, dev->drv->f);
|
||||
}
|
||||
|
||||
zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len);
|
||||
|
||||
@@ -1286,7 +1291,7 @@ zip_reset(scsi_common_t *sc)
|
||||
|
||||
zip_rezero(dev);
|
||||
dev->status = 0;
|
||||
dev->callback = 0LL;
|
||||
dev->callback = 0.0;
|
||||
zip_set_callback(dev);
|
||||
dev->phase = 1;
|
||||
dev->request_length = 0xEB14;
|
||||
@@ -1481,7 +1486,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
if (!max_len) {
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
dev->packet_status = PHASE_COMPLETE;
|
||||
dev->callback = 20LL * ZIP_TIME;
|
||||
dev->callback = 20.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
break;
|
||||
}
|
||||
@@ -1533,7 +1538,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
/* zip_log("ZIP %i: All done - callback set\n", dev->id); */
|
||||
dev->packet_status = PHASE_COMPLETE;
|
||||
dev->callback = 20LL * ZIP_TIME;
|
||||
dev->callback = 20.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
break;
|
||||
}
|
||||
@@ -1550,7 +1555,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
if (ret <= 0) {
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
dev->packet_status = PHASE_COMPLETE;
|
||||
dev->callback = 20LL * ZIP_TIME;
|
||||
dev->callback = 20.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
zip_buf_free(dev);
|
||||
return;
|
||||
@@ -1594,6 +1599,8 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
case GPCMD_VERIFY_6:
|
||||
case GPCMD_WRITE_6:
|
||||
dev->sector_len = cdb[4];
|
||||
if (dev->sector_len == 0)
|
||||
dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */
|
||||
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
||||
break;
|
||||
case GPCMD_VERIFY_10:
|
||||
@@ -1611,8 +1618,8 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dev->sector_pos >= dev->drv->medium_size) ||
|
||||
((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) {
|
||||
if ((dev->sector_pos >= dev->drv->medium_size)/* ||
|
||||
((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/) {
|
||||
zip_lba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
@@ -1621,7 +1628,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
/* zip_log("ZIP %i: All done - callback set\n", dev->id); */
|
||||
dev->packet_status = PHASE_COMPLETE;
|
||||
dev->callback = 20LL * ZIP_TIME;
|
||||
dev->callback = 20.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
break;
|
||||
}
|
||||
@@ -1663,8 +1670,8 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
||||
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
||||
|
||||
if ((dev->sector_pos >= dev->drv->medium_size) ||
|
||||
((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) {
|
||||
if ((dev->sector_pos >= dev->drv->medium_size)/* ||
|
||||
((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/) {
|
||||
zip_lba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
@@ -1673,7 +1680,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
/* zip_log("ZIP %i: All done - callback set\n", dev->id); */
|
||||
dev->packet_status = PHASE_COMPLETE;
|
||||
dev->callback = 20LL * ZIP_TIME;
|
||||
dev->callback = 20.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
break;
|
||||
}
|
||||
@@ -2307,7 +2314,7 @@ zip_drive_reset(int c)
|
||||
sd->type = SCSI_REMOVABLE_DISK;
|
||||
} else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) {
|
||||
/* ATAPI CD-ROM, attach to the IDE bus. */
|
||||
id = ide_drives[zip_drives[c].ide_channel];
|
||||
id = ide_get_drive(zip_drives[c].ide_channel);
|
||||
/* If the IDE channel is initialized, we attach to it,
|
||||
otherwise, we do nothing - it's going to be a drive
|
||||
that's not attached to anything. */
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#define BUF_SIZE 32768
|
||||
|
||||
#define ZIP_TIME (5LL * 100LL * (1LL << TIMER_SHIFT))
|
||||
#define ZIP_TIME 500.0
|
||||
|
||||
#define ZIP_SECTORS (96*2048)
|
||||
|
||||
@@ -85,7 +85,7 @@ typedef struct {
|
||||
uint32_t sector_pos, sector_len,
|
||||
packet_len, pos;
|
||||
|
||||
int64_t callback;
|
||||
double callback;
|
||||
} zip_t;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user