diff --git a/Analyser/Static/Enterprise/Target.hpp b/Analyser/Static/Enterprise/Target.hpp index f77f01f50..d758e4d6d 100644 --- a/Analyser/Static/Enterprise/Target.hpp +++ b/Analyser/Static/Enterprise/Target.hpp @@ -18,9 +18,21 @@ namespace Static { namespace Enterprise { struct Target: public Analyser::Static::Target, public Reflection::StructImpl { - Target() : Analyser::Static::Target(Machine::Enterprise) {} + ReflectableEnum(EXOSVersion, v10, v20, v21, v23, Any); + ReflectableEnum(BASICVersion, v10, v11, v21, Any, None); - // TODO: I assume there'll be relevant fields to add here. + EXOSVersion exos_version = EXOSVersion::Any; + BASICVersion basic_version = BASICVersion::None; + + Target() : Analyser::Static::Target(Machine::Enterprise) { + if(needs_declare()) { + AnnounceEnum(EXOSVersion); + AnnounceEnum(BASICVersion); + + DeclareField(exos_version); + DeclareField(basic_version); + } + } }; } diff --git a/Machines/Enterprise/Enterprise.cpp b/Machines/Enterprise/Enterprise.cpp index 1f9c156aa..269a08412 100644 --- a/Machines/Enterprise/Enterprise.cpp +++ b/Machines/Enterprise/Enterprise.cpp @@ -70,17 +70,92 @@ class ConcreteMachine: // Request a clock of 4Mhz; this'll be mapped upwards for Nick and Dave elsewhere. set_clock_rate(4'000'000); - constexpr ROM::Name exos_name = ROM::Name::EnterpriseEXOS; - const auto request = ROM::Request(exos_name); + ROM::Request request; + using Target = Analyser::Static::Enterprise::Target; + + // Pick one or more EXOS ROMs. + switch(target.exos_version) { + case Target::EXOSVersion::v10: request = request && ROM::Request(ROM::Name::EnterpriseEXOS10); break; + case Target::EXOSVersion::v20: request = request && ROM::Request(ROM::Name::EnterpriseEXOS20); break; + case Target::EXOSVersion::v21: request = request && ROM::Request(ROM::Name::EnterpriseEXOS21); break; + case Target::EXOSVersion::v23: request = request && ROM::Request(ROM::Name::EnterpriseEXOS23); break; + case Target::EXOSVersion::Any: + request = + request && ( + ROM::Request(ROM::Name::EnterpriseEXOS10) || ROM::Request(ROM::Name::EnterpriseEXOS20) || + ROM::Request(ROM::Name::EnterpriseEXOS21) || ROM::Request(ROM::Name::EnterpriseEXOS23) + ); + break; + + default: break; + } + + // Similarly pick one or more BASIC ROMs. + switch(target.basic_version) { + case Target::BASICVersion::v10: + request = request && ( + ROM::Request(ROM::Name::EnterpriseBASIC10) || + (ROM::Request(ROM::Name::EnterpriseBASIC10Part1) && ROM::Request(ROM::Name::EnterpriseBASIC10Part2)) + ); + break; + case Target::BASICVersion::v11: + request = request && ( + ROM::Request(ROM::Name::EnterpriseBASIC11) || + ROM::Request(ROM::Name::EnterpriseBASIC11Suffixed) + ); + case Target::BASICVersion::v21: + request = request && ROM::Request(ROM::Name::EnterpriseBASIC21); + break; + case Target::BASICVersion::Any: + request = + request && ( + ROM::Request(ROM::Name::EnterpriseBASIC10) || + (ROM::Request(ROM::Name::EnterpriseBASIC10Part1) && ROM::Request(ROM::Name::EnterpriseBASIC10Part2)) || + ROM::Request(ROM::Name::EnterpriseBASIC11) || + ROM::Request(ROM::Name::EnterpriseBASIC21) + ); + break; + + default: break; + } + + // Get and validate ROMs. auto roms = rom_fetcher(request); if(!request.validate(roms)) { throw ROMMachine::Error::MissingROMs; } - const auto &exos = roms.find(exos_name)->second; + // Extract the appropriate EXOS ROM. exos_.fill(0xff); - memcpy(exos_.data(), exos.data(), std::min(exos_.size(), exos.size())); + for(const auto rom_name: { ROM::Name::EnterpriseEXOS10, ROM::Name::EnterpriseEXOS20, ROM::Name::EnterpriseEXOS21, ROM::Name::EnterpriseEXOS23 }) { + const auto exos = roms.find(rom_name); + if(exos != roms.end()) { + memcpy(exos_.data(), exos->second.data(), std::min(exos_.size(), exos->second.size())); + break; + } + } + // Extract the appropriate BASIC ROM[s] (if any). + basic_.fill(0xff); + bool has_basic = false; + for(const auto rom_name: { ROM::Name::EnterpriseBASIC10, ROM::Name::EnterpriseBASIC11, ROM::Name::EnterpriseBASIC11Suffixed, ROM::Name::EnterpriseBASIC21 }) { + const auto basic = roms.find(rom_name); + if(basic != roms.end()) { + memcpy(basic_.data(), basic->second.data(), std::min(basic_.size(), basic->second.size())); + has_basic = true; + break; + } + } + if(!has_basic) { + const auto basic1 = roms.find(ROM::Name::EnterpriseBASIC10Part1); + const auto basic2 = roms.find(ROM::Name::EnterpriseBASIC10Part2); + if(basic1 != roms.end() && basic2 != roms.end()) { + memcpy(&basic_[0x0000], basic1->second.data(), std::min(size_t(8192), basic1->second.size())); + memcpy(&basic_[0x2000], basic2->second.data(), std::min(size_t(8192), basic2->second.size())); + } + } + + // Seed key state. clear_all_keys(); // Take a reasonable guess at the initial memory configuration: @@ -212,6 +287,7 @@ class ConcreteMachine: // MARK: - Memory layout std::array ram_; std::array exos_; + std::array basic_; const uint8_t min_ram_slot_ = uint8_t(0x100 - (ram_.size() / 0x4000)); const uint8_t *read_pointers_[4] = {nullptr, nullptr, nullptr, nullptr}; @@ -226,6 +302,11 @@ class ConcreteMachine: return; } + if(offset >= 16 && offset < 16 + basic_.size() / 0x4000) { + page(&basic_[(offset - 16) * 0x4000], nullptr); + return; + } + // Of whatever size of RAM I've declared above, use only the final portion. // This correlated with Nick always having been handed the final 64kb and, // at least while the RAM is the first thing declared above, does a little @@ -280,9 +361,6 @@ class ConcreteMachine: } // MARK: - Interrupts - - // TODO: include an error. - enum class Interrupt: uint8_t { Nick = 0x20 }; diff --git a/Machines/Utility/ROMCatalogue.cpp b/Machines/Utility/ROMCatalogue.cpp index 23bf6f1a8..d245e98bb 100644 --- a/Machines/Utility/ROMCatalogue.cpp +++ b/Machines/Utility/ROMCatalogue.cpp @@ -411,9 +411,51 @@ Description::Description(Name name) { *this = Description(name, "DiskII", "the Disk II 13-sector state machine ROM", "state-machine-13.rom", 256, 0x62e22620u); break; - case Name::EnterpriseEXOS: { - const std::initializer_list filenames = {"exos.bin", "Exos (198x)(Enterprise).bin"}; - *this = Description(name, "Enterprise", "the Enterprise EXOS ROM", filenames, 32 * 1024, 0x30b26387u); + case Name::EnterpriseEXOS10: { + const std::initializer_list filenames = {"exos10.bin", "Exos (198x)(Enterprise).bin"}; + *this = Description(name, "Enterprise", "the Enterprise EXOS ROM v1.0", filenames, 32 * 1024, 0x30b26387u); + } break; + case Name::EnterpriseEXOS20: { + const std::initializer_list filenames = {"exos20.bin", "Expandible OS v2.0 (1984)(Intelligent Software).bin"}; + *this = Description(name, "Enterprise", "the Enterprise EXOS ROM v2.0", filenames, 32 * 1024, 0xd421795fu); + } break; + case Name::EnterpriseEXOS21: { + const std::initializer_list filenames = {"exos21.bin", "Expandible OS v2.1 (1985)(Intelligent Software).bin"}; + *this = Description(name, "Enterprise", "the Enterprise EXOS ROM v2.1", filenames, 32 * 1024, 0x982a3b44u); + } break; + case Name::EnterpriseEXOS23: { + const std::initializer_list filenames = {"exos23.bin", "Expandible OS v2.3 (1987)(Intelligent Software).bin"}; + *this = Description(name, "Enterprise", "the Enterprise EXOS ROM v2.1", filenames, 64 * 1024, 0x24838410u); + } break; + + case Name::EnterpriseBASIC10: { + const std::initializer_list filenames = {"basic10.bin"}; + *this = Description(name, "Enterprise", "the Enterprise BASIC ROM v1.0", filenames, 16 * 1024, 0xd62e4fb7u); + } break; + case Name::EnterpriseBASIC10Part1: { + const std::initializer_list filenames = {"BASIC 1.0 - EPROM 1-2 (198x)(Enterprise).bin"}; + *this = Description(name, "Enterprise", "the Enterprise BASIC ROM v1.0, Part 1", filenames, 8193, 0x37bf48e1u); + } break; + case Name::EnterpriseBASIC10Part2: { + const std::initializer_list filenames = {"BASIC 1.0 - EPROM 2-2 (198x)(Enterprise).bin"}; + *this = Description(name, "Enterprise", "the Enterprise BASIC ROM v1.0, Part 2", filenames, 8193, 0xc5298c79u); + } break; + case Name::EnterpriseBASIC11: { + const std::initializer_list filenames = {"basic11.bin"}; + *this = Description(name, "Enterprise", "the Enterprise BASIC ROM v1.1", filenames, 16 * 1024, 0x683cf455u); + } break; + case Name::EnterpriseBASIC11Suffixed: { + const std::initializer_list filenames = {"BASIC 1.1 - EPROM 1.1 (198x)(Enterprise).bin"}; + *this = Description(name, "Enterprise", "the Enterprise BASIC ROM v1.1, with trailing byte", filenames, 16385, 0xc96b7602u); + } break; + case Name::EnterpriseBASIC21: { + const std::initializer_list filenames = { + "basic21.bin", + "BASIC Interpreter v2.1 (1985)(Intelligent Software).bin", + "BASIC Interpreter v2.1 (1985)(Intelligent Software)[a].bin" + }; + const std::initializer_list crcs = { 0x55f96251, 0x683cf455 }; + *this = Description(name, "Enterprise", "the Enterprise BASIC ROM v2.1", filenames, 16 * 1024, crcs); } break; case Name::Macintosh128k: *this = Description(name, "Macintosh", "the Macintosh 128k ROM", "mac128k.rom", 64*1024, 0x6d0c8a28u); break; diff --git a/Machines/Utility/ROMCatalogue.hpp b/Machines/Utility/ROMCatalogue.hpp index 5fabd093a..56b4e2c07 100644 --- a/Machines/Utility/ROMCatalogue.hpp +++ b/Machines/Utility/ROMCatalogue.hpp @@ -72,7 +72,17 @@ enum Name { DiskIIBoot13Sector, // Enterprise. - EnterpriseEXOS, + EnterpriseEXOS10, + EnterpriseEXOS20, + EnterpriseEXOS21, + EnterpriseEXOS23, + + EnterpriseBASIC10, + EnterpriseBASIC10Part1, + EnterpriseBASIC10Part2, + EnterpriseBASIC11, + EnterpriseBASIC11Suffixed, + EnterpriseBASIC21, // Macintosh. Macintosh128k,