From 9d9a1c341d8f86fc93c0bd684a006d38b59bdbb6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 16 Aug 2017 21:55:31 -0400 Subject: [PATCH 1/4] Added an extra test to try to avoid spurious |cpm launches. --- StaticAnalyser/AmstradCPC/StaticAnalyser.cpp | 51 +++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp index 8d76afe68..45f781390 100644 --- a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp +++ b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp @@ -26,11 +26,11 @@ static std::string RunCommandFor(const Storage::Disk::CPM::File &file) { } static void InspectDataCatalogue( - const std::unique_ptr &data_catalogue, + const Storage::Disk::CPM::Catalogue &catalogue, StaticAnalyser::Target &target) { // If there's just one file, run that. - if(data_catalogue->files.size() == 1) { - target.loadingCommand = RunCommandFor(data_catalogue->files[0]); + if(catalogue.files.size() == 1) { + target.loadingCommand = RunCommandFor(catalogue.files[0]); return; } @@ -42,22 +42,22 @@ 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 < catalogue.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(catalogue.files[c].type == " " && catalogue.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(catalogue.files[c].data.size() >= 128 && !((catalogue.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") + catalogue.files[c].type == " " || + strcmp_insensitive(catalogue.files[c].type.c_str(), "BAS") || + strcmp_insensitive(catalogue.files[c].type.c_str(), "BIN") ) { implicit_suffixed_files++; last_implicit_suffixed_file = c; @@ -65,7 +65,7 @@ static void InspectDataCatalogue( } 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(catalogue.files[selected_file]); return; } @@ -75,16 +75,31 @@ static void InspectDataCatalogue( static void InspectSystemCatalogue( const std::shared_ptr &disk, - const std::unique_ptr &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 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 +134,7 @@ void StaticAnalyser::AmstradCPC::AddTargets( std::unique_ptr 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 +146,7 @@ void StaticAnalyser::AmstradCPC::AddTargets( std::unique_ptr 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); } } } From 48290a8bbe6c0945b8897c8a43c0e509b32f5af4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 16 Aug 2017 22:11:49 -0400 Subject: [PATCH 2/4] Added a prefilter to catalogues to remove system files. They're not listed when you `CAT`, so almost certainly aren't what a user would be expected to load. --- StaticAnalyser/AmstradCPC/StaticAnalyser.cpp | 26 +++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp index 45f781390..a8c423755 100644 --- a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp +++ b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp @@ -28,9 +28,17 @@ static std::string RunCommandFor(const Storage::Disk::CPM::File &file) { static void InspectDataCatalogue( 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 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(catalogue.files.size() == 1) { - target.loadingCommand = RunCommandFor(catalogue.files[0]); + if(candidate_files.size() == 1) { + target.loadingCommand = RunCommandFor(candidate_files[0]); return; } @@ -42,22 +50,22 @@ static void InspectDataCatalogue( size_t last_basic_file = 0; size_t last_implicit_suffixed_file = 0; - for(size_t c = 0; c < 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(catalogue.files[c].type == " " && catalogue.files[c].name == " ") + if(candidate_files[c].type == " " && candidate_files[c].name == " ") continue; // Check for whether this is [potentially] BASIC. - if(catalogue.files[c].data.size() >= 128 && !((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( - catalogue.files[c].type == " " || - strcmp_insensitive(catalogue.files[c].type.c_str(), "BAS") || - strcmp_insensitive(catalogue.files[c].type.c_str(), "BIN") + candidate_files[c].type == " " || + strcmp_insensitive(candidate_files[c].type.c_str(), "BAS") || + strcmp_insensitive(candidate_files[c].type.c_str(), "BIN") ) { implicit_suffixed_files++; last_implicit_suffixed_file = c; @@ -65,7 +73,7 @@ static void InspectDataCatalogue( } 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(catalogue.files[selected_file]); + target.loadingCommand = RunCommandFor(candidate_files[selected_file]); return; } From b476f06524fb113641e70eb78f1a6fba48357928 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 16 Aug 2017 22:12:16 -0400 Subject: [PATCH 3/4] Slowed the typer, having discovered that otherwise it has problems transitioning from a shifted to an unshifted character. --- Machines/AmstradCPC/AmstradCPC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index c1f1476b0..f3900e1f6 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -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. From 76c6b715a2c338fcced9a2eeabfbd9f01820dbbb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 16 Aug 2017 22:24:37 -0400 Subject: [PATCH 4/4] Adjusted rules so as not to type unnecessary spaces in the name, and to include the extension if AMSDOS won't imply it. --- StaticAnalyser/AmstradCPC/StaticAnalyser.cpp | 30 ++++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp index a8c423755..5fec52032 100644 --- a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp +++ b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp @@ -21,8 +21,30 @@ 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( @@ -62,11 +84,7 @@ static void InspectDataCatalogue( } // Check suffix for emptiness. - if( - candidate_files[c].type == " " || - strcmp_insensitive(candidate_files[c].type.c_str(), "BAS") || - strcmp_insensitive(candidate_files[c].type.c_str(), "BIN") - ) { + if(is_implied_extension(candidate_files[c].type)) { implicit_suffixed_files++; last_implicit_suffixed_file = c; }