Some work on the ATA/ATAPI seek feature and related changes

- now using the more accurate name "seek latency"
- fixed CD-ROM LBA address range checks and renamed limit to "max_lba"
- make the latency for CD-ROM access variable depending on the distance between
  current and new block address, Maximum value should only occur at first access
  or after media change.
- TODO: make hard disk seek timing variable, too.
- still TODO: seek latency for USB drives (requires asynchronus packet support).
This commit is contained in:
Volker Ruppert 2014-02-09 20:28:42 +00:00
parent f6dcd04696
commit 54138f294e
3 changed files with 32 additions and 22 deletions

View File

@ -1,4 +1,4 @@
Changes after 2.6.2 (updated Jan 19, 2014):
Changes after 2.6.2 (updated Feb 09, 2014):
- CPU
- Bugfixes for CPU emulation correctness (critical fixes for VMX, TBM/BMI and RDRAND instructions)
@ -35,7 +35,7 @@ Changes after 2.6.2 (updated Jan 19, 2014):
- I/O Devices
- Hard drive / CD-ROM
- seek delay implemented for ATA/ATAPI read commands
- seek latency implemented for ATA/ATAPI read commands
- portable ISO image file access now available on all platforms
- Networking
- slirp/vnet: all supported TFTP extension options implemented now

View File

