Renamed some #defines to match up closer to the ATA specification. Added validation to register access, switching Primal Rage 2 away from using the DMA interface in it's DMA handler as the game only executes normal read commands (nw)

This commit is contained in:
smf- 2013-06-14 19:17:43 +00:00
parent 358509548a
commit e3bbb0a27d
5 changed files with 469 additions and 292 deletions

View File

@ -232,6 +232,15 @@ WRITE16_MEMBER( ide_controller_device::write_cs1 )
m_slot[i]->dev()->write_cs1(space, offset, data, mem_mask);
}
WRITE_LINE_MEMBER( ide_controller_device::write_dmack )
{
// printf( "write_dmack %04x\n", state );
for (int i = 0; i < 2; i++)
if (m_slot[i]->dev() != NULL)
m_slot[i]->dev()->write_dmack(state);
}
WRITE8_MEMBER( ide_controller_device::write_via_config )
{
// printf( "write via config %04x %04x %04x\n", offset, data, mem_mask );
@ -416,7 +425,9 @@ bus_master_ide_controller_device::bus_master_ide_controller_device(const machine
dma_last_buffer(0),
bus_master_command(0),
bus_master_status(0),
bus_master_descriptor(0)
bus_master_descriptor(0),
m_irq(0),
m_dmarq(0)
{
}
@ -568,6 +579,8 @@ WRITE32_MEMBER( bus_master_ide_controller_device::ide_bus_master32_w )
void bus_master_ide_controller_device::execute_dma()
{
write_dmack(ASSERT_LINE);
while (m_dmarq && (bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE))
{
/* if we're out of space, grab the next descriptor */
@ -624,4 +637,6 @@ void bus_master_ide_controller_device::execute_dma()
}
}
}
write_dmack(CLEAR_LINE);
}

View File

@ -94,9 +94,11 @@ public:
UINT16 read_dma();
DECLARE_READ16_MEMBER(read_cs0);
DECLARE_READ16_MEMBER(read_cs1);
void write_dma(UINT16 data);
DECLARE_WRITE16_MEMBER(write_cs0);
DECLARE_WRITE16_MEMBER(write_cs1);
DECLARE_WRITE_LINE_MEMBER(write_dmack);
DECLARE_READ8_MEMBER(read_via_config);
DECLARE_WRITE8_MEMBER(write_via_config);

View File

