├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── UPDATER.BAT ├── UPDATER.SH ├── docs ├── 1_introduction.md ├── 2_developing.md ├── 3_debugging.md └── 4_notes.md ├── games ├── Example_CrashTeamRacing │ ├── build │ │ └── .gitignore │ ├── config.json │ ├── disc.json │ ├── include │ │ └── common.h │ ├── mods │ │ ├── DecompUnitTester │ │ │ ├── MOD.BAT │ │ │ ├── README.md │ │ │ ├── buildList.txt │ │ │ ├── newtex │ │ │ │ └── .gitignore │ │ │ └── src │ │ │ │ ├── hook.s │ │ │ │ ├── main.c │ │ │ │ ├── math.c │ │ │ │ └── math.h │ │ ├── HelloWorld │ │ │ ├── MOD.BAT │ │ │ ├── buildList.txt │ │ │ ├── newtex │ │ │ │ └── .gitignore │ │ │ └── src │ │ │ │ ├── hello.c │ │ │ │ └── hook.s │ │ ├── PluginTest │ │ │ ├── MOD.BAT │ │ │ ├── assets │ │ │ │ └── title01_usa.tim │ │ │ └── buildList.txt │ │ ├── RemapController │ │ │ ├── MOD.BAT │ │ │ ├── buildList.txt │ │ │ ├── newtex │ │ │ │ └── .gitignore │ │ │ └── src │ │ │ │ ├── hook.s │ │ │ │ └── main.c │ │ └── TextureReplacement │ │ │ ├── MOD.BAT │ │ │ ├── buildList.txt │ │ │ ├── newtex │ │ │ └── SPYRO_368_216_1_251_44_26_4.png │ │ │ └── src │ │ │ └── .gitignore │ ├── plugins │ │ └── plugin.py │ └── symbols │ │ ├── addrs-j.txt │ │ ├── addrs-pal.txt │ │ ├── addrs-u.txt │ │ ├── funcs-j.txt │ │ ├── funcs-pal.txt │ │ └── funcs-u.txt ├── Example_MegaManX4 │ ├── config.json │ ├── disc.json │ ├── include │ │ ├── common.h │ │ ├── gpu.h │ │ ├── layer.h │ │ ├── misc.h │ │ └── object.h │ ├── mods │ │ └── DebugTools │ │ │ ├── LOAD_U.ARC │ │ │ ├── LOAD_U.BMP │ │ │ ├── MOD.BAT │ │ │ ├── buildlist.txt │ │ │ ├── define.mk │ │ │ ├── fileList.txt │ │ │ └── src │ │ │ ├── background.c │ │ │ ├── debugfont │ │ │ ├── font.c │ │ │ ├── font2.c │ │ │ ├── loadfont.s │ │ │ └── texthook.s │ │ │ ├── debugmenu.c │ │ │ ├── enableException.c │ │ │ ├── exception.c │ │ │ ├── exceptionHook.s │ │ │ ├── exceptionNames.c │ │ │ ├── exceptionRegisters.c │ │ │ ├── menuHook.s │ │ │ ├── resetCollision.s │ │ │ ├── symbol.ld │ │ │ ├── symbol_jp.ld │ │ │ ├── tools.h │ │ │ └── weaponMenu.c │ ├── plugins │ │ └── plugin.py │ └── symbols │ │ ├── common.txt │ │ ├── common_jp.txt │ │ ├── gpu.txt │ │ ├── gpu_jp.txt │ │ ├── layer.txt │ │ ├── layer_jp.txt │ │ ├── misc.txt │ │ ├── misc_jp.txt │ │ ├── object.txt │ │ └── object_jp.txt ├── Example_SpyroRiptosRage │ ├── build │ │ └── .gitignore │ ├── config.json │ ├── disc.json │ ├── include │ │ └── common.h │ ├── mods │ │ └── Speedometer │ │ │ ├── MOD.BAT │ │ │ ├── buildList.txt │ │ │ ├── newtex │ │ │ └── .gitignore │ │ │ └── src │ │ │ ├── hook.s │ │ │ ├── main.c │ │ │ ├── math.c │ │ │ └── math.h │ ├── plugins │ │ └── plugin.py │ └── symbols │ │ └── american.txt ├── STARTUP.BAT ├── STARTUP.SH ├── common.mk ├── settings.json └── startup_game.json ├── install_toolchain_prebuilt.sh ├── requirements.txt └── tools ├── gcc-psyq-converted ├── include │ └── .gitignore └── lib │ └── .gitignore ├── macos-mips ├── mipsel-none-elf-binutils.rb └── mipsel-none-elf-gcc.rb ├── minin00b ├── Makefile ├── README.md ├── gen_makefile.py ├── include │ ├── assert.h │ ├── ctype.h │ ├── gtereg.inc │ ├── hwregs_a.inc │ ├── hwregs_c.h │ ├── inline_c.h │ ├── inline_s.inc │ ├── psxapi.h │ ├── psxcd.h │ ├── psxetc.h │ ├── psxgpu.h │ ├── psxgte.h │ ├── psxpad.h │ ├── psxpress.h │ ├── psxsio.h │ ├── psxsn.h │ ├── psxspu.h │ ├── setjmp.h │ ├── stdio.h │ ├── stdlib.h │ ├── string.h │ ├── strings.h │ └── sys │ │ ├── fcntl.h │ │ ├── ioctl.h │ │ └── types.h ├── lib │ ├── libc.a │ ├── psxapi.a │ ├── psxcd.a │ ├── psxetc.a │ ├── psxgpu.a │ ├── psxgte.a │ ├── psxpress.a │ ├── psxsio.a │ └── psxspu.a ├── libc │ ├── clz.s │ ├── memset.s │ ├── misc.c │ ├── readme.txt │ ├── scanf.c │ ├── setjmp.s │ ├── string.c │ └── vsprintf.c ├── psxapi │ ├── _syscalls.s │ ├── drivers.s │ ├── fs.s │ ├── generate_stubs.py │ ├── stdio.s │ ├── stubs.json │ └── sys.s ├── psxcd │ ├── cdread.c │ ├── common.c │ ├── isofs.c │ ├── isofs.h │ ├── misc.c │ └── readme.txt ├── psxetc │ ├── interrupts.c │ └── readme.txt ├── psxgpu │ ├── common.c │ ├── dbugfont.png │ ├── dbugfont.tim │ ├── drawing.c │ ├── env.c │ ├── font.c │ ├── image.c │ └── readme.txt ├── psxgte │ ├── initgeom.s │ ├── isin.c │ ├── matrix.c │ ├── matrix.s │ ├── readme.txt │ ├── squareroot.s │ └── vector.s ├── psxpress │ ├── README.md │ ├── generate_lookup_table.py │ ├── mdec.c │ ├── vlc.c │ ├── vlc.s │ └── vlc2.c ├── psxsio │ ├── sio.c │ └── tty.c └── psxspu │ ├── common.c │ └── readme.txt ├── mod-builder ├── _files.py ├── c.py ├── clut.py ├── common.py ├── compile_list.py ├── disc.py ├── game_options.py ├── image.py ├── main.py ├── makefile.py ├── mkpsxiso.py ├── nops.py ├── redux.py ├── syms.py └── tests │ ├── fake_settings.json │ ├── makefiles │ ├── CTR_HW_makefile │ └── fake_makefile │ ├── spyro___str__.txt │ ├── spyro_c_struct.txt │ ├── test_common.py │ ├── test_compile_list.py │ ├── test_files.py │ ├── test_image.py │ └── test_redux.py ├── nugget ├── LICENSE ├── README.md ├── common.mk └── common │ └── macros │ └── gte.h ├── startup ├── MOD.BAT ├── MOD.SH ├── STARTUP_MOD.BAT ├── STARTUP_MOD.SH ├── plugin.py └── startup.py ├── trimbin └── trimbin.py ├── updater └── main.py └── vscode └── launch.json /.dockerignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/.dockerignore -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # IDE files 7 | .vs 8 | .vscode 9 | 10 | # C files 11 | *.o 12 | *.dep 13 | *.bin 14 | *.gch 15 | 16 | # ISO files 17 | *.cue 18 | *.iso 19 | 20 | # Build artifacts 21 | build/ 22 | debug/ 23 | *.log 24 | offset.txt 25 | comport.txt 26 | gcc_out.txt 27 | overlay.ld 28 | Makefile 29 | 30 | # Version tracker 31 | tools/updater/.version 32 | 33 | # Third party stuff 34 | tools/gcc-psyq-converted/include/* 35 | tools/gcc-psyq-converted/lib/* 36 | !/tools/gcc-psyq-converted/lib/.gitignore 37 | !/tools/gcc-psyq-converted/include/.gitignore 38 | 39 | # Settings 40 | games/ 41 | 42 | # Executables 43 | *.exe -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | WORKDIR / 3 | COPY . /install-runtime/ 4 | ENV RUNTIME_DIR=/install-runtime 5 | RUN bash /install-runtime/install_toolchain_prebuilt.sh 6 | ENV PATH "$PATH:/opt/gcc-mipsel-none-elf/bin" 7 | ENV PATH "$PATH:/opt/gcc-mipsel-none-elf/mipsel-none-elf/bin" 8 | RUN pip3 install -r /install-runtime/requirements.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSX Modding Toolchain 2 | The goal of this project is to provide a set of tools for PSX developers in order to make modding and reverse engineering games easier, while using modern non-proprietary software. 3 | 4 | Watch the demo: 5 | [![video](https://imgur.com/Mdqs9JH.jpg)](https://www.youtube.com/watch?v=-AE4QKrx5uY) 6 | 7 | ## Features 8 | * Compile, playtest and build an ISO in just a few clicks; 9 | * Compile C code into multiple overlays, targetting any PSX RAM address; 10 | * Test code and asset changes in game during runtime; 11 | * Replace game textures using custom images; 12 | * Automatic rebuild a PSX iso with your own modifications. 13 | * Generate xdelta patches to easily distribute your ROM hacks. You can apply xdelta patches using this [web application](https://kotcrab.github.io/xdelta-wasm/) 14 | 15 | To discuss PSX development, hacking, and reverse engineering in general, please join the PSXDev Network Discord server: [![Discord](https://img.shields.io/discord/642647820683444236)](https://discord.gg/QByKPpH) 16 | 17 | ## Setup 18 | 19 | ## Prerequisites 20 | ``` 21 | python3.7+ 22 | python-pip 23 | ``` 24 | Note: some python installations might be incomplete. Make sure that you have installed `python`, `pip` and add them to your `PATH`. 25 | 26 | To compile the GCC mipsel toolchain (incomplete) 27 | ``` 28 | make 29 | libgl1 with GLIBC_2.35 # if using prebuilt 30 | ``` 31 | 32 | ## Setup 33 | 34 | ### Clone this repository: 35 | ``` 36 | $ git clone https://github.com/mateusfavarin/psx-modding-toolchain.git 37 | ``` 38 | 39 | ### python dependencies 40 | Install the python dependencies from the command line 41 | ``` 42 | $ pip install --upgrade pip setuptools wheel 43 | $ pip install -r requirements.txt 44 | ``` 45 | Note: don't use whitespaces in the folder names. This will break the `make` script. 46 | TODO: Verify this is still the case 47 | 48 | ### gcc-mipsel-none-elf toolchain: 49 | 50 | ##### Windows: 51 | Run the following command in a terminal like cmd or powershell 52 | ``` 53 | $ powershell -c "& { iwr -UseBasicParsing https://raw.githubusercontent.com/grumpycoders/pcsx-redux/main/mips.ps1 | iex }" 54 | ``` 55 | In a new terminal, run the following 56 | ``` 57 | mips install 13.1.0 58 | ``` 59 | 60 | OR pre-built installations are found at 61 | - https://static.grumpycoder.net/pixel/mips/g++-mipsel-none-elf-13.1.0.zip 62 | - https://www.github.com/Lameguy64/PSn00bSDK/releases/latest 63 | 64 | Extract the folder, e.g. `g++-mipsel-none-elf` 65 | Then add both of these folders to your `PATH` 66 | ``` 67 | g++-mipsel-none-elf/bin 68 | g++-mipsel-none-elf/mipsel-non-elf/bin 69 | ``` 70 | 71 | #### Linux 72 | 73 | You can compile the necessary gcc && mipsel-none-elf from source using [this script](https://github.com/grumpycoders/pcsx-redux/tree/main/tools/linux-mips). It takes a few hours. 74 | 75 | OR you can find pre-built binaries here 76 | - https://www.github.com/Lameguy64/PSn00bSDK/releases/latest 77 | 78 | The `install_toolchain_prebuilt.sh` extracts them to /opt/gcc-mipsel-none-elf/ (you may need sudo access). You just need to add them to your PATH 79 | ``` 80 | export PATH="$PATH:/opt/gcc-mipsel-none-elf/bin" 81 | export PATH="$PATH:/opt/gcc-mipsel-none-elf/mipsel-none-elf/bin" 82 | ``` 83 | Note: This isn't permanent and only works in a single terminal at a time. 84 | 85 | OR you can run the dockerfile (EXPERIMENTAL) from the root of this directory 86 | ``` 87 | docker build -t psx-modding . 88 | docker run -d -t psx-modding 89 | ``` 90 | 91 | ##### MacOS 92 | You'll need [brew](https://brew.sh/), and then run: 93 | ``` 94 | brew install ./tools/macos-mips/mipsel-none-elf-binutils.rb 95 | brew install ./tools/macos-mips/mipsel-none-elf-gcc.rb 96 | ``` 97 | 98 | #### PCSX-Redux 99 | PCSX-Redux is a PSX emulator heavily focused on development, debuggability, and reverse engineering. This project uses Redux's web server in order to connect the PSX modding toolchain to the emulator, allowing the developer to seamlessly hot-reload code while playing the game and update the emulator debugger symbols during runtime. 100 | 101 | In order to setup the emulator, you'll need to download [PCSX-Redux](https://github.com/grumpycoders/pcsx-redux/#where) and change the following settings under the `configuration/emulation` tab: 102 | 103 | ``` 104 | [ ] Dynarec CPU # Leave this unchecked 105 | [ ] 8MB # Optional 106 | [x] Enable Debugger 107 | [x] Enable GDB Server 108 | [x] Enable Web Server 109 | ``` 110 | 111 | #### NoPS 112 | NotPSXSerial, or NoPS for short, is a Serial/TTY suite for Unirom 8 featuring kernel-resident debugging, cart/EEPROM flasher, .exe/.elf upload, memcard tools, peeks, pokes, dumps and bugs. This project is integrates NoPS in order to hot-reload code directly in your PS1. 113 | 114 | You can download the latest release of Unirom [here](https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases), and then set the NoPS folder to your `PATH`. 115 | 116 | #### Usage 117 | Check the [docs](docs/) for information about configuring and using the tools. 118 | 119 | If you're interested in decompiling a game, you might be interested in checking out [this](games/Example_CrashTeamRacing/mods/DecompUnitTester/README.md) real time function unit tester. 120 | 121 | ## Testing 122 | We use pytest for testing 123 | ``` 124 | cd /tools/mod-builder 125 | python -m pytest 126 | ``` -------------------------------------------------------------------------------- /UPDATER.BAT: -------------------------------------------------------------------------------- 1 | python tools/updater/main.py -------------------------------------------------------------------------------- /UPDATER.SH: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | python3 tools/updater/main.py -------------------------------------------------------------------------------- /docs/1_introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | This page is designed to teach people how to install and play PSX mods, assuming you already followed all the [setup](../README.md#setup) process. The next pages will describe how to set up your environment for developing. 3 | 4 | ## Basic usage 5 | Go to your desired mod folder, double click `MOD.BAT`. This invokes the main python application which is responsible for automating all the process. This project comes with 3 simple mods as examples, two for the game Crash Team Racing (cross-version mods) and one for the NTSC-U release of Spyro 2: Ripto's Rage. 6 | 7 | ## Folder structure 8 | This project uses a specific folder structure in order to look for components during execution. You must follow this structure in order to use this toolchain. 9 | ``` 10 | .psx-modding-toolchain 11 | ├──docs/ 12 | ├──games/ 13 | ├──game1/ 14 | ├──build/ 15 | ├──include/ 16 | ├──mods/ 17 | ├──mod1/ 18 | ├──src/ 19 | ├──buildList.txt 20 | ├──MOD.BAT 21 | ├──mod2/ 22 | ├──... 23 | ├──STARTUP_MOD.BAT 24 | ├──plugins/ 25 | ├──plugin.py 26 | ├──symbols/ 27 | ├──config.json 28 | ├──disc.json 29 | ├──game2/ 30 | ├──... 31 | ├──common.mk 32 | ├──settings.json 33 | ├──tools/ 34 | ├──gcc-psyq-converted/ 35 | ├──include/ 36 | ├──lib/ 37 | ... 38 | ``` 39 | 40 | ## Compiling 41 | In order to play a mod, the first thing you need to do is hit the compiler button. 42 | 43 | The tool will look for the `buildList.txt`, which contains a declaration of what files to compile and how to compile them. During the compilation process, several files will be created. The `output/` folder will contain `.bin` files which corresponds to the code that you compiled. The `debug/` folder contains useful debugging information, such as linker map files and `.elf` files. The `backup/` folder will contain saved information for uninstalling mods which you hot-reloaded. 44 | 45 | ## Extracting & Building an ISO 46 | Place your iso in the `games/game_name/build/` folder, rename your iso to match the same name as the iso specified in `games/game_name/config.json`, then run the `Extract ISO` or `Build ISO` command. 47 | 48 | Note: during the building process, all new files will be renamed to upper case files. 49 | 50 | ## Hot Reloading 51 | Edit the file `games/settings.json` with your redux port and/or NoPS comport, then run any of the hot reload commands during the game. This will stop the game, inject mod code or patch disc files, and then resume the game running the newly injected code/patched files. 52 | 53 | Note: for code hot reloads only, you can uninstall a mod if you select the backup option during the hot reload. 54 | Note/NoPS: you may need to launch your game via unirom in debug mode in order to hot-reload code in your PSX. 55 | 56 | ## Texture Replacement 57 | Edit the file `games/settings.json` with your redux port, place your images in the folder `newtex` as specified in [notes](4_notes.md), and then run the texture replacement command. This command will convert your image to the RGB5551 format, and then inject in the specified VRAM address. 58 | 59 | ## Clean Commands 60 | * `Clean`: cleans all the files generated during the compilation process, as well as the output of texture replacement. 61 | * `Clean Build`: cleans all the files generated during the iso building process, except the iso extraction files. 62 | * `Clean Precompiled Header`: cleans the compiled include header file. 63 | * `Clean All`: runs `Clean`, `Clean Build`, and `Clean Precompiled Header`, and also cleans all the files created in the iso extraction process. -------------------------------------------------------------------------------- /docs/3_debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging: GDB Setup for VSCode 2 | This page is a tutorial on how to setup your VSCode to debug your code using a GDB bridge with PCSX-Redux. 3 | 4 | Note: this method of debugging is only useful for the code that you compiled. If you want to debug the game assembly that you haven't decompiled, then you'll have to fallback to Redux's interval MIPS debugger. 5 | 6 | # Redux Configuration 7 | In `Configuration -> Emulation`, make sure to select `Enable GDB Server`. Reboot the emulator if it's your first time enabling it. 8 | 9 | # GDB Setup 10 | 11 | ### Windows 12 | Download the pre-compiled binaries [here](https://static.grumpycoder.net/pixel/gdb-multiarch-windows/), then add `gdb-multiarch/bin` to your `PATH`. 13 | 14 | ### GNU/Linux 15 | Download `gdb-multiarch` using your preferred package manager. 16 | 17 | # VSCode Setup 18 | * Download the `Native debug` extension 19 | ![image](https://pcsx-redux.consoledev.net/images/vscode_native_debug.png) 20 | 21 | * Copy the sample [launch.json](../tools/vscode/launch.json) to your `.vscode` folder. 22 | * Change the `executable` parameter in the `launch.json` to be the path of your mod elf file. 23 | 24 | # Run 25 | Inject your mod in redux, then simply run your GDB configuration in VSCode. You should be able to place breakpoints in your mod code and debug your program. 26 | ![image](https://i.imgur.com/rRDFfDe.png) -------------------------------------------------------------------------------- /docs/4_notes.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | This page is dedicated for notes/facts about the PSX, which may help you in your hacking journey. 3 | 4 | ## Retail Bios/Kernel 5 | The first `0x10000` bytes in memory is reserved to the kernel. However, the kernel doesn't use all of its memory, so you could use some of its space to load your own code in it. Here's a table with the three biggest memory holes which are generally safe to play with: 6 | 7 | | Start | End | Size | 8 | | :- | :- | :- | 9 | | 0x8000A000 | 0x8000B900 | 0x1900 | 10 | | 0x8000C000 | 0x8000DF00 | 0x1F00 | 11 | | 0x8000E400 | 0x80010000 | 0x1C00 | 12 | 13 | Note: these sections are rough estimations based on tests done using a SCPH 7501 bios. Results may vary depending on the game being played. 14 | 15 | ## Unirom 16 | If you wish to make your mods compatible with Unirom/Nops, make sure to avoid the following memory sections: 17 | 18 | | Start | End | Size | 19 | | :- | :- | :- | 20 | | 0x8000C000 | 0x8000D000 | 0x1000 | 21 | | 0x8000E400 | 0x8000E43C | 0x3C | 22 | | 0x8000FE00 | 0x80010000 | 0x200 | 23 | 24 | ## ps-exe header 25 | The playstation executable has a `0x800` bytes header, which is loaded in the retail bios/kernel at address `0x8000B070` (or `0x8000A8D0` on PS2 via backwards compatibility). However, only the first `0x4C` bytes of the header [are actually used](https://github.com/pcsx-redux/nugget/blob/main/ps-exe.ld#L53-L95), so you could exploit that fact and overwrite most of the header with your own custom code, which will be automatically installed in the kernel when the PSX tries to load the game executable. The [spyro mod example](../games/Example_SpyroRiptosRage/mods/Speedometer/) uses this exploit. -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/build/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/build/.gitignore -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compiler": { 3 | "function_sections": 1, 4 | "reorder_functions": 1, 5 | "optimization": 4, 6 | "debug": 1, 7 | "psyq": 0, 8 | "mininoob": 0, 9 | "8mb": 1 10 | }, 11 | "versions": [ 12 | { 13 | "ntsc-u": { 14 | "name": "ctr-u.bin", 15 | "symbols": [ 16 | "funcs-u.txt", 17 | "addrs-u.txt" 18 | ], 19 | "build_id": 926 20 | } 21 | }, 22 | { 23 | "pal": { 24 | "name": "ctr-pal.bin", 25 | "symbols": [ 26 | "funcs-pal.txt", 27 | "addrs-pal.txt" 28 | ], 29 | "build_id": 1020 30 | } 31 | }, 32 | { 33 | "ntsc-j": { 34 | "name": "ctr-j.bin", 35 | "symbols": [ 36 | "funcs-j.txt", 37 | "addrs-j.txt" 38 | ], 39 | "build_id": 1111 40 | } 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/disc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ntsc-u": [ 3 | { 4 | "SCUS_944.26": [ 5 | { 6 | "name": "header", 7 | "address": "0x8000B070", 8 | "offset": "0x0" 9 | }, 10 | { 11 | "name" : "exe", 12 | "address" : "0x80010000", 13 | "offset" : "0x800" 14 | } 15 | ], 16 | "bigfile/screen/title01_usa.tim": [ 17 | { 18 | "name": "splash01", 19 | "address": "0x0", 20 | "offset": "0x0" 21 | } 22 | ] 23 | } 24 | ], 25 | "pal": [ 26 | { 27 | "SCES_021.05": [ 28 | { 29 | "name": "header", 30 | "address": "0x8000B070", 31 | "offset": "0x0" 32 | }, 33 | { 34 | "name" : "exe", 35 | "address" : "0x80010000", 36 | "offset" : "0x800" 37 | } 38 | ] 39 | } 40 | ], 41 | "ntsc-j": [ 42 | { 43 | "SCPS_101.18": [ 44 | { 45 | "name": "header", 46 | "address": "0x8000B070", 47 | "offset": "0x0" 48 | }, 49 | { 50 | "name" : "exe", 51 | "address" : "0x80010000", 52 | "offset" : "0x800" 53 | } 54 | ] 55 | } 56 | ] 57 | } -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #define NTSC_U 926 5 | #define PAL 1020 6 | #define NTSC_J 1111 7 | 8 | enum gameModes { 9 | BATTLE_MODE = 0x20, 10 | RACE_INTRO_CUTSCENE = 0x40, 11 | WARPBALL_HELD = 0x1000, 12 | MAIN_MENU = 0x2000, 13 | TIME_TRIAL = 0x20000, 14 | ADVENTURE_MODE = 0x80000, 15 | ADVENTURE_HUB = 0x100000, 16 | RACE_OUTRO_CUTSCENE = 0x200000, 17 | ARCADE_MODE = 0x400000, 18 | ROLLING_ITEM = 0x800000, 19 | CRYSTAL_CHALLENGE = 0x8000000, 20 | ADVENTURE_CUP = 0x10000000, 21 | GAME_INTRO = 0x20000000, 22 | LOADING = 0x40000000, 23 | ADVENTURE_BOSS = 0x80000000 24 | }; 25 | 26 | enum RawButtons 27 | { 28 | RAW_BTN_SELECT = 0x1, 29 | RAW_BTN_START = 0x8, 30 | RAW_BTN_UP = 0x10, 31 | RAW_BTN_RIGHT = 0x20, 32 | RAW_BTN_DOWN = 0x40, 33 | RAW_BTN_LEFT = 0x80, 34 | RAW_BTN_L2 = 0x100, 35 | RAW_BTN_R2 = 0x200, 36 | RAW_BTN_L1 = 0x400, 37 | RAW_BTN_R1 = 0x800, 38 | RAW_BTN_TRIANGLE = 0x1000, 39 | RAW_BTN_CIRCLE = 0x2000, 40 | RAW_BTN_CROSS = 0x4000, 41 | RAW_BTN_SQUARE = 0x8000, 42 | RAW_BTN_COUNT = 14 43 | }; 44 | 45 | struct GamepadBuffer 46 | { 47 | char unk[0x20]; // 0x0 48 | unsigned short * rawController; // 0x20 49 | char unk2[0x2C]; // 0x24 50 | }; 51 | 52 | struct GamepadSystem 53 | { 54 | struct GamepadBuffer gamepadBuffer[8]; // 0x0 55 | }; 56 | 57 | void DrawText(char * text, int x, int y, int size, int color); 58 | int ND_MATH_Sin(unsigned int angle); 59 | void GameplayUpdateLoop(); 60 | int printf(const char * format, ...); 61 | 62 | // 0x8008D2AC - NTSC-U 63 | // 0x8008D644 - PAL 64 | // 0x800906B8 - NTSC-J 65 | extern unsigned int gameMode; 66 | extern struct GamepadSystem * gamepadSystem; 67 | 68 | // 0x800845a0 - NTSC-U 69 | extern int trigApprox[0x400]; 70 | 71 | #endif -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/README.md: -------------------------------------------------------------------------------- 1 | # What is this? 2 | This is a real time unit tester for decompiled functions. The idea of this mod is to use `PCSX-Redux` 8MB memory expansion in order to call both the decompiled function and the original function, and then compare their outputs. 3 | 4 | ## Why? 5 | Reverse engineering is the process of understanding how a piece of software accomplishes a task, without having the access to its original source code. Once you understand what the software does, you can re-write it in your own way, producing code which may not be identical to the original source, but will be functioning in the same way. 6 | 7 | There are multiple advantages of re-writing the software on your own. You will: 8 | * Gain a fundamental understanding of how the software works; 9 | * Be able to modify the software as you please; 10 | * Be able to fix bugs and optimize the code; 11 | 12 | The code generation is most likely going to be much better than the original progran since you could use modern compilers with your code. 13 | 14 | ## How? 15 | The idea behind comparing two functions is simple. In the PSX, a function can: 16 | * Return a value; 17 | * Write to the RAM; 18 | * Write to the scratchpad; 19 | * Modify the COP2 registers; 20 | 21 | If we want to tell whether two functions share the same behavior, we first need to create a backup of the current state of the program, and de-activate all the system interrupts. This will ensure that only our functions will be writing to memory, so we have full control of the function workflow. Then, we need to compare whether the RAM, scratchpad, COP2 regs and return value remains the same for both functions. -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/buildList.txt: -------------------------------------------------------------------------------- 1 | common, exe, GameplayUpdateLoop, -0x8, src/hook.s, hook.bin 2 | common, oob, 0x80200000, 0x0, src/*.c, unit_tester.bin -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/newtex/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/DecompUnitTester/newtex/.gitignore -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/src/hook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | j InstallHook 3 | -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "math.h" 4 | 5 | // MIPS Instructions 6 | #define J(addr) ((((unsigned int) addr & 0xFFFFFF) >> 2) | 0x08000000) 7 | #define JR_RA 0x03E00008 8 | #define NOP 0x00000000 9 | 10 | typedef int (*func)(unsigned int); 11 | func newFunc = (func) &MATH_Sin; 12 | int newRes; 13 | func oldFunc = (func) &ND_MATH_Sin; 14 | int ogRes; 15 | 16 | unsigned int * hookAddress = (unsigned int *) (&GameplayUpdateLoop - 8); 17 | unsigned int instructions[4]; 18 | 19 | unsigned int * ram = (unsigned int *) 0x80010000; 20 | unsigned int * ram_4mb = (unsigned int *) 0x80410000; 21 | unsigned int * ram_6mb = (unsigned int *) 0x80610000; 22 | const unsigned int ramSize = (0x1FF800 - 0x10000) / 4; 23 | unsigned int * scratchpad = (unsigned int *) 0x1F800000; 24 | unsigned int * scratchpadBackup_4mb = (unsigned int *) 0x80400000; 25 | unsigned int * scratchpadBackup_6mb = (unsigned int *) 0x80600000; 26 | const unsigned int scratchpadSize = 0x400 / 4; 27 | unsigned int * gteBackup_4mb = (unsigned int *) 0x80408000; 28 | unsigned int * gteBackup_6mb = (unsigned int *) 0x80608000; 29 | const unsigned int gteSize = 64; 30 | unsigned int hits = 0; 31 | unsigned int total = 0; 32 | 33 | /* 34 | The credit for the first two functions goes to Nicolas Noble, 35 | author of the openbios project. I'm calling these functions to 36 | disable interrupts, so that the PSX RAM is guaranteed to not change 37 | during all our function calls. 38 | https://github.com/grumpycoders/pcsx-redux/blob/main/src/mips/common/syscalls/syscalls.h#L39-L57 39 | */ 40 | static __attribute__((always_inline)) int enterCriticalSection() { 41 | register int n asm("a0") = 1; 42 | register int r asm("v0"); 43 | __asm__ volatile("syscall\n" 44 | : "=r"(n), "=r"(r) 45 | : "r"(n) 46 | : "at", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", 47 | "memory"); 48 | return r; 49 | } 50 | 51 | static __attribute__((always_inline)) void leaveCriticalSection() { 52 | register int n asm("a0") = 2; 53 | __asm__ volatile("syscall\n" 54 | : "=r"(n) 55 | : "r"(n) 56 | : "at", "v0", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", 57 | "memory"); 58 | } 59 | 60 | void memCopy(unsigned int * dest, unsigned int * src, unsigned int size) 61 | { 62 | for (unsigned int i = 0; i < size; i++) 63 | dest[i] = src[i]; 64 | } 65 | 66 | int isEqual(unsigned int * dest, unsigned int * src, unsigned int size) 67 | { 68 | int ret = 1; 69 | for (unsigned int i = 0; i < size; i++) 70 | { 71 | if (dest[i] != src[i]) 72 | { 73 | printf("Diff at %x\n", &dest[i]); 74 | ret = 0; 75 | } 76 | } 77 | return ret; 78 | } 79 | 80 | // The Tester() function takes the same signature as the function you're decompiling 81 | void Tester(unsigned int angle) 82 | { 83 | enterCriticalSection(); 84 | // Backup the program state before calling the decomp function 85 | memCopy(ram_4mb, ram, ramSize); 86 | memCopy(scratchpadBackup_4mb, scratchpad, scratchpadSize); 87 | gte_saveContext(gteBackup_4mb); 88 | // Call the decomp function 89 | newRes = newFunc(angle); 90 | // Backup result of decomp function 91 | memCopy(ram_6mb, ram, ramSize); 92 | memCopy(scratchpadBackup_6mb, scratchpad, scratchpadSize); 93 | gte_saveContext(gteBackup_6mb); 94 | // Load state 95 | memCopy(ram, ram_4mb, ramSize); 96 | memCopy(scratchpad, scratchpadBackup_4mb, scratchpadSize); 97 | gte_loadContext(gteBackup_4mb); 98 | // Call the original function 99 | func ogFunc = (func) &instructions[0]; 100 | ogRes = ogFunc(angle); 101 | gte_saveContext(gteBackup_4mb); 102 | total++; 103 | // Comparing the results of the original function and the decomp function 104 | if ((newRes == ogRes) && 105 | (isEqual(gteBackup_4mb, gteBackup_6mb, gteSize)) && 106 | (isEqual(scratchpad, scratchpadBackup_6mb, scratchpadSize)) && 107 | (isEqual(ram, ram_6mb, ramSize))) { 108 | hits++; 109 | } 110 | printf("Hits/totals: %d/%d\n", hits, total); 111 | leaveCriticalSection(); 112 | } 113 | 114 | void InstallHook() 115 | { 116 | unsigned int * oldFuncAddr = (unsigned int *) oldFunc; 117 | instructions[0] = oldFuncAddr[0]; 118 | instructions[1] = oldFuncAddr[1]; 119 | instructions[2] = J(&oldFuncAddr[2]); 120 | instructions[3] = NOP; 121 | 122 | oldFuncAddr[0] = J(&Tester); 123 | oldFuncAddr[1] = NOP; 124 | 125 | *hookAddress = JR_RA; 126 | } -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/src/math.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | 4 | int MATH_Sin(unsigned int angle) 5 | { 6 | int sine = trigApprox[angle & 0x3FF]; 7 | 8 | if ((angle & 0x400) == 0) 9 | sine = sine << 0x10; 10 | 11 | sine = sine >> 0x10; 12 | 13 | if ((angle & 0x800) != 0) 14 | sine = -sine; 15 | 16 | return sine; 17 | } 18 | 19 | int MATH_Cos(unsigned int angle) { 20 | 21 | int cos = trigApprox[angle & 0x3FF]; 22 | 23 | if ((angle & 0x400) != 0) 24 | { 25 | cos = (short)cos; 26 | if ((angle & 0x800) == 0) 27 | return -cos; 28 | } 29 | else 30 | { 31 | cos = cos >> 0x10; 32 | if ((angle & 0x800) != 0) 33 | return -cos; 34 | } 35 | 36 | return cos; 37 | } -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/DecompUnitTester/src/math.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H 2 | #define MATH_H 3 | 4 | int MATH_Sin(unsigned int angle); 5 | int MATH_Cos(unsigned int angle); 6 | 7 | #endif -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/HelloWorld/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/HelloWorld/buildList.txt: -------------------------------------------------------------------------------- 1 | common, exe, 0x80010100, 0x0, src/hello.c 2 | common, exe, BOTS_SetRotation, -0x8, src/hook.s -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/HelloWorld/newtex/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/HelloWorld/newtex/.gitignore -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/HelloWorld/src/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int Hello_Main() 4 | { 5 | if ((gameMode & LOADING) == 0) 6 | { 7 | DrawText("Hello World", 10, 180, 2, 0xffff0000); 8 | /* 9 | BUILD is a variable assigned during compilation time. 10 | It takes the value build_id defined in config.json 11 | */ 12 | #if BUILD == NTSC_U 13 | DrawText("NTSC-U", 10, 200, 2, 0xffff0000); 14 | #elif BUILD == PAL 15 | DrawText("PAL", 10, 200, 2, 0xffff0000); 16 | #elif BUILD == NTSC_J 17 | DrawText("NTSC-J", 10, 200, 2, 0xffff0000); 18 | #else 19 | DrawText("Unknown build", 10, 200, 2, 0xffff0000); 20 | #endif 21 | } 22 | } -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/HelloWorld/src/hook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | j Hello_Main 3 | -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/PluginTest/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/PluginTest/assets/title01_usa.tim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/PluginTest/assets/title01_usa.tim -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/PluginTest/buildList.txt: -------------------------------------------------------------------------------- 1 | common, splash01, 0x0, 0x0, assets/title01_usa.tim -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/RemapController/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/RemapController/buildList.txt: -------------------------------------------------------------------------------- 1 | common, exe, 0x80010100, 0x0, src/main.c 2 | common, exe, LOAD_Hub_ReadFile, -0x8, src/hook.s -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/RemapController/newtex/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/RemapController/newtex/.gitignore -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/RemapController/src/hook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | j Remap_Main 3 | -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/RemapController/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int original_map[] = { 4 | RAW_BTN_UP, 5 | RAW_BTN_DOWN, 6 | RAW_BTN_LEFT, 7 | RAW_BTN_RIGHT, 8 | RAW_BTN_CROSS, 9 | RAW_BTN_SQUARE, 10 | RAW_BTN_CIRCLE, 11 | RAW_BTN_TRIANGLE, 12 | RAW_BTN_R1, 13 | RAW_BTN_R2, 14 | RAW_BTN_L1, 15 | RAW_BTN_L2, 16 | RAW_BTN_SELECT, 17 | RAW_BTN_START 18 | }; 19 | 20 | // Mimic Nitro-Fueled Polswid controls! 21 | // simple remap: L2 -> Down, Down -> Left, Left -> Triangle, Triangle -> L2 22 | unsigned int new_map[] = { 23 | RAW_BTN_UP, // UP 24 | RAW_BTN_LEFT, // DOWN 25 | RAW_BTN_TRIANGLE, // LEFT 26 | RAW_BTN_RIGHT, // RIGHT 27 | RAW_BTN_CROSS, // CROSS 28 | RAW_BTN_SQUARE, // SQUARE 29 | RAW_BTN_CIRCLE, // CIRCLE 30 | RAW_BTN_L2, // TRIANGLE 31 | RAW_BTN_R1, // R1 32 | RAW_BTN_R2, // R2 33 | RAW_BTN_L1, // L1 34 | RAW_BTN_DOWN, // L2 35 | RAW_BTN_SELECT, // SELECT 36 | RAW_BTN_START // START 37 | }; 38 | 39 | void RemapButtons(unsigned short * buttons) 40 | { 41 | unsigned short curr_buttons = *buttons; 42 | unsigned short new_buttons = 0xFFFF; 43 | for (int i = 0; i < RAW_BTN_COUNT; i++) 44 | { 45 | if ((curr_buttons & original_map[i]) == 0) 46 | new_buttons ^= new_map[i]; 47 | } 48 | *buttons = new_buttons; 49 | } 50 | 51 | void Remap_Main() 52 | { 53 | struct GamepadBuffer * controller = &gamepadSystem->gamepadBuffer[0]; 54 | RemapButtons(&controller->rawController[1]); 55 | } -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/TextureReplacement/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/TextureReplacement/buildList.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/TextureReplacement/buildList.txt -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/TextureReplacement/newtex/SPYRO_368_216_1_251_44_26_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/TextureReplacement/newtex/SPYRO_368_216_1_251_44_26_4.png -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/mods/TextureReplacement/src/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_CrashTeamRacing/mods/TextureReplacement/src/.gitignore -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/plugins/plugin.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | def warning() -> None: 5 | print("[Plugin] WARNING: ctr-tools not found. Please download the tools from https://github.com/CTR-tools/CTR-tools/releases") 6 | print("rename the folder to ctr-tools and put it in Example_CrashTeamRacing/plugins/") 7 | 8 | def extract(plugin_path: str, game_path: str, version: None) -> None: 9 | if os.path.join(plugin_path, "ctr-tools"): 10 | os.system(plugin_path + "ctr-tools/bigtool.exe " + game_path + "BIGFILE.BIG") 11 | else: 12 | warning() 13 | 14 | def build(plugin_path: str, game_path: str, version: None) -> None: 15 | if os.path.join(plugin_path, "ctr-tools"): 16 | bigpath = os.getcwd() + "/bigfile" 17 | shutil.copytree(game_path + "bigfile", bigpath) 18 | os.system(plugin_path + "ctr-tools/bigtool.exe " + game_path + "bigfile.txt") 19 | shutil.rmtree(bigpath) 20 | else: 21 | warning() -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/symbols/addrs-j.txt: -------------------------------------------------------------------------------- 1 | gameMode = 0x800906B8; 2 | gamepadSystem = 0x800906B8; -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/symbols/addrs-pal.txt: -------------------------------------------------------------------------------- 1 | gameMode = 0x8008D644; 2 | gamepadSystem = 0x8008D648; -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/symbols/addrs-u.txt: -------------------------------------------------------------------------------- 1 | gameMode = 0x8008D2AC; 2 | gamepadSystem = 0x8008D2B0; 3 | trigApprox = 0x800845a0; -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/symbols/funcs-j.txt: -------------------------------------------------------------------------------- 1 | DrawText = 0x800241f0; 2 | BOTS_SetRotation = 0x800148e4; 3 | LOAD_Hub_ReadFile = 0x80034bc8; 4 | ND_MATH_Sin = 0x8003e91c; 5 | GameplayUpdateLoop = 0x800369c4; 6 | printf = 0x8007d748; -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/symbols/funcs-pal.txt: -------------------------------------------------------------------------------- 1 | DrawText = 0x80022aa8; 2 | BOTS_SetRotation = 0x80013464; 3 | LOAD_Hub_ReadFile = 0x80033370; 4 | ND_MATH_Sin = 0x8003cf48; 5 | GameplayUpdateLoop = 0x80035158; 6 | printf = 0x8007cc44; -------------------------------------------------------------------------------- /games/Example_CrashTeamRacing/symbols/funcs-u.txt: -------------------------------------------------------------------------------- 1 | DrawText = 0x80022878; 2 | BOTS_SetRotation = 0x80013444; 3 | LOAD_Hub_ReadFile = 0x80032ffc; 4 | ND_MATH_Sin = 0x8003d184; 5 | GameplayUpdateLoop = 0x80034d54; 6 | printf = 0x8007c820; -------------------------------------------------------------------------------- /games/Example_MegaManX4/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compiler": { 3 | "function_sections": 1, 4 | "reorder_functions": 0, 5 | "optimization": 4, 6 | "debug": 1, 7 | "psyq": 1, 8 | "mininoob": 0, 9 | "8mb": 0 10 | }, 11 | "versions": [ 12 | { 13 | "american": { 14 | "name": "MMX4.bin", 15 | "symbols": [ 16 | "common.txt", 17 | "object.txt", 18 | "gpu.txt", 19 | "layer.txt", 20 | "misc.txt" 21 | ], 22 | "build_id": 561 23 | } 24 | }, 25 | { 26 | "japan": { 27 | "name": "RMX4.BIN", 28 | "symbols": [ 29 | "common_jp.txt", 30 | "object_jp.txt", 31 | "gpu_jp.txt", 32 | "layer_jp.txt", 33 | "misc_jp.txt" 34 | ], 35 | "build_id": 902 36 | } 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /games/Example_MegaManX4/disc.json: -------------------------------------------------------------------------------- 1 | { 2 | "american": [ 3 | { 4 | "SLUS_005.61": [ 5 | { 6 | "name": "header", 7 | "address": "0x8000B070", 8 | "offset": "0x0" 9 | }, 10 | { 11 | "name": "exe", 12 | "address": "0x80010000", 13 | "offset": "0x800" 14 | } 15 | ] 16 | } 17 | ], 18 | "japan": [ 19 | { 20 | "SLPS_009.02": [ 21 | { 22 | "name": "header", 23 | "address": "0x8000B070", 24 | "offset": "0x0" 25 | }, 26 | { 27 | "name": "exe", 28 | "address": "0x80010000", 29 | "offset": "0x800" 30 | } 31 | ] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /games/Example_MegaManX4/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | #include 4 | #include 5 | #include 6 | 7 | #define WriteShort(addr, value) (*(short*)(addr) = (value)) 8 | #define WriteInt(addr, value) (*(int*)(addr) = (value)) 9 | #define WriteByte(addr, value) (*(char*)(addr) = (value)) 10 | 11 | enum PadButtons{ 12 | PAD_L1 = 4, 13 | PAD_R1 = 8, 14 | PAD_L2 = 1, 15 | PAD_R2 = 2, 16 | PAD_SELECT = 0x100, 17 | PAD_START = 0x800, 18 | PAD_UP = 0x1000, 19 | PAD_RIGHT = 0x2000, 20 | PAD_DOWN = 0x4000, 21 | PAD_LEFT = 0x8000, 22 | PAD_TRIANGLE = 0x10, 23 | PAD_CIRCLE = 0x20, 24 | PAD_CROSS = 0x40, 25 | PAD_SQUARE = 0x80 26 | }; 27 | 28 | extern ushort buttonsHeld; 29 | extern ushort buttonsPressed; 30 | extern u_char cursor; 31 | extern char fadeDirection; //0 = done 32 | extern int frameCount; 33 | extern void * freeArcP; 34 | 35 | typedef struct { 36 | byte mode; 37 | byte mode2; 38 | byte mode3; 39 | byte mode4; 40 | undefined field4_0x4; 41 | undefined field5_0x5; 42 | undefined field6_0x6; 43 | undefined field7_0x7; 44 | undefined field8_0x8; 45 | undefined field9_0x9; 46 | undefined field10_0xa; 47 | undefined field11_0xb; 48 | byte stageid; 49 | byte mid; 50 | byte movie; 51 | byte clear; 52 | bool rideArmorEnable; /* AI */ 53 | bool disableWepaonObjects; 54 | bool disableMainObjects; 55 | bool disableShotObjects; 56 | bool disableVisualObjects; 57 | bool disableEffectObjects; 58 | bool disableItemObjects; 59 | bool disableMiscObjects; 60 | bool disableQuadObjects; 61 | bool disableForeObjects; 62 | undefined field26_0x1a; 63 | undefined field27_0x1b; 64 | undefined field28_0x1c; 65 | char point; 66 | byte specialStart; 67 | bool enableBars; 68 | struct objStruct * bossP; 69 | bool enableBossBar; 70 | byte bossBarType; 71 | undefined field35_0x26; 72 | undefined field36_0x27; 73 | undefined field37_0x28; 74 | undefined field38_0x29; 75 | undefined field39_0x2a; 76 | undefined field40_0x2b; 77 | undefined field41_0x2c; 78 | undefined field42_0x2d; 79 | byte seenTextFlag; /* so that you dont see the boss dialog twice */ 80 | undefined field44_0x2f; 81 | undefined field45_0x30; 82 | undefined field46_0x31; 83 | undefined field47_0x32; 84 | undefined field48_0x33; 85 | undefined field49_0x34; 86 | undefined field50_0x35; 87 | undefined field51_0x36; 88 | byte cheatCodeFlag; /* Ultimate Armor/Black Zero */ 89 | undefined field53_0x38; 90 | undefined field54_0x39; 91 | undefined field55_0x3a; 92 | undefined field56_0x3b; 93 | undefined field57_0x3c; 94 | undefined field58_0x3d; 95 | undefined field59_0x3e; 96 | undefined field60_0x3f; 97 | byte sceneFlags; /* for X/Zero/Double/Iris */ 98 | undefined field62_0x41; 99 | undefined field63_0x42; 100 | char player; 101 | byte lives; 102 | byte currentMaxHP; 103 | byte maxHP; 104 | byte armorParts; 105 | byte busterType; 106 | undefined field70_0x49; 107 | undefined field71_0x4a; 108 | undefined field72_0x4b; 109 | undefined field73_0x4c; 110 | undefined field74_0x4d; 111 | undefined field75_0x4e; 112 | undefined field76_0x4f; 113 | undefined field77_0x50; 114 | undefined field78_0x51; 115 | undefined field79_0x52; 116 | undefined field80_0x53; 117 | undefined field81_0x54; 118 | undefined field82_0x55; 119 | undefined field83_0x56; 120 | undefined field84_0x57; 121 | undefined field85_0x58; 122 | byte clearedStages; 123 | ushort collectables; /* hearts , tanks , 1UP thing */ 124 | byte tanksAmmo[3]; /* 2 sub tanks then the w tanks */ 125 | byte startMode; 126 | undefined field90_0x60; 127 | undefined field91_0x61; 128 | undefined field92_0x62; 129 | undefined field93_0x63; 130 | }Game; 131 | 132 | extern Game game; 133 | 134 | void ArcSeek(ushort id,u_char bufferId,void * bufferP); 135 | void BinSeek(ushort id,void * dest); 136 | void ClearAll(void); 137 | void DrawLoad(bool showName ,bool fade); 138 | void DrawMain(); 139 | void DrawMMX4(void); 140 | void EndSong(void); 141 | 142 | void FadeIn(u_char speed); 143 | void FadeOut(u_char speed); 144 | void FileCollect(); 145 | 146 | void PlaySound(int slot,int id,Object *objP); 147 | void PlaySong(byte id,byte vol); 148 | 149 | char * strcpy(void * dest,void * src); 150 | void * memcpy(void *dest, void *src,int length); 151 | void * memset(void *dest, char *fillbyte,int length); 152 | 153 | int printf(const char *fmt,...); 154 | 155 | void SpawnText(ushort id,byte idk,byte flag); 156 | 157 | void NewThread(int id,void * func); 158 | void ThreadSleep(ushort frames); 159 | void DeleteThread(); 160 | void DeleteThread2(int id); 161 | void NewThread2(void * func); 162 | #endif -------------------------------------------------------------------------------- /games/Example_MegaManX4/include/gpu.h: -------------------------------------------------------------------------------- 1 | #ifndef GPU_H 2 | #define GPU_H 3 | #include 4 | #include 5 | #include 6 | #define GetTPageValue(tp,abr,x,y) (tp << 7) + (abr << 5) + x + (y << 4) //Use w/ SetDrawTPage() 7 | #define GetClutCord(id) (ushort)((id & 0xF) + ((id & 0xF0) << 2) + 0x7800) //Base is X:0 Y:480 8 | 9 | void AddPrim(void *ot,void *p); 10 | void AddPrims(void *ot,void *p0,void *p1); 11 | void CatPrim(void *p0,void *p1); 12 | 13 | u_long *ClearOTagR(u_long *ot, int n); 14 | 15 | void DrawOTag(u_long *p); 16 | int DrawSync(int mode); 17 | 18 | int VSync(int mode); 19 | 20 | int ClearImage(RECT *rect,u_char r,u_char g,u_char b); 21 | int ClearImage2(RECT *rect,u_char r,u_char g,u_char b); 22 | u_long *ClearOTag(u_long *ot, int n); 23 | int LoadImage(RECT *rect,u_long *p); 24 | int StoreImage(RECT *rect,u_long *p); 25 | int MoveImage(RECT * rect,int x,int y); 26 | 27 | DISPENV *PutDispEnv(DISPENV *env); 28 | DRAWENV *PutDrawEnv(DRAWENV *env); 29 | 30 | DISPENV * SetDefDispEnv(DISPENV *env,int x,int y,int w,int h); 31 | DRAWENV * SetDefDrawEnv(DRAWENV *env,int x,int y,int w,int h); 32 | 33 | void SetPolyF4(POLY_F4 *p); 34 | void SetPolyFT4(POLY_FT4 *p); 35 | void SetPolyGT3(POLY_GT3 *p); 36 | void SetPolyG4(POLY_G4 *p); 37 | void SetPolyGT4(POLY_GT4 *p); 38 | void SetSemiTrans(void *p,int abe); 39 | void SetSprt8(SPRT_8 *p); 40 | void SetSprt16(SPRT_16 *p); 41 | void SetSprt(SPRT *p); 42 | void SetTile1(TILE_1 * p); 43 | void SetTile8(TILE_8 * p); 44 | void SetTile16(TILE_16 * p); 45 | void SetTile(TILE * p); 46 | void SetLineF2(LINE_F2 * p); 47 | void SetLineG2(LINE_G2 * p); 48 | void SetLineF3(LINE_F3 * p); 49 | void SetLineG3(LINE_G3 * p); 50 | void SetLineF4(LINE_F4 * p); 51 | void SetLineG4(LINE_G4 * p); 52 | void SetDrawTPage(DR_TPAGE *p,int dfe,int dtd,int tpage); 53 | 54 | extern u_char buffer; 55 | typedef struct{ 56 | DISPENV disp; 57 | DRAWENV draw; 58 | ulong ot[12]; 59 | }DB; 60 | extern DB * drawP; 61 | extern DB drawSettings[2]; 62 | 63 | extern SPRT_16 rectBuffer[2][1024]; 64 | extern int rectCount; 65 | 66 | extern int primP; 67 | extern int primCount; 68 | 69 | extern int tempPrimP; 70 | #endif 71 | -------------------------------------------------------------------------------- /games/Example_MegaManX4/include/layer.h: -------------------------------------------------------------------------------- 1 | #ifndef LAYER_H 2 | #define LAYER_H 3 | #include 4 | #include 5 | 6 | typedef unsigned char undefined; 7 | typedef unsigned char byte; 8 | typedef unsigned int dword; 9 | typedef char sbyte; 10 | typedef unsigned char undefined1; 11 | typedef unsigned short undefined2; 12 | typedef unsigned int undefined4; 13 | typedef unsigned short word; 14 | 15 | void AssignLayer(int layer); 16 | 17 | void DefaultLayers(); 18 | void DrawLayer(int layer); 19 | void DumpActiveScreens(); 20 | void DumpLayerScreens(int layer); //BG1-3 21 | 22 | void LoadTiles(int id,short x,short y); 23 | void LoadTiles2(int id,short x,short y); //Not Permanet 24 | 25 | void ResetLayerPointers(int layer); 26 | 27 | typedef struct{ 28 | int layer; 29 | ushort settings; // tttt ttti , T = TileCount I = Increament-X (if 1 Increament-X instead of Y) 30 | ushort destX; 31 | ushort destY; 32 | ushort pad; 33 | u_char*tableP; 34 | int proceed; 35 | } tilesetStruct; 36 | 37 | typedef struct { 38 | undefined field0_0x0; 39 | undefined field1_0x1; 40 | undefined field2_0x2; 41 | bool display; 42 | char type; 43 | undefined field5_0x5; 44 | undefined field6_0x6; 45 | undefined field7_0x7; 46 | undefined field8_0x8; 47 | undefined field9_0x9; 48 | short x; 49 | undefined field11_0xc; 50 | undefined field12_0xd; 51 | short y; 52 | undefined field14_0x10; 53 | undefined field15_0x11; 54 | undefined field16_0x12; 55 | undefined field17_0x13; 56 | undefined field18_0x14; 57 | undefined field19_0x15; 58 | short pastX; 59 | undefined field21_0x18; 60 | undefined field22_0x19; 61 | short pastY; 62 | short pastBorderR; 63 | short pastBorderL; 64 | short pastBorderB; 65 | short pastBorderT; 66 | short borderR; 67 | short borderL; 68 | short borderB; 69 | short borderT; 70 | undefined field32_0x2c; 71 | undefined field33_0x2d; 72 | undefined field34_0x2e; 73 | undefined field35_0x2f; 74 | undefined field36_0x30; 75 | undefined field37_0x31; 76 | undefined field38_0x32; 77 | undefined field39_0x33; 78 | undefined field40_0x34; 79 | undefined field41_0x35; 80 | undefined field42_0x36; 81 | undefined field43_0x37; 82 | undefined field44_0x38; 83 | undefined field45_0x39; 84 | undefined field46_0x3a; 85 | undefined field47_0x3b; 86 | undefined field48_0x3c; 87 | undefined field49_0x3d; 88 | undefined field50_0x3e; 89 | undefined field51_0x3f; 90 | short baseX; 91 | short baseY; 92 | bool enabled; 93 | undefined field55_0x45; 94 | undefined field56_0x46; 95 | undefined field57_0x47; 96 | undefined field58_0x48; 97 | undefined field59_0x49; 98 | byte normalOT; 99 | byte priorityOT; 100 | bool update; 101 | undefined field63_0x4d; 102 | undefined field64_0x4e; 103 | undefined field65_0x4f; 104 | undefined field66_0x50; 105 | undefined field67_0x51; 106 | undefined field68_0x52; 107 | undefined field69_0x53; 108 | } Layer; 109 | 110 | extern Layer bgLayers[3]; 111 | 112 | extern u_char layoutWidth; 113 | extern u_char layoutHeight; 114 | extern u_char layoutSize; 115 | #endif -------------------------------------------------------------------------------- /games/Example_MegaManX4/include/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef MISC_H 2 | #define MISC_H 3 | #include 4 | #include 5 | #include 6 | typedef unsigned char undefined; 7 | typedef unsigned char byte; 8 | typedef unsigned int dword; 9 | typedef char sbyte; 10 | typedef unsigned char undefined1; 11 | typedef unsigned short undefined2; 12 | typedef unsigned int undefined4; 13 | typedef unsigned short word; 14 | 15 | void LoadLevel(); 16 | 17 | void SetupLayerSettings(); 18 | void SetupPriority(); 19 | void SetupSpawn(); 20 | #endif -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/LOAD_U.ARC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_MegaManX4/mods/DebugTools/LOAD_U.ARC -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/LOAD_U.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_MegaManX4/mods/DebugTools/LOAD_U.BMP -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/buildlist.txt: -------------------------------------------------------------------------------- 1 | 2 | //North American Version 3 | 4 | american, exe, 0x80026648, 0x0, src/background.c 5 | 6 | american, exe, 0x80020040, 0x0, src/menuHook.s 7 | american, exe, 0x800ee558, 0x0, src/debugmenu.c src/exception.c , DEBUG_AND_EXCEPTION.bin 8 | 9 | american, exe, 0x80027e68, 0x0, src/exceptionNames.c 10 | american, exe, 0x80012cf8, 0x0, src/exceptionRegisters.c 11 | american, exe, 0x8001da70, 0x0, src/enableException.c 12 | american, exe, 0x8001c7cc, 0x0, src/exceptionHook.s 13 | 14 | //stupid game/pause menu 15 | american, exe, 0x80017100, 0x0, src/weaponMenu.c 16 | 17 | american, exe, 0x80020094, 0x0, src/resetCollision.s 18 | 19 | //debug font 20 | american, exe, 0x80026CEC, 0x0, src/debugfont/font.c 21 | american, exe, 0x80015a50, 0x0, src/debugfont/font2.c 22 | american, exe, 0x8001d074, 0x0, src/debugfont/loadfont.s 23 | american, exe, 0x800120f4, 0x0, src/debugfont/texthook.s 24 | 25 | //Japanese Version 26 | 27 | japan, exe, 0x8002669c, 0x0, src/background.c 28 | 29 | japan, exe, 0x80020088, 0x0, src/menuHook.s 30 | japan, exe, 0x800ee734, 0x0, src/debugmenu.c src/exception.c , DEBUG_AND_EXCEPTION.bin 31 | 32 | //TODO: find place to put this in the Japanese Version 33 | 34 | //american, exe, 0x80027e68, 0x0, src/exceptionNames.c 35 | //american, exe, 0x80012cf8, 0x0, src/exceptionRegisters.c 36 | //american, exe, 0x8001da70, 0x0, src/enableException.c 37 | //american, exe, 0x8001c7cc, 0x0, src/exceptionHook.s 38 | 39 | japan, exe, 0x80017134, 0x0, src/weaponMenu.c 40 | 41 | japan, exe, 0x800200dc, 0x0, src/resetCollision.s 42 | 43 | japan, exe, 0x80026d40, 0x0, src/debugfont/font.c 44 | japan, exe, 0x80015a84, 0x0, src/debugfont/font2.c 45 | japan, exe, 0x8001d0f4, 0x0, src/debugfont/loadfont.s 46 | japan, exe, 0x80012128, 0x0, src/debugfont/texthook.s -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/define.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(BUILD_ID),561) 2 | LDFLAGS += src/symbol.ld 3 | else 4 | LDFLAGS += src/symbol_jp.ld 5 | endif -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/fileList.txt: -------------------------------------------------------------------------------- 1 | american , LOAD_U.ARC , ARC/LOAD_U.ARC 2 | american , LOAD_U.BMP 3 | american , debug/redux.map -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/background.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tools.h" 5 | 6 | void ResetLayerBuffer(); 7 | void DrawDebugOverlay(); 8 | extern DebugTools tools; 9 | void NewDrawBackground() 10 | { 11 | tempPrimP = &rectBuffer[buffer][0]; 12 | rectCount = 0; 13 | if(!tools.enableCollision) 14 | { 15 | ResetLayerBuffer(); 16 | 17 | for (size_t i = 0; i < 3; i++) 18 | { 19 | if(bgLayers[i].update){ 20 | DumpLayerScreens(i); 21 | } 22 | } 23 | DumpActiveScreens(); 24 | /* 25 | * TODO: maybe add back Intro Blue Rect effect... 26 | */ 27 | for (size_t i = 0; i < 3; i++) 28 | { 29 | if(bgLayers[i].display) 30 | { 31 | ResetLayerPointers(i); 32 | DrawLayer(i); 33 | AssignLayer(i); 34 | } 35 | } 36 | }else 37 | { 38 | DrawDebugOverlay(); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/debugfont/font2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 2nd file due to a lack of space... 3 | */ 4 | #include 5 | #include 6 | 7 | #if BUILD == 561 8 | #define bufferSize 0x1058 //of single buffer 9 | #define textBufferAddress 0x80175f50 //before Arc Buffer 10 | #else 11 | #define bufferSize 0x1004 12 | #define textBufferAddress 0x80175ff8 13 | #endif 14 | 15 | #define maxTextCount ((bufferSize / 16) - 1) 16 | 17 | int debugTextCount = 0; 18 | char hexDigits[] = "0123456789ABCDEF"; 19 | char lowerhexDigits[] = "0123456789abcdef"; 20 | DR_TPAGE debugfontTPages[2]; 21 | 22 | void ResetDebugText() 23 | { 24 | DrawSync(0); 25 | debugTextCount = 0; 26 | } 27 | 28 | void DrawChar(char letter, int destX, int destY, byte clut) 29 | { 30 | if (debugTextCount < maxTextCount && letter != ' ') 31 | { 32 | letter -= 0x20; 33 | SPRT_8 *sp = (SPRT_8 *)(debugTextCount * 16 + textBufferAddress + (bufferSize * buffer)); 34 | setRGB0(sp, 128, 128, 128); 35 | setXY0(sp, destX, destY); // 32 Chars per row 36 | setUV0(sp, (letter & 0x1F) * 8, 0xE0 + (letter / 32) * 8); 37 | setClut(sp, 0x100 + clut * 16, 0x1F8); 38 | SetSprt8(sp); 39 | AddPrim(&debugfontTPages[buffer], sp); 40 | debugTextCount += 1; 41 | } 42 | } 43 | #undef maxTextCount 44 | #undef textBufferAddress 45 | #undef bufferSize -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/debugfont/loadfont.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | jal LoadDebugFont -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/debugfont/texthook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | jal ResetDebugText -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/enableException.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int exceptionDescriptor = 0; 4 | 5 | long EnableEvent(unsigned long event); 6 | 7 | void Exception(); 8 | 9 | void ExitCriticalSection(); 10 | 11 | long OpenEvent(unsigned long desc,long spec,long mode,long *func()); 12 | 13 | void EnableExceptionEvent() 14 | { 15 | exceptionDescriptor = OpenEvent(0xF0000010,0x1000,0x1000,Exception); 16 | ExitCriticalSection(); 17 | 18 | EnableEvent(exceptionDescriptor); 19 | } -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/exception.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | static struct Registers 4 | { 5 | int r[32]; 6 | int returnPC; 7 | int hi, lo; 8 | int SR; 9 | int cause; 10 | }; 11 | 12 | static struct Thread 13 | { 14 | int flags, flags2; 15 | struct Registers registers; 16 | int unknown[9]; 17 | }; 18 | 19 | void DrawDebugText(ushort x, ushort y, byte clut, char *textP, ...); 20 | void ResetDebugText(); 21 | 22 | extern int debugTextCount; 23 | 24 | extern char *namesOfExceptions[13]; 25 | extern char *namesOfRegisters[37]; 26 | 27 | 28 | void Exception() 29 | { 30 | struct Thread **process = *(int *)0x108; 31 | struct Thread *thread = *process; 32 | 33 | struct Thread storedThread; 34 | 35 | memcpy(&storedThread, thread, sizeof(struct Thread)); 36 | 37 | void (*exitCriticalSection)() = 0x800ede0c; 38 | exitCriticalSection(); 39 | ClearOTagR(&drawSettings[0].ot, 0xC); 40 | ClearOTagR(&drawSettings[1].ot, 0xC); 41 | 42 | while (1) 43 | { 44 | ResetDebugText(); 45 | VSync(0); 46 | PutDispEnv(&drawSettings[buffer].disp); 47 | PutDrawEnv(&drawSettings[buffer].draw); 48 | DrawOTag(&drawSettings[buffer].ot[11]); 49 | buffer ^= 1; 50 | drawP = &drawSettings[buffer]; 51 | ClearOTagR(&drawSettings[buffer].ot, 0xC); 52 | 53 | DrawDebugText(2, 2, 0, "EXCEPTION=%s", namesOfExceptions[(storedThread.registers.cause >> 2) & 0x1F]); 54 | 55 | // Show Register Values 56 | for (size_t i = 0; i < 37; i++) 57 | { 58 | int x = 4; 59 | int y = 4 + i; 60 | if (i > 19) 61 | { 62 | x = 16; 63 | y -= 20; 64 | } 65 | 66 | DrawDebugText(x, y, 1, "%s=%8X", namesOfRegisters[i], storedThread.registers.r[i]); 67 | 68 | // Get around buffer size limitations... 69 | if (debugTextCount > 33) 70 | { 71 | DrawOTag(&drawSettings[buffer].ot[11]); 72 | ResetDebugText(); 73 | ClearOTagR(&drawSettings[buffer].ot, 0xC); 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/exceptionHook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | jal EnableExceptionEvent -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/exceptionNames.c: -------------------------------------------------------------------------------- 1 | char *namesOfExceptions[13] = { 2 | "INT", "MOD", "TLBL", "TLBS", "AdEL", "AdES", "IBE", "DBE", 3 | "Syscall", "BP", "RI", "CpU", "Ov" 4 | }; -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/exceptionRegisters.c: -------------------------------------------------------------------------------- 1 | char *namesOfRegisters[37] = { 2 | "R0", "AT", "V0", "V1", "A0", "A1", "A2", "A3", 3 | "T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7", 4 | "S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7", 5 | "T8", "T9", "K0", "K1", "GP", "SP", "FP", "RA", 6 | "PC", "HI", "LO", "SR", "CS"}; -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/menuHook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | jal MenuCheck -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/resetCollision.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | jal ResetCollisionCheck -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/symbol.ld: -------------------------------------------------------------------------------- 1 | DetermineClear = 0x800200d4; 2 | 3 | EnableEvent = 0x800edd7c; 4 | ExitCriticalSection = 0x800ede0c; 5 | 6 | 7 | OpenEvent = 0x800edd3c; 8 | 9 | RunVarious = 0x80021158; -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/symbol_jp.ld: -------------------------------------------------------------------------------- 1 | DetermineClear = 0x8002011c; 2 | 3 | EnableEvent = 0x800edf58; 4 | ExitCriticalSection = 0x800edfe8; 5 | 6 | OpenEvent = 0x800edf18; 7 | 8 | RunVarious = 0x800211a4; -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/tools.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOLS_H 2 | #define TOOLS_H 3 | #include 4 | typedef struct 5 | { 6 | bool opended; 7 | u_char mode; 8 | u_char mode2; 9 | u_char mode3; 10 | 11 | //Keep These in exact order 12 | bool showPlayerPos; 13 | bool showScroll; 14 | bool enableCollision; 15 | bool enableHitbox; 16 | u_char hitboxType; 17 | bool showTrigger; //Camera Trigger 18 | /************/ 19 | } DebugTools; 20 | #endif -------------------------------------------------------------------------------- /games/Example_MegaManX4/mods/DebugTools/src/weaponMenu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if BUILD == 561 5 | #define menuTPage ((DR_TPAGE *)0x80139580) 6 | #else 7 | #define menuTPage ((DR_TPAGE *)0x801396a0) 8 | #endif 9 | 10 | void DrawWeaponMenuBackground() 11 | { 12 | SetDrawTPage(&menuTPage[buffer], 0, 0, GetTPageValue(0, 0, 13, 1)); 13 | AddPrim(&drawP->ot[10], &menuTPage[buffer]); 14 | 15 | volatile ushort *menuScreenP = ((int *)0x1f800034)[0]; 16 | volatile SPRT_16 *rect = &rectBuffer[buffer]; 17 | int count = 0; 18 | int baseX = 0; 19 | 20 | for (size_t s = 0; s < 2; s++) 21 | { 22 | baseX = s * 256; 23 | for (size_t y = 0; y < 16; y++) 24 | { 25 | for (size_t x = 0; x < 16; x++) 26 | { 27 | short drawX = x * 16 + baseX; 28 | short drawY = y * 16; 29 | if (drawX < 320) 30 | { 31 | ushort val = *menuScreenP; 32 | rect->code = 0x7D; 33 | *(char *)((int)&rect->tag + 3) = 3; 34 | setXY0(rect, drawX, drawY); 35 | setUV0(rect, ((val & 0xF) << 4), (val & 0xF0)); 36 | rect->clut = val >> 0xC | 0x7900; 37 | AddPrim(&menuTPage[buffer], rect); 38 | rect++; 39 | } 40 | menuScreenP++; 41 | } 42 | } 43 | } 44 | 45 | /********/ 46 | } 47 | #undef menuTPage 48 | #undef rectBufferAddress -------------------------------------------------------------------------------- /games/Example_MegaManX4/plugins/plugin.py: -------------------------------------------------------------------------------- 1 | def extract(plugin_path: str, game_path: str, game_version: str) -> None: 2 | pass 3 | 4 | def build(plugin_path: str, game_path: str, game_version: str) -> None: 5 | pass -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/common.txt: -------------------------------------------------------------------------------- 1 | buttonsHeld = 0x80166c08; 2 | buttonsPressed = 0x80166c0c; 3 | cursor = 0x80141bdf; 4 | fadeDirection = 0x80141bdc; 5 | frameCount = 0x80141bd8; 6 | freeArcP = 0x8015d9c8; 7 | game = 0x801721c0; 8 | 9 | ArcSeek = 0x80013ad8; 10 | BinSeek = 0x80013890; 11 | 12 | ClearAll = 0x8002a7d0; 13 | 14 | DrawLoad = 0x80014a90; 15 | DrawMain = 0x80023d68; 16 | DrawMMX4 = 0x80016124; 17 | EndSong = 0x80016f0c; 18 | 19 | FadeIn = 0x800129a4; 20 | FadeOut = 0x800129f0; 21 | fadeDirection = 0x80141bdc; 22 | FileCollect = 0x80014c70; 23 | PlaySong = 0x8001663c; 24 | PlaySound = 0x8001540c; 25 | 26 | strcpy = 0x800edc9c; 27 | memcpy = 0x800edcac; 28 | memset = 0x800edcbc; 29 | 30 | printf = 0x800edccc; 31 | 32 | SpawnText = 0x8002217c; 33 | 34 | NewThread = 0x80012740; 35 | ThreadSleep = 0x800127c8; 36 | DeleteThread = 0x800127fc; 37 | DeleteThread2 = 0x80012854; 38 | NewThread2 = 0x800128b8; -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/common_jp.txt: -------------------------------------------------------------------------------- 1 | buttonsHeld = 0x80166ce8; 2 | buttonsPressed = 0x80166cec; 3 | cursor = 0x80141cbf; 4 | fadeDirection = 0x80141cbc; 5 | freeArcP = 0x8015daa8; 6 | game = 0x80172278; 7 | 8 | 9 | 10 | ArcSeek = 0x80013b0c; 11 | BinSeek = 0x800138c4; 12 | 13 | ClearAll = 0x8002a824; 14 | 15 | DrawLoad = 0x80014ac4; 16 | DrawMain = 0x80023dbc; 17 | DrawMMX4 = 0x80016158; 18 | EndSong = 0x80016f40; 19 | 20 | FadeIn = 0x800129d8; 21 | FadeOut = 0x80012a24; 22 | 23 | FileCollect = 0x80014ca4; 24 | PlaySong = 0x80016670; 25 | PlaySound = 0x80015440; 26 | 27 | strcpy = 0x800ede78; 28 | memcpy = 0x800ede88; 29 | memset = 0x800ede98; 30 | 31 | printf = 0x800edea8; 32 | 33 | SpawnText = 0x800221c8; 34 | 35 | NewThread = 0x80012774; 36 | ThreadSleep = 0x800127fc; 37 | DeleteThread = 0x80012830; 38 | DeleteThread2 = 0x80012888; 39 | NewThread2 = 0x800128ec; -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/gpu.txt: -------------------------------------------------------------------------------- 1 | AddPrim = 0x800e9690; 2 | AddPrims = 0x800e96cc; 3 | 4 | CatPrim = 0x800e9708; 5 | ClearOTagR = 0x800ea714; 6 | 7 | DrawOTag = 0x800ea80c; 8 | 9 | DrawSync = 0x800ea20c; 10 | 11 | VSync = 0x800e4db0; 12 | 13 | ClearImage = 0x800ea3a0; 14 | ClearImage2 = 0x800ea434; 15 | LoadImage = 0x800ea4d0; 16 | StoreImage = 0x800ea534; 17 | MoveImage = 0x800ea598; 18 | 19 | PutDispEnv = 0x800eaad8; 20 | PutDrawEnv = 0x800ea880; 21 | 22 | SetDefDispEnv = 0x800e9424; 23 | SetDefDrawEnv = 0x800e9354; 24 | 25 | SetPolyF4 = 0x800e97e4; 26 | SetPolyFT4 = 0x800e97f8; 27 | SetPolyGT3 = 0x800e97d0; 28 | SetPolyG4 = 0x800e980c; 29 | SetPolyGT4 = 0x800e9820; 30 | SetSemiTrans = 0x800e9744; 31 | SetSprt8 = 0x800e9834; 32 | SetSprt16 = 0x800e9848; 33 | SetSprt = 0x800e985c; 34 | SetTile1 = 0x800e9870; 35 | SetTile8 = 0x800e9884; 36 | SetTile16 = 0x800e9898; 37 | SetTile = 0x800e98ac; 38 | SetLineF2 = 0x800e98c0; 39 | SetLineG2 = 0x800e98d4; 40 | SetLineF3 = 0x800e98e8; 41 | SetLineG3 = 0x800e9908; 42 | SetLineF4 = 0x800e9928; 43 | SetLineG4 = 0x800e9948; 44 | SetDrawTPage = 0x800e9968; 45 | 46 | 47 | buffer = 0x1f800000; 48 | 49 | drawP = 0x80142f80; 50 | drawSettings = 0x80166c10; 51 | 52 | rectBuffer = 0x8015d9d0; 53 | rectCount = 0x1f80011c; 54 | 55 | primP = 0x1f800100; 56 | primCount = 0x1f800124; 57 | 58 | tempPrimP = 0x1f800108; -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/gpu_jp.txt: -------------------------------------------------------------------------------- 1 | AddPrim = 0x800e986c; 2 | AddPrims = 0x800e98a8; 3 | 4 | CatPrim = 0x800e98e4; 5 | 6 | DrawSync = 0x800ea3e8; 7 | VSync = 0x800e4f8c; 8 | 9 | ClearImage = 0x800ea57c; 10 | ClearImage2 = 0x800ea610; 11 | LoadImage = 0x800ea6ac; 12 | StoreImage = 0x800ea710; 13 | MoveImage = 0x800ea774; 14 | 15 | SetPolyF4 = 0x800e99c0; 16 | SetPolyFT4 = 0x800e99d4; 17 | SetPolyGT3 = 0x800e99ac; 18 | SetPolyG4 = 0x800e99e8; 19 | SetPolyGT4 = 0x800e99fc; 20 | SetSemiTrans = 0x800e9920; 21 | SetSprt8 = 0x800e9a10; 22 | SetSprt16 = 0x800e9a24; 23 | SetSprt = 0x800e9a38; 24 | SetTile1 = 0x800e9a4c; 25 | SetTile8 = 0x800e9a60; 26 | SetTile16 = 0x800e9a74; 27 | SetTile = 0x800e9a88; 28 | SetLineF2 = 0x800e9a9c; 29 | SetLineG2 = 0x800e9ab0; 30 | SetLineF3 = 0x800e9ac4; 31 | SetLineG3 = 0x800e9ae4; 32 | SetLineF4 = 0x800e9b04; 33 | SetLineG4 = 0x800e9b24; 34 | SetDrawTPage = 0x800e9b44; 35 | 36 | /*Variables*/ 37 | buffer = 0x1f800000; 38 | 39 | drawP = 0x80143060; 40 | drawSettings = 0x80143060; 41 | 42 | rectBuffer = 0x8015dab0; 43 | rectCount = 0x1f80011c; 44 | 45 | primP = 0x1f800100; 46 | primCount = 0x1f800124; 47 | 48 | tempPrimP = 0x1f800108; -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/layer.txt: -------------------------------------------------------------------------------- 1 | AssignLayer = 0x80026894; 2 | 3 | DefaultLayers = 0x8001d134; 4 | DrawLayer = 0x80026aa0; 5 | DumpActiveScreens = 0x8002728c; 6 | DumpLayerScreens = 0x800262b8; 7 | 8 | 9 | LoadTiles = 0x800dabe4; 10 | LoadTiles2 = 0x800da984; 11 | 12 | ResetLayerPointers = 0x800267d4; 13 | 14 | bgLayers = 0x801419b0; 15 | layoutWidth = 0x80172224; 16 | layoutHeight = 0x80173a28; 17 | -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/layer_jp.txt: -------------------------------------------------------------------------------- 1 | AssignLayer = 0x800268e8; 2 | 3 | DrawLayer = 0x80026af4; 4 | DumpActiveScreens = 0x800272e0; 5 | DumpLayerScreens = 0x8002630c; 6 | 7 | 8 | LoadTiles = 0x800dadc0; 9 | LoadTiles2 = 0x800dab60; 10 | 11 | ResetLayerPointers = 0x80026828; 12 | 13 | 14 | /*Variables*/ 15 | bgLayers = 0x80141a90; 16 | layoutWidth = 0x801722dc; 17 | layoutHeight = 0x80173ae0; 18 | -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/misc.txt: -------------------------------------------------------------------------------- 1 | LoadLevel = 0x80013014; 2 | 3 | SetupLayerSettings = 0x80023ce0; 4 | SetupPriority = 0x8002771c; 5 | SetupSpawn = 0x80028bf0; -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/misc_jp.txt: -------------------------------------------------------------------------------- 1 | LoadLevel = 0x80013048; 2 | -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/object.txt: -------------------------------------------------------------------------------- 1 | AnimeAdvance = 0x80015dc8; 2 | CollideCheck = 0x8002c614; 3 | 4 | ContactMega = 0x8002d9bc; 5 | ContactWeapon = 0x8002dd04; 6 | ContactObject = 0x8002bb80; 7 | ContactObject2 = 0x8002c160; 8 | 9 | DeleteObject = 0x8002b0c8; 10 | DeleteObject2 = 0x8002b108; 11 | DeleteObject3 = 0x8002b13c; 12 | DisplayObject = 0x8002b288; 13 | DisplayObject2 = 0x8002b318; 14 | DisplayObject3 = 0x8002b3c0; 15 | 16 | DrawSpites = 0x80023db8; 17 | 18 | GetEffectObject = 0x8002ad7c; 19 | GetMainObject = 0x8002ab74; 20 | GetMiscObject = 0x8002ae50; 21 | GetVisualObject = 0x8002ad3c; 22 | GetItemObject = 0x8002adbc; 23 | GetShotObject = 0x8002aca4; 24 | 25 | GetRNG = 0x8002b73c; 26 | 27 | LockMega = 0x80036ae4; 28 | 29 | MoveObject = 0x8002b694; 30 | MoveObject2 = 0x8002b718; 31 | 32 | OffScreenCheck = 0x8002b160; 33 | OffScreenCheck2 = 0x8002b1e8; 34 | 35 | PlayBossSong = 0x8009227c; 36 | SetAnime = 0x80015d60; 37 | SetAnimeFrame = 0x80015d90; 38 | UnlockMega = 0x80036b18; 39 | 40 | SpawnExplosion = 0x800af808; 41 | SpawnJunk = 0x800c813c; 42 | 43 | mega = 0x801418c8; -------------------------------------------------------------------------------- /games/Example_MegaManX4/symbols/object_jp.txt: -------------------------------------------------------------------------------- 1 | 2 | PlayBossSong = 0x800922c8; 3 | 4 | mega = 0x801419a8; -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/build/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_SpyroRiptosRage/build/.gitignore -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compiler": { 3 | "function_sections": 1, 4 | "reorder_functions": 1, 5 | "optimization": 4, 6 | "debug": 0, 7 | "psyq": 0, 8 | "mininoob": 0, 9 | "8mb": 0 10 | }, 11 | "versions": [ 12 | { 13 | "american": { 14 | "name": "spyro2.bin", 15 | "symbols": [ 16 | "american.txt" 17 | ], 18 | "build_id": 94425 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/disc.json: -------------------------------------------------------------------------------- 1 | { 2 | "american": [ 3 | { 4 | "SCUS_944.25": [ 5 | { 6 | "name": "header", 7 | "address": "0x8000B070", 8 | "offset": "0x0" 9 | }, 10 | { 11 | "name": "exe", 12 | "address": "0x80010000", 13 | "offset": "0x800" 14 | } 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | struct Vec3 5 | { 6 | int x; 7 | int z; 8 | int y; 9 | }; 10 | 11 | int sprintf(char * str, char * format, ...); 12 | void DrawText(char * text, int x, int y, int colorIndex, int * unk); 13 | 14 | extern struct Vec3 speed; 15 | extern int gameMode; 16 | 17 | #endif -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/buildList.txt: -------------------------------------------------------------------------------- 1 | american, exe, 0x8001bdc4, 0x0, src/hook.s 2 | american, header, 0x8000B0B8, 0x0, src/main.c src/math.c, speedometer.bin -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/newtex/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/games/Example_SpyroRiptosRage/mods/Speedometer/newtex/.gitignore -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/src/hook.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | j DrawSpeedometer 3 | -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "math.h" 3 | 4 | void DrawSpeedometer() 5 | { 6 | if (gameMode == 0) 7 | { 8 | unsigned int horSpeed = (unsigned int) ((speed.x * speed.x) + (speed.z * speed.z)); 9 | horSpeed = sqrt(horSpeed); 10 | int verSpeed = speed.y; 11 | char buffer[64]; 12 | sprintf(buffer, "Hor Speed: %u", horSpeed); 13 | DrawText(buffer, 0xB0, 0x15, 1, 0); 14 | sprintf(buffer, "Ver Speed: %d", verSpeed); 15 | DrawText(buffer, 0xB0, 0x25, 1, 0); 16 | } 17 | } -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/src/math.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | // Square root of integer 4 | // https://en.wikipedia.org/wiki/Integer_square_root 5 | unsigned int sqrt(unsigned int s) 6 | { 7 | unsigned int x0 = s / 2; // Initial estimate 8 | // Avoid overflow when s is the maximum representable value 9 | 10 | // Sanity check 11 | if ( x0 != 0 ) 12 | { 13 | unsigned int x1 = ( x0 + s / x0 ) / 2; // Update 14 | 15 | while ( x1 < x0 ) // This also checks for cycle 16 | { 17 | x0 = x1; 18 | x1 = ( x0 + s / x0 ) / 2; 19 | } 20 | 21 | return x0; 22 | } 23 | else 24 | { 25 | return s; 26 | } 27 | } -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/mods/Speedometer/src/math.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H 2 | #define MATH_H 3 | 4 | unsigned int sqrt(unsigned int s); 5 | 6 | #endif -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/plugins/plugin.py: -------------------------------------------------------------------------------- 1 | def extract(plugin_path: str, game_path: str, version: str) -> None: 2 | pass 3 | 4 | def build(plugin_path: str, game_path: str, version: str) -> None: 5 | pass -------------------------------------------------------------------------------- /games/Example_SpyroRiptosRage/symbols/american.txt: -------------------------------------------------------------------------------- 1 | sprintf = 0x800594ac; 2 | DrawText = 0x8004a374; 3 | 4 | speed = 0x8006a090; 5 | gameMode = 0x800681c8; -------------------------------------------------------------------------------- /games/STARTUP.BAT: -------------------------------------------------------------------------------- 1 | python ../tools/startup/startup.py 0 -------------------------------------------------------------------------------- /games/STARTUP.SH: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | python3 ../tools/startup/startup.py 0 -------------------------------------------------------------------------------- /games/common.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | PYTHON = python 3 | else ifeq ($(shell which python3),) 4 | PYTHON = python 5 | else 6 | PYTHON = python3 7 | endif 8 | 9 | THISDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 10 | TOOLSDIR = $(THISDIR)../tools/ 11 | 12 | CPPFLAGS += -I$(TOOLSDIR)nugget/common/macros/ 13 | CPPFLAGS += -I$(GAMEINCLUDEDIR) 14 | CPPFLAGS += -I$(MODDIR) 15 | CPPFLAGS += -I$(MODDIR)/src/ 16 | 17 | ifeq ($(USE_MININOOB),true) 18 | CPPFLAGS += -I$(TOOLSDIR)minin00b/include/ 19 | LDFLAGS += -L$(TOOLSDIR)minin00b/lib/ 20 | LDFLAGS += -Wl,--start-group 21 | LDFLAGS += -l:libc.a 22 | LDFLAGS += -l:psxcd.a 23 | LDFLAGS += -l:psxetc.a 24 | LDFLAGS += -l:psxgpu.a 25 | LDFLAGS += -l:psxgte.a 26 | LDFLAGS += -l:psxpress.a 27 | LDFLAGS += -l:psxsio.a 28 | LDFLAGS += -l:psxspu.a 29 | LDFLAGS += -l:psxapi.a 30 | LDFLAGS += -Wl,--end-group 31 | endif 32 | 33 | ifeq ($(USE_PSYQ),true) 34 | CPPFLAGS += -I$(TOOLSDIR)gcc-psyq-converted/include/ 35 | LDFLAGS += -L$(TOOLSDIR)gcc-psyq-converted/lib/ 36 | LDFLAGS += -Wl,--start-group 37 | LDFLAGS += -lapi 38 | LDFLAGS += -lc 39 | LDFLAGS += -lc2 40 | LDFLAGS += -lcard 41 | LDFLAGS += -lcomb 42 | LDFLAGS += -lds 43 | LDFLAGS += -letc 44 | LDFLAGS += -lgpu 45 | LDFLAGS += -lgs 46 | LDFLAGS += -lgte 47 | LDFLAGS += -lgun 48 | LDFLAGS += -lhmd 49 | LDFLAGS += -lmath 50 | LDFLAGS += -lmcrd 51 | LDFLAGS += -lmcx 52 | LDFLAGS += -lpad 53 | LDFLAGS += -lpress 54 | LDFLAGS += -lsio 55 | LDFLAGS += -lsnd 56 | LDFLAGS += -lspu 57 | LDFLAGS += -ltap 58 | LDFLAGS += -lcd 59 | LDFLAGS += -Wl,--end-group 60 | endif 61 | 62 | include $(TOOLSDIR)nugget/common.mk -------------------------------------------------------------------------------- /games/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "redux": { 3 | "port": 8080, 4 | "path": "C:/path/to/redux/" 5 | }, 6 | "nops": { 7 | "comport": "COM5", 8 | "mode": "fast" 9 | } 10 | } -------------------------------------------------------------------------------- /games/startup_game.json: -------------------------------------------------------------------------------- 1 | { 2 | "game_name": "game_name", 3 | "symbols": [ 4 | "functions.txt", 5 | "variables.txt" 6 | ], 7 | "versions": [ 8 | { 9 | "usa": { 10 | "build_id": 94426, 11 | "game_path": "path/to/usa_game.bin" 12 | } 13 | }, 14 | { 15 | "japan": { 16 | "build_id": 1111, 17 | "game_path": "path/to/japan_game.bin" 18 | } 19 | } 20 | ], 21 | "compiler": { 22 | "reorder_functions": 1, 23 | "optimization": 4, 24 | "debug": 1, 25 | "psyq": 0, 26 | "mininoob": 0, 27 | "8mb": 1 28 | } 29 | } -------------------------------------------------------------------------------- /install_toolchain_prebuilt.sh: -------------------------------------------------------------------------------- 1 | 2 | # Update host machine built-ins 3 | apt-get update 4 | apt-get -y upgrade 5 | # install dependencies 6 | apt-get -y install build-essential curl git pkg-config cmake texinfo libmpfr-dev libisl-dev libgmp-dev libmpc-dev libtinyxml2-dev unzip wget 7 | apt-get -y install python3 python3-pip python3-dev libgl1 8 | 9 | cd $RUNTIME_DIR 10 | echo $PWD 11 | # Get the latest binary 12 | # TODO: Stop mixing wget and curl 13 | wget $(curl -s https://api.github.com/repos/Lameguy64/PSn00bSDK/releases/latest | grep browser_download_url | cut -d\" -f4 | grep 'linux.zip') 14 | 15 | # Extract to the /opt folder 16 | find . -type f -name "gcc-mipsel-none-elf-*.zip" | xargs unzip -d "/opt/gcc-mipsel-none-elf/" -q 17 | 18 | # Add binaries to PATH 19 | echo "Prebuilt binaries installed in /opt" -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools 2 | wheel 3 | requests 4 | opencv-python 5 | pillow 6 | pymkpsxiso 7 | pyxdelta 8 | pytest 9 | -------------------------------------------------------------------------------- /tools/gcc-psyq-converted/include/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/gcc-psyq-converted/include/.gitignore -------------------------------------------------------------------------------- /tools/gcc-psyq-converted/lib/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/gcc-psyq-converted/lib/.gitignore -------------------------------------------------------------------------------- /tools/macos-mips/mipsel-none-elf-binutils.rb: -------------------------------------------------------------------------------- 1 | class MipselNoneElfBinutils < Formula 2 | desc "FSF Binutils for mipsel cross development" 3 | homepage "https://www.gnu.org/software/binutils/" 4 | url "https://ftp.gnu.org/gnu/binutils/binutils-2.40.tar.gz" 5 | sha256 "d7f82c4047decf43a6f769ac32456a92ddb6932409a585c633cdd4e9df23d956" 6 | 7 | depends_on "texinfo" => :build 8 | 9 | def install 10 | system "./configure", "--target=mipsel-none-elf", 11 | "--disable-multilib", 12 | "--disable-nls", 13 | "--disable-werror", 14 | "--prefix=#{prefix}" 15 | system "make" 16 | system "make", "install-strip" 17 | end 18 | test do 19 | assert_match "f()", shell_output("#{bin}/mipsel-none-elf-c++filt _Z1fv") 20 | end 21 | end -------------------------------------------------------------------------------- /tools/macos-mips/mipsel-none-elf-gcc.rb: -------------------------------------------------------------------------------- 1 | class MipselNoneElfGcc < Formula 2 | desc "The GNU compiler collection for mipsel" 3 | homepage "https://gcc.gnu.org" 4 | url "https://ftp.gnu.org/gnu/gcc/gcc-13.1.0/gcc-13.1.0.tar.xz" 5 | sha256 "61d684f0aa5e76ac6585ad8898a2427aade8979ed5e7f85492286c4dfc13ee86" 6 | 7 | depends_on "gmp" 8 | depends_on "mipsel-none-elf-binutils" 9 | depends_on "libmpc" 10 | depends_on "mpfr" 11 | depends_on "gnu-sed" 12 | 13 | def install 14 | ENV.prepend_path "PATH", Formula["gnu-sed"].opt_libexec/"gnubin" 15 | mkdir "mipsel-none-elf-gcc-build" do 16 | system "../configure", "--target=mipsel-none-elf", 17 | "--prefix=#{prefix}", 18 | "--without-isl", 19 | "--disable-nls", 20 | "--disable-threads", 21 | "--disable-shared", 22 | "--disable-libssp", 23 | "--disable-libstdcxx-pch", 24 | "--disable-libgomp", 25 | "--disable-werror", 26 | "--without-headers", 27 | "--disable-hosted-libstdcxx", 28 | "--with-as=#{Formula["mipsel-none-elf-binutils"].bin}/mipsel-none-elf-as", 29 | "--with-ld=#{Formula["mipsel-none-elf-binutils"].bin}/mipsel-none-elf-ld", 30 | "--enable-languages=c,c++" 31 | system "make", "all-gcc" 32 | system "make", "install-strip-gcc" 33 | system "make", "all-target-libgcc" 34 | system "make", "install-strip-target-libgcc" 35 | system "make", "all-target-libstdc++-v3" 36 | system "make", "install-strip-target-libstdc++-v3" 37 | end 38 | end 39 | 40 | test do 41 | (testpath/"test-c.c").write <<~EOS 42 | int main(void) 43 | { 44 | int i=0; 45 | while(i<10) i++; 46 | return i; 47 | } 48 | EOS 49 | system "#{bin}/mipsel-none-elf-gcc", "-c", "-o", "test-c.o", "test-c.c" 50 | end 51 | end -------------------------------------------------------------------------------- /tools/minin00b/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= mipsel-none-elf 2 | FORMAT ?= elf32-littlemips 3 | 4 | CC = $(PREFIX)-gcc 5 | CXX = $(PREFIX)-g++ 6 | AR = $(PREFIX)-ar 7 | 8 | ARCHFLAGS = -march=mips1 -mabi=32 -EL -fno-pic -mno-shared -mno-abicalls -mfp32 9 | ARCHFLAGS += -fno-stack-protector -nostdlib -ffreestanding 10 | 11 | CPPFLAGS += -O2 -Iinclude/ 12 | CPPFLAGS += -mno-gpopt -fomit-frame-pointer -ffunction-sections -fdata-sections 13 | CPPFLAGS += -fno-builtin -fno-strict-aliasing -Wno-attributes -Wextra 14 | CPPFLAGS += $(ARCHFLAGS) 15 | CXXFLAGS += -fno-exceptions -fno-rtti 16 | 17 | all: libc.a psxcd.a psxetc.a psxgpu.a psxgte.a psxpress.a psxsio.a psxspu.a psxapi.a 18 | 19 | libc.a: libc_misc.o libc_scanf.o libc_string.o libc_vsprintf.o libc_clz.o libc_memset.o libc_setjmp.o 20 | $(AR) rcs lib/$@ $^ 21 | 22 | psxcd.a: psxcd_cdread.o psxcd_common.o psxcd_isofs.o psxcd_misc.o 23 | $(AR) rcs lib/$@ $^ 24 | 25 | psxetc.a: psxetc_interrupts.o 26 | $(AR) rcs lib/$@ $^ 27 | 28 | psxgpu.a: psxgpu_common.o psxgpu_drawing.o psxgpu_env.o psxgpu_font.o psxgpu_image.o 29 | $(AR) rcs lib/$@ $^ 30 | 31 | psxgte.a: psxgte_isin.o psxgte_matrixc.o psxgte_initgeom.o psxgte_matrixs.o psxgte_squareroot.o psxgte_vector.o 32 | $(AR) rcs lib/$@ $^ 33 | 34 | psxpress.a: psxpress_mdec.o psxpress_vlcc.o psxpress_vlc2.o psxpress_vlcs.o 35 | $(AR) rcs lib/$@ $^ 36 | 37 | psxsio.a: psxsio_sio.o psxsio_tty.o 38 | $(AR) rcs lib/$@ $^ 39 | 40 | psxspu.a: psxspu_common.o 41 | $(AR) rcs lib/$@ $^ 42 | 43 | psxapi.a: psxapi_drivers.o psxapi_fs.o psxapi_stdio.o psxapi_sys.o psxapi__syscalls.o 44 | $(AR) rcs lib/$@ $^ 45 | 46 | libc_misc.o: libc/misc.c 47 | $(CC) $(CPPFLAGS) -c -o $@ $^ 48 | 49 | libc_scanf.o: libc/scanf.c 50 | $(CC) $(CPPFLAGS) -c -o $@ $^ 51 | 52 | libc_string.o: libc/string.c 53 | $(CC) $(CPPFLAGS) -c -o $@ $^ 54 | 55 | libc_vsprintf.o: libc/vsprintf.c 56 | $(CC) $(CPPFLAGS) -c -o $@ $^ 57 | 58 | psxcd_cdread.o: psxcd/cdread.c 59 | $(CC) $(CPPFLAGS) -c -o $@ $^ 60 | 61 | psxcd_common.o: psxcd/common.c 62 | $(CC) $(CPPFLAGS) -c -o $@ $^ 63 | 64 | psxcd_isofs.o: psxcd/isofs.c 65 | $(CC) $(CPPFLAGS) -c -o $@ $^ 66 | 67 | psxcd_misc.o: psxcd/misc.c 68 | $(CC) $(CPPFLAGS) -c -o $@ $^ 69 | 70 | psxetc_interrupts.o: psxetc/interrupts.c 71 | $(CC) $(CPPFLAGS) -c -o $@ $^ 72 | 73 | psxgpu_common.o: psxgpu/common.c 74 | $(CC) $(CPPFLAGS) -c -o $@ $^ 75 | 76 | psxgpu_drawing.o: psxgpu/drawing.c 77 | $(CC) $(CPPFLAGS) -c -o $@ $^ 78 | 79 | psxgpu_env.o: psxgpu/env.c 80 | $(CC) $(CPPFLAGS) -c -o $@ $^ 81 | 82 | psxgpu_font.o: psxgpu/font.c 83 | $(CC) $(CPPFLAGS) -c -o $@ $^ 84 | 85 | psxgpu_image.o: psxgpu/image.c 86 | $(CC) $(CPPFLAGS) -c -o $@ $^ 87 | 88 | psxgte_isin.o: psxgte/isin.c 89 | $(CC) $(CPPFLAGS) -c -o $@ $^ 90 | 91 | psxgte_matrixc.o: psxgte/matrix.c 92 | $(CC) $(CPPFLAGS) -c -o $@ $^ 93 | 94 | psxpress_mdec.o: psxpress/mdec.c 95 | $(CC) $(CPPFLAGS) -c -o $@ $^ 96 | 97 | psxpress_vlcc.o: psxpress/vlc.c 98 | $(CC) $(CPPFLAGS) -c -o $@ $^ 99 | 100 | psxpress_vlc2.o: psxpress/vlc2.c 101 | $(CC) $(CPPFLAGS) -c -o $@ $^ 102 | 103 | psxsio_sio.o: psxsio/sio.c 104 | $(CC) $(CPPFLAGS) -c -o $@ $^ 105 | 106 | psxsio_tty.o: psxsio/tty.c 107 | $(CC) $(CPPFLAGS) -c -o $@ $^ 108 | 109 | psxspu_common.o: psxspu/common.c 110 | $(CC) $(CPPFLAGS) -c -o $@ $^ 111 | 112 | libc_clz.o: libc/clz.s 113 | $(CC) $(CPPFLAGS) -c -o $@ $^ 114 | 115 | libc_memset.o: libc/memset.s 116 | $(CC) $(CPPFLAGS) -c -o $@ $^ 117 | 118 | libc_setjmp.o: libc/setjmp.s 119 | $(CC) $(CPPFLAGS) -c -o $@ $^ 120 | 121 | psxapi_drivers.o: psxapi/drivers.s 122 | $(CC) $(CPPFLAGS) -c -o $@ $^ 123 | 124 | psxapi_fs.o: psxapi/fs.s 125 | $(CC) $(CPPFLAGS) -c -o $@ $^ 126 | 127 | psxapi_stdio.o: psxapi/stdio.s 128 | $(CC) $(CPPFLAGS) -c -o $@ $^ 129 | 130 | psxapi_sys.o: psxapi/sys.s 131 | $(CC) $(CPPFLAGS) -c -o $@ $^ 132 | 133 | psxapi__syscalls.o: psxapi/_syscalls.s 134 | $(CC) $(CPPFLAGS) -c -o $@ $^ 135 | 136 | psxgte_initgeom.o: psxgte/initgeom.s 137 | $(CC) $(CPPFLAGS) -c -o $@ $^ 138 | 139 | psxgte_matrixs.o: psxgte/matrix.s 140 | $(CC) $(CPPFLAGS) -c -o $@ $^ 141 | 142 | psxgte_squareroot.o: psxgte/squareroot.s 143 | $(CC) $(CPPFLAGS) -c -o $@ $^ 144 | 145 | psxgte_vector.o: psxgte/vector.s 146 | $(CC) $(CPPFLAGS) -c -o $@ $^ 147 | 148 | psxpress_vlcs.o: psxpress/vlc.s 149 | $(CC) $(CPPFLAGS) -c -o $@ $^ 150 | 151 | objclean: 152 | rm *.o 153 | 154 | clean: 155 | rm *.o lib/*.a -------------------------------------------------------------------------------- /tools/minin00b/README.md: -------------------------------------------------------------------------------- 1 | # Minin00b 2 | Minin00b is a fork of [PSn00bSDK](https://github.com/Lameguy64/PSn00bSDK) source code, slighly modified and compiled to generate minimal libraries to use for modding purposes with the psx-mooding-toolchain. -------------------------------------------------------------------------------- /tools/minin00b/gen_makefile.py: -------------------------------------------------------------------------------- 1 | from glob import glob 2 | 3 | files = glob("*/*.c") + glob("*/*.s") 4 | files = [file.replace("\\", "/") for file in files] 5 | libs = {} 6 | buffer = "" 7 | 8 | for file in files: 9 | lib, filename = file.split("/") 10 | obj_file = lib + "_" + filename[:-2] + ".o" 11 | if lib in libs: 12 | libs[lib].append(obj_file) 13 | else: 14 | libs[lib] = [obj_file] 15 | buffer += obj_file + ": " + file + "\n" 16 | buffer += "\t" + "$(CC) $(CPPFLAGS) -c -o $@ $^\n\n" 17 | 18 | for key in libs: 19 | objs = libs[key] 20 | buffer += key + ".a: " + " ".join(objs) + "\n" 21 | buffer += "\t" + "$(AR) rcs lib/$@ $^\n\n" 22 | 23 | print(buffer) -------------------------------------------------------------------------------- /tools/minin00b/include/assert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK assert macro and internal logging 3 | * (C) 2022-2023 spicyjpeg - MPL licensed 4 | * 5 | * The _sdk_*() macros are used internally by PSn00bSDK to output messages when 6 | * building in debug mode. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | void _assert_abort(const char *file, int line, const char *expr); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #define NDEBUG 24 | #ifdef NDEBUG 25 | 26 | #define assert(expr) 27 | #define _sdk_log(fmt, ...) 28 | #define _sdk_assert(expr, fmt, ...) 29 | #define _sdk_validate_args_void(expr) 30 | #define _sdk_validate_args(expr, ret) 31 | 32 | #else 33 | 34 | #define assert(expr) \ 35 | ((expr) ? ((void) 0) : _assert_abort(__FILE__, __LINE__, #expr)) 36 | 37 | #ifdef SDK_LIBRARY_NAME 38 | #define _sdk_log(fmt, ...) \ 39 | printf(SDK_LIBRARY_NAME ": " fmt __VA_OPT__(,) __VA_ARGS__) 40 | #else 41 | #define _sdk_log(fmt, ...) \ 42 | printf(fmt __VA_OPT__(,) __VA_ARGS__) 43 | #endif 44 | 45 | #define _sdk_assert(expr, ret, fmt, ...) \ 46 | if (!(expr)) { \ 47 | _sdk_log(fmt, __VA_ARGS__); \ 48 | return ret; \ 49 | } 50 | #define _sdk_validate_args_void(expr) \ 51 | if (!(expr)) { \ 52 | _sdk_log("invalid args to %s() (%s)\n", __func__, #expr); \ 53 | return; \ 54 | } 55 | #define _sdk_validate_args(expr, ret) \ 56 | if (!(expr)) { \ 57 | _sdk_log("invalid args to %s() (%s)\n", __func__, #expr); \ 58 | return ret; \ 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /tools/minin00b/include/ctype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2019-2023 PSXSDK authors, Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | int isprint(int ch); 13 | int isgraph(int ch); 14 | int isspace(int ch); 15 | int isblank(int ch); 16 | int isalpha(int ch); 17 | int isdigit(int ch); 18 | 19 | int tolower(int ch); 20 | int toupper(int ch); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /tools/minin00b/include/gtereg.inc: -------------------------------------------------------------------------------- 1 | # GTE register definitions for GNU assembler (as). 2 | # 3 | # Part of the PSn00bSDK Project by Lameguy64. 4 | # 2019 Meido-Tek Productions 5 | 6 | # 7 | # GTE data registers (use mfc2, mtc2, lwc2, swc2) 8 | # 9 | .set C2_VXY0, $0 10 | .set C2_VZ0, $1 11 | .set C2_VXY1, $2 12 | .set C2_VZ1, $3 13 | .set C2_VXY2, $4 14 | .set C2_VZ2, $5 15 | .set C2_RGB, $6 16 | .set C2_OTZ, $7 17 | 18 | .set C2_IR0, $8 19 | .set C2_IR1, $9 20 | .set C2_IR2, $10 21 | .set C2_IR3, $11 22 | .set C2_SXY0, $12 23 | .set C2_SXY1, $13 24 | .set C2_SXY2, $14 25 | .set C2_SXYP, $15 26 | 27 | .set C2_SZ0, $16 28 | .set C2_SZ1, $17 29 | .set C2_SZ2, $18 30 | .set C2_SZ3, $19 31 | .set C2_RGB0, $20 32 | .set C2_RGB1, $21 33 | .set C2_RGB2, $22 34 | 35 | .set C2_MAC0, $24 36 | .set C2_MAC1, $25 37 | .set C2_MAC2, $26 38 | .set C2_MAC3, $27 39 | .set C2_IRGB, $28 40 | .set C2_ORGB, $29 41 | .set C2_LZCS, $30 42 | .set C2_LZCR, $31 43 | 44 | # 45 | # GTE control registers (use cfc2/ctc2) 46 | # 47 | .set C2_R11R12, $0 48 | .set C2_R13R21, $1 49 | .set C2_R22R23, $2 50 | .set C2_R31R32, $3 51 | .set C2_R33, $4 52 | .set C2_TRX, $5 53 | .set C2_TRY, $6 54 | .set C2_TRZ, $7 55 | 56 | .set C2_L11L12, $8 57 | .set C2_L13L21, $9 58 | .set C2_L22L23, $10 59 | .set C2_L31L32, $11 60 | .set C2_L33, $12 61 | .set C2_RBK, $13 62 | .set C2_GBK, $14 63 | .set C2_BBK, $15 64 | 65 | .set C2_LR1LR2, $16 66 | .set C2_LR3LG1, $17 67 | .set C2_LG2LG3, $18 68 | .set C2_LB1LB2, $19 69 | .set C2_LB3, $20 70 | .set C2_RFC, $21 71 | .set C2_GFC, $22 72 | .set C2_BFC, $23 73 | 74 | .set C2_OFX, $24 75 | .set C2_OFY, $25 76 | .set C2_H, $26 77 | .set C2_DQA, $27 78 | .set C2_DQB, $28 79 | .set C2_ZSF3, $29 80 | .set C2_ZSF4, $30 81 | .set C2_FLAG, $31 82 | -------------------------------------------------------------------------------- /tools/minin00b/include/hwregs_a.inc: -------------------------------------------------------------------------------- 1 | # PSn00bSDK hardware registers definitions 2 | # (C) 2019-2022 Lameguy64, spicyjpeg - MPL licensed 3 | 4 | ## Constants 5 | 6 | .set IOBASE, 0xbf80 7 | .set EXP1BASE, 0xbf00 8 | 9 | .set F_CPU, 33868800 10 | .set F_GPU, 53222400 11 | 12 | ## GPU 13 | 14 | .set GPU_GP0, 0x1810 # Also GPUREAD 15 | .set GPU_GP1, 0x1814 # Also GPUSTAT 16 | 17 | ## CD drive 18 | 19 | .set CD_STAT, 0x1800 20 | .set CD_CMD, 0x1801 # Also response FIFO 21 | .set CD_DATA, 0x1802 # Also parameters 22 | .set CD_IRQ, 0x1803 23 | 24 | .set CD_REG0, 0x1800 25 | .set CD_REG1, 0x1801 26 | .set CD_REG2, 0x1802 27 | .set CD_REG3, 0x1803 28 | 29 | ## SPU 30 | 31 | .set SPU_VOICE_BASE, 0x1c00 32 | 33 | .set SPU_MASTER_VOL_L, 0x1d80 34 | .set SPU_MASTER_VOL_R, 0x1d82 35 | .set SPU_REVERB_VOL_L, 0x1d84 36 | .set SPU_REVERB_VOL_R, 0x1d86 37 | .set SPU_KEY_ON1, 0x1d88 38 | .set SPU_KEY_ON1, 0x1d8a 39 | .set SPU_KEY_OFF1, 0x1d8c 40 | .set SPU_KEY_OFF2, 0x1d8e 41 | .set SPU_FM_MODE1, 0x1d90 42 | .set SPU_FM_MODE2, 0x1d92 43 | .set SPU_NOISE_MODE1, 0x1d94 44 | .set SPU_NOISE_MODE2, 0x1d96 45 | .set SPU_REVERB_ON1, 0x1d98 46 | .set SPU_REVERB_ON2, 0x1d9a 47 | .set SPU_CHAN_STATUS1, 0x1d9c 48 | .set SPU_CHAN_STATUS2, 0x1d9e 49 | 50 | .set SPU_REVERB_ADDR, 0x1da2 51 | .set SPU_IRQ_ADDR, 0x1da4 52 | .set SPU_ADDR, 0x1da6 53 | .set SPU_DATA, 0x1da8 54 | 55 | .set SPU_CTRL, 0x1daa 56 | .set SPU_DMA_CTRL, 0x1dac 57 | .set SPU_STAT, 0x1dae 58 | 59 | .set SPU_CD_VOL_L, 0x1db0 60 | .set SPU_CD_VOL_R, 0x1db2 61 | .set SPU_EXT_VOL_L, 0x1db4 62 | .set SPU_EXT_VOL_R, 0x1db6 63 | .set SPU_CURRENT_VOL_L, 0x1db8 64 | .set SPU_CURRENT_VOL_R, 0x1dba 65 | 66 | .set SPU_CH_VOL_L, 0x00 67 | .set SPU_CH_VOL_R, 0x02 68 | .set SPU_CH_FREQ, 0x04 69 | .set SPU_CH_ADDR, 0x06 70 | .set SPU_CH_ADSR1, 0x08 71 | .set SPU_CH_ADSR2, 0x0a 72 | .set SPU_CH_LOOP_ADDR, 0x0e 73 | 74 | ## MDEC 75 | 76 | .set MDEC0, 0x1820 77 | .set MDEC1, 0x1824 78 | 79 | ## SPI and serial interfaces 80 | 81 | .set SIO0_DATA, 0x1040 82 | .set SIO0_STAT, 0x1044 83 | .set SIO0_MODE, 0x1048 84 | .set SIO0_CTRL, 0x104a 85 | .set SIO0_BAUD, 0x104e 86 | 87 | .set SIO1_DATA, 0x1050 88 | .set SIO1_STAT, 0x1054 89 | .set SIO1_MODE, 0x1058 90 | .set SIO1_CTRL, 0x105a 91 | .set SIO1_BAUD, 0x105e 92 | 93 | ## IRQ controller 94 | 95 | .set IRQ_STAT, 0x1070 96 | .set IRQ_MASK, 0x1074 97 | 98 | ## DMA 99 | 100 | .set DMA_DPCR, 0x10f0 101 | .set DMA_DICR, 0x10f4 102 | 103 | .set DMA0_MADR, 0x1080 104 | .set DMA0_BCR, 0x1084 105 | .set DMA0_CHCR, 0x1088 106 | 107 | .set DMA1_MADR, 0x1090 108 | .set DMA1_BCR, 0x1094 109 | .set DMA1_CHCR, 0x1098 110 | 111 | .set DMA2_MADR, 0x10a0 112 | .set DMA2_BCR, 0x10a4 113 | .set DMA2_CHCR, 0x10a8 114 | 115 | .set DMA3_MADR, 0x10b0 116 | .set DMA3_BCR, 0x10b4 117 | .set DMA3_CHCR, 0x10b8 118 | 119 | .set DMA4_MADR, 0x10c0 120 | .set DMA4_BCR, 0x10c4 121 | .set DMA4_CHCR, 0x10c8 122 | 123 | .set DMA5_MADR, 0x10d0 124 | .set DMA5_BCR, 0x10d4 125 | .set DMA5_CHCR, 0x10d8 126 | 127 | .set DMA6_MADR, 0x10e0 128 | .set DMA6_BCR, 0x10e4 129 | .set DMA6_CHCR, 0x10e8 130 | 131 | ## Timers 132 | 133 | .set TIMER0_VALUE, 0x1100 134 | .set TIMER0_CTRL, 0x1104 135 | .set TIMER0_RELOAD, 0x1108 136 | 137 | .set TIMER1_VALUE, 0x1110 138 | .set TIMER1_CTRL, 0x1114 139 | .set TIMER1_RELOAD, 0x1118 140 | 141 | .set TIMER2_VALUE, 0x1120 142 | .set TIMER2_CTRL, 0x1124 143 | .set TIMER2_RELOAD, 0x1128 144 | 145 | ## Memory/bus control 146 | 147 | .set BUS_EXP1_ADDR, 0x1000 148 | .set BUS_EXP2_ADDR, 0x1004 149 | .set BUS_EXP1_CFG, 0x1008 150 | .set BUS_EXP3_CFG, 0x100c 151 | .set BUS_BIOS_CFG, 0x1010 152 | .set BUS_SPU_CFG, 0x1014 153 | .set BUS_CD_CFG, 0x1018 154 | .set BUS_EXP2_CFG, 0x101c 155 | .set BUS_COM_DELAY, 0x1020 156 | .set BUS_RAM_SIZE, 0x1060 157 | -------------------------------------------------------------------------------- /tools/minin00b/include/hwregs_c.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK hardware registers definitions 3 | * (C) 2022 spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #define _ADDR8(addr) ((volatile uint8_t *) (addr)) 11 | #define _ADDR16(addr) ((volatile uint16_t *) (addr)) 12 | #define _ADDR32(addr) ((volatile uint32_t *) (addr)) 13 | #define _MMIO8(addr) (*_ADDR8(addr)) 14 | #define _MMIO16(addr) (*_ADDR16(addr)) 15 | #define _MMIO32(addr) (*_ADDR32(addr)) 16 | 17 | /* Constants */ 18 | 19 | #define IOBASE 0xbf800000 20 | #define EXP1BASE 0xbf000000 21 | 22 | #define F_CPU 33868800L 23 | #define F_GPU 53222400L 24 | 25 | /* GPU */ 26 | 27 | #define GPU_GP0 _MMIO32(IOBASE | 0x1810) 28 | #define GPU_GP1 _MMIO32(IOBASE | 0x1814) 29 | 30 | /* CD drive */ 31 | 32 | #define CD_STAT _MMIO8(IOBASE | 0x1800) 33 | #define CD_CMD _MMIO8(IOBASE | 0x1801) 34 | #define CD_DATA _MMIO8(IOBASE | 0x1802) 35 | #define CD_IRQ _MMIO8(IOBASE | 0x1803) 36 | 37 | #define CD_REG(N) _MMIO8((IOBASE | 0x1800) + (N)) 38 | 39 | /* SPU */ 40 | 41 | #define SPU_MASTER_VOL_L _MMIO16(IOBASE | 0x1d80) 42 | #define SPU_MASTER_VOL_R _MMIO16(IOBASE | 0x1d82) 43 | #define SPU_REVERB_VOL_L _MMIO16(IOBASE | 0x1d84) 44 | #define SPU_REVERB_VOL_R _MMIO16(IOBASE | 0x1d86) 45 | #define SPU_KEY_ON1 _MMIO16(IOBASE | 0x1d88) 46 | #define SPU_KEY_ON2 _MMIO16(IOBASE | 0x1d8a) 47 | #define SPU_KEY_OFF1 _MMIO16(IOBASE | 0x1d8c) 48 | #define SPU_KEY_OFF2 _MMIO16(IOBASE | 0x1d8e) 49 | #define SPU_FM_MODE1 _MMIO16(IOBASE | 0x1d90) 50 | #define SPU_FM_MODE2 _MMIO16(IOBASE | 0x1d92) 51 | #define SPU_NOISE_MODE1 _MMIO16(IOBASE | 0x1d94) 52 | #define SPU_NOISE_MODE2 _MMIO16(IOBASE | 0x1d96) 53 | #define SPU_REVERB_ON1 _MMIO16(IOBASE | 0x1d98) 54 | #define SPU_REVERB_ON2 _MMIO16(IOBASE | 0x1d9a) 55 | #define SPU_CHAN_STATUS1 _MMIO16(IOBASE | 0x1d9c) 56 | #define SPU_CHAN_STATUS2 _MMIO16(IOBASE | 0x1d9e) 57 | 58 | #define SPU_REVERB_ADDR _MMIO16(IOBASE | 0x1da2) 59 | #define SPU_IRQ_ADDR _MMIO16(IOBASE | 0x1da4) 60 | #define SPU_ADDR _MMIO16(IOBASE | 0x1da6) 61 | #define SPU_DATA _MMIO16(IOBASE | 0x1da8) 62 | 63 | #define SPU_CTRL _MMIO16(IOBASE | 0x1daa) 64 | #define SPU_DMA_CTRL _MMIO16(IOBASE | 0x1dac) 65 | #define SPU_STAT _MMIO16(IOBASE | 0x1dae) 66 | 67 | #define SPU_CD_VOL_L _MMIO16(IOBASE | 0x1db0) 68 | #define SPU_CD_VOL_R _MMIO16(IOBASE | 0x1db2) 69 | #define SPU_EXT_VOL_L _MMIO16(IOBASE | 0x1db4) 70 | #define SPU_EXT_VOL_R _MMIO16(IOBASE | 0x1db6) 71 | #define SPU_CURRENT_VOL_L _MMIO16(IOBASE | 0x1db8) 72 | #define SPU_CURRENT_VOL_R _MMIO16(IOBASE | 0x1dba) 73 | 74 | // These are not named SPU_VOICE_* to avoid name clashes with SPU attribute 75 | // flags defined in psxspu.h. 76 | #define SPU_CH_VOL_L(N) _MMIO16((IOBASE | 0x1c00) + (16 * (N))) 77 | #define SPU_CH_VOL_R(N) _MMIO16((IOBASE | 0x1c02) + (16 * (N))) 78 | #define SPU_CH_FREQ(N) _MMIO16((IOBASE | 0x1c04) + (16 * (N))) 79 | #define SPU_CH_ADDR(N) _MMIO16((IOBASE | 0x1c06) + (16 * (N))) 80 | #define SPU_CH_ADSR1(N) _MMIO16((IOBASE | 0x1c08) + (16 * (N))) 81 | #define SPU_CH_ADSR2(N) _MMIO16((IOBASE | 0x1c0a) + (16 * (N))) 82 | #define SPU_CH_ADSR_VOL(N) _MMIO16((IOBASE | 0x1c0c) + (16 * (N))) 83 | #define SPU_CH_LOOP_ADDR(N) _MMIO16((IOBASE | 0x1c0e) + (16 * (N))) 84 | 85 | /* MDEC */ 86 | 87 | #define MDEC0 _MMIO32(IOBASE | 0x1820) 88 | #define MDEC1 _MMIO32(IOBASE | 0x1824) 89 | 90 | /* SPI and serial interfaces */ 91 | 92 | // IMPORTANT: even though SIO_DATA is a 32-bit register, it should only be 93 | // accessed as 8-bit. Reading it as 16 or 32-bit works fine on real hardware, 94 | // but leads to problems in some emulators. 95 | #define SIO_DATA(N) _MMIO8 ((IOBASE | 0x1040) + (16 * (N))) 96 | #define SIO_STAT(N) _MMIO16((IOBASE | 0x1044) + (16 * (N))) 97 | #define SIO_MODE(N) _MMIO16((IOBASE | 0x1048) + (16 * (N))) 98 | #define SIO_CTRL(N) _MMIO16((IOBASE | 0x104a) + (16 * (N))) 99 | #define SIO_BAUD(N) _MMIO16((IOBASE | 0x104e) + (16 * (N))) 100 | 101 | /* IRQ controller */ 102 | 103 | #define IRQ_STAT _MMIO16(IOBASE | 0x1070) 104 | #define IRQ_MASK _MMIO16(IOBASE | 0x1074) 105 | 106 | /* DMA */ 107 | 108 | #define DMA_DPCR _MMIO32(IOBASE | 0x10f0) 109 | #define DMA_DICR _MMIO32(IOBASE | 0x10f4) 110 | 111 | #define DMA_MADR(N) _MMIO32((IOBASE | 0x1080) + (16 * (N))) 112 | #define DMA_BCR(N) _MMIO32((IOBASE | 0x1084) + (16 * (N))) 113 | #define DMA_CHCR(N) _MMIO32((IOBASE | 0x1088) + (16 * (N))) 114 | 115 | /* Timers */ 116 | 117 | #define TIMER_VALUE(N) _MMIO16((IOBASE | 0x1100) + (16 * (N))) 118 | #define TIMER_CTRL(N) _MMIO16((IOBASE | 0x1104) + (16 * (N))) 119 | #define TIMER_RELOAD(N) _MMIO16((IOBASE | 0x1108) + (16 * (N))) 120 | 121 | /* Memory/bus control */ 122 | 123 | #define BUS_EXP1_ADDR _MMIO32(IOBASE | 0x1000) 124 | #define BUS_EXP2_ADDR _MMIO32(IOBASE | 0x1004) 125 | #define BUS_EXP1_CFG _MMIO32(IOBASE | 0x1008) 126 | #define BUS_EXP3_CFG _MMIO32(IOBASE | 0x100c) 127 | #define BUS_BIOS_CFG _MMIO32(IOBASE | 0x1010) 128 | #define BUS_SPU_CFG _MMIO32(IOBASE | 0x1014) 129 | #define BUS_CD_CFG _MMIO32(IOBASE | 0x1018) 130 | #define BUS_EXP2_CFG _MMIO32(IOBASE | 0x101c) 131 | #define BUS_COM_DELAY _MMIO32(IOBASE | 0x1020) 132 | #define BUS_RAM_SIZE _MMIO32(IOBASE | 0x1060) 133 | -------------------------------------------------------------------------------- /tools/minin00b/include/inline_s.inc: -------------------------------------------------------------------------------- 1 | # Inline GTE macros for GNU assembler (as). 2 | # 3 | # Part of the PSn00bSDK Project by Lameguy64. 4 | # 2019 Meido-Tek Productions 5 | # 6 | # Similar to inline_c.h, it does not require running your object file 7 | # through some silly tool. 8 | 9 | .macro nRTPS 10 | nop 11 | nop 12 | cop2 0x0180001 13 | .endm 14 | 15 | .macro nRTPT 16 | nop 17 | nop 18 | cop2 0x0280030 19 | .endm 20 | 21 | .macro nNCLIP 22 | nop 23 | nop 24 | cop2 0x1400006 25 | .endm 26 | 27 | .macro nAVSZ3 28 | nop 29 | nop 30 | cop2 0x158002D 31 | .endm 32 | 33 | .macro nAVSZ4 34 | nop 35 | nop 36 | cop2 0x168002E 37 | .endm 38 | 39 | .macro nMVMVA sf mx v cv lm 40 | nop 41 | nop 42 | cop2 0x0400012|(\sf<<19)|(\mx<<17)|(\v<<15)|(\cv<<13)|(\lm<<10) 43 | .endm 44 | 45 | .macro nSQR sf 46 | nop 47 | nop 48 | cop2 0x0A00428|(\sf<<19) 49 | .endm 50 | 51 | .macro nnOP sf lm # extra n to prevent conflict with the nop opcode 52 | nop 53 | nop 54 | cop2 0x170000C|(\sf<<19)|(\lm<<10) 55 | .endm 56 | 57 | .macro nNCS 58 | nop 59 | nop 60 | cop2 0x0C8041E 61 | .endm 62 | 63 | .macro nNCT 64 | nop 65 | nop 66 | cop2 0x0D80420 67 | .endm 68 | 69 | .macro nNCCS 70 | nop 71 | nop 72 | cop2 0x108041B 73 | .endm 74 | 75 | .macro nNCCT 76 | nop 77 | nop 78 | cop2 0x118043F 79 | .endm 80 | 81 | .macro nNCDS 82 | nop 83 | nop 84 | cop2 0x0E80413 85 | .endm 86 | 87 | .macro nNCDT 88 | nop 89 | nop 90 | cop2 0x0F80416 91 | .endm 92 | 93 | .macro nCC 94 | nop 95 | nop 96 | cop2 0x138041C 97 | .endm 98 | 99 | .macro nCDP 100 | nop 101 | nop 102 | cop2 0x1280414 103 | .endm 104 | 105 | .macro nDCPL 106 | nop 107 | nop 108 | cop2 0x0680029 109 | .endm 110 | 111 | .macro nDPCS 112 | nop 113 | nop 114 | cop2 0x0780010 115 | .endm 116 | 117 | .macro nDPCT 118 | nop 119 | nop 120 | cop2 0x0180001 121 | .endm 122 | 123 | .macro nINTPL 124 | nop 125 | nop 126 | cop2 0x0980011 127 | .endm 128 | 129 | .macro nGPF sf 130 | nop 131 | nop 132 | cop2 0x190003D|(\sf<<19) 133 | .endm 134 | 135 | .macro nGPL sf 136 | nop 137 | nop 138 | cop2 0x1A0003E|(\sf<<19) 139 | .endm 140 | 141 | # 142 | # Macros without leading nops (for optimized usage) 143 | # 144 | .macro RTPS 145 | cop2 0x0180001 146 | .endm 147 | 148 | .macro RTPT 149 | cop2 0x0280030 150 | .endm 151 | 152 | .macro NCLIP 153 | cop2 0x1400006 154 | .endm 155 | 156 | .macro AVSZ3 157 | cop2 0x158002D 158 | .endm 159 | 160 | .macro AVSZ4 161 | cop2 0x168002E 162 | .endm 163 | 164 | .macro MVMVA sf mx v cv lm 165 | cop2 0x0400012|(\sf<<19)|(\mx<<17)|(\v<<15)|(\cv<<13)|(\lm<<10) 166 | .endm 167 | 168 | .macro SQR sf 169 | cop2 0x0A00428|(\sf<<19) 170 | .endm 171 | 172 | .macro OP sf lm 173 | cop2 0x170000C|(\sf<<19)|(\lm<<10) 174 | .endm 175 | 176 | .macro NCS 177 | cop2 0x0C8041E 178 | .endm 179 | 180 | .macro NCT 181 | cop2 0x0D80420 182 | .endm 183 | 184 | .macro NCCS 185 | cop2 0x108041B 186 | .endm 187 | 188 | .macro NCCT 189 | cop2 0x118043F 190 | .endm 191 | 192 | .macro NCDS 193 | cop2 0x0E80413 194 | .endm 195 | 196 | .macro NCDT 197 | cop2 0x0F80416 198 | .endm 199 | 200 | .macro CC 201 | cop2 0x138041C 202 | .endm 203 | 204 | .macro CDP 205 | cop2 0x1280414 206 | .endm 207 | 208 | .macro DCPL 209 | cop2 0x0680029 210 | .endm 211 | 212 | .macro DPCS 213 | cop2 0x0780010 214 | .endm 215 | 216 | .macro DPCT 217 | cop2 0x0180001 218 | .endm 219 | 220 | .macro INTPL 221 | cop2 0x0980011 222 | .endm 223 | 224 | .macro GPF sf 225 | cop2 0x190003D|(\sf<<19) 226 | .endm 227 | 228 | .macro GPL sf 229 | cop2 0x1A0003E|(\sf<<19) 230 | .endm 231 | -------------------------------------------------------------------------------- /tools/minin00b/include/psxsn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK kernel API library (host file access) 3 | * (C) 2023 spicyjpeg - MPL licensed 4 | */ 5 | 6 | /** 7 | * @file psxsn.h 8 | * @brief Host file access API header 9 | * 10 | * @details This header provides stubs for the PCDRV API, which grants read and 11 | * write access to a directory on the host's filesystem when the executable is 12 | * running on an emulator or through a debugger that supports the PCDRV 13 | * protocol, such as Unirom or pcsx-redux. These functions are completely 14 | * separate and independent from the file APIs provided by the BIOS and do not 15 | * register any device drivers. 16 | * 17 | * Note that in the official SDK these functions are provided by libsn, while 18 | * in PSn00bSDK they are part of libpsxapi. 19 | * 20 | * IMPORTANT: as these function rely on break instructions internally, calling 21 | * them on real hardware without a PCDRV handler installed or on an emulator 22 | * that does not support the API will result in an uncaught break exception, 23 | * which will cause the BIOS to get stuck in an infinite loop. 24 | */ 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | typedef enum { 31 | PCDRV_MODE_READ = 0, 32 | PCDRV_MODE_WRITE = 1, 33 | PCDRV_MODE_READ_WRITE = 2 34 | } PCDRV_OpenMode; 35 | 36 | typedef enum { 37 | PCDRV_SEEK_SET = 0, 38 | PCDRV_SEEK_CUR = 1, 39 | PCDRV_SEEK_END = 2 40 | } PCDRV_SeekMode; 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | int PCinit(void); 47 | int PCcreat(const char *path); 48 | int PCopen(const char *path, PCDRV_OpenMode mode); 49 | int PCclose(int fd); 50 | int PCread(int fd, void *data, size_t length); 51 | int PCwrite(int fd, const void *data, size_t length); 52 | int PClseek(int fd, int offset, PCDRV_SeekMode mode); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /tools/minin00b/include/setjmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2023 spicyjpeg - MPL licensed 4 | * 5 | * This setjmp() implementation is compatible with the one in the BIOS, making 6 | * it possible to pass a jmp_buf structure as-is to BIOS functions such as 7 | * HookEntryInt(). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | 14 | typedef struct { 15 | uint32_t ra, sp, fp; 16 | uint32_t s0, s1, s2, s3, s4, s5, s6, s7; 17 | uint32_t gp; 18 | } JumpBuffer; 19 | 20 | typedef JumpBuffer jmp_buf[1]; 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | int setjmp(jmp_buf buf); 27 | void longjmp(jmp_buf buf, int value); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /tools/minin00b/include/stdio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2019-2023 Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | /* String I/O API (provided by BIOS) */ 15 | 16 | int printf(const char *fmt, ...); 17 | char *gets(char *str); 18 | void puts(const char *str); 19 | int getchar(void); 20 | void putchar(int ch); 21 | 22 | /* String formatting API (built-in) */ 23 | 24 | int vsnprintf(char *string, unsigned int size, const char *fmt, va_list ap); 25 | int vsprintf(char *string, const char *fmt, va_list ap); 26 | int sprintf(char *string, const char *fmt, ...); 27 | int snprintf(char *string, unsigned int size, const char *fmt, ...); 28 | 29 | int vsscanf(const char *str, const char *format, va_list ap); 30 | int sscanf(const char *str, const char *fmt, ...); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /tools/minin00b/include/stdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2019-2023 PSXSDK authors, Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | /* Definitions */ 11 | 12 | #define RAND_MAX 0x7fff 13 | 14 | /* Structure definitions */ 15 | 16 | typedef struct _HeapUsage { 17 | size_t total; // Total size of heap + stack 18 | size_t heap; // Amount of memory currently reserved for heap 19 | size_t stack; // Amount of memory currently reserved for stack 20 | size_t alloc; // Amount of memory currently allocated 21 | size_t alloc_max; // Maximum amount of memory ever allocated 22 | } HeapUsage; 23 | 24 | /* API */ 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | extern int __argc; 31 | extern const char **__argv; 32 | 33 | void abort(void); 34 | 35 | int abs(int value); 36 | int rand(void); 37 | void srand(int seed); 38 | 39 | long strtol(const char *str, char **str_end, int base); 40 | long long strtoll(const char *str, char **str_end, int base); 41 | //float strtof(const char *str, char **str_end); 42 | //double strtod(const char *str, char **str_end); 43 | //long double strtold(const char *str, char **str_end); 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /tools/minin00b/include/string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2019-2023 PSXSDK authors, Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | void *memset(void *dest, int ch, size_t count); 15 | void *memcpy(void *dest, const void *src, size_t count); 16 | void *memccpy(void *dest, const void *src, int ch, size_t count); 17 | void *memmove(void *dest, const void *src, size_t count); 18 | int memcmp(const void *lhs, const void *rhs, size_t count); 19 | void *memchr(const void *ptr, int ch, size_t count); 20 | 21 | char *strcpy(char *dest, const char *src); 22 | char *strncpy(char *dest, const char *src, size_t count); 23 | int strcmp(const char *lhs, const char *rhs); 24 | int strncmp(const char *lhs, const char *rhs, size_t count); 25 | char *strchr(const char *str, int ch); 26 | char *strrchr(const char *str, int ch); 27 | char *strpbrk(const char *str, const char *breakset); 28 | char *strstr(const char *str, const char *substr); 29 | 30 | size_t strlen(const char *str); 31 | char *strcat(char *dest, const char *src); 32 | char *strncat(char *dest, const char *src, size_t count); 33 | char *strdup(const char *str); 34 | char *strndup(const char *str, size_t count); 35 | 36 | char *strtok(char *str, const char *delim); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /tools/minin00b/include/strings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2019-2022 PSXSDK authors, Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | /* Compatibility macros (this header is useless) */ 11 | 12 | #define bcopy(src, dst, len) memmove(dst, src, len) 13 | #define bzero(ptr, len) memset(ptr, 0, len) 14 | #define bcmp(b1, b2, len) memcmp(b1, b2, len) 15 | #define index(s, c) strchr(s, c) 16 | #define rindex(s, c) strrchr(s, c) 17 | -------------------------------------------------------------------------------- /tools/minin00b/include/sys/fcntl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK kernel API library 3 | * (C) 2019-2023 Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #define FREAD 0x1 // Read 9 | #define FWRITE 0x2 // Write 10 | #define FNBLOCK 0x4 // Non-blocking read access 11 | #define FRLOCK 0x10 // Read lock 12 | #define FWLOCK 0x20 // Write lock 13 | #define FAPPEND 0x100 // Append 14 | #define FCREATE 0x200 // Create if not exist 15 | #define FTRUNC 0x400 // Truncate to zero length 16 | #define FSCAN 0x2000 // Scanning type 17 | #define FRCOM 0x2000 // Remote command entry 18 | #define FNBUF 0x4000 // No ring buffer and terminal interrupt 19 | #define FASYNC 0x8000 // Asynchronous I/O 20 | #define FNBLOCKS(a) (a<<16) // Number of blocks? (from nocash docs) 21 | -------------------------------------------------------------------------------- /tools/minin00b/include/sys/ioctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK kernel API library 3 | * (C) 2019-2023 Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | #define EOF -1 9 | 10 | #define FIONBLOCK (('f'<<8)|1) 11 | #define FIOCSCAN (('f'<<8)|2) 12 | 13 | #define DIOFORMAT (('d'<<8)|1) 14 | -------------------------------------------------------------------------------- /tools/minin00b/include/sys/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library 3 | * (C) 2019-2023 Lameguy64, spicyjpeg - MPL licensed 4 | */ 5 | 6 | #pragma once 7 | 8 | //#warning " and u_* types are deprecated, use instead" 9 | 10 | typedef unsigned char u_char; 11 | typedef unsigned short u_short; 12 | typedef unsigned int u_int; 13 | typedef unsigned long u_long; 14 | -------------------------------------------------------------------------------- /tools/minin00b/lib/libc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/libc.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxapi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxapi.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxcd.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxcd.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxetc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxetc.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxgpu.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxgpu.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxgte.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxgte.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxpress.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxpress.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxsio.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxsio.a -------------------------------------------------------------------------------- /tools/minin00b/lib/psxspu.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/lib/psxspu.a -------------------------------------------------------------------------------- /tools/minin00b/libc/clz.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK leading zero count intrinsics 2 | # (C) 2022-2023 spicyjpeg - MPL licensed 3 | # 4 | # libgcc provides two functions used internally by GCC to count the number of 5 | # leading zeroes in a value, __clzsi2() (32-bit) and __clzdi2() (64-bit). This 6 | # file overrides them with smaller implementations that make use of the GTE's 7 | # LZCS/LZCR registers. 8 | 9 | .set noreorder 10 | 11 | .set LZCS, $30 12 | .set LZCR, $31 13 | 14 | .section .text.__clzsi2, "ax", @progbits 15 | .global __clzsi2 16 | .type __clzsi2, @function 17 | 18 | __clzsi2: 19 | mtc2 $a0, LZCS 20 | bltz $a0, .Lreturn # if (value & (1 << 31)) return 0 21 | li $v0, 0 22 | mfc2 $v0, LZCR # else return GTE_CLZ(value) 23 | 24 | .Lreturn: 25 | jr $ra 26 | nop 27 | 28 | .section .text.__clzdi2, "ax", @progbits 29 | .global __clzdi2 30 | .type __clzdi2, @function 31 | 32 | __clzdi2: 33 | mtc2 $a1, LZCS 34 | bltz $a1, .Lreturn2 # if (msb & (1 << 31)) return 0 35 | li $v0, 0 36 | bnez $a1, .LreturnMSB # else if (msb) return GTE_CLZ(msb) 37 | nop 38 | 39 | .LnoMSB: 40 | mtc2 $a0, LZCS 41 | bltz $a0, .Lreturn2 # else if (lsb & (1 << 31)) return 32 42 | li $v0, 32 43 | mfc2 $v0, LZCR # else return 32 + GTE_CLZ(lsb) 44 | 45 | jr $ra 46 | addiu $v0, 32 47 | 48 | .LreturnMSB: 49 | mfc2 $v0, LZCR 50 | 51 | .Lreturn2: 52 | jr $ra 53 | nop 54 | -------------------------------------------------------------------------------- /tools/minin00b/libc/memset.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK optimized memset 2 | # (C) 2022 spicyjpeg - MPL licensed 3 | 4 | .set noreorder 5 | 6 | .section .text.memset, "ax", @progbits 7 | .global memset 8 | .type memset, @function 9 | 10 | memset: 11 | # If more than 16 bytes have to be written then take the "large" path, 12 | # otherwise use the code below. 13 | addiu $t0, $a2, -16 14 | bgtz $t0, .Llarge_fill 15 | move $v0, $a0 # return_value = dest 16 | 17 | # Jump to one of the sb opcodes below. This is basically a cut-down Duff's 18 | # device implementation with no looping. 19 | la $t0, .Lsmall_duff + 0x40 # jump_addr = &small_duff[(16 - count) * 4] 20 | sll $t1, $a2, 2 21 | subu $t0, $t1 22 | addu $a0, $a2 # dest -= 16 - count 23 | jr $t0 24 | addiu $a0, -16 25 | 26 | .Lsmall_duff: 27 | sb $a1, 0x0($a0) 28 | sb $a1, 0x1($a0) 29 | sb $a1, 0x2($a0) 30 | sb $a1, 0x3($a0) 31 | sb $a1, 0x4($a0) 32 | sb $a1, 0x5($a0) 33 | sb $a1, 0x6($a0) 34 | sb $a1, 0x7($a0) 35 | sb $a1, 0x8($a0) 36 | sb $a1, 0x9($a0) 37 | sb $a1, 0xa($a0) 38 | sb $a1, 0xb($a0) 39 | sb $a1, 0xc($a0) 40 | sb $a1, 0xd($a0) 41 | sb $a1, 0xe($a0) 42 | sb $a1, 0xf($a0) 43 | jr $ra 44 | nop 45 | 46 | .Llarge_fill: 47 | # Initialize fast filling by repeating the fill byte 4 times, so it can be 48 | # written 32 bits at a time. 49 | andi $a1, 0xff # ch &= 0xff 50 | sll $t0, $a1, 8 # ch |= (ch << 8) | (ch << 16) | (ch << 24) 51 | or $a1, $t0 52 | sll $t0, $a1, 16 53 | or $a1, $t0 54 | 55 | # Fill the first 1-4 bytes (here the swr instruction does all the magic) 56 | # and update dest and count accordingly. 57 | swr $a1, 0($a0) 58 | andi $t0, $a0, 3 # align = 4 - (dest % 4) 59 | addiu $t0, -4 60 | addu $a2, $t0 # count -= align 61 | subu $a0, $t0 # dest += align 62 | 63 | la $t1, .Llarge_duff 64 | andi $t2, $a2, 3 # remainder = count % 4 65 | subu $a2, $t2 # count -= remainder 66 | 67 | .Llarge_fill_loop: 68 | # If 128 bytes or more still have to be written, skip calculating the jump 69 | # offset and execute the whole block of sw opcodes. 70 | addiu $a2, -0x80 # count -= 0x80 71 | bgez $a2, .Llarge_duff 72 | #nop 73 | 74 | # Jump to one of the sw opcodes below. This is the "full" Duff's device. 75 | subu $t0, $t1, $a2 # jump_addr = &large_duff[0x80 - (count + 0x80)] 76 | jr $t0 77 | addu $a0, $a2 # dest -= 0x80 - (count + 0x80) 78 | 79 | .Llarge_duff: 80 | sw $a1, 0x00($a0) 81 | sw $a1, 0x04($a0) 82 | sw $a1, 0x08($a0) 83 | sw $a1, 0x0c($a0) 84 | sw $a1, 0x10($a0) 85 | sw $a1, 0x14($a0) 86 | sw $a1, 0x18($a0) 87 | sw $a1, 0x1c($a0) 88 | sw $a1, 0x20($a0) 89 | sw $a1, 0x24($a0) 90 | sw $a1, 0x28($a0) 91 | sw $a1, 0x2c($a0) 92 | sw $a1, 0x30($a0) 93 | sw $a1, 0x34($a0) 94 | sw $a1, 0x38($a0) 95 | sw $a1, 0x3c($a0) 96 | sw $a1, 0x40($a0) 97 | sw $a1, 0x44($a0) 98 | sw $a1, 0x48($a0) 99 | sw $a1, 0x4c($a0) 100 | sw $a1, 0x50($a0) 101 | sw $a1, 0x54($a0) 102 | sw $a1, 0x58($a0) 103 | sw $a1, 0x5c($a0) 104 | sw $a1, 0x60($a0) 105 | sw $a1, 0x64($a0) 106 | sw $a1, 0x68($a0) 107 | sw $a1, 0x6c($a0) 108 | sw $a1, 0x70($a0) 109 | sw $a1, 0x74($a0) 110 | sw $a1, 0x78($a0) 111 | sw $a1, 0x7c($a0) 112 | 113 | bgtz $a2, .Llarge_fill_loop 114 | addiu $a0, 0x80 # dest += 0x80 115 | 116 | # Fill the remaining 1-4 bytes, using (again) an unaligned store. 117 | addu $a0, $t2 # last_byte = dest + remainder - 1 118 | jr $ra 119 | swl $a1, -1($a0) 120 | -------------------------------------------------------------------------------- /tools/minin00b/libc/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK standard library (misc. functions) 3 | * (C) 2022-2023 spicyjpeg - MPL licensed 4 | */ 5 | 6 | #undef SDK_LIBRARY_NAME 7 | 8 | #include 9 | #include 10 | 11 | /* Abort functions */ 12 | 13 | void _assert_abort(const char *file, int line, const char *expr) { 14 | _sdk_log("%s:%d: assert(%s)\n", file, line, expr); 15 | 16 | for (;;) 17 | __asm__ volatile(""); 18 | } 19 | 20 | void abort(void) { 21 | _sdk_log("abort()\n"); 22 | 23 | for (;;) 24 | __asm__ volatile(""); 25 | } 26 | 27 | void __cxa_pure_virtual(void) { 28 | _sdk_log("__cxa_pure_virtual()\n"); 29 | 30 | for (;;) 31 | __asm__ volatile(""); 32 | } 33 | 34 | /* abs() */ 35 | 36 | int abs(int value) { 37 | return (value < 0) ? (-value) : value; 38 | } 39 | 40 | /* Pseudorandom number generator */ 41 | 42 | static int _random_seed = 0; 43 | 44 | int rand(void) { 45 | _random_seed *= 0x41c64e6d; 46 | _random_seed += 12345; 47 | 48 | return (_random_seed >> 16) & RAND_MAX; 49 | } 50 | 51 | void srand(int seed) { 52 | _random_seed = seed; 53 | } 54 | -------------------------------------------------------------------------------- /tools/minin00b/libc/readme.txt: -------------------------------------------------------------------------------- 1 | Limited C standard library implementation, part of PSn00bSDK 2 | 2019 Lameguy64 / Meido-Tek Productions 3 | 4 | Some components were inherited from PSXSDK. This library covers only the 5 | most commonly used C functions, mainly most string and memory manipulation 6 | functions. Improvements to this library such as adding more standard C 7 | functions are welcome. 8 | 9 | This library also contains the start code written in assembler which 10 | performs basic initialization such as clearing the bss section, setting the 11 | correct gp register value and initializing the heap for malloc. 12 | 13 | The dynamic memory allocation functions featured in this library are of 14 | an original implementation and do not use the BIOS memory allocation functions 15 | as they are are reportedly prone to memory leakage and is even explained in 16 | the official library documents. The implementation employed uses a simple 17 | first-fit memory allocation logic. 18 | 19 | 20 | Library developer(s)/contributor(s): 21 | 22 | Lameguy64 23 | 24 | 25 | Library header(s): 26 | 27 | stdio.h 28 | stdlib.h 29 | string.h 30 | strings.h 31 | malloc.h 32 | 33 | 34 | Todo list: 35 | 36 | * Many of the string manipulation and memory fill functions in string.c 37 | are yet to be replaced with more efficient assembly implementations. 38 | 39 | 40 | Changelog: 41 | 42 | 05-23-2019 by Lameguy64: 43 | 44 | * Made stack usage a lot less wastefull in _start entrypoint. 45 | -------------------------------------------------------------------------------- /tools/minin00b/libc/setjmp.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK setjmp/longjmp 2 | # (C) 2023 spicyjpeg - MPL licensed 3 | # 4 | # This is not a "proper" implementation of setjmp/longjmp as it does not save 5 | # COP0 and GTE registers, but it is fully compatible with the version found in 6 | # the BIOS. 7 | 8 | .set noreorder 9 | 10 | .section .text.setjmp, "ax", @progbits 11 | .global setjmp 12 | .type setjmp, @function 13 | 14 | setjmp: 15 | sw $ra, 0x00($a0) 16 | sw $sp, 0x04($a0) 17 | sw $fp, 0x08($a0) 18 | sw $s0, 0x0c($a0) 19 | sw $s1, 0x10($a0) 20 | sw $s2, 0x14($a0) 21 | sw $s3, 0x18($a0) 22 | sw $s4, 0x1c($a0) 23 | sw $s5, 0x20($a0) 24 | sw $s6, 0x24($a0) 25 | sw $s7, 0x28($a0) 26 | sw $gp, 0x2c($a0) 27 | 28 | jr $ra 29 | li $v0, 0 30 | 31 | .section .text.longjmp, "ax", @progbits 32 | .global longjmp 33 | .type longjmp, @function 34 | 35 | longjmp: 36 | lw $ra, 0x00($a0) 37 | lw $sp, 0x04($a0) 38 | lw $fp, 0x08($a0) 39 | lw $s0, 0x0c($a0) 40 | lw $s1, 0x10($a0) 41 | lw $s2, 0x14($a0) 42 | lw $s3, 0x18($a0) 43 | lw $s4, 0x1c($a0) 44 | lw $s5, 0x20($a0) 45 | lw $s6, 0x24($a0) 46 | lw $s7, 0x28($a0) 47 | lw $gp, 0x2c($a0) 48 | 49 | jr $ra 50 | move $v0, $a1 51 | -------------------------------------------------------------------------------- /tools/minin00b/psxapi/_syscalls.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK syscall wrappers 2 | # (C) 2022-2023 spicyjpeg - MPL licensed 3 | 4 | .set noreorder 5 | 6 | ## Interrupt enable/disable 7 | 8 | .section .text.EnterCriticalSection, "ax", @progbits 9 | .global EnterCriticalSection 10 | .type EnterCriticalSection, @function 11 | 12 | EnterCriticalSection: 13 | li $a0, 0x01 14 | syscall 0 15 | 16 | jr $ra 17 | nop 18 | 19 | .section .text.ExitCriticalSection, "ax", @progbits 20 | .global ExitCriticalSection 21 | .type ExitCriticalSection, @function 22 | 23 | ExitCriticalSection: 24 | li $a0, 0x02 25 | syscall 0 26 | 27 | jr $ra 28 | nop 29 | 30 | .section .text.SwEnterCriticalSection, "ax", @progbits 31 | .global SwEnterCriticalSection 32 | .type SwEnterCriticalSection, @function 33 | 34 | SwEnterCriticalSection: 35 | mfc0 $a0, $12 # cop0r12 &= ~0x401 36 | li $a1, -1026 37 | and $a1, $a0 38 | mtc0 $a1, $12 39 | andi $a0, 0x0401 # return !((cop0r12_prev & 0x401) < 0x401) 40 | sltiu $v0, $a0, 0x0401 41 | 42 | jr $ra 43 | xori $v0, 1 44 | 45 | .section .text.SwExitCriticalSection, "ax", @progbits 46 | .global SwExitCriticalSection 47 | .type SwExitCriticalSection, @function 48 | 49 | SwExitCriticalSection: 50 | mfc0 $a0, $12 # cop0r12 |= 0x401 51 | nop 52 | ori $a0, 0x0401 53 | mtc0 $a0, $12 54 | nop 55 | 56 | jr $ra 57 | nop 58 | 59 | ## PCDRV (host file access) API 60 | 61 | .section .text.PCinit, "ax", @progbits 62 | .global PCinit 63 | .type PCinit, @function 64 | 65 | PCinit: 66 | break 0, 0x101 # () -> error 67 | 68 | jr $ra 69 | nop 70 | 71 | .section .text.PCcreat, "ax", @progbits 72 | .global PCcreat 73 | .type PCcreat, @function 74 | 75 | PCcreat: 76 | li $a2, 0 77 | move $a1, $a0 78 | break 0, 0x102 # (path, path, 0) -> error, fd 79 | 80 | bgez $v0, .Lcreate_ok # if (error < 0) fd = error 81 | nop 82 | move $v1, $v0 83 | .Lcreate_ok: 84 | jr $ra # return fd 85 | move $v0, $v1 86 | 87 | .section .text.PCopen, "ax", @progbits 88 | .global PCopen 89 | .type PCopen, @function 90 | 91 | PCopen: 92 | move $a2, $a1 93 | move $a1, $a0 94 | break 0, 0x103 # (path, path, mode) -> error, fd 95 | 96 | bgez $v0, .Lopen_ok # if (error < 0) fd = error 97 | nop 98 | move $v1, $v0 99 | .Lopen_ok: 100 | jr $ra # return fd 101 | move $v0, $v1 102 | 103 | .section .text.PCclose, "ax", @progbits 104 | .global PCclose 105 | .type PCclose, @function 106 | 107 | PCclose: 108 | move $a1, $a0 109 | break 0, 0x104 # (fd, fd) -> error 110 | 111 | jr $ra 112 | nop 113 | 114 | .section .text.PCread, "ax", @progbits 115 | .global PCread 116 | .type PCread, @function 117 | 118 | PCread: 119 | move $a3, $a1 120 | move $a1, $a0 121 | break 0, 0x105 # (fd, fd, length, data) -> error, length 122 | 123 | bgez $v0, .Lread_ok # if (error < 0) length = error 124 | nop 125 | move $v1, $v0 126 | .Lread_ok: 127 | jr $ra # return length 128 | move $v0, $v1 129 | 130 | .section .text.PCwrite, "ax", @progbits 131 | .global PCwrite 132 | .type PCwrite, @function 133 | 134 | PCwrite: 135 | move $a3, $a1 136 | move $a1, $a0 137 | break 0, 0x106 # (fd, fd, length, data) -> error, length 138 | 139 | bgez $v0, .Lwrite_ok # if (error < 0) length = error 140 | nop 141 | move $v1, $v0 142 | .Lwrite_ok: 143 | jr $ra # return length 144 | move $v0, $v1 145 | 146 | .section .text.PClseek, "ax", @progbits 147 | .global PClseek 148 | .type PClseek, @function 149 | 150 | PClseek: 151 | move $a3, $a2 152 | move $a2, $a1 153 | move $a1, $a0 154 | break 0, 0x107 # (fd, fd, offset, mode) -> error, offset 155 | 156 | bgez $v0, .Lseek_ok # if (error < 0) offset = error 157 | nop 158 | move $v1, $v0 159 | .Lseek_ok: 160 | jr $ra # return offset 161 | move $v0, $v1 162 | -------------------------------------------------------------------------------- /tools/minin00b/psxapi/drivers.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK BIOS API stubs 2 | # (C) 2022 spicyjpeg - MPL licensed 3 | 4 | # This file has been generated automatically. Each function is placed in its 5 | # own section to allow the linker to strip unused functions. 6 | 7 | .set noreorder 8 | 9 | ## A0 table functions (7) 10 | 11 | .section .text._bu_init 12 | .global _bu_init 13 | .type _bu_init, @function 14 | _bu_init: 15 | li $t2, 0xa0 16 | jr $t2 17 | li $t1, 0x55 18 | 19 | .section .text._96_init 20 | .global _96_init 21 | .type _96_init, @function 22 | _96_init: 23 | li $t2, 0xa0 24 | jr $t2 25 | li $t1, 0x71 26 | 27 | .section .text._96_remove 28 | .global _96_remove 29 | .type _96_remove, @function 30 | _96_remove: 31 | li $t2, 0xa0 32 | jr $t2 33 | li $t1, 0x72 34 | 35 | .section .text.add_nullcon_driver 36 | .global add_nullcon_driver 37 | .type add_nullcon_driver, @function 38 | add_nullcon_driver: 39 | li $t2, 0xa0 40 | jr $t2 41 | li $t1, 0x99 42 | 43 | .section .text._card_info 44 | .global _card_info 45 | .type _card_info, @function 46 | _card_info: 47 | li $t2, 0xa0 48 | jr $t2 49 | li $t1, 0xab 50 | 51 | .section .text._card_load 52 | .global _card_load 53 | .type _card_load, @function 54 | _card_load: 55 | li $t2, 0xa0 56 | jr $t2 57 | li $t1, 0xac 58 | 59 | .section .text._card_clear 60 | .global _card_clear 61 | .type _card_clear, @function 62 | _card_clear: 63 | li $t2, 0xa0 64 | jr $t2 65 | li $t1, 0xaf 66 | 67 | ## B0 table functions (12) 68 | 69 | .section .text.AddDrv 70 | .global AddDrv 71 | .type AddDrv, @function 72 | AddDrv: 73 | li $t2, 0xb0 74 | jr $t2 75 | li $t1, 0x47 76 | 77 | .section .text.DelDrv 78 | .global DelDrv 79 | .type DelDrv, @function 80 | DelDrv: 81 | li $t2, 0xb0 82 | jr $t2 83 | li $t1, 0x48 84 | 85 | .section .text.ListDrv 86 | .global ListDrv 87 | .type ListDrv, @function 88 | ListDrv: 89 | li $t2, 0xb0 90 | jr $t2 91 | li $t1, 0x49 92 | 93 | .section .text.InitCARD 94 | .global InitCARD 95 | .type InitCARD, @function 96 | InitCARD: 97 | li $t2, 0xb0 98 | jr $t2 99 | li $t1, 0x4a 100 | 101 | .section .text.StartCARD 102 | .global StartCARD 103 | .type StartCARD, @function 104 | StartCARD: 105 | li $t2, 0xb0 106 | jr $t2 107 | li $t1, 0x4b 108 | 109 | .section .text.StopCARD 110 | .global StopCARD 111 | .type StopCARD, @function 112 | StopCARD: 113 | li $t2, 0xb0 114 | jr $t2 115 | li $t1, 0x4c 116 | 117 | .section .text._card_write 118 | .global _card_write 119 | .type _card_write, @function 120 | _card_write: 121 | li $t2, 0xb0 122 | jr $t2 123 | li $t1, 0x4e 124 | 125 | .section .text._card_read 126 | .global _card_read 127 | .type _card_read, @function 128 | _card_read: 129 | li $t2, 0xb0 130 | jr $t2 131 | li $t1, 0x4f 132 | 133 | .section .text._new_card 134 | .global _new_card 135 | .type _new_card, @function 136 | _new_card: 137 | li $t2, 0xb0 138 | jr $t2 139 | li $t1, 0x50 140 | 141 | .section .text._card_chan 142 | .global _card_chan 143 | .type _card_chan, @function 144 | _card_chan: 145 | li $t2, 0xb0 146 | jr $t2 147 | li $t1, 0x58 148 | 149 | .section .text._card_status 150 | .global _card_status 151 | .type _card_status, @function 152 | _card_status: 153 | li $t2, 0xb0 154 | jr $t2 155 | li $t1, 0x5c 156 | 157 | .section .text._card_wait 158 | .global _card_wait 159 | .type _card_wait, @function 160 | _card_wait: 161 | li $t2, 0xb0 162 | jr $t2 163 | li $t1, 0x5d 164 | 165 | -------------------------------------------------------------------------------- /tools/minin00b/psxapi/fs.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK BIOS API stubs 2 | # (C) 2022 spicyjpeg - MPL licensed 3 | 4 | # This file has been generated automatically. Each function is placed in its 5 | # own section to allow the linker to strip unused functions. 6 | 7 | .set noreorder 8 | 9 | ## B0 table functions (6) 10 | 11 | .section .text.cd 12 | .global cd 13 | .type cd, @function 14 | cd: 15 | li $t2, 0xb0 16 | jr $t2 17 | li $t1, 0x40 18 | 19 | .section .text.firstfile 20 | .global firstfile 21 | .type firstfile, @function 22 | firstfile: 23 | li $t2, 0xb0 24 | jr $t2 25 | li $t1, 0x42 26 | 27 | .section .text.nextfile 28 | .global nextfile 29 | .type nextfile, @function 30 | nextfile: 31 | li $t2, 0xb0 32 | jr $t2 33 | li $t1, 0x43 34 | 35 | .section .text.rename 36 | .global rename 37 | .type rename, @function 38 | rename: 39 | li $t2, 0xb0 40 | jr $t2 41 | li $t1, 0x44 42 | 43 | .section .text.erase 44 | .global erase 45 | .type erase, @function 46 | erase: 47 | li $t2, 0xb0 48 | jr $t2 49 | li $t1, 0x45 50 | 51 | .section .text.undelete 52 | .global undelete 53 | .type undelete, @function 54 | undelete: 55 | li $t2, 0xb0 56 | jr $t2 57 | li $t1, 0x46 58 | 59 | -------------------------------------------------------------------------------- /tools/minin00b/psxapi/generate_stubs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # PSn00bSDK BIOS stub generator 3 | # (C) 2022 spicyjpeg - MPL licensed 4 | 5 | import os, sys, json 6 | from argparse import ArgumentParser, FileType 7 | 8 | ## Listing section generation 9 | 10 | SECTION_TEMPLATE = """## {title} ({count}) 11 | 12 | {body}""" 13 | FUNCTION_TEMPLATE = """.section .text.{name} 14 | .global {name} 15 | .type {name}, @function 16 | {name}: 17 | li $t2, 0x{address:02x} 18 | jr $t2 19 | li $t1, 0x{id:02x} 20 | 21 | """ 22 | SYSCALL_TEMPLATE = """.section .text.{name} 23 | .global {name} 24 | .type {name}, @function 25 | {name}: 26 | li $a0, 0x{id:02x} 27 | syscall 0 28 | jr $ra 29 | nop 30 | 31 | """ 32 | 33 | STUB_TYPES = { 34 | "a": ( 0xa0, FUNCTION_TEMPLATE, "A0 table functions" ), 35 | "b": ( 0xb0, FUNCTION_TEMPLATE, "B0 table functions" ), 36 | "c": ( 0xc0, FUNCTION_TEMPLATE, "C0 table functions" ), 37 | "syscall": ( 0x00, SYSCALL_TEMPLATE, "Syscalls" ) 38 | } 39 | 40 | def generate_section(_type, entries): 41 | address, template, title = STUB_TYPES[_type] 42 | body = "" 43 | 44 | for entry in entries: 45 | if entry.get("comment", None): 46 | body += f"# {entry['comment'].strip()}\n" 47 | 48 | body += template.format( 49 | name = entry["name"].strip(), 50 | address = address, 51 | id = entry["id"] 52 | ) 53 | 54 | return SECTION_TEMPLATE.format( 55 | title = title, 56 | count = len(entries), 57 | body = body 58 | ) 59 | 60 | ## Main 61 | 62 | HEADER_TEMPLATE = """# PSn00bSDK BIOS API stubs 63 | # (C) 2022 spicyjpeg - MPL licensed 64 | 65 | # This file has been generated automatically. Each function is placed in its 66 | # own section to allow the linker to strip unused functions. 67 | 68 | .set noreorder 69 | 70 | """ 71 | 72 | def get_args(): 73 | parser = ArgumentParser( 74 | description = "Generates MIPS assembly listings of BIOS API stubs." 75 | ) 76 | parser.add_argument( 77 | "json_list", 78 | type = FileType("rt"), 79 | help = "path to JSON list of stubs to generate" 80 | ) 81 | parser.add_argument( 82 | "-o", "--output", 83 | type = str, 84 | default = os.curdir, 85 | help = "where to save generated files (current directory by default)", 86 | metavar = "directory" 87 | ) 88 | 89 | return parser.parse_args() 90 | 91 | def main(): 92 | args = get_args() 93 | 94 | with args.json_list as _file: 95 | all_entries = json.load(_file) 96 | 97 | # { file: { type: [ entry, ... ], ... }, ... } 98 | files = {} 99 | 100 | # Sort all functions by the file they are going to be put in, and by the 101 | # type within the file. 102 | for entry in all_entries: 103 | _type = entry["type"].strip().lower() 104 | _file = entry["file"].strip() 105 | 106 | if type(entry["id"]) is str: 107 | entry["id"] = int(entry["id"], 0) 108 | 109 | if _file not in files: 110 | files[_file] = { _type: [] for _type in STUB_TYPES.keys() } 111 | 112 | files[_file][_type].append(entry) 113 | 114 | for path, types in files.items(): 115 | full_path = os.path.normpath(os.path.join(args.output, path)) 116 | listing = HEADER_TEMPLATE 117 | 118 | for _type, entries in types.items(): 119 | if not entries: 120 | continue 121 | 122 | entries.sort(key = lambda entry: entry["id"]) 123 | listing += generate_section(_type, entries) 124 | 125 | with open(full_path, "wt", newline = "\n") as _file: 126 | _file.write(listing) 127 | 128 | if __name__ == "__main__": 129 | main() 130 | -------------------------------------------------------------------------------- /tools/minin00b/psxapi/stdio.s: -------------------------------------------------------------------------------- 1 | # PSn00bSDK BIOS API stubs 2 | # (C) 2022 spicyjpeg - MPL licensed 3 | 4 | # This file has been generated automatically. Each function is placed in its 5 | # own section to allow the linker to strip unused functions. 6 | 7 | .set noreorder 8 | 9 | ## A0 table functions (14) 10 | 11 | .section .text.open 12 | .global open 13 | .type open, @function 14 | open: 15 | li $t2, 0xa0 16 | jr $t2 17 | li $t1, 0x00 18 | 19 | .section .text.lseek 20 | .global lseek 21 | .type lseek, @function 22 | lseek: 23 | li $t2, 0xa0 24 | jr $t2 25 | li $t1, 0x01 26 | 27 | .section .text.read 28 | .global read 29 | .type read, @function 30 | read: 31 | li $t2, 0xa0 32 | jr $t2 33 | li $t1, 0x02 34 | 35 | .section .text.write 36 | .global write 37 | .type write, @function 38 | write: 39 | li $t2, 0xa0 40 | jr $t2 41 | li $t1, 0x03 42 | 43 | .section .text.close 44 | .global close 45 | .type close, @function 46 | close: 47 | li $t2, 0xa0 48 | jr $t2 49 | li $t1, 0x04 50 | 51 | .section .text.ioctl 52 | .global ioctl 53 | .type ioctl, @function 54 | ioctl: 55 | li $t2, 0xa0 56 | jr $t2 57 | li $t1, 0x05 58 | 59 | .section .text.isatty 60 | .global isatty 61 | .type isatty, @function 62 | isatty: 63 | li $t2, 0xa0 64 | jr $t2 65 | li $t1, 0x07 66 | 67 | .section .text.getc 68 | .global getc 69 | .type getc, @function 70 | getc: 71 | li $t2, 0xa0 72 | jr $t2 73 | li $t1, 0x08 74 | 75 | .section .text.putc 76 | .global putc 77 | .type putc, @function 78 | putc: 79 | li $t2, 0xa0 80 | jr $t2 81 | li $t1, 0x09 82 | 83 | .section .text.getchar 84 | .global getchar 85 | .type getchar, @function 86 | getchar: 87 | li $t2, 0xa0 88 | jr $t2 89 | li $t1, 0x3b 90 | 91 | .section .text.putchar 92 | .global putchar 93 | .type putchar, @function 94 | putchar: 95 | li $t2, 0xa0 96 | jr $t2 97 | li $t1, 0x3c 98 | 99 | .section .text.gets 100 | .global gets 101 | .type gets, @function 102 | gets: 103 | li $t2, 0xa0 104 | jr $t2 105 | li $t1, 0x3d 106 | 107 | .section .text.puts 108 | .global puts 109 | .type puts, @function 110 | puts: 111 | li $t2, 0xa0 112 | jr $t2 113 | li $t1, 0x3e 114 | 115 | .section .text.printf 116 | .global printf 117 | .type printf, @function 118 | printf: 119 | li $t2, 0xa0 120 | jr $t2 121 | li $t1, 0x3f 122 | 123 | ## B0 table functions (2) 124 | 125 | .section .text._get_errno 126 | .global _get_errno 127 | .type _get_errno, @function 128 | _get_errno: 129 | li $t2, 0xb0 130 | jr $t2 131 | li $t1, 0x54 132 | 133 | .section .text._get_error 134 | .global _get_error 135 | .type _get_error, @function 136 | _get_error: 137 | li $t2, 0xb0 138 | jr $t2 139 | li $t1, 0x55 140 | 141 | -------------------------------------------------------------------------------- /tools/minin00b/psxcd/cdread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK CD-ROM library (high-level reading API) 3 | * (C) 2020-2022 Lameguy64, spicyjpeg - MPL licensed 4 | * 5 | * CdRead() and its related functions are separate from the "main" psxcd code 6 | * since handling retries is fairly complicated. In particular the drive 7 | * controller will not process any command properly for some time after a 8 | * CdlPause command, so an external timer (the vblank counter) and manual 9 | * polling are required to defer the next attempt. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define CD_READ_TIMEOUT 180 19 | #define CD_READ_COOLDOWN 60 20 | 21 | /* Internal globals */ 22 | 23 | static CdlCB _read_callback = (CdlCB) 0; 24 | 25 | static int _total_sectors, _sector_size; 26 | static uint8_t _read_result[4]; 27 | 28 | static volatile uint32_t *_read_addr; 29 | static volatile int _read_timeout, _pending_attempts, _pending_sectors; 30 | 31 | extern CdlCB _cd_override_callback; 32 | 33 | /* Private utilities and sector callback */ 34 | 35 | static void _sector_callback(CdlIntrResult irq, uint8_t *result) { 36 | if (irq == CdlDataReady) { 37 | CdGetSector((void *) _read_addr, _sector_size); 38 | _read_addr += _sector_size; 39 | 40 | if (--_pending_sectors > 0) { 41 | _read_timeout = VSync(-1) + CD_READ_TIMEOUT; 42 | return; 43 | } 44 | } 45 | 46 | // Stop reading if an error occurred or if no more sectors need to be read. 47 | CdCommandF(CdlPause, 0, 0); 48 | 49 | _cd_override_callback = (CdlCB) 0; 50 | if ((!_pending_sectors || !_pending_attempts) && _read_callback) 51 | _read_callback(irq, result); 52 | 53 | _read_timeout = VSync(-1) + CD_READ_COOLDOWN; 54 | } 55 | 56 | static int _poll_retry(void) { 57 | if (!_pending_attempts) { 58 | _sdk_log("CdRead() failed, too many attempts\n"); 59 | 60 | _pending_sectors = 0; 61 | return -1; 62 | } 63 | 64 | //CdControlB(CdlPause, 0, 0); 65 | 66 | _sdk_log("CdRead() failed, retrying (%d sectors pending)\n", _pending_sectors); 67 | _pending_attempts--; 68 | 69 | // Restart from the first sector that returned an error. 70 | CdlLOC pos; 71 | CdIntToPos( 72 | CdPosToInt(CdLastPos()) + _total_sectors - _pending_sectors, 73 | &pos 74 | ); 75 | 76 | _read_timeout = VSync(-1) + CD_READ_TIMEOUT; 77 | _total_sectors = _pending_sectors; 78 | 79 | FastEnterCriticalSection(); 80 | _cd_override_callback = &_sector_callback; 81 | FastExitCriticalSection(); 82 | 83 | if (CdCommand(CdlSetloc, (uint8_t *) &pos, 3, _read_result)) 84 | CdCommand(CdlReadN, 0, 0, _read_result); 85 | 86 | return _pending_sectors; 87 | } 88 | 89 | /* Public API */ 90 | 91 | int CdReadRetry(int sectors, uint32_t *buf, int mode, int attempts) { 92 | _sdk_validate_args((sectors > 0) && buf && (attempts > 0), -1); 93 | 94 | if (CdReadSync(1, 0) > 0) { 95 | _sdk_log("CdRead() failed, another read in progress (%d sectors pending)\n", _pending_sectors); 96 | return 0; 97 | } 98 | 99 | _read_addr = buf; 100 | _read_timeout = VSync(-1) + CD_READ_TIMEOUT; 101 | _pending_attempts = attempts - 1; 102 | _pending_sectors = sectors; 103 | _total_sectors = sectors; 104 | _sector_size = (mode & CdlModeSize) ? 585 : 512; 105 | 106 | FastEnterCriticalSection(); 107 | _cd_override_callback = &_sector_callback; 108 | FastExitCriticalSection(); 109 | 110 | uint8_t _mode = mode; 111 | if (!CdCommand(CdlSetmode, &_mode, 1, 0)) 112 | return 0; 113 | if (!CdCommand(CdlReadN, 0, 0, _read_result)) 114 | return 0; 115 | 116 | return 1; 117 | } 118 | 119 | int CdRead(int sectors, uint32_t *buf, int mode) { 120 | return CdReadRetry(sectors, buf, mode, 1); 121 | } 122 | 123 | void CdReadBreak(void) { 124 | if (_pending_sectors > 0) 125 | _pending_sectors = -1; 126 | } 127 | 128 | int CdReadSync(int mode, uint8_t *result) { 129 | if (mode) { 130 | if (_pending_sectors < 0) 131 | return -2; 132 | if (!_pending_sectors) 133 | return 0; 134 | 135 | if (VSync(-1) > _read_timeout) 136 | return _poll_retry(); 137 | if (CdSync(1, 0) == CdlDiskError) 138 | return -1; 139 | 140 | return _pending_sectors; 141 | } 142 | 143 | while (_pending_sectors > 0) { 144 | if (VSync(-1) > _read_timeout) { 145 | if (_poll_retry() < 0) 146 | return -1; 147 | } 148 | 149 | //if (CdSync(1, 0) == CdlDiskError) 150 | //return -1; 151 | } 152 | 153 | CdlIntrResult status = CdSync(0, result); 154 | if (_pending_sectors < 0) 155 | return -2; 156 | if (status != CdlComplete) 157 | return -1; 158 | 159 | return 0; 160 | } 161 | 162 | CdlCB CdReadCallback(CdlCB func) { 163 | FastEnterCriticalSection(); 164 | 165 | CdlCB old_callback = _read_callback; 166 | _read_callback = func; 167 | 168 | FastExitCriticalSection(); 169 | return old_callback; 170 | } 171 | -------------------------------------------------------------------------------- /tools/minin00b/psxcd/readme.txt: -------------------------------------------------------------------------------- 1 | PSX CD-ROM library, part of PSn00bSDK 2 | 2020-2022 Lameguy64 / Meido-Tek Productions 3 | 4 | Licensed under Mozilla Public License 5 | 6 | Open source implementation of the long awaited CD-ROM library that provides 7 | greater functionality than the BIOS CD-ROM subsystem. Supports pretty much all 8 | features of the CD-ROM hardware such as CD data read, CD Audio and XA audio 9 | playback, with the exception of the St*() APIs for .STR playback (but manual 10 | streaming using CdReadyCallback() is still supported). 11 | 12 | An ISO9660 file system driver for locating files within the CD-ROM is also 13 | included. Unlike the ISO9660 parser in the official libraries, libpsxcd can 14 | parse directories containing any number of files. Currently no ISO9660 15 | extensions are supported. 16 | 17 | Be aware that the CD-ROM library might have some loose ends as it is still a 18 | work in progress, but should work flawlessly in most use cases. 19 | 20 | Library developer(s): 21 | 22 | Lameguy64 (ISO9660 driver, initial implementation of low-level functions) 23 | spicyjpeg (C rewrite) 24 | 25 | Library header(s): 26 | 27 | psxcd.h 28 | 29 | Todo list: 30 | 31 | * Command query mechanism so that more than 2 CD-ROM commands can 32 | easily be issued in callbacks. Official library probably does this. 33 | 34 | * Helper functions for handling disc changes (CdDiskReady and 35 | CdGetDiskType) are not yet implemented. 36 | 37 | * Data streaming functions (prefixed with St*) not yet implemented. 38 | Would require devising a PSn00bSDK equivalent of the STR file 39 | format. 40 | -------------------------------------------------------------------------------- /tools/minin00b/psxetc/readme.txt: -------------------------------------------------------------------------------- 1 | PSX Misc library, part of PSn00bSDK 2 | 2021 Lameguy64 / Meido-Tek Productions 3 | 4 | Licensed under Mozilla Public License 5 | 6 | Open source implementation of the ETC library. Currently provides the interrupt 7 | and DMA callback dispatchers (used by other libraries) as well as the DL_* and 8 | dl* functions for dynamic library loading (original, not present in the official 9 | SDK but similar to the standard dlopen() API). 10 | 11 | Library developer(s): 12 | 13 | Lameguy64 14 | spicyjpeg 15 | 16 | Library header(s): 17 | 18 | psxetc.h 19 | dlfcn.h 20 | elf.h (used internally) 21 | -------------------------------------------------------------------------------- /tools/minin00b/psxgpu/dbugfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/psxgpu/dbugfont.png -------------------------------------------------------------------------------- /tools/minin00b/psxgpu/dbugfont.tim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mateusfavarin/psx-modding-toolchain/f790f6c39750ad69b16c952940d9f32a21f217e2/tools/minin00b/psxgpu/dbugfont.tim -------------------------------------------------------------------------------- /tools/minin00b/psxgpu/drawing.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK GPU library (drawing/display list functions) 3 | * (C) 2022-2023 spicyjpeg - MPL licensed 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* Private utilities */ 13 | 14 | // This function is actually referenced in env.c as well, so it can't be static. 15 | void _send_linked_list(GPU_DrawOpType type, const uint32_t *ot) { 16 | SetDrawOpType(type); 17 | GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 18 | 19 | while (DMA_CHCR(DMA_GPU) & (1 << 24)) 20 | __asm__ volatile(""); 21 | 22 | DMA_MADR(DMA_GPU) = (uint32_t) ot; 23 | DMA_BCR(DMA_GPU) = 0; 24 | DMA_CHCR(DMA_GPU) = 0x01000401; 25 | } 26 | 27 | static void _send_buffer( 28 | GPU_DrawOpType type, const uint32_t *buf, size_t length 29 | ) { 30 | SetDrawOpType(type); 31 | GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 32 | 33 | while (DMA_CHCR(DMA_GPU) & (1 << 24)) 34 | __asm__ volatile(""); 35 | 36 | DMA_MADR(DMA_GPU) = (uint32_t) buf; 37 | DMA_BCR(DMA_GPU) = 0x00000001 | (length << 16); 38 | DMA_CHCR(DMA_GPU) = 0x01000201; 39 | } 40 | 41 | /* Buffer and primitive drawing API */ 42 | 43 | int DrawOTag(const uint32_t *ot) { 44 | _sdk_validate_args(ot, -1); 45 | 46 | return EnqueueDrawOp( 47 | (void *) &_send_linked_list, 48 | (uint32_t) DRAWOP_TYPE_DMA, 49 | (uint32_t) ot, 50 | 0 51 | ); 52 | } 53 | 54 | int DrawOTagIRQ(const uint32_t *ot) { 55 | _sdk_validate_args(ot, -1); 56 | 57 | return EnqueueDrawOp( 58 | (void *) &_send_linked_list, 59 | (uint32_t) DRAWOP_TYPE_GPU_IRQ, 60 | (uint32_t) ot, 61 | 0 62 | ); 63 | } 64 | 65 | int DrawBuffer(const uint32_t *buf, size_t length) { 66 | _sdk_validate_args(buf && length && (length <= 0xffff), -1); 67 | 68 | return EnqueueDrawOp( 69 | (void *) &DrawBuffer2, 70 | (uint32_t) DRAWOP_TYPE_DMA, 71 | (uint32_t) buf, 72 | (uint32_t) length 73 | ); 74 | } 75 | 76 | int DrawBufferIRQ(const uint32_t *buf, size_t length) { 77 | _sdk_validate_args(buf && length && (length <= 0xffff), -1); 78 | 79 | return EnqueueDrawOp( 80 | (void *) &DrawBuffer2, 81 | (uint32_t) DRAWOP_TYPE_GPU_IRQ, 82 | (uint32_t) buf, 83 | (uint32_t) length 84 | ); 85 | } 86 | 87 | void DrawOTag2(const uint32_t *ot) { 88 | _sdk_validate_args_void(ot); 89 | 90 | _send_linked_list(DRAWOP_TYPE_DMA, ot); 91 | } 92 | 93 | void DrawOTagIRQ2(const uint32_t *ot) { 94 | _sdk_validate_args_void(ot); 95 | 96 | _send_linked_list(DRAWOP_TYPE_GPU_IRQ, ot); 97 | } 98 | 99 | void DrawBuffer2(const uint32_t *buf, size_t length) { 100 | _sdk_validate_args_void(buf && length && (length <= 0xffff)); 101 | 102 | _send_buffer(DRAWOP_TYPE_DMA, buf, length); 103 | } 104 | 105 | void DrawBufferIRQ2(const uint32_t *buf, size_t length) { 106 | _sdk_validate_args_void(buf && length && (length <= 0xffff)); 107 | 108 | _send_buffer(DRAWOP_TYPE_GPU_IRQ, buf, length); 109 | } 110 | 111 | void DrawPrim(const void *pri) { 112 | _sdk_validate_args_void(pri); 113 | 114 | DrawSync(0); 115 | DrawBuffer2(((const uint32_t *) pri) + 1, getlen(pri)); 116 | } 117 | 118 | /* Helper functions */ 119 | 120 | void ClearOTagR(uint32_t *ot, size_t length) { 121 | _sdk_validate_args_void(ot && length); 122 | 123 | DMA_MADR(DMA_OTC) = (uint32_t) &ot[length - 1]; 124 | DMA_BCR(DMA_OTC) = length & 0xffff; 125 | DMA_CHCR(DMA_OTC) = 0x11000002; 126 | 127 | while (DMA_CHCR(DMA_OTC) & (1 << 24)) 128 | __asm__ volatile(""); 129 | } 130 | 131 | void ClearOTag(uint32_t *ot, size_t length) { 132 | _sdk_validate_args_void(ot && length); 133 | 134 | // DMA6 only supports writing to RAM in reverse order (last to first), so 135 | // the OT has to be cleared in software here. This function is thus much 136 | // slower than ClearOTagR(). 137 | // https://problemkaputt.de/psx-spx.htm#dmachannels 138 | for (int i = 0; i < (length - 1); i++) 139 | ot[i] = (uint32_t) &ot[i + 1] & 0x7fffff; 140 | 141 | ot[length - 1] = 0xffffff; 142 | } 143 | 144 | void AddPrim(uint32_t *ot, const void *pri) { 145 | _sdk_validate_args_void(ot && pri); 146 | 147 | addPrim(ot, pri); 148 | } 149 | -------------------------------------------------------------------------------- /tools/minin00b/psxgpu/readme.txt: -------------------------------------------------------------------------------- 1 | PSX GPU library, part of PSn00bSDK 2 | 2019 Lameguy64 / Meido-Tek Productions 3 | 4 | Licensed under Mozilla Public License 5 | 6 | Open source implementation of the GPU library written entirely in C. Supports 7 | DMA transfers for drawing OTs (with an internal queue so DrawOTag() can be 8 | called even when another OT is being drawn) and transferring image data to and 9 | from VRAM. The syntax is intentionally made to closely resemble Sony's syntax 10 | for familiarity and to make porting homebrew made using the official SDK to 11 | PSn00bSDK a little easier. 12 | 13 | Library developer(s): 14 | 15 | Lameguy64 (initial implementation in assembly, debug font API) 16 | spicyjpeg 17 | 18 | Library header(s): 19 | 20 | psxgpu.h 21 | -------------------------------------------------------------------------------- /tools/minin00b/psxgte/initgeom.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | 3 | .include "hwregs_a.inc" 4 | .include "gtereg.inc" 5 | 6 | .section .text.InitGeom 7 | .global InitGeom 8 | .type InitGeom, @function 9 | InitGeom: 10 | # Disable interrupts and make sure the GTE is enabled in COP0. 11 | lui $v0, IOBASE 12 | lhu $v1, IRQ_MASK($v0) 13 | nop 14 | sh $0, IRQ_MASK($v0) 15 | 16 | mfc0 $a0, $12 17 | lui $a1, 0x4000 18 | or $a1, $a0 19 | mtc0 $a1, $12 20 | nop 21 | #nop 22 | 23 | # Re-enable interrupts, then load default values into some GTE registers. 24 | sh $v1, IRQ_MASK($v0) 25 | 26 | ctc2 $0, C2_OFX 27 | nop 28 | ctc2 $0, C2_OFY 29 | 30 | li $a0, 320 31 | ctc2 $a0, C2_H 32 | 33 | li $a0, 0x155 34 | ctc2 $a0, C2_ZSF3 35 | li $a0, 0x100 36 | ctc2 $a0, C2_ZSF4 37 | 38 | li $a0, 0xef9e 39 | ctc2 $a0, C2_DQA 40 | lui $a0, 0x0140 41 | ctc2 $a0, C2_DQB 42 | 43 | jr $ra 44 | nop 45 | -------------------------------------------------------------------------------- /tools/minin00b/psxgte/isin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK (incomplete) trigonometry library 3 | * (C) 2019-2022 Lameguy64, spicyjpeg - MPL licensed 4 | * 5 | * Based on isin_S4 implementation from coranac: 6 | * https://www.coranac.com/2009/07/sines 7 | */ 8 | 9 | #define qN_l 10 10 | #define qN_h 15 11 | #define qA 12 12 | #define B 19900 13 | #define C 3516 14 | 15 | static inline int _isin(int qN, int x) { 16 | int c, x2, y; 17 | 18 | c = x << (30 - qN); // Semi-circle info into carry. 19 | x -= 1 << qN; // sine -> cosine calc 20 | 21 | x <<= (31 - qN); // Mask with PI 22 | x >>= (31 - qN); // Note: SIGNED shift! (to qN) 23 | x *= x; 24 | x >>= (2 * qN - 14); // x=x^2 To Q14 25 | 26 | y = B - (x * C >> 14); // B - x^2*C 27 | y = (1 << qA) - (x * y >> 16); // A - x^2*(B-x^2*C) 28 | 29 | return (c >= 0) ? y : (-y); 30 | } 31 | 32 | int isin(int x) { 33 | return _isin(qN_l, x); 34 | } 35 | 36 | int icos(int x) { 37 | return _isin(qN_l, x + (1 << qN_l)); 38 | } 39 | 40 | int hisin(int x) { 41 | return _isin(qN_h, x); 42 | } 43 | 44 | int hicos(int x) { 45 | return _isin(qN_h, x + (1 << qN_h)); 46 | } 47 | -------------------------------------------------------------------------------- /tools/minin00b/psxgte/matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MATRIX *RotMatrix(SVECTOR *r, MATRIX *m) { 4 | short s[3],c[3]; 5 | MATRIX tm[3]; 6 | 7 | s[0] = isin(r->vx); s[1] = isin(r->vy); s[2] = isin(r->vz); 8 | c[0] = icos(r->vx); c[1] = icos(r->vy); c[2] = icos(r->vz); 9 | 10 | // mX 11 | m->m[0][0] = ONE; m->m[0][1] = 0; m->m[0][2] = 0; 12 | m->m[1][0] = 0; m->m[1][1] = c[0]; m->m[1][2] = -s[0]; 13 | m->m[2][0] = 0; m->m[2][1] = s[0]; m->m[2][2] = c[0]; 14 | 15 | // mY 16 | tm[0].m[0][0] = c[1]; tm[0].m[0][1] = 0; tm[0].m[0][2] = s[1]; 17 | tm[0].m[1][0] = 0; tm[0].m[1][1] = ONE; tm[0].m[1][2] = 0; 18 | tm[0].m[2][0] = -s[1]; tm[0].m[2][1] = 0; tm[0].m[2][2] = c[1]; 19 | 20 | // mZ 21 | tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0; 22 | tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0; 23 | tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE; 24 | 25 | PushMatrix(); 26 | MulMatrix0( m, &tm[0], &tm[2] ); 27 | MulMatrix0( &tm[2], &tm[1], m ); 28 | PopMatrix(); 29 | 30 | return m; 31 | } 32 | 33 | MATRIX *HiRotMatrix(VECTOR *r, MATRIX *m) { 34 | short s[3],c[3]; 35 | MATRIX tm[3]; 36 | 37 | s[0] = hisin(r->vx); s[1] = hisin(r->vy); s[2] = hisin(r->vz); 38 | c[0] = hicos(r->vx); c[1] = hicos(r->vy); c[2] = hicos(r->vz); 39 | 40 | // mX 41 | m->m[0][0] = ONE; m->m[0][1] = 0; m->m[0][2] = 0; 42 | m->m[1][0] = 0; m->m[1][1] = c[0]; m->m[1][2] = -s[0]; 43 | m->m[2][0] = 0; m->m[2][1] = s[0]; m->m[2][2] = c[0]; 44 | 45 | // mY 46 | tm[0].m[0][0] = c[1]; tm[0].m[0][1] = 0; tm[0].m[0][2] = s[1]; 47 | tm[0].m[1][0] = 0; tm[0].m[1][1] = ONE; tm[0].m[1][2] = 0; 48 | tm[0].m[2][0] = -s[1]; tm[0].m[2][1] = 0; tm[0].m[2][2] = c[1]; 49 | 50 | // mZ 51 | tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0; 52 | tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0; 53 | tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE; 54 | 55 | PushMatrix(); 56 | MulMatrix0( m, &tm[0], &tm[2] ); 57 | MulMatrix0( &tm[2], &tm[1], m ); 58 | PopMatrix(); 59 | 60 | return m; 61 | } 62 | 63 | MATRIX *TransMatrix(MATRIX *m, VECTOR *r) { 64 | m->t[0] = r->vx; 65 | m->t[1] = r->vy; 66 | m->t[2] = r->vz; 67 | 68 | return m; 69 | } 70 | -------------------------------------------------------------------------------- /tools/minin00b/psxgte/readme.txt: -------------------------------------------------------------------------------- 1 | PSX GTE library, part of PSn00bSDK 2 | 2019 Lameguy64 / Meido-Tek Productions 3 | 4 | Licensed under Mozilla Public License 5 | 6 | Open source implementation of the GTE library written mostly in MIPS 7 | assembly. It makes full use of the GTE in complex matrix multiplication 8 | operations. The syntax is intentionally made to closely resemble Sony's syntax 9 | for familiarity and to make porting homebrew made using the official SDK to 10 | PSn00bSDK a little easier. 11 | 12 | Unlike the official GTE libraries using the inline GTE macro functions does 13 | not require running your object file through some stupid tool such as DMPSX. 14 | The GTE macros use the corresponding cop2 opcodes already. 15 | 16 | 17 | Library developer(s): 18 | 19 | Lameguy64 20 | 21 | 22 | Library header(s): 23 | 24 | gtereg.inc 25 | inline_c.h 26 | inline_s.inc 27 | psxgte.h 28 | 29 | 30 | Todo list: 31 | 32 | * Alternate RotMatrix() functions with different rotation orders are yet to 33 | be implemented. 34 | * Various high level RotTransPersp style functions not yet implemented. 35 | 36 | -------------------------------------------------------------------------------- /tools/minin00b/psxgte/squareroot.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | 3 | .include "gtereg.inc" 4 | .include "inline_s.inc" 5 | 6 | .section .text.SquareRoot12 7 | .global SquareRoot12 8 | .type SquareRoot12, @function 9 | SquareRoot12: 10 | mtc2 $a0, C2_LZCS 11 | nop 12 | nop 13 | mfc2 $v0, C2_LZCR 14 | beq $v0, 32, .Lbad_sqr12 15 | nop 16 | andi $t0, $v0, 0x1 17 | addiu $v1, $0 , -2 18 | and $t2, $v0, $v1 19 | li $t1, 19 20 | sub $t1, $t2 21 | sra $t1, 1 22 | addi $t3, $t2, -24 23 | bltz $t3, .Lvalue_less12 24 | nop 25 | sllv $t4, $a0, $t3 26 | b .Lvalue_greater12 27 | .Lvalue_less12: 28 | addiu $t3, $0 , 24 29 | sub $t3, $t2 30 | srav $t4, $a0, $t3 31 | .Lvalue_greater12: 32 | addi $t4, -64 33 | sll $t4, 1 34 | la $t5, _sqrt_table 35 | addu $t5, $t4 36 | lh $t5, 0($t5) 37 | nop 38 | 39 | bltz $t1, .L1594c 40 | nop 41 | jr $ra 42 | sllv $v0, $t5, $t1 43 | 44 | .L1594c: 45 | sub $t1, $0 , $t1 46 | jr $ra 47 | srl $v0, $t5, $t1 48 | 49 | .Lbad_sqr12: 50 | jr $ra 51 | move $v0, $0 52 | 53 | .section .text.SquareRoot0 54 | .global SquareRoot0 55 | .type SquareRoot0, @function 56 | SquareRoot0: 57 | mtc2 $a0, C2_LZCS 58 | nop 59 | nop 60 | mfc2 $v0, C2_LZCR 61 | beq $v0, 32, .Lbad_sqr 62 | nop 63 | andi $t0, $v0, 0x1 64 | addiu $v1, $0 , -2 65 | and $t2, $v0, $v1 66 | li $t1, 31 67 | sub $t1, $t2 68 | sra $t1, 1 69 | addi $t3, $t2, -24 70 | bltz $t3, .Lvalue_less 71 | nop 72 | sllv $t4, $a0, $t3 73 | b .Lvalue_greater 74 | .Lvalue_less: 75 | addiu $t3, $0 , 24 76 | sub $t3, $t2 77 | srav $t4, $a0, $t3 78 | .Lvalue_greater: 79 | addi $t4, -64 80 | sll $t4, 1 81 | la $t5, _sqrt_table 82 | addu $t5, $t4 83 | lh $t5, 0($t5) 84 | nop 85 | sllv $t5, $t5, $t1 86 | jr $ra 87 | srl $v0, $t5, 12 88 | .Lbad_sqr: 89 | jr $ra 90 | move $v0, $0 91 | 92 | .section .data._sqrt_table 93 | .type _sqrt_table, @object 94 | _sqrt_table: 95 | .hword 0x1000, 0x101f, 0x103f, 0x105e, 0x107e, 0x109c, 0x10bb, 0x10da 96 | .hword 0x10f8, 0x1116, 0x1134, 0x1152, 0x116f, 0x118c, 0x11a9, 0x11c6 97 | .hword 0x11e3, 0x1200, 0x121c, 0x1238, 0x1254, 0x1270, 0x128c, 0x12a7 98 | .hword 0x12c2, 0x12de, 0x12f9, 0x1314, 0x132e, 0x1349, 0x1364, 0x137e 99 | .hword 0x1398, 0x13b2, 0x13cc, 0x13e6, 0x1400, 0x1419, 0x1432, 0x144c 100 | .hword 0x1465, 0x147e, 0x1497, 0x14b0, 0x14c8, 0x14e1, 0x14f9, 0x1512 101 | .hword 0x152a, 0x1542, 0x155a, 0x1572, 0x158a, 0x15a2, 0x15b9, 0x15d1 102 | .hword 0x15e8, 0x1600, 0x1617, 0x162e, 0x1645, 0x165c, 0x1673, 0x1689 103 | .hword 0x16a0, 0x16b7, 0x16cd, 0x16e4, 0x16fa, 0x1710, 0x1726, 0x173c 104 | .hword 0x1752, 0x1768, 0x177e, 0x1794, 0x17aa, 0x17bf, 0x17d5, 0x17ea 105 | .hword 0x1800, 0x1815, 0x182a, 0x183f, 0x1854, 0x1869, 0x187e, 0x1893 106 | .hword 0x18a8, 0x18bd, 0x18d1, 0x18e6, 0x18fa, 0x190f, 0x1923, 0x1938 107 | .hword 0x194c, 0x1960, 0x1974, 0x1988, 0x199c, 0x19b0, 0x19c4, 0x19d8 108 | .hword 0x19ec, 0x1a00, 0x1a13, 0x1a27, 0x1a3a, 0x1a4e, 0x1a61, 0x1a75 109 | .hword 0x1a88, 0x1a9b, 0x1aae, 0x1ac2, 0x1ad5, 0x1ae8, 0x1afb, 0x1b0e 110 | .hword 0x1b21, 0x1b33, 0x1b46, 0x1b59, 0x1b6c, 0x1b7e, 0x1b91, 0x1ba3 111 | .hword 0x1bb6, 0x1bc8, 0x1bdb, 0x1bed, 0x1c00, 0x1c12, 0x1c24, 0x1c36 112 | .hword 0x1c48, 0x1c5a, 0x1c6c, 0x1c7e, 0x1c90, 0x1ca2, 0x1cb4, 0x1cc6 113 | .hword 0x1cd8, 0x1ce9, 0x1cfb, 0x1d0d, 0x1d1e, 0x1d30, 0x1d41, 0x1d53 114 | .hword 0x1d64, 0x1d76, 0x1d87, 0x1d98, 0x1daa, 0x1dbb, 0x1dcc, 0x1ddd 115 | .hword 0x1dee, 0x1e00, 0x1e11, 0x1e22, 0x1e33, 0x1e43, 0x1e54, 0x1e65 116 | .hword 0x1e76, 0x1e87, 0x1e98, 0x1ea8, 0x1eb9, 0x1eca, 0x1eda, 0x1eeb 117 | .hword 0x1efb, 0x1f0c, 0x1f1c, 0x1f2d, 0x1f3d, 0x1f4e, 0x1f5e, 0x1f6e 118 | .hword 0x1f7e, 0x1f8f, 0x1f9f, 0x1faf, 0x1fbf, 0x1fcf, 0x1fdf, 0x1fef 119 | -------------------------------------------------------------------------------- /tools/minin00b/psxgte/vector.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | .set noat 3 | 4 | .include "gtereg.inc" 5 | .include "inline_s.inc" 6 | 7 | .section .text.Square0 8 | .global Square0 9 | .type Square0, @function 10 | Square0: 11 | # a0 - Pointer to input vector (v0) 12 | # a1 - Pointer to output vector (v1) 13 | 14 | lwc2 C2_IR1, 0($a0) 15 | lwc2 C2_IR2, 4($a0) 16 | lwc2 C2_IR3, 8($a0) 17 | 18 | nSQR(0) 19 | 20 | swc2 C2_IR1, 0($a1) 21 | swc2 C2_IR2, 4($a1) 22 | swc2 C2_IR3, 8($a1) 23 | 24 | jr $ra 25 | nop 26 | 27 | .section .text.VectorNormalS 28 | .global VectorNormalS 29 | .type VectorNormalS, @function 30 | VectorNormalS: 31 | 32 | lw $t0, 0($a0) 33 | lw $t1, 4($a0) 34 | lw $t2, 8($a0) 35 | 36 | mtc2 $t0, C2_IR1 37 | mtc2 $t1, C2_IR2 38 | mtc2 $t2, C2_IR3 39 | 40 | nSQR(0) 41 | 42 | mfc2 $t3, C2_MAC1 43 | mfc2 $t4, C2_MAC2 44 | mfc2 $t5, C2_MAC3 45 | 46 | add $t3, $t4 47 | add $v0, $t3, $t5 48 | mtc2 $v0, C2_LZCS 49 | nop 50 | nop 51 | mfc2 $v1, C2_LZCR 52 | 53 | addiu $at, $0 , -2 54 | and $v1, $at 55 | 56 | addiu $t6, $0 , 0x1f 57 | sub $t6, $v1 58 | sra $t6, 1 59 | addiu $t3, $v1, -24 60 | 61 | bltz $t3, .Lvalue_neg 62 | nop 63 | b .Lvalue_pos 64 | sllv $t4, $v0, $t3 65 | .Lvalue_neg: 66 | addiu $t3, $0 , 24 67 | sub $t3, $v1 68 | srav $t4, $v0, $t3 69 | .Lvalue_pos: 70 | addi $t4, -64 71 | sll $t4, 1 72 | 73 | la $t5, _norm_table 74 | addu $t5, $t4 75 | lh $t5, 0($t5) 76 | 77 | mtc2 $t0, C2_IR1 78 | mtc2 $t1, C2_IR2 79 | mtc2 $t2, C2_IR3 80 | mtc2 $t5, C2_IR0 81 | 82 | nGPF(0) 83 | 84 | mfc2 $t0, C2_MAC1 85 | mfc2 $t1, C2_MAC2 86 | mfc2 $t2, C2_MAC3 87 | 88 | sra $t0, $t6 89 | sra $t1, $t6 90 | sra $t2, $t6 91 | 92 | sh $t0, 0($a1) 93 | sh $t1, 2($a1) 94 | jr $ra 95 | sh $t2, 4($a1) 96 | 97 | .section .data._norm_table 98 | .type _norm_table, @object 99 | _norm_table: 100 | .hword 0x1000, 0x0fe0, 0x0fc1, 0x0fa3, 0x0f85, 0x0f68, 0x0f4c, 0x0f30 101 | .hword 0x0f15, 0x0efb, 0x0ee1, 0x0ec7, 0x0eae, 0x0e96, 0x0e7e, 0x0e66 102 | .hword 0x0e4f, 0x0e38, 0x0e22, 0x0e0c, 0x0df7, 0x0de2, 0x0dcd, 0x0db9 103 | .hword 0x0da5, 0x0d91, 0x0d7e, 0x0d6b, 0x0d58, 0x0d45, 0x0d33, 0x0d21 104 | .hword 0x0d10, 0x0cff, 0x0cee, 0x0cdd, 0x0ccc, 0x0cbc, 0x0cac, 0x0c9c 105 | .hword 0x0c8d, 0x0c7d, 0x0c6e, 0x0c5f, 0x0c51, 0x0c42, 0x0c34, 0x0c26 106 | .hword 0x0c18, 0x0c0a, 0x0bfd, 0x0bef, 0x0be2, 0x0bd5, 0x0bc8, 0x0bbb 107 | .hword 0x0baf, 0x0ba2, 0x0b96, 0x0b8a, 0x0b7e, 0x0b72, 0x0b67, 0x0b5b 108 | .hword 0x0b50, 0x0b45, 0x0b39, 0x0b2e, 0x0b24, 0x0b19, 0x0b0e, 0x0b04 109 | .hword 0x0af9, 0x0aef, 0x0ae5, 0x0adb, 0x0ad1, 0x0ac7, 0x0abd, 0x0ab4 110 | .hword 0x0aaa, 0x0aa1, 0x0a97, 0x0a8e, 0x0a85, 0x0a7c, 0x0a73, 0x0a6a 111 | .hword 0x0a61, 0x0a59, 0x0a50, 0x0a47, 0x0a3f, 0x0a37, 0x0a2e, 0x0a26 112 | .hword 0x0a1e, 0x0a16, 0x0a0e, 0x0a06, 0x09fe, 0x09f6, 0x09ef, 0x09e7 113 | .hword 0x09e0, 0x09d8, 0x09d1, 0x09c9, 0x09c2, 0x09bb, 0x09b4, 0x09ad 114 | .hword 0x09a5, 0x099e, 0x0998, 0x0991, 0x098a, 0x0983, 0x097c, 0x0976 115 | .hword 0x096f, 0x0969, 0x0962, 0x095c, 0x0955, 0x094f, 0x0949, 0x0943 116 | .hword 0x093c, 0x0936, 0x0930, 0x092a, 0x0924, 0x091e, 0x0918, 0x0912 117 | .hword 0x090d, 0x0907, 0x0901, 0x08fb, 0x08f6, 0x08f0, 0x08eb, 0x08e5 118 | .hword 0x08e0, 0x08da, 0x08d5, 0x08cf, 0x08ca, 0x08c5, 0x08bf, 0x08ba 119 | .hword 0x08b5, 0x08b0, 0x08ab, 0x08a6, 0x08a1, 0x089c, 0x0897, 0x0892 120 | .hword 0x088d, 0x0888, 0x0883, 0x087e, 0x087a, 0x0875, 0x0870, 0x086b 121 | .hword 0x0867, 0x0862, 0x085e, 0x0859, 0x0855, 0x0850, 0x084c, 0x0847 122 | .hword 0x0843, 0x083e, 0x083a, 0x0836, 0x0831, 0x082d, 0x0829, 0x0824 123 | .hword 0x0820, 0x081c, 0x0818, 0x0814, 0x0810, 0x080c, 0x0808, 0x0804 124 | -------------------------------------------------------------------------------- /tools/minin00b/psxpress/README.md: -------------------------------------------------------------------------------- 1 | 2 | # PSn00bSDK MDEC library 3 | 4 | This is a fully original reimplementation of the official SDK's "data 5 | compression" library. This library is made up of two parts, the MDEC API and 6 | functions to decompress Huffman-encoded bitstreams (.BS files, or frames in 7 | .STR files) into data to be fed to the MDEC. Two different implementations of 8 | the latter are provided, one using the GTE and scratchpad region and an older 9 | one using a large lookup table in main RAM. 10 | 11 | FMV playback is not part of this library per se, but can implemented using the 12 | APIs defined here alongside some code to stream data from the CD drive. 13 | 14 | Currently bitstream versions 1, 2 and 3 are supported. Version 0 and .IKI 15 | bitstreams are not supported, but no encoder is publicly available for those 16 | anyway. 17 | 18 | ## MDEC API 19 | 20 | The MDEC data input/output API is almost identical to the official one, with 21 | only two minor differences: 22 | 23 | - `DecDCTPutEnv()` takes a second argument specifying whether the MDEC shall be 24 | put into monochrome or color mode (the original API only supported color). 25 | - A `DecDCTinRaw()` function was added for easier feeding of headerless data 26 | buffers to the MDEC. This function does not affect how `DecDCTin()` works. 27 | 28 | ## Decompression API 29 | 30 | The following functions are currently provided: 31 | 32 | - `DecDCTvlcStart()`, `DecDCTvlcContinue()`: a decompressor implementation that 33 | uses a small (<1 KB) lookup table and leverages the GTE, written in assembly. 34 | `DecDCTvlcCopyTableV2()` or `DecDCTvlcCopyTableV3()` may optionally be called 35 | to temporarily move the table to the scratchpad region in order to boost 36 | decompression speed. 37 | - `DecDCTvlcStart2()`, `DecDCTvlcContinue2()`: an older implementation using 38 | a large (34 KB) lookup table in main RAM, written in C. The table must be 39 | decompressed ahead of time manually using `DecDCTvlcBuild()`, but can be 40 | deallocated when no longer needed. **This implementation does not support** 41 | **version 3 bitstreams**. 42 | - `DecDCTvlc()`, `DecDCTvlc2()`: wrappers around the functions listed above, 43 | for compatibility with the Sony SDK. 44 | 45 | ## SPU ADPCM encoding API 46 | 47 | The Sony library has functions that can be used to convert raw 16-bit PCM audio 48 | data to SPU ADPCM. These are currently unimplemented due to their limited 49 | usefulness, but might be added at some point. 50 | -------------------------------------------------------------------------------- /tools/minin00b/psxsio/tty.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSn00bSDK serial port BIOS TTY driver 3 | * (C) 2019-2022 Lameguy64, spicyjpeg - MPL licensed 4 | * 5 | * This driver is designed to be as simple and reliable as possible: as such it 6 | * only relies on the SIO_*() API for receiving and sends data synchronously. 7 | * This allows printf() to work without issues, albeit slowly, if called from a 8 | * critical section or even from an interrupt handler. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* TTY device control block */ 17 | 18 | static int _sio_open(FCB *fcb, const char* file, int mode) { 19 | fcb->diskid = 1; 20 | return 0; 21 | } 22 | 23 | static int _sio_inout(FCB *fcb, int cmd) { 24 | char *ptr = (char*) fcb->trns_addr; 25 | 26 | switch (cmd) { 27 | case 1: // read 28 | for (int i = 0; i < fcb->trns_len; i++) 29 | *(ptr++) = (char) SIO_ReadByte(); 30 | 31 | return fcb->trns_len; 32 | 33 | case 2: // write 34 | for (int i = 0; i < fcb->trns_len; i++) { 35 | while (!(SIO_STAT(1) & (SR_TXRDY | SR_TXU))) 36 | __asm__ volatile(""); 37 | 38 | SIO_DATA(1) = *(ptr++); 39 | } 40 | 41 | return fcb->trns_len; 42 | 43 | default: 44 | return 0; 45 | } 46 | } 47 | 48 | static int _sio_close(FCB *fcb) { 49 | return 0; 50 | } 51 | 52 | static int _sio_ioctl(FCB *fcb, int cmd, int arg) { 53 | switch (cmd) { 54 | case FIOCSCAN: 55 | return SIO_ReadSync(1) ? 0 : -1; 56 | 57 | default: 58 | return -1; 59 | } 60 | } 61 | 62 | static int _sio_dummy(void) { 63 | return -1; 64 | } 65 | 66 | static DCB _sio_dcb = { 67 | .name = "tty", 68 | .flags = 3, 69 | .ssize = 1, 70 | .desc = "PSXSIO SERIAL CONSOLE", 71 | .f_init = &_sio_dummy, 72 | .f_open = &_sio_open, 73 | .f_inout = &_sio_inout, 74 | .f_close = &_sio_close, 75 | .f_ioctl = &_sio_ioctl, 76 | .f_read = &_sio_dummy, 77 | .f_write = &_sio_dummy, 78 | .f_erase = &_sio_dummy, 79 | .f_undelete = &_sio_dummy, 80 | .f_firstfile = &_sio_dummy, 81 | .f_nextfile = &_sio_dummy, 82 | .f_format = &_sio_dummy, 83 | .f_chdir = &_sio_dummy, 84 | .f_rename = &_sio_dummy, 85 | .f_remove = &_sio_dummy, 86 | .f_testdevice = &_sio_dummy 87 | }; 88 | 89 | /* Public API */ 90 | 91 | void AddSIO(int baud) { 92 | SIO_Init(baud, MR_SB_01 | MR_CHLEN_8); 93 | 94 | close(0); 95 | close(1); 96 | DelDrv(_sio_dcb.name); 97 | AddDrv(&_sio_dcb); 98 | open(_sio_dcb.name, 2); 99 | open(_sio_dcb.name, 1); 100 | } 101 | 102 | void DelSIO(void) { 103 | SIO_Quit(); 104 | 105 | DelDrv(_sio_dcb.name); 106 | add_nullcon_driver(); 107 | } 108 | -------------------------------------------------------------------------------- /tools/minin00b/psxspu/readme.txt: -------------------------------------------------------------------------------- 1 | PSX SPU Library, part of PSn00bSDK 2 | 2019 Lameguy64 / Meido-Tek Productions 3 | 4 | Licensed under Mozilla Public License 5 | 6 | Open source implementation of the SPU library written entirely in C. Currently 7 | only supports SPU initialization, reading/writing SPU RAM using DMA and basic 8 | sample playback. Most of the official API is not going to be implemented as the 9 | vast majority of it is just inefficient wrappers around accessing SPU registers 10 | directly, which can be done already using the macros defined in hwregs_c.h. 11 | 12 | Library developer(s): 13 | 14 | Lameguy64 (initial implementation in assembly) 15 | spicyjpeg 16 | 17 | Library header(s): 18 | 19 | psxspu.h 20 | 21 | Todo list: 22 | 23 | * SPU RAM allocation routines yet to be implemented (heap must only be 24 | stored in main RAM and not SPU RAM like in the official SDK). 25 | 26 | * SPU reverb configuration functions yet to be implemented. 27 | -------------------------------------------------------------------------------- /tools/mod-builder/_files.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | import pathlib 4 | import shutil 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | def get_file_directory(fname = "config.json", folder = "games"): 9 | """ 10 | Search each parent folder until the fname is found (if found at all) 11 | Returns the path with the fname 12 | 13 | Assumes exactly one file on path 14 | Assumes folder exists on path 15 | TODO: Prompt user to give absolute path 16 | """ 17 | # message = "No config.json found. Make sure to set this prerequisite file before continuing." 18 | path_search = pathlib.Path.cwd() # relative to where the script is run 19 | 20 | count_iterations = 0 21 | while (path_search != path_search.root): 22 | logger.debug(f"CWD Parent(x{count_iterations}): {path_search}") 23 | if (path_search / fname).exists(): 24 | return path_search 25 | for path in (path_search / folder).rglob("*.json"): # hardcoded 26 | if path.name == fname: 27 | return path.parent 28 | path_search = path_search.parent # move up one directory 29 | 30 | count_iterations += 1 31 | # if count_iterations == 10: 32 | # break 33 | 34 | return path_search 35 | 36 | def check_file(fname, quiet=False): 37 | path = pathlib.Path(fname) 38 | if not path.exists(): 39 | if not quiet: 40 | logger.error("fname not found: {}".format(fname)) 41 | return False 42 | return True 43 | 44 | def check_files(list_files): 45 | """ 46 | All files must exist to return True 47 | """ 48 | for fname in list_files: 49 | if not check_file(fname): 50 | logger.error("Missing prerequisite: {}".format(fname)) 51 | return False 52 | 53 | return True 54 | 55 | def delete_file(fname): 56 | """ 57 | Returns bool based on success 58 | TODO: missing_ok=True only available for python3.8, but exception handles not found 59 | """ 60 | path = pathlib.Path(fname) 61 | is_successful = True # default 62 | try: 63 | path.unlink(missing_ok=True) # only on python3.8 64 | except Exception as error: # usually existence, permission, or simultaneous access issues 65 | logger.exception("Cannot delete file: {}".format(fname), exc_info=error.__cause__) 66 | is_successful = False 67 | 68 | return is_successful 69 | 70 | def create_directory(dirname): 71 | """ 72 | TODO: Check if parents True produces intended result 73 | """ 74 | path_dir = pathlib.Path(dirname) 75 | path_dir.mkdir(exist_ok=True, parents=True) 76 | 77 | def delete_directory(dirname): 78 | path_dir = pathlib.Path(dirname) 79 | is_successful = True 80 | try: 81 | shutil.rmtree(path_dir, ignore_errors=True) 82 | except Exception as error: # usually existence, permission, or simultaneous access issues 83 | logger.exception("Cannot delete folder: {}".format(dirname), exc_info=error.__cause__) 84 | is_successful = False 85 | 86 | return is_successful 87 | -------------------------------------------------------------------------------- /tools/mod-builder/c.py: -------------------------------------------------------------------------------- 1 | from common import TEXTURES_FOLDER 2 | from image import create_images, clear_images, get_image_list 3 | from clut import clear_cluts, get_clut_list 4 | 5 | import logging 6 | import textwrap 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | RECT_SIZE = 8 11 | CHAR_SIZE = 1 12 | SHORT_SIZE = 2 13 | 14 | img_names = [] 15 | clut_names = [] 16 | 17 | def construct_header() -> str: 18 | """ 19 | TODO: Verify this works 20 | """ 21 | buffer = """ 22 | typedef struct 23 | { 24 | short x, y, w, h; 25 | } RECT; 26 | 27 | typedef struct 28 | { 29 | char * image; 30 | RECT * pos; 31 | } Texture; 32 | 33 | typedef struct 34 | { 35 | short * clut; 36 | RECT * pos; 37 | } CLUT; 38 | 39 | """ 40 | return textwrap.dedent(buffer) # remove indentation 41 | 42 | def export_objects(obj_list, is_img: bool) -> str: 43 | buffer = str() 44 | for obj in obj_list: 45 | buffer += obj.as_c_struct() 46 | if is_img: 47 | img_names.append(obj.name) 48 | else: 49 | clut_names.append(obj.name) 50 | return buffer + "\n" 51 | 52 | def create_texture_struct() -> str: 53 | def fill_struct(struct_type: str, struct_name: str, names: list[str]) -> str: 54 | buffer = struct_type + " " + struct_name + '[] __attribute__ ((section (".sdata"))) = {\n' 55 | counter = 0 56 | for name in names: 57 | buffer += " " * 4 + "[" + str(counter) + "] =\n" 58 | buffer += " " * 4 + "{\n" 59 | buffer += " " * 8 + ".image = " + name + ",\n" 60 | buffer += " " * 8 + ".pos = &" + name + "_pos,\n" 61 | buffer += " " * 4 + "},\n" 62 | counter += 1 63 | buffer += "};\n\n" 64 | return buffer 65 | 66 | return fill_struct("Texture", "textures", img_names) + fill_struct("CLUT", "cluts", clut_names) 67 | 68 | def clear_cache() -> None: 69 | clear_images() 70 | clear_cluts() 71 | img_names.clear() 72 | clut_names.clear() 73 | 74 | def export_as_c() -> None: 75 | img_count = create_images(TEXTURES_FOLDER) 76 | if img_count == 0: 77 | logger.warning("0 images found. No textures were exported.") 78 | return 79 | buffer = construct_header() 80 | buffer += export_objects(get_image_list(), True) 81 | buffer += export_objects(get_clut_list(), False) 82 | buffer += create_texture_struct() 83 | path_out = TEXTURES_FOLDER / "newtex.c" 84 | with open(path_out, "w") as file: 85 | file.write(buffer) 86 | logger.info(f"Textures successfully exported in {path_out}") 87 | clear_cache() -------------------------------------------------------------------------------- /tools/mod-builder/clut.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations # to use type in python 3.7 2 | 3 | from PIL import Image as PILImage 4 | 5 | cluts = [] 6 | num_clut = [0] 7 | 8 | class CLUT: 9 | def __init__(self, name: str, x: int, y: int, mode: int) -> None: 10 | self.name = name 11 | self.x = x * 16 12 | self.y = y 13 | self.address = (self.y * 2048) + (self.x * 2) 14 | self.colors = [] 15 | self.color_count = 0 16 | self.mode = mode 17 | self.w = 2 ** mode 18 | self.h = 1 19 | self.max_colors = 2 ** mode 20 | self.color_offset = {} 21 | self.valid = True 22 | self.output_path = None 23 | 24 | def add_color(self, psx_color: int) -> None: 25 | if self.color_count == self.max_colors: 26 | self.valid = False 27 | return 28 | self.color_offset[psx_color] = self.color_count 29 | self.colors.append(psx_color) 30 | self.color_count += 1 31 | 32 | def get_offset(self, color) -> int: 33 | alpha = 255 34 | if len(color) == 4: 35 | alpha = color[3] 36 | psx_color = rgb2psx(color[2], color[1], color[0], alpha) 37 | if psx_color in self.color_offset: 38 | return self.color_offset[psx_color] 39 | self.add_color(psx_color) 40 | if self.valid: 41 | return self.color_offset[psx_color] 42 | return -1 43 | 44 | def add_indexed_colors(self, img: PILImage) -> None: 45 | pal = img.getpalette("RGBA") 46 | for col in range(0, len(pal), 4): 47 | r = pal[col] 48 | g = pal[col+1] 49 | b = pal[col+2] 50 | a = pal[col+3] 51 | self.colors.append(rgb2psx(r, g, b, a)) 52 | 53 | def cmp_coords(self, x: int, y: int) -> bool: 54 | return (self.x == x * 16) and (self.y == y) 55 | 56 | def is_valid(self) -> bool: 57 | return self.valid 58 | 59 | def set_path(self, path: str) -> None: 60 | self.output_path = path 61 | 62 | def get_path(self) -> str: 63 | return self.output_path 64 | 65 | def as_c_struct(self) -> str: 66 | buffer = "short " + self.name + "[] = {" 67 | for color in self.colors: 68 | buffer += hex(color) + "," 69 | buffer += "};\n\n" 70 | buffer += "RECT " + self.name + "_pos = {\n" 71 | buffer += " " * 4 + ".x = " + str(self.x) + ",\n" 72 | buffer += " " * 4 + ".y = " + str(self.y) + ",\n" 73 | buffer += " " * 4 + ".w = " + str(self.w) + ",\n" 74 | buffer += " " * 4 + ".h = " + str(self.h) + "\n" 75 | buffer += "};\n" 76 | return buffer 77 | 78 | def __str__(self) -> str: 79 | buffer = "" 80 | if self.valid: 81 | buffer += "CLUT: " + self.name + "\n" 82 | buffer += "Coords: (" + str(self.x) + ", " + str(self.y) + ")\n" 83 | buffer += "Width, height: (" + str(self.w) + ", " + str(self.h) +")\n" 84 | buffer += "Address: " + hex(self.address) + "\n" 85 | buffer += '[' 86 | for color in self.colors: 87 | buffer += hex(color) + ',' 88 | buffer += ']\n' 89 | else: 90 | buffer += "ERROR: Too many colors for this CLUT.\n" 91 | return buffer 92 | 93 | 94 | def clear_cluts() -> None: 95 | num_clut[0] = 0 96 | cluts.clear() 97 | 98 | def dump_cluts(path: str) -> None: 99 | print("[CLUT-py] Dumping CLUTs...") 100 | for clut in cluts: 101 | if clut.is_valid(): 102 | output = bytearray() 103 | clut_path = path / (clut.name + ".bin") 104 | clut.set_path(clut_path) 105 | for color in clut.colors: 106 | output.append(color & 0xFF) 107 | output.append((color >> 8) & 0xFF) 108 | for _ in range(len(clut.colors), clut.max_colors): 109 | output.append(0) 110 | output.append(0) 111 | with open(clut_path, "wb") as file: 112 | file.write(output) 113 | 114 | def get_clut_list() -> list[CLUT]: 115 | return cluts 116 | 117 | def get_clut(x: int, y: int, mode: int) -> CLUT: 118 | if mode == 16: 119 | return None 120 | for clut in cluts: 121 | if clut.cmp_coords(x, y): 122 | return clut 123 | cluts.append(CLUT("clut_" + str(num_clut[0]), x, y, mode)) 124 | num_clut[0] += 1 125 | return cluts[-1] 126 | 127 | def rgb2psx(r: int, g: int, b: int, a: int) -> int: 128 | if a == 255: # No transparency case 129 | a = 0 130 | # PSX interprets opaque pitch black as fully transparent, 131 | # so we artificially set the color to RGBA(0, 0, 8, 255) in order 132 | # to draw as pitch black 133 | if r == 0 and g == 0 and b == 0: 134 | b = 8 135 | elif a == 0: # Full transparency translates to RGBA(0, 0, 0, 255) in the PSX 136 | r = 0 137 | g = 0 138 | b = 0 139 | a = 0 140 | else: # Last case, add transparency to the colors if a is in ]0, 255[ 141 | a = 1 142 | color = a << 5 143 | color = color | (((int(b) * 249) + 1014) >> 11) & 0x1F 144 | color = color << 5 145 | color = color | (((int(g) * 249) + 1014) >> 11) & 0x1F 146 | color = color << 5 147 | color = color | (((int(r) * 249) + 1014) >> 11) & 0x1F 148 | return color -------------------------------------------------------------------------------- /tools/mod-builder/disc.py: -------------------------------------------------------------------------------- 1 | from common import DISC_PATH 2 | 3 | import json 4 | 5 | class DiscFile: 6 | def __init__(self, metadata: dict, physical_file: str) -> None: 7 | self.address = int(metadata["address"], 0) 8 | self.offset = int(metadata["offset"], 0) 9 | self.physical_file = physical_file.replace("\\", "/") 10 | 11 | 12 | class Disc: 13 | def __init__(self, version) -> None: 14 | self.df_by_name = dict() 15 | with open(DISC_PATH, "r") as file: 16 | data = json.load(file) 17 | if "common" in data: 18 | self.read_data_container(data["common"]) 19 | self.read_data_container(data[version]) 20 | 21 | def read_data_container(self, data: dict) -> None: 22 | for file in data: 23 | for filename in file.keys(): 24 | for section in file[filename]: 25 | name = section["name"] 26 | df = DiscFile(section, filename) 27 | self.df_by_name[name] = df 28 | 29 | def get_df(self, name: str) -> DiscFile: 30 | if name in self.df_by_name: 31 | return self.df_by_name[name] 32 | return None -------------------------------------------------------------------------------- /tools/mod-builder/game_options.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations # to use type in python 3.7 2 | 3 | from common import DIR_SYMBOLS, CONFIG_PATH 4 | 5 | import json 6 | 7 | 8 | class GameVersion: 9 | """ 10 | Acts like a struct 11 | """ 12 | def __init__(self, version: str, rom_name: str, files_symbols: list[str], build_id: str): 13 | self.version = version 14 | self.rom_name = rom_name 15 | self.files_symbols = files_symbols 16 | self.build_id = build_id 17 | 18 | 19 | class GameOptions: 20 | def __init__(self) -> None: 21 | self.versions_by_name = dict() 22 | self.versions_by_build_id = dict() 23 | # hardcoded but doesn't change functionality 24 | self.path_config = CONFIG_PATH 25 | self.path_dir_symbols = DIR_SYMBOLS 26 | 27 | def load_config(self): 28 | """ 29 | TODO: Just pass in the data directly to avoid trouble 30 | TODO: Just pass in the paths directly to avoid more trouble 31 | TODO: Simplify the config.json structure to avoid this mess 32 | """ 33 | with open(self.path_config) as file: 34 | data = json.load(file) 35 | versions = data["versions"] 36 | for ver in versions: 37 | version = list(ver.keys())[0] 38 | ver_contents = ver[version] 39 | rom_name = ver_contents["name"] 40 | files_symbols = ver_contents["symbols"] 41 | for i in range(len(files_symbols)): 42 | files_symbols[i] = self.path_dir_symbols / files_symbols[i] 43 | build_id = ver_contents["build_id"] 44 | gv = GameVersion(version, rom_name, files_symbols, build_id) 45 | self.versions_by_name[version] = gv 46 | self.versions_by_build_id[build_id] = gv 47 | 48 | def get_version_names(self) -> list[str]: 49 | names = list() 50 | for version in self.versions_by_name.keys(): 51 | names.append(version) 52 | return names 53 | 54 | def get_gv_by_name(self, name: str) -> GameVersion: 55 | if name in self.versions_by_name: 56 | return self.versions_by_name[name] 57 | return None 58 | 59 | def get_gv_by_build_id(self, build_id: int) -> GameVersion: 60 | if build_id in self.versions_by_build_id: 61 | return self.versions_by_build_id[build_id] 62 | return None 63 | 64 | game_options = GameOptions() # why is this initialized here? -------------------------------------------------------------------------------- /tools/mod-builder/nops.py: -------------------------------------------------------------------------------- 1 | import _files # check_file 2 | from syms import Syms 3 | from compile_list import CompileList, free_sections 4 | from common import COMPILE_LIST, SETTINGS_PATH, BACKUP_FOLDER, get_build_id, request_user_input 5 | 6 | import os 7 | import json 8 | import pathlib 9 | import subprocess 10 | 11 | class Nops: 12 | def __init__(self) -> None: 13 | pass 14 | 15 | def load_config(self) -> None: 16 | """ TODO: Put in try/except """ 17 | with open(SETTINGS_PATH) as file: 18 | data = json.load(file)["nops"] 19 | self.prefix = ["nops", f"/{data['mode'].lower()}"] 20 | self.comport = [data["comport"].upper()] 21 | 22 | def fire_command(self, list_args): 23 | """TODO: Put this in logging""" 24 | command = [self.prefix] 25 | command.extend(list_args) 26 | command.append(self.comport) 27 | result = subprocess.run(command) 28 | 29 | def inject(self, backup: bool, restore: bool) -> None: 30 | """ 31 | COMPILE_LIST is a string 32 | """ 33 | sym = Syms(get_build_id()) 34 | build_lists = ["./"] 35 | while build_lists: 36 | prefix = build_lists.pop(0) 37 | bl = prefix + COMPILE_LIST 38 | free_sections() 39 | with open(bl, "r") as file: 40 | for line in file: 41 | cl = CompileList(line, sym, prefix) 42 | if not cl.should_build(): 43 | continue 44 | bin = cl.get_output_name() 45 | backup_bin = pathlib.Path(prefix) / BACKUP_FOLDER / ("nops_" + cl.section_name + ".bin") 46 | if backup: 47 | if not _files.check_file(bin): 48 | continue 49 | size = os.path.getsize(bin) 50 | self.fire_command(["/dump", hex(cl.address), hex(size),backup_bin]) 51 | if restore: 52 | bin = backup_bin 53 | if not _files.check_file(bin): 54 | continue 55 | self.fire_command(["/bin", hex(cl.address), bin]) 56 | 57 | def hot_reload(self) -> None: 58 | if not _files.check_file(COMPILE_LIST): 59 | return 60 | intro_msg = """ 61 | Would you like to backup the state? 62 | 1 - Yes 63 | 2 - No 64 | Note: this option is required if you want to uninstall the mod. 65 | By selecting yes you'll overwrite the current backup. 66 | """ 67 | error_msg = "ERROR: Invalid input. Please enter 1 for Yes or 2 for No." 68 | backup = request_user_input(first_option=1, last_option=2, intro_msg=intro_msg, error_msg=error_msg) == 1 69 | self.fire_command(["/halt"]) 70 | self.inject(backup, False) 71 | self.fire_command(["/cont"]) 72 | 73 | def restore(self) -> None: 74 | if not _files.check_file(COMPILE_LIST): 75 | return 76 | self.fire_command(["/halt"]) 77 | self.inject(False, True) 78 | self.fire_command(["/cont"]) 79 | -------------------------------------------------------------------------------- /tools/mod-builder/syms.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations # to use type in python 3.7 2 | 3 | import _files # check_file 4 | from common import request_user_input, is_number 5 | from game_options import game_options 6 | 7 | import logging 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | class Syms(): 12 | def __init__(self, build_id=None) -> None: 13 | self.version = int() 14 | self.gv = self.ask_user_for_version(build_id) 15 | self.syms = dict() 16 | for file in self.gv.files_symbols: 17 | self.parse_gcc_file(file) 18 | 19 | def ask_user_for_version(self, build_id: int): 20 | if build_id is not None: 21 | return game_options.get_gv_by_build_id(build_id) 22 | names = game_options.get_version_names() 23 | intro_msg = "Select the game version:\n" 24 | for i, name in enumerate(names): 25 | intro_msg += f"{i + 1} - {name}\n" 26 | error_msg = f"ERROR: Invalid version. Please select a number from 1-{len(names)}." 27 | self.version = request_user_input(first_option=1, last_option=len(names), intro_msg=intro_msg, error_msg=error_msg) 28 | return game_options.get_gv_by_name(names[self.version - 1]) 29 | 30 | def parse_gcc_file(self, fname: str) -> None: 31 | """ 32 | TODO: Abstract this out 33 | """ 34 | if not _files.check_file(fname): 35 | return 36 | with open(fname, "r") as file: 37 | for line in file: 38 | if line.strip() == "": 39 | continue 40 | original_line = line 41 | line = [l.strip() for l in line.split("=")] 42 | if len(line) != 2: 43 | logger.error(f"Syntax error in file: {fname} at line {original_line}") 44 | continue 45 | symbol = line[0] 46 | address = line[1].split(";")[0].strip() 47 | if not is_number(address): 48 | logger.error(f"Invalid address in file: {fname} at line: {original_line}") 49 | continue 50 | address = int(address, 0) 51 | self.syms[symbol] = address 52 | 53 | def get_files(self) -> list[str]: 54 | if self.gv is None: 55 | return None 56 | return self.gv.files_symbols 57 | 58 | def get_address(self, symbol: str) -> int: 59 | if symbol in self.syms: 60 | return self.syms[symbol] 61 | return None 62 | 63 | def get_version(self) -> str: 64 | if self.gv is None: 65 | return None 66 | return self.gv.version 67 | 68 | def get_build_id(self) -> int: 69 | if self.gv is None: 70 | return None 71 | return self.gv.build_id -------------------------------------------------------------------------------- /tools/mod-builder/tests/fake_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "redux": { 3 | "port": 8080, 4 | "path": "C:/path/to/redux/" 5 | }, 6 | "nops": { 7 | "comport": "COM5", 8 | "mode": "fast" 9 | } 10 | } -------------------------------------------------------------------------------- /tools/mod-builder/tests/makefiles/CTR_HW_makefile: -------------------------------------------------------------------------------- 1 | MODDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 2 | TARGET = mod 3 | 4 | SRCS = ./src/hello.c ./src/hook.s 5 | CPPFLAGS = -DBUILD=926 6 | LDSYMS = -T/mnt/c/dev/psx-modding-toolchain/games/Example_CrashTeamRacing/symbols/funcs-u.txt -T/mnt/c/dev/psx-modding-toolchain/games/Example_CrashTeamRacing/symbols/addrs-u.txt 7 | USE_FUNCTION_SECTIONS ?= true 8 | DISABLE_FUNCTION_REORDER ?= false 9 | USE_PSYQ ?= false 10 | OVERLAYSECTION ?= .helloc .hooks 11 | OVR_START_ADDR = 0x80010100 12 | OVERLAYSCRIPT = overlay.ld 13 | BUILDDIR = $(MODDIR)output/ 14 | SRCINCLUDEDIR = $(MODDIR)src/ 15 | GAMEINCLUDEDIR = /mnt/c/dev/psx-modding-toolchain/games/Example_CrashTeamRacing/include 16 | EXTRA_CC_FLAGS = -Os -g 17 | OPT_CC_FLAGS = 18 | OPT_LD_FLAGS = 19 | PCHS = $(GAMEINCLUDEDIR) 20 | TRIMBIN_OFFSET = $(MODDIR)debug/offset.txt 21 | 22 | include /mnt/c/dev/psx-modding-toolchain/games/common.mk 23 | -------------------------------------------------------------------------------- /tools/mod-builder/tests/spyro___str__.txt: -------------------------------------------------------------------------------- 1 | IMG: SPYRO 2 | Coords: (368, 216) 3 | Width, height: (11, 26) 4 | Address: 0x6c2e0 5 | [] -------------------------------------------------------------------------------- /tools/mod-builder/tests/spyro_c_struct.txt: -------------------------------------------------------------------------------- 1 | // CLUT = clut_0 2 | char SPYRO[] = {}; 3 | 4 | RECT SPYRO_pos = { 5 | .x = 368, 6 | .y = 216, 7 | .w = 11, 8 | .h = 26 9 | }; 10 | -------------------------------------------------------------------------------- /tools/mod-builder/tests/test_common.py: -------------------------------------------------------------------------------- 1 | """ 2 | TODO: This breaks because common calls some functions repeatedly and immediately 3 | """ 4 | import pytest 5 | 6 | import common 7 | 8 | cases_build_id = ( 9 | ([], None), 10 | (["These", "don't", "have", "ids"], None), 11 | (["", "-DBUILD=926", "", ""], 926), 12 | ) 13 | @pytest.mark.parametrize("list_tokens, expected", cases_build_id) 14 | def test_extract_build_id(list_tokens, expected): 15 | assert common.extract_build_id(list_tokens, expected) 16 | 17 | cases_makefiles = ( 18 | ("tests/makefiles/fake_makefile", 926), 19 | ) 20 | @pytest.mark.parametrize("fname, expected", cases_makefiles) 21 | def test_get_build_id(fname, expected): 22 | assert common.get_build_id(fname) == expected -------------------------------------------------------------------------------- /tools/mod-builder/tests/test_compile_list.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import pytest 3 | 4 | import compile_list 5 | 6 | cases_replace = ( 7 | ("// Include patches for PAL and NTSC-J", ",//, Include patches for PAL and NTSC-J"), 8 | ("// Include patches for PAL and NTSC-J //", ",//, Include patches for PAL and NTSC-J ,//,"), 9 | ("// Include patches // for PAL and NTSC-J //", ",//, Include patches ,//, for PAL and NTSC-J ,//,"), 10 | # no comment, no change 11 | ("1006, exe, 0x80012534, 0x0, ../../Patches/JpnModchips/src/jpnModchips.s","1006, exe, 0x80012534, 0x0, ../../Patches/JpnModchips/src/jpnModchips.s") 12 | ) 13 | @pytest.mark.parametrize("string, expected", cases_replace) 14 | def test_comment_replace(string, expected): 15 | comment = "//" 16 | assert string.replace(comment, f",{comment},") == expected 17 | 18 | cases_tokens = ( 19 | (",//, Include patches for PAL and NTSC-J", ["//", "Include patches for PAL and NTSC-J"]), 20 | (",//, Include patches for PAL and NTSC-J,//,", ["//","Include patches for PAL and NTSC-J","//"]), 21 | (",//, Include patches ,//, for PAL and NTSC-J,//,", ["//","Include patches","//","for PAL and NTSC-J","//"]), 22 | ("// Include anti-anti-piracy patches for PAL and NTSC-J",["// Include anti-anti-piracy patches for PAL and NTSC-J"]), 23 | ("1006, exe, 0x80012534, 0x0, ../../Patches/JpnModchips/src/jpnModchips.s",["1006", "exe", "0x80012534", "0x0","../../Patches/JpnModchips/src/jpnModchips.s"]), 24 | ("1111, exe, 0x80012570, 0x0, ../../Patches/JpnModchips/src/jpnModchips.s",["1111", "exe", "0x80012570", "0x0", "../../Patches/JpnModchips/src/jpnModchips.s"]), 25 | ("1020, exe, 0x80031cc8, 0x0, ../../Patches/EurLibcrypt/src/libcrypt.s",["1020", "exe", "0x80031cc8", "0x0", "../../Patches/EurLibcrypt/src/libcrypt.s"]), 26 | ('// Hooked at the end of BOTS_UpdateGlobals, which will make the code run every frame at all times, excluding the loading screen', ['// Hooked at the end of BOTS_UpdateGlobals', 'which will make the code run every frame at all times', 'excluding the loading screen']) 27 | ) 28 | @pytest.mark.parametrize("string, expected", cases_tokens) 29 | def test_tokenize_line(string, expected): 30 | assert compile_list.CompileList.tokenize_line(string) == expected 31 | 32 | cases_commments = ( 33 | (["//", "Include patches for PAL and NTSC-J"], []), # starts with comment 34 | (["//","Include patches for PAL and NTSC-J","//"], []), # starts with comment 35 | (["//","Include patches","//","for PAL and NTSC-J","//"], []), # starts with comment 36 | (["// Fake sentence "], ["// Fake sentence "]), # starts with comment but no commas 37 | (['// Hooked', 'which', 'excluding'], ['// Hooked', 'which', 'excluding']), # starts with comment with commas 38 | (["1006", "exe", "0x80012534", "0x0","../../Patches/JpnModchips/src/jpnModchips.s"], ["1006", "exe", "0x80012534", "0x0","../../Patches/JpnModchips/src/jpnModchips.s"]), 39 | (["1111", "exe", "0x80012570", "0x0", "../../Patches/JpnModchips/src/jpnModchips.s"], ["1111", "exe", "0x80012570", "0x0", "../../Patches/JpnModchips/src/jpnModchips.s"]), 40 | (["1020", "exe", "0x80031cc8", "0x0", "../../Patches/EurLibcrypt/src/libcrypt.s"], ["1020", "exe", "0x80031cc8", "0x0", "../../Patches/EurLibcrypt/src/libcrypt.s"]), 41 | ) 42 | @pytest.mark.parametrize("list_strings, expected", cases_commments) 43 | def test_skip_comments(list_strings, expected): 44 | assert compile_list.CompileList.skip_comments(list_strings) == expected 45 | 46 | # "// Include anti-anti-piracy patches for PAL and NTSC-J" 47 | # "1006, exe, 0x80012534, 0x0, ../../Patches/JpnModchips/src/jpnModchips.s" 48 | # "1111, exe, 0x80012570, 0x0, ../../Patches/JpnModchips/src/jpnModchips.s" 49 | # "1020, exe, 0x80031cc8, 0x0, ../../Patches/EurLibcrypt/src/libcrypt.s" 50 | 51 | # "// Compile the code in the empty space in RDATA" 52 | # "common, exe, rdata_free, 0x0, src/main.c src/menubox.c" 53 | 54 | # "// Compile the ASM injection that will load our code" 55 | # '// ASM injections for loading modded functions are typically done at the "jr ra" or "return" instruction of a function, which is 8 bytes away from the start of the function that follows it 56 | # '// Hooked at the end of BOTS_UpdateGlobals, which will make the code run every frame at all times, excluding the loading screen' 57 | # 'common, exe, BOTS_SetRotation, -0x8, src/hook.s' 58 | 59 | # '926, bigfilelangenlng, 0x0, 0x0, assets/NTSC-U.lng' 60 | 61 | # '// USAUnlimitedPenta //' 62 | 63 | # "// Inject compiled code for Penta's stats into the executable" 64 | # '926, exe, 0x80088A0C, 0x0, ../../Patches/USAUnlimitedPenta/assets/stats.bin' 65 | 66 | # '// Compile modified VehInit_SetConsts' 67 | # '926, exe, VehInit_SetConsts, 0x0, ../../Patches/USAUnlimitedPenta/src/USAUnlimitedPenta.c' 68 | 69 | # '// ExpandedFont //' 70 | 71 | # '926, exe, DecalFont_DrawLineStrlen, 0x0, ../../Modules/ExpandedFont/src/addquotationmarks.c' 72 | cases_sources = ( 73 | ("../../Patches/JpnModchips/src/jpnModchips.s", 'jpnModchipss'), 74 | ("../../Patches/JpnModchips/src/jpnModchips.s", 'jpnModchipss'), 75 | ("../../Patches/EurLibcrypt/src/libcrypt.s", 'libcrypts'), 76 | ("src/main.c src/menubox.c", 'menuboxc'), 77 | ("src/*.c", '*c'), 78 | ("assets/title01_usa.tim", 'title01_usatim') 79 | ) 80 | @pytest.mark.parametrize("string, expected", cases_sources) 81 | def test_get_section_name_from_filepath(string, expected): 82 | prefix = "/mnt/c/dev/psx-modding-toolchain/games/CTR-ModSDK-main/mods/Standalones/StatsEditor/" 83 | path = pathlib.Path(prefix + string).resolve() 84 | assert compile_list.CompileList.get_section_name_from_filepath(path) == expected -------------------------------------------------------------------------------- /tools/mod-builder/tests/test_files.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ensures reproducibility amongst the paths 3 | 4 | Arrange 5 | Action 6 | Assert 7 | """ 8 | import pathlib 9 | import pytest 10 | 11 | import _files 12 | 13 | # fname, folder 14 | cases_distance_to_file = ( 15 | ("common.py", "tools", pathlib.Path.cwd()), # look in this directory 16 | ("mipsel-none-elf-gcc.rb", "tools", pathlib.Path.cwd().parents[1] / "tools" / "macos-mips"), # doesn't do an os.walk 17 | ("config.json", "psx-modding-toolchain", pathlib.Path.cwd().parents[1] / "games" / "Example_CrashTeamRacing"), # doesn't do an os.walk 18 | ("config.json", "tools", pathlib.Path.cwd().parents[1] / "tools" ), # didn't find it 19 | ) 20 | @pytest.mark.parametrize("fname, folder, expected", cases_distance_to_file) 21 | def test_file_distance(fname, folder, expected): 22 | # pytest.set_trace() 23 | assert _files.get_file_directory(fname, folder) == expected 24 | 25 | 26 | def test_file_directory(fname, expected): 27 | assert _files.get_file_directory(fname) == expected 28 | 29 | cases_file = ( 30 | ("common.py", True), 31 | ("../../games/Example_CrashTeamRacing/config.json", True), 32 | ("buildList.txt", True), # common.COMPILE_LIST 33 | ("fake-file.txt", False) 34 | ) 35 | @pytest.mark.parametrize("fname, expected", cases_file) 36 | def test_check_file(fname, expected): 37 | assert _files.check_file(fname) == expected 38 | 39 | cases_files = ( 40 | (["common.py", "../../games/Example_CrashTeamRacing/config.json"], True), 41 | (["common.py", "../../games/Example_CrashTeamRacing/config.json", "fake.txt"], False), 42 | (["buildList.txt", "disc.json", "settings.json"], False), # prerequisites 43 | ) 44 | @pytest.mark.parametrize("list_strings, expected", cases_files) 45 | def test_check_files(list_strings, expected): 46 | assert _files.check_files(list_strings) == expected -------------------------------------------------------------------------------- /tools/mod-builder/tests/test_image.py: -------------------------------------------------------------------------------- 1 | """ 2 | TODO: create a fake image file to avoid having to look for hard-coded assets 3 | """ 4 | import pathlib 5 | import pytest 6 | 7 | import image 8 | 9 | @pytest.fixture(scope="module") 10 | def image_directory(): 11 | """ hard-coded directory """ 12 | dirname = pathlib.Path(__file__).resolve().parents[3] / "games" / "Example_CrashTeamRacing" / "mods" / "TextureReplacement" 13 | yield dirname 14 | 15 | cases_fnames = ( # fname stems 16 | "SPYRO_368_216_1_251_44_26_4", 17 | "ZERO_1_2_3_4_5_6_7", 18 | ) 19 | @pytest.mark.parametrize("string", cases_fnames) 20 | def test_check_naming_convention(string): 21 | assert image.Image.check_naming_convention(string) 22 | 23 | def test_create_images(image_directory): 24 | """ 25 | TODO: Replace hard-coded directory 26 | """ 27 | print(image_directory) 28 | assert image.create_images(image_directory) == 1 29 | 30 | def test_as_c_struct(image_directory): 31 | """ 32 | TODO: parametrize this 33 | """ 34 | fname_image_texture = "SPYRO_368_216_1_251_44_26_4.png" 35 | instance = image.Image(image_directory / "newtex" / fname_image_texture) 36 | string_test = instance.as_c_struct() 37 | string_actual = "" 38 | with open(pathlib.Path.cwd() / "tests" / "spyro_c_struct.txt", "r") as f: 39 | string_actual = f.read() 40 | print("="*10) 41 | print(string_actual) 42 | print("="*10) 43 | print(string_test) 44 | print("="*10) 45 | assert instance.is_valid() 46 | assert string_actual == string_test 47 | 48 | def test_string_constructor(image_directory): 49 | """ 50 | TODO: parametrize this 51 | """ 52 | fname_image_texture = "SPYRO_368_216_1_251_44_26_4.png" 53 | instance = image.Image(image_directory / "newtex" / fname_image_texture) 54 | string_test = instance.__str__() 55 | string_actual = "" 56 | with open(pathlib.Path.cwd() / "tests" / "spyro___str__.txt", "r") as f: 57 | string_actual = f.read() 58 | print("="*10) 59 | print(string_actual) 60 | print("="*10) 61 | print(string_test) 62 | print("="*10) 63 | assert instance.is_valid() 64 | assert string_actual == string_test -------------------------------------------------------------------------------- /tools/mod-builder/tests/test_redux.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # pytest.set_trace() 4 | import redux 5 | 6 | # cases_path_settings = ( 7 | # ("tests/test_settings.json"), 8 | # ) 9 | # @pytest.mark.parametrize("fname", cases_path_settings) 10 | # def test_load_config(fname, expected): 11 | def test_load_config(): 12 | fname = "tests/fake_settings.json" 13 | instance_redux = redux.Redux() 14 | is_found = instance_redux.load_config(fname) 15 | assert not is_found 16 | -------------------------------------------------------------------------------- /tools/nugget/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 PCSX-Redux authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /tools/nugget/README.md: -------------------------------------------------------------------------------- 1 | # PCSX-Redux's mips code 2 | 3 | This repository is a read-only mirror of 4 | [PCSX-Redux's mips folder](https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips). 5 | Its purpose is to be used as a submodule for projects that want to use the various parts 6 | contained herein without bringing the whole of PCSX-Redux's codebase. 7 | 8 | Check the [doc](doc/README.md) folder for more information. 9 | -------------------------------------------------------------------------------- /tools/nugget/common.mk: -------------------------------------------------------------------------------- 1 | PREFIX ?= mipsel-none-elf 2 | FORMAT ?= elf32-littlemips 3 | 4 | ROOTDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 5 | 6 | CC = $(PREFIX)-gcc 7 | CXX = $(PREFIX)-g++ 8 | 9 | OVR_START_SYM = -Xlinker --defsym=OVR_START_ADDR=$(OVR_START_ADDR) 10 | 11 | ARCHFLAGS = -march=mips1 -mabi=32 -EL -fno-pic -mno-shared -mno-abicalls -mfp32 12 | ARCHFLAGS += -fno-stack-protector -nostdlib -ffreestanding 13 | CPPFLAGS += -ffunction-sections -fdata-sections 14 | ifeq ($(DISABLE_FUNCTION_REORDER),true) 15 | CPPFLAGS += -fno-toplevel-reorder 16 | endif 17 | CPPFLAGS += -mno-gpopt -fomit-frame-pointer 18 | CPPFLAGS += -fno-builtin -fno-strict-aliasing -Wno-attributes -Wextra 19 | CPPFLAGS += $(ARCHFLAGS) 20 | CPPFLAGS += -I$(ROOTDIR) 21 | 22 | LDFLAGS += -Wl,-Map=$(BINDIR)$(TARGET).map -nostdlib -T$(OVERLAYSCRIPT) $(LDSYMS) -static -Wl,--gc-sections 23 | LDFLAGS += $(ARCHFLAGS) -Wl,--oformat=$(FORMAT) 24 | LDFLAGS += $(OVR_START_SYM) 25 | 26 | CPPFLAGS += $(EXTRA_CC_FLAGS) 27 | LDFLAGS += $(EXTRA_CC_FLAGS) 28 | CPPFLAGS += $(OPT_CC_FLAGS) 29 | LDFLAGS += $(OPT_LD_FLAGS) 30 | 31 | CXXFLAGS += -fno-exceptions -fno-rtti 32 | 33 | OBJS += $(addsuffix .o, $(basename $(SRCS))) 34 | 35 | DEPS := $(patsubst %.cpp, %.dep,$(filter %.cpp,$(SRCS))) 36 | DEPS += $(patsubst %.cc, %.dep,$(filter %.cc,$(SRCS))) 37 | DEPS += $(patsubst %.c, %.dep,$(filter %.c,$(SRCS))) 38 | DEPS += $(patsubst %.s, %.dep,$(filter %.s,$(SRCS))) 39 | 40 | all: pch dep $(foreach ovl, $(OVERLAYSECTION), $(BINDIR)Overlay$(ovl)) 41 | 42 | $(BINDIR)Overlay%: $(BINDIR)$(TARGET).elf 43 | $(PREFIX)-objcopy -j $(@:$(BINDIR)Overlay%=%) -O binary $< $(BINDIR)$(TARGET)$(@:$(BINDIR)Overlay%=%) 44 | $(PYTHON) $(TOOLSDIR)trimbin/trimbin.py $(BINDIR)$(TARGET)$(@:$(BINDIR)Overlay%=%) $(BUILDDIR) $(TRIMBIN_OFFSET) 45 | 46 | $(BINDIR)$(TARGET).elf: $(OBJS) 47 | ifneq ($(strip $(BINDIR)),) 48 | mkdir -p $(BINDIR) 49 | endif 50 | $(CC) -o $(BINDIR)$(TARGET).elf $(OBJS) $(LDFLAGS) 51 | 52 | %.o: %.s 53 | $(CC) $(ARCHFLAGS) -I$(ROOTDIR) -c $< -o $@ 54 | 55 | %.dep: %.c 56 | $(CC) $(CPPFLAGS) $(CFLAGS) -M -MT $(addsuffix .o, $(basename $@)) -MF $@ $< 57 | 58 | %.dep: %.cpp 59 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -M -MT $(addsuffix .o, $(basename $@)) -MF $@ $< 60 | 61 | %.dep: %.cc 62 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -M -MT $(addsuffix .o, $(basename $@)) -MF $@ $< 63 | 64 | %.dep: %.s 65 | $(GCCDIR)touch $@ 66 | 67 | dep: $(DEPS) 68 | 69 | %.h.gch: %.h 70 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 71 | 72 | pch: $(PCHS) 73 | 74 | -include $(DEPS) 75 | 76 | .PHONY: all pch dep -------------------------------------------------------------------------------- /tools/startup/MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /tools/startup/MOD.SH: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | python3 ../../../../tools/mod-builder/main.py -------------------------------------------------------------------------------- /tools/startup/STARTUP_MOD.BAT: -------------------------------------------------------------------------------- 1 | python ../../../tools/startup/startup.py 1 -------------------------------------------------------------------------------- /tools/startup/STARTUP_MOD.SH: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | python3 ../../../tools/startup/startup.py 1 -------------------------------------------------------------------------------- /tools/startup/plugin.py: -------------------------------------------------------------------------------- 1 | def extract(plugin_path: str, game_path: str, game_version: str) -> None: 2 | pass 3 | 4 | def build(plugin_path: str, game_path: str, game_version: str) -> None: 5 | pass 6 | -------------------------------------------------------------------------------- /tools/trimbin/trimbin.py: -------------------------------------------------------------------------------- 1 | """ 2 | Called by nugget/common.mk 3 | TODO: Move to the mod-bulider 4 | """ 5 | import logging 6 | import os 7 | import pathlib 8 | import sys 9 | 10 | # import _files 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | def trimbin(filename: str, target_path: str, offset_file: str) -> None: 15 | logger.debug("filename", filename) 16 | logger.debug("target_path", target_path) 17 | logger.debug("offset_file", offset_file) 18 | arr = bytearray() 19 | with open(filename, "rb") as file: 20 | arr = file.read() 21 | 22 | extension = pathlib.Path(filename).suffix.replace(".", "") 23 | with open(offset_file, "r") as file: 24 | for line in file: 25 | line = line.split() 26 | if line[0] == extension: 27 | arr = arr[int(line[1], 0):] 28 | break 29 | 30 | with open(filename, "wb") as file: 31 | file.write(arr) 32 | 33 | new_name = extension + ".bin" 34 | new_filename = pathlib.Path(target_path) / new_name 35 | if new_filename.exists(): 36 | new_filename.unlink() 37 | os.rename(filename, new_filename) 38 | 39 | def main() -> None: 40 | trimbin(sys.argv[1], sys.argv[2], sys.argv[3]) 41 | 42 | if __name__ == "__main__": 43 | main() -------------------------------------------------------------------------------- /tools/updater/main.py: -------------------------------------------------------------------------------- 1 | import requests as r 2 | import os 3 | import shutil 4 | 5 | temp_file = "repo.zip" 6 | temp_folder = "repo/" 7 | version_file = "tools/updater/.version" 8 | repo = "mateusfavarin/psx-modding-toolchain" 9 | branch = "main" 10 | url = "https://api.github.com/repos/" + repo 11 | 12 | def get_program_version() -> str: 13 | if os.path.isfile(version_file): 14 | with open(version_file, "r") as file: 15 | for line in file: 16 | return line 17 | return "0" 18 | 19 | def update_program_version(version: str): 20 | with open(version_file, "w") as file: 21 | file.write(version) 22 | 23 | def get_newest_version() -> str: 24 | commits = r.get(url + "/commits").json() 25 | return commits[0]["sha"] 26 | 27 | def cli_pause() -> None: 28 | print("Press Enter to continue...") 29 | input() 30 | 31 | def download_repo() -> bool: 32 | print("[Updater-py] Downloading update...") 33 | req = r.get(url + "/zipball/" + branch) 34 | if req.status_code == 200: 35 | with open(temp_file, "wb") as file: 36 | file.write(req.content) 37 | return True 38 | else: 39 | print(["[Updater-py] ERROR: Could not connect to " + url]) 40 | return False 41 | 42 | def move_files(folder: str, i: int) -> None: 43 | for root, _, files in os.walk(folder): 44 | for file in files: 45 | if file == ".gitignore": 46 | continue 47 | file_src = root + "/" + file 48 | file_dst = root[i:] + "/" + file 49 | folders = root[i:].replace("\\", "/").split("/") 50 | # Checking if the folder exists, so the file can be moved 51 | path = str() 52 | for folder in folders: 53 | path += folder + "/" 54 | if not os.path.exists(path): 55 | os.mkdir(path) 56 | # Deleting old file 57 | if os.path.isfile(file_dst): 58 | os.remove(file_dst) 59 | # Replacing with new file 60 | shutil.move(file_src, file_dst) 61 | 62 | def apply_patch() -> None: 63 | print("[Updater-py] Applying patch...") 64 | os.mkdir(temp_folder) 65 | shutil.unpack_archive(temp_file, temp_folder) 66 | content_folder = str() 67 | for root, dirs, _ in os.walk(temp_folder): 68 | content_folder = root + dirs[0] 69 | break 70 | i = len(content_folder) + 1 71 | move_files(content_folder + "/tools/", i) 72 | move_files(content_folder + "/docs/", i) 73 | shutil.rmtree(temp_folder) 74 | os.remove(temp_file) 75 | 76 | def main() -> None: 77 | curr_version = get_program_version() 78 | new_version = get_newest_version() 79 | if curr_version == new_version: 80 | print("[Updater-py] Your toolchain is already up-to-date.") 81 | cli_pause() 82 | return 83 | if not download_repo(): 84 | cli_pause() 85 | return 86 | apply_patch() 87 | update_program_version(new_version) 88 | cli_pause() 89 | 90 | if __name__ == "__main__": 91 | main() -------------------------------------------------------------------------------- /tools/vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "type": "gdb", 5 | "request": "attach", 6 | "name": "(gdb) Debug Mod", 7 | "target": "localhost:3333", 8 | "remote": true, 9 | "stopAtConnect": true, 10 | "executable": "./games/Example_CrashTeamRacing/mods/HelloWorld/debug/mod.elf", 11 | "gdbpath": "/usr/bin/gdb-multiarch", 12 | "windows": { 13 | "gdbpath": "C:/gdb-multiarch-12.1/bin/gdb.exe", 14 | }, 15 | "cwd": "${workspaceRoot}", 16 | "autorun": [ 17 | "set confirm off", 18 | "set substitute-path /project .", 19 | ], 20 | "valuesFormatting": "parseText" 21 | } 22 | ] 23 | } --------------------------------------------------------------------------------