Building Instructions & CI (#178)

Co-authored-by: Mr-Wiseguy <mrwiseguyromhacking@gmail.com>
This commit is contained in:
David Chavez 2024-05-18 04:23:48 +02:00 committed by GitHub
parent 008dfa5b0b
commit 7e8782c114
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 69338 additions and 29 deletions

155
.github/workflows/validate.yml vendored Normal file
View File

@ -0,0 +1,155 @@
name: validate
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-unix:
runs-on: ubuntu-22.04
strategy:
matrix:
type: [ Debug, Release ]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-z64re-ccache-${{ matrix.type }}
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y ninja-build libsdl2-dev libgtk-3-dev lld llvm clang-15
# Install SDL2
echo ::group::install SDL2
# Enable ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz
tar -xzf SDL2-2.26.1.tar.gz
cd SDL2-2.26.1
./configure
make -j 10
sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
echo ::endgroup::
- name: Prepare Build
run: |-
git clone https://${{ secrets.PAT }}@github.com/dcvz/zre.git
./zre/process.sh
env:
LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }}
- name: Build N64Recomp & RSPRecomp
if: runner.os != 'Windows'
run: |
git clone https://github.com/Mr-Wiseguy/N64Recomp.git --recurse-submodules N64RecompSource
cd N64RecompSource
# enable ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
# Build N64Recomp & RSPRecomp
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
cmake --build cmake-build --config Release --target N64Recomp -j 8
cmake --build cmake-build --config Release --target RSPRecomp -j 8
# Copy N64Recomp & RSPRecomp to root directory
cp cmake-build/N64Recomp ..
cp cmake-build/RSPRecomp ..
- name: Run N64Recomp & RSPRecomp
run: |
./N64Recomp us.rev1.toml
./RSPRecomp aspMain.us.rev1.toml
./RSPRecomp njpgdspMain.us.rev1.toml
- name: Build ZeldaRecomp
run: |-
# enable ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=clang++-15 -DCMAKE_C_COMPILER=clang-15 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
cmake --build cmake-build --config ${{ matrix.type }} --target Zelda64Recompiled -j 8
- name: Prepare Archive
run: |
mv cmake-build/Zelda64Recompiled Zelda64Recompiled
rm -rf assets/scss
- name: Archive Zelda64Recomp
uses: actions/upload-artifact@v4
with:
name: Zelda64Recompiled-${{ runner.os }}-${{ matrix.type }}
path: |
Zelda64Recompiled
assets/
build-windows:
runs-on: windows-latest
strategy:
matrix:
type: [ Debug, Release ]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-z64re-ccache-${{ matrix.type }}
- name: Install Windows Dependencies
run: |
choco install ninja
Remove-Item -Path "C:\ProgramData\Chocolatey\bin\ccache.exe" -Force -ErrorAction SilentlyContinue
- name: Configure Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Prepare Build
run: |-
git clone https://${{ secrets.PAT }}@github.com/dcvz/zre.git
./zre/process.ps1
env:
LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }}
- name: Build N64Recomp & RSPRecomp
run: |
git clone https://github.com/Mr-Wiseguy/N64Recomp.git --recurse-submodules N64RecompSource
cd N64RecompSource
# enable ccache
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
cmake --build cmake-build --config Release --target N64Recomp -j 8
cmake --build cmake-build --config Release --target RSPRecomp -j 8
# Copy N64Recomp & RSPRecomp to root directory
cp cmake-build/N64Recomp.exe ..
cp cmake-build/RSPRecomp.exe ..
- name: Run N64Recomp & RSPRecomp
run: |
./N64Recomp.exe us.rev1.toml
./RSPRecomp.exe aspMain.us.rev1.toml
./RSPRecomp.exe njpgdspMain.us.rev1.toml
- name: Build ZeldaRecomp
run: |-
# enable ccache
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH"
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER=clang-cl -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build -DCMAKE_CXX_FLAGS="-Xclang -fcxx-exceptions"
cmake --build cmake-build --config ${{ matrix.type }} --target Zelda64Recompiled -j 8
- name: Prepare Archive
run: |
Move-Item -Path "cmake-build/Zelda64Recompiled.exe" -Destination "Zelda64Recompiled.exe"
Remove-Item -Path "assets/scss" -Recurse -Force
- name: Archive Zelda64Recomp
uses: actions/upload-artifact@v4
with:
name: Zelda64Recompiled-${{ runner.os }}-${{ matrix.type }}
path: |
Zelda64Recompiled.exe
assets/

