From 20670bab2f0adc074b43b9fb59320eab638763a9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 19 Jul 2019 22:35:22 -0400 Subject: [PATCH 01/22] Expands information included in ROM load requests. --- Machines/AmstradCPC/AmstradCPC.cpp | 2 +- Machines/Apple/AppleII/AppleII.cpp | 18 ++++++------ Machines/Apple/AppleII/DiskIICard.cpp | 4 +-- Machines/ColecoVision/ColecoVision.cpp | 2 +- Machines/Commodore/Vic-20/Vic20.cpp | 22 +++++++-------- Machines/Electron/Electron.cpp | 8 +++--- Machines/MSX/MSX.cpp | 10 +++---- Machines/MasterSystem/MasterSystem.cpp | 2 +- Machines/Oric/Oric.cpp | 14 +++++----- Machines/ROMMachine.hpp | 28 ++++++++++++++++++- Machines/ZX8081/ZX8081.cpp | 2 +- .../Mac/Clock Signal/Machine/CSROMFetcher.mm | 11 +++++--- OSBindings/SDL/main.cpp | 16 +++++------ 13 files changed, 84 insertions(+), 55 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 9698aa3b1..d0599552d 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -781,7 +781,7 @@ template class ConcreteMachine: ay_.ay().set_port_handler(&key_state_); // construct the list of necessary ROMs - std::vector required_roms = {"amsdos.rom"}; + std::vector required_roms = { {"amsdos.rom"} }; std::string model_number; switch(target.model) { default: diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index f36e93103..a04c82318 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -347,26 +347,26 @@ template class ConcreteMachine: // Pick the required ROMs. using Target = Analyser::Static::AppleII::Target; - std::vector rom_names; + std::vector rom_names; size_t rom_size = 12*1024; switch(target.model) { default: - rom_names.push_back("apple2-character.rom"); - rom_names.push_back("apple2o.rom"); + rom_names.emplace_back("apple2-character.rom"); + rom_names.emplace_back("apple2o.rom"); break; case Target::Model::IIplus: - rom_names.push_back("apple2-character.rom"); - rom_names.push_back("apple2.rom"); + rom_names.emplace_back("apple2-character.rom"); + rom_names.emplace_back("apple2.rom"); break; case Target::Model::IIe: rom_size += 3840; - rom_names.push_back("apple2eu-character.rom"); - rom_names.push_back("apple2eu.rom"); + rom_names.emplace_back("apple2eu-character.rom"); + rom_names.emplace_back("apple2eu.rom"); break; case Target::Model::EnhancedIIe: rom_size += 3840; - rom_names.push_back("apple2e-character.rom"); - rom_names.push_back("apple2e.rom"); + rom_names.emplace_back("apple2e-character.rom"); + rom_names.emplace_back("apple2e.rom"); break; } const auto roms = rom_fetcher("AppleII", rom_names); diff --git a/Machines/Apple/AppleII/DiskIICard.cpp b/Machines/Apple/AppleII/DiskIICard.cpp index 2235cff6a..869770bfc 100644 --- a/Machines/Apple/AppleII/DiskIICard.cpp +++ b/Machines/Apple/AppleII/DiskIICard.cpp @@ -14,8 +14,8 @@ DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sec const auto roms = rom_fetcher( "DiskII", { - is_16_sector ? "boot-16.rom" : "boot-13.rom", - is_16_sector ? "state-machine-16.rom" : "state-machine-13.rom" + ROMMachine::ROM(is_16_sector ? "boot-16.rom" : "boot-13.rom"), + ROMMachine::ROM(is_16_sector ? "state-machine-16.rom" : "state-machine-13.rom") }); boot_ = std::move(*roms[0]); diskii_.set_state_machine(*roms[1]); diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index 722a33c9b..f0a409c9e 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -132,7 +132,7 @@ class ConcreteMachine: const auto roms = rom_fetcher( "ColecoVision", - { "coleco.rom" }); + { ROMMachine::ROM("coleco.rom") }); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 1d82bc909..342d3cdb9 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -323,27 +323,27 @@ class ConcreteMachine: // install a joystick joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); - std::vector rom_names = { "basic.bin" }; + std::vector rom_names = { ROMMachine::ROM("basic.bin") }; switch(target.region) { default: - rom_names.push_back("characters-english.bin"); - rom_names.push_back("kernel-pal.bin"); + rom_names.emplace_back("characters-english.bin"); + rom_names.emplace_back("kernel-pal.bin"); break; case Analyser::Static::Commodore::Target::Region::American: - rom_names.push_back("characters-english.bin"); - rom_names.push_back("kernel-ntsc.bin"); + rom_names.emplace_back("characters-english.bin"); + rom_names.emplace_back("kernel-ntsc.bin"); break; case Analyser::Static::Commodore::Target::Region::Danish: - rom_names.push_back("characters-danish.bin"); - rom_names.push_back("kernel-danish.bin"); + rom_names.emplace_back("characters-danish.bin"); + rom_names.emplace_back("kernel-danish.bin"); break; case Analyser::Static::Commodore::Target::Region::Japanese: - rom_names.push_back("characters-japanese.bin"); - rom_names.push_back("kernel-japanese.bin"); + rom_names.emplace_back("characters-japanese.bin"); + rom_names.emplace_back("kernel-japanese.bin"); break; case Analyser::Static::Commodore::Target::Region::Swedish: - rom_names.push_back("characters-swedish.bin"); - rom_names.push_back("kernel-japanese.bin"); + rom_names.emplace_back("characters-swedish.bin"); + rom_names.emplace_back("kernel-japanese.bin"); break; } diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 383793397..5aeb80411 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -64,14 +64,14 @@ class ConcreteMachine: speaker_.set_input_rate(2000000 / SoundGenerator::clock_rate_divider); speaker_.set_high_frequency_cutoff(7000); - std::vector rom_names = {"basic.rom", "os.rom"}; + std::vector rom_names = { {"basic.rom"}, {"os.rom"} }; if(target.has_adfs) { - rom_names.push_back("ADFS-E00_1.rom"); - rom_names.push_back("ADFS-E00_2.rom"); + rom_names.emplace_back("ADFS-E00_1.rom"); + rom_names.emplace_back("ADFS-E00_2.rom"); } const size_t dfs_rom_position = rom_names.size(); if(target.has_dfs) { - rom_names.push_back("DFS-1770-2.20.rom"); + rom_names.emplace_back("DFS-1770-2.20.rom"); } const auto roms = rom_fetcher("Electron", rom_names); diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index b2e57dcdb..7754719cf 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -173,7 +173,7 @@ class ConcreteMachine: mixer_.set_relative_volumes({0.5f, 0.1f, 0.4f}); // Install the proper TV standard and select an ideal BIOS name. - std::vector rom_names = {"msx.rom"}; + std::vector rom_names = { {"msx.rom"} }; bool is_ntsc = true; uint8_t character_generator = 1; /* 0 = Japan, 1 = USA, etc, 2 = USSR */ @@ -182,7 +182,7 @@ class ConcreteMachine: switch(target.region) { case Target::Region::Japan: - rom_names.push_back("msx-japanese.rom"); + rom_names.emplace_back("msx-japanese.rom"); vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC); is_ntsc = true; @@ -190,7 +190,7 @@ class ConcreteMachine: date_format = 0; break; case Target::Region::USA: - rom_names.push_back("msx-american.rom"); + rom_names.emplace_back("msx-american.rom"); vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC); is_ntsc = true; @@ -198,7 +198,7 @@ class ConcreteMachine: date_format = 1; break; case Target::Region::Europe: - rom_names.push_back("msx-european.rom"); + rom_names.emplace_back("msx-european.rom"); vdp_.set_tv_standard(TI::TMS::TVStandard::PAL); is_ntsc = false; @@ -212,7 +212,7 @@ class ConcreteMachine: size_t disk_index = 0; if(target.has_disk_drive) { disk_index = rom_names.size(); - rom_names.push_back("disk.rom"); + rom_names.emplace_back("disk.rom"); } const auto roms = rom_fetcher("MSX", rom_names); diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index 7400c6dae..2ef9072e4 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -132,7 +132,7 @@ class ConcreteMachine: // Load the BIOS if relevant. if(has_bios()) { - const auto roms = rom_fetcher("MasterSystem", {"bios.sms"}); + const auto roms = rom_fetcher("MasterSystem", { ROMMachine::ROM("bios.sms") }); if(!roms[0]) { // No BIOS found; attempt to boot as though it has already disabled itself. memory_control_ |= 0x08; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 58ebdd907..5382dc710 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -228,16 +228,16 @@ template class Co diskii_.set_clocking_hint_observer(this); } - std::vector rom_names = {"colour.rom"}; + std::vector rom_names = { {"colour.rom"} }; switch(target.rom) { - case Analyser::Static::Oric::Target::ROM::BASIC10: rom_names.push_back("basic10.rom"); break; - case Analyser::Static::Oric::Target::ROM::BASIC11: rom_names.push_back("basic11.rom"); break; - case Analyser::Static::Oric::Target::ROM::Pravetz: rom_names.push_back("pravetz.rom"); break; + case Analyser::Static::Oric::Target::ROM::BASIC10: rom_names.emplace_back("basic10.rom"); break; + case Analyser::Static::Oric::Target::ROM::BASIC11: rom_names.emplace_back("basic11.rom"); break; + case Analyser::Static::Oric::Target::ROM::Pravetz: rom_names.emplace_back("pravetz.rom"); break; } switch(disk_interface) { default: break; - case Analyser::Static::Oric::Target::DiskInterface::Microdisc: rom_names.push_back("microdisc.rom"); break; - case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.push_back("8dos.rom"); break; + case Analyser::Static::Oric::Target::DiskInterface::Microdisc: rom_names.emplace_back("microdisc.rom"); break; + case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.emplace_back("8dos.rom"); break; } const auto roms = rom_fetcher("Oric", rom_names); @@ -261,7 +261,7 @@ template class Co pravetz_rom_ = std::move(*roms[2]); pravetz_rom_.resize(512); - auto state_machine_rom = rom_fetcher("DiskII", {"state-machine-16.rom"}); + auto state_machine_rom = rom_fetcher("DiskII", { ROMMachine::ROM("state-machine-16.rom") }); if(!state_machine_rom[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/ROMMachine.hpp b/Machines/ROMMachine.hpp index a42942563..cd187bfe6 100644 --- a/Machines/ROMMachine.hpp +++ b/Machines/ROMMachine.hpp @@ -16,6 +16,32 @@ namespace ROMMachine { +/*! + Describes a ROM image; this term is used in this emulator strictly in the sense of firmware — + system software that is an inherent part of a machine. +*/ +struct ROM { + /// A descriptive name for this ROM, e.g. "Electron MOS 1.0". + std::string descriptive_name; + /// An idiomatic file name for this ROM, e.g. "os10.rom". + std::string file_name; + /// The expected size of this ROM in bytes, e.g. 32768. + size_t size = 0; + /// CRC32s for all known acceptable copies of this ROM; intended to allow a host platform + /// to test user-provided ROMs of unknown provenance. **Not** intended to be used + /// to exclude ROMs where the user's intent is otherwise clear. + std::vector crc32s; + + /// This is a temporary constructor provided for transitional purposes. + ROM(std::string file_name) : + file_name(file_name) {} + + ROM(std::string descriptive_name, std::string file_name, size_t size, uint32_t crc32) : + descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s({crc32}) {} + ROM(std::string descriptive_name, std::string file_name, size_t size, std::vector &crc32s) : + descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s(std::move(crc32s)) {} +}; + /*! Defines the signature for a function that must be supplied by the host environment in order to give machines a route for fetching any system ROMs they might need. @@ -24,7 +50,7 @@ namespace ROMMachine { to be present. The recevier should return a vector of unique_ptrs that either contain the contents of the ROM from @c names that corresponds by index, or else are the nullptr */ -typedef std::function>>(const std::string &machine, const std::vector &names)> ROMFetcher; +typedef std::function>>(const std::string &machine, const std::vector &roms)> ROMFetcher; enum class Error { MissingROMs diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index ab9818006..5121fc59e 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -76,7 +76,7 @@ template class ConcreteMachine: clear_all_keys(); const bool use_zx81_rom = target.is_ZX81 || target.ZX80_uses_ZX81_ROM; - const auto roms = rom_fetcher("ZX8081", { use_zx81_rom ? "zx81.rom" : "zx80.rom" }); + const auto roms = rom_fetcher("ZX8081", { ROMMachine::ROM(use_zx81_rom ? "zx81.rom" : "zx80.rom") } ); if(!roms[0]) throw ROMMachine::Error::MissingROMs; rom_ = std::move(*roms[0]); diff --git a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm index 0ab615bbf..44e7ebe62 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm @@ -15,11 +15,14 @@ #include ROMMachine::ROMFetcher CSROMFetcher() { - return [] (const std::string &machine, const std::vector &names) -> std::vector>> { - NSString *subDirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:machine.c_str()]]; + return [] (const std::string &machine, const std::vector &roms) -> std::vector>> { + NSString *subdirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:machine.c_str()]]; std::vector>> results; - for(const auto &name: names) { - NSData *fileData = [[NSBundle mainBundle] dataForResource:[NSString stringWithUTF8String:name.c_str()] withExtension:nil subdirectory:subDirectory]; + for(const auto &rom: roms) { + NSData *fileData = [[NSBundle mainBundle] + dataForResource:[NSString stringWithUTF8String:rom.file_name.c_str()] + withExtension:nil + subdirectory:subdirectory]; if(!fileData) results.emplace_back(nullptr); diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 31721e5d7..23a49836e 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -365,11 +365,11 @@ int main(int argc, char *argv[]) { // /usr/local/share/CLK/[system]; // /usr/share/CLK/[system]; or // [user-supplied path]/[system] - std::vector rom_names; + std::vector requested_roms; std::string machine_name; - ROMMachine::ROMFetcher rom_fetcher = [&rom_names, &machine_name, &arguments] - (const std::string &machine, const std::vector &names) -> std::vector>> { - rom_names.insert(rom_names.end(), names.begin(), names.end()); + ROMMachine::ROMFetcher rom_fetcher = [&requested_roms, &machine_name, &arguments] + (const std::string &machine, const std::vector &roms) -> std::vector>> { + requested_roms.insert(requested_roms.end(), roms.begin(), roms.end()); machine_name = machine; std::vector paths = { @@ -386,10 +386,10 @@ int main(int argc, char *argv[]) { } std::vector>> results; - for(const auto &name: names) { + for(const auto &rom: roms) { FILE *file = nullptr; for(const auto &path: paths) { - std::string local_path = path + machine + "/" + name; + std::string local_path = path + machine + "/" + rom.file_name; file = std::fopen(local_path.c_str(), "rb"); if(file) break; } @@ -425,8 +425,8 @@ int main(int argc, char *argv[]) { case ::Machine::Error::MissingROM: std::cerr << "Could not find system ROMs; please install to /usr/local/share/CLK/ or /usr/share/CLK/, or provide a --rompath." << std::endl; std::cerr << "One or more of the following was needed but not found:" << std::endl; - for(const auto &name: rom_names) { - std::cerr << machine_name << '/' << name << std::endl; + for(const auto &rom: requested_roms) { + std::cerr << machine_name << '/' << rom.file_name << std::endl; } break; } From 3c68a5ca656c68a00ab97758974bb515fa730833 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Jul 2019 16:08:40 -0400 Subject: [PATCH 02/22] Enhances the amount of ROM information posted by the Apple machines. --- Machines/Apple/AppleII/AppleII.cpp | 20 ++++++++++---------- Machines/Apple/Macintosh/Macintosh.cpp | 15 ++++++++------- Machines/ROMMachine.hpp | 4 ++-- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index a04c82318..67435b4c5 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -347,29 +347,29 @@ template class ConcreteMachine: // Pick the required ROMs. using Target = Analyser::Static::AppleII::Target; - std::vector rom_names; + std::vector rom_descriptions; size_t rom_size = 12*1024; switch(target.model) { default: - rom_names.emplace_back("apple2-character.rom"); - rom_names.emplace_back("apple2o.rom"); + rom_descriptions.emplace_back("the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6); + rom_descriptions.emplace_back("the original Apple II ROM", "apple2o.rom", 12*1024, 0xba210588); break; case Target::Model::IIplus: - rom_names.emplace_back("apple2-character.rom"); - rom_names.emplace_back("apple2.rom"); + rom_descriptions.emplace_back("the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6); + rom_descriptions.emplace_back("the Apple II+ ROM", "apple2.rom", 12*1024, 0xf66f9c26); break; case Target::Model::IIe: rom_size += 3840; - rom_names.emplace_back("apple2eu-character.rom"); - rom_names.emplace_back("apple2eu.rom"); + rom_descriptions.emplace_back("the Apple IIe character ROM", "apple2eu-character.rom", 4*1024, 0x816a86f1); + rom_descriptions.emplace_back("the Apple IIe ROM", "apple2eu.rom", 32*1024, 0xe12be18d); break; case Target::Model::EnhancedIIe: rom_size += 3840; - rom_names.emplace_back("apple2e-character.rom"); - rom_names.emplace_back("apple2e.rom"); + rom_descriptions.emplace_back("the Enhanced Apple IIe character ROM", "apple2e-character.rom", 4*1024, 0x2651014d); + rom_descriptions.emplace_back("the Enhanced Apple IIe ROM", "apple2e.rom", 32*1024, 0x65989942); break; } - const auto roms = rom_fetcher("AppleII", rom_names); + const auto roms = rom_fetcher("AppleII", rom_descriptions); if(!roms[0] || !roms[1]) { throw ROMMachine::Error::MissingROMs; diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index 46730e890..3915edadd 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -70,33 +70,34 @@ template class ConcreteMachin // Select a ROM name and determine the proper ROM and RAM sizes // based on the machine model. using Model = Analyser::Static::Macintosh::Target::Model; - std::string rom_name; uint32_t ram_size, rom_size; + std::vector rom_descriptions; switch(model) { default: case Model::Mac128k: ram_size = 128*1024; rom_size = 64*1024; - rom_name = "mac128k.rom"; + rom_descriptions.emplace_back("the Macintosh 128k ROM", "mac128k.rom", 64*1024, 0x6d0c8a28); break; case Model::Mac512k: ram_size = 512*1024; rom_size = 64*1024; - rom_name = "mac512k.rom"; + rom_descriptions.emplace_back("the Macintosh 512k ROM", "mac512k.rom", 64*1024, 0xcf759e0d); break; case Model::Mac512ke: - case Model::MacPlus: + case Model::MacPlus: { ram_size = 512*1024; rom_size = 128*1024; - rom_name = "macplus.rom"; - break; + const std::initializer_list crc32s = { 0x4fa5b399, 0x7cacd18f, 0xb2102e8e }; + rom_descriptions.emplace_back("the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s); + } break; } ram_mask_ = (ram_size >> 1) - 1; rom_mask_ = (rom_size >> 1) - 1; video_.set_ram_mask(ram_mask_); // Grab a copy of the ROM and convert it into big-endian data. - const auto roms = rom_fetcher("Macintosh", { rom_name }); + const auto roms = rom_fetcher("Macintosh", rom_descriptions); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/ROMMachine.hpp b/Machines/ROMMachine.hpp index cd187bfe6..3b47fb41a 100644 --- a/Machines/ROMMachine.hpp +++ b/Machines/ROMMachine.hpp @@ -38,8 +38,8 @@ struct ROM { ROM(std::string descriptive_name, std::string file_name, size_t size, uint32_t crc32) : descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s({crc32}) {} - ROM(std::string descriptive_name, std::string file_name, size_t size, std::vector &crc32s) : - descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s(std::move(crc32s)) {} + ROM(std::string descriptive_name, std::string file_name, size_t size, std::initializer_list crc32s) : + descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s(crc32s) {} }; /*! From 712cb473f7374e6f3b6c71ed00ec89666b9e88b9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Jul 2019 17:07:59 -0400 Subject: [PATCH 03/22] Adds extended ROM information for the CPC and ColecoVision. --- Machines/AmstradCPC/AmstradCPC.cpp | 15 ++++++++++++--- Machines/ColecoVision/ColecoVision.cpp | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index d0599552d..05bf98f3a 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -781,24 +781,33 @@ template class ConcreteMachine: ay_.ay().set_port_handler(&key_state_); // construct the list of necessary ROMs - std::vector required_roms = { {"amsdos.rom"} }; + std::vector required_roms = { + ROMMachine::ROM("the Amstrad Disk Operating System", "amsdos.rom", 16*1024, 0x1fe22ecd) + }; std::string model_number; + uint32_t crcs[2]; switch(target.model) { default: model_number = "6128"; has_128k_ = true; + crcs[0] = 0x0219bb74; + crcs[1] = 0xca6af63d; break; case Analyser::Static::AmstradCPC::Target::Model::CPC464: model_number = "464"; has_128k_ = false; + crcs[0] = 0x815752df; + crcs[1] = 0x7d9a3bac; break; case Analyser::Static::AmstradCPC::Target::Model::CPC664: model_number = "664"; has_128k_ = false; + crcs[0] = 0x3f5a6dc4; + crcs[1] = 0x32fee492; break; } - required_roms.push_back("os" + model_number + ".rom"); - required_roms.push_back("basic" + model_number + ".rom"); + required_roms.emplace_back("the CPC " + model_number + "firmware", "os" + model_number + ".rom", 16*1024, crcs[0]); + required_roms.emplace_back("the CPC " + model_number + "BASIC ROM", "basic" + model_number + ".rom", 16*1024, crcs[1]); // fetch and verify the ROMs const auto roms = rom_fetcher("AmstradCPC", required_roms); diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index f0a409c9e..8ffde6ecf 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -132,7 +132,7 @@ class ConcreteMachine: const auto roms = rom_fetcher( "ColecoVision", - { ROMMachine::ROM("coleco.rom") }); + { ROMMachine::ROM("the ColecoVision BIOS", "coleco.rom", 8*1024, 0x3aa93ef3) }); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; From f3aac603f844a6cc1af2f57f2d00db00ddfe075c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Jul 2019 21:30:37 -0400 Subject: [PATCH 04/22] Adds extended Introduces extended ROM details for the C1540, Electron, Master System and MSX. --- .../Commodore/1540/Implementation/C1540.cpp | 15 +++++++++++---- Machines/Electron/Electron.cpp | 15 +++++++++------ Machines/MSX/MSX.cpp | 17 ++++++++++------- Machines/MasterSystem/MasterSystem.cpp | 4 +++- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Machines/Commodore/1540/Implementation/C1540.cpp b/Machines/Commodore/1540/Implementation/C1540.cpp index 8fa73ee31..d88b6f152 100644 --- a/Machines/Commodore/1540/Implementation/C1540.cpp +++ b/Machines/Commodore/1540/Implementation/C1540.cpp @@ -39,13 +39,20 @@ MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher & // attach the only drive there is set_drive(drive_); - std::string rom_name; + std::string device_name; + uint32_t crc = 0; switch(personality) { - case Personality::C1540: rom_name = "1540.bin"; break; - case Personality::C1541: rom_name = "1541.bin"; break; + case Personality::C1540: + device_name = "1540"; + crc = 0x718d42b1; + break; + case Personality::C1541: + device_name = "1541"; + crc = 0xfb760019; + break; } - auto roms = rom_fetcher("Commodore1540", {rom_name}); + auto roms = rom_fetcher("Commodore1540", { ROMMachine::ROM("the " + device_name + " ROM", device_name + ".bin", 16*1024, crc) }); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 5aeb80411..48378fb2e 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -64,16 +64,19 @@ class ConcreteMachine: speaker_.set_input_rate(2000000 / SoundGenerator::clock_rate_divider); speaker_.set_high_frequency_cutoff(7000); - std::vector rom_names = { {"basic.rom"}, {"os.rom"} }; + std::vector required_roms = { + {"the Acorn BASIC II ROM", "basic.rom", 16*1024, 0x79434781}, + {"the Electron MOS ROM", "os.rom", 16*1024, 0xbf63fb1f} + }; if(target.has_adfs) { - rom_names.emplace_back("ADFS-E00_1.rom"); - rom_names.emplace_back("ADFS-E00_2.rom"); + required_roms.emplace_back("the E00 ADFS ROM, first slot", "ADFS-E00_1.rom", 16*1024, 0x51523993); + required_roms.emplace_back("the E00 ADFS ROM, second slot", "ADFS-E00_2.rom", 16*1024, 0x8d17de0e); } - const size_t dfs_rom_position = rom_names.size(); + const size_t dfs_rom_position = required_roms.size(); if(target.has_dfs) { - rom_names.emplace_back("DFS-1770-2.20.rom"); + required_roms.emplace_back("the 1770 DFS ROM", "DFS-1770-2.20.rom", 16*1024, 0xf3dc9bc5); } - const auto roms = rom_fetcher("Electron", rom_names); + const auto roms = rom_fetcher("Electron", required_roms); for(const auto &rom: roms) { if(!rom) { diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 7754719cf..e99a3e834 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -173,16 +173,19 @@ class ConcreteMachine: mixer_.set_relative_volumes({0.5f, 0.1f, 0.4f}); // Install the proper TV standard and select an ideal BIOS name. - std::vector rom_names = { {"msx.rom"} }; + std::vector required_roms = { + {"any MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3} + }; bool is_ntsc = true; uint8_t character_generator = 1; /* 0 = Japan, 1 = USA, etc, 2 = USSR */ uint8_t date_format = 1; /* 0 = Y/M/D, 1 = M/D/Y, 2 = D/M/Y */ uint8_t keyboard = 1; /* 0 = Japan, 1 = USA, 2 = France, 3 = UK, 4 = Germany, 5 = USSR, 6 = Spain */ + // TODO: CRCs below are incomplete, at best. switch(target.region) { case Target::Region::Japan: - rom_names.emplace_back("msx-japanese.rom"); + required_roms.emplace_back("a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390); vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC); is_ntsc = true; @@ -190,7 +193,7 @@ class ConcreteMachine: date_format = 0; break; case Target::Region::USA: - rom_names.emplace_back("msx-american.rom"); + required_roms.emplace_back("an American MSX BIOS", "msx-american.rom", 32*1024, 0); vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC); is_ntsc = true; @@ -198,7 +201,7 @@ class ConcreteMachine: date_format = 1; break; case Target::Region::Europe: - rom_names.emplace_back("msx-european.rom"); + required_roms.emplace_back("a European MSX BIOS", "msx-european.rom", 32*1024, 0); vdp_.set_tv_standard(TI::TMS::TVStandard::PAL); is_ntsc = false; @@ -211,10 +214,10 @@ class ConcreteMachine: // but failing that fall back on patching the main one. size_t disk_index = 0; if(target.has_disk_drive) { - disk_index = rom_names.size(); - rom_names.emplace_back("disk.rom"); + disk_index = required_roms.size(); + required_roms.emplace_back("the MSX-DOS ROM", "disk.rom", 16*1024, 0x721f61df); } - const auto roms = rom_fetcher("MSX", rom_names); + const auto roms = rom_fetcher("MSX", required_roms); if((!roms[0] && !roms[1]) || (target.has_disk_drive && !roms[2])) { throw ROMMachine::Error::MissingROMs; diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index 2ef9072e4..abde5b954 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -132,7 +132,9 @@ class ConcreteMachine: // Load the BIOS if relevant. if(has_bios()) { - const auto roms = rom_fetcher("MasterSystem", { ROMMachine::ROM("bios.sms") }); + // TODO: there's probably a million other versions of the Master System BIOS; try to build a + // CRC32 catalogue of those. + const auto roms = rom_fetcher("MasterSystem", { {"the Master System BIOS", "bios.sms", 8*1024, 0x0072ed54} }); if(!roms[0]) { // No BIOS found; attempt to boot as though it has already disabled itself. memory_control_ |= 0x08; From b2a66827987e7328bc9343d8c59e8d8b0c3afd78 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Jul 2019 22:46:49 -0400 Subject: [PATCH 05/22] Adds extended ROM information for the ZX80 and '81. --- Machines/ZX8081/ZX8081.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 5121fc59e..fcf995060 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -76,7 +76,11 @@ template class ConcreteMachine: clear_all_keys(); const bool use_zx81_rom = target.is_ZX81 || target.ZX80_uses_ZX81_ROM; - const auto roms = rom_fetcher("ZX8081", { ROMMachine::ROM(use_zx81_rom ? "zx81.rom" : "zx80.rom") } ); + const auto roms = + use_zx81_rom ? + rom_fetcher("ZX8081", { {"the ZX81 ROM", "zx81.rom", 8 * 1024, 0x4b1dd6eb} }) : + rom_fetcher("ZX8081", { {"the ZX80 ROM", "zx80.rom", 4 * 1024, 0x4c7fc597} }); + if(!roms[0]) throw ROMMachine::Error::MissingROMs; rom_ = std::move(*roms[0]); From 4ffa3c1b49ea1f1b228d2d8d828fe7958696715a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Jul 2019 22:52:57 -0400 Subject: [PATCH 06/22] Provides an output for some of the extended ROM information. --- OSBindings/SDL/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 23a49836e..301f5ccb5 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -426,7 +426,11 @@ int main(int argc, char *argv[]) { std::cerr << "Could not find system ROMs; please install to /usr/local/share/CLK/ or /usr/share/CLK/, or provide a --rompath." << std::endl; std::cerr << "One or more of the following was needed but not found:" << std::endl; for(const auto &rom: requested_roms) { - std::cerr << machine_name << '/' << rom.file_name << std::endl; + std::cerr << machine_name << '/' << rom.file_name; + if(!rom.descriptive_name.empty()) { + std::cerr << " (" << rom.descriptive_name << ")"; + } + std::cerr << std::endl; } break; } From a846c3245d0cf796d771f4aca4922a945ab2b472 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Jul 2019 23:04:46 -0400 Subject: [PATCH 07/22] Checks the application support directory before the application bundle for ROM images. --- .../Mac/Clock Signal/Machine/CSROMFetcher.mm | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm index 44e7ebe62..87c1f5f85 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm @@ -16,14 +16,30 @@ ROMMachine::ROMFetcher CSROMFetcher() { return [] (const std::string &machine, const std::vector &roms) -> std::vector>> { - NSString *subdirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:machine.c_str()]]; + NSString *const subdirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:machine.c_str()]]; + NSArray *const supportURLs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask]; + std::vector>> results; for(const auto &rom: roms) { - NSData *fileData = [[NSBundle mainBundle] - dataForResource:[NSString stringWithUTF8String:rom.file_name.c_str()] - withExtension:nil - subdirectory:subdirectory]; + NSData *fileData; + // Check for this file first within the application support directories. + for(NSURL *supportURL in supportURLs) { + NSURL *const fullURL = [[supportURL URLByAppendingPathComponent:subdirectory] + URLByAppendingPathComponent:[NSString stringWithUTF8String:rom.file_name.c_str()]]; + fileData = [NSData dataWithContentsOfURL:fullURL]; + if(fileData) break; + } + + // Failing that, check inside the application bundle. + if(!fileData) { + fileData = [[NSBundle mainBundle] + dataForResource:[NSString stringWithUTF8String:rom.file_name.c_str()] + withExtension:nil + subdirectory:subdirectory]; + } + + // Store an appropriate result. if(!fileData) results.emplace_back(nullptr); else { From d452d070a185593e52ba1d34cb483a38d014402e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 21 Jul 2019 18:41:00 -0400 Subject: [PATCH 08/22] Extends the Mac ROM fetcher to return a missing-ROMs list. --- .../Mac/Clock Signal.xcodeproj/project.pbxproj | 4 ++-- OSBindings/Mac/Clock Signal/Machine/CSMachine.mm | 3 ++- .../Mac/Clock Signal/Machine/CSROMFetcher.hpp | 2 +- OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm | 13 +++++++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index cb265c8f6..dec96b36d 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -339,6 +339,7 @@ 4BB0A65E204500A900FB3688 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A90EC20410A85008514A2 /* StaticAnalyser.cpp */; }; 4BB17D4E1ED7909F00ABD1E1 /* tests.expected.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BB17D4C1ED7909F00ABD1E1 /* tests.expected.json */; }; 4BB17D4F1ED7909F00ABD1E1 /* tests.in.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BB17D4D1ED7909F00ABD1E1 /* tests.in.json */; }; + 4BB1CBB522E5215B0030C002 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BB244D522AABAF600BE20E5 /* z8530.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB244D322AABAF500BE20E5 /* z8530.cpp */; }; 4BB244D622AABAF600BE20E5 /* z8530.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB244D322AABAF500BE20E5 /* z8530.cpp */; }; 4BB298F11B587D8400A49093 /* start in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E51B587D8300A49093 /* start */; }; @@ -633,7 +634,6 @@ 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; }; 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; }; 4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */; }; - 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; }; 4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCA6CC61D9DD9F000C2D7B2 /* CommodoreROM.cpp */; }; @@ -3555,9 +3555,9 @@ 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, 4B8FE21D1DA19D5F0090D3CE /* QuickLoadCompositeOptions.xib in Resources */, 4B79E4461E3AF38600141F11 /* floppy525.png in Resources */, - 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */, 4BEEE6BD20DC72EB003723BF /* CompositeOptions.xib in Resources */, 4B1497981EE4B97F00CE2596 /* ZX8081Options.xib in Resources */, + 4BB1CBB522E5215B0030C002 /* ROMImages in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index c2077baef..1aa0fab1f 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -96,7 +96,8 @@ struct ActivityObserver: public Activity::Observer { _analyser = result; Machine::Error error; - _machine.reset(Machine::MachineForTargets(_analyser.targets, CSROMFetcher(), error)); + std::vector missing_roms; + _machine.reset(Machine::MachineForTargets(_analyser.targets, CSROMFetcher(&missing_roms), error)); if(!_machine) return nil; _inputMode = diff --git a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.hpp b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.hpp index 28958b535..f1d039ade 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.hpp +++ b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.hpp @@ -8,4 +8,4 @@ #include "ROMMachine.hpp" -ROMMachine::ROMFetcher CSROMFetcher(); +ROMMachine::ROMFetcher CSROMFetcher(std::vector *missing_roms = nullptr); diff --git a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm index 87c1f5f85..9345040c0 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm @@ -14,8 +14,8 @@ #include -ROMMachine::ROMFetcher CSROMFetcher() { - return [] (const std::string &machine, const std::vector &roms) -> std::vector>> { +ROMMachine::ROMFetcher CSROMFetcher(std::vector *missing_roms) { + return [missing_roms] (const std::string &machine, const std::vector &roms) -> std::vector>> { NSString *const subdirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:machine.c_str()]]; NSArray *const supportURLs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask]; @@ -39,9 +39,14 @@ ROMMachine::ROMFetcher CSROMFetcher() { subdirectory:subdirectory]; } - // Store an appropriate result. - if(!fileData) + // Store an appropriate result, accumulating a list of the missing if requested. + if(!fileData) { results.emplace_back(nullptr); + + if(missing_roms) { + missing_roms->push_back(rom); + } + } else { std::unique_ptr> data(new std::vector); *data = fileData.stdVector8; From 67c5f6b7cb1698377ab949f3a742361f42394aa1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 21 Jul 2019 22:05:22 -0400 Subject: [PATCH 09/22] Ensures the missing ROM list bubbles up to Swift. --- .../Documents/MachineDocument.swift | 5 +- .../Mac/Clock Signal/Machine/CSMachine.h | 11 ++- .../Mac/Clock Signal/Machine/CSMachine.mm | 77 ++++++++++++++++++- 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index c4b42aa0a..d9962a42f 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -153,11 +153,14 @@ class MachineDocument: // MARK: configuring func configureAs(_ analysis: CSStaticAnalyser) { - if let machine = CSMachine(analyser: analysis) { + let missingROMs = NSMutableArray() + if let machine = CSMachine(analyser: analysis, missingROMs: missingROMs) { self.machine = machine self.optionsPanelNibName = analysis.optionsPanelNibName setupMachineOutput() setupActivityDisplay() + } else { + Swift.print(missingROMs) } } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index 5f1bd5da0..0a6e7496c 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -33,6 +33,13 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) { CSMachineKeyboardInputModeJoystick }; +@interface CSMissingROM: NSObject +@property (nonatomic, readonly, nonnull) NSString *fileName; +@property (nonatomic, readonly, nullable) NSString *descriptiveName; +@property (nonatomic, readonly) NSUInteger size; +@property (nonatomic, readonly, nonnull) NSArray *crc32s; +@end + // Deliberately low; to ensure CSMachine has been declared as an @class already. #import "CSAtari2600.h" #import "CSZX8081.h" @@ -45,8 +52,10 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) { Initialises an instance of CSMachine. @param result The CSStaticAnalyser result that describes the machine needed. + @param missingROMs An array that is filled with a list of ROMs that the machine requested but which + were not found; populated only if this `init` has failed. */ -- (nullable instancetype)initWithAnalyser:(nonnull CSStaticAnalyser *)result NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithAnalyser:(nonnull CSStaticAnalyser *)result missingROMs:(nullable inout NSMutableArray *)missingROMs NS_DESIGNATED_INITIALIZER; - (void)runForInterval:(NSTimeInterval)interval; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 1aa0fab1f..59476a9c0 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -74,6 +74,58 @@ struct ActivityObserver: public Activity::Observer { __unsafe_unretained CSMachine *machine; }; +@interface CSMissingROM (Mutability) +@property (nonatomic, nonnull, copy) NSString *fileName; +@property (nonatomic, nullable, copy) NSString *descriptiveName; +@property (nonatomic, readwrite) NSUInteger size; +@property (nonatomic, copy) NSArray *crc32s; +@end + +@implementation CSMissingROM { + NSString *_fileName; + NSString *_descriptiveName; + NSUInteger _size; + NSArray *_crc32s; +} + +- (NSString *)fileName { + return _fileName; +} + +- (void)setFileName:(NSString *)fileName { + _fileName = [fileName copy]; +} + +- (NSString *)descriptiveName { + return _descriptiveName; +} + +- (void)setDescriptiveName:(NSString *)descriptiveName { + _descriptiveName = [descriptiveName copy]; +} + +- (NSUInteger)size { + return _size; +} + +- (void)setSize:(NSUInteger)size { + _size = size; +} + +- (NSArray *)crc32s { + return _crc32s; +} + +- (void)setCrc32s:(NSArray *)crc32s { + _crc32s = [crc32s copy]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@/%@, %@ bytes, CRCs: %@", _fileName, _descriptiveName, @(_size), _crc32s]; +} + +@end + @implementation CSMachine { SpeakerDelegate _speakerDelegate; ActivityObserver _activityObserver; @@ -90,7 +142,7 @@ struct ActivityObserver: public Activity::Observer { std::unique_ptr _scanTarget; } -- (instancetype)initWithAnalyser:(CSStaticAnalyser *)result { +- (instancetype)initWithAnalyser:(CSStaticAnalyser *)result missingROMs:(inout NSMutableArray *)missingROMs { self = [super init]; if(self) { _analyser = result; @@ -98,7 +150,28 @@ struct ActivityObserver: public Activity::Observer { Machine::Error error; std::vector missing_roms; _machine.reset(Machine::MachineForTargets(_analyser.targets, CSROMFetcher(&missing_roms), error)); - if(!_machine) return nil; + if(!_machine) { + for(const auto &missing_rom : missing_roms) { + CSMissingROM *rom = [[CSMissingROM alloc] init]; + + // Copy/convert the primitive fields. + rom.fileName = [NSString stringWithUTF8String:missing_rom.file_name.c_str()]; + rom.descriptiveName = [NSString stringWithUTF8String:missing_rom.descriptive_name.c_str()]; + rom.size = missing_rom.size; + + // Convert the CRC list. + NSMutableArray *crc32s = [[NSMutableArray alloc] init]; + for(const auto &crc : missing_rom.crc32s) { + [crc32s addObject:@(crc)]; + } + rom.crc32s = [crc32s copy]; + + // Add to the missing list. + [missingROMs addObject:rom]; + } + + return nil; + } _inputMode = (_machine->keyboard_machine() && _machine->keyboard_machine()->get_keyboard().is_exclusive()) From e17b105574652f5bd302c78280920fcd5f72c995 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 11:18:39 -0400 Subject: [PATCH 10/22] Adds a quick label in exposition. --- .../Base.lproj/MachinePicker.xib | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib index b51807442..ad3c9b756 100644 --- a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib +++ b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib @@ -60,11 +60,14 @@ Gw + + + - + @@ -168,7 +171,7 @@ Gw - + + + + + + + + + + + + + + From 8de6cd3f44c88e2e6ad27f0f9d75761271c3d4c0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 17:18:31 -0400 Subject: [PATCH 13/22] Ensures that ROM files can be dragged and dropped into Swift. Also adjusts the main window background colour, better to bridge the time between selecting a machine and it starting. --- .../Clock Signal.xcodeproj/project.pbxproj | 10 ++++- .../Base.lproj/MachineDocument.xib | 13 ++++-- .../ClockSignal-Bridging-Header.h | 3 +- .../Documents/MachineDocument.swift | 9 ++++- .../ROMRequester/CSROMReceiverView.h | 27 +++++++++++++ .../ROMRequester/CSROMReceiverView.m | 40 +++++++++++++++++++ .../ROMRequester/ROMRequester.xib | 7 ++-- 7 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.h create mode 100644 OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.m diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 09108b7b7..aaef85a1f 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -666,8 +666,9 @@ 4BD67DD0209BF27B00AB2146 /* Encoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD67DCE209BF27B00AB2146 /* Encoder.cpp */; }; 4BD67DD1209BF27B00AB2146 /* Encoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD67DCE209BF27B00AB2146 /* Encoder.cpp */; }; 4BDA00DA22E60EE300AC3CD0 /* ROMRequester.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BDA00D922E60EE300AC3CD0 /* ROMRequester.xib */; }; - 4BDA00DC22E622BF00AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BDA00DD22E622C200AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; + 4BDA00E022E644AF00AC3CD0 /* CSROMReceiverView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDA00DF22E644AF00AC3CD0 /* CSROMReceiverView.m */; }; + 4BDA00E122E64ABE00AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; }; 4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE21F1DA19D7C0090D3CE /* Atari2600OptionsPanel.swift */; }; 4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; }; @@ -1476,6 +1477,8 @@ 4BD67DCF209BF27B00AB2146 /* Encoder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Encoder.hpp; sourceTree = ""; }; 4BD9137D1F311BC5009BCF85 /* i8255.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = i8255.hpp; path = 8255/i8255.hpp; sourceTree = ""; }; 4BDA00D922E60EE300AC3CD0 /* ROMRequester.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ROMRequester.xib; sourceTree = ""; }; + 4BDA00DE22E644AF00AC3CD0 /* CSROMReceiverView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSROMReceiverView.h; sourceTree = ""; }; + 4BDA00DF22E644AF00AC3CD0 /* CSROMReceiverView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CSROMReceiverView.m; sourceTree = ""; }; 4BDB3D8522833321002D3CEE /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = ""; }; 4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMMachine.hpp; sourceTree = ""; }; 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = ""; }; @@ -3305,6 +3308,8 @@ isa = PBXGroup; children = ( 4BDA00D922E60EE300AC3CD0 /* ROMRequester.xib */, + 4BDA00DE22E644AF00AC3CD0 /* CSROMReceiverView.h */, + 4BDA00DF22E644AF00AC3CD0 /* CSROMReceiverView.m */, ); path = ROMRequester; sourceTree = ""; @@ -3567,7 +3572,7 @@ 4B79E4441E3AF38600141F11 /* cassette.png in Resources */, 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, 4B8FE21D1DA19D5F0090D3CE /* QuickLoadCompositeOptions.xib in Resources */, - 4BDA00DC22E622BF00AC3CD0 /* ROMImages in Resources */, + 4BDA00E122E64ABE00AC3CD0 /* ROMImages in Resources */, 4B79E4461E3AF38600141F11 /* floppy525.png in Resources */, 4BEEE6BD20DC72EB003723BF /* CompositeOptions.xib in Resources */, 4B1497981EE4B97F00CE2596 /* ZX8081Options.xib in Resources */, @@ -4134,6 +4139,7 @@ 4B4518851F75E91A00926311 /* DiskController.cpp in Sources */, 4B8334841F5DA0360097E338 /* Z80Storage.cpp in Sources */, 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */, + 4BDA00E022E644AF00AC3CD0 /* CSROMReceiverView.m in Sources */, 4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */, 4BCD634922D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */, 4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/MachineDocument.xib b/OSBindings/Mac/Clock Signal/Base.lproj/MachineDocument.xib index b5225926c..0ed43edf8 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/MachineDocument.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/MachineDocument.xib @@ -1,8 +1,8 @@ - + - + @@ -14,7 +14,7 @@ - + @@ -25,7 +25,7 @@ - @@ -36,6 +36,11 @@ + + + + + diff --git a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h index 314208601..58bd8225d 100644 --- a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h +++ b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h @@ -10,8 +10,9 @@ #import "CSStaticAnalyser.h" -#import "CSOpenGLView.h" #import "CSAudioQueue.h" +#import "CSOpenGLView.h" +#import "CSROMReceiverView.h" #import "CSBestEffortUpdater.h" #import "CSJoystickManager.h" diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index a102cd546..57959a255 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -16,7 +16,8 @@ class MachineDocument: CSOpenGLViewDelegate, CSOpenGLViewResponderDelegate, CSBestEffortUpdaterDelegate, - CSAudioQueueDelegate + CSAudioQueueDelegate, + CSROMReciverViewDelegate { fileprivate let actionLock = NSLock() fileprivate let drawLock = NSLock() @@ -323,9 +324,11 @@ class MachineDocument: // MARK: User ROM provision. @IBOutlet var romRequesterPanel: NSWindow? @IBOutlet var romRequesterText: NSTextField? + @IBOutlet var romReceiverView: CSROMReceiverView? func requestRoms(missingROMs: NSMutableArray) { // Load the ROM requester dialogue. Bundle.main.loadNibNamed("ROMRequester", owner: self, topLevelObjects: nil) + self.romReceiverView!.delegate = self // Fill in the missing details; first build a list of all the individual // line items. @@ -361,6 +364,10 @@ class MachineDocument: close() } + func romReceiverView(_ view: CSROMReceiverView, didReceiveFileAt URL: URL) { + Swift.print("Should test " + URL.absoluteString) + } + // MARK: Joystick-via-the-keyboard selection @IBAction func useKeyboardAsKeyboard(_ sender: NSMenuItem?) { machine.inputMode = .keyboard diff --git a/OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.h b/OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.h new file mode 100644 index 000000000..9a489c2dd --- /dev/null +++ b/OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.h @@ -0,0 +1,27 @@ +// +// CSROMReceiverView.h +// Clock Signal +// +// Created by Thomas Harte on 22/07/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#import + +@class CSROMReceiverView; + +@protocol CSROMReciverViewDelegate +/*! + Announces receipt of a file by drag and drop to the delegate. + @param view The view making the request. + @param URL The file URL of the received file. +*/ +- (void)romReceiverView:(nonnull CSROMReceiverView *)view didReceiveFileAtURL:(nonnull NSURL *)URL; + +@end + +@interface CSROMReceiverView : NSView + +@property(nonatomic, weak, nullable) id delegate; + +@end diff --git a/OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.m b/OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.m new file mode 100644 index 000000000..cf1af86ec --- /dev/null +++ b/OSBindings/Mac/Clock Signal/ROMRequester/CSROMReceiverView.m @@ -0,0 +1,40 @@ +// +// CSROMReceiverView.m +// Clock Signal +// +// Created by Thomas Harte on 22/07/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#import "CSROMReceiverView.h" + +@interface CSROMReceiverView () +@end + + +@implementation CSROMReceiverView + +- (void)awakeFromNib { + [super awakeFromNib]; + + // Accept file URLs by drag and drop. + [self registerForDraggedTypes:@[(__bridge NSString *)kUTTypeFileURL]]; +} + +#pragma mark - NSDraggingDestination + +- (BOOL)performDragOperation:(id )sender { + // Just forward the URLs. + for(NSPasteboardItem *item in [[sender draggingPasteboard] pasteboardItems]) { + NSURL *URL = [NSURL URLWithString:[item stringForType:(__bridge NSString *)kUTTypeFileURL]]; + [self.delegate romReceiverView:self didReceiveFileAtURL:URL]; + } + return YES; +} + +- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender { + // The emulator will take a copy of any deposited ROM files. + return NSDragOperationCopy; +} + +@end diff --git a/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib b/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib index 9153b1bdb..ca28efdaf 100644 --- a/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib +++ b/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib @@ -8,6 +8,7 @@ + @@ -19,13 +20,13 @@ - + - + - + Clock Signal requires you to provide images of the system ROMs for this machine. They will be stored permanently; you need do this only once.

