mame/src/mess/machine/isa_ide_cd.c
Aaron Giles 8669a28810 Add safe_pc() and safe_pcbase() methods to device_t.
Convert all cpu_get_pc() to safe_pc() and
cpu_getpreviouspc() to safe_basepc(). Removed the
old macros.
2012-09-11 05:50:50 +00:00

465 lines
13 KiB
C

/***************************************************************************
ISA 16 bit IDE controller
***************************************************************************/
#include "emu.h"
#include "isa_ide_cd.h"
static void atapi_irq(device_t *device, int state)
{
isa16_ide_cd_device *ide = downcast<isa16_ide_cd_device *>(device);
if (ide->is_primary()) {
ide->m_isa->irq14_w(state);
} else {
ide->m_isa->irq15_w(state);
}
}
WRITE16_MEMBER( isa16_ide_cd_device::atapi_cmd_w )
{
}
READ16_MEMBER( isa16_ide_cd_device::atapi_status_r )
{
UINT8 *atapi_regs = m_atapi_regs;
int shift;
shift = 0;
switch(mem_mask)
{
case 0x000000ff:
break;
case 0x0000ff00:
shift=8;
break;
}
UINT32 data = atapi_regs[ATAPI_REG_CMDSTATUS];
data <<= shift;
return data;
}
READ16_MEMBER( isa16_ide_cd_device::atapi_r )
{
UINT8 *atapi_regs = m_atapi_regs;
//running_machine &machine = machine();
int reg, data;
if (mem_mask == 0x0000ffff) // word-wide command read
{
//logerror("ATAPI: packet read = %02x%02x\n", m_atapi_data[m_atapi_data_ptr+1],m_atapi_data[m_atapi_data_ptr]);
// assert IRQ and drop DRQ
if (m_atapi_data_ptr == 0 && m_atapi_data_len == 0)
{
// get the data from the device
if( m_atapi_xferlen > 0 )
{
m_inserted_cdrom->ReadData( m_atapi_data, m_atapi_xferlen );
m_atapi_data_len = m_atapi_xferlen;
}
if (m_atapi_xfermod > MAX_TRANSFER_SIZE)
{
m_atapi_xferlen = MAX_TRANSFER_SIZE;
m_atapi_xfermod = m_atapi_xfermod - MAX_TRANSFER_SIZE;
}
else
{
m_atapi_xferlen = m_atapi_xfermod;
m_atapi_xfermod = 0;
}
//verboselog\\( machine, 2, "atapi_r: atapi_xferlen=%d\n", m_atapi_xferlen );
if( m_atapi_xferlen != 0 )
{
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
}
else
{
//logerror("ATAPI: dropping DRQ\n");
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND;
}
atapi_regs[ATAPI_REG_COUNTLOW] = m_atapi_xferlen & 0xff;
atapi_regs[ATAPI_REG_COUNTHIGH] = (m_atapi_xferlen>>8)&0xff;
atapi_irq(this, ASSERT_LINE);
}
if( m_atapi_data_ptr < m_atapi_data_len )
{
data = m_atapi_data[m_atapi_data_ptr++];
data |= ( m_atapi_data[m_atapi_data_ptr++] << 8 );
if( m_atapi_data_ptr >= m_atapi_data_len )
{
m_atapi_data_ptr = 0;
m_atapi_data_len = 0;
if( m_atapi_xferlen == 0 )
{
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND;
atapi_irq(this, ASSERT_LINE);
}
}
}
else
{
data = 0;
}
}
else
{
atapi_irq(this, CLEAR_LINE);
int shift;
shift = 0;
reg = offset<<1;
switch(mem_mask)
{
case 0x000000ff:
break;
case 0x0000ff00:
reg+=1;
shift=8;
break;
}
if (m_cur_drive==1) return 0x00;
data = atapi_regs[reg];
//logerror("ATAPI: reg %d = %x (offset %x mask %x) [%08x][read]\n", reg, data, offset, mem_mask,machine().device("maincpu")->safe_pc());
data <<= shift;
}
return data;
}
WRITE16_MEMBER( isa16_ide_cd_device::atapi_w )
{
UINT8 *atapi_regs = m_atapi_regs;
UINT8 *atapi_data = m_atapi_data;
int reg;
if (mem_mask == 0x0000ffff) // word-wide command write
{
atapi_data[m_atapi_data_ptr++] = data & 0xff;
atapi_data[m_atapi_data_ptr++] = data >> 8;
if (m_atapi_cdata_wait)
{
//logerror("ATAPI: waiting, ptr %d wait %d\n", m_atapi_data_ptr, m_atapi_cdata_wait);
if (m_atapi_data_ptr == m_atapi_cdata_wait)
{
// send it to the device
m_inserted_cdrom->WriteData( atapi_data, m_atapi_cdata_wait );
// assert IRQ
atapi_irq(this, ASSERT_LINE);
// not sure here, but clear DRQ at least?
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
}
}
else if ( m_atapi_data_ptr == 12 )
{
int phase;
// reset data pointer for reading SCSI results
m_atapi_data_ptr = 0;
m_atapi_data_len = 0;
void *cdrom;
m_inserted_cdrom->GetDevice( &cdrom );
bool checkready = false;
switch(atapi_data[0]&0xff) {
case 0x00 :
case 0x25 :
case 0x28 :
case 0x2b :
case 0x43 :
case 0xa8 :
case 0xad :
case 0xbe :
checkready = true;
break;
}
if (checkready && cdrom_get_toc((cdrom_file *)cdrom)==NULL)
{
logerror("ATAPI: SCSI command %02x returned not ready\n", atapi_data[0]&0xff);
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY | ATAPI_STAT_CHECK;
atapi_regs[ATAPI_REG_ERRFEAT] = (2 << 4) | ATAPI_ERRFEAT_ABRT;
// assert IRQ
atapi_irq(this, ASSERT_LINE);
} else {
// send it to the SCSI device
m_inserted_cdrom->SetCommand( m_atapi_data, 12 );
m_inserted_cdrom->ExecCommand( &m_atapi_xferlen );
m_inserted_cdrom->GetPhase( &phase );
if (m_atapi_xferlen != -1)
{
logerror("ATAPI: SCSI command %02x returned %d bytes from the device\n", atapi_data[0]&0xff, m_atapi_xferlen);
// store the returned command length in the ATAPI regs, splitting into
// multiple transfers if necessary
m_atapi_xfermod = 0;
if (m_atapi_xferlen > MAX_TRANSFER_SIZE)
{
m_atapi_xfermod = m_atapi_xferlen - MAX_TRANSFER_SIZE;
m_atapi_xferlen = MAX_TRANSFER_SIZE;
}
atapi_regs[ATAPI_REG_COUNTLOW] = m_atapi_xferlen & 0xff;
atapi_regs[ATAPI_REG_COUNTHIGH] = (m_atapi_xferlen>>8)&0xff;
if (m_atapi_xferlen == 0)
{
// if no data to return, set the registers properly
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY;
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO|ATAPI_INTREASON_COMMAND;
}
else
{
// indicate data ready: set DRQ and DMA ready, and IO in INTREASON
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
}
switch( phase )
{
case SCSI_PHASE_DATAOUT:
m_atapi_cdata_wait = m_atapi_xferlen;
break;
}
// perform special ATAPI processing of certain commands
switch (atapi_data[0]&0xff)
{
case 0x00: // BUS RESET / TEST UNIT READY
case 0xbb: // SET CDROM SPEED
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
break;
case 0x45: // PLAY
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY;
//m_atapi_timer->adjust( downcast<cpu_device *>(this)->cycles_to_attotime( ATAPI_CYCLES_PER_SECTOR ) );
break;
}
// assert IRQ
atapi_irq(this, ASSERT_LINE);
}
else
{
logerror("ATAPI: SCSI device returned error!\n");
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_CHECK;
atapi_regs[ATAPI_REG_ERRFEAT] = 0x50; // sense key = ILLEGAL REQUEST
atapi_regs[ATAPI_REG_COUNTLOW] = 0;
atapi_regs[ATAPI_REG_COUNTHIGH] = 0;
}
}
}
}
else
{
reg = offset<<1;
switch(mem_mask)
{
case 0x000000ff:
break;
case 0x0000ff00:
reg+=1;
data >>= 8;
break;
}
if (reg==6) m_cur_drive = (data & 0x10) >> 4;
if (m_cur_drive==1) return;
atapi_regs[reg] = data;
//logerror("ATAPI: reg %d = %x (offset %x mask %x)\n", reg, data, offset, mem_mask);
if (reg == ATAPI_REG_CMDSTATUS)
{
logerror("ATAPI command %x issued!\n", data);
switch (data)
{
case 0xa0: // PACKET
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_COMMAND;
m_atapi_data_ptr = 0;
m_atapi_data_len = 0;
/* we have no data */
m_atapi_xferlen = 0;
m_atapi_xfermod = 0;
m_atapi_cdata_wait = 0;
break;
case 0xa1: // IDENTIFY PACKET DEVICE
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
m_atapi_data_ptr = 0;
m_atapi_data_len = 512;
/* we have no data */
m_atapi_xferlen = 0;
m_atapi_xfermod = 0;
memset( atapi_data, 0, m_atapi_data_len );
atapi_data[ 0 ^ 1 ] = 0x85; // ATAPI device, cmd set 5 compliant, DRQ within 3 ms of PACKET command
atapi_data[ 1 ^ 1 ] = 0x80; // ATAPI device, removable media
memset( &atapi_data[ 46 ], ' ', 8 );
atapi_data[ 46 ^ 1 ] = '1';
atapi_data[ 47 ^ 1 ] = '.';
atapi_data[ 48 ^ 1 ] = '0';
memset( &atapi_data[ 54 ], ' ', 40 );
atapi_data[ 54 ^ 1 ] = 'M';
atapi_data[ 55 ^ 1 ] = 'A';
atapi_data[ 56 ^ 1 ] = 'M';
atapi_data[ 57 ^ 1 ] = 'E';
atapi_data[ 58 ^ 1 ] = ' ';
atapi_data[ 59 ^ 1 ] = 'C';
atapi_data[ 60 ^ 1 ] = 'o';
atapi_data[ 61 ^ 1 ] = 'm';
atapi_data[ 62 ^ 1 ] = 'p';
atapi_data[ 63 ^ 1 ] = 'r';
atapi_data[ 64 ^ 1 ] = 'e';
atapi_data[ 65 ^ 1 ] = 's';
atapi_data[ 66 ^ 1 ] = 's';
atapi_data[ 67 ^ 1 ] = 'e';
atapi_data[ 68 ^ 1 ] = 'd';
atapi_data[ 69 ^ 1 ] = ' ';
atapi_data[ 70 ^ 1 ] = 'C';
atapi_data[ 71 ^ 1 ] = 'D';
atapi_data[ 72 ^ 1 ] = '-';
atapi_data[ 73 ^ 1 ] = 'R';
atapi_data[ 74 ^ 1 ] = 'O';
atapi_data[ 75 ^ 1 ] = 'M';
atapi_data[ 98 ^ 1 ] = 0x06; // Word 49=Capabilities, IORDY may be disabled (bit_10), LBA Supported mandatory (bit_9)
atapi_data[ 99 ^ 1 ] = 0x00;
atapi_regs[ATAPI_REG_COUNTLOW] = 0;
atapi_regs[ATAPI_REG_COUNTHIGH] = 2;
atapi_irq(this, ASSERT_LINE);
break;
case 0xec: //IDENTIFY DEVICE - Must abort here and set for packet data
atapi_regs[ATAPI_REG_ERRFEAT] = ATAPI_ERRFEAT_ABRT;
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_CHECK;
atapi_irq(this, ASSERT_LINE);
break;
case 0xef: // SET FEATURES
atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
m_atapi_data_ptr = 0;
m_atapi_data_len = 0;
atapi_irq(this, ASSERT_LINE);
break;
case 0x08: // ATAPI RESET
atapi_regs[ATAPI_REG_CMDSTATUS] = 0x00;
atapi_regs[ATAPI_REG_ERRFEAT] = 0x01;
atapi_regs[ATAPI_REG_INTREASON] = 0x01; // SECTOR_COUNT
atapi_regs[ATAPI_REG_SAMTAG] = 0x01; // SECTOR_NUMBER
atapi_regs[ATAPI_REG_COUNTLOW] = 0x14; // CYLINDER_LSB
atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb; // CYLINDER_MSB
atapi_regs[ATAPI_REG_DRIVESEL] &= 0xf0; // HEAD_NUMBER
atapi_irq(this, ASSERT_LINE);
break;
default:
logerror("ATAPI: Unknown IDE command %x\n", data);
atapi_regs[ATAPI_REG_ERRFEAT] = ATAPI_ERRFEAT_ABRT;
atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_CHECK;
atapi_irq(this, ASSERT_LINE);
break;
}
}
}
}
static MACHINE_CONFIG_FRAGMENT( ide )
MCFG_DEVICE_ADD("cdrom", SCSICD, 0)
MACHINE_CONFIG_END
static INPUT_PORTS_START( ide )
PORT_START("DSW")
PORT_DIPNAME( 0x01, 0x00, "IDE Configuration")
PORT_DIPSETTING( 0x00, "Primary" )
PORT_DIPSETTING( 0x01, "Secondary" )
INPUT_PORTS_END
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
const device_type ISA16_IDE_CD = &device_creator<isa16_ide_cd_device>;
//-------------------------------------------------
// machine_config_additions - device-specific
// machine configurations
//-------------------------------------------------
machine_config_constructor isa16_ide_cd_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( ide );
}
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor isa16_ide_cd_device::device_input_ports() const
{
return INPUT_PORTS_NAME( ide );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// isa16_ide_cd_device - constructor
//-------------------------------------------------
isa16_ide_cd_device::isa16_ide_cd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, ISA16_IDE_CD, "IDE CD Drive Adapter", tag, owner, clock),
device_isa16_card_interface( mconfig, *this ),
m_is_primary(true),
m_inserted_cdrom(NULL)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void isa16_ide_cd_device::device_start()
{
set_isa_device();
m_inserted_cdrom = subdevice<scsicd_device>("cdrom");
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void isa16_ide_cd_device::device_reset()
{
m_is_primary = (ioport("DSW")->read() & 1) ? false : true;
if (m_is_primary) {
m_isa->install16_device(0x01f0, 0x01f7, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_w), this));
//m_isa->install16_device(0x03f0, 0x03f7, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_status_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_cmd_w), this));
} else {
m_isa->install16_device(0x0170, 0x0177, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_w), this));
m_isa->install16_device(0x0370, 0x0377, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_status_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_cmd_w), this));
}
m_cur_drive = 0;
}