86
BUILDING.md Normal file
View File

@ -0,0 +1,86 @@
# Building Guide
> [!NOTE]
> The need for an elf file from the Majora's Mask decompilation is temporary and will be removed in the future.
This guide will help you build the project on your local machine. The process will require you to provide two items:
- A decompressed ROM of the US version of the game.
- An elf file created from [this commit](https://github.com/zeldaret/mm/tree/23beee0717364de43ca9a82957cc910cf818de90) of the Majora's Mask decompilation.
These steps cover: acquiring these, running the required processes and finally building the project.
## 1. Clone the Zelda64Recomp Repository
This project makes use of submodules so you will need to clone the repository with the `--recurse-submodules` flag.
```bash
git clone --recurse-submodules
# if you forgot to clone with --recurse-submodules
# cd /path/to/cloned/repo && git submodule update --init --recursive
```
## 2. Install Dependencies
### Linux
For Linux the instructions for Ubuntu are provided, but you can find the equivalent packages for your preferred distro.
```bash
# For Ubuntu, simply run:
sudo apt-get install cmake ninja libsdl2-dev libgtk-3-dev lld llvm clang-15
```
### Windows
You will need to install [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/).
In the setup process you'll need to select the following options and tools for installation:
- Desktop development with C++
- C++ Clang Compiler for Windows
- C++ CMake tools for Windows
The other tool necessary will be `make` which can be installe via [Chocolatey](https://chocolatey.org/):
```bash
choco install make
```
## 3. Creating the ELF file & decompressed ROM
You will need to build [this commit](https://github.com/zeldaret/mm/tree/23beee0717364de43ca9a82957cc910cf818de90) of the Majora's Mask decompilation. Follow their build instructions to generate the ELF file and decompressed ROM. However, while building you may get the following build error:
```bash
RuntimeError: 'jr' instruction does not have an 'jump label' field
```
To fix this you will have to modify the problematic file `tools/disasm/disasm.py` at line 1115. This issue is due to a bug in this specific commit of the decomp project and will be resolved once Zelda64Recomp is updated to a more recent commit. To fix it, replace the line:
```diff
- elif insn.isJump():
+ elif insn.isJumpWithAddress():
```
Upon successful build it will generate the two required files. Copy them to the root of the Zelda64Recomp repository:
- `mm.us.rev1.rom_uncompressed.elf`
- `mm.us.rev1.rom_uncompressed.z64`
## 4. Generating the C code
Now that you have the required files, you must build [N64Recomp](https://github.com/Mr-Wiseguy/N64Recomp) and run it to generate the C code to be compiled. The building instructions can be found [here](https://github.com/Mr-Wiseguy/N64Recomp?tab=readme-ov-file#building). That will build the executables: `N64Recomp` and `RSPRecomp` which you should copy to the root of the Zelda64Recomp repository.
After that, go back to the repository root, and run the following commands:
```bash
./N64Recomp us.rev1.toml
./RSPRecomp aspMain.us.rev1.toml
./RSPRecomp njpgdspMain.us.rev1.toml
```
## 5. Building the Project
Finally, you can build the project! :rocket:
On Windows, you can open the repository folder with Visual Studio, and you'll be able to `[build / run / debug]` the project from there. If you prefer the commandline or you're on a Unix platform you can build the project using CMake:
```bash
cmake -S . -B cmake-build -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -G Ninja -DCMAKE_BUILD_TYPE=Release # or Debug if you want to debug
cmake --build build-cmake --target Zelda64Recompiled -j$(nproc) --config Release # or Debug
```
## 6. Success
Voilà! You should now have a `Zelda64Recompiled` file in the `build-cmake` directory!
> [!IMPORTANT]
> In the game itself, you should be using a standard ROM, not the decompressed one.

View File

@ -43,6 +43,7 @@ add_library(RecompiledFuncs STATIC)
target_compile_options(RecompiledFuncs PRIVATE
# -Wno-unused-but-set-variable
-fno-strict-aliasing
-Wno-implicit-function-declaration
)
target_include_directories(RecompiledFuncs PRIVATE
@ -74,10 +75,10 @@ target_sources(PatchesLib PRIVATE
set_source_files_properties(${CMAKE_SOURCE_DIR}/RecompiledPatches/patches.c PROPERTIES COMPILE_FLAGS -fno-strict-aliasing)
# Build patches elf
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/patches/patches.bin
add_custom_target(PatchesBin
COMMAND make
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/patches
BYPRODUCTS ${CMAKE_SOURCE_DIR}/patches/patches.bin}
BYPRODUCTS ${CMAKE_SOURCE_DIR}/patches/patches.bin
)
# Generate patches_bin.c from patches.bin

View File

@ -109,7 +109,7 @@ You'll probably also want to change the default behavior so that you don't need
* Overlays such as MSI Afterburner and other software such as Wallpaper Engine can cause performance issues with this project that prevent the game from rendering correctly. Disabling such software is recommended.
## Building
Building is not required to play this project, as prebuilt binaries (which do not contain game assets) can be found in the [Releases section](https://github.com/Mr-Wiseguy/Zelda64Recomp/releases). Instructions on how to build this project are being worked on and will be available in the near future.
Building is not required to play this project, as prebuilt binaries (which do not contain game assets) can be found in the [Releases](https://github.com/Mr-Wiseguy/Zelda64Recomp/releases) section. Instructions on how to build this project can be found in the [BUILDING.md](BUILDING.md) file.
## Libraries Used and Projects Referenced
* [RT64](https://github.com/rt64/rt64) for the project's rendering engine

View File

@ -1,7 +1,7 @@
text_offset = 0xC40FF0
text_size = 0x1000
text_address = 0x04001000
rom_file_path = "mm.us.rev1_uncompressed.z64"
rom_file_path = "mm.us.rev1.rom_uncompressed.z64"
output_file_path = "rsp/aspMain.cpp"
output_function_name = "aspMain"
extra_indirect_branch_targets = [

10
include/recomp_overlays.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __RECOMP_OVERLAYS_H__
#define __RECOMP_OVERLAYS_H__
#include <cstdint>
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size);
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size);
void init_overlays();
#endif

@ -1 +1 @@
Subproject commit d64100a058b6fa6185be9a2754a197b31f050467
Subproject commit ecdd609c49fb5f10e3040335901d8860ef259f67

View File

@ -1,6 +1,6 @@
text_offset = 0xC438B0
text_size = 0xAF0
text_address = 0x04001080
rom_file_path = "mm.us.rev1_uncompressed.z64"
rom_file_path = "mm.us.rev1.rom_uncompressed.z64"
output_file_path = "rsp/njpgdspMain.cpp"
output_function_name = "njpgdspMain"

View File

@ -8,7 +8,7 @@ CFLAGS := -target mips -mips2 -mabi=32 -O2 -G0 -mno-abicalls -mno-odd-spreg -m
-fomit-frame-pointer -ffast-math -fno-unsafe-math-optimizations -fno-builtin-memset \
-Wall -Wextra -Wno-incompatible-library-redeclaration -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-variable -Wno-missing-braces -Wno-unsupported-floating-point-opt
CPPFLAGS := -nostdinc -D_LANGUAGE_C -DMIPS -I dummy_headers -I ../lib/mm-decomp/include -I ../lib/mm-decomp/src -I ../lib/mm-decomp/assets -I../lib/rt64/include
LDFLAGS := -nostdlib -T patches.ld -T syms.ld --just-symbols=../mm.us.rev1.elf --allow-multiple-definition -Map patches.map
LDFLAGS := -nostdlib -T patches.ld -T syms.ld --just-symbols=../mm.us.rev1.rom_uncompressed.elf --allow-multiple-definition -Map patches.map
BINFLAGS := -O binary --remove-section=.bss --remove-section=.pad --remove-section=.text
C_SRCS := $(wildcard *.c)

View File

@ -3,6 +3,7 @@
#include "patch_helpers.h"
DECLARE_FUNC(void, recomp_load_overlays, u32 rom, void* ram, u32 size);
DECLARE_FUNC(void, recomp_puts, const char* data, u32 size);
DECLARE_FUNC(void, recomp_exit);
DECLARE_FUNC(void, recomp_handle_quicksave_actions, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq);

View File

@ -9,6 +9,7 @@
#define osFlashWriteArray osFlashWriteArray_recomp
#define osFlashWriteBuffer osFlashWriteBuffer_recomp
#define osWritebackDCache osWritebackDCache_recomp
#define osInvalICache osInvalICache_recomp
#define osGetTime osGetTime_recomp
#define osContStartReadData osContStartReadData_recomp

View File

@ -0,0 +1,75 @@
#include "patches.h"
#include "misc_funcs.h"
#include "loadfragment.h"
void Main_ClearMemory(void* begin, void* end);
void Main_InitMemory(void);
void Main_InitScreen(void);
// @recomp Patched to load the code segment in the recomp runtime.
void Main_Init(void) {
DmaRequest dmaReq;
OSMesgQueue mq;
OSMesg msg[1];
size_t prevSize;
osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg));
prevSize = gDmaMgrDmaBuffSize;
gDmaMgrDmaBuffSize = 0;
// @recomp Load the code segment in the recomp runtime.
recomp_load_overlays(SEGMENT_ROM_START(code), SEGMENT_START(code), SEGMENT_ROM_END(code) - SEGMENT_ROM_START(code));
DmaMgr_SendRequestImpl(&dmaReq, SEGMENT_START(code), SEGMENT_ROM_START(code),
SEGMENT_ROM_END(code) - SEGMENT_ROM_START(code), 0, &mq, NULL);
Main_InitScreen();
Main_InitMemory();
osRecvMesg(&mq, NULL, OS_MESG_BLOCK);
gDmaMgrDmaBuffSize = prevSize;
Main_ClearMemory(SEGMENT_BSS_START(code), SEGMENT_BSS_END(code));
}
void Overlay_Relocate(void* allocatedRamAddr, OverlayRelocationSection* ovlRelocs, uintptr_t vramStart);
// @recomp Patched to load the overlay in the recomp runtime.
size_t Overlay_Load(uintptr_t vromStart, uintptr_t vromEnd, void* ramStart, void* ramEnd, void* allocatedRamAddr) {
uintptr_t vramStart = (uintptr_t)ramStart;
uintptr_t vramEnd = (uintptr_t)ramEnd;
s32 size = vromEnd - vromStart;
uintptr_t end;
OverlayRelocationSection* ovlRelocs;
// @recomp Load the overlay in the recomp runtime.
recomp_load_overlays(vromStart, allocatedRamAddr, vromEnd - vromStart);
if (gOverlayLogSeverity >= 3) {}
if (gOverlayLogSeverity >= 3) {}
end = (uintptr_t)allocatedRamAddr + size;
DmaMgr_SendRequest0(allocatedRamAddr, vromStart, size);
ovlRelocs = (OverlayRelocationSection*)(end - ((s32*)end)[-1]);
if (gOverlayLogSeverity >= 3) {}
if (gOverlayLogSeverity >= 3) {}
Overlay_Relocate(allocatedRamAddr, ovlRelocs, vramStart);
if (ovlRelocs->bssSize != 0) {
if (gOverlayLogSeverity >= 3) {}
bzero((void*)end, ovlRelocs->bssSize);
}
size = vramEnd - vramStart;
osWritebackDCache(allocatedRamAddr, size);
osInvalICache(allocatedRamAddr, size);
if (gOverlayLogSeverity >= 3) {}
return size;
}

View File

@ -50,3 +50,5 @@ recomp_get_mouse_deltas = 0x8F000080;
bcmp_recomp = 0x8F000084;
osGetTime_recomp = 0x8F000088;
recomp_autosave_enabled = 0x8F00008C;
recomp_load_overlays = 0x8F000090;
osInvalICache_recomp = 0x8F000094;

View File

@ -1,6 +1,7 @@
#include <cmath>
#include "recomp.h"
#include "recomp_overlays.h"
#include "recomp_config.h"
#include "recomp_input.h"
#include "recomp_ui.h"
@ -93,3 +94,11 @@ extern "C" void recomp_time_us(uint8_t* rdram, recomp_context* ctx) {
extern "C" void recomp_autosave_enabled(uint8_t* rdram, recomp_context* ctx) {
_return(ctx, static_cast<s32>(recomp::get_autosave_mode() == recomp::AutosaveMode::On));
}
extern "C" void recomp_load_overlays(uint8_t * rdram, recomp_context * ctx) {
u32 rom = _arg<0, u32>(rdram, ctx);
PTR(void) ram = _arg<1, PTR(void)>(rdram, ctx);
u32 size = _arg<2, u32>(rdram, ctx);
load_overlays(rom, ram, size);
}

View File

@ -2,6 +2,7 @@
#include <algorithm>
#include <vector>
#include "recomp.h"
#include "recomp_overlays.h"
#include "../RecompiledFuncs/recomp_overlays.inl"
constexpr size_t num_code_sections = ARRLEN(section_table);

View File

@ -11,6 +11,7 @@
#include <fstream>
#include <iostream>
#include "recomp.h"
#include "recomp_overlays.h"
#include "recomp_game.h"
#include "recomp_config.h"
#include "xxHash/xxh3.h"
@ -301,9 +302,6 @@ void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t ar
extern "C" void recomp_entrypoint(uint8_t * rdram, recomp_context * ctx);
gpr get_entrypoint_address();
const char* get_rom_name();
void init_overlays();
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size);
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size);
void read_patch_data(uint8_t* rdram, gpr patch_data_address) {
for (size_t i = 0; i < sizeof(mm_patches_bin); i++) {

68987
us.rev1.syms.toml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,10 @@
[input]
entrypoint = 0x80080000
# Paths are relative to the location of this config file.
elf_path = "mm.us.rev1.elf"
output_func_path = "RecompiledFuncs"
relocatable_sections_path = "overlays.us.rev1.txt"
symbols_file_path = "us.rev1.syms.toml"
rom_file_path = "mm.us.rev1.rom_uncompressed.z64"
[patches]
stubs = [
@ -21,24 +22,6 @@ ignored = [
"D_80186028"
]
# Hooks
# Function definition for the overlay loading function.
[[patches.func]]
name = "load_overlays"
args = ["u32", "u32", "u32"]
# Function hooks for overlay loading.
[[patches.hook]]
func = "Main_Init"
text = " load_overlays((uint32_t)ctx->r6, (uint32_t)ctx->r5, (uint32_t)ctx->r7);"
after_vram = 0x800802A4
[[patches.hook]]
func = "Overlay_Load"
text = " load_overlays((uint32_t)ctx->r4, MEM_W(0x10, ctx->r29), (uint32_t)(ctx->r5 - ctx->r4));"
# No after_vram means this will be placed at the start of the function
# Single-instruction patches
# Write audio dlists to kseg0 (cached, 0x80...) addresses instead of kseg1 (uncached, 0xA0...) ones.