And in disk/hdd.c
This commit is contained in:
158
src/disk/hdd.c
158
src/disk/hdd.c
@@ -31,10 +31,13 @@
|
||||
#include <86box/video.h>
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
#define HDD_OVERHEAD_TIME 50.0
|
||||
|
||||
|
||||
hard_disk_t hdd[HDD_NUM];
|
||||
|
||||
|
||||
int
|
||||
hdd_init(void)
|
||||
{
|
||||
@@ -156,6 +159,7 @@ hdd_is_valid(int c)
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time)
|
||||
{
|
||||
@@ -169,11 +173,9 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef OLD_CODE
|
||||
double continuous_times[2][2] = { { hdd->head_switch_usec, hdd->cyl_switch_usec },
|
||||
{ zone->sector_time_usec, zone->sector_time_usec } };
|
||||
double times[2] = { HDD_OVERHEAD_TIME, hdd->avg_rotation_lat_usec };
|
||||
#endif
|
||||
|
||||
uint32_t new_track = zone->start_track + ((dst_addr - zone->start_sector) / zone->sectors_per_track);
|
||||
uint32_t new_cylinder = new_track / hdd->phy_heads;
|
||||
@@ -183,43 +185,14 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_
|
||||
continuous = continuous && sequential;
|
||||
|
||||
double seek_time = 0.0;
|
||||
if (continuous) {
|
||||
#ifdef OLD_CODE
|
||||
if (new_track == hdd->cur_track) {
|
||||
// Same track
|
||||
seek_time = zone->sector_time_usec;
|
||||
} else if (!cylinder_diff) {
|
||||
// Same cylinder, sequential track
|
||||
seek_time = hdd->head_switch_usec;
|
||||
} else {
|
||||
// Sequential cylinder
|
||||
seek_time = hdd->cyl_switch_usec;
|
||||
}
|
||||
#else
|
||||
if (continuous)
|
||||
seek_time = continuous_times[new_track == hdd->cur_track][!!cylinder_diff];
|
||||
#endif
|
||||
} else {
|
||||
if (!cylinder_diff) {
|
||||
#ifdef OLD_CODE
|
||||
if (operation != HDD_OP_SEEK) {
|
||||
seek_time = hdd->avg_rotation_lat_usec;
|
||||
} else {
|
||||
//seek_time = hdd->cyl_switch_usec;
|
||||
seek_time = HDD_OVERHEAD_TIME;
|
||||
}
|
||||
#else
|
||||
else {
|
||||
if (!cylinder_diff)
|
||||
seek_time = times[operation != HDD_OP_SEEK];
|
||||
#endif
|
||||
} else {
|
||||
#ifdef OLD_CODE
|
||||
seek_time = hdd->cyl_switch_usec + (hdd->full_stroke_usec * (double)cylinder_diff / (double)hdd->phy_cyl);
|
||||
if (operation != HDD_OP_SEEK) {
|
||||
seek_time += hdd->avg_rotation_lat_usec;
|
||||
}
|
||||
#else
|
||||
else {
|
||||
seek_time = hdd->cyl_switch_usec + (hdd->full_stroke_usec * (double)cylinder_diff / (double)hdd->phy_cyl) +
|
||||
((operation != HDD_OP_SEEK) * hdd->avg_rotation_lat_usec);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,21 +205,27 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_
|
||||
return seek_time;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hdd_readahead_update(hard_disk_t *hdd)
|
||||
{
|
||||
uint64_t elapsed_cycles;
|
||||
double elapsed_us, seek_time;
|
||||
uint32_t max_read_ahead, i;
|
||||
uint32_t space_needed;
|
||||
|
||||
hdd_cache_t *cache = &hdd->cache;
|
||||
if (cache->ra_ongoing) {
|
||||
hdd_cache_seg_t *segment = &cache->segments[cache->ra_segment];
|
||||
|
||||
uint64_t elapsed_cycles = tsc - cache->ra_start_time;
|
||||
double elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0;
|
||||
// Do not overwrite data not yet read by host
|
||||
uint32_t max_read_ahead = (segment->host_addr + cache->segment_size) - segment->ra_addr;
|
||||
elapsed_cycles = tsc - cache->ra_start_time;
|
||||
elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0;
|
||||
/* Do not overwrite data not yet read by host */
|
||||
max_read_ahead = (segment->host_addr + cache->segment_size) - segment->ra_addr;
|
||||
|
||||
double seek_time = 0.0;
|
||||
seek_time = 0.0;
|
||||
|
||||
for (uint32_t i = 0; i < max_read_ahead; i++) {
|
||||
for (i = 0; i < max_read_ahead; i++) {
|
||||
seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, elapsed_us - seek_time);
|
||||
if (seek_time > elapsed_us)
|
||||
break;
|
||||
@@ -255,16 +234,18 @@ hdd_readahead_update(hard_disk_t *hdd)
|
||||
}
|
||||
|
||||
if (segment->ra_addr > segment->lba_addr + cache->segment_size) {
|
||||
uint32_t space_needed = segment->ra_addr - (segment->lba_addr + cache->segment_size);
|
||||
space_needed = segment->ra_addr - (segment->lba_addr + cache->segment_size);
|
||||
segment->lba_addr += space_needed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static double
|
||||
hdd_writecache_flush(hard_disk_t *hdd)
|
||||
{
|
||||
double seek_time = 0.0;
|
||||
|
||||
while (hdd->cache.write_pending) {
|
||||
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0);
|
||||
hdd->cache.write_addr++;
|
||||
@@ -274,13 +255,17 @@ hdd_writecache_flush(hard_disk_t *hdd)
|
||||
return seek_time;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hdd_writecache_update(hard_disk_t *hdd)
|
||||
{
|
||||
uint64_t elapsed_cycles;
|
||||
double elapsed_us, seek_time;
|
||||
|
||||
if (hdd->cache.write_pending) {
|
||||
uint64_t elapsed_cycles = tsc - hdd->cache.write_start_time;
|
||||
double elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0;
|
||||
double seek_time = 0.0;
|
||||
elapsed_cycles = tsc - hdd->cache.write_start_time;
|
||||
elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0;
|
||||
seek_time = 0.0;
|
||||
|
||||
while (hdd->cache.write_pending) {
|
||||
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, elapsed_us - seek_time);
|
||||
@@ -293,9 +278,13 @@ hdd_writecache_update(hard_disk_t *hdd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
{
|
||||
double seek_time = 0.0;
|
||||
uint32_t flush_needed;
|
||||
|
||||
if (!hdd->speed_preset)
|
||||
return HDD_OVERHEAD_TIME;
|
||||
|
||||
@@ -304,22 +293,20 @@ hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
|
||||
hdd->cache.ra_ongoing = 0;
|
||||
|
||||
double seek_time = 0.0;
|
||||
|
||||
if (hdd->cache.write_pending && (addr != (hdd->cache.write_addr + hdd->cache.write_pending))) {
|
||||
// New request is not sequential to existing cache, need to flush it
|
||||
/* New request is not sequential to existing cache, need to flush it */
|
||||
seek_time += hdd_writecache_flush(hdd);
|
||||
}
|
||||
|
||||
if (!hdd->cache.write_pending) {
|
||||
// Cache is empty
|
||||
/* Cache is empty */
|
||||
hdd->cache.write_addr = addr;
|
||||
}
|
||||
|
||||
hdd->cache.write_pending += len;
|
||||
if (hdd->cache.write_pending > hdd->cache.write_size) {
|
||||
// If request is bigger than free cache, flush some data first
|
||||
uint32_t flush_needed = hdd->cache.write_pending - hdd->cache.write_size;
|
||||
/* If request is bigger than free cache, flush some data first */
|
||||
flush_needed = hdd->cache.write_pending - hdd->cache.write_size;
|
||||
for (uint32_t i = 0; i < flush_needed; i++) {
|
||||
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0);
|
||||
hdd->cache.write_addr++;
|
||||
@@ -331,16 +318,18 @@ hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
return seek_time;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
{
|
||||
double seek_time = 0.0;
|
||||
|
||||
if (!hdd->speed_preset)
|
||||
return HDD_OVERHEAD_TIME;
|
||||
|
||||
hdd_readahead_update(hdd);
|
||||
hdd_writecache_update(hdd);
|
||||
|
||||
double seek_time = 0.0;
|
||||
seek_time += hdd_writecache_flush(hdd);
|
||||
|
||||
hdd_cache_t *cache = &hdd->cache;
|
||||
@@ -354,7 +343,7 @@ hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
}
|
||||
|
||||
if (segment->lba_addr <= addr && (segment->lba_addr + cache->segment_size) >= addr) {
|
||||
// Cache HIT
|
||||
/* Cache HIT */
|
||||
segment->host_addr = addr;
|
||||
active_seg = segment;
|
||||
if (addr + len > segment->ra_addr) {
|
||||
@@ -365,19 +354,18 @@ hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
}
|
||||
}
|
||||
if (addr + len > segment->lba_addr + cache->segment_size) {
|
||||
// Need to erase some previously cached data
|
||||
/* Need to erase some previously cached data */
|
||||
uint32_t space_needed = (addr + len) - (segment->lba_addr + cache->segment_size);
|
||||
segment->lba_addr += space_needed;
|
||||
}
|
||||
goto update_lru;
|
||||
} else {
|
||||
if (segment->lru > active_seg->lru) {
|
||||
if (segment->lru > active_seg->lru)
|
||||
active_seg = segment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache MISS
|
||||
/* Cache MISS */
|
||||
active_seg->lba_addr = addr;
|
||||
active_seg->valid = 1;
|
||||
active_seg->host_addr = addr;
|
||||
@@ -389,9 +377,8 @@ hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
||||
}
|
||||
|
||||
update_lru:
|
||||
for (uint32_t i = 0; i < cache->num_segments; i++) {
|
||||
for (uint32_t i = 0; i < cache->num_segments; i++)
|
||||
cache->segments[i].lru++;
|
||||
}
|
||||
|
||||
active_seg->lru = 0;
|
||||
|
||||
@@ -402,15 +389,18 @@ update_lru:
|
||||
return seek_time;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hdd_cache_init(hard_disk_t *hdd)
|
||||
{
|
||||
hdd_cache_t *cache = &hdd->cache;
|
||||
uint32_t i;
|
||||
|
||||
cache->ra_segment = 0;
|
||||
cache->ra_ongoing = 0;
|
||||
cache->ra_start_time = 0;
|
||||
|
||||
for (uint32_t i = 0; i < cache->num_segments; i++) {
|
||||
for (i = 0; i < cache->num_segments; i++) {
|
||||
cache->segments[i].valid = 0;
|
||||
cache->segments[i].lru = 0;
|
||||
cache->segments[i].id = i;
|
||||
@@ -419,25 +409,28 @@ hdd_cache_init(hard_disk_t *hdd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hdd_zones_init(hard_disk_t *hdd)
|
||||
{
|
||||
uint32_t lba = 0;
|
||||
uint32_t track = 0;
|
||||
|
||||
uint32_t lba = 0, track = 0;
|
||||
uint32_t i, tracks;
|
||||
double revolution_usec = 60.0 / (double)hdd->rpm * 1000000.0;
|
||||
for (uint32_t i = 0; i < hdd->num_zones; i++) {
|
||||
hdd_zone_t *zone = &hdd->zones[i];
|
||||
hdd_zone_t *zone;
|
||||
|
||||
for (i = 0; i < hdd->num_zones; i++) {
|
||||
zone = &hdd->zones[i];
|
||||
zone->start_sector = lba;
|
||||
zone->start_track = track;
|
||||
zone->sector_time_usec = revolution_usec / (double)zone->sectors_per_track;
|
||||
uint32_t tracks = zone->cylinders * hdd->phy_heads;
|
||||
tracks = zone->cylinders * hdd->phy_heads;
|
||||
lba += tracks * zone->sectors_per_track;
|
||||
zone->end_sector = lba - 1;
|
||||
track += tracks - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static hdd_preset_t hdd_speed_presets[] = {
|
||||
{ .name = "RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
|
||||
|
||||
@@ -463,30 +456,33 @@ static hdd_preset_t hdd_speed_presets[] = {
|
||||
.full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
hdd_preset_get_num()
|
||||
{
|
||||
return sizeof(hdd_speed_presets) / sizeof(hdd_preset_t);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
hdd_preset_getname(int preset)
|
||||
{
|
||||
return (char *)hdd_speed_presets[preset].name;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
hdd_preset_get_internal_name(int preset)
|
||||
{
|
||||
return (char *)hdd_speed_presets[preset].internal_name;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hdd_preset_get_from_internal_name(char *s)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < (sizeof(hdd_speed_presets) / sizeof(hdd_preset_t)); i++) {
|
||||
if (!strcmp((char *)hdd_speed_presets[c].internal_name, s))
|
||||
return c;
|
||||
@@ -496,10 +492,15 @@ hdd_preset_get_from_internal_name(char *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hdd_preset_apply(int hdd_id)
|
||||
{
|
||||
hard_disk_t *hd = &hdd[hdd_id];
|
||||
double revolution_usec, zone_percent;
|
||||
uint32_t disk_sectors, sectors_per_surface, cylinders, cylinders_per_zone;
|
||||
uint32_t total_sectors = 0, i;
|
||||
uint32_t spt, zone_sectors;
|
||||
|
||||
if (hd->speed_preset >= hdd_preset_get_num())
|
||||
hd->speed_preset = 0;
|
||||
@@ -516,7 +517,7 @@ hdd_preset_apply(int hdd_id)
|
||||
hd->phy_heads = preset->heads;
|
||||
hd->rpm = preset->rpm;
|
||||
|
||||
double revolution_usec = 60.0 / (double)hd->rpm * 1000000.0;
|
||||
revolution_usec = 60.0 / (double)hd->rpm * 1000000.0;
|
||||
hd->avg_rotation_lat_usec = revolution_usec / 2;
|
||||
hd->full_stroke_usec = preset->full_stroke_ms * 1000;
|
||||
hd->head_switch_usec = preset->track_seek_ms * 1000;
|
||||
@@ -526,26 +527,23 @@ hdd_preset_apply(int hdd_id)
|
||||
|
||||
hd->num_zones = preset->zones;
|
||||
|
||||
uint32_t disk_sectors = hd->tracks * hd->hpc * hd->spt;
|
||||
uint32_t sectors_per_surface = (uint32_t)ceil((double)disk_sectors / (double)hd->phy_heads);
|
||||
uint32_t cylinders = (uint32_t)ceil((double)sectors_per_surface / (double)preset->avg_spt);
|
||||
disk_sectors = hd->tracks * hd->hpc * hd->spt;
|
||||
sectors_per_surface = (uint32_t)ceil((double)disk_sectors / (double)hd->phy_heads);
|
||||
cylinders = (uint32_t)ceil((double)sectors_per_surface / (double)preset->avg_spt);
|
||||
hd->phy_cyl = cylinders;
|
||||
uint32_t cylinders_per_zone = cylinders / preset->zones;
|
||||
cylinders_per_zone = cylinders / preset->zones;
|
||||
|
||||
uint32_t total_sectors = 0;
|
||||
for (uint32_t i = 0; i < preset->zones; i++) {
|
||||
uint32_t spt;
|
||||
double zone_percent = i * 100 / (double)preset->zones;
|
||||
for (i = 0; i < preset->zones; i++) {
|
||||
zone_percent = i * 100 / (double)preset->zones;
|
||||
|
||||
if (i < preset->zones - 1) {
|
||||
// Function for realistic zone sector density
|
||||
/* Function for realistic zone sector density */
|
||||
double spt_percent = -0.00341684 * pow(zone_percent, 2) - 0.175811 * zone_percent + 118.48;
|
||||
spt = (uint32_t)ceil((double)preset->avg_spt * spt_percent / 100);
|
||||
} else {
|
||||
} else
|
||||
spt = (uint32_t)ceil((double)(disk_sectors - total_sectors) / (double)(cylinders_per_zone*preset->heads));
|
||||
}
|
||||
|
||||
uint32_t zone_sectors = spt * cylinders_per_zone * preset->heads;
|
||||
zone_sectors = spt * cylinders_per_zone * preset->heads;
|
||||
total_sectors += zone_sectors;
|
||||
|
||||
hd->zones[i].cylinders = cylinders_per_zone;
|
||||
|
Reference in New Issue
Block a user