From 78eaecb29e67f203b55e66c2a89675ab3aa1d56a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 9 Mar 2018 15:36:11 -0500 Subject: [PATCH] Provides the proper framework for encapsulation of analyser target specifics. ... while making them a safe container for objects too. Uses the ZX80/81 as the pilot platform. --- .../MultiConfigurationTarget.cpp | 2 +- .../MultiConfigurationTarget.hpp | 2 +- Analyser/Static/StaticAnalyser.hpp | 13 ++------ Analyser/Static/ZX8081/StaticAnalyser.cpp | 19 ++++++----- Analyser/Static/ZX8081/Target.hpp | 33 +++++++++++++++++++ Machines/AmstradCPC/AmstradCPC.cpp | 10 +++--- Machines/Atari2600/Atari2600.cpp | 12 +++---- Machines/ColecoVision/ColecoVision.cpp | 4 +-- Machines/Commodore/Vic-20/Vic20.cpp | 12 +++---- Machines/ConfigurationTarget.hpp | 2 +- Machines/Electron/Electron.cpp | 16 ++++----- Machines/MSX/MSX.cpp | 10 +++--- Machines/Oric/Oric.cpp | 12 +++---- Machines/Utility/MachineForTarget.cpp | 8 ++--- Machines/ZX8081/ZX8081.cpp | 28 +++++++++------- Machines/ZX8081/ZX8081.hpp | 2 +- .../Clock Signal.xcodeproj/project.pbxproj | 2 ++ 17 files changed, 110 insertions(+), 77 deletions(-) create mode 100644 Analyser/Static/ZX8081/Target.hpp diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiConfigurationTarget.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiConfigurationTarget.cpp index b4d8a7192..e8d3e09bf 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiConfigurationTarget.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiConfigurationTarget.cpp @@ -17,7 +17,7 @@ MultiConfigurationTarget::MultiConfigurationTarget(const std::vector> &machines); // Below is the standard ConfigurationTarget::Machine interface; see there for documentation. - void configure_as_target(const Analyser::Static::Target &target) override; + void configure_as_target(const Analyser::Static::Target *target) override; bool insert_media(const Analyser::Static::Media &media) override; private: diff --git a/Analyser/Static/StaticAnalyser.hpp b/Analyser/Static/StaticAnalyser.hpp index 3a679c0a8..cc9107881 100644 --- a/Analyser/Static/StaticAnalyser.hpp +++ b/Analyser/Static/StaticAnalyser.hpp @@ -42,12 +42,6 @@ enum class Atari2600PagingModel { Pitfall2 }; -enum class ZX8081MemoryModel { - Unexpanded, - SixteenKB, - SixtyFourKB -}; - enum class AmstradCPCModel { CPC464, CPC664, @@ -72,6 +66,8 @@ struct Media { and instructions on how to launch the software attached, plus a measure of confidence in this target's correctness. */ struct Target { + virtual ~Target() {} + Machine machine; Media media; @@ -102,11 +98,6 @@ struct Target { bool has_c1540; } vic20; - struct { - ZX8081MemoryModel memory_model; - bool isZX81; - } zx8081; - struct { AmstradCPCModel model; } amstradcpc; diff --git a/Analyser/Static/ZX8081/StaticAnalyser.cpp b/Analyser/Static/ZX8081/StaticAnalyser.cpp index 266b4c9df..4ee957325 100644 --- a/Analyser/Static/ZX8081/StaticAnalyser.cpp +++ b/Analyser/Static/ZX8081/StaticAnalyser.cpp @@ -11,6 +11,7 @@ #include #include +#include "Target.hpp" #include "../../../Storage/Tape/Parsers/ZX8081.hpp" static std::vector GetFiles(const std::shared_ptr &tape) { @@ -27,41 +28,41 @@ static std::vector GetFiles(const std::shared_ptr> &destination, TargetPlatform::IntType potential_platforms) { +void Analyser::Static::ZX8081::AddTargets(const Media &media, std::vector> &destination, TargetPlatform::IntType potential_platforms) { if(!media.tapes.empty()) { std::vector files = GetFiles(media.tapes.front()); media.tapes.front()->reset(); if(!files.empty()) { - std::unique_ptr target(new Target); + Target *target = new Target; + destination.push_back(std::unique_ptr<::Analyser::Static::Target>(target)); target->machine = Machine::ZX8081; // Guess the machine type from the file only if it isn't already known. switch(potential_platforms & (TargetPlatform::ZX80 | TargetPlatform::ZX81)) { default: - target->zx8081.isZX81 = files.front().isZX81; + target->isZX81 = files.front().isZX81; break; - case TargetPlatform::ZX80: target->zx8081.isZX81 = false; break; - case TargetPlatform::ZX81: target->zx8081.isZX81 = true; break; + case TargetPlatform::ZX80: target->isZX81 = false; break; + case TargetPlatform::ZX81: target->isZX81 = true; break; } /*if(files.front().data.size() > 16384) { target->zx8081.memory_model = ZX8081MemoryModel::SixtyFourKB; } else*/ if(files.front().data.size() > 1024) { - target->zx8081.memory_model = ZX8081MemoryModel::SixteenKB; + target->memory_model = Target::MemoryModel::SixteenKB; } else { - target->zx8081.memory_model = ZX8081MemoryModel::Unexpanded; + target->memory_model = Target::MemoryModel::Unexpanded; } target->media.tapes = media.tapes; // TODO: how to run software once loaded? Might require a BASIC detokeniser. - if(target->zx8081.isZX81) { + if(target->isZX81) { target->loading_command = "J\"\"\n"; } else { target->loading_command = "W\n"; } - destination.push_back(std::move(target)); } } } diff --git a/Analyser/Static/ZX8081/Target.hpp b/Analyser/Static/ZX8081/Target.hpp new file mode 100644 index 000000000..180282576 --- /dev/null +++ b/Analyser/Static/ZX8081/Target.hpp @@ -0,0 +1,33 @@ +// +// Target.hpp +// Clock Signal +// +// Created by Thomas Harte on 09/03/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef Target_h +#define Target_h + +#include "../StaticAnalyser.hpp" + +namespace Analyser { +namespace Static { +namespace ZX8081 { + +struct Target: public ::Analyser::Static::Target { + enum class MemoryModel { + Unexpanded, + SixteenKB, + SixtyFourKB + }; + + MemoryModel memory_model; + bool isZX81; +}; + +} +} +} + +#endif /* Target_h */ diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index d93aeef79..b81b852ba 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -874,8 +874,8 @@ class ConcreteMachine: } /// The ConfigurationTarget entry point; should configure this meachine as described by @c target. - void configure_as_target(const Analyser::Static::Target &target) override final { - switch(target.amstradcpc.model) { + void configure_as_target(const Analyser::Static::Target *target) override final { + switch(target->amstradcpc.model) { case Analyser::Static::AmstradCPCModel::CPC464: rom_model_ = ROMType::OS464; has_128k_ = false; @@ -908,11 +908,11 @@ class ConcreteMachine: read_pointers_[3] = roms_[upper_rom_].data(); // Type whatever is required. - if(target.loading_command.length()) { - type_string(target.loading_command); + if(target->loading_command.length()) { + type_string(target->loading_command); } - insert_media(target.media); + insert_media(target->media); } bool insert_media(const Analyser::Static::Media &media) override final { diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index ed969863c..181a57bdd 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -89,9 +89,9 @@ class ConcreteMachine: close_output(); } - void configure_as_target(const Analyser::Static::Target &target) override { - const std::vector &rom = target.media.cartridges.front()->get_segments().front().data; - switch(target.atari.paging_model) { + void configure_as_target(const Analyser::Static::Target *target) override { + const std::vector &rom = target->media.cartridges.front()->get_segments().front().data; + switch(target->atari.paging_model) { case Analyser::Static::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::Cartridge(rom)); break; case Analyser::Static::Atari2600PagingModel::CBSRamPlus: bus_.reset(new Cartridge::Cartridge(rom)); break; case Analyser::Static::Atari2600PagingModel::CommaVid: bus_.reset(new Cartridge::Cartridge(rom)); break; @@ -103,21 +103,21 @@ class ConcreteMachine: case Analyser::Static::Atari2600PagingModel::Tigervision: bus_.reset(new Cartridge::Cartridge(rom)); break; case Analyser::Static::Atari2600PagingModel::Atari8k: - if(target.atari.uses_superchip) { + if(target->atari.uses_superchip) { bus_.reset(new Cartridge::Cartridge(rom)); } else { bus_.reset(new Cartridge::Cartridge(rom)); } break; case Analyser::Static::Atari2600PagingModel::Atari16k: - if(target.atari.uses_superchip) { + if(target->atari.uses_superchip) { bus_.reset(new Cartridge::Cartridge(rom)); } else { bus_.reset(new Cartridge::Cartridge(rom)); } break; case Analyser::Static::Atari2600PagingModel::Atari32k: - if(target.atari.uses_superchip) { + if(target->atari.uses_superchip) { bus_.reset(new Cartridge::Cartridge(rom)); } else { bus_.reset(new Cartridge::Cartridge(rom)); diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index da62dda4f..f238637a3 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -150,9 +150,9 @@ class ConcreteMachine: z80_.run_for(cycles); } - void configure_as_target(const Analyser::Static::Target &target) override { + void configure_as_target(const Analyser::Static::Target *target) override { // Insert the media. - insert_media(target.media); + insert_media(target->media); } bool insert_media(const Analyser::Static::Media &media) override { diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 1aeb6d1df..11e99f5e7 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -363,12 +363,12 @@ class ConcreteMachine: return true; } - void configure_as_target(const Analyser::Static::Target &target) override final { - if(target.loading_command.length()) { - type_string(target.loading_command); + void configure_as_target(const Analyser::Static::Target *target) override final { + if(target->loading_command.length()) { + type_string(target->loading_command); } - switch(target.vic20.memory_model) { + switch(target->vic20.memory_model) { case Analyser::Static::Vic20MemoryModel::Unexpanded: set_memory_size(Default); break; @@ -380,7 +380,7 @@ class ConcreteMachine: break; } - if(target.media.disks.size()) { + if(target->media.disks.size()) { // construct the 1540 c1540_.reset(new ::Commodore::C1540::Machine(Commodore::C1540::Machine::C1540)); @@ -391,7 +391,7 @@ class ConcreteMachine: c1540_->set_rom_fetcher(rom_fetcher_); } - insert_media(target.media); + insert_media(target->media); } bool insert_media(const Analyser::Static::Media &media) override final { diff --git a/Machines/ConfigurationTarget.hpp b/Machines/ConfigurationTarget.hpp index 600f76730..05cbaa3f2 100644 --- a/Machines/ConfigurationTarget.hpp +++ b/Machines/ConfigurationTarget.hpp @@ -23,7 +23,7 @@ namespace ConfigurationTarget { class Machine { public: /// Instructs the machine to configure itself as described by @c target and insert the included media. - virtual void configure_as_target(const Analyser::Static::Target &target) = 0; + virtual void configure_as_target(const Analyser::Static::Target *target) = 0; /*! Requests that the machine insert @c media as a modification to current state diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 3e98f5131..aeb7e927b 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -123,28 +123,28 @@ class ConcreteMachine: if(is_holding_shift_) set_key_state(KeyShift, true); } - void configure_as_target(const Analyser::Static::Target &target) override final { - if(target.loading_command.length()) { - type_string(target.loading_command); + void configure_as_target(const Analyser::Static::Target *target) override final { + if(target->loading_command.length()) { + type_string(target->loading_command); } - if(target.acorn.should_shift_restart) { + if(target->acorn.should_shift_restart) { shift_restart_counter_ = 1000000; } - if(target.acorn.has_dfs || target.acorn.has_adfs) { + if(target->acorn.has_dfs || target->acorn.has_adfs) { plus3_.reset(new Plus3); - if(target.acorn.has_dfs) { + if(target->acorn.has_dfs) { set_rom(ROMSlot0, dfs_, true); } - if(target.acorn.has_adfs) { + if(target->acorn.has_adfs) { set_rom(ROMSlot4, adfs1_, true); set_rom(ROMSlot5, adfs2_, true); } } - insert_media(target.media); + insert_media(target->media); } bool insert_media(const Analyser::Static::Media &media) override final { diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index a927c4cb5..cec831d93 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -178,20 +178,20 @@ class ConcreteMachine: } } - void configure_as_target(const Analyser::Static::Target &target) override { + void configure_as_target(const Analyser::Static::Target *target) override { // Add a disk cartridge if any disks were supplied. - if(!target.media.disks.empty()) { + if(!target->media.disks.empty()) { map(2, 0, 0x4000, 0x2000); unmap(2, 0x6000, 0x2000); memory_slots_[2].set_handler(new DiskROM(memory_slots_[2].source)); } // Insert the media. - insert_media(target.media); + insert_media(target->media); // Type whatever has been requested. - if(target.loading_command.length()) { - type_string(target.loading_command); + if(target->loading_command.length()) { + type_string(target->loading_command); } } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index abe91ff74..172fe6f28 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -262,18 +262,18 @@ class ConcreteMachine: } // to satisfy ConfigurationTarget::Machine - void configure_as_target(const Analyser::Static::Target &target) override final { - if(target.oric.has_microdisc) { + void configure_as_target(const Analyser::Static::Target *target) override final { + if(target->oric.has_microdisc) { microdisc_is_enabled_ = true; microdisc_did_change_paging_flags(µdisc_); microdisc_.set_delegate(this); } - if(target.loading_command.length()) { - type_string(target.loading_command); + if(target->loading_command.length()) { + type_string(target->loading_command); } - if(target.oric.use_atmos_rom) { + if(target->oric.use_atmos_rom) { std::memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_))); is_using_basic11_ = true; @@ -289,7 +289,7 @@ class ConcreteMachine: tape_speed_address_ = 0x67; } - insert_media(target.media); + insert_media(target->media); } bool insert_media(const Analyser::Static::Media &media) override final { diff --git a/Machines/Utility/MachineForTarget.cpp b/Machines/Utility/MachineForTarget.cpp index 7ec719686..294b8663e 100644 --- a/Machines/Utility/MachineForTarget.cpp +++ b/Machines/Utility/MachineForTarget.cpp @@ -22,10 +22,10 @@ namespace { -::Machine::DynamicMachine *MachineForTarget(const Analyser::Static::Target &target, const ROMMachine::ROMFetcher &rom_fetcher, Machine::Error &error) { +::Machine::DynamicMachine *MachineForTarget(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher, Machine::Error &error) { error = Machine::Error::None; ::Machine::DynamicMachine *machine = nullptr; - switch(target.machine) { + switch(target->machine) { case Analyser::Machine::AmstradCPC: machine = new Machine::TypedDynamicMachine(AmstradCPC::Machine::AmstradCPC()); break; case Analyser::Machine::Atari2600: machine = new Machine::TypedDynamicMachine(Atari2600::Machine::Atari2600()); break; case Analyser::Machine::ColecoVision: machine = new Machine::TypedDynamicMachine(Coleco::Vision::Machine::ColecoVision()); break; @@ -71,7 +71,7 @@ namespace { if(targets.size() > 1) { std::vector> machines; for(const auto &target: targets) { - machines.emplace_back(MachineForTarget(*target, rom_fetcher, error)); + machines.emplace_back(MachineForTarget(target.get(), rom_fetcher, error)); // Exit early if any errors have occurred. if(error != Error::None) { @@ -89,7 +89,7 @@ namespace { } // There's definitely exactly one target. - return MachineForTarget(*targets.front(), rom_fetcher, error); + return MachineForTarget(targets.front().get(), rom_fetcher, error); } std::string Machine::ShortNameForTargetMachine(const Analyser::Machine machine) { diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index c10d3b27c..7d80d2fc1 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -25,6 +25,8 @@ #include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp" +#include "../../Analyser/Static/ZX8081/Target.hpp" + #include "Keyboard.hpp" #include "Video.hpp" @@ -277,8 +279,10 @@ template class ConcreteMachine: z80_.run_for(cycles); } - void configure_as_target(const Analyser::Static::Target &target) override final { - is_zx81_ = target.zx8081.isZX81; + void configure_as_target(const Analyser::Static::Target *target) override final { + const Analyser::Static::ZX8081::Target *const zx8081_target = + dynamic_cast(target); + is_zx81_ = zx8081_target->isZX81; if(is_zx81_) { rom_ = zx81_rom_; tape_trap_address_ = 0x37c; @@ -298,18 +302,18 @@ template class ConcreteMachine: } rom_mask_ = static_cast(rom_.size() - 1); - switch(target.zx8081.memory_model) { - case Analyser::Static::ZX8081MemoryModel::Unexpanded: + switch(zx8081_target->memory_model) { + case Analyser::Static::ZX8081::Target::MemoryModel::Unexpanded: ram_.resize(1024); ram_base_ = 16384; ram_mask_ = 1023; break; - case Analyser::Static::ZX8081MemoryModel::SixteenKB: + case Analyser::Static::ZX8081::Target::MemoryModel::SixteenKB: ram_.resize(16384); ram_base_ = 16384; ram_mask_ = 16383; break; - case Analyser::Static::ZX8081MemoryModel::SixtyFourKB: + case Analyser::Static::ZX8081::Target::MemoryModel::SixtyFourKB: ram_.resize(65536); ram_base_ = 8192; ram_mask_ = 65535; @@ -317,11 +321,11 @@ template class ConcreteMachine: } Memory::Fuzz(ram_); - if(target.loading_command.length()) { - type_string(target.loading_command); + if(target->loading_command.length()) { + type_string(target->loading_command); } - insert_media(target.media); + insert_media(target->media); } bool insert_media(const Analyser::Static::Media &media) override final { @@ -517,9 +521,11 @@ template class ConcreteMachine: using namespace ZX8081; // See header; constructs and returns an instance of the ZX80 or 81. -Machine *Machine::ZX8081(const Analyser::Static::Target &target_hint) { +Machine *Machine::ZX8081(const Analyser::Static::Target *target_hint) { + const Analyser::Static::ZX8081::Target *const hint = dynamic_cast(target_hint); + // Instantiate the correct type of machine. - if(target_hint.zx8081.isZX81) + if(hint->isZX81) return new ZX8081::ConcreteMachine(); else return new ZX8081::ConcreteMachine(); diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index b04a317a8..cbe1615eb 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -21,7 +21,7 @@ class Machine { public: virtual ~Machine(); - static Machine *ZX8081(const Analyser::Static::Target &target_hint); + static Machine *ZX8081(const Analyser::Static::Target *target_hint); virtual void set_tape_is_playing(bool is_playing) = 0; virtual bool get_tape_is_playing() = 0; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 0bc7b7618..f912171d9 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1330,6 +1330,7 @@ 4BD9137D1F311BC5009BCF85 /* i8255.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = i8255.hpp; path = 8255/i8255.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 = ""; }; + 4BE3231220532443006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; 4BE7C9161E3D397100A5496D /* TIA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cpp; sourceTree = ""; }; 4BE7C9171E3D397100A5496D /* TIA.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIA.hpp; sourceTree = ""; }; 4BE845201F2FF7F100A5EA22 /* CRTC6845.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRTC6845.hpp; path = 6845/CRTC6845.hpp; sourceTree = ""; }; @@ -2208,6 +2209,7 @@ children = ( 4B894506201967B4007DE474 /* StaticAnalyser.cpp */, 4B894505201967B4007DE474 /* StaticAnalyser.hpp */, + 4BE3231220532443006EF799 /* Target.hpp */, ); path = ZX8081; sourceTree = "";