diff --git a/Analyser/Machines.hpp b/Analyser/Machines.hpp index 280994c17..9a0c41fe7 100644 --- a/Analyser/Machines.hpp +++ b/Analyser/Machines.hpp @@ -17,6 +17,7 @@ enum class Machine { Atari2600, AtariST, Amiga, + Archimedes, ColecoVision, Electron, Enterprise, diff --git a/Analyser/Static/Acorn/Disk.cpp b/Analyser/Static/Acorn/Disk.cpp index 5e06708e4..a80771cb6 100644 --- a/Analyser/Static/Acorn/Disk.cpp +++ b/Analyser/Static/Acorn/Disk.cpp @@ -87,37 +87,45 @@ std::unique_ptr Analyser::Static::Acorn::GetADFSCatalogue(const std:: auto catalogue = std::make_unique(); Storage::Encodings::MFM::Parser parser(Storage::Encodings::MFM::Density::Double, disk); - const Storage::Encodings::MFM::Sector *free_space_map_second_half = parser.sector(0, 0, 1); + // Grab the second half of the free-space map because it has the boot option in it. + const Storage::Encodings::MFM::Sector *const free_space_map_second_half = parser.sector(0, 0, 1); if(!free_space_map_second_half) return nullptr; + const bool has_large_sectors = free_space_map_second_half->samples[0].size() == 1024; std::vector root_directory; - root_directory.reserve(5 * 256); - for(uint8_t c = 2; c < 7; c++) { + root_directory.reserve((has_large_sectors ? 5 : 8) * 256); + + for(uint8_t c = 2; c < (has_large_sectors ? 4 : 7); c++) { const Storage::Encodings::MFM::Sector *const sector = parser.sector(0, 0, c); if(!sector) return nullptr; root_directory.insert(root_directory.end(), sector->samples[0].begin(), sector->samples[0].end()); } - // Quick sanity checks. - if(root_directory[0x4cb]) return nullptr; - catalogue->is_hugo = !memcmp(&root_directory[1], "Hugo", 4) && !memcmp(&root_directory[0x4FB], "Hugo", 4); - const bool is_nick = !memcmp(&root_directory[1], "Nick", 4) && !memcmp(&root_directory[0x4FB], "Nick", 4); + // Check for end of directory marker. + if(root_directory[has_large_sectors ? 0x7d7 : 0x4cb]) return nullptr; + + // Check for both directory identifiers. + catalogue->is_hugo = !memcmp(&root_directory[1], "Hugo", 4) && !memcmp(&root_directory[0x4fb], "Hugo", 4); + const bool is_nick = !memcmp(&root_directory[1], "Nick", 4) && !memcmp(&root_directory[0x7fb], "Nick", 4); if(!catalogue->is_hugo && !is_nick) { return nullptr; } - switch(free_space_map_second_half->samples[0][0xfd]) { - default: catalogue->bootOption = Catalogue::BootOption::None; break; - case 1: catalogue->bootOption = Catalogue::BootOption::LoadBOOT; break; - case 2: catalogue->bootOption = Catalogue::BootOption::RunBOOT; break; - case 3: catalogue->bootOption = Catalogue::BootOption::ExecBOOT; break; + if(!has_large_sectors) { + // TODO: I don't know where the boot option rests with large sectors. + switch(free_space_map_second_half->samples[0][0xfd]) { + default: catalogue->bootOption = Catalogue::BootOption::None; break; + case 1: catalogue->bootOption = Catalogue::BootOption::LoadBOOT; break; + case 2: catalogue->bootOption = Catalogue::BootOption::RunBOOT; break; + case 3: catalogue->bootOption = Catalogue::BootOption::ExecBOOT; break; + } } // Parse the root directory, at least. - for(std::size_t file_offset = 0x005; file_offset < 0x4cb; file_offset += 0x1a) { + for(std::size_t file_offset = 0x005; file_offset < (has_large_sectors ? 0x7d7 : 0x4cb); file_offset += 0x1a) { // Obtain the name, which will be at most ten characters long, and will // be terminated by either a NULL character or a \r. - char name[11]; + char name[11]{}; std::size_t c = 0; for(; c < 10; c++) { const char next = root_directory[file_offset + c] & 0x7f; diff --git a/Analyser/Static/Acorn/StaticAnalyser.cpp b/Analyser/Static/Acorn/StaticAnalyser.cpp index 7246972de..f07d7fffc 100644 --- a/Analyser/Static/Acorn/StaticAnalyser.cpp +++ b/Analyser/Static/Acorn/StaticAnalyser.cpp @@ -60,10 +60,11 @@ static std::vector> } Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) { - auto target = std::make_unique(); + auto target8bit = std::make_unique(); + auto targetArchimedes = std::make_unique(Machine::Archimedes); - // Strip out inappropriate cartridges. - target->media.cartridges = AcornCartridgesFrom(media.cartridges); + // Copy appropriate cartridges to the 8-bit target. + target8bit->media.cartridges = AcornCartridgesFrom(media.cartridges); // If there are any tapes, attempt to get data from the first. if(!media.tapes.empty()) { @@ -94,9 +95,9 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me // Inspect first file. If it's protected or doesn't look like BASIC // then the loading command is *RUN. Otherwise it's CHAIN"". - target->loading_command = is_basic ? "CHAIN\"\"\n" : "*RUN\n"; + target8bit->loading_command = is_basic ? "CHAIN\"\"\n" : "*RUN\n"; - target->media.tapes = media.tapes; + target8bit->media.tapes = media.tapes; } } @@ -112,16 +113,16 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me if(dfs_catalogue || (adfs_catalogue && adfs_catalogue->is_hugo)) { // Accept the disk and determine whether DFS or ADFS ROMs are implied. // Use the Pres ADFS if using an ADFS, as it leaves Page at &EOO. - target->media.disks = media.disks; - target->has_dfs = bool(dfs_catalogue); - target->has_pres_adfs = bool(adfs_catalogue); + target8bit->media.disks = media.disks; + target8bit->has_dfs = bool(dfs_catalogue); + target8bit->has_pres_adfs = bool(adfs_catalogue); // Check whether a simple shift+break will do for loading this disk. Catalogue::BootOption bootOption = (dfs_catalogue ?: adfs_catalogue)->bootOption; if(bootOption != Catalogue::BootOption::None) { - target->should_shift_restart = true; + target8bit->should_shift_restart = true; } else { - target->loading_command = "*CAT\n"; + target8bit->loading_command = "*CAT\n"; } // Check whether adding the AP6 ROM is justified. @@ -137,39 +138,44 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me "VERIFY", "ZERO" }) { if(std::search(file.data.begin(), file.data.end(), command, command+strlen(command)) != file.data.end()) { - target->has_ap6_rom = true; - target->has_sideways_ram = true; + target8bit->has_ap6_rom = true; + target8bit->has_sideways_ram = true; } } } + } else if(adfs_catalogue) { + targetArchimedes->media.disks = media.disks; } } // Enable the Acorn ADFS if a mass-storage device is attached; // unlike the Pres ADFS it retains SCSI logic. if(!media.mass_storage_devices.empty()) { - target->has_pres_adfs = false; // To override a floppy selection, if one was made. - target->has_acorn_adfs = true; + target8bit->has_pres_adfs = false; // To override a floppy selection, if one was made. + target8bit->has_acorn_adfs = true; // Assume some sort of later-era Acorn work is likely to happen; // so ensure *TYPE, etc are present. - target->has_ap6_rom = true; - target->has_sideways_ram = true; + target8bit->has_ap6_rom = true; + target8bit->has_sideways_ram = true; - target->media.mass_storage_devices = media.mass_storage_devices; + target8bit->media.mass_storage_devices = media.mass_storage_devices; // Check for a boot option. - const auto sector = target->media.mass_storage_devices.front()->get_block(1); + const auto sector = target8bit->media.mass_storage_devices.front()->get_block(1); if(sector[0xfd]) { - target->should_shift_restart = true; + target8bit->should_shift_restart = true; } else { - target->loading_command = "*CAT\n"; + target8bit->loading_command = "*CAT\n"; } } TargetList targets; - if(!target->media.empty()) { - targets.push_back(std::move(target)); + if(!target8bit->media.empty()) { + targets.push_back(std::move(target8bit)); + } + if(!targetArchimedes->media.empty()) { + targets.push_back(std::move(targetArchimedes)); } return targets; } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 81bafb355..b7c6d9392 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -144,13 +144,21 @@ struct ActivityObserver: public Activity::Observer { ROM::Request missing_roms; _machine = Machine::MachineForTargets(_analyser.targets, CSROMFetcher(&missing_roms), error); if(!_machine) { - const std::wstring description = missing_roms.description(0, L'•'); - static_assert(sizeof(wchar_t) == 4, "This code assumes wchar_t is UTF32"); - NSString *nativeString = [[NSString alloc] - initWithBytes:description.data() - length:description.size()*sizeof(wchar_t) - encoding:NSUTF32LittleEndianStringEncoding]; - [missingROMs appendString:nativeString]; + switch(error) { + case Machine::Error::MissingROM: { + const std::wstring description = missing_roms.description(0, L'•'); + static_assert(sizeof(wchar_t) == 4, "This code assumes wchar_t is UTF32"); + NSString *nativeString = [[NSString alloc] + initWithBytes:description.data() + length:description.size()*sizeof(wchar_t) + encoding:NSUTF32LittleEndianStringEncoding]; + [missingROMs appendString:nativeString]; + } break; + + default: + NSLog(@"Unhandled machine creation error %d", error); + break; + } return nil; } updater.performer.machine = _machine.get();