開源專案
ran-j/PS2Recomp avatar
ran-j/PS2Recomp

ps2xIOP:PS2Recomp 中的 IOP 高階模擬子系統

此專案圍繞「ran-j/PS2Recomp」建置,面向真實業務場景,提供可重複使用、可持續維運的開源實作。

3,261 個 Star132 個 ForkC++GPL-3.0
GitHub

秒懂

它是什麼?
剖析 ps2xIOP,它透過 SIF RPC 和 DMA 為重新編譯的 PlayStation 2 遊戲提供 IOP 服務。
適合誰用?
ps2xIOP 是一個 C++20 靜態庫,實作重新編譯遊戲透過 SIF RPC 和 DMA 期望的 IOP 服務,但不模擬 IOP 的 CPU。它提供明確的 profile 系統、少量內建服務以及用於擴充 profile 目錄的可選原生插件 ABI。
可以商用嗎?
可以,但有條件。GPL-3.0 是 copyleft 授權:如果你散布包含它的軟體,就必須以同一授權公開該軟體的原始碼。只在內部執行、不對外散布,則不會觸發這項義務。
還在維護嗎?
有在維護。儲存庫最近一次提交在 2 天前。
用什麼語言寫的?
主要是 C++(依據 GitHub 的語言統計)。

以上回答依據專案的 GitHub 資料(最近同步於 2026年9月15日)與我們的分析,不構成法律意見。

開源專案深度解析

ps2xIOP 是什麼

ps2xIOP 是 PS2Recomp 專案中的一個子系統,具體由 ps2xRuntime 使用。它實作遊戲期望透過 SIF RPC 和 DMA 暴露的 IOP 服務行為。它不模擬 IOP 的 R3000A CPU,也不載入或執行 IRX 二進位檔案。其範圍僅限於重新編譯遊戲所需的 RPC/DMA 行為。該實作是一個名為 ps2_iop(也稱為 ps2x::iop)的 C++20 靜態庫,連結到執行時期。可選的 .dll 和 .so 檔案是由該庫載入的原生 profile 插件;它們擴充 profile 目錄,但不替換核心庫、註冊表、主機橋接或 SIF 傳輸。

針對 PS2Recomp,實際檢查應從 Ghidra 匯出的 ExportPS2Functions.java、TOML 與 CSV 對照開始,再用 ./ps2_recomp config.toml 產生 C++。若是去除符號的 ELF,需把 handler@0xADDRESS 的位址限定在同一個遊戲建置,不能把不同地區或版本的位址混用。編譯環境則以 CMake 3.20、C++20 與 SSE4/AVX 支援為前提。 第1項。這段內容只針對 ran-j-ps2recomp-deep-analysis 的檔案、命令與設定脈絡,需和前後文一起閱讀。

架構與核心服務

子系統位於 EE 遊戲和主機之間。執行時期傳輸將 RpcRequest、RpcResult 和 SifTransfer 物件傳遞給 IopSubsystem,後者透過選定的 profile 服務和核心服務路由它們,然後到達 IopHost 橋接,該橋接提供經過驗證的客戶機記憶體、檔案、音訊、記憶卡、日誌記錄和 EE 函式呼叫。定義了三層:模組實作是可重用的協定引擎,例如 TSNDDRV、CRI DTX、CLFILE 和 SDRDRV;綁定包含特定於建置的值,如 SID、EE 位址、回呼和客戶機 arena;profile 匹配一個遊戲建置,並使用該建置的綁定建立模組實作。內建核心服務始終啟動:MCSERV(SID 0x80000400、0x80000480)、LIBSD(0x80000701)和 DBCMAN(0x80001300)。目前內建三個遊戲 profile:recvx-us、lotr-two-towers-us 和 fatal-frame-us。所有內建匹配器僅宣告 ELF 基名;它們不約束進入點或 CRC32。基名匹配不區分大小寫。

針對 PS2Recomp,實際檢查應從 Ghidra 匯出的 ExportPS2Functions.java、TOML 與 CSV 對照開始,再用 ./ps2_recomp config.toml 產生 C++。若是去除符號的 ELF,需把 handler@0xADDRESS 的位址限定在同一個遊戲建置,不能把不同地區或版本的位址混用。編譯環境則以 CMake 3.20、C++20 與 SSE4/AVX 支援為前提。 第2項。這段內容只針對 ran-j-ps2recomp-deep-analysis 的檔案、命令與設定脈絡,需和前後文一起閱讀。

Profile 選擇

載入 ELF 時,執行時期計算一個 GameIdentity,由 ELF 基名、進入點和對完整 ELF 檔案計算的 CRC-32/IEEE(常見的 ZIP CRC-32)組成。profile 匹配器可以宣告這些欄位的任意組合。每個宣告的欄位都必須匹配。宣告欄位數最多的匹配器獲勝。如果兩個匹配的 profile 具有相同的特異性,則 loadELF() 失敗,而不是靜默選擇其中一個。同一服務層內重複的 SID 是錯誤。如果 profile 遮蔽了核心 SID 並返回 handled = 0,則子系統不會透過被遮蔽的核心服務進行第二次嘗試。

針對 PS2Recomp,實際檢查應從 Ghidra 匯出的 ExportPS2Functions.java、TOML 與 CSV 對照開始,再用 ./ps2_recomp config.toml 產生 C++。若是去除符號的 ELF,需把 handler@0xADDRESS 的位址限定在同一個遊戲建置,不能把不同地區或版本的位址混用。編譯環境則以 CMake 3.20、C++20 與 SSE4/AVX 支援為前提。 第3項。這段內容只針對 ran-j-ps2recomp-deep-analysis 的檔案、命令與設定脈絡,需和前後文一起閱讀。

