hdd: make speed preset configurable

This includes settings UI for Qt
This commit is contained in:
Adrien Moulin
2022-07-19 11:31:06 +02:00
parent efdf003272
commit 46f6540542
12 changed files with 206 additions and 63 deletions

View File

@@ -1378,6 +1378,18 @@ load_hard_disks(void)
if (hdd[c].tracks > max_tracks)
hdd[c].tracks = max_tracks;
sprintf(temp, "hdd_%02i_speed", c+1);
switch (hdd[c].bus) {
case HDD_BUS_IDE:
sprintf(tmp2, "1997_5400rpm");
break;
default:
sprintf(tmp2, "ramdisk");
break;
}
p = config_get_string(cat, temp, tmp2);
hdd[c].speed_preset = hdd_preset_get_from_internal_name(p);
/* MFM/RLL */
sprintf(temp, "hdd_%02i_mfm_channel", c+1);
if (hdd[c].bus == HDD_BUS_MFM)
@@ -2918,6 +2930,13 @@ save_hard_disks(void)
}
else
config_delete_var(cat, temp);
sprintf(temp, "hdd_%02i_speed", c+1);
if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE))
config_delete_var(cat, temp);
else
config_set_string(cat, temp, hdd_preset_get_internal_name(hdd[c].speed_preset));
}
delete_section_if_empty(cat);

View File

@@ -734,7 +734,7 @@ loadhd(ide_t *ide, int d, const char *fn)
return;
}
hdd_preset_auto(&hdd[d]);
hdd_preset_apply(d);
ide->spt = ide->cfg_spt = hdd[d].spt;
ide->hpc = ide->cfg_hpc = hdd[d].hpc;

View File

