{"id":21407278,"url":"https://github.com/mkst/maspsx","last_synced_at":"2025-10-26T05:40:38.387Z","repository":{"id":177627651,"uuid":"654572321","full_name":"mkst/maspsx","owner":"mkst","description":null,"archived":false,"fork":false,"pushed_at":"2024-09-16T07:07:11.000Z","size":125,"stargazers_count":4,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-09-16T08:28:01.693Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkst.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-16T12:25:51.000Z","updated_at":"2024-09-16T07:07:15.000Z","dependencies_parsed_at":"2023-10-31T22:29:10.008Z","dependency_job_id":"ded64b09-d30e-4650-bb50-cebbd210eaa4","html_url":"https://github.com/mkst/maspsx","commit_stats":null,"previous_names":["mkst/maspsx"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkst%2Fmaspsx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkst%2Fmaspsx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkst%2Fmaspsx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkst%2Fmaspsx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkst","download_url":"https://codeload.github.com/mkst/maspsx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225934012,"owners_count":17547728,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-22T16:45:53.783Z","updated_at":"2025-10-26T05:40:38.382Z","avatar_url":"https://github.com/mkst.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# maspsx AKA \"Modern ASPSX\"\n\nThe goal of `maspsx` is to facilitate the replacement of the combination of `ASPSX.EXE` + [psyq-obj-parser](https://github.com/grumpycoders/pcsx-redux/tree/main/tools/psyq-obj-parser) when attempting to generate byte-perfect ELF objects.\n\n`maspsx` takes the assembly code output of `gcc` and massages it such that it can be assembled via GNU `as` to the equivalent object as what the original PSYQ SDK would create.\n\n`ASPSX` does not appear to do very much in terms of code *optimisation*, therefore the belief is that this will be a straightforward process.\n\nThere are a number of reasons why using `maspsx` with GNU `as` is preferable to the original toolchain:\n - No need to run 16-bit DOS or 32-bit Windows applications\n   - Native, vanilla, [gcc](https://github.com/decompals/old-gcc) versions make `dosemu2` and `wine` unnecessary.\n - Decomp tooling expects ELF objects\n - Support for line numbers in diff!\n   - Pass `-gcoff` to gcc to get line numbers in [asm-differ](https://github.com/simonlindholm/asm-differ)\n\n\n## Usage\n\n`maspsx` supports the following arguments:\n\n### `--aspsx-version`\n**EXPERIMENTAL** There are slight nuances in behaviour across `ASPSX` versions. In order to emulate the correct behaviour, pass the `ASPSX` version to `maspsx`, e.g. `--aspsx-version=2.78`.\n\n### `--run-assembler`\nThe default behaviour of `maspsx` is to write the output to stdout, by passing `--run-assembler`, `maspsx` will run `mipsel-linux-gnu-as` directly.\n\n### `--gnu-as-path`\nIf `mipsel-linux-gnu-as` isn't on your path, or you want to use a different assembler (e.g. `mips-linux-gnu-as`), specify the **full path** here.\n\n### `--dont-force-G0`\nCurrent understanding is that `-G0` needs to be passed to GNU `as` in order to get correct behaviour. If you need to pass a non-zero value for `-G` to the GNU assembler, use this flag.\n\n### `--expand-div`\nIf you need `maspsx` to expand `div/divu` and `rem/remu` ops, pass `--expand-div` to `maspsx`. There is already handling for partial div expansion (i.e. where `-0` was passed to `ASPSX.EXE`).\n\n### `--macro-inc`\nGet `maspsx` to add an `include \"macro.inc\"` statement to the output.\n\n### `--use-comm-section`\nPut any common symbols (in C, this means non-`static` global variables without an initializer) in the `.comm` section (which is the default ccpsx behaviour).\n\n### `--use-comm-for-lcomm`\nAlso put `.lcomm`-declared symbols (in C, this means `static` variables without an initializer) in the `.comm` section.\nThis can be convenient with games using non-zero `-G` in situations where a variable needs to be marked `static` to get code generation to match, but you don't want to migrate `.sdata`/`.sbss` to that .c file yet.\n**NOTE:** This also makes the symbols *global* (unlike regular `static` behaviour).\n\n### `-G`\n**EXPERIMENTAL** If your project uses `$gp`, maspsx needs to be explicitly passed a non-zero value for `-G`.\n\n\n## Known Differences\n\n| Behavior / Version            | 1.05/1.07      | 2.05/2.08      | 2.21          | 2.30/2.34      | 2.56           | 2.67           | 2.77/2.79      | 2.81/2.86      |\n|:------------------------------|:--------------:|:--------------:|:-------------:|:--------------:|:--------------:|:--------------:|:--------------:|:--------------:|\n| div uses tge not break        | :white_circle: | :green_circle: |:white_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: |\n| add nop before $at expansion  | :green_circle: | :green_circle: |:green_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: |\n| use addiu in $at expansion    | :green_circle: | :green_circle: |:green_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: |\n| li 1 expands to ori 1         | :green_circle: | :green_circle: |:green_circle: | :green_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: |\n| use $at for sltu \u003c 0          | :green_circle: | :green_circle: |:green_circle: | :green_circle: | :green_circle: | :green_circle: | :white_circle: | :white_circle: |\n| supports `-0` argument        | :white_circle: | :white_circle: |:white_circle: | :green_circle: | :green_circle: | :green_circle: | :green_circle: | :green_circle: |\n| mflo+mfhi / mult+div inst gap | :white_circle: | :white_circle: |:white_circle: | :green_circle: | :green_circle: | :green_circle: | :green_circle: | :green_circle: |\n| support for %hi/%lo macros    | :white_circle: | :white_circle: |:white_circle: | :white_circle: | :white_circle: | :green_circle: | :green_circle: | :green_circle: |\n| use $gp for symbol+offset     | :white_circle: | :white_circle: |:white_circle: | :white_circle: | :white_circle: | :white_circle: | :green_circle: | :green_circle: |\n| use $gp for la                | :white_circle: | :white_circle: |:white_circle: | :white_circle: | :white_circle: | :white_circle: | :white_circle: | :green_circle: |\n\n\n## `INCLUDE_ASM` reordering workaround hack\n\nWhenever compiling with non-zero `-G` value, some versions of `gcc` reorder all functions to appear *after* data definitions in the output assembly. Unfortunately, this also causes functions to be placed *after* `__asm__` statements, thus breaking the usual implementation of the `INCLUDE_ASM` macro.\n\nThis can be worked around with maspsx by wrapping each `__asm__` statement in a function whose name starts with `__maspsx_include_asm_hack`, and appending `# maspsx-keep` to each line of the `__asm__` statement. Thus a working version of `INCLUDE_ASM` would look like:\n````\n#define INCLUDE_ASM(FOLDER, NAME) \\\n    void __maspsx_include_asm_hack_##NAME() { \\\n        __asm__( \\\n            \".text # maspsx-keep \\n\" \\\n            \"\\t.align\\t2 # maspsx-keep\\n\" \\\n            \"\\t.set noreorder # maspsx-keep\\n\" \\\n            \"\\t.set noat # maspsx-keep\\n\" \\\n            \".include \\\"\"FOLDER\"/\"#NAME\".s\\\" # maspsx-keep\\n\" \\\n            \"\\t.set reorder # maspsx-keep\\n\" \\\n            \"\\t.set at # maspsx-keep\\n\" \\\n        ); \\\n    }\n````\n\n## Examples\n\nProjects that use `maspsx` include:\n  - [Castlevania: Symphony of the Night Decompilation](https://github.com/Xeeynamo/sotn-decomp)\n  - [open-ribbon](https://github.com/open-ribbon/open-ribbon)\n  - [Evo's Space Adventures](https://github.com/mkst/esa)\n  - [Croc: Legend of the Gobbos](https://github.com/Xeeynamo/croc)\n  - [Legacy of Kain: Soul Reaver](https://github.com/FedericoMilesi/soul-re)\n  - [Silent Hill](https://github.com/Vatuu/silent-hill-decomp)\n  - [Rayman 1](https://github.com/fuerchter/rayman-ps1-decomp)\n  - [Spyro The Dragon](https://github.com/TheMobyCollective/spyro-1)\n  - [MediEvil 1](https://github.com/MediEvilDecompilation/medievil-decomp)\n\n\n## Bugs\n\nThis project is a work-in-progress. If you encounter scenarios where `maspsx` output differs from the original PSYQ toolchain please create a [GitHub Issue](https://github.com/mkst/maspsx/issues/new) - ideally with a link to a [decomp.me](https://decomp.me/) scratch that demonstrates the problem.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkst%2Fmaspsx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkst%2Fmaspsx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkst%2Fmaspsx/lists"}