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 "devices/hwcomponent.h"
#include <map>
#include <memory>
#include <string>
#include <thirdparty/loguru/loguru.hpp>
std::unique_ptr<MachineBase> gMachineObj = 0;
MachineBase::MachineBase(std::string name) {
this->name = name;

View File

@ -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 {

View File

@ -33,10 +33,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <thirdparty/loguru/loguru.hpp>
using namespace std;
map<string, unique_ptr<BasicProperty>> gMachineSettings;
/**
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
};
typedef std::map<std::string, StrProperty> 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<string, Settings> machines = {
{"pmg3", GossamerSettings}
static const map<string, tuple<PropMap, function<int(void)>>> 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<string, string> &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<BasicProperty>(p.second->clone());
}
}
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) {
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<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) {
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);

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);
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);
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 */

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) {
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<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage")));

View File

@ -3,29 +3,60 @@
#include <cinttypes>
#include <string>
#include <map>
#include <memory>
#include <iostream>
#include <utility>
#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<uint32_t>::min();
this->max = std::numeric_limits<uint32_t>::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<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_cpu_type(std::string cpu_str);
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;
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<string, string> 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;
*/
}