From c81c00f91832a93b1f4e27a778615719e9c5d0d3 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Tue, 6 Oct 2020 11:01:13 +0200 Subject: [PATCH] Make properties overridable from the command line. --- machines/machinebase.cpp | 2 +- machines/machineconfig.cpp | 2 +- machines/machinefactory.cpp | 103 +++++++++++++++++++++++++++++------ machines/machinefactory.h | 6 +- machines/machinegossamer.cpp | 11 ++-- machines/machineproperties.h | 88 ++++++++++++++++++++++++------ main.cpp | 84 +++++++++++----------------- 7 files changed, 204 insertions(+), 92 deletions(-) diff --git a/machines/machinebase.cpp b/machines/machinebase.cpp index 240cfea..f992608 100644 --- a/machines/machinebase.cpp +++ b/machines/machinebase.cpp @@ -1,12 +1,12 @@ #include "machinebase.h" #include "devices/hwcomponent.h" +#include #include #include #include std::unique_ptr gMachineObj = 0; - MachineBase::MachineBase(std::string name) { this->name = name; diff --git a/machines/machineconfig.cpp b/machines/machineconfig.cpp index 41a6754..2c8ec40 100644 --- a/machines/machineconfig.cpp +++ b/machines/machineconfig.cpp @@ -143,7 +143,7 @@ int establish_machine_presets( if (loop_ram_check(machine_str, ram_sizes) == true) { if (machine_str.compare("pmg3") == 0) { - create_gossamer(ram_sizes, gfx_mem); + create_gossamer(); } } else { diff --git a/machines/machinefactory.cpp b/machines/machinefactory.cpp index c72a24b..d155987 100644 --- a/machines/machinefactory.cpp +++ b/machines/machinefactory.cpp @@ -33,10 +33,13 @@ along with this program. If not, see . #include #include #include +#include #include using namespace std; +map> gMachineSettings; + /** Power Macintosh ROM identification map. @@ -60,17 +63,15 @@ static const map> rom_identity = { {0x5A616E7A, {"pm4400", "Power Mac 4400/7220"}}, // Zanzibar }; -typedef std::map Settings; - -static const Settings GossamerSettings = { - {"rambank1_size", StrProperty("256MB")}, - {"rambank2_size", StrProperty("0") }, - {"rambank3_size", StrProperty("0") }, - {"gfxmem_size", StrProperty("2MB") } +static const PropMap GossamerSettings = { + {"rambank1_size", new IntProperty("256")}, + {"rambank2_size", new IntProperty("0") }, + {"rambank3_size", new IntProperty("0") }, + {"gfxmem_size", new IntProperty("2") } }; -static const map machines = { - {"pmg3", GossamerSettings} +static const map>> machines = { + {"pmg3", {GossamerSettings, create_gossamer}}, }; string machine_name_from_rom(string& rom_filepath) { @@ -131,10 +132,15 @@ bail_out: int get_machine_settings(string& id, map &settings) { try { - Settings props = machines.at(id); + auto props = get<0>(machines.at(id)); + + gMachineSettings.clear(); for (auto& p : props) { - settings[p.first] = p.second.get_string(); + settings[p.first] = p.second->get_string(); + + /* populate dynamic machine settings from presets */ + gMachineSettings[p.first] = unique_ptr(p.second->clone()); } } catch(out_of_range ex) { @@ -146,14 +152,21 @@ int get_machine_settings(string& id, map &settings) { void set_machine_settings(map &settings) { for (auto& s : settings) { - cout << s.first << " : " << s.second << endl; + gMachineSettings.at(s.first)->set_string(s.second); + } + + /* print machine settings summary */ + cout << endl << "Machine settings summary: " << endl; + + for (auto& p : gMachineSettings) { + cout << p.first << " : " << p.second->get_string() << endl; } } int create_machine_for_id(uint32_t id, uint32_t* grab_ram_size, uint32_t gfx_size) { switch (id) { case 0x476F7373: - create_gossamer(grab_ram_size, gfx_size); + create_gossamer(); break; default: LOG_F(ERROR, "Unknown machine ID: %X", id); @@ -162,7 +175,6 @@ int create_machine_for_id(uint32_t id, uint32_t* grab_ram_size, uint32_t gfx_siz return 0; } - /* Read ROM file content and transfer it to the dedicated ROM region */ void load_rom(std::ifstream& rom_file, uint32_t file_size) { unsigned char* sysrom_mem = new unsigned char[file_size]; @@ -177,6 +189,63 @@ void load_rom(std::ifstream& rom_file, uint32_t file_size) { delete[] sysrom_mem; } +/* Read ROM file content and transfer it to the dedicated ROM region */ +int load_boot_rom(string& rom_filepath) { + ifstream rom_file; + size_t file_size; + int result; + + rom_file.open(rom_filepath, ios::in | ios::binary); + if (rom_file.fail()) { + LOG_F(ERROR, "Cound not open the specified ROM file."); + rom_file.close(); + return -1; + } + + rom_file.seekg(0, rom_file.end); + file_size = rom_file.tellg(); + rom_file.seekg(0, rom_file.beg); + + if (file_size != 0x400000UL) { + LOG_F(ERROR, "Unxpected ROM File size. Expected size is 4 megabytes."); + result = -1; + } else { + unsigned char* sysrom_mem = new unsigned char[file_size]; + + rom_file.seekg(0, ios::beg); + rom_file.read((char*)sysrom_mem, file_size); + + MemCtrlBase* mem_ctrl = dynamic_cast( + gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL)); + + mem_ctrl->set_data(0xFFC00000, sysrom_mem, file_size); + delete[] sysrom_mem; + + result = 0; + } + + rom_file.close(); + + return result; +} + + +int create_machine_for_id(string& id, string& rom_filepath) { + try { + auto machine = machines.at(id); + + /* build machine and load boot ROM */ + if (get<1>(machine)() < 0 || load_boot_rom(rom_filepath) < 0) { + return -1; + } + } catch(out_of_range ex) { + LOG_F(ERROR, "Unknown machine id %s", id.c_str()); + return -1; + } + + return 0; +} + int create_machine_for_rom(const char* rom_filepath, uint32_t* grab_ram_size, uint32_t gfx_size) { ifstream rom_file; @@ -221,9 +290,11 @@ int create_machine_for_rom(const char* rom_filepath, uint32_t* grab_ram_size, ui } /* convert BootstrapVersion string to ROM ID */ - rom_id = (rom_id_str[5] << 24) | (rom_id_str[6] << 16) | (rom_id_str[7] << 8) | rom_id_str[8]; + rom_id = (rom_id_str[5] << 24) | (rom_id_str[6] << 16) | + (rom_id_str[7] << 8) | rom_id_str[8]; - LOG_F(INFO, "The machine is identified as... %s\n", std::get<1>(rom_identity.at(rom_id))); + LOG_F(INFO, "The machine is identified as... %s\n", + std::get<1>(rom_identity.at(rom_id))); create_machine_for_id(rom_id, grab_ram_size, gfx_size); diff --git a/machines/machinefactory.h b/machines/machinefactory.h index 3c35aa2..bbf709e 100644 --- a/machines/machinefactory.h +++ b/machines/machinefactory.h @@ -37,11 +37,13 @@ std::string machine_name_from_rom(std::string& rom_filepath); void load_rom(std::ifstream& rom_file, uint32_t file_size); -int get_machine_settings(string& id, map &settings); +int get_machine_settings(string& id, map &settings); void set_machine_settings(map &settings); +int create_machine_for_id(string& id, string& rom_filepath); int create_machine_for_rom(const char* rom_filepath, uint32_t* grab_ram_size, uint32_t gfx_size); -int create_gossamer(uint32_t* grab_ram_size, uint32_t gfx_size); +/* Machine-specific factory functions. */ +int create_gossamer(void); #endif /* MACHINE_FACTORY_H */ diff --git a/machines/machinegossamer.cpp b/machines/machinegossamer.cpp index 96cc563..4a3062a 100644 --- a/machines/machinegossamer.cpp +++ b/machines/machinegossamer.cpp @@ -51,7 +51,7 @@ static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) { } -int create_gossamer(uint32_t* grab_ram_size, uint32_t gfx_size) { +int create_gossamer() { if (gMachineObj) { LOG_F(ERROR, "Global machine object not empty!"); return -1; @@ -88,12 +88,13 @@ int create_gossamer(uint32_t* grab_ram_size, uint32_t gfx_size) { } /* configure RAM slots */ - setup_ram_slot("RAM_DIMM_1", 0x57, grab_ram_size[0]); /* RAM slot 1 -> 64MB by default */ - setup_ram_slot("RAM_DIMM_2", 0x56, grab_ram_size[1]); /* RAM slot 2 -> empty by default */ - setup_ram_slot("RAM_DIMM_3", 0x55, grab_ram_size[2]); /* RAM slot 3 -> empty by default */ + setup_ram_slot("RAM_DIMM_1", 0x57, GET_INT_PROP("rambank1_size")); + setup_ram_slot("RAM_DIMM_2", 0x56, GET_INT_PROP("rambank2_size")); + setup_ram_slot("RAM_DIMM_3", 0x55, GET_INT_PROP("rambank3_size")); /* register ATI 3D Rage Pro video card with the PCI host bridge */ - gMachineObj->add_component("ATIRage", new ATIRage(ATI_RAGE_PRO_DEV_ID, gfx_size)); + gMachineObj->add_component("ATIRage", + new ATIRage(ATI_RAGE_PRO_DEV_ID, GET_INT_PROP("gfxmem_size"))); grackle_obj->pci_register_device( 18, dynamic_cast(gMachineObj->get_comp_by_name("ATIRage"))); diff --git a/machines/machineproperties.h b/machines/machineproperties.h index 192c3d8..25106cf 100644 --- a/machines/machineproperties.h +++ b/machines/machineproperties.h @@ -3,29 +3,60 @@ #include #include #include +#include #include #include #ifndef MACHINE_PROPERTIES_H #define MACHINE_PROPERTIES_H + using namespace std; #define ILLEGAL_DEVICE_VALUE 0x168A523B -class StrProperty { +/** Property types. */ +enum PropType : int { + PROP_TYPE_UNKNOWN = 0, + PROP_TYPE_STRING = 1, + PROP_TYPE_INTEGER = 2, +}; + +class BasicProperty { public: - StrProperty(string str) { - this->prop_val = str; + BasicProperty(PropType type, string val) { + this->type = type; + set_string(val); } + virtual ~BasicProperty() = default; + + virtual BasicProperty* clone() const = 0; + string get_string() { - return this->prop_val; + return this->val; } void set_string(string str) { - this->prop_val = str; + this->val = str; } + PropType get_type() { + return this->type; + } + +protected: + PropType type; + string val; +}; + + +class StrProperty : public BasicProperty { +public: + StrProperty(string str) + : BasicProperty(PROP_TYPE_STRING, str) {} + + BasicProperty* clone() const { return new StrProperty(*this); } + uint32_t IntRep() { try { return strtoul(get_string().c_str(), 0, 0); @@ -35,35 +66,60 @@ public: return ILLEGAL_DEVICE_VALUE; } } - -private: - string prop_val = string(""); }; -class IntProperty { +class IntProperty : public BasicProperty { public: - IntProperty(string str) { - this->prop_val = str; + IntProperty(string str) + : BasicProperty(PROP_TYPE_INTEGER, str) + { + this->int_val = 0; + this->min = std::numeric_limits::min(); + this->max = std::numeric_limits::max(); } - void set_string(string str) { - this->prop_val = str; + IntProperty(string str, uint32_t min, uint32_t max) + : BasicProperty(PROP_TYPE_INTEGER, str) + { + this->int_val = 0; + this->min = min; + this->max = max; + + this->int_val = this->get_int(); } + BasicProperty* clone() const { return new IntProperty(*this); } + uint32_t get_int() { try { - return strtoul(this->prop_val.c_str(), 0, 0); + uint32_t result = strtoul(this->get_string().c_str(), 0, 0); + + /* perform range check */ + if (result < this->min || result > this->max) { + LOG_F(ERROR, "Value %d out of range!", result); + } else { + this->int_val = result; + } } catch (string bad_string) { LOG_F(ERROR, "Could not convert string %s to an integer!", bad_string.c_str()); } - return 0; + return this->int_val; } private: - string prop_val = string(""); + uint32_t int_val; + uint32_t min; + uint32_t max; }; +typedef map PropMap; + +extern map> gMachineSettings; + +#define GET_INT_PROP(name) \ + dynamic_cast(gMachineSettings.at(name).get())->get_int() + uint32_t get_gfx_card(std::string gfx_str); uint32_t get_cpu_type(std::string cpu_str); void search_properties(uint32_t chosen_gestalt); diff --git a/main.cpp b/main.cpp index 9151c74..c0eb436 100644 --- a/main.cpp +++ b/main.cpp @@ -38,23 +38,14 @@ along with this program. If not, see . using namespace std; -void display_help() { - std::cout << " " << endl; - std::cout << "To interact with DingusPPC, please refer to the " << endl; - std::cout << "following command line reference guide: " << endl; - std::cout << "___________________________________________________" << endl; - std::cout << "| COMMAND | FUNCTION |" << endl; - std::cout << "___________________________________________________" << endl; - std::cout << " realtime | Run the emulator in real-time " << endl; - std::cout << " debugger | Enter the interactive debugger " << endl; - std::cout << " ram | Specify the number of RAM banks, " << endl; - std::cout << " | followed by how much each bank holds " << endl; - std::cout << " videocard | Specify the video card to emulate " << endl; - std::cout << " gfxmem | Specify the how much memory " << endl; - std::cout << " | to allocate to the emulated video card" << endl; - std::cout << " romfile | Insert the ROM file to use " << endl; - std::cout << " " << endl; -} +static string appDescription = string( + "\nDingusPPC - Prototype 5bf5 (8/23/2020) " + "\nWritten by divingkatae and maximumspatium " + "\n(c) 2018-2020 The DingusPPC Dev Team. " + "\nThis is not intended for general use. " + "\nUse at your own discretion. " + "\n" +); void display_recognized_machines() { std::cout << " " << endl; @@ -77,23 +68,12 @@ int main(int argc, char** argv) { The rest will be decided later */ - uint32_t execution_mode = 0; - uint32_t sys_ram_size[12] = {64, 0, 0, 0}; - uint32_t gfx_mem = 2; - string machine_name = ""; + uint32_t execution_mode = 0; - CLI::App app("DingusPPC CLI"); + CLI::App app(appDescription); app.allow_windows_style_options(); /* we want Windows-style options */ app.allow_extras(); - cout << endl; - cout << "DingusPPC - Prototype 5bf5 (8/23/2020) " << endl; - cout << "Written by divingkatae and maximumspatium " << endl; - cout << "(c) 2018-2020 The DingusPPC Dev Team. " << endl; - cout << "This is not intended for general use. " << endl; - cout << "Use at your own discretion. " << endl; - cout << endl; - bool realtime_enabled, debugger_enabled; string machine_str; string bootrom_path("bootrom.bin"); @@ -110,11 +90,20 @@ int main(int argc, char** argv) { CLI::Option* machine_opt = app.add_option("-m,--machine", machine_str, "Specify machine ID"); - auto list_cmd = app.add_subcommand("machines", + auto list_cmd = app.add_subcommand("list", "Display available machine configurations and exit"); + string sub_arg; + + list_cmd->add_option("machines", sub_arg, "List supported machines"); + list_cmd->add_option("properties", sub_arg, "List available properties"); + CLI11_PARSE(app, argc, argv); + if (*list_cmd) { + std::cout << "Got: " << sub_arg << std::endl; + } + if (debugger_enabled) { if (realtime_enabled) cout << "Both realtime and debugger enabled! Using debugger" << endl; @@ -126,7 +115,7 @@ int main(int argc, char** argv) { loguru::g_preamble_time = false; loguru::g_preamble_thread = false; - if (execution_mode) { + if (!execution_mode) { loguru::g_stderr_verbosity = loguru::Verbosity_OFF; loguru::init(argc, argv); loguru::add_file("dingusppc.log", loguru::Append, 0); @@ -137,31 +126,22 @@ int main(int argc, char** argv) { if (*machine_opt) { LOG_F(INFO, "Machine option was passed in: %s", machine_str.c_str()); - create_machine_for_rom(bootrom_path.c_str(), sys_ram_size, gfx_mem); } else { machine_str = machine_name_from_rom(bootrom_path); if (machine_str.empty()) { LOG_F(ERROR, "Could not autodetect machine"); return 0; - } + } else { LOG_F(INFO, "Machine was autodetected as: %s", machine_str.c_str()); - if (machine_str.compare("pmg3") == 0) { - LOG_F(INFO, "Time to build up a machine"); - establish_machine_presets(bootrom_path.c_str(), machine_str, sys_ram_size, gfx_mem); - } else if (machine_str.compare("pm6100") == 0) { - LOG_F(ERROR, "Board not yet ready for: %s", machine_str.c_str()); - return -1; - } else { - cout << "Unable to define machine: " << machine_str << endl; - return -1; - } } } - /* handle overriding of machine settings from CLI */ + /* handle overriding of machine settings from command line */ map settings; - get_machine_settings(machine_str, settings); + if (get_machine_settings(machine_str, settings) < 0) { + return 0; + } CLI::App sa; sa.allow_extras(); @@ -176,13 +156,17 @@ int main(int argc, char** argv) { cout << "BootROM path: " << bootrom_path << endl; cout << "Execution mode: " << execution_mode << endl; + if (create_machine_for_id(machine_str, bootrom_path) < 0) { + goto bail; + } + #ifdef SDL if (SDL_Init(SDL_INIT_AUDIO)){ LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError()); return 0; } #endif - + switch (execution_mode) { case 0: for (;;) { @@ -196,13 +180,11 @@ int main(int argc, char** argv) { LOG_F(ERROR, "Invalid EXECUTION MODE"); return 0; } - - /* - bail: + +bail: LOG_F(INFO, "Cleaning up..."); delete gMachineObj.release(); return 0; - */ }