From 00a1c7533bb7b4eb6fd4ed9c16bc07a757415569 Mon Sep 17 00:00:00 2001 From: ThirstyWraith <93416469+ThirstyWraith@users.noreply.github.com> Date: Sun, 22 Mar 2026 14:41:04 +0100 Subject: [PATCH 1/2] correctly map cli paramters for all supported cc_mips versions --- host_ctx.h | 218 +++++++++++++++++++++++++++++++++++++++++----------- mwccwrap.c | 201 ++++++++++++++++++++++-------------------------- pluginlib.c | 186 +++++++++++++++++++++++++++++++------------- 3 files changed, 400 insertions(+), 205 deletions(-) diff --git a/host_ctx.h b/host_ctx.h index ebe0364..81f4f1c 100644 --- a/host_ctx.h +++ b/host_ctx.h @@ -282,41 +282,153 @@ typedef struct PPreprocessor { * MIPS preference panel structs * ============================================================ */ -/* "MIPS CodeGen" panel (20 bytes) */ -typedef struct PMIPSCodeGen { - SInt16 version; /* 0x00: ignored by DLL */ - UInt8 structalignment; /* 0x02: struct alignment (bulk-copied, not individually read) */ - UInt8 tracebacktables; /* 0x03: traceback tables (bulk-copied, not individually read) */ - SInt16 processor; /* 0x04: processor type (overridden to 0x1000 for PSX in init) */ - SInt16 fpuType; /* 0x06: FPU type: 0=none, 1=single, 2=double, 3=all */ - SInt16 isaLevel; /* 0x08: MIPS ISA level (I/II/III/IV) */ - UInt8 multibyteAware; /* 0x0A: multibyte string handling */ - UInt8 peephole; /* 0x0B: peephole optimization enable */ - UInt8 reserved_0C; /* 0x0C: unused */ - UInt8 useIntrinsics; /* 0x0D: inline intrinsics for strcpy/memcpy/etc */ - UInt8 reserved_0E; /* 0x0E: unused */ - UInt8 reserved_0F; /* 0x0F: unused */ - UInt32 reserved_10; /* 0x10: stored but never read */ -} PMIPSCodeGen; - -/* "MIPS Linker Panel" (340 bytes) */ -typedef struct PMIPSLinker { - SInt16 version; /* 0x00 */ - UInt8 reserved_02; /* 0x02 */ - UInt8 reserved_03; /* 0x03 */ - UInt8 reserved_04; /* 0x04 */ - UInt8 genOutput; /* 0x05: controls linker output behavior */ - UInt8 reserved_06[334]; /* 0x06..0x153 */ -} PMIPSLinker; - -/* "MIPS Project" (60 bytes) */ -typedef struct PMIPSProject { - SInt16 version; /* 0x00 */ - UInt8 reserved_02; /* 0x02 */ - UInt8 reserved_03; /* 0x03 */ - SInt16 projectSetting; /* 0x04: project-level setting */ - UInt8 reserved_06[54]; /* 0x06..0x3B */ -} PMIPSProject; +typedef struct MIPSCodeGenR3 { + SInt16 version; + SInt16 processor; + SInt16 optimizationlevel; + UInt8 readonlystrings; + UInt8 floatgen; + UInt8 isa_ii; + UInt8 isa_iii; + UInt8 isa_iv; + UInt8 pad_0B; +} MIPSCodeGenR3; + +typedef struct MIPSCodeGenR4 { + SInt16 version; + SInt16 pad_02; + SInt16 optimizationlevel; + UInt8 readonlystrings; + UInt8 pad_07; + UInt8 pad_08; // always set + UInt8 pad_09; + UInt8 pad_0A; + UInt8 pad_0B; + UInt8 profiler; + UInt8 pad_0D; +} MIPSCodeGenR4; + +typedef struct MIPSCodeGenR5 { + SInt16 version; + SInt16 pad_02; + SInt16 optimizationlevel; + SInt16 pad_06; + UInt8 pad_08; // always set + UInt8 pad_09; + UInt8 readonlystrings; + UInt8 profiler; + UInt8 pad_0C[8]; +} MIPSCodeGenR5; + +typedef struct MIPSLinkerPanelR3 { + SInt16 version; + UInt8 listdwarf; + UInt8 symfullpath; + UInt8 linkmap; + UInt8 nolinkwarnings; + UInt8 genSrecFile; + UInt8 linkunused; + SInt32 codeaddr; + SInt32 dataaddr; + SInt32 smalldataaddr; + SInt32 stackaddr; + UInt8 mainname[64]; + UInt8 listclosure; + UInt8 pad_0x59; + SInt16 srecLength; + UInt8 srecEOL; + UInt8 pad_0x5D; +} MIPSLinkerPanelR3; + +typedef struct MIPSLinkerPanelR4 { + SInt16 version; + UInt8 listdwarf; + UInt8 symfullpath; + UInt8 linkmap; + UInt8 nolinkwarnings; + UInt8 genSrecFile; + UInt8 linkunused; + UInt8 mainname[64]; + UInt8 listclosure; + UInt8 pad_0x49; + SInt16 srecLength; + UInt8 srecEOL; + UInt8 outputformat; +} MIPSLinkerPanelR4; + +typedef struct MIPSLinkerPanelR5 { + SInt16 version; + SInt16 srecLength; + UInt8 listdwarf; + UInt8 symfullpath; + UInt8 linkmap; + UInt8 nolinkwarnings; + UInt8 genSrecFile; + UInt8 linkunused; + UInt8 listclosure; + UInt8 pad1; + UInt8 srecEOL; + UInt8 pad2; + UInt8 nodeadstrip; + UInt8 genelfsymtable; + UInt8 pad3[4]; + UInt8 mainname[64]; + UInt8 forceactivesymbols[256]; +} MIPSLinkerPanelR5; + +typedef struct MIPSProjectR3 { + SInt16 version; + SInt16 projtype; + UInt8 outfile_name_length; + char outfile_name[31]; + SInt32 heapsize; + SInt32 stacksize; + UInt8 bigendian; + UInt8 pad2d; + SInt16 datathreshold; + SInt16 codeModel; + UInt8 gprelative; + UInt8 pcrelative; + UInt8 data16bit; + UInt8 pad35; +} MIPSProjectR3; + +typedef struct MIPSProjectR4 { + SInt16 version; + SInt16 projtype; + UInt8 outfile_name_length; + char outfile_name[31]; + SInt32 heapsize; + SInt32 stacksize; + UInt8 bigendian; + UInt8 pad2d; + SInt16 datathreshold; + SInt16 codeModel; + UInt8 gprelative; + UInt8 pcrelative; + UInt8 data16bit; + UInt8 pad35; +} MIPSProjectR4; + +typedef struct MIPSProjectR5 { + SInt16 version; + SInt16 projtype; + SInt16 datathreshold; + SInt16 codeModel; + UInt8 pad[4]; + SInt32 heapsize; + SInt32 stacksize; + UInt8 bigendian; + UInt8 gprelative; + UInt8 pcrelative; + UInt8 data16bit_leftover; + UInt8 pad2[4]; + UInt8 outfile_name_length; + char outfile_name[31]; +} MIPSProjectR5; + +/* Dummy struct for IR Optimizer request in older DLLs */ +typedef struct PIROptimizerDummy { UInt8 pad[12]; } PIROptimizerDummy; #pragma pack(pop) @@ -369,20 +481,40 @@ typedef struct CWPluginPrivateContext { PWarningC prefsWarnings; PGlobalOptimizer prefsOptimizer; - /* MIPS-specific panels */ - PMIPSCodeGen prefsMIPSCodeGen; - PMIPSLinker prefsMIPSLinker; - PMIPSProject prefsMIPSProject; - UInt8 prefsMIPSCodeGenPanel[sizeof(PMIPSCodeGen)]; - UInt8 prefsMIPSLinkerPanel[sizeof(PMIPSLinker)]; - Boolean prefsMIPSCodeGenR4Compat; + /* Safe scratchpad specifically for MIPS command-line flags */ + struct { + int floatgen; /* -fp */ + int datathreshold; /* -sdata */ + int profiler; /* -profile */ + int readonlystrings; /* -rostr */ + } mips_cmdline; /* PPC EABI-specific panels */ PPCEABICodeGen prefsPPCCodeGen; PPCEABILinker prefsPPCLinker; PPCEABIProject prefsPPCProject; PPreprocessor prefsPreprocessor; - + /* MIPS Binary Output Buffers */ + int mips_version; /* 3, 4, or 5 (0 if PowerPC) */ + union { + struct { + MIPSCodeGenR3 codegen; + MIPSLinkerPanelR3 linker; + MIPSProjectR3 project; + PIROptimizerDummy ir_opt; + } r3; + struct { + MIPSCodeGenR4 codegen; + MIPSLinkerPanelR4 linker; + MIPSProjectR4 project; + PIROptimizerDummy ir_opt; + } r4; + struct { + MIPSCodeGenR5 codegen; + MIPSLinkerPanelR5 linker; + MIPSProjectR5 project; + } r5; + } mips_panels; /* Define/pragma text exposed as a virtual prefix file */ char* defineText; /* accumulated #define/#undef/#pragma/#include lines */ SInt32 defineTextLen; diff --git a/mwccwrap.c b/mwccwrap.c index 726e878..2f0568d 100644 --- a/mwccwrap.c +++ b/mwccwrap.c @@ -162,7 +162,6 @@ static void print_help(void) { " -opt off|on|all|full Optimization level\n" " -opt speed|space Optimization target\n" " -opt level= Set optimization level (0-4)\n" - " -opt [no]intrinsics Inline intrinsic functions\n" " -opt [no]peephole Peephole optimization\n" "\n" "Debug:\n" @@ -343,28 +342,28 @@ static int get_compiler_version_info(const char* dll_path, CompilerVersionInfo* free(info_blob); return found_any; } - -static int should_enable_mips_r4_compat(const CompilerVersionInfo* info) { - unsigned int major, minor, patch, build; - - if (!info || !info->has_fixed_version) return 0; - - major = (unsigned int)HIWORD(info->version_ms); - minor = (unsigned int)LOWORD(info->version_ms); - patch = (unsigned int)HIWORD(info->version_ls); - build = (unsigned int)LOWORD(info->version_ls); - - if (!(major == 2 && minor == 44 && patch == 14 && build == 0)) return 0; - - if (info->file_description[0] && - _stricmp(info->file_description, "MIPS Compiler for PlayStation") != 0) - { - return 0; +/* + * Zero-I/O MIPS Version Detection using Opcode Fingerprinting. + * Reads the instruction bytes exactly 16 bytes deep into PluginMain + * to uniquely identify the CodeWarrior compiler version. + */ +static int detect_mips_version(void* plugin_main_ptr) { + unsigned int* p; + + if (!plugin_main_ptr) return 0; + + p = (unsigned int*)plugin_main_ptr; + + /* Check the opcode block at offset 0x10 (p[4]) */ + switch (p[4]) { + case 0x0025389F: return 30; /* R3 */ + case 0x0025AF26: return 40; /* R4 */ + case 0x885550D2: return 41; /* R4.1 */ + case 0x89000000: return 50; /* R5.0 */ + case 0xDEF0E855: return 52; /* R5.2 */ + default: return 0; /* Unknown or PowerPC */ } - - return 1; } - static void format_version_line(const CompilerVersionInfo* info, char* out, size_t out_size) { unsigned int major, minor, patch, build; @@ -713,86 +712,78 @@ static int set_ppc_alignment(PPCEABICodeGen* ppc, const char* value) { return 0; } -static int apply_ppc_string_option(PFrontEndC* fe, PPCEABICodeGen* ppc, const char* token) { - if (!fe || !ppc || !token || !token[0]) return 0; +static int apply_string_option(CWPluginContext ctx, const char* token) { + if (!ctx || !token || !token[0]) return 0; if (_stricmp(token, "reuse") == 0) { - fe->dontreusestrings = 0; + ctx->prefsFrontEnd.dontreusestrings = 0; return 1; } if (_stricmp(token, "noreuse") == 0) { - fe->dontreusestrings = 1; + ctx->prefsFrontEnd.dontreusestrings = 1; return 1; } if (_stricmp(token, "pool") == 0) { - fe->poolstrings = 1; + ctx->prefsFrontEnd.poolstrings = 1; return 1; } if (_stricmp(token, "nopool") == 0) { - fe->poolstrings = 0; + ctx->prefsFrontEnd.poolstrings = 0; return 1; } if (_stricmp(token, "readonly") == 0) { - ppc->readonlystrings = 1; + ctx->prefsPPCCodeGen.readonlystrings = 1; + ctx->mips_cmdline.readonlystrings = 1; return 1; } if (_stricmp(token, "noreadonly") == 0) { - ppc->readonlystrings = 0; + ctx->prefsPPCCodeGen.readonlystrings = 0; + ctx->mips_cmdline.readonlystrings = 0; return 1; } return 0; } -static void apply_dash_o_token(const char* token, - PGlobalOptimizer* opt, - PMIPSCodeGen* mips, - PPCEABICodeGen* ppc, - int* handled) +static void apply_dash_o_token(const char* token, CWPluginContext ctx, int* handled) { if (!token || !token[0]) return; if (strcmp(token, "0") == 0) { - opt->optimizationlevel = 0; + ctx->prefsOptimizer.optimizationlevel = 0; return; } if (strcmp(token, "1") == 0) { - opt->optimizationlevel = 1; + ctx->prefsOptimizer.optimizationlevel = 1; return; } if (strcmp(token, "2") == 0) { - opt->optimizationlevel = 2; - mips->peephole = 1; - ppc->peephole = 1; + ctx->prefsOptimizer.optimizationlevel = 2; + ctx->prefsPPCCodeGen.peephole = 1; return; } if (strcmp(token, "3") == 0) { - opt->optimizationlevel = 3; - mips->peephole = 1; - ppc->peephole = 1; + ctx->prefsOptimizer.optimizationlevel = 3; + ctx->prefsPPCCodeGen.peephole = 1; return; } if (strcmp(token, "4") == 0) { - opt->optimizationlevel = 4; - mips->peephole = 1; - ppc->peephole = 1; - ppc->scheduling = 1; + ctx->prefsOptimizer.optimizationlevel = 4; + ctx->prefsPPCCodeGen.peephole = 1; + ctx->prefsPPCCodeGen.scheduling = 1; return; } if (strcmp(token, "p") == 0) { - opt->optfor = 2; + ctx->prefsOptimizer.optfor = 1; /* 1 = Speed */ return; } if (strcmp(token, "s") == 0) { - opt->optfor = 1; + ctx->prefsOptimizer.optfor = 2; /* 2 = Space */ return; } if (handled) *handled = 0; } -static int parse_dash_o_option(const char* arg, - PGlobalOptimizer* opt, - PMIPSCodeGen* mips, - PPCEABICodeGen* ppc) +static int parse_dash_o_option(const char* arg, CWPluginContext ctx) { const char* spec; int handled = 1; @@ -801,7 +792,7 @@ static int parse_dash_o_option(const char* arg, spec = arg + 2; if (!spec[0]) { - apply_dash_o_token("2", opt, mips, ppc, &handled); + apply_dash_o_token("2", ctx, &handled); return handled; } @@ -815,84 +806,68 @@ static int parse_dash_o_option(const char* arg, char* tok = strtok(tmp, ","); while (tok) { if (tok[0]) { - apply_dash_o_token(tok, opt, mips, ppc, &handled); + apply_dash_o_token(tok, ctx, &handled); } tok = strtok(NULL, ","); } return handled; } - apply_dash_o_token(spec, opt, mips, ppc, &handled); + apply_dash_o_token(spec, ctx, &handled); return handled; } -static int apply_opt_keyword(const char* token, - PGlobalOptimizer* opt, - PMIPSCodeGen* mips, - PPCEABICodeGen* ppc) +static int apply_opt_keyword(const char* token, CWPluginContext ctx) { if (!token || !token[0]) return 0; if (strcmp(token, "off") == 0 || strcmp(token, "none") == 0) { - opt->optimizationlevel = 0; + ctx->prefsOptimizer.optimizationlevel = 0; return 1; } if (strcmp(token, "on") == 0) { - opt->optimizationlevel = 2; - mips->peephole = 1; - ppc->peephole = 1; + ctx->prefsOptimizer.optimizationlevel = 2; + ctx->prefsPPCCodeGen.peephole = 1; return 1; } if (strcmp(token, "all") == 0 || strcmp(token, "full") == 0) { - opt->optimizationlevel = 4; - opt->optfor = 1; - mips->useIntrinsics = 1; - mips->peephole = 1; - ppc->peephole = 1; - ppc->scheduling = 1; + ctx->prefsOptimizer.optimizationlevel = 4; + ctx->prefsOptimizer.optfor = 1; + ctx->prefsPPCCodeGen.peephole = 1; + ctx->prefsPPCCodeGen.scheduling = 1; return 1; } if (strcmp(token, "speed") == 0) { - opt->optfor = 2; + ctx->prefsOptimizer.optfor = 2; /* 2 = Speed */ return 1; } if (strcmp(token, "space") == 0 || strcmp(token, "size") == 0) { - opt->optfor = 1; + ctx->prefsOptimizer.optfor = 1; /* 1 = Space */ return 1; } if (strncmp(token, "level=", 6) == 0 || strncmp(token, "l=", 2) == 0) { const char* num = strchr(token, '=') + 1; int lv = atoi(num); if (lv >= 0 && lv <= 4) { - opt->optimizationlevel = (UInt8)lv; + ctx->prefsOptimizer.optimizationlevel = (UInt8)lv; return 1; } return 0; } - if (strcmp(token, "intrinsics") == 0) { - mips->useIntrinsics = 1; - return 1; - } - if (strcmp(token, "nointrinsics") == 0) { - mips->useIntrinsics = 0; - return 1; - } if (strcmp(token, "peephole") == 0 || strcmp(token, "peep") == 0) { - mips->peephole = 1; - ppc->peephole = 1; + ctx->prefsPPCCodeGen.peephole = 1; return 1; } if (strcmp(token, "nopeephole") == 0 || strcmp(token, "nopeep") == 0) { - mips->peephole = 0; - ppc->peephole = 0; + ctx->prefsPPCCodeGen.peephole = 0; return 1; } if (strcmp(token, "schedule") == 0) { - ppc->scheduling = 1; + ctx->prefsPPCCodeGen.scheduling = 1; return 1; } if (strcmp(token, "noschedule") == 0) { - ppc->scheduling = 0; + ctx->prefsPPCCodeGen.scheduling = 0; return 1; } return 0; @@ -1314,11 +1289,9 @@ static void init_pref_defaults(CWPluginContext ctx) { memset(&ctx->prefsOptimizer, 0, sizeof(PGlobalOptimizer)); /* ---- MIPS-specific panels ---- */ - memset(&ctx->prefsMIPSCodeGen, 0, sizeof(PMIPSCodeGen)); - ctx->prefsMIPSCodeGen.fpuType = 1; /* -fp single (default) */ - - memset(&ctx->prefsMIPSLinker, 0, sizeof(PMIPSLinker)); - memset(&ctx->prefsMIPSProject, 0, sizeof(PMIPSProject)); + memset(&ctx->mips_cmdline, 0, sizeof(ctx->mips_cmdline)); + memset(&ctx->mips_panels, 0, sizeof(ctx->mips_panels)); + ctx->mips_cmdline.datathreshold = 8; /* -sdata 8 (default) */ /* ---- PPC EABI-specific panels ---- */ memset(&ctx->prefsPPCCodeGen, 0, sizeof(PPCEABICodeGen)); @@ -1404,8 +1377,6 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, { PFrontEndC* fe = &ctx->prefsFrontEnd; PWarningC* warn = &ctx->prefsWarnings; - PGlobalOptimizer* opt = &ctx->prefsOptimizer; - PMIPSCodeGen* cg = &ctx->prefsMIPSCodeGen; PPCEABICodeGen* ppc = &ctx->prefsPPCCodeGen; const char* arg_val; @@ -1717,16 +1688,17 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, tok; tok = strtok(NULL, ",")) { - if (!apply_ppc_string_option(fe, ppc, tok)) { + if (!apply_string_option(ctx, tok)) { fprintf(stderr, "warning: unknown -str value: %s\n", tok); } } - } else if (!apply_ppc_string_option(fe, ppc, arg_val)) { + } else if (!apply_string_option(ctx, arg_val)) { fprintf(stderr, "warning: unknown -str value: %s\n", arg_val); } } else if (strcmp(arg, "-rostr") == 0 || strcmp(arg, "-readonlystrings") == 0) { /* Deprecated alias for -str readonly. Does not imply [no]reuse. */ + ctx->mips_cmdline.readonlystrings = 1; ppc->readonlystrings = 1; } else if (strcmp(arg, "-multibyte") == 0 || strcmp(arg, "-multibyteaware") == 0) { @@ -1872,7 +1844,7 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, /* --- Optimizer --- */ else if (arg[0] == '-' && arg[1] == 'O') { - if (!parse_dash_o_option(arg, opt, cg, ppc)) { + if (!parse_dash_o_option(arg, ctx)) { fprintf(stderr, "warning: unknown -O option: %s\n", arg); } } @@ -1888,11 +1860,11 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, tok; tok = strtok(NULL, ",")) { - if (!apply_opt_keyword(tok, opt, cg, ppc)) { + if (!apply_opt_keyword(tok, ctx)) { fprintf(stderr, "warning: unknown -opt value: %s\n", tok); } } - } else if (!apply_opt_keyword(arg_val, opt, cg, ppc)) { + } else if (!apply_opt_keyword(arg_val, ctx)) { fprintf(stderr, "warning: unknown -opt value: %s\n", arg_val); } } @@ -1901,13 +1873,15 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, else if (strcmp(arg, "-fp") == 0) { NEXT_ARG(arg_val); if (_stricmp(arg_val, "off") == 0 || _stricmp(arg_val, "none") == 0) { - cg->fpuType = 0; + ctx->mips_cmdline.floatgen = 0; ppc->floatingpoint = 0; } else if (_stricmp(arg_val, "single") == 0) { - cg->fpuType = 1; + ctx->mips_cmdline.floatgen = 1; } else if (_stricmp(arg_val, "soft") == 0 || _stricmp(arg_val, "software") == 0) { + ctx->mips_cmdline.floatgen = 0; ppc->floatingpoint = 1; } else if (_stricmp(arg_val, "hard") == 0 || _stricmp(arg_val, "hardware") == 0) { + ctx->mips_cmdline.floatgen = 1; ppc->floatingpoint = 2; } else if (_stricmp(arg_val, "fmadd") == 0) { ppc->floatingpoint = 2; @@ -1948,7 +1922,9 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, strcmp(arg, "-sdata") == 0 || strcmp(arg, "-sdatathreshold") == 0) { NEXT_ARG(arg_val); - ctx->prefsPPCProject.datathreshold = (SInt16)atoi(arg_val); + SInt16 threshold = (SInt16)atoi(arg_val); + ctx->prefsPPCProject.datathreshold = threshold; + ctx->mips_cmdline.datathreshold = threshold; } else if (strcmp(arg, "-sdata2") == 0 || strcmp(arg, "-sdata2threshold") == 0) { @@ -2014,7 +1990,8 @@ static int parse_args(int argc, char* argv[], CWPluginContext ctx, } } else if (strcmp(arg, "-profile") == 0) { - /* profiler - stored but cc_mips.dll may not use it for PS1 */ + /* profiler */ + ctx->mips_cmdline.profiler = 1; ppc->profiler = 1; } else if (strcmp(arg, "-farcall") == 0) { @@ -2255,12 +2232,8 @@ int main(int argc, char* argv[]) { copy_cstr(loaded_dll_name, sizeof(loaded_dll_name), loaded_dll_path); } - has_active_version_info = get_compiler_version_info(loaded_dll_path, &active_version_info); - ctx.prefsMIPSCodeGenR4Compat = - has_active_version_info ? should_enable_mips_r4_compat(&active_version_info) : FALSE; - if (ctx.verbose && ctx.prefsMIPSCodeGenR4Compat) { - fprintf(stderr, "Enabled prefsMIPSCodeGenR4Compat based on compiler version metadata.\n"); - } + /* Initialize to 0. It will be properly detected later when PluginMain is found. */ + ctx.mips_version = 0; if (g_registered_pluginlib_version == 2) { plugin_api_version = 8; @@ -2303,6 +2276,16 @@ int main(int argc, char* argv[]) { if (ctx.verbose) fprintf(stderr, "Found plugin main at %p\n", (void*)plugin_main); + /* LATE DETECTION: Reuse the pointer mwccwrap already found */ + ctx.mips_version = detect_mips_version((void*)plugin_main); + + if (ctx.verbose) { + if (ctx.mips_version > 0) { + fprintf(stderr, "Detected MIPS Compiler Version Scale: %d\n", ctx.mips_version); + } else { + fprintf(stderr, "Detected PowerPC/Legacy Compiler Mode.\n"); + } + } ctx.apiVersion = plugin_api_version; ctx.numFiles = num_sources; @@ -2529,4 +2512,4 @@ int main(int argc, char* argv[]) { if (ctx.defineText) free(ctx.defineText); return (ctx.numErrors > 0 || had_compile_failure) ? 1 : 0; -} +} \ No newline at end of file diff --git a/pluginlib.c b/pluginlib.c index 2b6817a..f91dab2 100644 --- a/pluginlib.c +++ b/pluginlib.c @@ -1019,48 +1019,131 @@ CW_CALLBACK CWFreeObjectData(CWPluginContext ctx, SInt32 whichfile, CWMemHandle return CWFreeMemHandle(ctx, objectdata); } -/* ============================================================ - * Preferences - * ============================================================ */ - -static void build_mips_codegen_panel(CWPluginContext ctx) { - memcpy(ctx->prefsMIPSCodeGenPanel, - &ctx->prefsMIPSCodeGen, - sizeof(ctx->prefsMIPSCodeGenPanel)); +static CWResult MIPS_GetPreferences(CWPluginContext ctx, const char* prefsname, void** prefsdata) { + const void* prefs = NULL; + SInt32 prefsSize = 0; - if (ctx->prefsMIPSCodeGenR4Compat) { - /* - * R4 reads PMIPSCodeGen with a different layout than R5/R5.2. - * Keep a 20-byte panel, but patch overlapping bytes so both - * layouts see sensible values. + if (strcmp(prefsname, "C/C++ Compiler") == 0) { + prefs = &ctx->prefsFrontEnd; + prefsSize = sizeof(ctx->prefsFrontEnd); + if (ctx->mips_version >= 52) ctx->prefsFrontEnd.version = 13; + else if (ctx->mips_version >= 40) ctx->prefsFrontEnd.version = 12; + else ctx->prefsFrontEnd.version = 9; + } + else if (strcmp(prefsname, "C/C++ Warnings") == 0) { + prefs = &ctx->prefsWarnings; + prefsSize = sizeof(ctx->prefsWarnings); + if (ctx->mips_version >= 52) ctx->prefsWarnings.version = 5; + else if (ctx->mips_version >= 40) ctx->prefsWarnings.version = 4; + else ctx->prefsWarnings.version = 3; + } + else if (strcmp(prefsname, "PS Global Optimizer") == 0) { + + ctx->prefsOptimizer.version = 1; + + /* Parser gives us: 1=Space, 2=Speed, 0=Default. + * MIPS DLL wants: 1=Space, 0=Speed. + * Default to Space (1) unless Speed (2) was explicitly requested. */ - ctx->prefsMIPSCodeGenPanel[0x04] = (UInt8)(ctx->prefsMIPSCodeGen.processor & 0xFF); - ctx->prefsMIPSCodeGenPanel[0x05] = 0; - ctx->prefsMIPSCodeGenPanel[0x06] = (UInt8)(ctx->prefsMIPSCodeGen.fpuType & 0xFF); - ctx->prefsMIPSCodeGenPanel[0x07] = (ctx->prefsMIPSCodeGen.fpuType != 0) ? 1 : 0; - ctx->prefsMIPSCodeGenPanel[0x0C] = ctx->prefsMIPSCodeGen.useIntrinsics; + ctx->prefsOptimizer.optfor = (ctx->prefsOptimizer.optfor == 2) ? 0 : 1; + + prefs = &ctx->prefsOptimizer; + prefsSize = sizeof(PGlobalOptimizer); + } + else if (strcmp(prefsname, "MIPS Project") == 0) { + if (ctx->mips_version >= 50) { + MIPSProjectR5* p = &ctx->mips_panels.r5.project; + p->version = 3; + p->datathreshold = ctx->mips_cmdline.datathreshold; + // "Absolute Addressing" Code Model + p->codeModel = 1; + prefs = p; + prefsSize = sizeof(MIPSProjectR5); + } else { + MIPSProjectR4* p = &ctx->mips_panels.r4.project; + p->version = 2; + p->datathreshold = ctx->mips_cmdline.datathreshold; + // "Absolute Addressing" Code Model + p->codeModel = 1; + prefs = p; + prefsSize = sizeof(MIPSProjectR4); + } + } + else if (strcmp(prefsname, "MIPS CodeGen") == 0) { + if (ctx->mips_version >= 50) { + MIPSCodeGenR5* p = &ctx->mips_panels.r5.codegen; + p->version = 7; + p->optimizationlevel = ctx->prefsOptimizer.optimizationlevel; + p->readonlystrings = ctx->mips_cmdline.readonlystrings; + p->profiler = ctx->mips_cmdline.profiler; + // always set + p->pad_08 = 1; + prefs = p; + prefsSize = sizeof(MIPSCodeGenR5); + } else if (ctx->mips_version >= 40) { + MIPSCodeGenR4* p = &ctx->mips_panels.r4.codegen; + p->version = 5; + p->optimizationlevel = ctx->prefsOptimizer.optimizationlevel; + p->readonlystrings = ctx->mips_cmdline.readonlystrings; + p->profiler = ctx->mips_cmdline.profiler; + // always set + p->pad_08 = 1; + prefs = p; + prefsSize = sizeof(MIPSCodeGenR4); + } else { + MIPSCodeGenR3* p = &ctx->mips_panels.r3.codegen; + p->version = 2; + p->optimizationlevel = ctx->prefsOptimizer.optimizationlevel; + p->floatgen = ctx->mips_cmdline.floatgen; + p->readonlystrings = ctx->mips_cmdline.readonlystrings; + // TODO: possibly implement setting ISA Level, as the IDE lets you + prefs = p; + prefsSize = sizeof(MIPSCodeGenR3); + } + } + else if (strcmp(prefsname, "MIPS Linker Panel") == 0) { + if (ctx->mips_version >= 50) { + MIPSLinkerPanelR5* p = &ctx->mips_panels.r5.linker; + p->version = 6; + //p->symfullpath = 1; + prefs = p; + prefsSize = sizeof(MIPSLinkerPanelR5); + } else if (ctx->mips_version >= 40) { + MIPSLinkerPanelR4* p = &ctx->mips_panels.r4.linker; + p->version = 4; + //p->symfullpath = 1; + prefs = p; + prefsSize = sizeof(MIPSLinkerPanelR4); + } else { + MIPSLinkerPanelR3* p = &ctx->mips_panels.r3.linker; + p->version = 2; + // in R3, passing -g with symfullpath = 1 causes a crash + //p->symfullpath = 1; + prefs = p; + prefsSize = sizeof(MIPSLinkerPanelR3); + } + } + else if (strcmp(prefsname, "IR Optimizer") == 0) { + prefs = &ctx->mips_panels.r3.ir_opt; + prefsSize = sizeof(PIROptimizerDummy); + } + else { + LOG(" Unknown MIPS preference panel: %s", prefsname); + prefsSize = 256; } -} - -static void build_mips_linker_panel(CWPluginContext ctx) { - memcpy(ctx->prefsMIPSLinkerPanel, - &ctx->prefsMIPSLinker, - sizeof(ctx->prefsMIPSLinkerPanel)); - /* - * R4 reads genOutput at 0x03, R5/R5.2 reads 0x05. - * Mirror to both offsets to avoid version branching. - */ - ctx->prefsMIPSLinkerPanel[0x03] = ctx->prefsMIPSLinker.genOutput; - ctx->prefsMIPSLinkerPanel[0x05] = ctx->prefsMIPSLinker.genOutput; + CWAllocMemHandle(ctx, prefsSize, FALSE, (CWMemHandle*)prefsdata); + if (prefs && prefsSize > 0) { + void* ptr = NULL; + CWLockMemHandle(ctx, *(CWMemHandle*)prefsdata, FALSE, &ptr); + if (ptr) memcpy(ptr, prefs, (size_t)prefsSize); + CWUnlockMemHandle(ctx, *(CWMemHandle*)prefsdata); + } + return cwNoErr; } -CW_CALLBACK CWSecretGetNamedPreferences(CWPluginContext ctx, - const char* prefsname, void** prefsdata) -{ - LOG("CWSecretGetNamedPreferences(\"%s\", %p)", prefsname ? prefsname : "NULL", prefsdata); - if (!ctx || !prefsname || !prefsdata) return cwErrInvalidParameter; - +/* Original PowerPC / Legacy layout mapping */ +static CWResult PPC_GetPreferences(CWPluginContext ctx, const char* prefsname, void** prefsdata) { const void* prefs = NULL; SInt32 prefsSize = 0; if (strcmp(prefsname, "C/C++ Compiler") == 0) { @@ -1074,23 +1157,7 @@ CW_CALLBACK CWSecretGetNamedPreferences(CWPluginContext ctx, strcmp(prefsname, "EPPC Global Optimizer") == 0) { prefs = &ctx->prefsOptimizer; prefsSize = sizeof(ctx->prefsOptimizer); - } else if (strcmp(prefsname, "MIPS CodeGen") == 0) { - build_mips_codegen_panel(ctx); - prefs = ctx->prefsMIPSCodeGenPanel; - prefsSize = sizeof(ctx->prefsMIPSCodeGenPanel); - } else if (strcmp(prefsname, "MIPS Linker Panel") == 0) { - build_mips_linker_panel(ctx); - prefs = ctx->prefsMIPSLinkerPanel; - prefsSize = sizeof(ctx->prefsMIPSLinkerPanel); - } else if (strcmp(prefsname, "MIPS Project") == 0) { - prefs = &ctx->prefsMIPSProject; - prefsSize = sizeof(ctx->prefsMIPSProject); - } else if (strcmp(prefsname, "IR Optimizer") == 0) { - /* CW PS R4/R4.1 vestigial panel: data never read, just return zeros */ - prefsSize = 12; - } - /* ---- PPC EABI panels (GC/Wii target) ---- */ - else if (strcmp(prefsname, "PPC EABI CodeGen") == 0) { + } else if (strcmp(prefsname, "PPC EABI CodeGen") == 0) { prefs = &ctx->prefsPPCCodeGen; prefsSize = sizeof(ctx->prefsPPCCodeGen); } else if (strcmp(prefsname, "PPC EABI Linker") == 0) { @@ -1120,6 +1187,19 @@ CW_CALLBACK CWSecretGetNamedPreferences(CWPluginContext ctx, return cwNoErr; } +CW_CALLBACK CWSecretGetNamedPreferences(CWPluginContext ctx, + const char* prefsname, void** prefsdata) +{ + LOG("CWSecretGetNamedPreferences(\"%s\", %p)", prefsname ? prefsname : "NULL", prefsdata); + if (!ctx || !prefsname || !prefsdata) return cwErrInvalidParameter; + + if (ctx->mips_version > 0) { + return MIPS_GetPreferences(ctx, prefsname, prefsdata); + } else { + return PPC_GetPreferences(ctx, prefsname, prefsdata); + } +} + CW_CALLBACK CWGetNamedPreferences(CWPluginContext ctx, const char* prefsname, CWMemHandle* prefsdata) { LOG("CWGetNamedPreferences(\"%s\", %p)", prefsname ? prefsname : "NULL", prefsdata); return CWSecretGetNamedPreferences(ctx, prefsname, (void**)prefsdata); From 701b7a28bd7b8ab8a601731f5093a59b49192448 Mon Sep 17 00:00:00 2001 From: ThirstyWraith <93416469+ThirstyWraith@users.noreply.github.com> Date: Sun, 22 Mar 2026 19:41:07 +0100 Subject: [PATCH 2/2] fix inconsistency with speed/space value --- mwccwrap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mwccwrap.c b/mwccwrap.c index 2f0568d..f6b0508 100644 --- a/mwccwrap.c +++ b/mwccwrap.c @@ -773,11 +773,11 @@ static void apply_dash_o_token(const char* token, CWPluginContext ctx, int* hand return; } if (strcmp(token, "p") == 0) { - ctx->prefsOptimizer.optfor = 1; /* 1 = Speed */ + ctx->prefsOptimizer.optfor = 2; return; } if (strcmp(token, "s") == 0) { - ctx->prefsOptimizer.optfor = 2; /* 2 = Space */ + ctx->prefsOptimizer.optfor = 1; return; } if (handled) *handled = 0; @@ -838,11 +838,11 @@ static int apply_opt_keyword(const char* token, CWPluginContext ctx) return 1; } if (strcmp(token, "speed") == 0) { - ctx->prefsOptimizer.optfor = 2; /* 2 = Speed */ + ctx->prefsOptimizer.optfor = 2; return 1; } if (strcmp(token, "space") == 0 || strcmp(token, "size") == 0) { - ctx->prefsOptimizer.optfor = 1; /* 1 = Space */ + ctx->prefsOptimizer.optfor = 1; return 1; } if (strncmp(token, "level=", 6) == 0 || strncmp(token, "l=", 2) == 0) {