Abort ATA commands when writing to command block registers and DRQ or BSY is set, which is mentioned in the ATA3 specification as a possible outcome. Removed the equivalent hack used by the cojag games. Improved the logging in the ATA code. [smf]

This commit is contained in:
smf- 2025-02-07 12:53:38 +00:00
parent d246968ffc
commit 5fcf2f031c
2 changed files with 264 additions and 370 deletions

View File

@ -3,11 +3,27 @@
#include "emu.h" #include "emu.h"
#include "atahle.h" #include "atahle.h"
#define VERBOSE 0 #define LOG_COMMAND (1U << 1)
#define PRINTF_IDE_COMMANDS 0 #define LOG_READ (1U << 2)
#define LOG_READDATA (1U << 3)
#define LOG_READSTATUS (1U << 4)
#define LOG_READCOMPLETED (1U << 5)
#define LOG_WRITE (1U << 6)
#define LOG_WRITEDATA (1U << 7)
#define LOG_WRITECOMPLETED (1U << 8)
#define LOG(x) do { if (VERBOSE) logerror x; } while (0) //#define VERBOSE (LOG_GENERAL | LOG_COMMAND | LOG_READ | LOG_WRITE | LOG_READCOMPLETED | LOG_WRITECOMPLETED)
#define LOGPRINT(x) do { if (VERBOSE) logerror x; if (PRINTF_IDE_COMMANDS) osd_printf_debug x; } while (0) //#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
#define LOGCOMMAND(...) LOGMASKED(LOG_COMMAND, __VA_ARGS__)
#define LOGREAD(...) LOGMASKED(LOG_READ, __VA_ARGS__)
#define LOGREADDATA(...) LOGMASKED(LOG_READDATA, __VA_ARGS__)
#define LOGREADSTATUS(...) LOGMASKED(LOG_READSTATUS, __VA_ARGS__)
#define LOGREADCOMPLETED(...) LOGMASKED(LOG_READCOMPLETED, __VA_ARGS__)
#define LOGWRITE(...) LOGMASKED(LOG_WRITE, __VA_ARGS__)
#define LOGWRITEDATA(...) LOGMASKED(LOG_WRITEDATA, __VA_ARGS__)
#define LOGWRITECOMPLETED(...) LOGMASKED(LOG_WRITECOMPLETED, __VA_ARGS__)
enum enum
{ {
@ -110,7 +126,6 @@ void ata_hle_device_base::device_start()
void ata_hle_device_base::device_reset() void ata_hle_device_base::device_reset()
{ {
/* reset the drive state */
set_dasp(CLEAR_LINE); set_dasp(CLEAR_LINE);
set_dmarq(CLEAR_LINE); set_dmarq(CLEAR_LINE);
set_irq(CLEAR_LINE); set_irq(CLEAR_LINE);
@ -121,9 +136,7 @@ void ata_hle_device_base::device_reset()
m_resetting = true; m_resetting = true;
if (m_csel == 0) if (m_csel == 0)
{
start_busy(DETECT_DEVICE1_TIME, PARAM_DETECT_DEVICE1); start_busy(DETECT_DEVICE1_TIME, PARAM_DETECT_DEVICE1);
}
else else
{ {
set_dasp(ASSERT_LINE); set_dasp(ASSERT_LINE);
@ -138,9 +151,7 @@ void ata_hle_device_base::soft_reset()
m_status = 0; m_status = 0;
if (is_ready()) if (is_ready())
{
m_status |= IDE_STATUS_DRDY; m_status |= IDE_STATUS_DRDY;
}
start_busy(DIAGNOSTIC_TIME, PARAM_DIAGNOSTIC); start_busy(DIAGNOSTIC_TIME, PARAM_DIAGNOSTIC);
} }
@ -198,7 +209,7 @@ void ata_hle_device_base::process_command()
break; break;
default: default:
LOGPRINT(("IDE unknown command (%02X)\n", m_command)); LOG("%s device %d process_command() unknown command (0x%02x)\n", machine().describe_context(), dev(), m_command);
m_status |= IDE_STATUS_ERR; m_status |= IDE_STATUS_ERR;
m_error = IDE_ERROR_ABRT; m_error = IDE_ERROR_ABRT;
set_irq(ASSERT_LINE); set_irq(ASSERT_LINE);
@ -221,7 +232,7 @@ void ata_hle_device_base::finished_command()
case IDE_COMMAND_SET_FEATURES: case IDE_COMMAND_SET_FEATURES:
if (!set_features()) if (!set_features())
{ {
LOGPRINT(("IDE Set features failed (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high)); LOGCOMMAND("IDE Set features failed (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high);
m_status |= IDE_STATUS_ERR; m_status |= IDE_STATUS_ERR;
m_error = IDE_ERROR_ABRT; m_error = IDE_ERROR_ABRT;
@ -234,7 +245,7 @@ void ata_hle_device_base::finished_command()
break; break;
default: default:
logerror( "finished_command() unhandled command %02x\n", m_command ); LOG("device %d finished_command() unhandled command 0x%02x\n", dev(), m_command);
break; break;
} }
} }
@ -319,10 +330,10 @@ bool ata_hle_device_base::set_features()
m_revert_to_defaults = true; m_revert_to_defaults = true;
return true; return true;
// not actually handled, but reply as if we did
case IDE_SET_FEATURES_ENABLE_ECC: case IDE_SET_FEATURES_ENABLE_ECC:
case IDE_SET_FEATURES_ENABLE_RETRIES: case IDE_SET_FEATURES_ENABLE_RETRIES:
case IDE_SET_FEATURES_ENABLE_READ_LOOK_AHEAD: case IDE_SET_FEATURES_ENABLE_READ_LOOK_AHEAD:
// not actually handled, but reply as if we did
return true; return true;
} }
@ -331,7 +342,7 @@ bool ata_hle_device_base::set_features()
int ata_hle_device_base::bit_to_mode(uint16_t word) int ata_hle_device_base::bit_to_mode(uint16_t word)
{ {
switch (word>>8) switch (word >> 8)
{ {
case 0x01: case 0x01:
return 0; return 0;
@ -347,26 +358,23 @@ int ata_hle_device_base::bit_to_mode(uint16_t word)
return 5; return 5;
case 0x40: case 0x40:
return 6; return 6;
case 0x080: case 0x80:
return 7; return 7;
} }
return -1; return -1;
} }
// Return the currently selected single word dma mode, -1 if none selected
int ata_hle_device_base::single_word_dma_mode() int ata_hle_device_base::single_word_dma_mode()
{ {
return bit_to_mode(m_identify_buffer[62]); return bit_to_mode(m_identify_buffer[62]);
} }
// Return the currently selected multi word dma mode, -1 if none selected
int ata_hle_device_base::multi_word_dma_mode() int ata_hle_device_base::multi_word_dma_mode()
{ {
return bit_to_mode(m_identify_buffer[63]); return bit_to_mode(m_identify_buffer[63]);
} }
// Return the currently selected ultra dma mode, -1 if none selected
int ata_hle_device_base::ultra_dma_mode() int ata_hle_device_base::ultra_dma_mode()
{ {
return bit_to_mode(m_identify_buffer[88]); return bit_to_mode(m_identify_buffer[88]);
@ -374,15 +382,13 @@ int ata_hle_device_base::ultra_dma_mode()
uint16_t ata_hle_device_base::read_data() uint16_t ata_hle_device_base::read_data()
{ {
/* fetch the correct amount of data */
uint16_t result = m_buffer[m_buffer_offset++]; uint16_t result = m_buffer[m_buffer_offset++];
if (!m_8bit_data_transfers) if (!m_8bit_data_transfers)
result |= m_buffer[m_buffer_offset++] << 8; result |= m_buffer[m_buffer_offset++] << 8;
/* if we're at the end of the buffer, handle it */
if (m_buffer_offset >= m_buffer_size) if (m_buffer_offset >= m_buffer_size)
{ {
LOG(("%s:IDE completed PIO read\n", machine().describe_context())); LOGREADCOMPLETED("%s device %d read_data() completed\n", machine().describe_context(), dev());
read_buffer_empty(); read_buffer_empty();
} }
@ -391,15 +397,13 @@ uint16_t ata_hle_device_base::read_data()
void ata_hle_device_base::write_data(uint16_t data) void ata_hle_device_base::write_data(uint16_t data)
{ {
/* store the correct amount of data */
m_buffer[m_buffer_offset++] = data; m_buffer[m_buffer_offset++] = data;
if (!m_8bit_data_transfers) if (!m_8bit_data_transfers)
m_buffer[m_buffer_offset++] = data >> 8; m_buffer[m_buffer_offset++] = data >> 8;
/* if we're at the end of the buffer, handle it */
if (m_buffer_offset >= m_buffer_size) if (m_buffer_offset >= m_buffer_size)
{ {
LOG(("%s:IDE completed PIO write\n", machine().describe_context())); LOGWRITECOMPLETED("%s device %d write_data() completed\n", machine().describe_context(), dev());
write_buffer_full(); write_buffer_full();
} }
} }
@ -429,12 +433,10 @@ void ata_hle_device_base::read_buffer_empty()
m_buffer_offset = 0; m_buffer_offset = 0;
m_status &= ~IDE_STATUS_DRQ; m_status &= ~IDE_STATUS_DRQ;
// Doesn't matter if we're in dma or not, when the buffer is empty
// there's no more request to be had
set_dmarq(CLEAR_LINE); set_dmarq(CLEAR_LINE);
if (ultra_dma_mode() >= 0) { if (ultra_dma_mode() >= 0)
{
m_buffer_empty_timer->enable(true); m_buffer_empty_timer->enable(true);
m_buffer_empty_timer->adjust(attotime::zero); m_buffer_empty_timer->adjust(attotime::zero);
} }
@ -447,9 +449,6 @@ void ata_hle_device_base::write_buffer_full()
m_buffer_offset = 0; m_buffer_offset = 0;
m_status &= ~IDE_STATUS_DRQ; m_status &= ~IDE_STATUS_DRQ;
// Doesn't matter if we're in dma or not, when the buffer is full
// there's no more request to be had
set_dmarq(CLEAR_LINE); set_dmarq(CLEAR_LINE);
process_buffer(); process_buffer();
@ -499,240 +498,198 @@ void ata_hle_device_base::set_pdiag_in(int state)
uint16_t ata_hle_device_base::dma_r() uint16_t ata_hle_device_base::dma_r()
{ {
uint16_t result = 0xffff;
if (device_selected()) if (device_selected())
{ {
if (!m_dmack) if (!m_dmack)
{ LOG("%s device %d dma_r 0x%04x (ignored DMACK)\n", machine().describe_context(), dev(), 0xffff);
logerror( "%s: %s dev %d read_dma ignored (!DMACK)\n", machine().describe_context(), tag(), dev() );
}
else if (m_dmarq && single_word_dma_mode() >= 0) else if (m_dmarq && single_word_dma_mode() >= 0)
{ LOG("%s device %d dma_r 0x%04x (ignored DMARQ)\n", machine().describe_context(), dev(), 0xffff);
logerror( "%s: %s dev %d read_dma ignored (DMARQ)\n", machine().describe_context(), tag(), dev() );
}
else if (!m_dmarq && multi_word_dma_mode() >= 0) else if (!m_dmarq && multi_word_dma_mode() >= 0)
{ LOG("%s device %d dma_r 0x%04x (ignored !DMARQ)\n", machine().describe_context(), dev(), 0xffff);
logerror( "%s: %s dev %d read_dma ignored (!DMARQ)\n", machine().describe_context(), tag(), dev() );
}
else if (!m_dmarq && ultra_dma_mode() >= 0) else if (!m_dmarq && ultra_dma_mode() >= 0)
{ LOG("%s device %d dma_r 0x%04x (ignored !DMARQ)\n", machine().describe_context(), dev(), 0xffff);
logerror("%s: %s dev %d read_dma ignored (!DMARQ)\n", machine().describe_context(), tag(), dev());
}
else if (m_status & IDE_STATUS_BSY) else if (m_status & IDE_STATUS_BSY)
{ LOG("%s device %d dma_r 0x%04x (ignored BSY)\n", machine().describe_context(), dev(), 0xffff);
logerror( "%s: %s dev %d read_dma ignored (BSY)\n", machine().describe_context(), tag(), dev() );
}
else if (!(m_status & IDE_STATUS_DRQ)) else if (!(m_status & IDE_STATUS_DRQ))
{ LOG("%s device %d dma_r 0x%04x (ignored !DRQ)\n", machine().describe_context(), dev(), 0xffff);
logerror( "%s: %s dev %d read_dma ignored (!DRQ)\n", machine().describe_context(), tag(), dev() );
}
else else
{ {
result = read_data(); uint16_t data = read_data();
if ((m_status & IDE_STATUS_DRQ) && single_word_dma_mode() >= 0) if ((m_status & IDE_STATUS_DRQ) && single_word_dma_mode() >= 0)
set_dmarq(ASSERT_LINE); set_dmarq(ASSERT_LINE);
LOGREADDATA("%s device %d dma_r 0x%04x\n", data);
return data;
} }
} }
return result; return 0xffff;
} }
uint16_t ata_hle_device_base::command_r(offs_t offset) uint16_t ata_hle_device_base::command_r(offs_t offset)
{ {
uint16_t result = 0xffff;
if (device_selected() || m_single_device) if (device_selected() || m_single_device)
{ {
if (m_dmack) if (m_dmack)
{ {
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
logerror( "%s: %s dev %d read_cs0 %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset ); LOG("%s device %d cs0_r (0x%x) 0x%04x (ignored DMACK)\n", machine().describe_context(), dev(), offset, 0xffff);
} }
else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_STATUS_R) else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_STATUS_R)
{ {
// ATA5 spec says status reads should also go through here, but this breaks Primal Rage 2. unsigned short busy = !device_selected() ? 0 : (offset == IDE_CS0_DATA_RW) ? 0xffff : calculate_status();
// Real hardware might work due to read ahead in the vt83c461.
if (device_selected())
{
switch (offset)
{
case IDE_CS0_DATA_RW:
if (!machine().side_effects_disabled())
logerror( "%s: %s dev %d read_cs0 %04x ignored (BSY)\n", machine().describe_context(), tag(), dev(), offset );
break;
default: if (!machine().side_effects_disabled())
result = calculate_status(); LOG("%s device %d cs0_r (0x%x) 0x%04x (ignored BSY)\n", machine().describe_context(), dev(), offset, busy);
break;
} return busy;
}
else
{
result = 0;
}
} }
else else
{ {
switch (offset) switch (offset)
{ {
/* read data if there's data to be read */ case IDE_CS0_DATA_RW:
case IDE_CS0_DATA_RW: if (device_selected() && !(m_status & IDE_STATUS_DRQ))
if (device_selected()) {
{
if (!(m_status & IDE_STATUS_DRQ))
{
if (!machine().side_effects_disabled())
logerror( "%s: %s dev %d read_cs0 ignored (!DRQ)\n", machine().describe_context(), tag(), dev() );
}
else
{
if (!machine().side_effects_disabled())
result = read_data();
else
result = 0;
}
}
else
{
result = 0;
}
break;
/* return the current error */
case IDE_CS0_ERROR_R:
result = m_error;
break;
/* return the current sector count */
case IDE_CS0_SECTOR_COUNT_RW:
result = m_sector_count;
break;
/* return the current sector */
case IDE_CS0_SECTOR_NUMBER_RW:
result = m_sector_number;
break;
/* return the current cylinder LSB */
case IDE_CS0_CYLINDER_LOW_RW:
result = m_cylinder_low;
break;
/* return the current cylinder MSB */
case IDE_CS0_CYLINDER_HIGH_RW:
result = m_cylinder_high;
break;
/* return the current head */
case IDE_CS0_DEVICE_HEAD_RW:
result = m_device_head;
break;
/* return the current status and clear any pending interrupts */
case IDE_CS0_STATUS_R:
if (device_selected())
{
result = calculate_status();
if (!(m_status & IDE_STATUS_DRDY) && is_ready())
m_status |= IDE_STATUS_DRDY;
set_irq(CLEAR_LINE);
}
else
{
result = 0;
}
break;
/* log anything else */
default:
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
logerror("%s:unknown IDE cs0 read at %03X\n", machine().describe_context(), offset); LOG("%s device %d cs0_r data !DRQ 0x%04x\n", machine().describe_context(), dev(), 0xffff);
break; }
else
{
uint16_t data = device_selected() ? read_data() : 0xffff;
LOGREADDATA("%s device %d cs0_r data 0x%04x\n", data);
return data;
}
break;
case IDE_CS0_ERROR_R:
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs0_r error register 0x%02x\n", machine().describe_context(), dev(), m_error);
return m_error;
case IDE_CS0_SECTOR_COUNT_RW:
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs0_r sector count 0x%02x\n", machine().describe_context(), dev(), m_sector_count);
return m_sector_count;
case IDE_CS0_SECTOR_NUMBER_RW:
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs0_r sector number 0x%02x\n", machine().describe_context(), dev(), m_sector_number);
return m_sector_number;
case IDE_CS0_CYLINDER_LOW_RW:
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs0_r cylinder low 0x%02x\n", machine().describe_context(), dev(), m_cylinder_low);
return m_cylinder_low;
case IDE_CS0_CYLINDER_HIGH_RW:
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs0_r cylinder high 0x%02x\n", machine().describe_context(), dev(), m_cylinder_high);
return m_cylinder_high;
case IDE_CS0_DEVICE_HEAD_RW:
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs0_r device/head 0x%02x\n", machine().describe_context(), dev(), m_device_head);
return m_device_head;
case IDE_CS0_STATUS_R:
{
uint8_t status;
if (device_selected())
{
status = calculate_status();
if (!(m_status & IDE_STATUS_DRDY) && is_ready())
m_status |= IDE_STATUS_DRDY;
set_irq(CLEAR_LINE);
}
else
status = 0;
if (!machine().side_effects_disabled())
LOGREADSTATUS("%s device %d cs0_r status 0x%04x\n", machine().describe_context(), dev(), status);
return status;
}
default:
if (!machine().side_effects_disabled())
LOG("%s device %d cs0_r unknown (0x%x) 0x%04x\n", machine().describe_context(), dev(), offset, 0xffff);
} }
} }
} }
/* logit */ return 0xffff;
// if (offset != IDE_CS0_DATA_RW && offset != IDE_CS0_STATUS_R)
if (!machine().side_effects_disabled())
LOG(("%s:IDE cs0 read %X at %X (err: %X)\n", machine().describe_context(), result, offset, m_error));
/* return the result */
return result;
} }
uint16_t ata_hle_device_base::control_r(offs_t offset) uint16_t ata_hle_device_base::control_r(offs_t offset)
{ {
/* logit */
// if (offset != IDE_CS1_ALTERNATE_STATUS_R)
if (!machine().side_effects_disabled())
LOG(("%s:IDE cs1 read at %X\n", machine().describe_context(), offset));
uint16_t result = 0xffff;
if (device_selected() || m_single_device) if (device_selected() || m_single_device)
{ {
if (m_dmack) if (m_dmack)
{ {
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
logerror( "%s: %s dev %d read_cs1 %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset ); LOG("%s device %d cs1_r (0x%x) 0x%0x (ignored DMACK)\n", machine().describe_context(), dev(), offset, 0xffff);
return 0xffff;
} }
else else
{ {
switch (offset) switch (offset)
{ {
case IDE_CS1_ALTERNATE_STATUS_R: case IDE_CS1_ALTERNATE_STATUS_R:
if (device_selected()) {
{ uint8_t status = device_selected() ? calculate_status() : 0;
result = calculate_status();
}
else
{
result = 0;
}
break;
case IDE_CS1_ACTIVE_STATUS: if (!machine().side_effects_disabled())
/* LOGREADSTATUS("%s device %d cs1_r status 0x%04x\n", machine().describe_context(), dev(), status);
return status;
}
bit description case IDE_CS1_ACTIVE_STATUS:
{
uint8_t active_status = device_selected() ? 1 : 0;
0 master active /*
1 slave active
2 complement of active disk head bit 0
3 complement of active disk head bit 1
4 complement of active disk head bit 2
5 complement of active disk head bit 3
6 write in progress
7 floppy present (unused)
*/ bit description
if (device_selected())
{
result = 0x01;
}
else
{
result = 0;
}
break;
/* log anything else */ 0 master active
default: 1 slave active
if (!machine().side_effects_disabled()) 2 complement of active disk head bit 0
logerror("%s:unknown IDE cs1 read at %03X\n", machine().describe_context(), offset); 3 complement of active disk head bit 1
break; 4 complement of active disk head bit 2
5 complement of active disk head bit 3
6 write in progress
7 floppy present (unused)
*/
if (!machine().side_effects_disabled())
LOGREAD("%s device %d cs1_r active status 0x%04x\n", machine().describe_context(), dev(), active_status);
return active_status;
}
default:
if (!machine().side_effects_disabled())
LOG("%s device %d cs1_r unknown (0x%x) 0x%04x\n", machine().describe_context(), dev(), offset, 0xffff);
return 0xffff;
} }
} }
} }
/* return the result */ return 0xffff;
return result;
} }
void ata_hle_device_base::dma_w(uint16_t data) void ata_hle_device_base::dma_w(uint16_t data)
@ -740,29 +697,17 @@ void ata_hle_device_base::dma_w(uint16_t data)
if (device_selected()) if (device_selected())
{ {
if (!m_dmack) if (!m_dmack)
{ LOG("%s device %d dma_w 0x%04x (ignored !DMACK)\n", machine().describe_context(), dev(), data);
logerror( "%s: %s dev %d write_dma %04x ignored (!DMACK)\n", machine().describe_context(), tag(), dev(), data );
}
else if (m_dmarq && single_word_dma_mode() >= 0) else if (m_dmarq && single_word_dma_mode() >= 0)
{ LOG("%s device %d dma_w 0x%04x (ignored DMARQ)\n", machine().describe_context(), dev(), data);
logerror( "%s: %s dev %d write_dma %04x ignored (DMARQ)\n", machine().describe_context(), tag(), dev(), data );
}
else if (!m_dmarq && multi_word_dma_mode() >= 0) else if (!m_dmarq && multi_word_dma_mode() >= 0)
{ LOG("%s device %d dma_w 0x%04x (ignored !DMARQ)\n", machine().describe_context(), dev(), data);
logerror( "%s: %s dev %d write_dma %04x ignored (!DMARQ)\n", machine().describe_context(), tag(), dev(), data );
}
else if (!m_dmarq && ultra_dma_mode() >= 0) else if (!m_dmarq && ultra_dma_mode() >= 0)
{ LOG("%s device %d dma_w 0x%04x (ignored !DMARQ)\n", machine().describe_context(), dev(), data);
logerror("%s: %s dev %d write_dma %04x ignored (!DMARQ)\n", machine().describe_context(), tag(), dev(), data);
}
else if (m_status & IDE_STATUS_BSY) else if (m_status & IDE_STATUS_BSY)
{ LOG("%s device %d dma_w 0x%04x (ignored BSY)\n", machine().describe_context(), dev(), data);
logerror( "%s: %s dev %d write_dma %04x ignored (BSY)\n", machine().describe_context(), tag(), dev(), data );
}
else if (!(m_status & IDE_STATUS_DRQ)) else if (!(m_status & IDE_STATUS_DRQ))
{ LOG("%s device %d dma_w 0x%04x (ignored !DRQ)\n", machine().describe_context(), dev(), data);
logerror( "%s: %s dev %d write_dma %04x ignored (!DRQ)\n", machine().describe_context(), tag(), dev(), data );
}
else else
{ {
write_data(data); write_data(data);
@ -775,164 +720,140 @@ void ata_hle_device_base::dma_w(uint16_t data)
void ata_hle_device_base::command_w(offs_t offset, uint16_t data) void ata_hle_device_base::command_w(offs_t offset, uint16_t data)
{ {
/* logit */ if ((m_status & (IDE_STATUS_DRQ | IDE_STATUS_BSY)) && offset != IDE_CS0_DATA_RW)
if (offset != IDE_CS0_DATA_RW) {
LOG(("%s:IDE cs0 write to %X = %04X\n", machine().describe_context(), offset, data)); LOGREADCOMPLETED("%s device %d cs0_w (0x%x) aborted after %d bytes\n", machine().describe_context(), dev(), offset, m_buffer_offset);
stop_busy();
m_status &= ~IDE_STATUS_DRQ;
set_dmarq(CLEAR_LINE);
m_status |= IDE_STATUS_ERR;
m_error = IDE_ERROR_ABRT;
}
if (m_dmack) if (m_dmack)
LOG("%s device %d cs0_w (0x%x) 0x%04x (ignored DMACK)\n", machine().describe_context(), dev(), offset, data);
else if (device_selected() || m_single_device)
{ {
logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, data );
}
else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_COMMAND_W)
{
logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (BSY) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
}
else if ((m_status & IDE_STATUS_DRQ) && offset != IDE_CS0_DATA_RW && offset != IDE_CS0_COMMAND_W)
{
logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (DRQ) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
}
else
{
uint8_t old;
switch (offset) switch (offset)
{ {
/* write data */ case IDE_CS0_DATA_RW:
case IDE_CS0_DATA_RW: if (m_status & IDE_STATUS_BSY)
if (device_selected()) LOG("%s device %d cs0_w data 0x%04x (ignored BSY)\n", machine().describe_context(), dev(), data);
{ if (!(m_status & IDE_STATUS_DRQ))
if (!(m_status & IDE_STATUS_DRQ)) LOG("%s device %d cs0_w data 0x%04x (ignored !DRQ)\n", machine().describe_context(), dev(), data);
{ else if (!device_selected())
logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (!DRQ)\n", machine().describe_context(), tag(), dev(), offset, data ); LOG("%s device %d cs0_w data 0x%04x (ignored !selected)\n", machine().describe_context(), dev(), data);
} else
else {
{ LOGWRITEDATA("%s device %d cs0_w data 0x%04x\n", machine().describe_context(), dev(), data);
write_data(data); write_data(data);
} }
} break;
break;
case IDE_CS0_FEATURE_W: case IDE_CS0_FEATURE_W:
m_feature = data; LOGWRITE("%s device %d cs0_w feature 0x%02x\n", machine().describe_context(), dev(), data);
break; m_feature = data;
break;
/* sector count */ case IDE_CS0_SECTOR_COUNT_RW:
case IDE_CS0_SECTOR_COUNT_RW: LOGWRITE("%s device %d cs0_w sector count 0x%02x\n", machine().describe_context(), dev(), data);
m_sector_count = (data & 0xff) ? (data & 0xff) : 0x100; m_sector_count = (data & 0xff) ? (data & 0xff) : 0x100;
break; break;
/* current sector */ case IDE_CS0_SECTOR_NUMBER_RW:
case IDE_CS0_SECTOR_NUMBER_RW: LOGWRITE("%s device %d cs0_w sector number 0x%02x\n", machine().describe_context(), dev(), data);
m_sector_number = data; m_sector_number = data;
break; break;
/* current cylinder LSB */ case IDE_CS0_CYLINDER_LOW_RW:
case IDE_CS0_CYLINDER_LOW_RW: LOGWRITE("%s device %d cs0_w cylinder low 0x%02x\n", machine().describe_context(), dev(), data);
m_cylinder_low = data; m_cylinder_low = data;
break; break;
/* current cylinder MSB */ case IDE_CS0_CYLINDER_HIGH_RW:
case IDE_CS0_CYLINDER_HIGH_RW: LOGWRITE("%s device %d cs0_w cylinder high 0x%02x\n", machine().describe_context(), dev(), data);
m_cylinder_high = data; m_cylinder_high = data;
break; break;
/* current head */ case IDE_CS0_DEVICE_HEAD_RW:
case IDE_CS0_DEVICE_HEAD_RW: {
old = m_device_head; LOGWRITE("%s device %d cs0_w device/head 0x%02x\n", machine().describe_context(), dev(), data);
m_device_head = data;
if ((m_device_head ^ old) & IDE_DEVICE_HEAD_DRV) bool drv_changed = ((m_device_head ^ data) & IDE_DEVICE_HEAD_DRV) != 0;
update_irq(); m_device_head = data;
break;
/* command */ if (drv_changed)
case IDE_CS0_COMMAND_W: update_irq();
// Packet devices can accept DEVICE RESET when BSY or DRQ is set. break;
if (m_status & IDE_STATUS_BSY) }
{
logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (BSY) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
}
else if (m_status & IDE_STATUS_DRQ)
{
logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (DRQ) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
}
else if (device_selected() || m_command == IDE_COMMAND_DIAGNOSTIC)
{
m_command = data;
m_error = IDE_ERROR_NONE;
/* implicitly clear interrupts & dmarq here */ case IDE_CS0_COMMAND_W:
set_irq(CLEAR_LINE); LOGWRITE("%s device %d cs0_w command 0x%02x\n", machine().describe_context(), dev(), data);
set_dmarq(CLEAR_LINE);
m_buffer_offset = 0; m_command = data;
m_buffer_offset = 0;
m_status &= ~IDE_STATUS_ERR;
m_error = IDE_ERROR_NONE;
set_dasp(CLEAR_LINE); set_irq(CLEAR_LINE);
m_status &= ~IDE_STATUS_DRQ; set_dasp(CLEAR_LINE);
m_status &= ~IDE_STATUS_ERR;
process_command(); if (!device_selected() && m_command != IDE_COMMAND_DIAGNOSTIC)
} LOG("%s device %d cs0_w command 0x%04x (ignored !selected)\n", machine().describe_context(), dev(), offset, data);
break; else
process_command();
break;
default: default:
logerror("%s:unknown IDE cs0 write at %03X = %04x\n", machine().describe_context(), offset, data); LOG("%s device %d cs0_w unknown (0x%x) 0x%02x\n", machine().describe_context(), dev(), offset, data);
break; break;
} }
} }
} }
void ata_hle_device_base::control_w(offs_t offset, uint16_t data) void ata_hle_device_base::control_w(offs_t offset, uint16_t data)
{ {
/* logit */
LOG(("%s:IDE cs1 write to %X = %08X\n", machine().describe_context(), offset, data));
if (m_dmack) if (m_dmack)
{ LOG("%s device %d cs1_w (0x%x) 0x%04x (ignored DMACK)\n", machine().describe_context(), dev(), offset, data);
logerror( "%s: %s dev %d write_cs1 %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, data);
}
else else
{ {
uint8_t old;
switch (offset) switch (offset)
{ {
/* adapter control */ case IDE_CS1_DEVICE_CONTROL_W:
case IDE_CS1_DEVICE_CONTROL_W: {
old = m_device_control; LOGWRITE("%s device %d cs1_w device control 0x%02x\n", machine().describe_context(), dev(), data);
m_device_control = data;
if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_NIEN) uint8_t old = m_device_control;
update_irq(); m_device_control = data;
if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_SRST) if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_NIEN)
update_irq();
if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_SRST)
{
if (m_device_control & IDE_DEVICE_CONTROL_SRST)
{ {
if (m_device_control & IDE_DEVICE_CONTROL_SRST) if (m_resetting)
LOG("%s device %d cs1_w (0x%x) %04x (ignored RESET)\n", machine().describe_context(), dev(), offset, data);
else
{ {
if (m_resetting) set_dasp(CLEAR_LINE);
{ set_dmarq(CLEAR_LINE);
logerror( "%s: %s dev %d write_cs1 %04x %04x ignored (RESET)\n", machine().describe_context(), tag(), dev(), offset, data ); set_irq(CLEAR_LINE);
} set_pdiag(CLEAR_LINE);
else
{
set_dasp(CLEAR_LINE);
set_dmarq(CLEAR_LINE);
set_irq(CLEAR_LINE);
set_pdiag(CLEAR_LINE);
start_busy(attotime::never, PARAM_RESET); start_busy(attotime::never, PARAM_RESET);
}
}
else if (m_busy_timer->param() == PARAM_RESET)
{
soft_reset();
} }
} }
break; else if (m_busy_timer->param() == PARAM_RESET)
soft_reset();
}
break;
}
default: default:
logerror("%s:unknown IDE cs1 write at %03X = %04x\n", machine().describe_context(), offset, data); LOG("%s device %d cs1_w unknown (0x%x) 0x%02x\n", machine().describe_context(), dev(), offset, data);
break; break;
} }
} }
} }

View File

@ -366,36 +366,9 @@ Notes:
* *
*************************************/ *************************************/
/// HACK: Maximum force requests data but doesn't transfer it all before issuing another command.
/// According to the ATA specification this is not allowed, more investigation is required.
DECLARE_DEVICE_TYPE(COJAG_HARDDISK, cojag_hdd)
class cojag_hdd : public ide_hdd_device
{
public:
cojag_hdd(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ide_hdd_device(mconfig, COJAG_HARDDISK, tag, owner, clock)
{
}
virtual void write_cs0(offs_t offset, uint16_t data, uint16_t mem_mask) override
{
// the first write is to the device head register
if( offset == 6 && (m_status & IDE_STATUS_DRQ))
{
m_status &= ~IDE_STATUS_DRQ;
}
ide_hdd_device::write_cs0(offset, data, mem_mask);
}
};
DEFINE_DEVICE_TYPE(COJAG_HARDDISK, cojag_hdd, "cojag_hdd", "HDD CoJag")
void cojag_devices(device_slot_interface &device) void cojag_devices(device_slot_interface &device)
{ {
device.option_add("hdd", COJAG_HARDDISK); device.option_add("hdd", IDE_HARDDISK);
} }