Files
FEX-Emu--FEX/Source/Common/ArgumentLoader.cpp
T
Ryan Houdek f14cd54791 Switches over to having a correctly layered configuration system
Instead of having the configuration being loaded and stored in to a
frontend system. First moves the backing store of the configuration in
to FEXCore.

Each layer that is constructed then loads its particular configuration.
After the layers are loaded, then a meta layer is constructed that
merges the layers flat.

This means we will no longer hit the problem where a configuration is
stored in the "main" configuration file, then environment and arguments
passed manage to overwrite it.

The order of the layers going from inner most layer to outer most, with
outermost overwriting previous layer configurations is as follows:

Main < Global application < Local application < Arguments < Environment

One step that needs to be changed in the future is that FEXCore can then
just load its configuration from the layers directly since the data is
in FEXCore now. This will be reserved for a future change so we are less
disruptive.
2020-12-07 11:15:48 -08:00

292 lines
9.6 KiB
C++

#include "Common/ArgumentLoader.h"
#include "Common/Config.h"
#include "OptionParser.h"
namespace FEX::ArgLoader {
std::vector<std::string> RemainingArgs;
std::vector<std::string> ProgramArguments;
void FEX::ArgLoader::ArgLoader::Load() {
optparse::OptionParser Parser{};
optparse::OptionGroup CPUGroup(Parser, "CPU Core options");
optparse::OptionGroup EmulationGroup(Parser, "Emulation options");
optparse::OptionGroup TestGroup(Parser, "Test Harness options");
optparse::OptionGroup LoggingGroup(Parser, "Logging options");
{
CPUGroup.add_option("-c", "--core")
.dest("Core")
.help("Which CPU core to use")
#ifdef _M_X86_64
.choices({"irint", "irjit", "host"})
#else
.choices({"irint", "irjit"})
#endif
.set_default("irint");
std::string BreakString = "Break";
std::string MultiBlockString = "Multiblock";
Parser.set_defaults(BreakString, "0");
Parser.set_defaults(MultiBlockString, "0");
CPUGroup.add_option("-b", "--break")
.dest("Break")
.action("store_true")
.help("Break when op dispatcher doesn't understand instruction");
CPUGroup.add_option("--no-break")
.dest("Break")
.action("store_false")
.help("Break when op dispatcher doesn't understand instruction");
CPUGroup.add_option("-s", "--single-step")
.dest("SingleStep")
.action("store_true")
.help("Single Step config");
CPUGroup.add_option("-n", "--max-inst")
.dest("MaxInst")
.help("Maximum number of instructions to stick in a block")
.set_default(~0U);
CPUGroup.add_option("-m", "--multiblock")
.dest("Multiblock")
.action("store_true")
.help("Enable Multiblock code compilation");
CPUGroup.add_option("--no-multiblock")
.dest("Multiblock")
.action("store_false")
.help("Enable Multiblock code compilation");
CPUGroup.add_option("-G", "--gdb")
.dest("GdbServer")
.action("store_true")
.help("Enables the GDB server");
CPUGroup.add_option("-T", "--Threads")
.dest("Threads")
.help("Number of physical hardware threads to tell the process we have")
.set_default(1);
CPUGroup.add_option("--smc-full-checks")
.dest("SMCChecks")
.action("store_true")
.help("Checks code for modification before execution. Slow.")
.set_default(false);
CPUGroup.add_option("--unsafe-no-tso")
.dest("TSOEnabled")
.action("store_false")
.help("Disables TSO IR ops. Highly likely to break any threaded application")
.set_default(true);
CPUGroup.add_option("--unsafe-local-flags")
.dest("AbiLocalFlags")
.action("store_true")
.help("Assumes flags are not used across calls. Hand-written asm could violate this assumption")
.set_default(false);
CPUGroup.add_option("--unsafe-no-pf")
.dest("AbiNoPF")
.action("store_true")
.help("Does not calculate the parity flag on integer operations")
.set_default(false);
Parser.add_option_group(CPUGroup);
}
{
Parser.set_defaults("RootFS", "");
Parser.set_defaults("ThunkLibs", "");
EmulationGroup.add_option("-R", "--rootfs")
.dest("RootFS")
.help("Which Root filesystem prefix to use");
EmulationGroup.add_option("-t", "--thunklibs")
.dest("ThunkLibs")
.help("Folder to find the host-side thunking libs");
EmulationGroup.add_option("-U", "--unified-memory")
.dest("UnifiedMemory")
.action("store_true")
.help("Enable unified memory for the emulator");
EmulationGroup.add_option("-E", "--env")
.dest("Env")
.help("Adds an environment variable")
.action("append");
Parser.add_option_group(EmulationGroup);
}
{
TestGroup.add_option("-g", "--dump-gprs")
.dest("DumpGPRs")
.action("store_true")
.help("When Test Harness ends, print GPR state")
.set_default(false);
TestGroup.add_option("-C", "--ipc-client")
.dest("IPCClient")
.action("store_true")
.help("If the lockstep runner is a client or server")
.set_default(false);
TestGroup.add_option("-I", "--ID")
.dest("IPCID")
.help("Sets an ID that is prepended to IPC names. For multiple runners")
.set_default("0");
TestGroup.add_option("-e", "--elf")
.dest("ELFType")
.action("store_true")
.help("Lockstep runner should load argument as ELF")
.set_default(false);
Parser.add_option_group(TestGroup);
}
{
LoggingGroup.add_option("-s", "--silent")
.dest("SilentLog")
.help("Disable logging")
.action("store_true");
LoggingGroup.add_option("-o", "--output-log")
.dest("OutputLog")
.help("File to write FEX output to [stdout, stderr, <Filename>]")
.set_default("stderr");
LoggingGroup.add_option("--dump-ir")
.dest("DumpIR")
.help("Folder to dump the IR [no, stdout, stderr, <Folder>]")
.set_default("no");
Parser.add_option_group(LoggingGroup);
}
optparse::Values Options = Parser.parse_args(argc, argv);
{
if (Options.is_set_by_user("Core")) {
auto Core = Options["Core"];
if (Core == "irint")
Set(FEXCore::Config::ConfigOption::CONFIG_DEFAULTCORE, "0");
else if (Core == "irjit")
Set(FEXCore::Config::ConfigOption::CONFIG_DEFAULTCORE, "1");
#ifdef _M_X86_64
else if (Core == "host")
Set(FEXCore::Config::ConfigOption::CONFIG_DEFAULTCORE, "2");
#endif
}
if (Options.is_set_by_user("Break")) {
bool Break = Options.get("Break");
Set(FEXCore::Config::ConfigOption::CONFIG_BREAK_ON_FRONTEND, std::to_string(Break));
}
if (Options.is_set_by_user("SingleStep")) {
bool SingleStep = Options.get("SingleStep");
Set(FEXCore::Config::ConfigOption::CONFIG_SINGLESTEP, std::to_string(SingleStep));
// Single stepping also enforces single instruction size blocks
Set(FEXCore::Config::ConfigOption::CONFIG_MAXBLOCKINST, std::to_string(1u));
}
else {
if (Options.is_set_by_user("MaxInst")) {
uint32_t MaxInst = Options.get("MaxInst");
Set(FEXCore::Config::ConfigOption::CONFIG_MAXBLOCKINST, std::to_string(MaxInst));
}
}
if (Options.is_set_by_user("Multiblock")) {
bool Multiblock = Options.get("Multiblock");
Set(FEXCore::Config::ConfigOption::CONFIG_MULTIBLOCK, std::to_string(Multiblock));
}
if (Options.is_set_by_user("GdbServer")) {
bool GdbServer = Options.get("GdbServer");
Set(FEXCore::Config::ConfigOption::CONFIG_GDBSERVER, std::to_string(GdbServer));
}
if (Options.is_set_by_user("Threads")) {
uint64_t Config = Options.get("Threads");
Set(FEXCore::Config::ConfigOption::CONFIG_EMULATED_CPU_CORES, std::to_string(Config));
}
if (Options.is_set_by_user("TSOEnabled")) {
bool TSOEnabled = Options.get("TSOEnabled");
Set(FEXCore::Config::ConfigOption::CONFIG_TSO_ENABLED, std::to_string(TSOEnabled));
}
if (Options.is_set_by_user("SMCChecks")) {
bool SMCChecks = Options.get("SMCChecks");
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, std::to_string(SMCChecks));
}
if (Options.is_set_by_user("AbiLocalFlags")) {
bool AbiLocalFlags = Options.get("AbiLocalFlags");
Set(FEXCore::Config::ConfigOption::CONFIG_ABI_LOCAL_FLAGS, std::to_string(AbiLocalFlags));
}
if (Options.is_set_by_user("AbiNoPF")) {
bool AbiNoPF = Options.get("AbiNoPF");
Set(FEXCore::Config::ConfigOption::CONFIG_ABI_NO_PF, std::to_string(AbiNoPF));
}
}
{
if (Options.is_set_by_user("RootFS")) {
std::string Option = Options["RootFS"];
Set(FEXCore::Config::ConfigOption::CONFIG_ROOTFSPATH, Option);
}
if (Options.is_set_by_user("ThunkLibs")) {
std::string Option = Options["ThunkLibs"];
Set(FEXCore::Config::ConfigOption::CONFIG_THUNKLIBSPATH, Option);
}
if (Options.is_set_by_user("UnifiedMemory")) {
bool Option = Options.get("UnifiedMemory");
Set(FEXCore::Config::ConfigOption::CONFIG_UNIFIED_MEMORY, std::to_string(Option));
}
if (Options.is_set_by_user("Env")) {
for (auto iter = Options.all("Env").begin(); iter != Options.all("Env").end(); ++iter) {
Set(FEXCore::Config::ConfigOption::CONFIG_ENVIRONMENT, *iter);
}
}
}
{
if (Options.is_set_by_user("DumpGPRs")) {
bool DumpGPRs = Options.get("DumpGPRs");
Set(FEXCore::Config::ConfigOption::CONFIG_DUMP_GPRS, std::to_string(DumpGPRs));
}
}
{
if (Options.is_set_by_user("SilentLog")) {
bool SilentLog = Options.get("SilentLog");
Set(FEXCore::Config::ConfigOption::CONFIG_SILENTLOGS, std::to_string(SilentLog));
}
if (Options.is_set_by_user("OutputLog")) {
std::string OutputLog = Options["OutputLog"];
Set(FEXCore::Config::ConfigOption::CONFIG_OUTPUTLOG, OutputLog);
}
if (Options.is_set_by_user("DumpIR")) {
std::string DumpIR = Options["DumpIR"];
Set(FEXCore::Config::ConfigOption::CONFIG_DUMPIR, DumpIR);
}
}
RemainingArgs = Parser.args();
ProgramArguments = Parser.parsed_args();
}
std::vector<std::string> Get() {
return RemainingArgs;
}
std::vector<std::string> GetParsedArgs() {
return ProgramArguments;
}
}