@@ -31,8 +31,9 @@
#include <86box/video.h>
#include "cpu.h"
hard_disk_t hdd[HDD_NUM];
#define HDD_OVERHEAD_TIME 50.0
hard_disk_t hdd[HDD_NUM];
int
hdd_init(void)
@@ -158,6 +159,9 @@ hdd_is_valid(int c)
double
hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time)
{
if (!hdd->speed_preset)
return HDD_OVERHEAD_TIME;
hdd_zone_t *zone = NULL;
for (int i = 0; i < hdd->num_zones; i++) {
zone = &hdd->zones[i];
@@ -168,7 +172,7 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_
#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] = { 50.0, hdd->avg_rotation_lat_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);
@@ -201,7 +205,7 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_
seek_time = hdd->avg_rotation_lat_usec;
} else {
//seek_time = hdd->cyl_switch_usec;
seek_time = 50.0;
seek_time = HDD_OVERHEAD_TIME;
}
#else
seek_time = times[operation != HDD_OP_SEEK];
@@ -292,6 +296,9 @@ hdd_writecache_update(hard_disk_t *hdd)
double
hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
{
if (!hdd->speed_preset)
return HDD_OVERHEAD_TIME;
hdd_readahead_update(hdd);
hdd_writecache_update(hdd);
@@ -327,6 +334,9 @@ hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
double
hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
{
if (!hdd->speed_preset)
return HDD_OVERHEAD_TIME;
hdd_readahead_update(hdd);
hdd_writecache_update(hdd);
@@ -388,7 +398,7 @@ update_lru:
cache->ra_ongoing = 1;
cache->ra_segment = active_seg->id;
cache->ra_start_time = tsc + (uint32_t)(seek_time * cpuclock / 1000000.0);
return seek_time;
}
@@ -414,7 +424,7 @@ hdd_zones_init(hard_disk_t *hdd)
{
uint32_t lba = 0;
uint32_t track = 0;
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];
@@ -428,53 +438,98 @@ hdd_zones_init(hard_disk_t *hdd)
}
}
hdd_preset_t hdd_presets[] = {
{ .target_year = 1989, .match_max_mbyte = 99, .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8,
.rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 },
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 },
{ .target_year = 1992, .match_max_mbyte = 249, .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3500, .full_stroke_ms = 30, .track_seek_ms = 6,
.rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 },
{ .name = "[1989] 3500 RPM", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500,
.full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 },
{ .target_year = 1994, .match_max_mbyte = 999, .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5,
.rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 },
{ .name = "[1992] 3600 RPM", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600,
.full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 },
{ .target_year = 1996, .match_max_mbyte = 1999, .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3,
.rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 },
{ .name = "[1994] 4500 RPM", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500,
.full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 },
{ .target_year = 1997, .match_max_mbyte = 4999, .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5,
.rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 },
{ .name = "[1996] 5400 RPM", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400,
.full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 },
{ .target_year = 1998, .match_max_mbyte = 9999, .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2,
.rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 },
{ .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400,
.full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 },
{ .target_year = 2000, .match_max_mbyte = 99999, .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2,
.rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
{ .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400,
.full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 },
{ .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200,
.full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
};
void
hdd_preset_apply(hard_disk_t *hdd, hdd_preset_t *preset)
int
hdd_preset_get_num()
{
hdd->phy_heads = preset->heads;
hdd->rpm = preset->rpm;
return sizeof(hdd_speed_presets) / sizeof(hdd_preset_t);
}
double revolution_usec = 60.0 / (double)hdd->rpm * 1000000.0;
hdd->avg_rotation_lat_usec = revolution_usec / 2;
hdd->full_stroke_usec = preset->full_stroke_ms * 1000;
hdd->head_switch_usec = preset->track_seek_ms * 1000;
hdd->cyl_switch_usec = preset->track_seek_ms * 1000;
char *
hdd_preset_getname(int preset)
{
return (char *)hdd_speed_presets[preset].name;
}
hdd->cache.num_segments = preset->rcache_num_seg;
hdd->cache.segment_size = preset->rcache_seg_size;
hdd->max_multiple_block = preset->max_multiple;
char *
hdd_preset_get_internal_name(int preset)
{
return (char *)hdd_speed_presets[preset].internal_name;
}
hdd->cache.write_size = 64;
int
hdd_preset_get_from_internal_name(char *s)
{
int c = 0;
hdd->num_zones = preset->zones;
uint32_t disk_sectors = hdd->tracks * hdd->hpc * hdd->spt;
uint32_t sectors_per_surface = (uint32_t)ceil((double)disk_sectors / (double)hdd->phy_heads);
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;
c++;
}
return 0;
}
void
hdd_preset_apply(int hdd_id)
{
hard_disk_t *hd = &hdd[hdd_id];
if (hd->speed_preset >= hdd_preset_get_num())
hd->speed_preset = 0;
hdd_preset_t *preset = &hdd_speed_presets[hd->speed_preset];
hd->cache.num_segments = preset->rcache_num_seg;
hd->cache.segment_size = preset->rcache_seg_size;
hd->max_multiple_block = preset->max_multiple;
if (!hd->speed_preset)
return;
hd->phy_heads = preset->heads;
hd->rpm = preset->rpm;
double 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;
hd->cyl_switch_usec = preset->track_seek_ms * 1000;
hd->cache.write_size = 64;
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);
hdd->phy_cyl = cylinders;
hd->phy_cyl = cylinders;
uint32_t cylinders_per_zone = cylinders / preset->zones;
uint32_t total_sectors = 0;
@@ -493,26 +548,10 @@ hdd_preset_apply(hard_disk_t *hdd, hdd_preset_t *preset)
uint32_t zone_sectors = spt * cylinders_per_zone * preset->heads;
total_sectors += zone_sectors;
hdd->zones[i].cylinders = cylinders_per_zone;
hdd->zones[i].sectors_per_track = spt;
hd->zones[i].cylinders = cylinders_per_zone;
hd->zones[i].sectors_per_track = spt;
}
hdd_zones_init(hdd);
hdd_cache_init(hdd);
}
void
hdd_preset_auto(hard_disk_t *hdd)
{
uint32_t disk_sectors = hdd->tracks * hdd->hpc * hdd->spt;
uint32_t disk_size_mb = disk_sectors * 512 / 1024 / 1024;
int i;
for (i = 0; i < (sizeof(hdd_presets) / sizeof(hdd_presets[0])); i++) {
if (hdd_presets[i].match_max_mbyte >= disk_size_mb)
break;
}
hdd_preset_t *preset = &hdd_presets[i];
hdd_preset_apply(hdd, preset);
hdd_zones_init(hd);
hdd_cache_init(hd);
}

View File

@@ -82,12 +82,12 @@ enum {
#define HDD_MAX_CACHE_SEG 16
typedef struct {
uint32_t match_max_mbyte;
const char *name;
const char *internal_name;
uint32_t zones;
uint32_t avg_spt;
uint32_t heads;
uint32_t rpm;
uint32_t target_year;
uint32_t rcache_num_seg;
uint32_t rcache_seg_size;
uint32_t max_multiple;
@@ -169,6 +169,8 @@ typedef struct {
uint32_t cur_track;
uint32_t cur_addr;
uint32_t speed_preset;
double avg_rotation_lat_usec;
double full_stroke_usec;
double head_switch_usec;
@@ -207,7 +209,10 @@ extern int image_is_vhd(const char *s, int check_signature);
extern double hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len);
extern double hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len);
extern double hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time);
extern void hdd_preset_apply(hard_disk_t *hdd, hdd_preset_t *preset);
extern void hdd_preset_auto(hard_disk_t *hdd);
int hdd_preset_get_num();
char * hdd_preset_getname(int preset);
extern char *hdd_preset_get_internal_name(int preset);
extern int hdd_preset_get_from_internal_name(char *s);
extern void hdd_preset_apply(int hdd_id);
#endif /*EMU_HDD_H*/