Please drag and drop the following over this view: From 2129bfc570a88d5aca560effb128650b4f70f44d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 18:02:48 -0400 Subject: [PATCH 14/22] Gets as far as testing ROMs against the missing list. Though now it strikes me that I've forgotten to retain the machine name. --- .../Clock Signal.xcodeproj/project.pbxproj | 14 +++-- .../ClockSignal-Bridging-Header.h | 2 + .../Documents/MachineDocument.swift | 56 +++++++++++++++++-- .../Mac/Clock Signal/Machine/NSData+CRC32.h | 17 ++++++ .../Mac/Clock Signal/Machine/NSData+CRC32.m | 19 +++++++ 5 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.h create mode 100644 OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.m diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index aaef85a1f..29d85df7c 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -668,7 +668,8 @@ 4BDA00DA22E60EE300AC3CD0 /* ROMRequester.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BDA00D922E60EE300AC3CD0 /* ROMRequester.xib */; }; 4BDA00DD22E622C200AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BDA00E022E644AF00AC3CD0 /* CSROMReceiverView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDA00DF22E644AF00AC3CD0 /* CSROMReceiverView.m */; }; - 4BDA00E122E64ABE00AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; + 4BDA00E422E663B900AC3CD0 /* NSData+CRC32.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDA00E222E663B900AC3CD0 /* NSData+CRC32.m */; }; + 4BDA00E522E669DC00AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; }; 4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE21F1DA19D7C0090D3CE /* Atari2600OptionsPanel.swift */; }; 4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; }; @@ -1479,6 +1480,8 @@ 4BDA00D922E60EE300AC3CD0 /* ROMRequester.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ROMRequester.xib; sourceTree = ""; }; 4BDA00DE22E644AF00AC3CD0 /* CSROMReceiverView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSROMReceiverView.h; sourceTree = ""; }; 4BDA00DF22E644AF00AC3CD0 /* CSROMReceiverView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CSROMReceiverView.m; sourceTree = ""; }; + 4BDA00E222E663B900AC3CD0 /* NSData+CRC32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+CRC32.m"; sourceTree = ""; }; + 4BDA00E322E663B900AC3CD0 /* NSData+CRC32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+CRC32.h"; sourceTree = ""; }; 4BDB3D8522833321002D3CEE /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = ""; }; 4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMMachine.hpp; sourceTree = ""; }; 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = ""; }; @@ -1742,13 +1745,15 @@ 4BBC34241D2208B100FFC9DF /* CSFastLoading.h */, 4B2A53951D117D36003C6002 /* CSMachine.h */, 4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */, - 4B98A05C1FFAD3F600ADF63B /* CSROMFetcher.hpp */, 4B2A53971D117D36003C6002 /* KeyCodes.h */, 4B8FE2251DA1DE2D0090D3CE /* NSBundle+DataResource.h */, + 4BDA00E322E663B900AC3CD0 /* NSData+CRC32.h */, 4BA61EAE1D91515900B3C876 /* NSData+StdVector.h */, - 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */, + 4B98A05C1FFAD3F600ADF63B /* CSROMFetcher.hpp */, 4B8FE2261DA1DE2D0090D3CE /* NSBundle+DataResource.m */, + 4BDA00E222E663B900AC3CD0 /* NSData+CRC32.m */, 4B2A53961D117D36003C6002 /* CSMachine.mm */, + 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */, 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */, 4B643F3B1D77AD6D00D431D6 /* StaticAnalyser */, 4B2A53981D117D36003C6002 /* Wrappers */, @@ -3572,7 +3577,7 @@ 4B79E4441E3AF38600141F11 /* cassette.png in Resources */, 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, 4B8FE21D1DA19D5F0090D3CE /* QuickLoadCompositeOptions.xib in Resources */, - 4BDA00E122E64ABE00AC3CD0 /* ROMImages in Resources */, + 4BDA00E522E669DC00AC3CD0 /* ROMImages in Resources */, 4B79E4461E3AF38600141F11 /* floppy525.png in Resources */, 4BEEE6BD20DC72EB003723BF /* CompositeOptions.xib in Resources */, 4B1497981EE4B97F00CE2596 /* ZX8081Options.xib in Resources */, @@ -4086,6 +4091,7 @@ 4B595FAD2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */, 4B1497921EE4B5A800CE2596 /* ZX8081.cpp in Sources */, 4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */, + 4BDA00E422E663B900AC3CD0 /* NSData+CRC32.m in Sources */, 4BB4BFB022A42F290069048D /* MacintoshIMG.cpp in Sources */, 4B05401E219D1618001BF69C /* ScanTarget.cpp in Sources */, 4B4518861F75E91A00926311 /* MFMDiskController.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h index 58bd8225d..5b21dd3fc 100644 --- a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h +++ b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h @@ -17,4 +17,6 @@ #import "CSBestEffortUpdater.h" #import "CSJoystickManager.h" +#import "NSData+CRC32.h" + #include "KeyCodes.h" diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 57959a255..edd7ebeb1 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -153,15 +153,27 @@ class MachineDocument: } // MARK: configuring + var missingROMs: [CSMissingROM] = [] + var selectedMachine: CSStaticAnalyser? + func configureAs(_ analysis: CSStaticAnalyser) { let missingROMs = NSMutableArray() if let machine = CSMachine(analyser: analysis, missingROMs: missingROMs) { + self.selectedMachine = nil self.machine = machine self.optionsPanelNibName = analysis.optionsPanelNibName setupMachineOutput() setupActivityDisplay() } else { - requestRoms(missingROMs: missingROMs) + // Store the selected machine and list of missing ROMs, and + // show the missing ROMs dialogue. + self.missingROMs = [] + for untypedMissingROM in missingROMs { + self.missingROMs.append(untypedMissingROM as! CSMissingROM) + } + + self.selectedMachine = analysis + requestRoms() } } @@ -325,7 +337,7 @@ class MachineDocument: @IBOutlet var romRequesterPanel: NSWindow? @IBOutlet var romRequesterText: NSTextField? @IBOutlet var romReceiverView: CSROMReceiverView? - func requestRoms(missingROMs: NSMutableArray) { + func requestRoms() { // Load the ROM requester dialogue. Bundle.main.loadNibNamed("ROMRequester", owner: self, topLevelObjects: nil) self.romReceiverView!.delegate = self @@ -333,8 +345,7 @@ class MachineDocument: // Fill in the missing details; first build a list of all the individual // line items. var requestLines: [String] = [] - for untypedMissingROM in missingROMs { - let missingROM = untypedMissingROM as! CSMissingROM + for missingROM in self.missingROMs { if let descriptiveName = missingROM.descriptiveName { requestLines.append("• " + descriptiveName) } else { @@ -365,7 +376,42 @@ class MachineDocument: } func romReceiverView(_ view: CSROMReceiverView, didReceiveFileAt URL: URL) { - Swift.print("Should test " + URL.absoluteString) + // Test whether the file identified matches any of the currently missing ROMs. + // If so then remove that ROM from the missing list and update the request screen. + // If no ROMs are still missing, start the machine. + do { + let fileData = try Data(contentsOf: URL) + + // Try to match by size first, CRC second. Accept that some ROMs may have + // some additional appended data. Arbitrarily allow them to be up to 10kb + // too large. + var index = 0 + for missingROM in self.missingROMs { + if fileData.count >= missingROM.size && fileData.count < missingROM.size + 10*1024 { + // Trim to size. + let trimmedData = fileData[0 ..< missingROM.size] + + // Get CRC. + if missingROM.crc32s.contains( (trimmedData as NSData).crc32 ) { + // This ROM matches; copy it into the application library, + // strike it from the missing ROM list and decide how to + // proceed. + Swift.print("Matches") + + self.missingROMs.remove(at: index) + break + } + } + + index = index + 1 + } + + if self.missingROMs.count == 0 { + Swift.print("Should start") + } + } catch let error { + Swift.print("TODO: couldn't open \(URL.absoluteString); \(error)") + } } // MARK: Joystick-via-the-keyboard selection diff --git a/OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.h b/OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.h new file mode 100644 index 000000000..c62f5ac97 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.h @@ -0,0 +1,17 @@ +// +// NSData+CRC32.m +// Clock Signal +// +// Created by Thomas Harte on 22/07/2019. +// Copyright 2019 Thomas Harte. All rights reserved. +// + +#import + +#include + +@interface NSData (CRC32) + +@property(nonnull, nonatomic, readonly) NSNumber *crc32; + +@end diff --git a/OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.m b/OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.m new file mode 100644 index 000000000..e31513f92 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Machine/NSData+CRC32.m @@ -0,0 +1,19 @@ +// +// NSData+CRC32.m +// Clock Signal +// +// Created by Thomas Harte on 22/07/2019. +// Copyright 2019 Thomas Harte. All rights reserved. +// + +#import "NSData+CRC32.h" + +#include + +@implementation NSData (StdVector) + +- (NSNumber *)crc32 { + return @(crc32(crc32(0, Z_NULL, 0), self.bytes, (uInt)self.length)); +} + +@end From 2432151bf8364eb1f365a45f10bd1d18ff4a26c6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 21:14:21 -0400 Subject: [PATCH 15/22] Puts machine name into ROMMachine::ROM. Also switches to idiomatic exit codes. --- Machines/AmstradCPC/AmstradCPC.cpp | 9 ++++--- Machines/Apple/AppleII/AppleII.cpp | 19 +++++++------- Machines/Apple/AppleII/DiskIICard.cpp | 5 ++-- Machines/Apple/Macintosh/Macintosh.cpp | 9 ++++--- Machines/ColecoVision/ColecoVision.cpp | 3 +-- .../Commodore/1540/Implementation/C1540.cpp | 2 +- Machines/Commodore/Vic-20/Vic20.cpp | 25 +++++++++--------- Machines/Electron/Electron.cpp | 13 +++++----- Machines/MSX/MSX.cpp | 13 +++++----- Machines/MasterSystem/MasterSystem.cpp | 2 +- Machines/Oric/Oric.cpp | 17 ++++++------ Machines/ROMMachine.hpp | 26 +++++++++++-------- Machines/ZX8081/ZX8081.cpp | 4 +-- .../Mac/Clock Signal/Machine/CSROMFetcher.mm | 4 +-- OSBindings/SDL/main.cpp | 25 +++++++++--------- 15 files changed, 92 insertions(+), 84 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 05bf98f3a..c1ad3173f 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -781,8 +781,9 @@ template class ConcreteMachine: ay_.ay().set_port_handler(&key_state_); // construct the list of necessary ROMs + const std::string machine_name = "AmstradCPC"; std::vector required_roms = { - ROMMachine::ROM("the Amstrad Disk Operating System", "amsdos.rom", 16*1024, 0x1fe22ecd) + ROMMachine::ROM(machine_name, "the Amstrad Disk Operating System", "amsdos.rom", 16*1024, 0x1fe22ecd) }; std::string model_number; uint32_t crcs[2]; @@ -806,11 +807,11 @@ template class ConcreteMachine: crcs[1] = 0x32fee492; break; } - required_roms.emplace_back("the CPC " + model_number + "firmware", "os" + model_number + ".rom", 16*1024, crcs[0]); - required_roms.emplace_back("the CPC " + model_number + "BASIC ROM", "basic" + model_number + ".rom", 16*1024, crcs[1]); + required_roms.emplace_back(machine_name, "the CPC " + model_number + "firmware", "os" + model_number + ".rom", 16*1024, crcs[0]); + required_roms.emplace_back(machine_name, "the CPC " + model_number + "BASIC ROM", "basic" + model_number + ".rom", 16*1024, crcs[1]); // fetch and verify the ROMs - const auto roms = rom_fetcher("AmstradCPC", required_roms); + const auto roms = rom_fetcher(required_roms); for(std::size_t index = 0; index < roms.size(); ++index) { auto &data = roms[index]; diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 67435b4c5..8e04458d5 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -347,29 +347,30 @@ template class ConcreteMachine: // Pick the required ROMs. using Target = Analyser::Static::AppleII::Target; + const std::string machine_name = "AppleII"; std::vector rom_descriptions; size_t rom_size = 12*1024; switch(target.model) { default: - rom_descriptions.emplace_back("the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6); - rom_descriptions.emplace_back("the original Apple II ROM", "apple2o.rom", 12*1024, 0xba210588); + rom_descriptions.emplace_back(machine_name, "the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6); + rom_descriptions.emplace_back(machine_name, "the original Apple II ROM", "apple2o.rom", 12*1024, 0xba210588); break; case Target::Model::IIplus: - rom_descriptions.emplace_back("the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6); - rom_descriptions.emplace_back("the Apple II+ ROM", "apple2.rom", 12*1024, 0xf66f9c26); + rom_descriptions.emplace_back(machine_name, "the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6); + rom_descriptions.emplace_back(machine_name, "the Apple II+ ROM", "apple2.rom", 12*1024, 0xf66f9c26); break; case Target::Model::IIe: rom_size += 3840; - rom_descriptions.emplace_back("the Apple IIe character ROM", "apple2eu-character.rom", 4*1024, 0x816a86f1); - rom_descriptions.emplace_back("the Apple IIe ROM", "apple2eu.rom", 32*1024, 0xe12be18d); + rom_descriptions.emplace_back(machine_name, "the Apple IIe character ROM", "apple2eu-character.rom", 4*1024, 0x816a86f1); + rom_descriptions.emplace_back(machine_name, "the Apple IIe ROM", "apple2eu.rom", 32*1024, 0xe12be18d); break; case Target::Model::EnhancedIIe: rom_size += 3840; - rom_descriptions.emplace_back("the Enhanced Apple IIe character ROM", "apple2e-character.rom", 4*1024, 0x2651014d); - rom_descriptions.emplace_back("the Enhanced Apple IIe ROM", "apple2e.rom", 32*1024, 0x65989942); + rom_descriptions.emplace_back(machine_name, "the Enhanced Apple IIe character ROM", "apple2e-character.rom", 4*1024, 0x2651014d); + rom_descriptions.emplace_back(machine_name, "the Enhanced Apple IIe ROM", "apple2e.rom", 32*1024, 0x65989942); break; } - const auto roms = rom_fetcher("AppleII", rom_descriptions); + const auto roms = rom_fetcher(rom_descriptions); if(!roms[0] || !roms[1]) { throw ROMMachine::Error::MissingROMs; diff --git a/Machines/Apple/AppleII/DiskIICard.cpp b/Machines/Apple/AppleII/DiskIICard.cpp index 869770bfc..4bb530d27 100644 --- a/Machines/Apple/AppleII/DiskIICard.cpp +++ b/Machines/Apple/AppleII/DiskIICard.cpp @@ -12,10 +12,9 @@ using namespace Apple::II; DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector) : diskii_(2045454) { const auto roms = rom_fetcher( - "DiskII", { - ROMMachine::ROM(is_16_sector ? "boot-16.rom" : "boot-13.rom"), - ROMMachine::ROM(is_16_sector ? "state-machine-16.rom" : "state-machine-13.rom") + {"DiskII", is_16_sector ? "boot-16.rom" : "boot-13.rom"}, + {"DiskII", is_16_sector ? "state-machine-16.rom" : "state-machine-13.rom"} }); boot_ = std::move(*roms[0]); diskii_.set_state_machine(*roms[1]); diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index 3915edadd..32f979528 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -70,6 +70,7 @@ template class ConcreteMachin // Select a ROM name and determine the proper ROM and RAM sizes // based on the machine model. using Model = Analyser::Static::Macintosh::Target::Model; + const std::string machine_name = "Macintosh"; uint32_t ram_size, rom_size; std::vector rom_descriptions; switch(model) { @@ -77,19 +78,19 @@ template class ConcreteMachin case Model::Mac128k: ram_size = 128*1024; rom_size = 64*1024; - rom_descriptions.emplace_back("the Macintosh 128k ROM", "mac128k.rom", 64*1024, 0x6d0c8a28); + rom_descriptions.emplace_back(machine_name, "the Macintosh 128k ROM", "mac128k.rom", 64*1024, 0x6d0c8a28); break; case Model::Mac512k: ram_size = 512*1024; rom_size = 64*1024; - rom_descriptions.emplace_back("the Macintosh 512k ROM", "mac512k.rom", 64*1024, 0xcf759e0d); + rom_descriptions.emplace_back(machine_name, "the Macintosh 512k ROM", "mac512k.rom", 64*1024, 0xcf759e0d); break; case Model::Mac512ke: case Model::MacPlus: { ram_size = 512*1024; rom_size = 128*1024; const std::initializer_list crc32s = { 0x4fa5b399, 0x7cacd18f, 0xb2102e8e }; - rom_descriptions.emplace_back("the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s); + rom_descriptions.emplace_back(machine_name, "the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s); } break; } ram_mask_ = (ram_size >> 1) - 1; @@ -97,7 +98,7 @@ template class ConcreteMachin video_.set_ram_mask(ram_mask_); // Grab a copy of the ROM and convert it into big-endian data. - const auto roms = rom_fetcher("Macintosh", rom_descriptions); + const auto roms = rom_fetcher(rom_descriptions); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index 8ffde6ecf..d699a4016 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -131,8 +131,7 @@ class ConcreteMachine: joysticks_.emplace_back(new Joystick); const auto roms = rom_fetcher( - "ColecoVision", - { ROMMachine::ROM("the ColecoVision BIOS", "coleco.rom", 8*1024, 0x3aa93ef3) }); + { {"ColecoVision", "the ColecoVision BIOS", "coleco.rom", 8*1024, 0x3aa93ef3} }); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; diff --git a/Machines/Commodore/1540/Implementation/C1540.cpp b/Machines/Commodore/1540/Implementation/C1540.cpp index d88b6f152..515dee334 100644 --- a/Machines/Commodore/1540/Implementation/C1540.cpp +++ b/Machines/Commodore/1540/Implementation/C1540.cpp @@ -52,7 +52,7 @@ MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher & break; } - auto roms = rom_fetcher("Commodore1540", { ROMMachine::ROM("the " + device_name + " ROM", device_name + ".bin", 16*1024, crc) }); + auto roms = rom_fetcher({ {"Commodore1540", "the " + device_name + " ROM", device_name + ".bin", 16*1024, crc} }); if(!roms[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 342d3cdb9..84c1b05f1 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -323,31 +323,32 @@ class ConcreteMachine: // install a joystick joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); - std::vector rom_names = { ROMMachine::ROM("basic.bin") }; + const std::string machine_name = "Vic20"; + std::vector rom_names = { {machine_name, "basic.bin"} }; switch(target.region) { default: - rom_names.emplace_back("characters-english.bin"); - rom_names.emplace_back("kernel-pal.bin"); + rom_names.emplace_back(machine_name, "characters-english.bin"); + rom_names.emplace_back(machine_name, "kernel-pal.bin"); break; case Analyser::Static::Commodore::Target::Region::American: - rom_names.emplace_back("characters-english.bin"); - rom_names.emplace_back("kernel-ntsc.bin"); + rom_names.emplace_back(machine_name, "characters-english.bin"); + rom_names.emplace_back(machine_name, "kernel-ntsc.bin"); break; case Analyser::Static::Commodore::Target::Region::Danish: - rom_names.emplace_back("characters-danish.bin"); - rom_names.emplace_back("kernel-danish.bin"); + rom_names.emplace_back(machine_name, "characters-danish.bin"); + rom_names.emplace_back(machine_name, "kernel-danish.bin"); break; case Analyser::Static::Commodore::Target::Region::Japanese: - rom_names.emplace_back("characters-japanese.bin"); - rom_names.emplace_back("kernel-japanese.bin"); + rom_names.emplace_back(machine_name, "characters-japanese.bin"); + rom_names.emplace_back(machine_name, "kernel-japanese.bin"); break; case Analyser::Static::Commodore::Target::Region::Swedish: - rom_names.emplace_back("characters-swedish.bin"); - rom_names.emplace_back("kernel-japanese.bin"); + rom_names.emplace_back(machine_name, "characters-swedish.bin"); + rom_names.emplace_back(machine_name, "kernel-japanese.bin"); break; } - const auto roms = rom_fetcher("Vic20", rom_names); + const auto roms = rom_fetcher(rom_names); for(const auto &rom: roms) { if(!rom) { diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 48378fb2e..f0a31815e 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -64,19 +64,20 @@ class ConcreteMachine: speaker_.set_input_rate(2000000 / SoundGenerator::clock_rate_divider); speaker_.set_high_frequency_cutoff(7000); + const std::string machine_name = "Electron"; std::vector required_roms = { - {"the Acorn BASIC II ROM", "basic.rom", 16*1024, 0x79434781}, - {"the Electron MOS ROM", "os.rom", 16*1024, 0xbf63fb1f} + {machine_name, "the Acorn BASIC II ROM", "basic.rom", 16*1024, 0x79434781}, + {machine_name, "the Electron MOS ROM", "os.rom", 16*1024, 0xbf63fb1f} }; if(target.has_adfs) { - required_roms.emplace_back("the E00 ADFS ROM, first slot", "ADFS-E00_1.rom", 16*1024, 0x51523993); - required_roms.emplace_back("the E00 ADFS ROM, second slot", "ADFS-E00_2.rom", 16*1024, 0x8d17de0e); + required_roms.emplace_back(machine_name, "the E00 ADFS ROM, first slot", "ADFS-E00_1.rom", 16*1024, 0x51523993); + required_roms.emplace_back(machine_name, "the E00 ADFS ROM, second slot", "ADFS-E00_2.rom", 16*1024, 0x8d17de0e); } const size_t dfs_rom_position = required_roms.size(); if(target.has_dfs) { - required_roms.emplace_back("the 1770 DFS ROM", "DFS-1770-2.20.rom", 16*1024, 0xf3dc9bc5); + required_roms.emplace_back(machine_name, "the 1770 DFS ROM", "DFS-1770-2.20.rom", 16*1024, 0xf3dc9bc5); } - const auto roms = rom_fetcher("Electron", required_roms); + const auto roms = rom_fetcher(required_roms); for(const auto &rom: roms) { if(!rom) { diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index e99a3e834..a4b563d01 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -173,8 +173,9 @@ class ConcreteMachine: mixer_.set_relative_volumes({0.5f, 0.1f, 0.4f}); // Install the proper TV standard and select an ideal BIOS name. + const std::string machine_name = "MSX"; std::vector required_roms = { - {"any MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3} + {machine_name, "any MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3} }; bool is_ntsc = true; @@ -185,7 +186,7 @@ class ConcreteMachine: // TODO: CRCs below are incomplete, at best. switch(target.region) { case Target::Region::Japan: - required_roms.emplace_back("a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390); + required_roms.emplace_back(machine_name, "a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390); vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC); is_ntsc = true; @@ -193,7 +194,7 @@ class ConcreteMachine: date_format = 0; break; case Target::Region::USA: - required_roms.emplace_back("an American MSX BIOS", "msx-american.rom", 32*1024, 0); + required_roms.emplace_back(machine_name, "an American MSX BIOS", "msx-american.rom", 32*1024, 0); vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC); is_ntsc = true; @@ -201,7 +202,7 @@ class ConcreteMachine: date_format = 1; break; case Target::Region::Europe: - required_roms.emplace_back("a European MSX BIOS", "msx-european.rom", 32*1024, 0); + required_roms.emplace_back(machine_name, "a European MSX BIOS", "msx-european.rom", 32*1024, 0); vdp_.set_tv_standard(TI::TMS::TVStandard::PAL); is_ntsc = false; @@ -215,9 +216,9 @@ class ConcreteMachine: size_t disk_index = 0; if(target.has_disk_drive) { disk_index = required_roms.size(); - required_roms.emplace_back("the MSX-DOS ROM", "disk.rom", 16*1024, 0x721f61df); + required_roms.emplace_back(machine_name, "the MSX-DOS ROM", "disk.rom", 16*1024, 0x721f61df); } - const auto roms = rom_fetcher("MSX", required_roms); + const auto roms = rom_fetcher(required_roms); if((!roms[0] && !roms[1]) || (target.has_disk_drive && !roms[2])) { throw ROMMachine::Error::MissingROMs; diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index abde5b954..05b37493e 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -134,7 +134,7 @@ class ConcreteMachine: if(has_bios()) { // TODO: there's probably a million other versions of the Master System BIOS; try to build a // CRC32 catalogue of those. - const auto roms = rom_fetcher("MasterSystem", { {"the Master System BIOS", "bios.sms", 8*1024, 0x0072ed54} }); + const auto roms = rom_fetcher({ {"MasterSystem", "the Master System BIOS", "bios.sms", 8*1024, 0x0072ed54} }); if(!roms[0]) { // No BIOS found; attempt to boot as though it has already disabled itself. memory_control_ |= 0x08; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 5382dc710..37bf52b4f 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -228,19 +228,20 @@ template class Co diskii_.set_clocking_hint_observer(this); } - std::vector rom_names = { {"colour.rom"} }; + const std::string machine_name = "Oric"; + std::vector rom_names = { {machine_name, "colour.rom"} }; switch(target.rom) { - case Analyser::Static::Oric::Target::ROM::BASIC10: rom_names.emplace_back("basic10.rom"); break; - case Analyser::Static::Oric::Target::ROM::BASIC11: rom_names.emplace_back("basic11.rom"); break; - case Analyser::Static::Oric::Target::ROM::Pravetz: rom_names.emplace_back("pravetz.rom"); break; + case Analyser::Static::Oric::Target::ROM::BASIC10: rom_names.emplace_back(machine_name, "basic10.rom"); break; + case Analyser::Static::Oric::Target::ROM::BASIC11: rom_names.emplace_back(machine_name, "basic11.rom"); break; + case Analyser::Static::Oric::Target::ROM::Pravetz: rom_names.emplace_back(machine_name, "pravetz.rom"); break; } switch(disk_interface) { default: break; - case Analyser::Static::Oric::Target::DiskInterface::Microdisc: rom_names.emplace_back("microdisc.rom"); break; - case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.emplace_back("8dos.rom"); break; + case Analyser::Static::Oric::Target::DiskInterface::Microdisc: rom_names.emplace_back(machine_name, "microdisc.rom"); break; + case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.emplace_back(machine_name, "8dos.rom"); break; } - const auto roms = rom_fetcher("Oric", rom_names); + const auto roms = rom_fetcher(rom_names); for(std::size_t index = 0; index < roms.size(); ++index) { if(!roms[index]) { @@ -261,7 +262,7 @@ template class Co pravetz_rom_ = std::move(*roms[2]); pravetz_rom_.resize(512); - auto state_machine_rom = rom_fetcher("DiskII", { ROMMachine::ROM("state-machine-16.rom") }); + auto state_machine_rom = rom_fetcher({ {"DiskII", "state-machine-16.rom"} }); if(!state_machine_rom[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/ROMMachine.hpp b/Machines/ROMMachine.hpp index 3b47fb41a..071eb68f4 100644 --- a/Machines/ROMMachine.hpp +++ b/Machines/ROMMachine.hpp @@ -21,7 +21,11 @@ namespace ROMMachine { system software that is an inherent part of a machine. */ struct ROM { - /// A descriptive name for this ROM, e.g. "Electron MOS 1.0". + /// The machine with which this ROM is associated, in a form that is safe for using as + /// part of a file name. + std::string machine_name; + /// A descriptive name for this ROM, suitable for use in a bullet-point list, a bracket + /// clause, etc, e.g. "the Electron MOS 1.0". std::string descriptive_name; /// An idiomatic file name for this ROM, e.g. "os10.rom". std::string file_name; @@ -33,24 +37,24 @@ struct ROM { std::vector crc32s; /// This is a temporary constructor provided for transitional purposes. - ROM(std::string file_name) : - file_name(file_name) {} + ROM(std::string machine_name, std::string file_name) : + machine_name(machine_name), file_name(file_name) {} - ROM(std::string descriptive_name, std::string file_name, size_t size, uint32_t crc32) : - descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s({crc32}) {} - ROM(std::string descriptive_name, std::string file_name, size_t size, std::initializer_list crc32s) : - descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s(crc32s) {} + ROM(std::string machine_name, std::string descriptive_name, std::string file_name, size_t size, uint32_t crc32) : + machine_name(machine_name), descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s({crc32}) {} + ROM(std::string machine_name, std::string descriptive_name, std::string file_name, size_t size, std::initializer_list crc32s) : + machine_name(machine_name), descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s(crc32s) {} }; /*! Defines the signature for a function that must be supplied by the host environment in order to give machines a route for fetching any system ROMs they might need. - The caller will supply the idiomatic name of the machine plus a vector of the names of ROM files that it expects - to be present. The recevier should return a vector of unique_ptrs that either contain the contents of the - ROM from @c names that corresponds by index, or else are the nullptr + The caller will supply a vector of the names of ROM files that it would like to inspect. The recevier should + return a vector of unique_ptrs that either contain the contents of the ROM from @c names that corresponds by + index, or else are @c nullptr. */ -typedef std::function>>(const std::string &machine, const std::vector &roms)> ROMFetcher; +typedef std::function>>(const std::vector &roms)> ROMFetcher; enum class Error { MissingROMs diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index fcf995060..024601e41 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -78,8 +78,8 @@ template class ConcreteMachine: const bool use_zx81_rom = target.is_ZX81 || target.ZX80_uses_ZX81_ROM; const auto roms = use_zx81_rom ? - rom_fetcher("ZX8081", { {"the ZX81 ROM", "zx81.rom", 8 * 1024, 0x4b1dd6eb} }) : - rom_fetcher("ZX8081", { {"the ZX80 ROM", "zx80.rom", 4 * 1024, 0x4c7fc597} }); + rom_fetcher({ {"ZX8081", "the ZX81 BASIC ROM", "zx81.rom", 8 * 1024, 0x4b1dd6eb} }) : + rom_fetcher({ {"ZX8081", "the ZX80 BASIC ROM", "zx80.rom", 4 * 1024, 0x4c7fc597} }); if(!roms[0]) throw ROMMachine::Error::MissingROMs; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm index 9345040c0..474a36b41 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSROMFetcher.mm @@ -15,13 +15,13 @@ #include ROMMachine::ROMFetcher CSROMFetcher(std::vector *missing_roms) { - return [missing_roms] (const std::string &machine, const std::vector &roms) -> std::vector>> { - NSString *const subdirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:machine.c_str()]]; + return [missing_roms] (const std::vector &roms) -> std::vector>> { NSArray *const supportURLs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask]; std::vector>> results; for(const auto &rom: roms) { NSData *fileData; + NSString *const subdirectory = [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:rom.machine_name.c_str()]]; // Check for this file first within the application support directories. for(NSURL *supportURL in supportURLs) { diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 301f5ccb5..ffa356b30 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -339,21 +340,21 @@ int main(int argc, char *argv[]) { } std::cout << std::endl; } - return 0; + return EXIT_SUCCESS; } // Perform a sanity check on arguments. if(arguments.file_name.empty()) { std::cerr << "Usage: " << final_path_component(argv[0]) << usage_suffix << std::endl; std::cerr << "Use --help to learn more about available options." << std::endl; - return -1; + return EXIT_FAILURE; } // Determine the machine for the supplied file. Analyser::Static::TargetList targets = Analyser::Static::GetTargets(arguments.file_name); if(targets.empty()) { std::cerr << "Cannot open " << arguments.file_name << "; no target machine found" << std::endl; - return -1; + return EXIT_FAILURE; } Concurrency::BestEffortUpdater updater; @@ -366,11 +367,9 @@ int main(int argc, char *argv[]) { // /usr/share/CLK/[system]; or // [user-supplied path]/[system] std::vector requested_roms; - std::string machine_name; - ROMMachine::ROMFetcher rom_fetcher = [&requested_roms, &machine_name, &arguments] - (const std::string &machine, const std::vector &roms) -> std::vector>> { + ROMMachine::ROMFetcher rom_fetcher = [&requested_roms, &arguments] + (const std::vector &roms) -> std::vector>> { requested_roms.insert(requested_roms.end(), roms.begin(), roms.end()); - machine_name = machine; std::vector paths = { "/usr/local/share/CLK/", @@ -389,7 +388,7 @@ int main(int argc, char *argv[]) { for(const auto &rom: roms) { FILE *file = nullptr; for(const auto &path: paths) { - std::string local_path = path + machine + "/" + rom.file_name; + std::string local_path = path + rom.machine_name + "/" + rom.file_name; file = std::fopen(local_path.c_str(), "rb"); if(file) break; } @@ -426,7 +425,7 @@ int main(int argc, char *argv[]) { std::cerr << "Could not find system ROMs; please install to /usr/local/share/CLK/ or /usr/share/CLK/, or provide a --rompath." << std::endl; std::cerr << "One or more of the following was needed but not found:" << std::endl; for(const auto &rom: requested_roms) { - std::cerr << machine_name << '/' << rom.file_name; + std::cerr << rom.machine_name << '/' << rom.file_name; if(!rom.descriptive_name.empty()) { std::cerr << " (" << rom.descriptive_name << ")"; } @@ -435,7 +434,7 @@ int main(int argc, char *argv[]) { break; } - return -1; + return EXIT_FAILURE; } best_effort_updater_delegate.machine = machine.get(); @@ -445,7 +444,7 @@ int main(int argc, char *argv[]) { // Attempt to set up video and audio. if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl; - return -1; + return EXIT_FAILURE; } // Ask for no depth buffer, a core profile and vsync-aligned rendering. @@ -467,7 +466,7 @@ int main(int argc, char *argv[]) { if(!window || !gl_context) { std::cerr << "Could not create " << (window ? "OpenGL context" : "window"); std::cerr << "; reported error: \"" << SDL_GetError() << "\"" << std::endl; - return -1; + return EXIT_FAILURE; } SDL_GL_MakeCurrent(window, gl_context); @@ -820,5 +819,5 @@ int main(int argc, char *argv[]) { SDL_DestroyWindow( window ); SDL_Quit(); - return 0; + return EXIT_SUCCESS; } From ed0c4c117b2882974ccf667560247e7b01d22ad3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 21:18:30 -0400 Subject: [PATCH 16/22] Ensures that machine name reaches Swift. --- OSBindings/Mac/Clock Signal/Machine/CSMachine.h | 1 + OSBindings/Mac/Clock Signal/Machine/CSMachine.mm | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index 0a6e7496c..7a14bf721 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -34,6 +34,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) { }; @interface CSMissingROM: NSObject +@property (nonatomic, readonly, nonnull) NSString *machineName; @property (nonatomic, readonly, nonnull) NSString *fileName; @property (nonatomic, readonly, nullable) NSString *descriptiveName; @property (nonatomic, readonly) NSUInteger size; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 59476a9c0..28e755a8e 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -75,6 +75,7 @@ struct ActivityObserver: public Activity::Observer { }; @interface CSMissingROM (Mutability) +@property (nonatomic, nonnull, copy) NSString *machineName; @property (nonatomic, nonnull, copy) NSString *fileName; @property (nonatomic, nullable, copy) NSString *descriptiveName; @property (nonatomic, readwrite) NSUInteger size; @@ -82,12 +83,21 @@ struct ActivityObserver: public Activity::Observer { @end @implementation CSMissingROM { + NSString *_machineName; NSString *_fileName; NSString *_descriptiveName; NSUInteger _size; NSArray *_crc32s; } +- (NSString *)machineName { + return _machineName; +} + +- (void)setMachineName:(NSString *)machineName { + _machineName = [machineName copy]; +} + - (NSString *)fileName { return _fileName; } @@ -155,8 +165,9 @@ struct ActivityObserver: public Activity::Observer { CSMissingROM *rom = [[CSMissingROM alloc] init]; // Copy/convert the primitive fields. + rom.machineName = [NSString stringWithUTF8String:missing_rom.machine_name.c_str()]; rom.fileName = [NSString stringWithUTF8String:missing_rom.file_name.c_str()]; - rom.descriptiveName = [NSString stringWithUTF8String:missing_rom.descriptive_name.c_str()]; + rom.descriptiveName = missing_rom.descriptive_name.empty() ? nil : [NSString stringWithUTF8String:missing_rom.descriptive_name.c_str()]; rom.size = missing_rom.size; // Convert the CRC list. From a3ad0ab09b9d88ac9b21e7d6ce33d45e6cefbb1d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 21:46:28 -0400 Subject: [PATCH 17/22] Completes the successful import path. --- .../Clock Signal.xcodeproj/project.pbxproj | 6 +-- .../Documents/MachineDocument.swift | 46 ++++++++++++++----- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 29d85df7c..0c8c3b434 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -145,7 +145,6 @@ 4B1EDB451E39A0AC009D6819 /* chip.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B1EDB431E39A0AC009D6819 /* chip.png */; }; 4B2A332D1DB86821002876E3 /* OricOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2A332B1DB86821002876E3 /* OricOptions.xib */; }; 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; }; - 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53961D117D36003C6002 /* CSMachine.mm */; }; 4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A471F9B8FA70062DABF /* Typer.cpp */; }; 4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A481F9B8FA70062DABF /* MemoryFuzzer.cpp */; }; 4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */; }; @@ -669,7 +668,7 @@ 4BDA00DD22E622C200AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BDA00E022E644AF00AC3CD0 /* CSROMReceiverView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDA00DF22E644AF00AC3CD0 /* CSROMReceiverView.m */; }; 4BDA00E422E663B900AC3CD0 /* NSData+CRC32.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDA00E222E663B900AC3CD0 /* NSData+CRC32.m */; }; - 4BDA00E522E669DC00AC3CD0 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; + 4BDA00E622E699B000AC3CD0 /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53961D117D36003C6002 /* CSMachine.mm */; }; 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; }; 4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE21F1DA19D7C0090D3CE /* Atari2600OptionsPanel.swift */; }; 4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; }; @@ -3577,7 +3576,6 @@ 4B79E4441E3AF38600141F11 /* cassette.png in Resources */, 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, 4B8FE21D1DA19D5F0090D3CE /* QuickLoadCompositeOptions.xib in Resources */, - 4BDA00E522E669DC00AC3CD0 /* ROMImages in Resources */, 4B79E4461E3AF38600141F11 /* floppy525.png in Resources */, 4BEEE6BD20DC72EB003723BF /* CompositeOptions.xib in Resources */, 4B1497981EE4B97F00CE2596 /* ZX8081Options.xib in Resources */, @@ -4124,6 +4122,7 @@ 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, 4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */, 4B7913CC1DFCD80E00175A82 /* Video.cpp in Sources */, + 4BDA00E622E699B000AC3CD0 /* CSMachine.mm in Sources */, 4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */, 4B45189F1F75FD1C00926311 /* AcornADF.cpp in Sources */, 4B7136911F789C93008B8ED9 /* SegmentParser.cpp in Sources */, @@ -4219,7 +4218,6 @@ 4BF437EE209D0F7E008CBD6B /* SegmentParser.cpp in Sources */, 4B8334861F5DA3780097E338 /* 6502Storage.cpp in Sources */, 4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */, - 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */, 4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */, 4B55DD8320DF06680043F2E5 /* MachinePicker.swift in Sources */, 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index edd7ebeb1..20e9bc301 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -153,8 +153,8 @@ class MachineDocument: } // MARK: configuring - var missingROMs: [CSMissingROM] = [] - var selectedMachine: CSStaticAnalyser? + fileprivate var missingROMs: [CSMissingROM] = [] + fileprivate var selectedMachine: CSStaticAnalyser? func configureAs(_ analysis: CSStaticAnalyser) { let missingROMs = NSMutableArray() @@ -337,11 +337,25 @@ class MachineDocument: @IBOutlet var romRequesterPanel: NSWindow? @IBOutlet var romRequesterText: NSTextField? @IBOutlet var romReceiverView: CSROMReceiverView? + var romRequestBaseText = "" func requestRoms() { // Load the ROM requester dialogue. Bundle.main.loadNibNamed("ROMRequester", owner: self, topLevelObjects: nil) self.romReceiverView!.delegate = self + self.romRequestBaseText = romRequesterText!.stringValue + // Populate the current absentee list. + populateMissingRomList() + + // Show the thing. + self.windowControllers[0].window?.beginSheet(self.romRequesterPanel!, completionHandler: nil) + } + + @IBAction func cancelRequestROMs(_ sender: NSButton?) { + close() + } + + func populateMissingRomList() { // Fill in the missing details; first build a list of all the individual // line items. var requestLines: [String] = [] @@ -365,14 +379,7 @@ class MachineDocument: requestLines[x].append(".") } } - romRequesterText!.stringValue += requestLines.joined(separator: "\n") - - // Show the thing. - self.windowControllers[0].window?.beginSheet(self.romRequesterPanel!, completionHandler: nil) - } - - @IBAction func cancelRequestROMs(_ sender: NSButton?) { - close() + romRequesterText!.stringValue = self.romRequestBaseText + requestLines.joined(separator: "\n") } func romReceiverView(_ view: CSROMReceiverView, didReceiveFileAt URL: URL) { @@ -396,7 +403,19 @@ class MachineDocument: // This ROM matches; copy it into the application library, // strike it from the missing ROM list and decide how to // proceed. - Swift.print("Matches") + let fileManager = FileManager.default + let targetPath = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] + .appendingPathComponent("ROMImages") + .appendingPathComponent(missingROM.machineName) + let targetFile = targetPath + .appendingPathComponent(missingROM.fileName) + + do { + try fileManager.createDirectory(atPath: targetPath.path, withIntermediateDirectories: true, attributes: nil) + try trimmedData.write(to: targetFile) + } catch let error { + Swift.print("Some sort of error \(error)") + } self.missingROMs.remove(at: index) break @@ -407,7 +426,10 @@ class MachineDocument: } if self.missingROMs.count == 0 { - Swift.print("Should start") + self.windowControllers[0].window?.endSheet(self.romRequesterPanel!) + configureAs(self.selectedMachine!) + } else { + populateMissingRomList() } } catch let error { Swift.print("TODO: couldn't open \(URL.absoluteString); \(error)") From dbee37ab34c877f8bde399667b378a0925aab7ad Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 22:15:44 -0400 Subject: [PATCH 18/22] Provides extended ROM details for the VIC-20 and Oric. --- Machines/Apple/AppleII/DiskIICard.cpp | 15 +++++++++++---- Machines/Commodore/Vic-20/Vic20.cpp | 24 +++++++++++++----------- Machines/MasterSystem/MasterSystem.cpp | 7 +++++-- Machines/Oric/Oric.cpp | 25 ++++++++++++++++++------- Machines/ROMMachine.hpp | 4 ---- 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Machines/Apple/AppleII/DiskIICard.cpp b/Machines/Apple/AppleII/DiskIICard.cpp index 4bb530d27..dae7b30cf 100644 --- a/Machines/Apple/AppleII/DiskIICard.cpp +++ b/Machines/Apple/AppleII/DiskIICard.cpp @@ -11,11 +11,18 @@ using namespace Apple::II; DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector) : diskii_(2045454) { - const auto roms = rom_fetcher( - { - {"DiskII", is_16_sector ? "boot-16.rom" : "boot-13.rom"}, - {"DiskII", is_16_sector ? "state-machine-16.rom" : "state-machine-13.rom"} + std::vector>> roms; + if(is_16_sector) { + roms = rom_fetcher({ + {"DiskII", "the Disk II 16-sector boot ROM", "boot-16.rom", 256, 0xce7144f6}, + {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0xce7144f6, 0xb72a2c70 } } }); + } else { + roms = rom_fetcher({ + {"DiskII", "the Disk II 13-sector boot ROM", "boot-13.rom", 256, 0xd34eb2ff}, + {"DiskII", "the Disk II 13-sector state machine ROM", "state-machine-13.rom", 256, 0x62e22620 } + }); + } boot_ = std::move(*roms[0]); diskii_.set_state_machine(*roms[1]); set_select_constraints(None); diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 84c1b05f1..2ac58a2e5 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -324,27 +324,29 @@ class ConcreteMachine: joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); const std::string machine_name = "Vic20"; - std::vector rom_names = { {machine_name, "basic.bin"} }; + std::vector rom_names = { + {machine_name, "the VIC-20 BASIC ROM", "basic.bin", 8*1024, 0xdb4c43c1} + }; switch(target.region) { default: - rom_names.emplace_back(machine_name, "characters-english.bin"); - rom_names.emplace_back(machine_name, "kernel-pal.bin"); + rom_names.emplace_back(machine_name, "the English-language VIC-20 character ROM", "characters-english.bin", 4*1024, 0x83e032a6); + rom_names.emplace_back(machine_name, "the English-language PAL VIC-20 kernel ROM", "kernel-pal.bin", 8*1024, 0x4be07cb4); break; case Analyser::Static::Commodore::Target::Region::American: - rom_names.emplace_back(machine_name, "characters-english.bin"); - rom_names.emplace_back(machine_name, "kernel-ntsc.bin"); + rom_names.emplace_back(machine_name, "the English-language VIC-20 character ROM", "characters-english.bin", 4*1024, 0x83e032a6); + rom_names.emplace_back(machine_name, "the English-language NTSC VIC-20 kernel ROM", "kernel-ntsc.bin", 8*1024, 0xe5e7c174); break; case Analyser::Static::Commodore::Target::Region::Danish: - rom_names.emplace_back(machine_name, "characters-danish.bin"); - rom_names.emplace_back(machine_name, "kernel-danish.bin"); + rom_names.emplace_back(machine_name, "the Danish VIC-20 character ROM", "characters-danish.bin", 4*1024, 0x7fc11454); + rom_names.emplace_back(machine_name, "the Danish VIC-20 kernel ROM", "kernel-danish.bin", 8*1024, 0x02adaf16); break; case Analyser::Static::Commodore::Target::Region::Japanese: - rom_names.emplace_back(machine_name, "characters-japanese.bin"); - rom_names.emplace_back(machine_name, "kernel-japanese.bin"); + rom_names.emplace_back(machine_name, "the Japanese VIC-20 character ROM", "characters-japanese.bin", 4*1024, 0xfcfd8a4b); + rom_names.emplace_back(machine_name, "the Japanese VIC-20 kernel ROM", "kernel-japanese.bin", 8*1024, 0x336900d7); break; case Analyser::Static::Commodore::Target::Region::Swedish: - rom_names.emplace_back(machine_name, "characters-swedish.bin"); - rom_names.emplace_back(machine_name, "kernel-japanese.bin"); + rom_names.emplace_back(machine_name, "the Swedish VIC-20 character ROM", "characters-swedish.bin", 4*1024, 0xd808551d); + rom_names.emplace_back(machine_name, "the Swedish VIC-20 kernel ROM", "kernel-swedish.bin", 8*1024, 0xb2a60662); break; } diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index 05b37493e..0f5f89eda 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -133,8 +133,11 @@ class ConcreteMachine: // Load the BIOS if relevant. if(has_bios()) { // TODO: there's probably a million other versions of the Master System BIOS; try to build a - // CRC32 catalogue of those. - const auto roms = rom_fetcher({ {"MasterSystem", "the Master System BIOS", "bios.sms", 8*1024, 0x0072ed54} }); + // CRC32 catalogue of those. So far: + // + // 0072ed54 = US/European BIOS 1.3 + // 48d44a13 = Japanese BIOS 2.1 + const auto roms = rom_fetcher({ {"MasterSystem", "the Master System BIOS", "bios.sms", 8*1024, { 0x0072ed54, 0x48d44a13 } } }); if(!roms[0]) { // No BIOS found; attempt to boot as though it has already disabled itself. memory_control_ |= 0x08; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 37bf52b4f..bbeea6290 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -229,16 +229,26 @@ template class Co } const std::string machine_name = "Oric"; - std::vector rom_names = { {machine_name, "colour.rom"} }; + std::vector rom_names = { {machine_name, "the Oric colour ROM", "colour.rom", 128, 0xd50fca65} }; switch(target.rom) { - case Analyser::Static::Oric::Target::ROM::BASIC10: rom_names.emplace_back(machine_name, "basic10.rom"); break; - case Analyser::Static::Oric::Target::ROM::BASIC11: rom_names.emplace_back(machine_name, "basic11.rom"); break; - case Analyser::Static::Oric::Target::ROM::Pravetz: rom_names.emplace_back(machine_name, "pravetz.rom"); break; + case Analyser::Static::Oric::Target::ROM::BASIC10: + rom_names.emplace_back(machine_name, "Oric BASIC 1.0", "basic10.rom", 16*1024, 0xf18710b4); + break; + case Analyser::Static::Oric::Target::ROM::BASIC11: + rom_names.emplace_back(machine_name, "Oric BASIC 1.1", "basic11.rom", 16*1024, 0xc3a92bef); + break; + case Analyser::Static::Oric::Target::ROM::Pravetz: + rom_names.emplace_back(machine_name, "Pravetz BASIC", "pravetz.rom", 16*1024, 0x58079502); + break; } switch(disk_interface) { default: break; - case Analyser::Static::Oric::Target::DiskInterface::Microdisc: rom_names.emplace_back(machine_name, "microdisc.rom"); break; - case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.emplace_back(machine_name, "8dos.rom"); break; + case Analyser::Static::Oric::Target::DiskInterface::Microdisc: + rom_names.emplace_back(machine_name, "the ORIC Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9c); + break; + case Analyser::Static::Oric::Target::DiskInterface::Pravetz: + rom_names.emplace_back(machine_name, "the 8DOS boot ROM", "8dos.rom", 512, 0x49a74c06); + break; } const auto roms = rom_fetcher(rom_names); @@ -262,7 +272,8 @@ template class Co pravetz_rom_ = std::move(*roms[2]); pravetz_rom_.resize(512); - auto state_machine_rom = rom_fetcher({ {"DiskII", "state-machine-16.rom"} }); + // This ROM name is coupled with that in the DiskIICard. + const auto state_machine_rom = rom_fetcher({ {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0xce7144f6, 0xb72a2c70 } } }); if(!state_machine_rom[0]) { throw ROMMachine::Error::MissingROMs; } diff --git a/Machines/ROMMachine.hpp b/Machines/ROMMachine.hpp index 071eb68f4..b1b9cb818 100644 --- a/Machines/ROMMachine.hpp +++ b/Machines/ROMMachine.hpp @@ -36,10 +36,6 @@ struct ROM { /// to exclude ROMs where the user's intent is otherwise clear. std::vector crc32s; - /// This is a temporary constructor provided for transitional purposes. - ROM(std::string machine_name, std::string file_name) : - machine_name(machine_name), file_name(file_name) {} - ROM(std::string machine_name, std::string descriptive_name, std::string file_name, size_t size, uint32_t crc32) : machine_name(machine_name), descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s({crc32}) {} ROM(std::string machine_name, std::string descriptive_name, std::string file_name, size_t size, std::initializer_list crc32s) : From b4191b62256ddc9104d5e40cabe74ed02529ef30 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 23:07:23 -0400 Subject: [PATCH 19/22] Corrects DiskII boot ROM CRCs and improves corresponding declarations. --- Machines/Apple/AppleII/AppleII.cpp | 13 ++++++++----- Machines/Apple/AppleII/DiskIICard.cpp | 6 +++++- Machines/Oric/Oric.cpp | 11 +++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 8e04458d5..8a857c6ef 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -372,6 +372,14 @@ template class ConcreteMachine: } const auto roms = rom_fetcher(rom_descriptions); + // Try to install a Disk II card now, before checking the ROM list, + // to make sure that Disk II dependencies have been communicated. + if(target.disk_controller != Target::DiskController::None) { + // Apple recommended slot 6 for the (first) Disk II. + install_card(6, new Apple::II::DiskIICard(rom_fetcher, target.disk_controller == Target::DiskController::SixteenSector)); + } + + // Now, check and move the ROMs. if(!roms[0] || !roms[1]) { throw ROMMachine::Error::MissingROMs; } @@ -383,11 +391,6 @@ template class ConcreteMachine: video_.set_character_rom(*roms[0]); - if(target.disk_controller != Target::DiskController::None) { - // Apple recommended slot 6 for the (first) Disk II. - install_card(6, new Apple::II::DiskIICard(rom_fetcher, target.disk_controller == Target::DiskController::SixteenSector)); - } - // Set up the default memory blocks. On a II or II+ these values will never change. // On a IIe they'll be affected by selection of auxiliary RAM. set_main_paging(); diff --git a/Machines/Apple/AppleII/DiskIICard.cpp b/Machines/Apple/AppleII/DiskIICard.cpp index dae7b30cf..11349e1fc 100644 --- a/Machines/Apple/AppleII/DiskIICard.cpp +++ b/Machines/Apple/AppleII/DiskIICard.cpp @@ -15,7 +15,7 @@ DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sec if(is_16_sector) { roms = rom_fetcher({ {"DiskII", "the Disk II 16-sector boot ROM", "boot-16.rom", 256, 0xce7144f6}, - {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0xce7144f6, 0xb72a2c70 } } + {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 } } }); } else { roms = rom_fetcher({ @@ -23,6 +23,10 @@ DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sec {"DiskII", "the Disk II 13-sector state machine ROM", "state-machine-13.rom", 256, 0x62e22620 } }); } + if(!roms[0] || !roms[1]) { + throw ROMMachine::Error::MissingROMs; + } + boot_ = std::move(*roms[0]); diskii_.set_state_machine(*roms[1]); set_select_constraints(None); diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index bbeea6290..b90ce9fd8 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -241,6 +241,7 @@ template class Co rom_names.emplace_back(machine_name, "Pravetz BASIC", "pravetz.rom", 16*1024, 0x58079502); break; } + size_t diskii_state_machine_index = 0; switch(disk_interface) { default: break; case Analyser::Static::Oric::Target::DiskInterface::Microdisc: @@ -248,6 +249,9 @@ template class Co break; case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.emplace_back(machine_name, "the 8DOS boot ROM", "8dos.rom", 512, 0x49a74c06); + // These ROM details are coupled with those in the DiskIICard. + diskii_state_machine_index = rom_names.size(); + rom_names.push_back({"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 }}); break; } @@ -272,12 +276,7 @@ template class Co pravetz_rom_ = std::move(*roms[2]); pravetz_rom_.resize(512); - // This ROM name is coupled with that in the DiskIICard. - const auto state_machine_rom = rom_fetcher({ {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0xce7144f6, 0xb72a2c70 } } }); - if(!state_machine_rom[0]) { - throw ROMMachine::Error::MissingROMs; - } - diskii_.set_state_machine(*state_machine_rom[0]); + diskii_.set_state_machine(*roms[diskii_state_machine_index]); } break; } From fcee7779b0fbaffc9fcac528c53a1a8b17c2719d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Jul 2019 23:11:37 -0400 Subject: [PATCH 20/22] Inserts missing spaces. --- Machines/AmstradCPC/AmstradCPC.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index c1ad3173f..c570b341a 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -807,8 +807,8 @@ template class ConcreteMachine: crcs[1] = 0x32fee492; break; } - required_roms.emplace_back(machine_name, "the CPC " + model_number + "firmware", "os" + model_number + ".rom", 16*1024, crcs[0]); - required_roms.emplace_back(machine_name, "the CPC " + model_number + "BASIC ROM", "basic" + model_number + ".rom", 16*1024, crcs[1]); + required_roms.emplace_back(machine_name, "the CPC " + model_number + " firmware", "os" + model_number + ".rom", 16*1024, crcs[0]); + required_roms.emplace_back(machine_name, "the CPC " + model_number + " BASIC ROM", "basic" + model_number + ".rom", 16*1024, crcs[1]); // fetch and verify the ROMs const auto roms = rom_fetcher(required_roms); From 4d361b1952e13dc281531d0e01b00c899757dfab Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 23 Jul 2019 11:36:47 -0400 Subject: [PATCH 21/22] Adds MIME type for Apple-recognised disk images. --- OSBindings/Mac/Clock Signal/Info.plist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OSBindings/Mac/Clock Signal/Info.plist b/OSBindings/Mac/Clock Signal/Info.plist index f9f308fcd..07ade7517 100644 --- a/OSBindings/Mac/Clock Signal/Info.plist +++ b/OSBindings/Mac/Clock Signal/Info.plist @@ -509,6 +509,10 @@ CFBundleTypeIconFile floppy35 + CFBundleTypeMIMETypes + + application/x-apple-diskimage + CFBundleTypeName DiskCopy 4.2 Disk Image CFBundleTypeOSTypes From 374cac01072ea4fd86b36cdb6284e90a8a3d2d2e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 23 Jul 2019 16:24:23 -0400 Subject: [PATCH 22/22] Adds negative feedback to ROM installation process. As an ugly kludge, code wise. --- .../Documents/MachineDocument.swift | 64 +++++++++++++++++-- .../ROMRequester/ROMRequester.xib | 12 ++++ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 20e9bc301..b36369ffa 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -336,13 +336,15 @@ class MachineDocument: // MARK: User ROM provision. @IBOutlet var romRequesterPanel: NSWindow? @IBOutlet var romRequesterText: NSTextField? + @IBOutlet var romReceiverErrorField: NSTextField? @IBOutlet var romReceiverView: CSROMReceiverView? - var romRequestBaseText = "" + private var romRequestBaseText = "" func requestRoms() { // Load the ROM requester dialogue. Bundle.main.loadNibNamed("ROMRequester", owner: self, topLevelObjects: nil) self.romReceiverView!.delegate = self self.romRequestBaseText = romRequesterText!.stringValue + romReceiverErrorField?.alphaValue = 0.0 // Populate the current absentee list. populateMissingRomList() @@ -388,6 +390,7 @@ class MachineDocument: // If no ROMs are still missing, start the machine. do { let fileData = try Data(contentsOf: URL) + var didInstallRom = false // Try to match by size first, CRC second. Accept that some ROMs may have // some additional appended data. Arbitrarily allow them to be up to 10kb @@ -414,10 +417,11 @@ class MachineDocument: try fileManager.createDirectory(atPath: targetPath.path, withIntermediateDirectories: true, attributes: nil) try trimmedData.write(to: targetFile) } catch let error { - Swift.print("Some sort of error \(error)") + showRomReceiverError(error: "Couldn't write to application support directory: \(error)") } self.missingROMs.remove(at: index) + didInstallRom = true break } } @@ -425,14 +429,60 @@ class MachineDocument: index = index + 1 } - if self.missingROMs.count == 0 { - self.windowControllers[0].window?.endSheet(self.romRequesterPanel!) - configureAs(self.selectedMachine!) + if didInstallRom { + if self.missingROMs.count == 0 { + self.windowControllers[0].window?.endSheet(self.romRequesterPanel!) + configureAs(self.selectedMachine!) + } else { + populateMissingRomList() + } } else { - populateMissingRomList() + showRomReceiverError(error: "Didn't recognise contents of \(URL.lastPathComponent)") } } catch let error { - Swift.print("TODO: couldn't open \(URL.absoluteString); \(error)") + showRomReceiverError(error: "Couldn't read file at \(URL.absoluteString): \(error)") + } + } + + // Yucky ugliness follows; my experience as an iOS developer intersects poorly with + // NSAnimationContext hence the various stateful diplications below. isShowingError + // should be essentially a duplicate of the current alphaValue, and animationCount + // is to resolve my inability to figure out how to cancel scheduled animations. + private var errorText = "" + private var isShowingError = false + private var animationCount = 0 + private func showRomReceiverError(error: String) { + // Set or append the new error. + if self.errorText.count > 0 { + self.errorText = self.errorText + "\n" + error + } else { + self.errorText = error + } + + // Apply the new complete text. + romReceiverErrorField!.stringValue = self.errorText + + if !isShowingError { + // Schedule the box's appearance. + NSAnimationContext.beginGrouping() + NSAnimationContext.current.duration = 0.1 + romReceiverErrorField?.animator().alphaValue = 1.0 + NSAnimationContext.endGrouping() + isShowingError = true + } + + // Schedule the box to disappear. + self.animationCount = self.animationCount + 1 + let capturedAnimationCount = animationCount + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(2)) { + if self.animationCount == capturedAnimationCount { + NSAnimationContext.beginGrouping() + NSAnimationContext.current.duration = 1.0 + self.romReceiverErrorField?.animator().alphaValue = 0.0 + NSAnimationContext.endGrouping() + self.isShowingError = false + self.errorText = "" + } } } diff --git a/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib b/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib index ca28efdaf..ff11445ab 100644 --- a/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib +++ b/OSBindings/Mac/Clock Signal/ROMRequester/ROMRequester.xib @@ -8,6 +8,7 @@ + @@ -48,10 +49,21 @@ DQ + + + + + + + + + + +