Make properties overridable from the command line.

This commit is contained in:
Maxim Poliakovski 2020-10-06 11:01:13 +02:00
parent 0ca03be001
commit c81c00f918
7 changed files with 204 additions and 92 deletions

View File

@ -1,12 +1,12 @@
#include "machinebase.h" #include "machinebase.h"
#include "devices/hwcomponent.h" #include "devices/hwcomponent.h"
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thirdparty/loguru/loguru.hpp> #include <thirdparty/loguru/loguru.hpp>
std::unique_ptr<MachineBase> gMachineObj = 0; std::unique_ptr<MachineBase> gMachineObj = 0;
MachineBase::MachineBase(std::string name) { MachineBase::MachineBase(std::string name) {
this->name = name; this->name = name;

View File

@ -143,7 +143,7 @@ int establish_machine_presets(
if (loop_ram_check(machine_str, ram_sizes) == true) { if (loop_ram_check(machine_str, ram_sizes) == true) {
if (machine_str.compare("pmg3") == 0) { if (machine_str.compare("pmg3") == 0) {
create_gossamer(ram_sizes, gfx_mem); create_gossamer();
} }
} }
else { else {

View File

@ -33,10 +33,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <memory>
#include <thirdparty/loguru/loguru.hpp> #include <thirdparty/loguru/loguru.hpp>
using namespace std; using namespace std;
map<string, unique_ptr<BasicProperty>> gMachineSettings;
/** /**
Power Macintosh ROM identification map. Power Macintosh ROM identification map.
@ -60,17 +63,15 @@ static const map<uint32_t, std::tuple<string, const char*>> rom_identity = {
{0x5A616E7A, {"pm4400", "Power Mac 4400/7220"}}, // Zanzibar {0x5A616E7A, {"pm4400", "Power Mac 4400/7220"}}, // Zanzibar
}; };
typedef std::map<std::string, StrProperty> Settings; static const PropMap GossamerSettings = {
{"rambank1_size", new IntProperty("256")},
static const Settings GossamerSettings = { {"rambank2_size", new IntProperty("0") },
{"rambank1_size", StrProperty("256MB")}, {"rambank3_size", new IntProperty("0") },
{"rambank2_size", StrProperty("0") }, {"gfxmem_size", new IntProperty("2") }
{"rambank3_size", StrProperty("0") },
{"gfxmem_size", StrProperty("2MB") }
}; };
static const map<string, Settings> machines = { static const map<string, tuple<PropMap, function<int(void)>>> machines = {
{"pmg3", GossamerSettings} {"pmg3", {GossamerSettings, create_gossamer}},
}; };
string machine_name_from_rom(string& rom_filepath) { string machine_name_from_rom(string& rom_filepath) {
@ -131,10 +132,15 @@ bail_out:
int get_machine_settings(string& id, map<string, string> &settings) { int get_machine_settings(string& id, map<string, string> &settings) {
try { try {
Settings props = machines.at(id); auto props = get<0>(machines.at(id));
gMachineSettings.clear();
for (auto& p : props) { 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<BasicProperty>(p.second->clone());
} }
} }
catch(out_of_range ex) { catch(out_of_range ex) {
@ -146,14 +152,21 @@ int get_machine_settings(string& id, map<string, string> &settings) {
void set_machine_settings(map<string, string> &settings) { void set_machine_settings(map<string, string> &settings) {
for (auto& s : 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) { int create_machine_for_id(uint32_t id, uint32_t* grab_ram_size, uint32_t gfx_size) {
switch (id) { switch (id) {
case 0x476F7373: case 0x476F7373:
create_gossamer(grab_ram_size, gfx_size); create_gossamer();
break; break;
default: default:
LOG_F(ERROR, "Unknown machine ID: %X", id); 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; return 0;
} }
/* Read ROM file content and transfer it to the dedicated ROM region */ /* Read ROM file content and transfer it to the dedicated ROM region */
void load_rom(std::ifstream& rom_file, uint32_t file_size) { void load_rom(std::ifstream& rom_file, uint32_t file_size) {
unsigned char* sysrom_mem = new unsigned char[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; 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<MemCtrlBase*>(
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) { int create_machine_for_rom(const char* rom_filepath, uint32_t* grab_ram_size, uint32_t gfx_size) {
ifstream rom_file; 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 */ /* 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); create_machine_for_id(rom_id, grab_ram_size, gfx_size);

View File

@ -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); void load_rom(std::ifstream& rom_file, uint32_t file_size);
int get_machine_settings(string& id, map<string, string> &settings); int get_machine_settings(string& id, map<string, string> &settings);
void set_machine_settings(map<string, string> &settings); void set_machine_settings(map<string, string> &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_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 */ #endif /* MACHINE_FACTORY_H */

View File

@ -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) { if (gMachineObj) {
LOG_F(ERROR, "Global machine object not empty!"); LOG_F(ERROR, "Global machine object not empty!");
return -1; return -1;
@ -88,12 +88,13 @@ int create_gossamer(uint32_t* grab_ram_size, uint32_t gfx_size) {
} }
/* configure RAM slots */ /* 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_1", 0x57, GET_INT_PROP("rambank1_size"));
setup_ram_slot("RAM_DIMM_2", 0x56, grab_ram_size[1]); /* RAM slot 2 -> empty by default */ setup_ram_slot("RAM_DIMM_2", 0x56, GET_INT_PROP("rambank2_size"));
setup_ram_slot("RAM_DIMM_3", 0x55, grab_ram_size[2]); /* RAM slot 3 -> empty by default */ setup_ram_slot("RAM_DIMM_3", 0x55, GET_INT_PROP("rambank3_size"));
/* register ATI 3D Rage Pro video card with the PCI host bridge */ /* 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( grackle_obj->pci_register_device(
18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage"))); 18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage")));

View File

@ -3,29 +3,60 @@
#include <cinttypes> #include <cinttypes>
#include <string> #include <string>
#include <map> #include <map>
#include <memory>
#include <iostream> #include <iostream>
#include <utility> #include <utility>
#ifndef MACHINE_PROPERTIES_H #ifndef MACHINE_PROPERTIES_H
#define MACHINE_PROPERTIES_H #define MACHINE_PROPERTIES_H
using namespace std; using namespace std;
#define ILLEGAL_DEVICE_VALUE 0x168A523B #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: public:
StrProperty(string str) { BasicProperty(PropType type, string val) {
this->prop_val = str; this->type = type;
set_string(val);
} }
virtual ~BasicProperty() = default;
virtual BasicProperty* clone() const = 0;
string get_string() { string get_string() {
return this->prop_val; return this->val;
} }
void set_string(string str) { 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() { uint32_t IntRep() {
try { try {
return strtoul(get_string().c_str(), 0, 0); return strtoul(get_string().c_str(), 0, 0);
@ -35,35 +66,60 @@ public:
return ILLEGAL_DEVICE_VALUE; return ILLEGAL_DEVICE_VALUE;
} }
} }
private:
string prop_val = string("");
}; };
class IntProperty { class IntProperty : public BasicProperty {
public: public:
IntProperty(string str) { IntProperty(string str)
this->prop_val = str; : BasicProperty(PROP_TYPE_INTEGER, str)
{
this->int_val = 0;
this->min = std::numeric_limits<uint32_t>::min();
this->max = std::numeric_limits<uint32_t>::max();
} }
void set_string(string str) { IntProperty(string str, uint32_t min, uint32_t max)
this->prop_val = str; : 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() { uint32_t get_int() {
try { 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) { } catch (string bad_string) {
LOG_F(ERROR, "Could not convert string %s to an integer!", LOG_F(ERROR, "Could not convert string %s to an integer!",
bad_string.c_str()); bad_string.c_str());
} }
return 0; return this->int_val;
} }
private: private:
string prop_val = string(""); uint32_t int_val;
uint32_t min;
uint32_t max;
}; };
typedef map<string, BasicProperty*> PropMap;
extern map<string, unique_ptr<BasicProperty>> gMachineSettings;
#define GET_INT_PROP(name) \
dynamic_cast<IntProperty*>(gMachineSettings.at(name).get())->get_int()
uint32_t get_gfx_card(std::string gfx_str); uint32_t get_gfx_card(std::string gfx_str);
uint32_t get_cpu_type(std::string cpu_str); uint32_t get_cpu_type(std::string cpu_str);
void search_properties(uint32_t chosen_gestalt); void search_properties(uint32_t chosen_gestalt);

View File

@ -38,23 +38,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std; using namespace std;
void display_help() { static string appDescription = string(
std::cout << " " << endl; "\nDingusPPC - Prototype 5bf5 (8/23/2020) "
std::cout << "To interact with DingusPPC, please refer to the " << endl; "\nWritten by divingkatae and maximumspatium "
std::cout << "following command line reference guide: " << endl; "\n(c) 2018-2020 The DingusPPC Dev Team. "
std::cout << "___________________________________________________" << endl; "\nThis is not intended for general use. "
std::cout << "| COMMAND | FUNCTION |" << endl; "\nUse at your own discretion. "
std::cout << "___________________________________________________" << endl; "\n"
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;
}
void display_recognized_machines() { void display_recognized_machines() {
std::cout << " " << endl; std::cout << " " << endl;
@ -77,23 +68,12 @@ int main(int argc, char** argv) {
The rest will be decided later The rest will be decided later
*/ */
uint32_t execution_mode = 0; uint32_t execution_mode = 0;
uint32_t sys_ram_size[12] = {64, 0, 0, 0};
uint32_t gfx_mem = 2;
string machine_name = "";
CLI::App app("DingusPPC CLI"); CLI::App app(appDescription);
app.allow_windows_style_options(); /* we want Windows-style options */ app.allow_windows_style_options(); /* we want Windows-style options */
app.allow_extras(); 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; bool realtime_enabled, debugger_enabled;
string machine_str; string machine_str;
string bootrom_path("bootrom.bin"); string bootrom_path("bootrom.bin");
@ -110,11 +90,20 @@ int main(int argc, char** argv) {
CLI::Option* machine_opt = app.add_option("-m,--machine", CLI::Option* machine_opt = app.add_option("-m,--machine",
machine_str, "Specify machine ID"); 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"); "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); CLI11_PARSE(app, argc, argv);
if (*list_cmd) {
std::cout << "Got: " << sub_arg << std::endl;
}
if (debugger_enabled) { if (debugger_enabled) {
if (realtime_enabled) if (realtime_enabled)
cout << "Both realtime and debugger enabled! Using debugger" << endl; 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_time = false;
loguru::g_preamble_thread = false; loguru::g_preamble_thread = false;
if (execution_mode) { if (!execution_mode) {
loguru::g_stderr_verbosity = loguru::Verbosity_OFF; loguru::g_stderr_verbosity = loguru::Verbosity_OFF;
loguru::init(argc, argv); loguru::init(argc, argv);
loguru::add_file("dingusppc.log", loguru::Append, 0); loguru::add_file("dingusppc.log", loguru::Append, 0);
@ -137,31 +126,22 @@ int main(int argc, char** argv) {
if (*machine_opt) { if (*machine_opt) {
LOG_F(INFO, "Machine option was passed in: %s", machine_str.c_str()); 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 { } else {
machine_str = machine_name_from_rom(bootrom_path); machine_str = machine_name_from_rom(bootrom_path);
if (machine_str.empty()) { if (machine_str.empty()) {
LOG_F(ERROR, "Could not autodetect machine"); LOG_F(ERROR, "Could not autodetect machine");
return 0; return 0;
} }
else { else {
LOG_F(INFO, "Machine was autodetected as: %s", machine_str.c_str()); 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<string, string> settings; map<string, string> settings;
get_machine_settings(machine_str, settings); if (get_machine_settings(machine_str, settings) < 0) {
return 0;
}
CLI::App sa; CLI::App sa;
sa.allow_extras(); sa.allow_extras();
@ -176,13 +156,17 @@ int main(int argc, char** argv) {
cout << "BootROM path: " << bootrom_path << endl; cout << "BootROM path: " << bootrom_path << endl;
cout << "Execution mode: " << execution_mode << endl; cout << "Execution mode: " << execution_mode << endl;
if (create_machine_for_id(machine_str, bootrom_path) < 0) {
goto bail;
}
#ifdef SDL #ifdef SDL
if (SDL_Init(SDL_INIT_AUDIO)){ if (SDL_Init(SDL_INIT_AUDIO)){
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError()); LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
return 0; return 0;
} }
#endif #endif
switch (execution_mode) { switch (execution_mode) {
case 0: case 0:
for (;;) { for (;;) {
@ -196,13 +180,11 @@ int main(int argc, char** argv) {
LOG_F(ERROR, "Invalid EXECUTION MODE"); LOG_F(ERROR, "Invalid EXECUTION MODE");
return 0; return 0;
} }
/* bail:
bail:
LOG_F(INFO, "Cleaning up..."); LOG_F(INFO, "Cleaning up...");
delete gMachineObj.release(); delete gMachineObj.release();
return 0; return 0;
*/
} }