@ -21,16 +21,19 @@
#define TIME_SEEK_MULTISECTOR (attotime::from_msec(13))
#define TIME_NO_SEEK_MULTISECTOR (attotime::from_nsec(16300))
#define IDE_BANK0_DATA 0
#define IDE_BANK0_ERROR 1
#define IDE_BANK0_SECTOR_COUNT 2
#define IDE_BANK0_SECTOR_NUMBER 3
#define IDE_BANK0_CYLINDER_LSB 4
#define IDE_BANK0_CYLINDER_MSB 5
#define IDE_BANK0_HEAD_NUMBER 6
#define IDE_BANK0_STATUS_COMMAND 7
#define IDE_CS0_DATA_RW 0
#define IDE_CS0_ERROR_R 1
#define IDE_CS0_FEATURE_W 1
#define IDE_CS0_SECTOR_COUNT_RW 2
#define IDE_CS0_SECTOR_NUMBER_RW 3
#define IDE_CS0_CYLINDER_LOW_RW 4
#define IDE_CS0_CYLINDER_HIGH_RW 5
#define IDE_CS0_DEVICE_HEAD_RW 6
#define IDE_CS0_STATUS_R 7
#define IDE_CS0_COMMAND_W 7
#define IDE_BANK1_STATUS_CONTROL 6
#define IDE_CS1_ALTERNATE_STATUS_R 6
#define IDE_CS1_DEVICE_CONTROL_W 6
#define IDE_COMMAND_READ_SECTORS 0x20
#define IDE_COMMAND_READ_SECTORS_NORETRY 0x21
@ -90,26 +93,37 @@ ide_mass_storage_device::ide_mass_storage_device(const machine_config &mconfig,
ide_device_interface(mconfig, *this),
device_slot_card_interface(mconfig, *this),
m_csel(0),
m_dasp(0)
m_dasp(0),
m_dmack(0),
m_dmarq(0),
m_irq(0)
{
}
void ide_mass_storage_device::set_irq(int state)
{
if (m_irq != state)
{
m_irq = state;
if (state == ASSERT_LINE)
LOG(("IDE interrupt assert\n"));
else
LOG(("IDE interrupt clear\n"));
m_interrupt_pending = state;
/* signal an interrupt */
m_irq_handler(state);
}
}
void ide_mass_storage_device::set_dmarq(int state)
{
if (m_dmarq != state)
{
m_dmarq = state;
m_dmarq_handler(state);
}
}
WRITE_LINE_MEMBER( ide_mass_storage_device::write_csel )
@ -122,6 +136,11 @@ WRITE_LINE_MEMBER( ide_mass_storage_device::write_dasp )
m_dasp = state;
}
WRITE_LINE_MEMBER( ide_mass_storage_device::write_dmack )
{
m_dmack = state;
}
/*************************************
*
* Compute the LBA address
@ -340,11 +359,12 @@ void ide_mass_storage_device::device_start()
save_item(NAME(m_command));
save_item(NAME(m_error));
save_item(NAME(m_adapter_control));
save_item(NAME(m_precomp_offset));
save_item(NAME(m_device_control));
save_item(NAME(m_feature));
save_item(NAME(m_sector_count));
save_item(NAME(m_interrupt_pending));
save_item(NAME(m_irq));
save_item(NAME(m_dmarq));
save_item(NAME(m_sectors_until_int));
save_item(NAME(m_master_password_enable));
@ -368,7 +388,13 @@ void ide_mass_storage_device::device_reset()
m_master_password_enable = (m_master_password != NULL);
m_user_password_enable = (m_user_password != NULL);
m_error = IDE_ERROR_DEFAULT;
m_status = IDE_STATUS_DRIVE_READY | IDE_STATUS_SEEK_COMPLETE;
m_status = IDE_STATUS_DSC;
if (is_ready())
{
m_status |= IDE_STATUS_DRDY;
}
m_cur_drive = 0;
/* reset the drive state */
@ -381,13 +407,14 @@ void ide_mass_storage_device::device_timer(emu_timer &timer, device_timer_id id,
switch(id)
{
case TID_DELAYED_INTERRUPT:
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_BSY;
set_irq(ASSERT_LINE);
break;
case TID_DELAYED_INTERRUPT_BUFFER_READY:
m_status &= ~IDE_STATUS_BUSY;
m_status |= IDE_STATUS_BUFFER_READY;
m_status &= ~IDE_STATUS_BSY;
m_status |= IDE_STATUS_DRQ;
set_irq(ASSERT_LINE);
break;
@ -397,8 +424,8 @@ void ide_mass_storage_device::device_timer(emu_timer &timer, device_timer_id id,
case TID_SECURITY_ERROR_DONE:
/* clear error state */
m_status &= ~IDE_STATUS_ERROR;
m_status |= IDE_STATUS_DRIVE_READY;
m_status &= ~IDE_STATUS_ERR;
m_status |= IDE_STATUS_DRDY;
break;
case TID_READ_SECTOR_DONE_CALLBACK:
@ -414,8 +441,8 @@ void ide_mass_storage_device::device_timer(emu_timer &timer, device_timer_id id,
void ide_mass_storage_device::signal_delayed_interrupt(attotime time, int buffer_ready)
{
/* clear buffer ready and set the busy flag */
m_status &= ~IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_DRQ;
m_status |= IDE_STATUS_BSY;
/* set a timer */
if (buffer_ready)
@ -476,8 +503,8 @@ void ide_mass_storage_device::next_sector()
void ide_mass_storage_device::security_error()
{
/* set error state */
m_status |= IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_DRIVE_READY;
m_status |= IDE_STATUS_ERR;
m_status &= ~IDE_STATUS_DRDY;
/* just set a timer and mark ourselves error */
timer_set(TIME_SECURITY_ERROR, TID_SECURITY_ERROR_DONE);
@ -497,8 +524,8 @@ void ide_mass_storage_device::read_buffer_empty()
m_buffer_offset = 0;
/* clear the buffer ready and busy flag */
m_status &= ~IDE_STATUS_BUFFER_READY;
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_DRQ;
m_status &= ~IDE_STATUS_BSY;
m_error = IDE_ERROR_DEFAULT;
set_dmarq(CLEAR_LINE);
@ -525,8 +552,8 @@ void ide_mass_storage_device::read_sector_done()
/* GNET readlock check */
if (m_gnetreadlock) {
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_ERR;
m_status &= ~IDE_STATUS_BSY;
return;
}
@ -535,12 +562,13 @@ void ide_mass_storage_device::read_sector_done()
/* by default, mark the buffer ready and the seek complete */
if (!m_verify_only)
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_SEEK_COMPLETE;
m_status |= IDE_STATUS_DRQ;
m_status |= IDE_STATUS_DSC;
/* and clear the busy and error flags */
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_ERR;
m_status &= ~IDE_STATUS_BSY;
/* if we succeeded, advance to the next sector and set the nice bits */
if (count == 1)
@ -575,7 +603,7 @@ void ide_mass_storage_device::read_sector_done()
else
{
/* set the error flag and the error */
m_status |= IDE_STATUS_ERROR;
m_status |= IDE_STATUS_ERR;
m_error = IDE_ERROR_BAD_SECTOR;
/* signal an interrupt */
@ -587,7 +615,7 @@ void ide_mass_storage_device::read_sector_done()
void ide_mass_storage_device::read_first_sector()
{
/* mark ourselves busy */
m_status |= IDE_STATUS_BUSY;
m_status |= IDE_STATUS_BSY;
/* just set a timer */
if (m_command == IDE_COMMAND_READ_MULTIPLE)
@ -611,7 +639,7 @@ void ide_mass_storage_device::read_first_sector()
void ide_mass_storage_device::read_next_sector()
{
/* mark ourselves busy */
m_status |= IDE_STATUS_BUSY;
m_status |= IDE_STATUS_BSY;
if (m_command == IDE_COMMAND_READ_MULTIPLE)
{
@ -641,8 +669,8 @@ void ide_mass_storage_device::continue_write()
m_buffer_offset = 0;
/* clear the buffer ready flag */
m_status &= ~IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_DRQ;
m_status |= IDE_STATUS_BSY;
if (m_command == IDE_COMMAND_WRITE_MULTIPLE)
{
@ -668,6 +696,7 @@ void ide_mass_storage_device::continue_write()
void ide_mass_storage_device::write_buffer_full()
{
set_dmarq(CLEAR_LINE);
if (m_command == IDE_COMMAND_SECURITY_UNLOCK)
{
if (m_user_password_enable && memcmp(m_buffer, m_user_password, 2 + 32) == 0)
@ -696,14 +725,14 @@ void ide_mass_storage_device::write_buffer_full()
}
/* clear the busy and error flags */
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_BUFFER_READY;
m_status &= ~IDE_STATUS_ERR;
m_status &= ~IDE_STATUS_BSY;
m_status &= ~IDE_STATUS_DRQ;
if (m_master_password_enable || m_user_password_enable)
security_error();
else
m_status |= IDE_STATUS_DRIVE_READY;
m_status |= IDE_STATUS_DRDY;
}
else if (m_command == IDE_COMMAND_TAITO_GNET_UNLOCK_2)
{
@ -714,12 +743,12 @@ void ide_mass_storage_device::write_buffer_full()
for (i=0; !bad && i<512; i++)
bad = ((i < 2 || i >= 7) && m_buffer[i]) || ((i >= 2 && i < 7) && m_buffer[i] != key[i-2]);
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_BUFFER_READY;
m_status &= ~IDE_STATUS_BSY;
m_status &= ~IDE_STATUS_DRQ;
if (bad)
m_status |= IDE_STATUS_ERROR;
m_status |= IDE_STATUS_ERR;
else {
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_ERR;
m_gnetreadlock= 0;
}
}
@ -738,12 +767,12 @@ void ide_mass_storage_device::write_sector_done()
count = write_sector(lba, m_buffer);
/* by default, mark the buffer ready and the seek complete */
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_SEEK_COMPLETE;
m_status |= IDE_STATUS_DRQ;
m_status |= IDE_STATUS_DSC;
/* and clear the busy adn error flags */
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_ERR;
m_status &= ~IDE_STATUS_BSY;
/* if we succeeded, advance to the next sector and set the nice bits */
if (count == 1)
@ -767,7 +796,7 @@ void ide_mass_storage_device::write_sector_done()
if (m_sector_count > 0)
m_sector_count--;
if (m_sector_count == 0)
m_status &= ~IDE_STATUS_BUFFER_READY;
m_status &= ~IDE_STATUS_DRQ;
/* keep going for DMA */
if (m_dma_active && m_sector_count != 0)
@ -780,7 +809,7 @@ void ide_mass_storage_device::write_sector_done()
else
{
/* set the error flag and the error */
m_status |= IDE_STATUS_ERROR;
m_status |= IDE_STATUS_ERR;
m_error = IDE_ERROR_BAD_SECTOR;
/* signal an interrupt */
@ -796,14 +825,14 @@ void ide_mass_storage_device::write_sector_done()
*
*************************************/
void ide_mass_storage_device::handle_command(UINT8 _command)
void ide_mass_storage_device::handle_command()
{
UINT8 key[5];
/* implicitly clear interrupts & dmarq here */
set_irq(CLEAR_LINE);
set_dmarq(CLEAR_LINE);
m_command = _command;
switch (m_command)
{
case IDE_COMMAND_READ_SECTORS:
@ -875,7 +904,7 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
m_dma_active = 0;
/* mark the buffer ready */
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_DRQ;
break;
case IDE_COMMAND_WRITE_MULTIPLE:
@ -888,7 +917,7 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
m_dma_active = 0;
/* mark the buffer ready */
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_DRQ;
break;
case IDE_COMMAND_WRITE_DMA:
@ -900,6 +929,9 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
m_sectors_until_int = m_sector_count;
m_dma_active = 1;
/* mark the buffer ready */
m_status |= IDE_STATUS_DRQ;
/* start the read going */
set_dmarq(ASSERT_LINE);
break;
@ -913,7 +945,8 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
m_dma_active = 0;
/* mark the buffer ready */
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_DRQ;
set_irq(ASSERT_LINE);
break;
@ -928,13 +961,13 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
memcpy(m_buffer, m_features, sizeof(m_buffer));
/* indicate everything is ready */
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_SEEK_COMPLETE;
m_status |= IDE_STATUS_DRIVE_READY;
m_status |= IDE_STATUS_DRQ;
m_status |= IDE_STATUS_DSC;
m_status |= IDE_STATUS_DRDY;
/* and clear the busy adn error flags */
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_ERR;
m_status &= ~IDE_STATUS_BSY;
/* clear the error too */
m_error = IDE_ERROR_NONE;
@ -969,7 +1002,7 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
case IDE_COMMAND_SET_CONFIG:
LOGPRINT(("IDE Set configuration (%d heads, %d sectors)\n", m_cur_head + 1, m_sector_count));
m_status &= ~IDE_STATUS_ERROR;
m_status &= ~IDE_STATUS_ERR;
m_error = IDE_ERROR_NONE;
set_geometry(m_sector_count,m_cur_head + 1);
@ -986,7 +1019,7 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
break;
case IDE_COMMAND_SET_FEATURES:
LOGPRINT(("IDE Set features (%02X %02X %02X %02X %02X)\n", m_precomp_offset, m_sector_count & 0xff, m_cur_sector, m_cur_cylinder & 0xff, m_cur_cylinder >> 8));
LOGPRINT(("IDE Set features (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_cur_sector, m_cur_cylinder & 0xff, m_cur_cylinder >> 8));
/* signal an interrupt */
signal_delayed_interrupt(MINIMUM_COMMAND_TIME, 0);
@ -997,7 +1030,7 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
m_block_count = m_sector_count;
// judge dredd wants 'drive ready' on this command
m_status |= IDE_STATUS_DRIVE_READY;
m_status |= IDE_STATUS_DRDY;
/* signal an interrupt */
set_irq(ASSERT_LINE);
@ -1007,8 +1040,8 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
LOGPRINT(("IDE GNET Unlock 1\n"));
m_sector_count = 1;
m_status |= IDE_STATUS_DRIVE_READY;
m_status &= ~IDE_STATUS_ERROR;
m_status |= IDE_STATUS_DRDY;
m_status &= ~IDE_STATUS_ERR;
set_irq(ASSERT_LINE);
break;
@ -1021,7 +1054,8 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
m_dma_active = 0;
/* mark the buffer ready */
m_status |= IDE_STATUS_BUFFER_READY;
m_status |= IDE_STATUS_DRQ;
set_irq(ASSERT_LINE);
break;
@ -1030,14 +1064,14 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
/* key check */
read_key(key);
if ((m_precomp_offset == key[0]) && (m_sector_count == key[1]) && (m_cur_sector == key[2]) && (m_cur_cylinder == (((UINT16)key[4]<<8)|key[3])))
if ((m_feature == key[0]) && (m_sector_count == key[1]) && (m_cur_sector == key[2]) && (m_cur_cylinder == (((UINT16)key[4]<<8)|key[3])))
{
m_gnetreadlock= 0;
}
/* update flags */
m_status |= IDE_STATUS_DRIVE_READY;
m_status &= ~IDE_STATUS_ERROR;
m_status |= IDE_STATUS_DRDY;
m_status &= ~IDE_STATUS_ERR;
set_irq(ASSERT_LINE);
break;
@ -1059,7 +1093,7 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
default:
LOGPRINT(("IDE unknown command (%02X)\n", m_command));
m_status |= IDE_STATUS_ERROR;
m_status |= IDE_STATUS_ERR;
m_error = IDE_ERROR_UNKNOWN_COMMAND;
set_irq(ASSERT_LINE);
//debugger_break(device->machine());
@ -1069,15 +1103,29 @@ void ide_mass_storage_device::handle_command(UINT8 _command)
UINT16 ide_mass_storage_device::read_dma()
{
if (m_cur_drive != m_csel)
UINT16 result = 0xffff;
if (device_selected())
{
if (m_csel == 0 && m_dasp == 0)
return 0;
return 0xffff;
if (!m_dmack)
{
logerror( "%s: read_dma ignored (!DMACK)\n", machine().describe_context() );
}
UINT16 result = m_buffer[m_buffer_offset++];
else if( !m_dmarq)
{
logerror( "%s: read_dma ignored (!DMARQ)\n", machine().describe_context() );
}
else if (m_status & IDE_STATUS_BSY)
{
logerror( "%s: read_dma ignored (BSY)\n", machine().describe_context() );
}
else if (!(m_status & IDE_STATUS_DRQ))
{
logerror( "%s: read_dma ignored (!DRQ)\n", machine().describe_context() );
}
else
{
result = m_buffer[m_buffer_offset++];
result |= m_buffer[m_buffer_offset++] << 8;
if (m_buffer_offset >= IDE_DISK_SECTOR_SIZE)
@ -1085,37 +1133,61 @@ UINT16 ide_mass_storage_device::read_dma()
LOG(("%s:IDE completed DMA read\n", machine().describe_context()));
read_buffer_empty();
}
}
}
return result;
}
READ16_MEMBER( ide_mass_storage_device::read_cs0 )
{
UINT16 result = 0;
/* logit */
// if (offset != IDE_BANK0_DATA && offset != IDE_BANK0_STATUS_COMMAND)
// if (offset != IDE_CS0_DATA_RW && offset != IDE_CS0_STATUS_R)
LOG(("%s:IDE cs0 read at %X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask));
if (m_cur_drive != m_csel)
UINT16 result = 0xffff;
if (device_selected() || single_device())
{
if (m_csel == 0 && m_dasp == 0)
return 0;
return 0xffff;
if (m_dmack)
{
logerror( "%s: read_cs0 %04x %04x ignored (DMACK)\n", machine().describe_context(), offset, mem_mask );
}
else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_STATUS_R)
{
if (device_selected())
{
switch (offset)
{
case IDE_CS0_DATA_RW:
logerror( "%s: read_cs0 %04x %04x ignored (BSY)\n", machine().describe_context(), offset, mem_mask );
break;
if (is_ready()) {
m_status |= IDE_STATUS_DRIVE_READY;
} else {
m_status &= ~IDE_STATUS_DRIVE_READY;
default:
result = m_status;
if (m_last_status_timer->elapsed() > TIME_PER_ROTATION)
{
result |= IDE_STATUS_IDX;
m_last_status_timer->adjust(attotime::never);
}
break;
}
}
else
{
result = 0;
}
}
else
{
switch (offset)
{
/* read data if there's data to be read */
case IDE_BANK0_DATA:
if (m_status & IDE_STATUS_BUFFER_READY)
case IDE_CS0_DATA_RW:
if (device_selected())
{
if (m_status & IDE_STATUS_DRQ)
{
/* fetch the correct amount of data */
result = m_buffer[m_buffer_offset++];
@ -1129,48 +1201,61 @@ READ16_MEMBER( ide_mass_storage_device::read_cs0 )
read_buffer_empty();
}
}
}
else
{
result = 0;
}
break;
/* return the current error */
case IDE_BANK0_ERROR:
case IDE_CS0_ERROR_R:
result = m_error;
break;
/* return the current sector count */
case IDE_BANK0_SECTOR_COUNT:
case IDE_CS0_SECTOR_COUNT_RW:
result = m_sector_count;
break;
/* return the current sector */
case IDE_BANK0_SECTOR_NUMBER:
case IDE_CS0_SECTOR_NUMBER_RW:
result = m_cur_sector;
break;
/* return the current cylinder LSB */
case IDE_BANK0_CYLINDER_LSB:
case IDE_CS0_CYLINDER_LOW_RW:
result = m_cur_cylinder & 0xff;
break;
/* return the current cylinder MSB */
case IDE_BANK0_CYLINDER_MSB:
case IDE_CS0_CYLINDER_HIGH_RW:
result = m_cur_cylinder >> 8;
break;
/* return the current head */
case IDE_BANK0_HEAD_NUMBER:
case IDE_CS0_DEVICE_HEAD_RW:
result = m_cur_head_reg;
break;
/* return the current status and clear any pending interrupts */
case IDE_BANK0_STATUS_COMMAND:
case IDE_CS0_STATUS_R:
if (device_selected())
{
result = m_status;
if (m_last_status_timer->elapsed() > TIME_PER_ROTATION)
{
result |= IDE_STATUS_HIT_INDEX;
result |= IDE_STATUS_IDX;
m_last_status_timer->adjust(attotime::never);
}
if (m_interrupt_pending == ASSERT_LINE)
set_irq(CLEAR_LINE);
}
else
{
result = 0;
}
break;
/* log anything else */
@ -1178,6 +1263,8 @@ READ16_MEMBER( ide_mass_storage_device::read_cs0 )
logerror("%s:unknown IDE cs0 read at %03X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask);
break;
}
}
}
/* return the result */
return result;
@ -1185,36 +1272,37 @@ READ16_MEMBER( ide_mass_storage_device::read_cs0 )
READ16_MEMBER( ide_mass_storage_device::read_cs1 )
{
if (m_cur_drive != m_csel)
{
if (m_csel == 0 && m_dasp == 0)
return 0;
return 0xffff;
}
if (is_ready()) {
m_status |= IDE_STATUS_DRIVE_READY;
} else {
m_status &= ~IDE_STATUS_DRIVE_READY;
}
/* logit */
// if (offset != IDE_BANK1_STATUS_CONTROL)
// if (offset != IDE_CS1_ALTERNATE_STATUS_R)
LOG(("%s:IDE cs1 read at %X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask));
/* return the current status but don't clear interrupts */
UINT16 result = 0;
UINT16 result = 0xffff;
if (device_selected() || single_device())
{
if (m_dmack)
{
logerror( "%s: read_cs1 %04x %04x ignored (DMACK)\n", machine().describe_context(), offset, mem_mask );
}
else
{
switch (offset)
{
case IDE_BANK1_STATUS_CONTROL:
case IDE_CS1_ALTERNATE_STATUS_R:
if( device_selected() )
{
/* return the current status but don't clear interrupts */
result = m_status;
if (m_last_status_timer->elapsed() > TIME_PER_ROTATION)
{
result |= IDE_STATUS_HIT_INDEX;
result |= IDE_STATUS_IDX;
m_last_status_timer->adjust(attotime::never);
}
}
else
{
result = 0;
}
break;
/* log anything else */
@ -1222,6 +1310,8 @@ READ16_MEMBER( ide_mass_storage_device::read_cs1 )
logerror("%s:unknown IDE cs1 read at %03X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask);
break;
}
}
}
/* return the result */
return result;
@ -1229,9 +1319,26 @@ READ16_MEMBER( ide_mass_storage_device::read_cs1 )
void ide_mass_storage_device::write_dma( UINT16 data )
{
if (m_cur_drive != m_csel)
return;
if (device_selected())
{
if (!m_dmack)
{
logerror( "%s: write_dma %04x ignored (!DMACK)\n", machine().describe_context(), data );
}
else if( !m_dmarq)
{
logerror( "%s: write_dma %04x ignored (!DMARQ)\n", machine().describe_context(), data );
}
else if (m_status & IDE_STATUS_BSY)
{
logerror( "%s: write_dma %04x ignored (BSY)\n", machine().describe_context(), data );
}
else if (!(m_status & IDE_STATUS_DRQ))
{
logerror( "%s: write_dma %04x ignored (!DRQ)\n", machine().describe_context(), data );
}
else
{
m_buffer[m_buffer_offset++] = data;
m_buffer[m_buffer_offset++] = data >> 8;
@ -1241,29 +1348,42 @@ void ide_mass_storage_device::write_dma( UINT16 data )
LOG(("%s:IDE completed DMA write\n", machine().describe_context()));
write_buffer_full();
}
}
}
}
WRITE16_MEMBER( ide_mass_storage_device::write_cs0 )
{
switch (offset)
{
case IDE_BANK0_HEAD_NUMBER:
m_cur_drive = (data & 0x10) >> 4;
break;
}
if (m_cur_drive != m_csel)
return;
/* logit */
if (offset != IDE_BANK0_DATA)
if (offset != IDE_CS0_DATA_RW)
LOG(("%s:IDE cs0 write to %X = %08X, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask));
// fprintf(stderr, "ide write %03x %02x mem_mask=%d\n", offset, data, size);
if (m_dmack)
{
logerror( "%s: write_cs0 %04x %04x %04x ignored (DMACK)\n", machine().describe_context(), offset, data, mem_mask );
}
else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_COMMAND_W)
{
logerror( "%s: write_cs0 %04x %04x %04x ignored (BSY)\n", machine().describe_context(), offset, data, mem_mask );
}
else if ((m_status & IDE_STATUS_DRQ) && offset != IDE_CS0_DATA_RW && offset != IDE_CS0_COMMAND_W)
{
logerror( "%s: write_cs0 %04x %04x %04x ignored (DRQ)\n", machine().describe_context(), offset, data, mem_mask );
}
else
{
switch (offset)
{
/* write data */
case IDE_BANK0_DATA:
if (m_status & IDE_STATUS_BUFFER_READY)
case IDE_CS0_DATA_RW:
if( device_selected() )
{
if (!(m_status & IDE_STATUS_DRQ))
{
logerror( "%s: write_cs0 %04x %04x %04x ignored (!DRQ)\n", machine().describe_context(), offset, data, mem_mask );
}
else
{
/* store the correct amount of data */
m_buffer[m_buffer_offset++] = data;
@ -1277,71 +1397,85 @@ WRITE16_MEMBER( ide_mass_storage_device::write_cs0 )
write_buffer_full();
}
}
}
break;
/* precompensation offset?? */
case IDE_BANK0_ERROR:
m_precomp_offset = data;
case IDE_CS0_FEATURE_W:
m_feature = data;
break;
/* sector count */
case IDE_BANK0_SECTOR_COUNT:
case IDE_CS0_SECTOR_COUNT_RW:
m_sector_count = data ? data : 256;
break;
/* current sector */
case IDE_BANK0_SECTOR_NUMBER:
case IDE_CS0_SECTOR_NUMBER_RW:
m_cur_sector = data;
break;
/* current cylinder LSB */
case IDE_BANK0_CYLINDER_LSB:
case IDE_CS0_CYLINDER_LOW_RW:
m_cur_cylinder = (m_cur_cylinder & 0xff00) | (data & 0xff);
break;
/* current cylinder MSB */
case IDE_BANK0_CYLINDER_MSB:
m_cur_cylinder = (m_cur_cylinder & 0x00ff) | ((data & 0xff) << 8);
case IDE_CS0_CYLINDER_HIGH_RW:
m_cur_cylinder = ((data << 8) & 0xff00) | (m_cur_cylinder & 0xff);
break;
/* current head */
case IDE_BANK0_HEAD_NUMBER:
case IDE_CS0_DEVICE_HEAD_RW:
// LBA mode = data & 0x40
m_cur_drive = (data & 0x10) >> 4;
m_cur_head = data & 0x0f;
m_cur_head_reg = data;
// LBA mode = data & 0x40
break;
/* command */
case IDE_BANK0_STATUS_COMMAND:
handle_command(data);
case IDE_CS0_COMMAND_W:
m_command = data;
if (device_selected() || m_command == IDE_COMMAND_DIAGNOSTIC)
handle_command();
break;
}
}
}
WRITE16_MEMBER( ide_mass_storage_device::write_cs1 )
{
if (m_cur_drive != m_csel)
return;
/* logit */
LOG(("%s:IDE cs1 write to %X = %08X, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask));
if (m_dmack)
{
logerror( "%s: write_cs1 %04x %04x %04x ignored (DMACK)\n", machine().describe_context(), offset, data, mem_mask );
}
else
{
switch (offset)
{
/* adapter control */
case IDE_BANK1_STATUS_CONTROL:
m_adapter_control = data;
case IDE_CS1_DEVICE_CONTROL_W:
m_device_control = data;
if (data & 0x02)
{
// nIEN
logerror( "%s: write_cs1 %04x %04x %04x nIEN not supported\n", machine().describe_context(), offset, data, mem_mask );
}
/* handle controller reset */
//if (data == 0x04)
if (data & 0x04)
{
m_status |= IDE_STATUS_BUSY;
m_status &= ~IDE_STATUS_DRIVE_READY;
// SRST
m_status |= IDE_STATUS_BSY;
m_status &= ~IDE_STATUS_DRDY;
m_reset_timer->adjust(attotime::from_msec(5));
}
break;
}
}
}
//**************************************************************************
@ -1371,8 +1505,6 @@ ide_hdd_device::ide_hdd_device(const machine_config &mconfig, device_type type,
void ide_hdd_device::device_reset()
{
ide_mass_storage_device::device_reset();
m_handle = subdevice<harddisk_image_device>("harddisk")->get_chd_file();
if (m_handle)
@ -1385,6 +1517,8 @@ void ide_hdd_device::device_reset()
m_disk = hard_disk_open(m_handle);
}
ide_mass_storage_device::device_reset();
if (m_disk != NULL)
{
const hard_disk_info *hdinfo = hard_disk_get_info(m_disk);

View File

@ -3,12 +3,29 @@
#define IDE_DISK_SECTOR_SIZE 512
#define IDE_STATUS_ERROR 0x01
#define IDE_STATUS_HIT_INDEX 0x02
#define IDE_STATUS_BUFFER_READY 0x08
#define IDE_STATUS_SEEK_COMPLETE 0x10
#define IDE_STATUS_DRIVE_READY 0x40
#define IDE_STATUS_BUSY 0x80
// Error
#define IDE_STATUS_ERR (0x01)
// Index
#define IDE_STATUS_IDX (0x02)
// Corrected Data
#define IDE_STATUS_CORR (0x04)
// Data Request
#define IDE_STATUS_DRQ (0x08)
// Drive Seek Complete
#define IDE_STATUS_DSC (0x10)
// Drive Write Fault
#define IDE_STATUS_DWF (0x20)
// Drive Ready
#define IDE_STATUS_DRDY (0x40)
// Busy
#define IDE_STATUS_BSY (0x80)
#define IDE_ERROR_NONE 0x00
#define IDE_ERROR_DEFAULT 0x01
@ -32,6 +49,7 @@ public:
virtual void write_dma(UINT16 data) = 0;
virtual DECLARE_WRITE16_MEMBER(write_cs0) = 0;
virtual DECLARE_WRITE16_MEMBER(write_cs1) = 0;
virtual DECLARE_WRITE_LINE_MEMBER(write_dmack) = 0;
virtual DECLARE_WRITE_LINE_MEMBER(write_csel) = 0;
virtual DECLARE_WRITE_LINE_MEMBER(write_dasp) = 0;
@ -62,6 +80,7 @@ public:
virtual DECLARE_WRITE16_MEMBER(write_cs1);
virtual DECLARE_WRITE_LINE_MEMBER(write_csel);
virtual DECLARE_WRITE_LINE_MEMBER(write_dasp);
virtual DECLARE_WRITE_LINE_MEMBER(write_dmack);
virtual UINT8 *get_features() { return m_features; }
@ -75,6 +94,9 @@ protected:
virtual bool is_ready() = 0;
virtual void read_key(UINT8 key[]) = 0;
bool device_selected() { return m_cur_drive == m_csel; }
bool single_device() { return m_csel == 0 && m_dasp == 0; }
void set_irq(int state);
void set_dmarq(int state);
void ide_build_features();
@ -98,12 +120,15 @@ private:
void security_error();
void continue_read();
void read_first_sector();
void handle_command(UINT8 _command);
void handle_command();
void read_buffer_empty();
void write_buffer_full();
int m_csel;
int m_dasp;
int m_dmack;
int m_dmarq;
int m_irq;
int m_cur_drive;
UINT16 m_cur_cylinder;
@ -119,12 +144,11 @@ private:
UINT8 m_buffer[IDE_DISK_SECTOR_SIZE];
UINT16 m_buffer_offset;
UINT8 m_adapter_control;
UINT8 m_precomp_offset;
UINT8 m_device_control;
UINT8 m_feature;
UINT16 m_sector_count;
UINT16 m_block_count;
UINT8 m_interrupt_pending;
UINT16 m_sectors_until_int;
UINT8 m_dma_active;

View File

@ -1338,11 +1338,13 @@ void zn_state::atpsx_dma_read( UINT32 *p_n_psxram, UINT32 n_address, INT32 n_siz
return;
}
address_space &space = machine().firstcpu->space(AS_PROGRAM);
/* dma size is in 32-bit words, convert to words */
n_size <<= 1;
while( n_size > 0 )
{
psxwriteword( p_n_psxram, n_address, m_ide->read_dma() );
psxwriteword( p_n_psxram, n_address, m_ide->read_cs0(space, 0, 0xffff) );
n_address += 2;
n_size--;
}