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:
OBattler
2019-09-20 14:02:30 +02:00
parent b06296bbf6
commit 552a87ea3d
524 changed files with 129555 additions and 21862 deletions

View File

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

View File

@@ -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 */

View File

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

View File

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

View File

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

View 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);

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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,

View File

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

View File

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

View 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. */

View File

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