mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge pull request #206 from TomHarte/AnalysisFailure
Corrects a couple of cases in which the CPC analyser could pick an incorrect loading command
This commit is contained in:
commit
175faebdc9
@ -812,7 +812,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
HalfCycles get_typer_frequency() {
|
||||
return Cycles(80000); // Type one character per frame.
|
||||
return Cycles(160000); // Type one character per frame.
|
||||
}
|
||||
|
||||
// See header; sets a key as either pressed or released.
|
||||
|
@ -21,16 +21,46 @@ static bool strcmp_insensitive(const char *a, const char *b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_implied_extension(const std::string &extension) {
|
||||
return
|
||||
extension == " " ||
|
||||
strcmp_insensitive(extension.c_str(), "BAS") ||
|
||||
strcmp_insensitive(extension.c_str(), "BIN");
|
||||
}
|
||||
|
||||
static std::string RunCommandFor(const Storage::Disk::CPM::File &file) {
|
||||
return "run\"" + file.name + "\n";
|
||||
// Trim spaces from the name.
|
||||
std::string name = file.name;
|
||||
name.erase(std::find_if(name.rbegin(), name.rend(), [](int ch) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), name.end());
|
||||
|
||||
// Form the basic command.
|
||||
std::string command = "run\"" + name;
|
||||
|
||||
// Consider whether the extension is required.
|
||||
if(!is_implied_extension(file.type)) {
|
||||
command += "." + file.type;
|
||||
}
|
||||
|
||||
// Add a newline and return.
|
||||
return command + "\n";
|
||||
}
|
||||
|
||||
static void InspectDataCatalogue(
|
||||
const std::unique_ptr<Storage::Disk::CPM::Catalogue> &data_catalogue,
|
||||
const Storage::Disk::CPM::Catalogue &catalogue,
|
||||
StaticAnalyser::Target &target) {
|
||||
// Make a copy of all files and filter out any that are marked as system.
|
||||
std::vector<Storage::Disk::CPM::File> candidate_files = catalogue.files;
|
||||
candidate_files.erase(
|
||||
std::remove_if(candidate_files.begin(), candidate_files.end(), [](const Storage::Disk::CPM::File &file) {
|
||||
return file.system;
|
||||
}),
|
||||
candidate_files.end());
|
||||
|
||||
// If there's just one file, run that.
|
||||
if(data_catalogue->files.size() == 1) {
|
||||
target.loadingCommand = RunCommandFor(data_catalogue->files[0]);
|
||||
if(candidate_files.size() == 1) {
|
||||
target.loadingCommand = RunCommandFor(candidate_files[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -42,30 +72,26 @@ static void InspectDataCatalogue(
|
||||
size_t last_basic_file = 0;
|
||||
size_t last_implicit_suffixed_file = 0;
|
||||
|
||||
for(size_t c = 0; c < data_catalogue->files.size(); c++) {
|
||||
for(size_t c = 0; c < candidate_files.size(); c++) {
|
||||
// Files with nothing but spaces in their name can't be loaded by the user, so disregard them.
|
||||
if(data_catalogue->files[c].type == " " && data_catalogue->files[c].name == " ")
|
||||
if(candidate_files[c].type == " " && candidate_files[c].name == " ")
|
||||
continue;
|
||||
|
||||
// Check for whether this is [potentially] BASIC.
|
||||
if(data_catalogue->files[c].data.size() >= 128 && !((data_catalogue->files[c].data[18] >> 1) & 7)) {
|
||||
if(candidate_files[c].data.size() >= 128 && !((candidate_files[c].data[18] >> 1) & 7)) {
|
||||
basic_files++;
|
||||
last_basic_file = c;
|
||||
}
|
||||
|
||||
// Check suffix for emptiness.
|
||||
if(
|
||||
data_catalogue->files[c].type == " " ||
|
||||
strcmp_insensitive(data_catalogue->files[c].type.c_str(), "BAS") ||
|
||||
strcmp_insensitive(data_catalogue->files[c].type.c_str(), "BIN")
|
||||
) {
|
||||
if(is_implied_extension(candidate_files[c].type)) {
|
||||
implicit_suffixed_files++;
|
||||
last_implicit_suffixed_file = c;
|
||||
}
|
||||
}
|
||||
if(basic_files == 1 || implicit_suffixed_files == 1) {
|
||||
size_t selected_file = (basic_files == 1) ? last_basic_file : last_implicit_suffixed_file;
|
||||
target.loadingCommand = RunCommandFor(data_catalogue->files[selected_file]);
|
||||
target.loadingCommand = RunCommandFor(candidate_files[selected_file]);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -75,16 +101,31 @@ static void InspectDataCatalogue(
|
||||
|
||||
static void InspectSystemCatalogue(
|
||||
const std::shared_ptr<Storage::Disk::Disk> &disk,
|
||||
const std::unique_ptr<Storage::Disk::CPM::Catalogue> &catalogue,
|
||||
const Storage::Disk::CPM::Catalogue &catalogue,
|
||||
StaticAnalyser::Target &target) {
|
||||
Storage::Encodings::MFM::Parser parser(true, disk);
|
||||
// Check that the boot sector exists.
|
||||
if(parser.get_sector(0, 0, 0x41) != nullptr) {
|
||||
|
||||
// Check that the boot sector exists and looks like it had content written to it.
|
||||
std::shared_ptr<Storage::Encodings::MFM::Sector> boot_sector = parser.get_sector(0, 0, 0x41);
|
||||
if(boot_sector != nullptr) {
|
||||
// Check that the first 64 bytes of the sector aren't identical; if they are then probably
|
||||
// this disk was formatted and the filler byte never replaced.
|
||||
bool matched = true;
|
||||
for(size_t c = 1; c < 64; c++) {
|
||||
if(boot_sector->data[c] != boot_sector->data[0]) {
|
||||
matched = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a system disk, then launch it as though it were CP/M.
|
||||
target.loadingCommand = "|cpm\n";
|
||||
} else {
|
||||
InspectDataCatalogue(catalogue, target);
|
||||
if(!matched) {
|
||||
target.loadingCommand = "|cpm\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
InspectDataCatalogue(catalogue, target);
|
||||
}
|
||||
|
||||
void StaticAnalyser::AmstradCPC::AddTargets(
|
||||
@ -119,7 +160,7 @@ void StaticAnalyser::AmstradCPC::AddTargets(
|
||||
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), data_format);
|
||||
if(data_catalogue) {
|
||||
InspectDataCatalogue(data_catalogue, target);
|
||||
InspectDataCatalogue(*data_catalogue, target);
|
||||
} else {
|
||||
Storage::Disk::CPM::ParameterBlock system_format;
|
||||
system_format.sectors_per_track = 9;
|
||||
@ -131,7 +172,7 @@ void StaticAnalyser::AmstradCPC::AddTargets(
|
||||
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), system_format);
|
||||
if(system_catalogue) {
|
||||
InspectSystemCatalogue(target.disks.front(), data_catalogue, target);
|
||||
InspectSystemCatalogue(target.disks.front(), *system_catalogue, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user