diff --git a/.github/filter-mips/filter.sh b/.github/filter-mips/filter.sh index c519d5c16..dfdae82f0 100755 --- a/.github/filter-mips/filter.sh +++ b/.github/filter-mips/filter.sh @@ -10,8 +10,8 @@ cd $CWD # Need to delete submodules actively. # Done in two passes for speed. -git filter-branch -f --tree-filter 'find third_party -depth -not -name uC-sdk -and -not -path third_party/psxlua -and -not -path third_party/EABase -and -not -path third_party/EABase/\* -and -not -path third_party/EASTL -and -not -path third_party/EASTL/\* -delete || true' --tag-name-filter cat --prune-empty -git filter-branch -f --tree-filter 'find third_party -depth -not -name uC-sdk -and -not -path third_party/psxlua -and -not -path third_party/EABase -and -not -path third_party/EABase/\* -and -not -path third_party/EASTL -and -not -path third_party/EASTL/\* -exec git rm -f {} \; || true' --tag-name-filter cat --prune-empty +git filter-branch -f --tree-filter 'find third_party -depth -not -name uC-sdk -and -not -path third_party/psxlua -and -not -path third_party/EABase -and -not -path third_party/EABase/\* -and -not -path third_party/EASTL -and -not -path third_party/EASTL/\* -and -not -path third_party/xmake-psx -delete || true' --tag-name-filter cat --prune-empty +git filter-branch -f --tree-filter 'find third_party -depth -not -name uC-sdk -and -not -path third_party/psxlua -and -not -path third_party/EABase -and -not -path third_party/EABase/\* -and -not -path third_party/EASTL -and -not -path third_party/EASTL/\* -and -not -path third_party/xmake-psx -exec git rm -f {} \; || true' --tag-name-filter cat --prune-empty # Shuffle files around. git filter-branch -f --tree-filter 'mkdir -p src/mips ; git mv third_party src/mips ; mv .gitmodules src/mips ; mv docker* src/mips || true' --tag-name-filter cat --prune-empty @@ -38,6 +38,9 @@ git filter-branch -f --tree-filter "find . -name '*.mk' -exec sed 's|\.\./\.\./\ git filter-branch -f --tree-filter "find . -name Makefile -exec sed 's|\.\./\.\./\.\./third_party/psxlua/|../third_party/psxlua/|' -i {} \;" --tag-name-filter cat --prune-empty git filter-branch -f --tree-filter "find . -name '*.mk' -exec sed 's|\.\./\.\./\.\./third_party/psxlua/|../third_party/psxlua/|' -i {} \;" --tag-name-filter cat --prune-empty +# Adjust paths for xmake +git filter-branch -f --tree-filter "find . -name xmake.lua -exec sed 's|local root = path.join(os.scriptdir(), \"\.\.\", \"\.\.\"|local root = path.join(os.scriptdir()|' -i {} \;" --tag-name-filter cat --prune-empty + # Delete unwanted files git filter-branch -f --tree-filter 'find . -name compile_flags.txt -delete || true' --tag-name-filter cat --prune-empty git filter-branch -f --tree-filter 'find . -name Doxyfile -delete || true' --tag-name-filter cat --prune-empty diff --git a/.gitignore b/.gitignore index 44deb7e8a..2c6907566 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,9 @@ luacov.stats.out /appimage-build /AppDir /*.AppImage -/*.AppImage.zsync \ No newline at end of file +/*.AppImage.zsync + +# xmake +.xmake/ +build/ + diff --git a/.gitmodules b/.gitmodules index 0ee92da37..61af79bba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -100,3 +100,6 @@ [submodule "third_party/psxlua"] path = third_party/psxlua url = https://github.com/grumpycoders/psxlua.git +[submodule "third_party/xmake-psx"] + path = third_party/xmake-psx + url = https://codeberg.org/malucart/xmake-psx.git diff --git a/src/mips/common/crt0/cxxglue.c b/src/mips/common/crt0/cxxglue.c index 46e7f46f5..c26d655d9 100644 --- a/src/mips/common/crt0/cxxglue.c +++ b/src/mips/common/crt0/cxxglue.c @@ -161,6 +161,7 @@ __attribute__((section(".preinit_array"))) static fptr pi_heap[] = { // we're not going to care about exit cleanup __attribute__((weak)) void __cxa_atexit(void (*func)(void*), void* arg, void* dso_handle) {} +__attribute__((weak)) void atexit(void (*func)(void)) {} // no, we're not going to have shared libraries __attribute__((weak)) void* __dso_handle = NULL; diff --git a/src/mips/helloworld/xmake.lua b/src/mips/helloworld/xmake.lua new file mode 100644 index 000000000..e1c64811b --- /dev/null +++ b/src/mips/helloworld/xmake.lua @@ -0,0 +1,23 @@ +local root = path.join(os.scriptdir(), "..", "..", "..") +local mips = path.join(os.scriptdir(), "..") + +set_allowedmodes("debug", "dev", "release") +includes(path.join(root, "tools", "exe2iso")) +includes(path.join(root, "tools", "ps1-packer")) +includes(mips) + +target("helloworld", function() + set_kind("binary") + add_rules("nugget") + add_files("main/**.c") +end) + +target("helloworld.ps-exe", function() + add_deps("helloworld") + add_rules("pcsx.ps1-packer.psexe") +end) + +target("helloworld.iso", function() + add_deps("helloworld.ps-exe") + add_rules("pcsx.exe2iso.iso") +end) diff --git a/src/mips/psyqo/examples/hello/xmake.lua b/src/mips/psyqo/examples/hello/xmake.lua new file mode 100644 index 000000000..5671662c1 --- /dev/null +++ b/src/mips/psyqo/examples/hello/xmake.lua @@ -0,0 +1,8 @@ +local psyqo = path.join(os.scriptdir(), "..", "..") + +includes(psyqo) + +target("hello", function() + add_rules("psyqo.app") + add_files("*.cpp") +end) diff --git a/src/mips/psyqo/xmake.lua b/src/mips/psyqo/xmake.lua new file mode 100644 index 000000000..693d6915e --- /dev/null +++ b/src/mips/psyqo/xmake.lua @@ -0,0 +1,25 @@ +local root = path.join(os.scriptdir(), "..", "..", "..") +local mips = path.join(os.scriptdir(), "..") +local psyqo = path.join(os.scriptdir()) + +set_allowedmodes("debug", "dev", "release") +includes(mips) + +set_languages("c11", "c++26") + +rule("psyqo.app", function () + add_deps("nugget") + on_load(function(target) + target:add("values", "c++", true) + target:set("kind", "binary") + target:add("files", path.join(psyqo, "src", "*.c")) + target:add("files", path.join(psyqo, "src", "*.cpp")) + target:add("files", path.join(psyqo, "src", "**/*.cpp")) + target:add("files", path.join(mips, "common", "hardware", "flushcache.s")) + target:add("files", path.join(mips, "common", "psxlibc", "ucontext.s")) + target:add("files", path.join(mips, "common", "util", "*.cc")) + target:add("files", path.join(root, "third_party", "EASTL", "source", "*.cpp")) + target:add("includedirs", path.join(root, "third_party", "EASTL", "include")) + target:add("includedirs", path.join(root, "third_party", "EABase", "include", "Common")) + end) +end) diff --git a/src/mips/xmake.ld b/src/mips/xmake.ld new file mode 100644 index 000000000..d5233548a --- /dev/null +++ b/src/mips/xmake.ld @@ -0,0 +1,153 @@ +/* + +MIT License + +Copyright (c) 2026 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +EXTERN(_start) +ENTRY(_start) + +RAM_SIZE = DEFINED(RAM_SIZE) ? RAM_SIZE : 2M; +TLOAD_ADDR = DEFINED(TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; + +MEMORY { + ram (rwx) : ORIGIN = TLOAD_ADDR, LENGTH = RAM_SIZE - (TLOAD_ADDR - 0x80000000) + dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 +} + +__ram_top = ORIGIN(ram) + LENGTH(ram); +__sp = __ram_top - 0x100; + +__dcache = ORIGIN(dcache); +__dcache_top = ORIGIN(dcache) + LENGTH(dcache); + +__bss_len = (__bss_end - __bss_start); +__ftext_len = (__ftext_end - __ftext_start); +__fdata_len = (__fdata_end - __fdata_start); + +__stack_start = ORIGIN(ram) + LENGTH(ram); + +SECTIONS { + __ftext_start = ABSOLUTE(.); + .text TLOAD_ADDR : { + *(.start) + *(.init) + KEEP (*(SORT_NONE(.fini))) + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + + . = ALIGN(16); + KEEP(*(.init)) + . = ALIGN(16); + KEEP(*(.fini)) + } > ram + + . = ALIGN(16); + __text_end = .; + __ftext_end = ABSOLUTE(.); + + __fdata_start = ABSOLUTE(.); + + .rodata : { + *(.rodata .rodata.* .rdata .rdata.* .gnu.linkonce.r.*) + . = ALIGN(16); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(16); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + + . = ALIGN(16); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + __init_array_end = .; + + . = ALIGN(16); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + __fini_array_end = .; + __build_id = .; + *(.note.gnu.build-id) + __build_id_end = .; + } > ram + + .rodata1 : { + *(.rodata1) + } > ram + + __data_start = .; + .data : { + KEEP (*(.data .data.* .gnu.linkonce.d.*)) + KEEP (*(.data1)) + KEEP (*(.sdata .sdata.* .gnu.linkonce.s.*)) + KEEP (*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)) + KEEP (*(.got.plt)) + KEEP (*(.got)) + } > ram + + __data_end = .; + __fdata_end = .; + __bss_start = .; + .sbss (NOLOAD) : { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } > ram + + . = ALIGN(4); + __bss_end = .; + + __heap_start = __heap_base; + + . = ADDR(.text) - 0x800; + __end = .; + + /DISCARD/ : { *(.MIPS.abiflags) } + + /* Everything is statically linked, so discard PLTs. */ + /DISCARD/ : { *(.rel.iplt) *(.rela.iplt) *(.rel.plt) *(.rela.plt) *(.plt) *(.iplt) } + + /* Discard things that the standard link script drops, too. */ + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } + + .scratchpad (NOLOAD) : { + *(.scratchpad) + } > dcache +} diff --git a/src/mips/xmake.lua b/src/mips/xmake.lua new file mode 100644 index 000000000..e903d69a8 --- /dev/null +++ b/src/mips/xmake.lua @@ -0,0 +1,29 @@ +local root = path.join(os.scriptdir(), "..", "..") +local mips = path.join(os.scriptdir()) + +includes(path.join(root, "third_party", "xmake-psx")) + +rule("nugget", function() + add_deps("psx") + on_load(function(target) + target:add("includedirs", mips) + target:add("values", "psx.no_crt", true) + target:add("values", "psx.no_ldscript", true) + target:add("values", "psx.nogp", true) + end) + before_config(function (target) + if target:get("kind") == "binary" then + if target:values("c++") then + target:add("files", path.join(mips, "common", "crt0", "crt0cxx.s")) + target:add("files", path.join(mips, "common", "crt0", "cxxglue.c")) + else + target:add("files", path.join(mips, "common", "crt0", "crt0.s")) + end + target:add("files", path.join(mips, "common", "crt0", "memory-c.c")) + target:add("files", path.join(mips, "common", "crt0", "memory-s.s")) + target:add("files", path.join(mips, "common", "syscalls", "printf.s")) + target:add("files", path.join(mips, "xmake.ld")) + target:add("files", path.join(mips, "nooverlay.ld")) + end + end) +end) diff --git a/src/support/xmake.lua b/src/support/xmake.lua index fdcf50bb6..0286743e5 100644 --- a/src/support/xmake.lua +++ b/src/support/xmake.lua @@ -5,7 +5,7 @@ add_rules("mode.debug", "mode.release") add_requires("fmt", "zlib") set_languages("c++26") -target("pcsx.support") +target("pcsx.support", function() set_kind("static") if is_plat("windows") then @@ -20,3 +20,5 @@ target("pcsx.support") ) add_files("*.cc") + remove_files("ffmpeg-audio-file.cc", "uvfile.cc", "version*.cc") +end) diff --git a/src/supportpsx/binloader.cc b/src/supportpsx/binloader.cc index cb55803d5..8441713f6 100644 --- a/src/supportpsx/binloader.cc +++ b/src/supportpsx/binloader.cc @@ -220,7 +220,7 @@ bool loadELF(IO file, IO dest, BinaryLoader::Info& info, std::map(reader.get_entry()); Elf_Half sec_num = reader.sections.size(); for (unsigned i = 0; i < sec_num; i++) { diff --git a/src/supportpsx/xmake.lua b/src/supportpsx/xmake.lua index e2a67f106..8f6455cc1 100644 --- a/src/supportpsx/xmake.lua +++ b/src/supportpsx/xmake.lua @@ -6,7 +6,7 @@ add_requires("fmt", "zlib") set_languages("c11", "c++26") includes(path.join(support_root, "src", "support")) -target("pcsx.supportpsx") +target("pcsx.supportpsx", function() set_kind("static") add_packages("fmt", "zlib") @@ -26,5 +26,9 @@ target("pcsx.supportpsx") add_files( path.join(support_root, "third_party", "ucl", "src", "alloc.c"), - path.join(support_root, "third_party", "ucl", "src", "n2e_99.c") + path.join(support_root, "third_party", "ucl", "src", "n2e_99.c"), + path.join(support_root, "third_party", "iec-60908b", "*.c") ) + + remove_files("assembler.cc", "*lua.cc") +end) diff --git a/third_party/xmake-psx b/third_party/xmake-psx new file mode 160000 index 000000000..e68416791 --- /dev/null +++ b/third_party/xmake-psx @@ -0,0 +1 @@ +Subproject commit e6841679177921054c2a07b6f6e803943df5ff76 diff --git a/tools/authoring/xmake.lua b/tools/authoring/xmake.lua new file mode 100644 index 000000000..a3cf7e6e4 --- /dev/null +++ b/tools/authoring/xmake.lua @@ -0,0 +1,14 @@ +local support_root = path.join(os.scriptdir(), "..", "..") + +includes(path.join(support_root, "tools", "xmake")) + +common_rules() + +target("pcsx.authoring", function () + common_tool() + add_includedirs(path.join(support_root, "third_party", "ucl", "include")) +end) + +rule("pcsx.authoring.iso", function() + generic_conversion("pcsx.authoring", ".iso", "authoring") +end) diff --git a/tools/exe2iso/xmake.lua b/tools/exe2iso/xmake.lua new file mode 100644 index 000000000..d8f1e88bd --- /dev/null +++ b/tools/exe2iso/xmake.lua @@ -0,0 +1,11 @@ +local support_root = path.join(os.scriptdir(), "..", "..") + +includes(path.join(support_root, "tools", "xmake")) + +common_rules() + +target("pcsx.exe2iso", common_tool) + +rule("pcsx.exe2iso.iso", function() + generic_conversion("pcsx.exe2iso", ".iso", "iso conversion") +end) diff --git a/tools/ps1-packer/xmake.lua b/tools/ps1-packer/xmake.lua index 318036726..641082fff 100644 --- a/tools/ps1-packer/xmake.lua +++ b/tools/ps1-packer/xmake.lua @@ -1,47 +1,11 @@ local support_root = path.join(os.scriptdir(), "..", "..") -add_rules("mode.debug", "mode.release") +includes(path.join(support_root, "tools", "xmake")) -includes( - path.join(support_root, "src", "support"), - path.join(support_root, "src", "supportpsx") -) +common_rules() -add_requires("fmt", "zlib") -set_languages("c++26") +target("pcsx.ps1-packer", common_tool) -target("ps1-packer") - set_kind("binary") - - add_packages("fmt", "zlib") - add_deps("pcsx.support", "pcsx.supportpsx") - add_includedirs( - path.join(support_root, "src"), - path.join(support_root, "third_party") - ) - - add_files("*.cc") - -rule("ps1-packer.psexe") - set_extensions(".elf") - on_config(function(target) - local extension = target:values("psx.extension") - if extension == nil then - extension = ".psexe" - end - local targetdir = target:targetdir() - local targetname = target:basename() - local outfile = path.join(targetdir, targetname .. extension) - target:add("deps", "ps1-packer", {inherit = false}) - target:add("values", "ps1-packer.psexe.postlink.outfile", outfile) - target:add("values", "psexe", false) - end) - after_link(function(target) - local ps1packer = target:dep("ps1-packer") - local outfile = target:values("ps1-packer.psexe.postlink.outfile") - os.vrunv(ps1packer:targetfile(), {target:targetfile(), "-o", outfile}) - end) - on_clean(function(target) - local outfile = target:values("ps1-packer.psexe.postlink.outfile") - os.tryrm(outfile) - end) +rule("pcsx.ps1-packer.psexe", function() + generic_conversion("pcsx.ps1-packer", ".psexe", "psexe compression") +end) diff --git a/tools/xmake/xmake.lua b/tools/xmake/xmake.lua new file mode 100644 index 000000000..6e68f6fe2 --- /dev/null +++ b/tools/xmake/xmake.lua @@ -0,0 +1,99 @@ +local support_root = path.join(os.scriptdir(), "..", "..") + +function common_rules() + add_rules("mode.debug", "mode.release") + + includes( + path.join(support_root, "src", "support"), + path.join(support_root, "src", "supportpsx") + ) + + add_requires("fmt", "zlib") + set_languages("c++26") +end + +function common_tool() + set_kind("binary") + + add_packages("fmt", "zlib") + add_deps("pcsx.support", "pcsx.supportpsx") + add_includedirs( + path.join(support_root, "src"), + path.join(support_root, "third_party") + ) + + add_files("*.cc") +end + +local function get_binary_dep(target) + local deps = target:get("deps") + if type(deps) == "string" then deps = { deps } end + if not deps or #deps == 0 then + return nil, "target must have at least one dependency" + end + local binary = nil + for _, value in ipairs(deps) do + if type(value) == "string" then + local dep_target = target:dep(value) + if not dep_target then + return nil, "target dependency '" .. value .. "' does not exist" + end + if dep_target:get("kind") == "binary" and dep_target:get("plat") == "psx" and dep_target:get("arch") == "mipsel" then + if binary then + return nil, + "target can only have one binary dependency, found '" .. + binary:name() .. "' and '" .. dep_target:name() .. "'" + end + if dep_target:get("plat") ~= "psx" then + return nil, "target dependency '" .. dep_target:name() .. "' must be a psx target" + end + binary = dep_target + end + else + return nil, "target dependencies must be strings" + end + end + if not binary then + return nil, "target must have at least one binary dependency" + end + return binary +end + +function generic_conversion(tool, default_extension, conversion_name) + local tool_name = tool .. default_extension + on_load(function(target) + target:add("deps", tool, { inherit = false }) + target:set("kind", "binary") + target:set("plat", "psx") + target:set("arch", "mipsel") + local extension = target:get("extension") + if not extension then + target:set("extension", default_extension) + end + end) + before_config(function(target) + local binary, err = get_binary_dep(target) + if not binary then + raise(tool_name .. " target error: " .. err) + end + target:set("basename", binary:basename()) + end) + on_build(function(target) + import("core.project.depend") + + os.mkdir(target:targetdir()) + local binary, err = get_binary_dep(target) + if not binary then + raise(tool_name .. " target error: " .. err) + end + local opts = { + input = binary:targetfile(), + output = target:targetfile(), + } + depend.on_changed(function() + print(conversion_name .. " of %s to %s", opts.input, opts.output) + local tooldep = target:dep(tool) + os.vrunv(tooldep:targetfile(), { opts.input, "-o", opts.output }) + end, { files = opts.input }) + end) +end