diff options
Diffstat (limited to 'src/devices/bus/isa/hdc.c')
-rw-r--r-- | src/devices/bus/isa/hdc.c | 1050 |
1 files changed, 1050 insertions, 0 deletions
diff --git a/src/devices/bus/isa/hdc.c b/src/devices/bus/isa/hdc.c new file mode 100644 index 00000000000..45b6bc334dd --- /dev/null +++ b/src/devices/bus/isa/hdc.c @@ -0,0 +1,1050 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + ISA 8 bit XT Hard Disk Controller + +**********************************************************************/ + +#include "emu.h" +#include "hdc.h" + +#define LOG_HDC_STATUS 0 +#define LOG_HDC_CALL 0 +#define LOG_HDC_DATA 0 + +#define CMD_TESTREADY 0x00 +#define CMD_RECALIBRATE 0x01 +#define CMD_SENSE 0x03 +#define CMD_FORMATDRV 0x04 +#define CMD_VERIFY 0x05 +#define CMD_FORMATTRK 0x06 +#define CMD_FORMATBAD 0x07 +#define CMD_READ 0x08 +#define CMD_WRITE 0x0a +#define CMD_SEEK 0x0b + +#define CMD_SETPARAM 0x0c +#define CMD_GETECC 0x0d + +#define CMD_READSBUFF 0x0e +#define CMD_WRITESBUFF 0x0f + +#define CMD_RAMDIAG 0xe0 +#define CMD_DRIVEDIAG 0xe3 +#define CMD_INTERNDIAG 0xe4 +#define CMD_READLONG 0xe5 +#define CMD_WRITELONG 0xe6 + +/* Bits for command status byte */ +#define CSB_ERROR 0x02 +#define CSB_LUN 0x20 + +/* XT hard disk controller status bits */ +#define STA_READY 0x01 +#define STA_INPUT 0x02 +#define STA_COMMAND 0x04 +#define STA_SELECT 0x08 +#define STA_REQUEST 0x10 +#define STA_INTERRUPT 0x20 + +/* XT hard disk controller control bits */ +#define CTL_PIO 0x00 +#define CTL_DMA 0x01 + +static const char *const hdc_command_names[] = +{ + "CMD_TESTREADY", /* 0x00 */ + "CMD_RECALIBRATE", /* 0x01 */ + NULL, /* 0x02 */ + "CMD_SENSE", /* 0x03 */ + "CMD_FORMATDRV", /* 0x04 */ + "CMD_VERIFY", /* 0x05 */ + "CMD_FORMATTRK", /* 0x06 */ + "CMD_FORMATBAD", /* 0x07 */ + "CMD_READ", /* 0x08 */ + NULL, /* 0x09 */ + "CMD_WRITE", /* 0x0A */ + "CMD_SEEK", /* 0x0B */ + "CMD_SETPARAM", /* 0x0C */ + "CMD_GETECC", /* 0x0D */ + "CMD_READSBUFF", /* 0x0E */ + "CMD_WRITESBUFF", /* 0x0F */ + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x10-0x17 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x18-0x1F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x20-0x27 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x28-0x2F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x30-0x37 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x38-0x3F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x40-0x47 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x48-0x4F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x50-0x57 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x58-0x5F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x60-0x67 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x68-0x6F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x70-0x77 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x78-0x7F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x80-0x87 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x88-0x8F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x90-0x97 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x98-0x9F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xA0-0xA7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xA8-0xAF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xB0-0xB7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xB8-0xBF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xC0-0xC7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xC8-0xCF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xD0-0xD7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xD8-0xDF */ + + "CMD_RAMDIAG", /* 0xE0 */ + NULL, /* 0xE1 */ + NULL, /* 0xE2 */ + "CMD_DRIVEDIAG", /* 0xE3 */ + "CMD_INTERNDIAG", /* 0xE4 */ + "CMD_READLONG", /* 0xE5 */ + "CMD_WRITELONG", /* 0xE6 */ + NULL, /* 0xE7 */ + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xE8-0xEF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xF0-0xF7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* 0xF8-0xFF */ +}; + +static MACHINE_CONFIG_FRAGMENT( xt_hdc_config ) + MCFG_DEVICE_ADD("hdc",XT_HDC,0) + MCFG_XTHDC_IRQ_HANDLER(WRITELINE(isa8_hdc_device,irq_w)) + MCFG_XTHDC_DRQ_HANDLER(WRITELINE(isa8_hdc_device,drq_w)) + MCFG_HARDDISK_ADD("hdc:primary") + MCFG_HARDDISK_ADD("hdc:slave") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( ec1841_hdc_config ) + MCFG_DEVICE_ADD("hdc",EC1841_HDC,0) + MCFG_XTHDC_IRQ_HANDLER(WRITELINE(isa8_hdc_ec1841_device,irq_w)) + MCFG_XTHDC_DRQ_HANDLER(WRITELINE(isa8_hdc_ec1841_device,drq_w)) + MCFG_HARDDISK_ADD("hdc:primary") + MCFG_HARDDISK_ADD("hdc:slave") +MACHINE_CONFIG_END + +ROM_START( hdc ) + ROM_REGION(0x02000,"hdc", 0) + // Bios taken from WD1002A-WX1 + ROM_LOAD("wdbios.rom", 0x00000, 0x02000, CRC(8e9e2bd4) SHA1(601d7ceab282394ebab50763c267e915a6a2166a)) /* WDC IDE Superbios 2.0 (06/28/89) Expansion Rom C8000-C9FFF */ +ROM_END + +static INPUT_PORTS_START( isa_hdc ) + PORT_START("HDD") + PORT_BIT( 0xb0, 0xb0, IPT_UNUSED ) + PORT_DIPNAME( 0x40, 0x40, "IRQ level") + PORT_DIPSETTING( 0x40, "5" ) + PORT_DIPSETTING( 0x00, "2" ) + PORT_DIPNAME( 0x0c, 0x0c, "Type of 1st drive") + PORT_DIPSETTING( 0x0c, "0" ) + PORT_DIPSETTING( 0x08, "1" ) + PORT_DIPSETTING( 0x04, "2" ) + PORT_DIPSETTING( 0x00, "3" ) + PORT_DIPNAME( 0x03, 0x03, "Type of 2nd drive") + PORT_DIPSETTING( 0x03, "0" ) + PORT_DIPSETTING( 0x02, "1" ) + PORT_DIPSETTING( 0x01, "2" ) + PORT_DIPSETTING( 0x00, "3" ) + + PORT_START("ROM") + PORT_DIPNAME( 0x01, 0x01, "Install ROM?") + PORT_DIPSETTING( 0x01, DEF_STR(Yes) ) + PORT_DIPSETTING( 0x00, DEF_STR(No) ) +INPUT_PORTS_END + +const device_type XT_HDC = &device_creator<xt_hdc_device>; +const device_type EC1841_HDC = &device_creator<ec1841_device>; +const device_type ST11M_HDC = &device_creator<st11m_device>; + +xt_hdc_device::xt_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, XT_HDC, "Generic PC-XT Fixed Disk Controller", tag, owner, clock, "xt_hdc", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ + m_type = STANDARD; +} + +xt_hdc_device::xt_hdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_irq_handler(*this), + m_drq_handler(*this) +{ +} + +ec1841_device::ec1841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + xt_hdc_device(mconfig, EC1841_HDC, "EC1841 Fixed Disk Controller", tag, owner, clock, "ec1481", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ + m_type = EC1841; +} + +st11m_device::st11m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + xt_hdc_device(mconfig, EC1841_HDC, "Seagate ST11M Fixed Disk Controller", tag, owner, clock, "st11m", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ + m_type = ST11M; +} + +void xt_hdc_device::device_start() +{ + buffer.resize(256*512); // maximum possible transfer + timer = timer_alloc(); + m_irq_handler.resolve_safe(); + m_drq_handler.resolve_safe(); +} + +void xt_hdc_device::device_reset() +{ + drv = 0; + data_cnt = 0; + buffer_ptr = NULL; + hdc_control = 0; + for (int i = 0; i < 2; i++) + { + cylinders[i] = 612; + rwc[i] = 613; + wp[i] = 613; + heads[i] = 4; + ecc[i] = 11; + + /* indexes */ + cylinder[i] = 0; + head[i] = 0; + sector[i] = 0; + sector_cnt[i] = 0; + control[i] = 0; + } + + csb = 0; + status = 0; + error = 0; +} + +hard_disk_file *xt_hdc_device::pc_hdc_file(int id) +{ + harddisk_image_device *img = NULL; + switch( id ) + { + case 0: + img = dynamic_cast<harddisk_image_device *>(machine().device(subtag("primary").c_str())); + break; + case 1: + img = dynamic_cast<harddisk_image_device *>(machine().device(subtag("slave").c_str())); + break; + } + if ( img == NULL ) + return NULL; + + if (!img->exists()) + return NULL; + + return img->get_hard_disk_file(); +} + +void xt_hdc_device::pc_hdc_result(int set_error_info) +{ + if ( ( hdc_control & 0x02 )) + { + // dip switch selected IRQ 5 or 2 + m_irq_handler(1); + } + + if (LOG_HDC_STATUS) + logerror("pc_hdc_result(): $%02x to $%04x\n", csb, data_cnt); + + buffer[data_cnt++] = csb; + + if (set_error_info && ( csb & CSB_ERROR ) ) + { + buffer[data_cnt++] = error; + if (error & 0x80) + { + buffer[data_cnt++] = (drv << 5) | head[drv]; + buffer[data_cnt++] = ((cylinder[drv] >> 2) & 0xc0) | sector[drv]; + buffer[data_cnt++] = cylinder[drv] & 0xff; + + if (LOG_HDC_STATUS) + { + logerror("pc_hdc_result(): result [%02x %02x %02x %02x]\n", + buffer[data_cnt-4], buffer[data_cnt-3], buffer[data_cnt-2], buffer[data_cnt-1]); + } + } + else + { + if (LOG_HDC_STATUS) + logerror("pc_hdc_result(): result [%02x]\n", buffer[data_cnt-1]); + } + } + status |= STA_INTERRUPT | STA_INPUT | STA_REQUEST | STA_COMMAND | STA_READY; +} + + + +int xt_hdc_device::no_dma(void) +{ + return (hdc_control & CTL_DMA) == 0; +} + + + +int xt_hdc_device::get_lbasector() +{ + hard_disk_info *info; + hard_disk_file *file; + int lbasector; + + file = pc_hdc_file(drv); + info = hard_disk_get_info(file); + + lbasector = cylinder[drv]; + lbasector *= info->heads; + lbasector += head[drv]; + lbasector *= info->sectors; + lbasector += sector[drv]; + return lbasector; +} + +/******************************************************************** + * + * Read a number of sectors to the address set up for DMA chan #3 + * + ********************************************************************/ + +/* the following crap is an abomination; it is a relic of the old crappy DMA + * implementation that threw the idea of "emulating the hardware" to the wind + */ + +int xt_hdc_device::dack_r() +{ + UINT8 result; + hard_disk_info *info; + hard_disk_file *file; + + file = pc_hdc_file(drv); + if (!file) + return 0; + info = hard_disk_get_info(file); + + if (hdcdma_read == 0) + { + hard_disk_read(file, get_lbasector(), hdcdma_data); + hdcdma_read = 512; + hdcdma_size -= 512; + hdcdma_src = hdcdma_data; + sector[drv]++; + } + + result = *(hdcdma_src++); + + if( --hdcdma_read == 0 ) + { + /* end of cylinder ? */ + if (sector[drv] >= info->sectors) + { + sector[drv] = 0; + if (++head[drv] >= info->heads) /* beyond heads? */ + { + head[drv] = 0; /* reset head */ + cylinder[drv]++; /* next cylinder */ + } + } + } + + if (!no_dma()) + { + m_drq_handler((hdcdma_read || hdcdma_size ) ? 1 : 0); + if(!(hdcdma_read || hdcdma_size)) pc_hdc_result(0); + } + + return result; +} + + + +void xt_hdc_device::dack_w(int data) +{ + hard_disk_info *info; + hard_disk_file *file; + + file = pc_hdc_file(drv); + if (!file) + return; + info = hard_disk_get_info(file); + + *(hdcdma_dst++) = data; + + if( --hdcdma_write == 0 ) + { + hard_disk_write(file, get_lbasector(), hdcdma_data); + hdcdma_write = 512; + hdcdma_size -= 512; + + /* end of cylinder ? */ + if( ++sector[drv] >= info->sectors ) + { + sector[drv] = 0; + if (++head[drv] >= info->heads) /* beyond heads? */ + { + head[drv] = 0; /* reset head */ + cylinder[drv]++; /* next cylinder */ + } + } + hdcdma_dst = hdcdma_data; + } + + if (!no_dma()) + { + m_drq_handler(hdcdma_size ? 1 : 0); + if(!hdcdma_size) pc_hdc_result(1); + } +} + + + +void xt_hdc_device::dack_ws(int data) +{ + *(hdcdma_dst++) = data; + + if( --hdcdma_write == 0 ) + { + hdcdma_write = 512; + hdcdma_size -= 512; + hdcdma_dst = hdcdma_data; + } + + if (!no_dma()) + { + m_drq_handler(hdcdma_size ? 1 : 0); + if(!hdcdma_size) pc_hdc_result(1); + } +} + + + +void xt_hdc_device::execute_read() +{ + hard_disk_file *disk = NULL; + int size = sector_cnt[drv] * 512; + int read_ = 0; + + if(sector_cnt[drv] == 0) + size = 256 * 512; + + disk = pc_hdc_file(drv); + if (!disk) + return; + + status |= STA_READY; // ready to recieve data + status &= ~STA_INPUT; + status &= ~STA_COMMAND; + + hdcdma_src = hdcdma_data; + hdcdma_read = read_; + hdcdma_size = size; + + if(!no_dma()) + { + m_drq_handler(1); + if(!hdcdma_size) pc_hdc_result(0); + } +} + + + +void xt_hdc_device::execute_write() +{ + hard_disk_file *disk = NULL; + int size = sector_cnt[drv] * 512; + int write_ = 512; + + if(sector_cnt[drv] == 0) + size = 256 * 512; + + disk = pc_hdc_file(drv); + if (!disk) + return; + + status |= STA_READY; // ready to recieve data + status |= STA_INPUT; + status &= ~STA_COMMAND; + + hdcdma_dst = hdcdma_data; + hdcdma_write = write_; + hdcdma_size = size; + + if (!no_dma()) + { + m_drq_handler(1); + } +} + + + +void xt_hdc_device::execute_writesbuff() +{ + hdcdma_dst = hdcdma_data; + hdcdma_write = 512; + hdcdma_size = 512; + + status |= STA_READY; // ready to recieve data + status |= STA_INPUT; + status &= ~STA_COMMAND; + + if (!no_dma()) + { + m_drq_handler(1); + } +} + + + +void xt_hdc_device::get_drive() +{ + drv = (buffer[1] >> 5) & 1; + csb = (drv) ? CSB_LUN : 0x00; +} + + + +void xt_hdc_device::get_chsn() +{ + head[drv] = buffer[1] & 0x1f; + sector[drv] = buffer[2] & 0x3f; + cylinder[drv] = (buffer[2] & 0xc0) << 2; + cylinder[drv] |= buffer[3]; + sector_cnt[drv] = buffer[4]; + control[drv] = buffer[5]; /* 7: no retry, 6: no ecc retry, 210: step rate */ + + error = 0x80; /* a potential error has C/H/S/N info */ +} + +int xt_hdc_device::test_ready() +{ + if( !pc_hdc_file(drv) ) + { + csb |= CSB_ERROR; + error |= 0x04; /* drive not ready */ + return 0; + } + return 1; +} + +void xt_hdc_device::command() +{ + int set_error_info = 1; + int old_error = error; /* Previous error data is needed for CMD_SENSE */ + const char *command_name; + + csb = 0x00; + error = 0; + + buffer_ptr = &buffer[0]; + + get_drive(); + data_cnt = 0; + + if (LOG_HDC_STATUS) + { + command_name = hdc_command_names[m_current_cmd] ? hdc_command_names[m_current_cmd] : "Unknown"; + logerror("%s pc_hdc_command(): Executing command; cmd=0x%02x (%s) drv=%d\n", + machine().describe_context(), m_current_cmd, command_name, drv); + } + + switch (m_current_cmd) + { + case CMD_TESTREADY: + set_error_info = 0; + test_ready(); + if(no_dma()) pc_hdc_result(set_error_info); + break; + case CMD_SENSE: + /* Perform error code translation. This may need to be expanded in the future. */ + buffer[data_cnt++] = ( old_error & 0xC0 ) | ( ( old_error & 0x04 ) ? 0x04 : 0x00 ) ; + buffer[data_cnt++] = (drv << 5) | head[drv]; + buffer[data_cnt++] = ((cylinder[drv] >> 2) & 0xc0) | sector[drv]; + buffer[data_cnt++] = cylinder[drv] & 0xff; + set_error_info = 0; + if(no_dma()) pc_hdc_result(set_error_info); + break; + case CMD_RECALIBRATE: + get_chsn(); + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_FORMATDRV: + case CMD_VERIFY: + case CMD_FORMATTRK: + case CMD_FORMATBAD: + case CMD_SEEK: + case CMD_DRIVEDIAG: + get_chsn(); + test_ready(); + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_READ: + case CMD_READLONG: + get_chsn(); + + if (LOG_HDC_STATUS) + { + logerror("%s hdc read D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n", + machine().describe_context(), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]); + } + + if (test_ready()) + execute_read(); + else + pc_hdc_result(1); + set_error_info = 0; + break; + + case CMD_WRITE: + case CMD_WRITELONG: + get_chsn(); + + if (LOG_HDC_STATUS) + { + logerror("%s hdc write D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n", + machine().describe_context(), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]); + } + + if (test_ready()) + execute_write(); + break; + + case CMD_WRITESBUFF: + if (LOG_HDC_STATUS) + { + logerror("%s hdc write sector buffer\n", machine().describe_context()); + } + + execute_writesbuff(); + break; + + case CMD_SETPARAM: + get_chsn(); + cylinders[drv] = ((buffer[6]&3)<<8) | buffer[7]; + heads[drv] = buffer[8] & 0x1f; + rwc[drv] = ((buffer[9]&3)<<8) | buffer[10]; + wp[drv] = ((buffer[11]&3)<<8) | buffer[12]; + ecc[drv] = buffer[13]; + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_GETECC: + buffer[data_cnt++] = ecc[drv]; + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_READSBUFF: + case CMD_RAMDIAG: + case CMD_INTERNDIAG: + if(no_dma()) pc_hdc_result(set_error_info); + break; + } +} + +void xt_hdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + command(); +} + + +/* Command format + * Bits Description + * 7 0 + * xxxxxxxx command + * dddhhhhh drive / head + * ccssssss cylinder h / sector + * cccccccc cylinder l + * nnnnnnnn count + * xxxxxxxx control + * + * Command format extra for set drive characteristics + * 000000cc cylinders h + * cccccccc cylinders l + * 000hhhhh heads + * 000000cc reduced write h + * cccccccc reduced write l + * 000000cc write precomp h + * cccccccc write precomp l + * eeeeeeee ecc + */ +void xt_hdc_device::data_w(int data) +{ + if(!(status & STA_COMMAND) && m_current_cmd != CMD_SETPARAM) + { + if (LOG_HDC_DATA) + logerror("hdc_data_w PIO $%02x (%i) (%s): \n", data,data_cnt,hdc_command_names[m_current_cmd] ? hdc_command_names[m_current_cmd] : "Unknown"); + // PIO data transfer + buffer[data_cnt++] = data; + if(data_cnt >= hdcdma_size) + { + data_cnt = 0; + // write to disk + do + { + if(m_current_cmd == CMD_WRITESBUFF) + dack_ws(buffer[data_cnt++]); + else + dack_w(buffer[data_cnt++]); + } + while (hdcdma_size); + data_cnt = 0; + pc_hdc_result(1); + } + return; + } + + if( data_cnt == 0 ) + { + buffer_ptr = &buffer[0]; + m_current_cmd = data; + data_cnt = 6; /* expect 6 bytes including this one */ + status &= ~STA_READY; + status &= ~STA_INPUT; + switch (data) + { + case CMD_SETPARAM: + data_cnt += 8; + break; + + case CMD_TESTREADY: + case CMD_RECALIBRATE: + case CMD_SENSE: + case CMD_FORMATDRV: + case CMD_VERIFY: + case CMD_FORMATTRK: + case CMD_FORMATBAD: + case CMD_READ: + case CMD_WRITE: + case CMD_SEEK: + case CMD_GETECC: + case CMD_READSBUFF: + case CMD_WRITESBUFF: + case CMD_RAMDIAG: + case CMD_DRIVEDIAG: + case CMD_INTERNDIAG: + case CMD_READLONG: + case CMD_WRITELONG: + break; + + default: + data_cnt = 0; + status |= STA_INPUT; + csb |= CSB_ERROR | 0x20; /* unknown command */ + pc_hdc_result(1); + break; + } + if( data_cnt ) + status |= STA_REQUEST; + } + + if (data_cnt) + { + if (LOG_HDC_DATA) + logerror("hdc_data_w $%02x (%i) (%s): \n", data,data_cnt,hdc_command_names[m_current_cmd] ? hdc_command_names[m_current_cmd] : "Unknown"); + + *buffer_ptr++ = data; + // XXX ec1841 wants this + if (m_current_cmd == CMD_SETPARAM && data_cnt == 9 && (m_type == EC1841)) { + status &= ~STA_READY; + } else { + status |= STA_READY; + if(m_current_cmd == CMD_SETPARAM && data_cnt == 9) // some controllers want geometry info as data, not as a command (true for the Seagate ST11M?) + status &= ~STA_COMMAND; + } + if (--data_cnt == 0) + { + if (LOG_HDC_STATUS) + logerror("%s pc_hdc_data_w(): Launching command\n", machine().describe_context()); + + status &= ~STA_COMMAND; + status &= ~STA_REQUEST; + status &= ~STA_READY; + status &= ~STA_INPUT; + timer->adjust(attotime::from_msec(1),0); + } + } +} + + + +void xt_hdc_device::reset_w(int data) +{ + cylinder[0] = cylinder[1] = 0; + head[0] = head[1] = 0; + sector[0] = sector[1] = 0; + csb = 0; + status = STA_COMMAND | STA_READY; + memset(&buffer[0], 0, buffer.size()); + buffer_ptr = &buffer[0]; + data_cnt = 0; +} + + + +void xt_hdc_device::select_w(int data) +{ + status &= ~STA_INTERRUPT; + status |= STA_SELECT; +} + + + +void xt_hdc_device::control_w(int data) +{ + if (LOG_HDC_STATUS) + logerror("%s: pc_hdc_control_w(): control write %d\n", machine().describe_context(), data); + + hdc_control = data; + + if (!(hdc_control & 0x02)) + { + m_irq_handler(0); + } +} + + + +UINT8 xt_hdc_device::data_r() +{ + UINT8 data = 0xff; + + if(!(status & STA_COMMAND) && (m_current_cmd == CMD_READ || m_current_cmd == CMD_READLONG || m_current_cmd == CMD_READSBUFF)) + { + // PIO data transfer + if(data_cnt == 0) + { + do + { + buffer[data_cnt++] = dack_r(); + } while (hdcdma_read); + data_cnt = 0; + } + data = buffer[data_cnt++]; + if(data_cnt >= ((sector_cnt[drv] * 512) ? (sector_cnt[drv] * 512) : (256 * 512))) + { + data_cnt = 0; + pc_hdc_result(1); + } + if (LOG_HDC_DATA) + logerror("hdc_data_r PIO $%02x (%i): \n", data,data_cnt); + return data; + } + + if( data_cnt ) + { + data = *buffer_ptr++; + status &= ~STA_INTERRUPT; + if( --data_cnt == 0 ) + { + status &= ~STA_INPUT; + status &= ~STA_REQUEST; + status &= ~STA_SELECT; + status |= STA_COMMAND; + } + if (LOG_HDC_DATA) + logerror("hdc_data_r $%02x (%i): \n", data,data_cnt); + } + return data; +} + + + +UINT8 xt_hdc_device::status_r() +{ + return status; +} + +void xt_hdc_device::set_ready() +{ + status |= STA_READY; // XXX +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_HDC = &device_creator<isa8_hdc_device>; +const device_type ISA8_HDC_EC1841 = &device_creator<isa8_hdc_ec1841_device>; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_hdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( xt_hdc_config ); +} + +machine_config_constructor isa8_hdc_ec1841_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ec1841_hdc_config ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_hdc_device::device_rom_region() const +{ + return ROM_NAME( hdc ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor isa8_hdc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( isa_hdc ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_hdc_device - constructor +//------------------------------------------------- + +isa8_hdc_device::isa8_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_HDC, "Fixed Disk Controller Card", tag, owner, clock, "hdc", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_hdc(*this,"hdc") +{ +} + +isa8_hdc_device::isa8_hdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_hdc(*this,"hdc") +{ +} + +isa8_hdc_ec1841_device::isa8_hdc_ec1841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_hdc_device( mconfig, ISA8_HDC_EC1841, "EC1841 HDC", tag, owner, clock, "hdc_ec1841", __FILE__), + m_hdc(*this,"hdc") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_hdc_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0320, 0x0323, 0, 0, read8_delegate( FUNC(isa8_hdc_device::pc_hdc_r), this ), write8_delegate( FUNC(isa8_hdc_device::pc_hdc_w), this ) ); + m_isa->set_dma_channel(3, this, FALSE); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_hdc_device::device_reset() +{ + dip = ioport("HDD")->read(); + + if (ioport("ROM")->read() == 1) + m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "hdc", "hdc"); +} + +/************************************************************************* + * + * HDC + * hard disk controller + * + *************************************************************************/ +READ8_MEMBER( isa8_hdc_device::pc_hdc_r ) +{ + UINT8 data = 0xff; + + switch( offset ) + { + case 0: data = m_hdc->data_r(); break; + case 1: data = m_hdc->status_r(); break; + case 2: data = pc_hdc_dipswitch_r(); break; + case 3: break; + } + + if (LOG_HDC_CALL) + logerror("%s pc_hdc_r(): offs=%d result=0x%02x\n", machine().describe_context(), offset, data); + + return data; +} + +WRITE8_MEMBER( isa8_hdc_device::pc_hdc_w ) +{ + if (LOG_HDC_CALL) + logerror("%s pc_hdc_w(): offs=%d data=0x%02x\n", machine().describe_context(), offset, data); + + switch( offset ) + { + case 0: m_hdc->data_w(data); break; + case 1: m_hdc->reset_w(data); break; + case 2: m_hdc->select_w(data); break; + case 3: m_hdc->control_w(data); break; + } +} + + +UINT8 isa8_hdc_device::dack_r(int line) +{ + return m_hdc->dack_r(); +} + +void isa8_hdc_device::dack_w(int line,UINT8 data) +{ + if (m_hdc->get_command() == CMD_WRITESBUFF) + m_hdc->dack_ws(data); + else + m_hdc->dack_w(data); +} + +/* + Dipswitch configuration + + + Tandon/Western Digital Fixed Disk Controller + bit0-1 : Determine disk size(?) + Causes geometry data to be read from c8043, c8053, c8063, c8073 (?) + 00 - 40 Mbytes + 01 - 30 Mbytes + 10 - 10 Mbytes + 11 - 20 Mbytes + bit2-7 : unknown + + */ + +UINT8 isa8_hdc_device::pc_hdc_dipswitch_r() +{ + m_hdc->set_ready(); + if (LOG_HDC_STATUS) + logerror("%s: pc_hdc_dipswitch_r: status $%02X\n", machine().describe_context(), m_hdc->status_r()); + return dip; +} + +WRITE_LINE_MEMBER( isa8_hdc_device::irq_w ) +{ + if (BIT(dip, 6)) + m_isa->irq5_w(state); + else + m_isa->irq2_w(state); +} + +WRITE_LINE_MEMBER( isa8_hdc_device::drq_w ) +{ + m_isa->drq3_w(state); +} |