@ -393,7 +393,8 @@ void bx_hard_drive_c::init(void)
BX_INFO(("Media present in CD-ROM drive"));
BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1;
Bit32u capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity();
BX_HD_THIS channels[channel].drives[device].cdrom.capacity = capacity;
BX_HD_THIS channels[channel].drives[device].cdrom.max_lba = capacity - 1;
BX_HD_THIS channels[channel].drives[device].cdrom.next_lba = capacity - 1;
BX_INFO(("Capacity is %d sectors (%.2f MB)", capacity, (float)capacity / 512.0));
} else {
BX_INFO(("Could not locate CD-ROM, continuing with media not present"));
@ -1557,7 +1558,7 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
init_send_atapi_command(channel, atapi_command, 8, 8);
if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
Bit32u capacity = BX_SELECTED_DRIVE(channel).cdrom.capacity - 1;
Bit32u capacity = BX_SELECTED_DRIVE(channel).cdrom.max_lba;
controller->buffer[0] = (capacity >> 24) & 0xff;
controller->buffer[1] = (capacity >> 16) & 0xff;
controller->buffer[2] = (capacity >> 8) & 0xff;
@ -1595,13 +1596,18 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
case 0xf8:
controller->buffer_size = 2352;
case 0x10:
init_send_atapi_command(channel, atapi_command,
transfer_length * controller->buffer_size,
transfer_length * controller->buffer_size, 1);
BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks = transfer_length;
BX_SELECTED_DRIVE(channel).cdrom.next_lba = lba;
bx_pc_system.activate_timer(
BX_DRIVE(channel,BX_SLAVE_SELECTED(channel)).seek_timer_index, 80000, 0);
{
init_send_atapi_command(channel, atapi_command,
transfer_length * controller->buffer_size,
transfer_length * controller->buffer_size, 1);
BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks = transfer_length;
Bit32u last_lba = BX_SELECTED_DRIVE(channel).cdrom.next_lba;
Bit32u max_lba = BX_SELECTED_DRIVE(channel).cdrom.max_lba;
float seek_time = 80000.0 * (float)abs(lba - last_lba + 1) / (max_lba + 1);
BX_SELECTED_DRIVE(channel).cdrom.next_lba = lba;
bx_pc_system.activate_timer(
BX_SELECTED_DRIVE(channel).seek_timer_index, (Bit32u)seek_time, 0);
}
break;
default:
BX_ERROR(("Read CD: unknown format"));
@ -1684,15 +1690,15 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
raise_interrupt(channel);
break;
}
if (lba > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
if (lba > BX_SELECTED_DRIVE(channel).cdrom.max_lba) {
atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR, 1);
raise_interrupt(channel);
break;
}
// Ben: see comment below
if (lba + transfer_length > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
transfer_length = (BX_SELECTED_DRIVE(channel).cdrom.capacity - lba);
if ((lba + transfer_length - 1) > BX_SELECTED_DRIVE(channel).cdrom.max_lba) {
transfer_length = (BX_SELECTED_DRIVE(channel).cdrom.max_lba - lba + 1);
}
if (transfer_length <= 0) {
atapi_cmd_nop(controller);
@ -1707,7 +1713,7 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
some sort of flag/error/bitrep stating so. I haven't read the atapi specs enough to know
what needs to be done though.
if (lba + transfer_length > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
if ((lba + transfer_length - 1) > BX_SELECTED_DRIVE(channel).cdrom.max_lba) {
atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR, 1);
raise_interrupt(channel);
break;
@ -1720,9 +1726,12 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
init_send_atapi_command(channel, atapi_command, transfer_length * 2048,
transfer_length * 2048, 1);
BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks = transfer_length;
Bit32u last_lba = BX_SELECTED_DRIVE(channel).cdrom.next_lba;
Bit32u max_lba = BX_SELECTED_DRIVE(channel).cdrom.max_lba;
float seek_time = 80000.0 * (float)abs(lba - last_lba + 1) / (max_lba + 1);
BX_SELECTED_DRIVE(channel).cdrom.next_lba = lba;
bx_pc_system.activate_timer(
BX_DRIVE(channel,BX_SLAVE_SELECTED(channel)).seek_timer_index, 80000, 0);
BX_SELECTED_DRIVE(channel).seek_timer_index, (Bit32u)seek_time, 0);
}
break;
@ -1735,7 +1744,7 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
break;
}
if (lba > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
if (lba > BX_SELECTED_DRIVE(channel).cdrom.max_lba) {
atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR, 1);
raise_interrupt(channel);
break;
@ -1991,7 +2000,7 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
controller->status.corrected_data = 0;
controller->buffer_index = 0;
bx_pc_system.activate_timer(
BX_DRIVE(channel,BX_SLAVE_SELECTED(channel)).seek_timer_index, 5000, 0);
BX_SELECTED_DRIVE(channel).seek_timer_index, 5000, 0);
}
break;
@ -2371,7 +2380,7 @@ void bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
controller->status.drq = 0;
controller->status.corrected_data = 0;
bx_pc_system.activate_timer(
BX_DRIVE(channel,BX_SLAVE_SELECTED(channel)).seek_timer_index, 5000, 0);
BX_SELECTED_DRIVE(channel).seek_timer_index, 5000, 0);
DEV_ide_bmdma_start_transfer(channel);
} else {
@ -3216,7 +3225,8 @@ bx_bool bx_hard_drive_c::set_cd_media_status(Bit32u handle, bx_bool status)
BX_INFO(("Media present in CD-ROM drive"));
BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1;
Bit32u capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity();
BX_HD_THIS channels[channel].drives[device].cdrom.capacity = capacity;
BX_HD_THIS channels[channel].drives[device].cdrom.max_lba = capacity - 1;
BX_HD_THIS channels[channel].drives[device].cdrom.next_lba = capacity - 1;
BX_INFO(("Capacity is %d sectors (%.2f MB)", capacity, (float)capacity / 512.0));
SIM->get_param_enum("status", base)->set(BX_INSERTED);
BX_SELECTED_DRIVE(channel).sense.sense_key = SENSE_UNIT_ATTENTION;

View File

@ -133,8 +133,8 @@ struct cdrom_t
bx_bool ready;
bx_bool locked;
cdrom_base_c *cd;
Bit32u capacity;
int next_lba;
Bit32u max_lba;
Bit32u next_lba;
int remaining_blocks;
struct currentStruct {
error_recovery_t error_recovery;