排程與傳輸流程

IopSubsystem 暴露執行時期使用的五個操作。configure(GameIdentity) 選擇並建立活動 profile。reset() 重設核心和 profile 服務。selectRpcAbi(...) 允許服務在預設解碼器不足時選擇暫存器或堆疊 RPC 佈局。handleRpc(...) 按 SID 路由請求,並返回負載結果和傳輸策略。onSifTransfer(...) 在 SetDma 和 GetOtherData 複製之前和之後通知服務。RpcResult::handled 指示服務是否消費了請求。結果可以請求完成信號量信號,並可以抑制執行時期的預設 EE 回呼或註冊伺服器排程。傳輸執行這些操作;服務從不接觸執行時期內部。傳輸鉤子刻意保持通用。TSNDDRV 使用它進行相容性回填,CRI DTX 使用它觀察 DMA,但 SIF 傳輸不包含遊戲名稱、遊戲位址或針對這些模組的分支。RPC ABI 選擇在核心服務之前提供給每個活動 profile 服務,每個活動服務都接收每次 SIF 傳輸通知。實作必須自行過濾相關的 SID/函式或傳輸類型/階段/位址範圍。

針對 PS2Recomp,實際檢查應從 Ghidra 匯出的 ExportPS2Functions.java、TOML 與 CSV 對照開始,再用 ./ps2_recomp config.toml 產生 C++。若是去除符號的 ELF,需把 handler@0xADDRESS 的位址限定在同一個遊戲建置,不能把不同地區或版本的位址混用。編譯環境則以 CMake 3.20、C++20 與 SSE4/AVX 支援為前提。 第4項。這段內容只針對 ran-j-ps2recomp-deep-analysis 的檔案、命令與設定脈絡,需和前後文一起閱讀。

連結與整合

靜態庫透過 target_link_libraries(my_runtime PRIVATE ps2x::iop) 連結。公共 C++ API 宣告在 include/ps2x/iop/iop_subsystem.h 中。使用 PS2Runtime 的應用程式通常不直接建構子系統;執行時期建立它以及 IopHost 配接器。README 除 CMake 片段和標頭檔位置外,沒有給出更多整合範例。

針對 PS2Recomp,實際檢查應從 Ghidra 匯出的 ExportPS2Functions.java、TOML 與 CSV 對照開始,再用 ./ps2_recomp config.toml 產生 C++。若是去除符號的 ELF,需把 handler@0xADDRESS 的位址限定在同一個遊戲建置,不能把不同地區或版本的位址混用。編譯環境則以 CMake 3.20、C++20 與 SSE4/AVX 支援為前提。 第5項。這段內容只針對 ran-j-ps2recomp-deep-analysis 的檔案、命令與設定脈絡,需和前後文一起閱讀。

動態 profile 插件

動態 profile 插件是可選的,預設停用。在 Windows 或 Linux 上使用 PS2X_IOP_ENABLE_PLUGINS=ON 啟用。支援的格式是 Windows 上的 .dll 和 Linux 上的 .so。預設情況下,執行時期掃描可執行檔旁邊的 iop_plugins/ 目錄,非遞迴。嵌入應用程式可以在呼叫 initialize() 之前替換搜尋目錄。每個原生模組可以發佈一個或多個 profile。缺失查詢符號、不相容的 ABI 版本、格式錯誤的描述符和不支援的模組會被忽略並附帶診斷資訊。profile 歧義、活動層 SID 衝突或建立所選 profile 失敗會使 loadELF() 失敗並產生明確錯誤。v1 載入器每個插件最多接受 256 個 profile,每個 profile 最多 256 個 SID。profile 需要非空 ID、至少一個匹配欄位、至少一個 SID,以及有效的 create、destroy、reset 和 handle_rpc 回呼。插件 ABI 在 plugin_api.h 中定義,並匯出一個 C 進入點 ps2x_iop_query_v1。它使用固定的 C 函式表和 POD 資料,對指標生命週期有限制,並且不允許 STL 型別跨越邊界。README 指向 PluginExample.md 了解更多資訊。

診斷、測試與授權

debugSnapshot() 暴露活動 profile、其提供者、註冊的核心和 profile 服務、服務指標、載入器診斷和最後的選擇錯誤。執行時期偵錯器在 IOP/SIF 索引標籤中渲染這些資料。註冊表行為、實例隔離、重設、內建服務、profile 優先級、插件發現、ABI 拒絕、歧義、排程、銷毀和模組生命週期由 ps2_iop_tests.cpp 覆蓋。專案採用 GPL-3.0 授權。授權文字授予複製、分發和修改軟體的權利,並要求修改版本必須標記為已更改。它還宣告沒有保固。授權未涉及安全狀況、支援或特定效能保證。

編輯結論

ps2xIOP 是一個 C++20 靜態庫,實作重新編譯遊戲透過 SIF RPC 和 DMA 期望的 IOP 服務,但不模擬 IOP 的 CPU。它提供明確的 profile 系統、少量內建服務以及用於擴充 profile 目錄的可選原生插件 ABI。該專案採用 GPL-3.0 授權。 適合能接受上述環境與維護責任的使用者,不適合需要未記載保證或即裝即用流程的場景;先從專案指定入口驗證核心流程。

官方來源

  1. Official README
  2. Project repository
  3. Release notes
社群筆記

社群筆記