Enable HDD timing simulation with IDE

This commit is contained in:
Adrien Moulin
2022-07-07 23:38:45 +02:00
parent fe3061ff7a
commit 27d31c4d99
2 changed files with 94 additions and 53 deletions

View File

@@ -220,7 +220,7 @@ ide_get_drive(int ch)
double double
ide_get_period(ide_t *ide, int size) ide_get_xfer_time(ide_t *ide, int size)
{ {
double period = (10.0 / 3.0); double period = (10.0 / 3.0);
@@ -313,7 +313,7 @@ ide_atapi_get_period(uint8_t channel)
return -1.0; return -1.0;
} }
return ide_get_period(ide, 1); return ide_get_xfer_time(ide, 1);
} }
@@ -535,7 +535,7 @@ static void ide_hd_identify(ide_t *ide)
ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */
ide->buffer[0] = (1 << 6); /*Fixed drive*/ ide->buffer[0] = (1 << 6); /*Fixed drive*/
ide->buffer[20] = 3; /*Buffer type*/ ide->buffer[20] = 3; /*Buffer type*/
ide->buffer[21] = 512; /*Buffer size*/ ide->buffer[21] = hdd[ide->hdd_num].cache.num_segments * hdd[ide->hdd_num].cache.segment_size; /*Buffer size*/
ide->buffer[50] = 0x4000; /* Capabilities */ ide->buffer[50] = 0x4000; /* Capabilities */
ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0;
@@ -577,12 +577,11 @@ static void ide_hd_identify(ide_t *ide)
ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]);
} }
ide->buffer[47] = hdd[ide->hdd_num].max_multiple_block | 0x8000; /*Max sectors on multiple transfer command*/
if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board]) { if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board]) {
ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/
ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/ ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/
ide->buffer[81] = 0x19; /*ATA-6 revision 3a supported*/ ide->buffer[81] = 0x19; /*ATA-6 revision 3a supported*/
} else { } else {
ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/
ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/
} }
} }
@@ -692,13 +691,15 @@ ide_get_sector(ide_t *ide)
uint32_t heads, sectors; uint32_t heads, sectors;
if (ide->lba) if (ide->lba)
return (off64_t)ide->lba_addr + ide->skip512; return (off64_t)ide->lba_addr;
else { else {
heads = ide->cfg_hpc; heads = ide->cfg_hpc;
sectors = ide->cfg_spt; sectors = ide->cfg_spt;
uint8_t sector = ide->sector ? ide->sector : 1;
return ((((off64_t) ide->cylinder * heads) + ide->head) * return ((((off64_t) ide->cylinder * heads) + ide->head) *
sectors) + (ide->sector - 1) + ide->skip512; sectors) + (sector - 1);
} }
} }
@@ -733,6 +734,8 @@ loadhd(ide_t *ide, int d, const char *fn)
return; return;
} }
hdd_preset_auto(&hdd[d]);
ide->spt = ide->cfg_spt = hdd[d].spt; ide->spt = ide->cfg_spt = hdd[d].spt;
ide->hpc = ide->cfg_hpc = hdd[d].hpc; ide->hpc = ide->cfg_hpc = hdd[d].hpc;
ide->tracks = hdd[d].tracks; ide->tracks = hdd[d].tracks;
@@ -1226,31 +1229,41 @@ ide_write_data(ide_t *ide, uint32_t val, int length)
if (ide->type == IDE_ATAPI) if (ide->type == IDE_ATAPI)
ide_atapi_packet_write(ide, val, length); ide_atapi_packet_write(ide, val, length);
} else { } else {
switch(length) { switch(length) {
case 1: case 1:
idebufferb[ide->pos] = val & 0xff; idebufferb[ide->pos] = val & 0xff;
ide->pos++; ide->pos++;
break; break;
case 2: case 2:
idebufferw[ide->pos >> 1] = val & 0xffff; idebufferw[ide->pos >> 1] = val & 0xffff;
ide->pos += 2; ide->pos += 2;
break; break;
case 4: case 4:
idebufferl[ide->pos >> 2] = val; idebufferl[ide->pos >> 2] = val;
ide->pos += 4; ide->pos += 4;
break; break;
default: default:
return; return;
} }
if (ide->pos >= 512) { if (ide->pos >= 512) {
ide->pos=0; ide->pos=0;
ide->atastat = BSY_STAT; ide->atastat = BSY_STAT;
if (ide->command == WIN_WRITE_MULTIPLE) double seek_time = hdd_timing_write(&hdd[ide->hdd_num], ide_get_sector(ide), 1);
ide_callback(ide); double xfer_time = ide_get_xfer_time(ide, 512);
else double wait_time = seek_time + xfer_time;
ide_set_callback(ide, ide_get_period(ide, 512)); if (ide->command == WIN_WRITE_MULTIPLE) {
} if ((ide->blockcount+1) >= ide->blocksize || ide->secount == 1) {
ide_set_callback(ide, seek_time + xfer_time + ide->pending_delay);
ide->pending_delay = 0;
} else {
ide->pending_delay += wait_time;
ide_callback(ide);
}
} else {
ide_set_callback(ide, wait_time);
}
}
} }
} }
@@ -1601,9 +1614,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
else else
ide->atastat = READY_STAT | BSY_STAT; ide->atastat = READY_STAT | BSY_STAT;
if (ide->type == IDE_ATAPI) if (ide->type == IDE_ATAPI) {
ide->sc->callback = 100.0 * IDE_TIME; ide->sc->callback = 100.0 * IDE_TIME;
ide_set_callback(ide, 100.0 * IDE_TIME); ide_set_callback(ide, 100.0 * IDE_TIME);
} else {
double seek_time = hdd_seek_get_time(&hdd[ide->hdd_num], ide_get_sector(ide), HDD_OP_SEEK, 0, 0.0);
ide_set_callback(ide, seek_time);
}
return; return;
} }
@@ -1641,15 +1658,26 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide->atastat = BSY_STAT; ide->atastat = BSY_STAT;
if (ide->type == IDE_HDD) { if (ide->type == IDE_HDD) {
uint32_t sec_count;
double wait_time;
if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) {
if (ide->secount) // TODO make DMA timing more accurate
ide_set_callback(ide, ide_get_period(ide, (int) ide->secount << 9)); sec_count = ide->secount ? ide->secount : 256;
else double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count);
ide_set_callback(ide, ide_get_period(ide, 131072)); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count);
} else if (val == WIN_READ_MULTIPLE) wait_time = seek_time > xfer_time ? seek_time : xfer_time;
ide_set_callback(ide, 200.0 * IDE_TIME); } else if (val == WIN_READ_MULTIPLE) {
else sec_count = (ide->secount < ide->blocksize) ? ide->secount : ide->blocksize;
ide_set_callback(ide, ide_get_period(ide, 512)); double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count);
double xfer_time = ide_get_xfer_time(ide, 512 * sec_count);
wait_time = seek_time + xfer_time;
} else {
sec_count = 1;
double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count);
double xfer_time = ide_get_xfer_time(ide, 512 * sec_count);
wait_time = seek_time + xfer_time;
}
ide_set_callback(ide, wait_time);
} else } else
ide_set_callback(ide, 200.0 * IDE_TIME); ide_set_callback(ide, 200.0 * IDE_TIME);
ide->do_initial_read = 1; ide->do_initial_read = 1;
@@ -1690,14 +1718,16 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
if ((ide->type == IDE_HDD) && if ((ide->type == IDE_HDD) &&
((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) {
if (ide->secount) uint32_t sec_count = ide->secount ? ide->secount : 256;
ide_set_callback(ide, ide_get_period(ide, (int) ide->secount << 9)); double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count);
else double xfer_time = ide_get_xfer_time(ide, 512 * sec_count);
ide_set_callback(ide, ide_get_period(ide, 131072)); double wait_time = seek_time > xfer_time ? seek_time : xfer_time;
ide_set_callback(ide, wait_time);
} else if ((ide->type == IDE_HDD) && } else if ((ide->type == IDE_HDD) &&
((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) {
ide_set_callback(ide, ide_get_period(ide, 512)); double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), ide->secount);
else if (val == WIN_IDENTIFY) ide_set_callback(ide, seek_time + ide_get_xfer_time(ide, 2));
} else if (val == WIN_IDENTIFY)
ide_callback(ide); ide_callback(ide);
else else
ide_set_callback(ide, 200.0 * IDE_TIME); ide_set_callback(ide, 200.0 * IDE_TIME);
@@ -1864,10 +1894,20 @@ ide_read_data(ide_t *ide, int length)
if (ide->secount) { if (ide->secount) {
ide_next_sector(ide); ide_next_sector(ide);
ide->atastat = BSY_STAT | READY_STAT | DSC_STAT; ide->atastat = BSY_STAT | READY_STAT | DSC_STAT;
if (ide->command == WIN_READ_MULTIPLE) if (ide->command == WIN_READ_MULTIPLE) {
ide_callback(ide); if (!ide->blockcount) {
else uint32_t sec_count = (ide->secount < ide->blocksize) ? ide->secount : ide->blocksize;
ide_set_callback(ide, ide_get_period(ide, 512)); double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count);
double xfer_time = ide_get_xfer_time(ide, 512 * sec_count);
ide_set_callback(ide, seek_time + xfer_time);
} else {
ide_callback(ide);
}
} else {
double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), 1);
double xfer_time = ide_get_xfer_time(ide, 512);
ide_set_callback(ide, seek_time + xfer_time);
}
} else if (ide->command != WIN_READ_MULTIPLE) } else if (ide->command != WIN_READ_MULTIPLE)
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
} }

View File

@@ -49,7 +49,7 @@ typedef struct ide_s {
blocksize, blockcount, blocksize, blockcount,
hdd_num, channel, hdd_num, channel,
pos, sector_pos, pos, sector_pos,
lba, skip512, lba,
reset, mdma_mode, reset, mdma_mode,
do_initial_read; do_initial_read;
uint32_t secount, sector, uint32_t secount, sector,
@@ -67,6 +67,7 @@ typedef struct ide_s {
/* Stuff mostly used by ATAPI */ /* Stuff mostly used by ATAPI */
scsi_common_t *sc; scsi_common_t *sc;
int interrupt_drq; int interrupt_drq;
double pending_delay;
int (*get_max)(int ide_has_dma, int type); int (*get_max)(int ide_has_dma, int type);
int (*get_timings)(int ide_has_dma, int type); int (*get_timings)(int ide_has_dma, int type);