View File

@@ -138,6 +138,10 @@ QString HarddiskDialog::fileName() const {
return ui->fileField->fileName();
}
uint32_t HarddiskDialog::speed() const {
return static_cast<uint32_t>(ui->comboBoxSpeed->currentData().toUInt());
}
void HarddiskDialog::on_comboBoxFormat_currentIndexChanged(int index) {
bool enabled;
if (index == 5) { /* They switched to a diff VHD; disable the geometry fields. */
@@ -700,6 +704,8 @@ void HarddiskDialog::on_comboBoxBus_currentIndexChanged(int index) {
ui->lineEditSectors->setValidator(new QIntValidator(1, max_sectors, this));
Harddrives::populateBusChannels(ui->comboBoxChannel->model(), ui->comboBoxBus->currentData().toInt());
Harddrives::populateSpeeds(ui->comboBoxSpeed->model(), ui->comboBoxBus->currentData().toInt());
switch (ui->comboBoxBus->currentData().toInt())
{
case HDD_BUS_MFM:

View File

@@ -21,6 +21,7 @@ public:
uint32_t cylinders() const { return cylinders_; }
uint32_t heads() const { return heads_; }
uint32_t sectors() const { return sectors_; }
uint32_t speed() const;
signals:
void fileProgress(int i);

View File

@@ -42,6 +42,16 @@
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Speed:</string>
</property>
</widget>
</item>
<item row="6" column="5">
<widget class="QComboBox" name="comboBoxSpeed"/>
</item>
<item row="3" column="4">
<widget class="QLabel" name="label_5">
<property name="text">

View File

@@ -54,6 +54,27 @@ void Harddrives::populateRemovableBuses(QAbstractItemModel *model) {
model->setData(model->index(2, 0), HDD_BUS_SCSI, Qt::UserRole);
}
void Harddrives::populateSpeeds(QAbstractItemModel *model, int bus) {
int num_preset;
switch (bus) {
case HDD_BUS_IDE:
num_preset = hdd_preset_get_num();
break;
default:
num_preset = 1;
}
model->removeRows(0, model->rowCount());
model->insertRows(0, num_preset);
for (int i = 0; i < num_preset; i++) {
model->setData(model->index(i, 0), QObject::tr(hdd_preset_getname(i)));
model->setData(model->index(i, 0), i, Qt::UserRole);
}
}
void Harddrives::populateBusChannels(QAbstractItemModel *model, int bus) {
model->removeRows(0, model->rowCount());

View File

@@ -10,6 +10,7 @@ namespace Harddrives {
void populateBuses(QAbstractItemModel* model);
void populateRemovableBuses(QAbstractItemModel* model);
void populateBusChannels(QAbstractItemModel* model, int bus);
void populateSpeeds(QAbstractItemModel* model, int bus);
QString BusChannelName(uint8_t bus, uint8_t channel);
inline SettingsBusTracking* busTrackClass = nullptr;
};

View File

@@ -37,6 +37,7 @@ const int ColumnCylinders = 2;
const int ColumnHeads = 3;
const int ColumnSectors = 4;
const int ColumnSize = 5;
const int ColumnSpeed = 6;
const int DataBus = Qt::UserRole;
const int DataBusChannel = Qt::UserRole + 1;
@@ -94,6 +95,8 @@ static void addRow(QAbstractItemModel* model, hard_disk_t* hd) {
model->setData(model->index(row, ColumnHeads), hd->hpc);
model->setData(model->index(row, ColumnSectors), hd->spt);
model->setData(model->index(row, ColumnSize), (hd->tracks * hd->hpc * hd->spt) >> 11);
model->setData(model->index(row, ColumnSpeed), hdd_preset_getname(hd->speed_preset));
model->setData(model->index(row, ColumnSpeed), hd->speed_preset, Qt::UserRole);
}
SettingsHarddisks::SettingsHarddisks(QWidget *parent) :
@@ -102,13 +105,14 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) :
{
ui->setupUi(this);
QAbstractItemModel* model = new QStandardItemModel(0, 6, this);
QAbstractItemModel* model = new QStandardItemModel(0, 7, this);
model->setHeaderData(ColumnBus, Qt::Horizontal, tr("Bus"));
model->setHeaderData(ColumnFilename, Qt::Horizontal, tr("File"));
model->setHeaderData(ColumnCylinders, Qt::Horizontal, tr("C"));
model->setHeaderData(ColumnHeads, Qt::Horizontal, tr("H"));
model->setHeaderData(ColumnSectors, Qt::Horizontal, tr("S"));
model->setHeaderData(ColumnSize, Qt::Horizontal, tr("MiB"));
model->setHeaderData(ColumnSpeed, Qt::Horizontal, tr("Speed"));
ui->tableView->setModel(model);
for (int i = 0; i < HDD_NUM; i++) {
@@ -149,6 +153,7 @@ void SettingsHarddisks::save() {
hdd[i].tracks = idx.siblingAtColumn(ColumnCylinders).data().toUInt();
hdd[i].hpc = idx.siblingAtColumn(ColumnHeads).data().toUInt();
hdd[i].spt = idx.siblingAtColumn(ColumnSectors).data().toUInt();
hdd[i].speed_preset = idx.siblingAtColumn(ColumnSpeed).data(Qt::UserRole).toUInt();
QByteArray fileName = idx.siblingAtColumn(ColumnFilename).data(Qt::UserRole).toString().toUtf8();
strncpy(hdd[i].fn, fileName.data(), sizeof(hdd[i].fn) - 1);
@@ -173,6 +178,7 @@ void SettingsHarddisks::on_comboBoxBus_currentIndexChanged(int index) {
}
Harddrives::populateBusChannels(ui->comboBoxChannel->model(), ui->comboBoxBus->currentData().toInt());
Harddrives::populateSpeeds(ui->comboBoxSpeed->model(), ui->comboBoxBus->currentData().toInt());
int chanIdx = 0;
switch (ui->comboBoxBus->currentData().toInt())
@@ -221,15 +227,32 @@ void SettingsHarddisks::on_comboBoxChannel_currentIndexChanged(int index) {
}
}
void SettingsHarddisks::on_comboBoxSpeed_currentIndexChanged(int index) {
if (index < 0) {
return;
}
auto idx = ui->tableView->selectionModel()->currentIndex();
if (idx.isValid()) {
auto* model = ui->tableView->model();
auto col = idx.siblingAtColumn(ColumnSpeed);
model->setData(col, ui->comboBoxSpeed->currentData(Qt::UserRole), Qt::UserRole);
model->setData(col, hdd_preset_getname(ui->comboBoxSpeed->currentData(Qt::UserRole).toUInt()));
}
}
void SettingsHarddisks::onTableRowChanged(const QModelIndex &current) {
bool hidden = !current.isValid();
ui->labelBus->setHidden(hidden);
ui->labelChannel->setHidden(hidden);
ui->labelSpeed->setHidden(hidden);
ui->comboBoxBus->setHidden(hidden);
ui->comboBoxChannel->setHidden(hidden);
ui->comboBoxSpeed->setHidden(hidden);
uint32_t bus = current.siblingAtColumn(ColumnBus).data(DataBus).toUInt();
uint32_t busChannel = current.siblingAtColumn(ColumnBus).data(DataBusChannel).toUInt();
uint32_t speed = current.siblingAtColumn(ColumnSpeed).data(Qt::UserRole).toUInt();
auto* model = ui->comboBoxBus->model();
auto match = model->match(model->index(0, 0), Qt::UserRole, bus);
@@ -241,6 +264,12 @@ void SettingsHarddisks::onTableRowChanged(const QModelIndex &current) {
if (! match.isEmpty()) {
ui->comboBoxChannel->setCurrentIndex(match.first().row());
}
model = ui->comboBoxSpeed->model();
match = model->match(model->index(0, 0), Qt::UserRole, speed);
if (! match.isEmpty()) {
ui->comboBoxSpeed->setCurrentIndex(match.first().row());
}
}
static void addDriveFromDialog(Ui::SettingsHarddisks* ui, const HarddiskDialog& dlg) {
@@ -255,6 +284,7 @@ static void addDriveFromDialog(Ui::SettingsHarddisks* ui, const HarddiskDialog&
hd.hpc = dlg.heads();
hd.spt = dlg.sectors();
strncpy(hd.fn, fn.data(), sizeof(hd.fn) - 1);
hd.speed_preset = dlg.speed();
addRow(ui->tableView->model(), &hd);
ui->tableView->resizeColumnsToContents();

View File

@@ -19,6 +19,7 @@ public:
private slots:
void on_comboBoxChannel_currentIndexChanged(int index);
void on_comboBoxSpeed_currentIndexChanged(int index);
private slots:
void on_pushButtonRemove_clicked();

View File

@@ -64,6 +64,16 @@
<item>
<widget class="QComboBox" name="comboBoxChannel"/>
</item>
<item>
<widget class="QLabel" name="labelSpeed">
<property name="text">
<string>Speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSpeed"/>
</item>
</layout>
</item>
<item>