1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-09 05:25:01 +00:00

Edges further towards providing enough information for dynamic user-provided machine creation.

This commit is contained in:
Thomas Harte
2020-03-15 12:54:55 -04:00
parent 880bed04f5
commit fc3d3c76f8
3 changed files with 60 additions and 40 deletions

View File

@@ -26,19 +26,19 @@
#include "../../Analyser/Static/Acorn/Target.hpp" #include "../../Analyser/Static/Acorn/Target.hpp"
#include "../../Analyser/Static/AmstradCPC/Target.hpp" #include "../../Analyser/Static/AmstradCPC/Target.hpp"
#include "../../Analyser/Static/AppleII/Target.hpp" #include "../../Analyser/Static/AppleII/Target.hpp"
#include "../../Analyser/Static/Atari2600/Target.hpp"
#include "../../Analyser/Static/AtariST/Target.hpp" #include "../../Analyser/Static/AtariST/Target.hpp"
#include "../../Analyser/Static/Commodore/Target.hpp" #include "../../Analyser/Static/Commodore/Target.hpp"
#include "../../Analyser/Static/Macintosh/Target.hpp" #include "../../Analyser/Static/Macintosh/Target.hpp"
#include "../../Analyser/Static/MSX/Target.hpp" #include "../../Analyser/Static/MSX/Target.hpp"
#include "../../Analyser/Static/Oric/Target.hpp" #include "../../Analyser/Static/Oric/Target.hpp"
#include "../../Analyser/Static/Sega/Target.hpp"
#include "../../Analyser/Static/ZX8081/Target.hpp" #include "../../Analyser/Static/ZX8081/Target.hpp"
#include "../../Analyser/Dynamic/MultiMachine/MultiMachine.hpp" #include "../../Analyser/Dynamic/MultiMachine/MultiMachine.hpp"
#include "TypedDynamicMachine.hpp" #include "TypedDynamicMachine.hpp"
namespace { Machine::DynamicMachine *Machine::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; error = Machine::Error::None;
Machine::DynamicMachine *machine = nullptr; Machine::DynamicMachine *machine = nullptr;
@@ -78,9 +78,7 @@ namespace {
return machine; return machine;
} }
} Machine::DynamicMachine *Machine::MachineForTargets(const Analyser::Static::TargetList &targets, const ROMMachine::ROMFetcher &rom_fetcher, Error &error) {
::Machine::DynamicMachine *::Machine::MachineForTargets(const Analyser::Static::TargetList &targets, const ROMMachine::ROMFetcher &rom_fetcher, Error &error) {
// Zero targets implies no machine. // Zero targets implies no machine.
if(targets.empty()) { if(targets.empty()) {
error = Error::NoTargets; error = Error::NoTargets;
@@ -193,8 +191,8 @@ std::map<std::string, std::vector<std::unique_ptr<Configurable::Option>>> Machin
return options; return options;
} }
std::map<std::string, std::unique_ptr<Reflection::Struct>> Machine::ConstructionOptionsByMachineName() { std::map<std::string, std::unique_ptr<Analyser::Static::Target>> Machine::TargetsByMachineName(bool meaningful_without_media_only) {
std::map<std::string, std::unique_ptr<Reflection::Struct>> options; std::map<std::string, std::unique_ptr<Analyser::Static::Target>> options;
#define AddMapped(Name, TargetNamespace) \ #define AddMapped(Name, TargetNamespace) \
options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::Name), new Analyser::Static::TargetNamespace::Target)); options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::Name), new Analyser::Static::TargetNamespace::Target));
@@ -210,6 +208,12 @@ std::map<std::string, std::unique_ptr<Reflection::Struct>> Machine::Construction
AddMapped(Vic20, Commodore); AddMapped(Vic20, Commodore);
Add(ZX8081); Add(ZX8081);
if(!meaningful_without_media_only) {
Add(Atari2600);
options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::ColecoVision), new Analyser::Static::Target(Analyser::Machine::ColecoVision)));
AddMapped(MasterSystem, Sega);
}
#undef Add #undef Add
#undef AddTwo #undef AddTwo

