Files
86Box/src/disk/hdc_xta.c

1170 lines
38 KiB
C
Raw Normal View History

/*
2022-10-29 10:52:49 -04:00
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* Implementation of a generic IDE-XTA disk controller.
*
* XTA is the acronym for 'XT-Attached', which was basically
* the XT-counterpart to what we know now as IDE (which is
* also named ATA - AT Attachment.) The basic ideas was to
* put the actual drive controller electronics onto the drive
* itself, and have the host machine just talk to that using
* a simpe, standardized I/O path- hence the name IDE, for
* Integrated Drive Electronics.
*
* In the ATA version of IDE, the programming interface of
* the IBM PC/AT (which used the Western Digitial 1002/1003
* controllers) was kept, and, so, ATA-IDE assumes a 16bit
* data path: it reads and writes 16bit words of data. The
* disk drives for this bus commonly have an 'A' suffix to
* identify them as 'ATBUS'.
*
* In XTA-IDE, which is slightly older, the programming
* interface of the IBM PC/XT (which used the MFM controller
* from Xebec) was kept, and, so, it uses an 8bit data path.
* Disk drives for this bus commonly have the 'X' suffix to
* mark them as being for this XTBUS variant.
*
* So, XTA and ATA try to do the same thing, but they use
* different ways to achive their goal.
*
* Also, XTA is **not** the same as XTIDE. XTIDE is a modern
* variant of ATA-IDE, but retro-fitted for use on 8bit XT
* systems: an extra register is used to deal with the extra
* data byte per transfer. XTIDE uses regular IDE drives,
* and uses the regular ATA/IDE programming interface, just
* with the extra register.
2022-02-20 02:26:27 -05:00
*
* NOTE: This driver implements both the 'standard' XTA interface,
* sold by Western Digital as the WDXT-140 (no BIOS) and the
* WDXT-150 (with BIOS), as well as some variants customized
* for specific machines.
*
* NOTE: The XTA interface is 0-based for sector numbers !!
*
2020-03-25 00:46:02 +02:00
*
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
*
* Based on my earlier HD20 driver for the EuroPC.
*
2023-01-06 15:36:29 -05:00
* Copyright 2017-2018 Fred N. van Kempen.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/dma.h>
#include <86box/pic.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/plat.h>
#include <86box/ui.h>
#include <86box/hdc.h>
#include <86box/hdd.h>
2022-09-18 17:13:50 -04:00
#define HDC_TIME (50 * TIMER_USEC)
#define WD_REV_1_BIOS_FILE "roms/hdd/xta/idexywd2.bin"
#define WD_REV_2_BIOS_FILE "roms/hdd/xta/infowdbios.rom"
enum {
STATE_IDLE = 0,
STATE_RECV,
STATE_RDATA,
STATE_RDONE,
STATE_SEND,
STATE_SDATA,
STATE_SDONE,
STATE_COMPL
};
/* Command values. */
2022-09-18 17:13:50 -04:00
#define CMD_TEST_READY 0x00
#define CMD_RECALIBRATE 0x01
/* unused 0x02 */
2022-09-18 17:13:50 -04:00
#define CMD_READ_SENSE 0x03
#define CMD_FORMAT_DRIVE 0x04
#define CMD_READ_VERIFY 0x05
#define CMD_FORMAT_TRACK 0x06
#define CMD_FORMAT_BAD_TRACK 0x07
#define CMD_READ_SECTORS 0x08
/* unused 0x09 */
2022-09-18 17:13:50 -04:00
#define CMD_WRITE_SECTORS 0x0a
#define CMD_SEEK 0x0b
#define CMD_SET_DRIVE_PARAMS 0x0c
#define CMD_READ_ECC_BURST 0x0d
#define CMD_READ_SECTOR_BUFFER 0x0e
#define CMD_WRITE_SECTOR_BUFFER 0x0f
#define CMD_RAM_DIAGS 0xe0
/* unused 0xe1 */
/* unused 0xe2 */
2022-09-18 17:13:50 -04:00
#define CMD_DRIVE_DIAGS 0xe3
#define CMD_CTRL_DIAGS 0xe4
#define CMD_READ_LONG 0xe5
#define CMD_WRITE_LONG 0xe6
/* Status register (reg 1) values. */
2022-09-18 17:13:50 -04:00
#define STAT_REQ 0x01 /* controller needs data transfer */
#define STAT_IO 0x02 /* direction of transfer (TO bus) */
#define STAT_CD 0x04 /* transfer of Command or Data */
#define STAT_BSY 0x08 /* controller is busy */
#define STAT_DRQ 0x10 /* DMA requested */
#define STAT_IRQ 0x20 /* interrupt requested */
#define STAT_DCB 0x80 /* not seen by driver */
/* Sense Error codes. */
2022-09-18 17:13:50 -04:00
#define ERR_NOERROR 0x00 /* no error detected */
#define ERR_NOINDEX 0x01 /* drive did not detect IDX pulse */
#define ERR_NOSEEK 0x02 /* drive did not complete SEEK */
#define ERR_WRFAULT 0x03 /* write fault during last cmd */
#define ERR_NOTRDY 0x04 /* drive did not go READY after cmd */
#define ERR_NOTRK000 0x06 /* drive did not see TRK0 signal */
#define ERR_LONGSEEK 0x08 /* long seek in progress */
#define ERR_IDREAD 0x10 /* ECC error during ID field */
#define ERR_DATA 0x11 /* uncorrectable ECC err in data */
#define ERR_NOMARK 0x12 /* no address mark detected */
#define ERR_NOSECT 0x14 /* sector not found */
#define ERR_SEEK 0x15 /* seek error */
#define ERR_ECCDATA 0x18 /* ECC corrected data */
#define ERR_BADTRK 0x19 /* bad track detected */
#define ERR_ILLCMD 0x20 /* invalid command received */
#define ERR_ILLADDR 0x21 /* invalid disk address received */
#define ERR_BADRAM 0x30 /* bad RAM in sector data buffer */
#define ERR_BADROM 0x31 /* bad checksum in ROM test */
#define ERR_BADECC 0x32 /* ECC polynomial generator bad */
/* Completion Byte fields. */
2022-09-18 17:13:50 -04:00
#define COMP_DRIVE 0x20
#define COMP_ERR 0x02
2022-09-18 17:13:50 -04:00
#define IRQ_ENA 0x02
#define DMA_ENA 0x01
/* The device control block (6 bytes) */
2022-09-18 17:13:50 -04:00
#pragma pack(push, 1)
typedef struct {
uint8_t cmd; /* [7:5] class, [4:0] opcode */
uint8_t head : 5, /* [4:0] head number */
drvsel : 1, /* [5] drive select */
mbz : 2; /* [7:6] 00 */
uint8_t sector : 6, /* [5:0] sector number 0-63 */
cyl_high : 2; /* [7:6] cylinder [9:8] bits */
uint8_t cyl_low; /* [7:0] cylinder [7:0] bits */
uint8_t count; /* [7:0] blk count / interleave */
uint8_t ctrl; /* [7:0] control field */
} dcb_t;
#pragma pack(pop)
/* The (configured) Drive Parameters. */
2022-09-18 17:13:50 -04:00
#pragma pack(push, 1)
typedef struct {
2022-09-18 17:13:50 -04:00
uint8_t cyl_high; /* (MSB) number of cylinders */
uint8_t cyl_low; /* (LSB) number of cylinders */
uint8_t heads; /* number of heads per cylinder */
uint8_t rwc_high; /* (MSB) reduced write current cylinder */
uint8_t rwc_low; /* (LSB) reduced write current cylinder */
uint8_t wp_high; /* (MSB) write precompensation cylinder */
uint8_t wp_low; /* (LSB) write precompensation cylinder */
uint8_t maxecc; /* max ECC data burst length */
} dprm_t;
#pragma pack(pop)
/* Define an attached drive. */
typedef struct {
2022-09-18 17:13:50 -04:00
int8_t id, /* drive ID on bus */
present, /* drive is present */
hdd_num, /* index to global disk table */
type; /* drive type ID */
2022-09-18 17:13:50 -04:00
uint16_t cur_cyl; /* last known position of heads */
2022-09-18 17:13:50 -04:00
uint8_t spt, /* active drive parameters */
hpc;
uint16_t tracks;
2022-09-18 17:13:50 -04:00
uint8_t cfg_spt, /* configured drive parameters */
cfg_hpc;
uint16_t cfg_tracks;
} drive_t;
typedef struct {
2022-09-18 17:13:50 -04:00
const char *name; /* controller name */
2022-09-18 17:13:50 -04:00
uint16_t base; /* controller base I/O address */
int8_t irq; /* controller IRQ channel */
int8_t dma; /* controller DMA channel */
int8_t type; /* controller type ID */
2022-09-18 17:13:50 -04:00
uint32_t rom_addr; /* address where ROM is */
rom_t bios_rom; /* descriptor for the BIOS */
/* Controller state. */
2022-09-18 17:13:50 -04:00
int8_t state; /* controller state */
uint8_t sense; /* current SENSE ERROR value */
uint8_t status; /* current operational status */
2022-09-18 17:13:50 -04:00
uint8_t intr;
uint64_t callback;
pc_timer_t timer;
/* Data transfer. */
2022-09-18 17:13:50 -04:00
int16_t buf_idx, /* buffer index and pointer */
buf_len;
uint8_t *buf_ptr;
/* Current operation parameters. */
2022-09-18 17:13:50 -04:00
dcb_t dcb; /* device control block */
uint16_t track; /* requested track# */
uint8_t head, /* requested head# */
sector, /* requested sector# */
comp; /* operation completion byte */
int count; /* requested sector count */
2022-09-18 17:13:50 -04:00
drive_t drives[XTA_NUM]; /* the attached drive(s) */
2022-09-18 17:13:50 -04:00
uint8_t data[512]; /* data buffer */
uint8_t sector_buf[512]; /* sector buffer */
} hdc_t;
2018-04-26 02:53:18 +02:00
#ifdef ENABLE_XTA_LOG
int xta_do_log = ENABLE_XTA_LOG;
static void
xta_log(const char *fmt, ...)
{
va_list ap;
if (xta_do_log) {
2022-09-18 17:13:50 -04:00
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
2018-04-26 02:53:18 +02:00
}
}
#else
2022-09-18 17:13:50 -04:00
# define xta_log(fmt, ...)
#endif
2018-04-26 02:53:18 +02:00
static void
set_intr(hdc_t *dev)
{
2022-09-18 17:13:50 -04:00
dev->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY;
dev->state = STATE_COMPL;
if (dev->intr & IRQ_ENA) {
2022-09-18 17:13:50 -04:00
dev->status |= STAT_IRQ;
picint(1 << dev->irq);
}
}
/* Get the logical (block) address of a CHS triplet. */
static int
get_sector(hdc_t *dev, drive_t *drive, off64_t *addr)
{
if (drive->cur_cyl != dev->track) {
2022-09-18 17:13:50 -04:00
xta_log("%s: get_sector: wrong cylinder %d/%d\n",
dev->name, drive->cur_cyl, dev->track);
dev->sense = ERR_ILLADDR;
return (1);
}
if (dev->head >= drive->hpc) {
2022-09-18 17:13:50 -04:00
xta_log("%s: get_sector: past end of heads\n", dev->name);
dev->sense = ERR_ILLADDR;
return (1);
}
if (dev->sector >= drive->spt) {
2022-09-18 17:13:50 -04:00
xta_log("%s: get_sector: past end of sectors\n", dev->name);
dev->sense = ERR_ILLADDR;
return (1);
}
/* Calculate logical address (block number) of desired sector. */
2022-09-18 17:13:50 -04:00
*addr = ((((off64_t) dev->track * drive->hpc) + dev->head) * drive->spt) + dev->sector;
2022-09-18 17:13:50 -04:00
return (0);
}
static void
next_sector(hdc_t *dev, drive_t *drive)
{
if (++dev->sector >= drive->spt) {
2022-09-18 17:13:50 -04:00
dev->sector = 0;
if (++dev->head >= drive->hpc) {
dev->head = 0;
dev->track++;
if (++drive->cur_cyl >= drive->tracks)
drive->cur_cyl = (drive->tracks - 1);
}
}
}
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.
2019-09-20 14:02:30 +02:00
static void
xta_set_callback(hdc_t *dev, uint64_t callback)
{
if (!dev) {
2022-09-18 17:13:50 -04:00
return;
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.
2019-09-20 14:02:30 +02:00
}
if (callback) {
2022-09-18 17:13:50 -04:00
dev->callback = callback;
timer_set_delay_u64(&dev->timer, dev->callback);
} else {
dev->callback = 0;
timer_disable(&dev->timer);
}
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.
2019-09-20 14:02:30 +02:00
}
/* Perform the seek operation. */
static void
do_seek(hdc_t *dev, drive_t *drive, int cyl)
{
dev->track = cyl;
if (dev->track >= drive->tracks)
2022-09-18 17:13:50 -04:00
drive->cur_cyl = (drive->tracks - 1);
else
drive->cur_cyl = dev->track;
}
/* Format a track or an entire drive. */
static void
do_format(hdc_t *dev, drive_t *drive, dcb_t *dcb)
{
2022-09-18 17:13:50 -04:00
int start_cyl, end_cyl;
int start_hd, end_hd;
off64_t addr;
2022-09-18 17:13:50 -04:00
int h, s;
/* Get the parameters from the DCB. */
if (dcb->cmd == CMD_FORMAT_DRIVE) {
2022-09-18 17:13:50 -04:00
start_cyl = 0;
start_hd = 0;
end_cyl = drive->tracks;
end_hd = drive->hpc;
} else {
2022-09-18 17:13:50 -04:00
start_cyl = (dcb->cyl_low | (dcb->cyl_high << 8));
start_hd = dcb->head;
end_cyl = start_cyl + 1;
end_hd = start_hd + 1;
}
switch (dev->state) {
2022-09-18 17:13:50 -04:00
case STATE_IDLE:
/* Seek to cylinder. */
do_seek(dev, drive, start_cyl);
dev->head = dcb->head;
dev->sector = 0;
2022-09-18 17:13:50 -04:00
/* Activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1);
do_fmt:
2022-09-18 17:13:50 -04:00
/*
* For now, we don't use the interleave factor (in
* dcb->count), although we should one day use an
* image format that can handle it..
*
* That said, we have been given a sector_buf of
* data to fill the sectors with, so we will use
* that at least.
*/
for (h = start_hd; h < end_hd; h++) {
for (s = 0; s < drive->spt; s++) {
/* Set the sector we need to write. */
dev->head = h;
dev->sector = s;
/* Get address of sector to write. */
if (get_sector(dev, drive, &addr))
break;
/* Write the block to the image. */
hdd_image_write(drive->hdd_num, addr, 1,
(uint8_t *) dev->sector_buf);
}
}
/* One more track done. */
if (++start_cyl == end_cyl)
break;
/* This saves us a LOT of code. */
goto do_fmt;
}
/* De-activate the status icon. */
2022-09-18 17:13:50 -04:00
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0);
}
/* Execute the DCB we just received. */
static void
hdc_callback(void *priv)
{
2022-09-18 17:13:50 -04:00
hdc_t *dev = (hdc_t *) priv;
dcb_t *dcb = &dev->dcb;
drive_t *drive;
2022-09-18 17:13:50 -04:00
dprm_t *params;
off64_t addr;
int no_data = 0;
int val;
/* Cancel timer. */
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.
2019-09-20 14:02:30 +02:00
xta_set_callback(dev, 0);
2022-09-18 17:13:50 -04:00
drive = &dev->drives[dcb->drvsel];
dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00;
dev->status |= STAT_DCB;
switch (dcb->cmd) {
2022-09-18 17:13:50 -04:00
case CMD_TEST_READY:
if (!drive->present) {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
}
set_intr(dev);
break;
case CMD_RECALIBRATE:
if (!drive->present) {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
} else {
dev->track = drive->cur_cyl = 0;
}
set_intr(dev);
break;
case CMD_READ_SENSE:
switch (dev->state) {
case STATE_IDLE:
dev->buf_idx = 0;
dev->buf_len = 4;
dev->buf_ptr = dev->data;
dev->buf_ptr[0] = dev->sense;
dev->buf_ptr[1] = dcb->drvsel ? 0x20 : 0x00;
dev->buf_ptr[2] = (drive->cur_cyl >> 2) | (dev->sector & 0x3f);
dev->buf_ptr[3] = (drive->cur_cyl & 0xff);
dev->sense = ERR_NOERROR;
dev->status |= (STAT_IO | STAT_REQ);
dev->state = STATE_SDATA;
break;
case STATE_SDONE:
set_intr(dev);
}
break;
case CMD_READ_VERIFY:
no_data = 1;
/*FALLTHROUGH*/
case CMD_READ_SECTORS:
if (!drive->present) {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
set_intr(dev);
break;
}
switch (dev->state) {
case STATE_IDLE:
/* Seek to cylinder. */
do_seek(dev, drive,
(dcb->cyl_low | (dcb->cyl_high << 8)));
dev->head = dcb->head;
dev->sector = dcb->sector;
/* Get sector count; count=0 means 256. */
dev->count = (int) dcb->count;
if (dev->count == 0)
dev->count = 256;
dev->buf_len = 512;
dev->state = STATE_SEND;
/*FALLTHROUGH*/
case STATE_SEND:
/* Activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1);
do_send:
2022-09-18 17:13:50 -04:00
/* Get address of sector to load. */
if (get_sector(dev, drive, &addr)) {
/* De-activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0);
dev->comp |= COMP_ERR;
set_intr(dev);
return;
}
/* Read the block from the image. */
hdd_image_read(drive->hdd_num, addr, 1,
(uint8_t *) dev->sector_buf);
/* Ready to transfer the data out. */
dev->state = STATE_SDATA;
dev->buf_idx = 0;
if (no_data) {
/* Delay a bit, no actual transfer. */
xta_set_callback(dev, HDC_TIME);
} else {
if (dev->intr & DMA_ENA) {
/* DMA enabled. */
dev->buf_ptr = dev->sector_buf;
xta_set_callback(dev, HDC_TIME);
} else {
/* Copy from sector to data. */
memcpy(dev->data,
dev->sector_buf,
dev->buf_len);
dev->buf_ptr = dev->data;
dev->status |= (STAT_IO | STAT_REQ);
}
}
break;
case STATE_SDATA:
if (!no_data) {
/* Perform DMA. */
while (dev->buf_idx < dev->buf_len) {
val = dma_channel_write(dev->dma,
*dev->buf_ptr);
if (val == DMA_NODATA) {
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);
xta_set_callback(dev, HDC_TIME);
return;
}
dev->buf_ptr++;
dev->buf_idx++;
}
}
xta_set_callback(dev, HDC_TIME);
dev->state = STATE_SDONE;
break;
case STATE_SDONE:
dev->buf_idx = 0;
if (--dev->count == 0) {
/* De-activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0);
set_intr(dev);
return;
}
/* Addvance to next sector. */
next_sector(dev, drive);
/* This saves us a LOT of code. */
dev->state = STATE_SEND;
goto do_send;
}
break;
case CMD_WRITE_SECTORS:
if (!drive->present) {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
set_intr(dev);
break;
}
switch (dev->state) {
case STATE_IDLE:
/* Seek to cylinder. */
do_seek(dev, drive,
(dcb->cyl_low | (dcb->cyl_high << 8)));
dev->head = dcb->head;
dev->sector = dcb->sector;
/* Get sector count; count=0 means 256. */
dev->count = (int) dev->dcb.count;
if (dev->count == 0)
dev->count = 256;
dev->buf_len = 512;
dev->state = STATE_RECV;
/*FALLTHROUGH*/
case STATE_RECV:
/* Activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1);
do_recv:
2022-09-18 17:13:50 -04:00
/* Ready to transfer the data in. */
dev->state = STATE_RDATA;
dev->buf_idx = 0;
if (dev->intr & DMA_ENA) {
/* DMA enabled. */
dev->buf_ptr = dev->sector_buf;
xta_set_callback(dev, HDC_TIME);
} else {
/* No DMA, do PIO. */
dev->buf_ptr = dev->data;
dev->status |= STAT_REQ;
}
break;
case STATE_RDATA:
if (!no_data) {
/* Perform DMA. */
dev->status = STAT_BSY;
while (dev->buf_idx < dev->buf_len) {
val = dma_channel_read(dev->dma);
if (val == DMA_NODATA) {
xta_log("%s: CMD_WRITE_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len);
xta_log("%s: CMD_WRITE_SECTORS out of data!\n", dev->name);
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
xta_set_callback(dev, HDC_TIME);
return;
}
dev->buf_ptr[dev->buf_idx] = (val & 0xff);
dev->buf_idx++;
}
dev->state = STATE_RDONE;
xta_set_callback(dev, HDC_TIME);
}
break;
case STATE_RDONE:
/* Copy from data to sector if PIO. */
if (!(dev->intr & DMA_ENA))
memcpy(dev->sector_buf, dev->data,
dev->buf_len);
/* Get address of sector to write. */
if (get_sector(dev, drive, &addr)) {
/* De-activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0);
dev->comp |= COMP_ERR;
set_intr(dev);
return;
}
/* Write the block to the image. */
hdd_image_write(drive->hdd_num, addr, 1,
(uint8_t *) dev->sector_buf);
dev->buf_idx = 0;
if (--dev->count == 0) {
/* De-activate the status icon. */
ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0);
set_intr(dev);
return;
}
/* Advance to next sector. */
next_sector(dev, drive);
/* This saves us a LOT of code. */
dev->state = STATE_RECV;
goto do_recv;
}
break;
case CMD_FORMAT_DRIVE:
case CMD_FORMAT_TRACK:
if (drive->present) {
do_format(dev, drive, dcb);
} else {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
}
set_intr(dev);
break;
case CMD_SEEK:
/* Seek to cylinder. */
val = (dcb->cyl_low | (dcb->cyl_high << 8));
if (drive->present) {
do_seek(dev, drive, val);
if (val != drive->cur_cyl) {
dev->comp |= COMP_ERR;
dev->sense = ERR_SEEK;
}
} else {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
}
set_intr(dev);
break;
case CMD_SET_DRIVE_PARAMS:
switch (dev->state) {
case STATE_IDLE:
dev->state = STATE_RDATA;
dev->buf_idx = 0;
dev->buf_len = sizeof(dprm_t);
dev->buf_ptr = (uint8_t *) dev->data;
dev->status |= STAT_REQ;
break;
case STATE_RDONE:
params = (dprm_t *) dev->data;
drive->tracks = (params->cyl_high << 8) | params->cyl_low;
drive->hpc = params->heads;
drive->spt = 17 /*hardcoded*/;
dev->status &= ~STAT_REQ;
set_intr(dev);
break;
}
break;
case CMD_WRITE_SECTOR_BUFFER:
switch (dev->state) {
case STATE_IDLE:
dev->buf_idx = 0;
dev->buf_len = 512;
dev->state = STATE_RDATA;
if (dev->intr & DMA_ENA) {
dev->buf_ptr = dev->sector_buf;
xta_set_callback(dev, HDC_TIME);
} else {
dev->buf_ptr = dev->data;
dev->status |= STAT_REQ;
}
break;
case STATE_RDATA:
if (dev->intr & DMA_ENA) {
/* Perform DMA. */
while (dev->buf_idx < dev->buf_len) {
val = dma_channel_read(dev->dma);
if (val == DMA_NODATA) {
xta_log("%s: CMD_WRITE_BUFFER out of data!\n", dev->name);
dev->status |= (STAT_CD | STAT_IO | STAT_REQ);
xta_set_callback(dev, HDC_TIME);
return;
}
dev->buf_ptr[dev->buf_idx] = (val & 0xff);
dev->buf_idx++;
}
dev->state = STATE_RDONE;
xta_set_callback(dev, HDC_TIME);
}
break;
case STATE_RDONE:
if (!(dev->intr & DMA_ENA))
memcpy(dev->sector_buf,
dev->data, dev->buf_len);
set_intr(dev);
break;
}
break;
case CMD_RAM_DIAGS:
switch (dev->state) {
case STATE_IDLE:
dev->state = STATE_RDONE;
xta_set_callback(dev, 5 * HDC_TIME);
break;
case STATE_RDONE:
set_intr(dev);
break;
}
break;
case CMD_DRIVE_DIAGS:
switch (dev->state) {
case STATE_IDLE:
if (drive->present) {
dev->state = STATE_RDONE;
xta_set_callback(dev, 5 * HDC_TIME);
} else {
dev->comp |= COMP_ERR;
dev->sense = ERR_NOTRDY;
set_intr(dev);
}
break;
case STATE_RDONE:
set_intr(dev);
break;
}
break;
case CMD_CTRL_DIAGS:
switch (dev->state) {
case STATE_IDLE:
dev->state = STATE_RDONE;
xta_set_callback(dev, 10 * HDC_TIME);
break;
case STATE_RDONE:
set_intr(dev);
break;
}
break;
default:
xta_log("%s: unknown command - %02x\n", dev->name, dcb->cmd);
dev->comp |= COMP_ERR;
dev->sense = ERR_ILLCMD;
set_intr(dev);
}
}
/* Read one of the controller registers. */
static uint8_t
hdc_read(uint16_t port, void *priv)
{
2022-09-18 17:13:50 -04:00
hdc_t *dev = (hdc_t *) priv;
uint8_t ret = 0xff;
2022-02-20 02:26:27 -05:00
switch (port & 7) {
2022-09-18 17:13:50 -04:00
case 0: /* DATA register */
dev->status &= ~STAT_IRQ;
if (dev->state == STATE_SDATA) {
if (dev->buf_idx > dev->buf_len) {
xta_log("%s: read with empty buffer!\n",
dev->name);
dev->comp |= COMP_ERR;
dev->sense = ERR_ILLCMD;
break;
}
ret = dev->buf_ptr[dev->buf_idx];
if (++dev->buf_idx == dev->buf_len) {
/* All data sent. */
dev->status &= ~STAT_REQ;
dev->state = STATE_SDONE;
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);
ret = dev->comp;
dev->status = 0x00;
dev->state = STATE_IDLE;
}
break;
case 1: /* STATUS register */
ret = (dev->status & ~STAT_DCB);
break;
case 2: /* "read option jumpers" */
ret = 0xff; /* all switches off */
break;
}
2022-09-18 17:13:50 -04:00
return (ret);
}
/* Write to one of the controller registers. */
static void
hdc_write(uint16_t port, uint8_t val, void *priv)
{
2022-09-18 17:13:50 -04:00
hdc_t *dev = (hdc_t *) priv;
switch (port & 7) {
2022-09-18 17:13:50 -04:00
case 0: /* DATA register */
if (dev->state == STATE_RDATA) {
if (!(dev->status & STAT_REQ)) {
xta_log("%s: not ready for command/data!\n", dev->name);
dev->comp |= COMP_ERR;
dev->sense = ERR_ILLCMD;
break;
}
if (dev->buf_idx >= dev->buf_len) {
xta_log("%s: write with full buffer!\n", dev->name);
dev->comp |= COMP_ERR;
dev->sense = ERR_ILLCMD;
break;
}
/* Store the data into the buffer. */
dev->buf_ptr[dev->buf_idx] = val;
if (++dev->buf_idx == dev->buf_len) {
/* We got all the data we need. */
dev->status &= ~STAT_REQ;
if (dev->status & STAT_DCB)
dev->state = STATE_RDONE;
else
dev->state = STATE_IDLE;
dev->status &= ~STAT_CD;
xta_set_callback(dev, HDC_TIME);
}
}
break;
case 1: /* RESET register */
dev->sense = 0x00;
dev->state = STATE_IDLE;
break;
case 2: /* "controller-select" */
/* Reset the DCB buffer. */
dev->buf_idx = 0;
dev->buf_len = sizeof(dcb_t);
dev->buf_ptr = (uint8_t *) &dev->dcb;
dev->state = STATE_RDATA;
dev->status = (STAT_BSY | STAT_CD | STAT_REQ);
break;
case 3: /* DMA/IRQ intr register */
// xta_log("%s: WriteMASK(%02X)\n", dev->name, val);
dev->intr = val;
break;
}
}
static void *
xta_init(const device_t *info)
{
drive_t *drive;
char *bios_rev = NULL;
2022-09-18 17:13:50 -04:00
char *fn = NULL;
hdc_t *dev;
int c, i;
int max = XTA_NUM;
/* Allocate and initialize device block. */
dev = malloc(sizeof(hdc_t));
memset(dev, 0x00, sizeof(hdc_t));
dev->type = info->local;
/* Do per-controller-type setup. */
2022-09-18 17:13:50 -04:00
switch (dev->type) {
case 0: /* WDXT-150, with BIOS */
dev->name = "WDXT-150";
dev->base = device_get_config_hex16("base");
dev->irq = device_get_config_int("irq");
dev->rom_addr = device_get_config_hex20("bios_addr");
dev->dma = 3;
bios_rev = (char *) device_get_config_bios("bios_rev");
fn = (char *) device_get_bios_file(info, (const char *) bios_rev, 0);
2022-09-18 17:13:50 -04:00
max = 1;
break;
case 1: /* EuroPC */
dev->name = "HD20";
dev->base = 0x0320;
dev->irq = 5;
dev->dma = 3;
break;
}
2018-04-26 02:53:18 +02:00
xta_log("%s: initializing (I/O=%04X, IRQ=%d, DMA=%d",
2022-09-18 17:13:50 -04:00
dev->name, dev->base, dev->irq, dev->dma);
if (dev->rom_addr != 0x000000)
2022-09-18 17:13:50 -04:00
xta_log(", BIOS=%06X", dev->rom_addr);
2018-04-26 02:53:18 +02:00
xta_log(")\n");
/* Load any disks for this device class. */
c = 0;
for (i = 0; i < HDD_NUM; i++) {
2022-09-18 17:13:50 -04:00
if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].xta_channel < max)) {
drive = &dev->drives[hdd[i].xta_channel];
if (!hdd_image_load(i)) {
drive->present = 0;
continue;
}
drive->id = c;
drive->hdd_num = i;
drive->present = 1;
/* These are the "hardware" parameters (from the image.) */
drive->cfg_spt = (uint8_t) (hdd[i].spt & 0xff);
drive->cfg_hpc = (uint8_t) (hdd[i].hpc & 0xff);
drive->cfg_tracks = (uint16_t) hdd[i].tracks;
/* Use them as "configured" parameters until overwritten. */
drive->spt = drive->cfg_spt;
drive->hpc = drive->cfg_hpc;
drive->tracks = drive->cfg_tracks;
xta_log("%s: drive%d (cyl=%d,hd=%d,spt=%d), disk %d\n",
dev->name, hdd[i].xta_channel, drive->tracks,
drive->hpc, drive->spt, i);
if (++c > max)
break;
}
}
/* Enable the I/O block. */
io_sethandler(dev->base, 4,
2022-09-18 17:13:50 -04:00
hdc_read, NULL, NULL, hdc_write, NULL, NULL, dev);
/* Load BIOS if it has one. */
2021-04-29 22:02:16 +02:00
if (dev->rom_addr != 0x000000) {
2022-09-18 17:13:50 -04:00
rom_init(&dev->bios_rom, fn,
dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
}
2022-02-20 02:26:27 -05:00
/* Create a timer for command delays. */
2021-04-29 22:02:16 +02:00
timer_add(&dev->timer, hdc_callback, dev, 0);
2022-09-18 17:13:50 -04:00
return (dev);
}
static void
xta_close(void *priv)
{
2022-09-18 17:13:50 -04:00
hdc_t *dev = (hdc_t *) priv;
drive_t *drive;
2022-09-18 17:13:50 -04:00
int d;
/* Remove the I/O handler. */
io_removehandler(dev->base, 4,
2022-09-18 17:13:50 -04:00
hdc_read, NULL, NULL, hdc_write, NULL, NULL, dev);
/* Close all disks and their images. */
for (d = 0; d < XTA_NUM; d++) {
2022-09-18 17:13:50 -04:00
drive = &dev->drives[d];
2022-09-18 17:13:50 -04:00
hdd_image_close(drive->hdd_num);
}
/* Release the device. */
free(dev);
}
static const device_config_t wdxt150_config[] = {
2022-09-18 17:13:50 -04:00
// clang-format off
2022-02-26 23:31:28 -05:00
{
2022-04-02 17:08:04 -04:00
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0320,
.file_filter = "",
.spinner = { 0 }, /*W2*/
.selection = {
{ .description = "320H", .value = 0x0320 },
{ .description = "324H", .value = 0x0324 },
{ .description = "" }
},
2022-02-26 23:31:28 -05:00
},
{
2022-04-02 17:08:04 -04:00
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 5,
.file_filter = "",
.spinner = { 0 }, /*W3*/
.selection = {
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 4", .value = 4 },
{ .description = "" }
},
2022-02-26 23:31:28 -05:00
},
{
2022-04-02 17:08:04 -04:00
.name = "bios_addr",
.description = "BIOS Address",
.type = CONFIG_HEX20,
.default_string = "",
.default_int = 0xc8000,
.file_filter = "",
.spinner = { 0 }, /*W1*/
.selection = {
{ .description = "C800H", .value = 0xc8000 },
{ .description = "CA00H", .value = 0xca000 },
{ .description = "" }
},
2022-02-26 23:31:28 -05:00
},
{
.name = "bios_rev",
.description = "BIOS Revision",
.type = CONFIG_BIOS,
.default_string = "rev_1",
.default_int = 0,
.file_filter = "",
.spinner = { 0 }, /*W1*/
.bios = {
{ .name = "Revision 1.0", .internal_name = "rev_1", .bios_type = BIOS_NORMAL,
.files_no = 1, .local = 0, .size = 8192, .files = { WD_REV_1_BIOS_FILE, "" } },
{ .name = "Revision 2.0", .internal_name = "rev_2", .bios_type = BIOS_NORMAL,
.files_no = 1, .local = 0, .size = 8192, .files = { WD_REV_2_BIOS_FILE, "" } },
{ .files_no = 0 }
},
},
2022-04-02 17:08:04 -04:00
{ .name = "", .description = "", .type = CONFIG_END }
2022-02-26 23:31:28 -05:00
// clang-format off
};
const device_t xta_wdxt150_device = {
2022-03-13 09:37:19 -04:00
.name = "WDXT-150 XTA Fixed Disk Controller",
.internal_name = "xta_wdxt150",
.flags = DEVICE_ISA,
.local = 0,
.init = xta_init,
.close = xta_close,
.reset = NULL,
{ .available = NULL /*xta_available*/ },
2022-03-13 09:37:19 -04:00
.speed_changed = NULL,
.force_redraw = NULL,
.config = wdxt150_config
};
const device_t xta_hd20_device = {
2022-03-13 09:37:19 -04:00
.name = "EuroPC HD20 Fixed Disk Controller",
.internal_name = "xta_hd20",
.flags = DEVICE_ISA,
.local = 1,
.init = xta_init,
.close = xta_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};