View File

@@ -19,6 +19,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
/*!
*/
namespace Machine { namespace Machine {
enum class Error { enum class Error {
@@ -36,6 +38,12 @@ enum class Error {
*/ */
DynamicMachine *MachineForTargets(const Analyser::Static::TargetList &targets, const ::ROMMachine::ROMFetcher &rom_fetcher, Error &error); DynamicMachine *MachineForTargets(const Analyser::Static::TargetList &targets, const ::ROMMachine::ROMFetcher &rom_fetcher, Error &error);
/*!
Allocates an instance of DynamicMaachine holding the machine described
by @c target. It is the caller's responsibility to delete the class when finished.
*/
DynamicMachine *MachineForTarget(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher, Machine::Error &error);
/*! /*!
Returns a short string name for the machine identified by the target, Returns a short string name for the machine identified by the target,
which is guaranteed not to have any spaces or other potentially which is guaranteed not to have any spaces or other potentially
@@ -55,12 +63,17 @@ std::string LongNameForTargetMachine(const Analyser::Machine target);
std::vector<std::string> AllMachines(bool meaningful_without_media_only, bool long_names); std::vector<std::string> AllMachines(bool meaningful_without_media_only, bool long_names);
/*! /*!
Returns a map from machine name to the list of options that machine Returns a map from long machine name to the list of options that machine
exposes, for all machines. exposes, for all machines.
*/ */
std::map<std::string, std::vector<std::unique_ptr<Configurable::Option>>> AllOptionsByMachineName(); std::map<std::string, std::vector<std::unique_ptr<Configurable::Option>>> AllOptionsByMachineName();
std::map<std::string, std::unique_ptr<Reflection::Struct>> ConstructionOptionsByMachineName(); /*!
Returns a map from long machine name to appropriate instances of Target for the machine.
NB: Usually the instances of Target can be dynamic_casted to Reflection::Struct in order to determine available properties.
*/
std::map<std::string, std::unique_ptr<Analyser::Static::Target>> TargetsByMachineName(bool meaningful_without_media_only);
} }

View File

@@ -13,10 +13,11 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <map>
#include <memory> #include <memory>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <map> #include <variant>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
@@ -363,7 +364,7 @@ bool KeyboardKeyForSDLScancode(SDL_Scancode scancode, Inputs::Keyboard::Key &key
struct ParsedArguments { struct ParsedArguments {
std::string file_name; std::string file_name;
Configurable::SelectionSet selections; std::map<std::string, std::variant<std::string, bool>> selections;
}; };
/*! Parses an argc/argv pair to discern program arguments. */ /*! Parses an argc/argv pair to discern program arguments. */
@@ -388,11 +389,11 @@ ParsedArguments parse_arguments(int argc, char *argv[]) {
std::size_t split_index = argument.find("="); std::size_t split_index = argument.find("=");
if(split_index == std::string::npos) { if(split_index == std::string::npos) {
arguments.selections[argument] = std::make_unique<Configurable::BooleanSelection>(true); arguments.selections[argument] = true;
} else { } else {
std::string name = argument.substr(0, split_index); std::string name = argument.substr(0, split_index);
std::string value = argument.substr(split_index+1, std::string::npos); std::string value = argument.substr(split_index+1, std::string::npos);
arguments.selections[name] = std::make_unique<Configurable::ListSelection>(value); arguments.selections[name] = value;
} }
} else { } else {
arguments.file_name = arg; arguments.file_name = arg;
@@ -506,12 +507,14 @@ int main(int argc, char *argv[]) {
std::cout << std::endl; std::cout << std::endl;
} }
const auto construction_options = Machine::ConstructionOptionsByMachineName(); const auto targets = Machine::TargetsByMachineName(false);
for(const auto &options: construction_options) { for(const auto &target: targets) {
std::cout << options.first << ":" << std::endl; const auto reflectable = dynamic_cast<Reflection::Struct *>(target.second.get());
for(const auto &option: options.second->all_keys()) {
std::cout << target.first << ":" << std::endl;
for(const auto &option: reflectable->all_keys()) {
std::cout << '\t' << "--" << option; std::cout << '\t' << "--" << option;
const auto type = options.second->type_of(option); const auto type = reflectable->type_of(option);
// Is this a registered enum? If so, list options. // Is this a registered enum? If so, list options.
if(!Reflection::Enum::name(*type).empty()) { if(!Reflection::Enum::name(*type).empty()) {
@@ -565,14 +568,14 @@ int main(int argc, char *argv[]) {
"/usr/local/share/CLK/", "/usr/local/share/CLK/",
"/usr/share/CLK/" "/usr/share/CLK/"
}; };
if(arguments.selections.find("rompath") != arguments.selections.end()) { // if(arguments.selections.find("rompath") != arguments.selections.end()) {
const std::string user_path = arguments.selections["rompath"]->list_selection()->value; // const std::string user_path = arguments.selections["rompath"]->list_selection()->value;
if(user_path.back() != '/') { // if(user_path.back() != '/') {
paths.push_back(user_path + "/"); // paths.push_back(user_path + "/");
} else { // } else {
paths.push_back(user_path); // paths.push_back(user_path);
} // }
} // }
std::vector<std::unique_ptr<std::vector<uint8_t>>> results; std::vector<std::unique_ptr<std::vector<uint8_t>>> results;
for(const auto &rom: roms) { for(const auto &rom: roms) {
@@ -630,17 +633,17 @@ int main(int argc, char *argv[]) {
// Apply the speed multiplier, if one was requested. // Apply the speed multiplier, if one was requested.
if(arguments.selections.find("speed") != arguments.selections.end()) { if(arguments.selections.find("speed") != arguments.selections.end()) {
const char *speed_string = arguments.selections["speed"]->list_selection()->value.c_str(); // const char *speed_string = arguments.selections["speed"]->list_selection()->value.c_str();
char *end; // char *end;
double speed = strtod(speed_string, &end); // double speed = strtod(speed_string, &end);
//
if(size_t(end - speed_string) != strlen(speed_string)) { // if(size_t(end - speed_string) != strlen(speed_string)) {
std::cerr << "Unable to parse speed: " << speed_string << std::endl; // std::cerr << "Unable to parse speed: " << speed_string << std::endl;
} else if(speed <= 0.0) { // } else if(speed <= 0.0) {
std::cerr << "Cannot run at speed " << speed_string << "; speeds must be positive." << std::endl; // std::cerr << "Cannot run at speed " << speed_string << "; speeds must be positive." << std::endl;
} else { // } else {
machine_runner.set_speed_multiplier(speed); // machine_runner.set_speed_multiplier(speed);
} // }
} }
// Check whether a 'logical' keyboard has been requested. // Check whether a 'logical' keyboard has been requested.
@@ -718,7 +721,7 @@ int main(int argc, char *argv[]) {
int window_width, window_height; int window_width, window_height;
SDL_GetWindowSize(window, &window_width, &window_height); SDL_GetWindowSize(window, &window_width, &window_height);
Configurable::Device *const configurable_device = machine->configurable_device(); /* Configurable::Device *const configurable_device = machine->configurable_device();
if(configurable_device) { if(configurable_device) {
// Establish user-friendly options by default. // Establish user-friendly options by default.
configurable_device->set_selections(configurable_device->get_user_friendly_selections()); configurable_device->set_selections(configurable_device->get_user_friendly_selections());
@@ -741,7 +744,7 @@ int main(int argc, char *argv[]) {
// Apply the user's actual selections to final the defaults. // Apply the user's actual selections to final the defaults.
configurable_device->set_selections(arguments.selections); configurable_device->set_selections(arguments.selections);
} }*/
// If this is a joystick machine, check for and open attached joysticks. // If this is a joystick machine, check for and open attached joysticks.
/*! /*!