Editing PSP Emulation
Jump to navigation
Jump to search
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
=='''PSPHD'''== | |||
The new ps plus psp emulator has a lot of undiscovered functionalities, it even allows patches directly to the emulated Allegrex cpu. | |||
Sadly sony has not made it easy for users to use CLI commands because sony mostly uses lua patches for the psp releases, thus, not many cli commands were needed to be added. Very few commands have a description to their usage inside of the eboot.bin, everything else is just guesswork from the scene. The psp emulator has not gained the same popularity as the ps2 emulator because currently, there is an unofficial PPSSPP core in the unofficial retroarch port for the ps4. and as far as the compatibility and performance goes, the retroarch core is second to no one. This emulator may still hold potential, though sadly it does not seem to have support for gamedata installation and that has led to render many games unplayable. | |||
== '''PSPHD''' == | |||
The | |||
== Commands == | == Commands == | ||
'''Known functions:''' Require cleanup. | '''Known functions:''' Require cleanup. | ||
<br>The rest of the cli and lua commands can all be found inside of an emu's decrypted '''eboot.bin'''. | |||
<br>The rest of the | |||
=== CLI commands === | === CLI commands === | ||
These commands can be added to any of these files: | These commands can be added to any of these files: | ||
Line 157: | Line 94: | ||
|- | |- | ||
|-style="background-color:#7698FF" | |-style="background-color:#7698FF" | ||
| || Speedhacks | | || Speedhacks || || | ||
|- | |- | ||
| --antialias || off || Turning Anti-Alias Off Improves Performance||--antialias=off | | --antialias || off || Turning Anti-Alias Off Improves Performance||--antialias=off | ||
Line 177: | Line 114: | ||
| --texrecent || true || Optimize texture hashes ||--texrecent=true | | --texrecent || true || Optimize texture hashes ||--texrecent=true | ||
|} | |} | ||
==== | |||
====Texture replacement==== | |||
{| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | {| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | ||
! Command !! Values !! Notes !! Usage | ! Command !! Values !! Notes !! Usage | ||
|- | |- | ||
| -- | | --texswitch||true, false|| Enables Texture replacement || --texswitch=true | ||
|- | |- | ||
| -- | | --texsave || || || | ||
|- | |- | ||
| -- | | --texmissingsave || || || | ||
|- | |- | ||
| -- | | --autoresampler || true, false|| Turns on the auto-resampler. Assumes textures in texreplace are at 8x resolution and resamples them at load, May only work on new LocoRoco Midnight Carnival emu || --autoresampler=true | ||
|- | |- | ||
| -- | | --texreplace || Directory || Set directory of texture replacement folder || --texreplace="host0:texreplace" | ||
|- | |- | ||
| -- | | --replacementfilter || true, false || This forces alpha blending to on for replaced textures. || --replacementfilter=true | ||
|- | |- | ||
| -- | | --replacementalpha || true, false || || --replacementalpha=true | ||
|- | |- | ||
| -- | |} | ||
===XXXXYYYYY_patches.lua=== | |||
Your lua can be placed as '''scripts\XXXXYYYYY_patches.lua''' | |||
<br>'''Requires Cleanup'''. | |||
====Emulator commands==== | |||
{| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | |||
! Command !! Usage !! Notes - Example | |||
|- | |- | ||
| | |getEmuObject || '''local emuObj = getEmuObject()''' || Required for all functions using emuObj | ||
|- | |- | ||
| | |LoadSlideshow ||emuObj.LoadSlideshow()|| | ||
|- | |- | ||
| | |StartSlideshow ||emuObj.StartSlideshow()|| | ||
|- | |- | ||
| | |Log ||emuObj.Log()|| | ||
|- | |- | ||
| | | GetLanguage ||emuObj.GetLanguage()|| Get the language the ps4 is using | ||
|- | |- | ||
| | | GetNativeLanguage ||emuObj.GetNativeLanguage()|| | ||
|- | |- | ||
| | |DisplayManual || emuObj.DisplayManual()|| | ||
|- | |- | ||
| | | DisplayProduct||emuObj.DisplayProduct()|| | ||
|- | |- | ||
| | |LoadConfig ||emuObj.LoadConfig()|| | ||
|- | |- | ||
| | | SaveConfig||emuObj.SaveConfig()|| | ||
|- | |- | ||
| | | LoadMIDI ||emuObj.LoadMIDI()|| | ||
|- | |- | ||
| | | GetMIDINotesAtTick ||emuObj.GetMIDINotesAtTick()|| | ||
|- | |- | ||
| | |LoadState ||emuObj.LoadState()|| | ||
|- | |- | ||
| | | SaveState ||emuObj.SaveState()|| | ||
|- | |- | ||
| | | SetFDExtraDelay ||emuObj.SetFDExtraDelay()|| 0? 1? | ||
|- | |- | ||
| | | MeshSmooth ||emuObj.MeshSmooth()|| | ||
|- | |- | ||
| | | SetHue ||emuObj.SetHue()|| | ||
|- | |- | ||
| | | SetSaturation ||emuObj.SetSaturation()|| | ||
|- | |- | ||
| | | SetBrightness ||emuObj.SetBrightness()|| | ||
|- | |- | ||
| | | SetContrast ||emuObj.SetContrast()|| | ||
|- | |- | ||
| | | VideoScale ||emuObj.VideoScale()|| | ||
|- | |- | ||
| | | SetOverlay ||emuObj.SetOverlay()|| | ||
|- | |- | ||
| | | DisplayUIOverlay ||emuObj.DisplayUIOverlay()|| | ||
|- | |- | ||
| | | CRC32 ||emuObj.CRC32()|| | ||
|- | |- | ||
| | | SASGetCRC ||emuObj.SASGetCRC()|| | ||
|- | |- | ||
| | | SASGetSampleRate ||emuObj.SASGetSampleRate() | ||
|- | |- | ||
| | | GetAppName ||emuObj.GetAppName()|| | ||
|- | |- | ||
| | | ReadFile ||emuObj.ReadFile()|| | ||
|- | |- | ||
| | | RemapFB ||emuObj.RemapFB()|| | ||
|- | |- | ||
| | | InvalFB ||emuObj.InvalFB()|| | ||
|- | |- | ||
| | | PlayVideo||emuObj.PlayVideo()|| | ||
|- | |- | ||
| | | RescaleUForUpscale ||emuObj.RescaleUForUpscale()|| | ||
|- | |- | ||
| | | RescaleVForUpscale||emuObj.RescaleVForUpscale()|| | ||
|- | |- | ||
| | | ShrinkUVRect ||emuObj.ShrinkUVRect()|| | ||
|- | |- | ||
| | | ScalePosition ||emuObj.ScalePosition()|| | ||
|- | |- | ||
| | | AdjustUVJitter ||emuObj.AdjustUVJitter()|| | ||
|- | |- | ||
| | | OverrideFBSize||emuObj.OverrideFBSize()|| Override framebuffer size ? | ||
|- | |- | ||
| | |RemapSavedata || emuObj.RemapSavedata() ||emuObj.RemapSavedata("UCUS98711", "CUSA06171", "504e802b04a1838c32b616abbe0b475fbea1c823825ef0df06cc2bad129ce2f7") | ||
|- | |- | ||
| | | NeoMode || emuObj.NeoMode() || Checks whether or not the ps4 is pro | ||
|- | |- | ||
| | | ThrottleMax || emuObj.ThrottleMax() || Disable framelimiter during loading screens. This setting can sometimes be harmful when used globally in config files. Loading times are faster, but the game also runs faster than it should when the PS4 has enough free cpu power. | ||
|- | |- | ||
| | | ThrottleFast|| emuObj.ThrottleFast() || Faster than default, but exact value is unknown. | ||
|- | |- | ||
| | | ThrottleNorm ||emuObj.ThrottleNorm() || Enable default framelimiter (50/60 fps depend on region) | ||
|- | |- | ||
| | |SetTextureHashMode||emuObj.SetTextureHashMode()|| | ||
|- | |- | ||
| | |SetTextureScaleOffset||emuObj.SetTextureScaleOffset()|| | ||
|- | |- | ||
| | |SetTextureSaveSubdir||emuObj.SetTextureSaveSubdir()|| | ||
|- | |- | ||
| | | SetDrawEDRam || emuObj.SetDrawEDRam() || | ||
|- | |- | ||
| | |SetSampleTitle||emuObj.SetSampleTitle()|| | ||
|- | |- | ||
| | |ToggleTextures||emuObj.ToggleTextures()|| | ||
|- | |- | ||
| | | CopyFB || emuObj.CopyFB() || | ||
|-style="background-color:#c6ecd9" | |||
| Hooks || || | |||
|- | |- | ||
| | | AddVsyncHook ||emuObj.AddVsyncHook()|| Set function to be done on every vsync | ||
|- | |- | ||
| | | RemoveVsyncHook ||emuObj.RemoveVsyncHook()|| Remove vsynchook | ||
|- | |- | ||
| | | AddBootHook ||emuObj.AddBootHook()|| Set function to be done when the game boots up | ||
|- | |- | ||
| | |RemoveBootHook||emuObj.RemoveBootHook()|| remove function to be done when the game boots up | ||
|- | |- | ||
| | | AddGPUHook ||emuObj.AddGPUHook()|| | ||
|- | |- | ||
| | |-style="background-color:#D7EF54" | ||
| Pad || || | |||
|- | |- | ||
| | | Pad require ||'''local pad = require("pad")''' || Required for all commands that rely on pad | ||
|- | |- | ||
| | |PadRead || emuObj.PadRead() || | ||
<br>L3 = 0x00000002 | |||
<br>R3 = 0x00000004 | |||
<br>OPTIONS = 0x00000008 | |||
<br>UP = 0x00000010 | |||
<br>RIGHT = 0x00000020 | |||
<br>DOWN = 0x00000040 | |||
<br>LEFT = 0x00000080 | |||
<br>L2 = 0x00000100 | |||
<br>R2 = 0x00000200 | |||
<br>L1 = 0x00000400 | |||
<br>R1 = 0x00000800 | |||
<br>TRIANGLE = 0x00001000 | |||
<br>CIRCLE = 0x00002000 | |||
<br>CROSS = 0x00004000 | |||
<br>SQUARE = 0x00008000 | |||
<br>SELECT = 0x00010000 | |||
<br>START = 0x00020000 | |||
|- | |- | ||
| | |PadReadPitch || emuObj.PadReadPitch() || | ||
|- | |- | ||
| | |PadReadRoll || emuObj.PadReadRoll()|| | ||
|- | |- | ||
| | |PadRegisterSamples || emuObj.PadRegisterSamples()|| | ||
|- | |- | ||
| | | PadSetButtonsMode || emuObj.PadSetButtonsMode() || | ||
<br>0 = Touch bar is split in two for Start/Select. Option is unmapped (default behaviour) | |||
<br>1 = Touch bar is Start. Option is Select | |||
<br>2 = Touch bar is Select. Option is Start | |||
|- | |- | ||
| | | PadVibrate|| emuObj.PadVibrate() || emuObj.PadVibrate(5,180,180) | ||
|- | |- | ||
| | |} | ||
====Allegrex commands==== | |||
{| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | |||
! Command !! Usage !! Notes - Example | |||
|- | |- | ||
| | | getAXObject ||'''local axObj = getAXObject()''' || Required for all functions using AXObject | ||
|- | |- | ||
| | | AddHook || axObj.AddHook() || | ||
|- | |- | ||
| | | RemoveHook || axObj.RemoveHook() || | ||
|- | |- | ||
| | | BurnCycles|| axobj.BurnCycles() || Could be an option to overclock cpu at a hooked offset | ||
|- | |- | ||
| | |AddAOTBlock ||axObj.AddAOTBlock()|| Ahead of time compilation block ? | ||
|- | |- | ||
| | |Overlay ||axObj.Overlay()|| | ||
|-style="background-color:#ff8080" | |||
| GPR || || | |||
|- | |- | ||
| | | gpr require || '''local gpr = require("ax-gpr-alias")''' || Required for any command that includes gpr registers | ||
|- | |- | ||
| | |SetPC|| axObj.SetPC() || | ||
|- | |- | ||
| | |GetPC|| axObj.GetPC() || | ||
|- | |- | ||
| | | GetGpr || axObj.GetGpr() || | ||
|- | |- | ||
| | | SetGpr ||axObj.SetGpr() || | ||
|- | |- | ||
| | |SetFpr|| axObj.SetFpr() ||axObj.SetFpr(0) | ||
|- | |- | ||
| | |GetFpr || axObj.GetFpr() || | ||
|- | |- | ||
| | |SetHi|| axObj.SetHi()|| | ||
|- | |- | ||
| | |GetHi|| axObj.GetHi()|| | ||
|- | |- | ||
| | | SetLo || axObj.SetLo()|| | ||
|- | |- | ||
| | | GetLo ||axObj.GetLo()|| | ||
|- | |||
| SetReg||axObj.SetReg()|| | |||
|- | |- | ||
| | |GetReg||axObj.GetReg()|| | ||
|-style="background-color:#D7EF54" | |||
| Memory editing || || Do note that the offsets on PPSSPP are different than the ones on the PS4 | |||
|- | |- | ||
| | | ReadMem32 || axObj.ReadMem32() || Read 4 bytes from offset | ||
|- | |- | ||
| | | WriteMem32 || axObj.WriteMem32() || Write 4 bytes to offset | ||
|- | |- | ||
| | | ReadMem16 || axObj.ReadMem16() || Read 2 bytes from offset | ||
|- | |- | ||
| | | WriteMem16 || axObj.WriteMem16() || Write 2 bytes to offset | ||
|- | |- | ||
| | | ReadMem8 || axObj.ReadMem8() || Read 1 byte from offset | ||
|- | |- | ||
| | | WriteMem8 || axObj.WriteMem8() || Write 1 byte to offset | ||
|- | |- | ||
| | | ReadMemString || axObj.ReadMemString() || | ||
|- | |- | ||
| | | WriteMemString || axObj.WriteMemString() || | ||
|- | |- | ||
| | | WriteMemStr16 || axObj.WriteMemStr16() || | ||
|- | |- | ||
| | |WriteMemStr16Z ||axObj.WriteMemStr16Z() || | ||
|- | |- | ||
| | | WriteMemStringZ ||axobj.WriteMemStringZ || | ||
|- | |- | ||
| | |ReadMemFloat || axObj.ReadMemFloat() || | ||
|- | |- | ||
| | |WriteMemFloat || axObj.WriteMemFloat() || | ||
|- | |- | ||
! !! Other/Unknown/Standalone Commands !! | |||
|- | |- | ||
| | |FuncReplace || axFuncReplace() || axFuncReplace(0x8804670, "__ptmf_scall") Replace allegrex function. | ||
|- | |- | ||
| | | InsnReplace || axInsnReplace() || Replace allegrex memory | ||
|- | |- | ||
| | |} | ||
====Examples==== | |||
<br>'''''LUA example:''''' | |||
<br> | |||
<br>Coconut Dodge "NPEZ00164" | |||
<pre> | |||
local axObj = getAXObject() | |||
local emuObj = getEmuObject() | |||
local patcher = function() | |||
--Infinite lives | |||
axObj.WriteMem32(0x8ACA1A4, 0x3) --0x08ACE1A4 on PPSSPP, PPSSPP addresses need to be reduced by 0x4000 in order to work on PS4 | |||
end | |||
emuObj.AddVsyncHook(patcher) | |||
</pre> | |||
[https://www.psdevwiki.com/ps4/Talk:PSP_Emulator_Compatibility_List#Official_PSPemu_Configuration_Files More patches can be found here] | |||
=====Patches.lua===== | |||
'''An official lua created by sony for Patapon 2''' | |||
<pre> | |||
-- Lua 5.3 | |||
-- Title: Patapon 2 PSP - UCUS-98732 (USA) | |||
apiRequest(1.0) -- request version 1.0 API. Calling apiRequest() is mandatory. | |||
local gpr = require( "ax-gpr-alias" ) -- you can access Allegrex GPR by alias (gpr.a0 / gpr["a0"]) | |||
local emuObj = getEmuObject() -- emulator | |||
local axObj = getAXObject() -- allegrex | |||
local pad = require("pad") | |||
-- Hook memcpy to catch framebuffer effects | |||
axFuncReplace(0x881D194, "patapon_memcpy") | |||
-- Accelerate some functions | |||
axFuncReplace(0x8804670, "__ptmf_scall") | |||
axFuncReplace(0x8892230, "Renderer__makeWorldMatrix__4psysFv") | |||
axFuncReplace(0x88209A8, "patapon_strcmp") | |||
axFuncReplace(0x8815130, "sceGupSetStatus") | |||
axFuncReplace(0x8851D84, "FMtx44__setRow__3PydFv") | |||
axFuncReplace(0x88437F0, "Script__Talk__Controller__setDeltaTime__3PydFv") | |||
axFuncReplace(0x8843B6C, "Script__Talk__Controller__setCmdId__3PydFv") | |||
axFuncReplace(0x88441DC, "Script__Talk__Controller__getArgValuePtr__3PydFv_0") | |||
axFuncReplace(0x89B25B0, "sceGmoCol4Multiply") | |||
axFuncReplace(0x8910A60, "Gfx__CacheModel__getNodeMtx__6SystemFv") | |||
axFuncReplace(0x8911440, "Gfx__StaticGmoModel__getNodeIdx__6SystemFv") | |||
axFuncReplace(0x89114C8, "Gfx__StaticGmoModel__getNodeMtx__6SystemFv") | |||
axFuncReplace(0x891157C, "Gfx__StaticGmoModel__getNodeMtx__6SystemFv_0") | |||
-- | axFuncReplace(0x881462C, "sceGuEnable", 0x8B3C050) -- param = gupbase pointer | ||
axFuncReplace(0x8814684, "sceGuDisable", 0x8B3C050) -- param = gupbase pointer | |||
axFuncReplace(0x89B2D84, "sceGmoFCurveEval_fastpath", 0x89B2D88) -- param = function entry if not fast path | |||
--axFuncReplace(0x88D0788, "Game__Map__Weather__WindLocus__update__4LaboFv_loop", 0x88D0864) -- param = continue address | |||
axFuncReplace(0x890FCBC, "convertLowerString__6SystemFv") | |||
axFuncReplace(0x8877104, "convertLowerString__6SystemFv") -- convertLowerString__21@unnamed@BNDFile_cpp@Fv, same functionality | |||
axFuncReplace(0x897927C, "__extendsfdf2") | |||
axFuncReplace(0x8979AF8, "__muldf3") | |||
axFuncReplace(0x8979A8C, "__adddf3") | |||
axFuncReplace(0x897A750, "__truncdfsf2") | |||
axFuncReplace(0x88CBD64, "RemapPacket", 0x8ACC394) -- param comes from RemapPacketAddr24 & RemapPacketAddr16 | |||
axFuncReplace(0x890FEA0, "patapon_strcmp") -- strcmpFast__6SystemFv ('fast' strcmp) | |||
-- Switch Select command to "Options" button. | |||
emuObj.PadSetButtonsMode(pad.BUTTONS_MODE_OPTION_IS_SELECT) | |||
-- Remove "Transfer Patapon Saved Data" option from New Game option | |||
--axInsnReplace(0x8A46660, 0x24070002, 0x24070001) -- li a3,0x2 (change 2 menu options to 1) | |||
emuObj.RemapSavedata("UCUS98711", "CUSA06171", "504e802b04a1838c32b616abbe0b475fbea1c823825ef0df06cc2bad129ce2f7") | |||
-- Fix "Tree of Life" unaligned lines and shadows | |||
axObj.AddHook(0x884600C, 0x8c850010, function() -- PSP::Gfx::PrimitiveContext::setVertex2f | |||
local context = axObj.GetGpr(gpr.a0) | |||
local cmdCount = axObj.ReadMem32(context + 0x14) | |||
if (cmdCount & 1) == 1 then -- we have at least 2 commands | |||
local cmdBuffer = axObj.ReadMem32(context + 0x10) | |||
local cx = axObj.GetFpr(12) | |||
local cy = axObj.GetFpr(13) | |||
local ox = axObj.ReadMemFloat(cmdBuffer-12) | |||
local oy = axObj.ReadMemFloat(cmdBuffer-8) | |||
if cx == ox then | |||
axObj.SetFpr(12, cx + 0.5) | |||
axObj.WriteMemFloat(cmdBuffer-12, ox + 0.5) | |||
elseif cy == oy then | |||
axObj.SetFpr(13, cy + 0.5) | |||
axObj.WriteMemFloat(cmdBuffer-8, oy + 0.5) | |||
function | |||
local | |||
local | |||
end | end | ||
end | end | ||
end | end) | ||
-- LANGUAGES -- | |||
-- | local langCode = "us" -- default | ||
--local languageList = {"Japanese","English","UK","Italian","German","Spanish","French","Korean","Chinese","ns","nf","Dutch","Portuguese","gr","Belgium"} | |||
--local gameLanguageCode = {"jp","us","uk","it","de","sp","fr","kr","cn","ns","nf","nl","pt","gr","be"} | |||
local languageList = {"","English","","","","","","","","Spanish","French","","","",""} | |||
local gameLanguageCode = {"","us","","","","","","","","ns","nf","","","",""} | |||
= | |||
-- US: english = 1, spanish = 9, french = 0xA (from Localize__Manager__setDefaultLangage) | |||
-- | -- EU: uk = 2, italian = 3, german = 4, spanish = 5, french = 6 | ||
-- | -- JP: jp = 0 | ||
-- HP: ko = 7, ch = 8, | |||
-- GLOBAL FUNCTIONS -- | |||
local GLOBAL = 0x8B7D088 -- reawakeDeathUnit - offset 0x88A95E8 in $v1 | |||
function getGlobalAddr() -- gets Global to user data. | |||
local | -- address comes from: Labo::Bases::Camp::Controller::reawakeDeathUnit - offset 0x88A95E8 in $v1 | ||
local axObj | -- add 0x20 to address to align it with the word "none" | ||
local main = axObj.ReadMem32(GLOBAL) -- fixed Global address from: 0x88A95E8 -> 0x8c9fbc0 | |||
if main == 0xFFFFFFFF or main == 0 then | |||
return 0xFFFFFFFF | |||
end | |||
local ptr = axObj.ReadMem32(main + 0x10c0) --> sets to: 0x8d07840 | |||
if ptr == 0xFFFFFFFF or ptr == 0 then | |||
return 0xFFFFFFFF | |||
end | |||
return ptr | |||
end | |||
-- | -- MAIN FUNCTIONS -- | ||
-- | local H1 = function() -- Labo::Bases::Camp::Scene::updateTips | ||
emuObj. | local v0 = axObj.GetGpr(gpr.v0) | ||
if v0 > 0 then | |||
emuObj.ThrottleMax() | |||
else | |||
emuObj.ThrottleNormal() | |||
end | |||
end | |||
local H2 = function() -- GameSystem__SaveDataController__setStateMessage | |||
local ptr = axObj.GetGpr(gpr.a2) | |||
local str = axObj.ReadMemStr16(ptr) | |||
local newStr = "Now loading. Do not turn off the power." | |||
-- english: Now loading./Do not remove the Memory Stick Duo™ /or turn off the system power. | |||
-- spanish: Cargando./No extraigas el Memory Stick Duo™ /ni apagues el sistema. | |||
local | -- french: Chargement./Ne pas retirer le Memory Stick Duo™ /ou éteindre le système. | ||
local | -- italian: Caricamento in corso.../Non rimuovere il Memory Stick Duo™ /e non spegnere il sistema. | ||
-- german: Lädt./Bitte den Memory Stick Duo™ nicht entfernen /und das System nicht ausschalten. | |||
-- japanese: システムデータをロード中です。/Memory Stick Duo™を抜き挿ししたり、/電源を切ったりしないでください。 | |||
-- chinese: 系統資料載入中。/請勿插拔Memory Stick Duo™/或是關閉主機的電源。 | |||
-- korean: 시스템 데이터를 불러오는 중입니다./Memory Stick Duo™를 빼거나/전원을 끄지 마십시오. | |||
-- | |||
-- | |||
-- | |||
-- | |||
if string.find(str, "Now loading") then | |||
newStr = "Now loading." -- English: Now loading./Do not remove the Memory Stick Duo™ /or turn off the system power. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
elseif string.find(str, "Checking Memory Stick") then | |||
newStr = "Please wait." -- English: Checking Memory Stick Duo™. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
elseif string.find(str, "Now saving")then | |||
newStr = "Now saving." -- English: Now saving./Do not remove the Memory Stick Duo™ /or turn off the system power. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
-- | |||
elseif string.find(str, "Cargando.") then | |||
newStr = "Cargando..." -- Spanish: Cargando./No extraigas el Memory Stick Duo™ /ni apagues el sistema. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
elseif string.find(str, "Guardando...")then | |||
newStr = "Espera..." -- Spanish: Guardando.../No extraigas el Memory Stick Duo™ /ni apagues el sistema. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
elseif string.find(str, "Comprobando el Memory Stick") then | |||
newStr = "Guardando..." -- Spanish: Comprobando el Memory Stick Duo™. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
-- | |||
elseif string.find(str, "Chargement.") then | |||
newStr = "Chargement." -- French: Chargement./Ne pas retirer le Memory Stick Duo™ /ou éteindre le système. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
elseif string.find(str, "Vérification du Memory Stick")then | |||
newStr = "Veuillez patienter." -- French: Vérification du Memory Stick Duo™. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
elseif string.find(str, "Sauvegarde.") then | |||
newStr = "Sauvegarde en cours." -- French: Sauvegarde./Ne pas retirer le Memory Stick Duo™ /ou éteindre le système. | |||
axObj.WriteMemStr16Z(ptr, newStr) | |||
-- | |||
elseif string.find(str, "Caricamento in corso") then | |||
newStr = "Caricamento in corso." -- Italian: Caricamento in corso.../Non rimuovere il Memory Stick Duo™ /e non spegnere il sistema. | |||
-- | |||
-- | |||
-- | |||
-- | |||
-- | |||
newStr = " | |||
axObj.WriteMemStr16Z(ptr, newStr) | axObj.WriteMemStr16Z(ptr, newStr) | ||
elseif string.find(str, " | elseif string.find(str, "Controllo del Memory Stick")then | ||
newStr = " | newStr = "Attendi." -- Italian: Controllo del Memory Stick Duo™. | ||
axObj.WriteMemStr16Z(ptr, newStr) | axObj.WriteMemStr16Z(ptr, newStr) | ||
elseif string.find(str, " | elseif string.find(str, "Salvataggio in corso") then | ||
newStr = " | newStr = "Salvataggio in corso." -- Italian: Salvataggio in corso.../Non rimuovere il Memory Stick Duo™ /e non spegnere il sistema. | ||
axObj.WriteMemStr16Z(ptr, newStr) | axObj.WriteMemStr16Z(ptr, newStr) | ||
-- | -- | ||
elseif string.find(str, " | elseif string.find(str, "Lädt") then | ||
newStr = " | newStr = "Lädt." -- German: Lädt./Bitte den Memory Stick Duo™ nicht entfernen /und das System nicht ausschalten. | ||
axObj.WriteMemStr16Z(ptr, newStr) | axObj.WriteMemStr16Z(ptr, newStr) | ||
elseif string.find(str, "Memory Stick Duo™ wird überprüft")then | |||
elseif string.find(str, "Memory Stick Duo™ wird überprüft")then | |||
newStr = "Bitte warten." -- German: Memory Stick Duo™ wird überprüft. | newStr = "Bitte warten." -- German: Memory Stick Duo™ wird überprüft. | ||
axObj.WriteMemStr16Z(ptr, newStr) | axObj.WriteMemStr16Z(ptr, newStr) | ||
Line 997: | Line 796: | ||
== Emulators == | == Emulators == | ||
<pre>Every emulator is programmed in a different way, sometimes choosing the right emulator is the only possible way to fix a game. Emulators are not provided pre-installed on the ps4, they have to be unpacked from a backup that's downloaded from the ps store from that specific game. this list includes The typical usage of some of The emulators.</pre> | |||
{| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | {| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | ||
! Emulator !! Usage !! API Version !! Similar emulators (compatibility) | ! Emulator !! Usage !! API Version !! Similar emulators (compatibility) | ||
|- | |- | ||
| Echochrome || The default | | Echochrome || The default psp emulator for PSPFPKG tool at the time of writing and the best in terms of compatibility. || ? || ? | ||
|- | |- | ||
| | | LocoRoco Midnight Carnival || ? || ? || ? | ||
|- | |- | ||
| | | LocoRoco 1 || ? || ? || ? | ||
|- | |- | ||
| | | LocoRoco 2 || ? || ? || ? | ||
|- | |- | ||
| | | Castlevania Requiem || ? || ? || ? | ||
|- | |- | ||
| | | Patapon 2 || ? || ? || ? | ||
|- | |- | ||
| PaRappa the Rapper || An unofficial emulator developed by | | PaRappa the Rapper || An unofficial emulator developed by sony with very bad compatibility || ? || ? | ||
|- | |- | ||
|} | |} | ||
== Memory mapping == | ==Memory mapping== | ||
<br>'''Note''': The memory on PPSSPP is 0x4000 offsets ahead of the memory on the PS4 | <br>'''Note''': The memory on PPSSPP is 0x4000 offsets ahead of the memory on the PS4 | ||
{| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | {| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | ||
! Size !! Offset From -> Offset To !! Name | ! Size !! Offset From -> Offset To !! Name | ||
|- | |- | ||
| || 1008000000 -> 10887FFFFF || | | || 1008000000 -> 10887FFFFF || || Allegrex memory(?) | ||
|- | |- | ||
|640.00MB || 228200000 -> 250200000 || | |640.00MB || 228200000 -> 250200000 || | ||
Line 1,052: | Line 843: | ||
===Registers map=== | ===Registers map=== | ||
<br>Registers that are marked with '''(?)''' are untested but should be accurate. | <br>Registers that are marked with '''(?)''' are untested but should be accurate. | ||
<br>*'''Note''': The offsets' positions change as the CLI file's content increases, but the offsets should still be somewhere nearby the offsets | <br>*'''Note''': The offsets' positions change as the CLI file's content increases, but the offsets should still be somewhere nearby the offsets below and the layout should be the same regardless. | ||
{| class=wikitable style="border: none; background: none;" | {| class=wikitable style="border: none; background: none;" | ||
! scope=col | GPR | ! scope=col | GPR | ||
Line 1,138: | Line 929: | ||
|- | |- | ||
|} | |} | ||
'''VFPU''' | '''VFPU''' | ||
{| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | {| cellspacing="0" cellpadding="2" border="1" class="wikitable" style="text-align: center;" | ||
Line 1,219: | Line 1,003: | ||
! Issue !! Games affected !! Solution !! Description | ! Issue !! Games affected !! Solution !! Description | ||
|- | |- | ||
| | | Lack of ability to install gamedata (?)|| || || | ||
|- | |- | ||
|} | |} | ||
= | =LUA include files= | ||
<br>Files that need to be placed in the '''/lua_include/''' folder | <br>Files that need to be placed in the '''/lua_include/''' folder | ||
''' | '''ax-gpr-alias.lua''' | ||
<pre> | <pre> | ||
-- Recommended method to import this module: | |||
-- local gpr = require("ax-gpr-alias") | |||
gpr = {} | |||
gpr.zero = 0 | |||
gpr.at = 1 | |||
gpr.v0 = 2 | |||
gpr.v1 = 3 | |||
gpr.a0 = 4 | |||
gpr.a1 = 5 | |||
gpr.a2 = 6 | |||
gpr.a3 = 7 | |||
gpr.t0 = 8 | |||
gpr.t1 = 9 | |||
gpr.t2 = 10 | |||
gpr.t3 = 11 | |||
gpr.t4 = 12 | |||
gpr.t5 = 13 | |||
gpr.t6 = 14 | |||
gpr.t7 = 15 | |||
gpr.s0 = 16 | |||
gpr.s1 = 17 | |||
gpr.s2 = 18 | |||
gpr.s3 = 19 | |||
gpr.s4 = 20 | |||
gpr.s5 = 21 | |||
gpr.s6 = 22 | |||
gpr.s7 = 23 | |||
gpr.t8 = 24 | |||
gpr.t9 = 25 | |||
gpr.k0 = 26 | |||
gpr.k1 = 27 | |||
gpr.gp = 28 | |||
gpr.sp = 29 | |||
gpr.fp = 30 | |||
gpr.ra = 31 | |||
return gpr | |||
</pre> | |||
'''multiapp.lua''' | |||
<pre> | |||
-- Recommended method to import this module: | |||
-- local mapp = require("mapp") | |||
-- | |||
-- Multi-application support module | |||
-- Wraps common hook calls to support multiple executables | |||
-- | |||
local emuObj = getEmuObject() -- emulator | |||
local axObj = getAXObject() -- allegrex | |||
mapp = {} | |||
mapp.curAppName = emuObj.GetAppName() | |||
mapp.AddBootHook = function(app, func) | |||
if | if mapp[app] == nil then | ||
mapp[app] = {} | |||
end | end | ||
mapp[app].boot = func | |||
end | end | ||
mapp.AddHook = function(app, pc, verify, func) | |||
if mapp[app] == nil then | |||
mapp[app] = {} | |||
if | |||
end | end | ||
if mapp[app].hooks == nil then | |||
mapp[app].hooks = {} | |||
mapp[app].hookids = 1 | |||
end | end | ||
local localid = mapp[app].hookids | |||
mapp[app].hookids = mapp[app].hookids + 1 | |||
local handler = { addr = pc, v = verify, f = func, id = 0 } | |||
if mapp.curAppName == app then | |||
handler.id = axObj.AddHook(pc, verify, func) | |||
end | |||
-- print(string.format("Added Hook for app: %s, pc=%08x, handler=%d", app, pc, localid)) | |||
mapp[app].hooks[localid] = handler | |||
return localid | |||
end | end | ||
mapp.RemoveHook = function(app, hookid) | |||
-- print(string.format("RemoveHook for app: %s, id=%d", app, hookid)) | |||
if mapp[app] ~= nil then | |||
if mapp[app].hooks ~= nil then | |||
-- | if mapp[app].hooks[hookid] ~= nil then | ||
local id = mapp[app].hooks[hookid].id | |||
mapp[app].hooks[hookid] = nil -- WBD 7/6/2018 | |||
if mapp.curAppName == app and id > 0 then | |||
axObj.RemoveHook(id) | |||
end | |||
end | |||
end | |||
end | |||
end | |||
mapp.GetHookPC = function(app, hookid) | |||
if mapp[app] ~= nil then | |||
if mapp[app].hooks ~= nil then | |||
if mapp[app].hooks[hookid] ~= nil then | |||
return mapp[app].hooks[hookid].addr | |||
end | |||
end | |||
end | |||
return 0 | |||
end | |||
mapp.AddVSyncHook = function(app, func) | |||
if mapp[app] == nil then | |||
mapp[app] = {} | |||
end | |||
mapp[app].vsync = func | |||
if mapp.curAppName == app then | |||
emuObj.AddVsyncHook(func) | |||
end | |||
end | |||
mapp.RemoveVSyncHook = function(app) | |||
if mapp[app] == nil then | |||
mapp[app] = {} | |||
end | |||
if mapp[app].vsync ~= nil then | |||
table.remove(mapp[app].vsync) | |||
end | |||
if mapp.curAppName == app then | |||
emuObj.RemoveVsyncHook(func) | |||
end | |||
end | |||
-- Actual switch functionality | |||
emuObj.AddBootHook(function() | |||
local app = emuObj.GetAppName() | |||
if app ~= mapp.curAppName then | |||
-- switch out the old handlers | |||
-- print(string.format("Switching out handlers for app: %s", mapp.curAppName)) | |||
-- | if mapp[mapp.curAppName] ~= nil then | ||
-- | if mapp[mapp.curAppName].vsync ~= nil then | ||
emuObj.RemoveVsyncHook() | |||
end | |||
if mapp[mapp.curAppName].hooks ~= nil then | |||
local hooks = mapp[mapp.curAppName].hooks | |||
-- print(string.format("hooks: %d", #hooks)) | |||
mapp | for k,v in pairs(hooks) do | ||
mapp.curAppName = emuObj. | if v.id > 0 then | ||
axObj.RemoveHook(v.id) | |||
v.id = 0 | |||
end | |||
end | |||
end | |||
end | |||
-- switch current app name | |||
mapp.curAppName = app | |||
-- install the new handlers | |||
-- print(string.format("Switching in handlers for app: %s", mapp.curAppName)) | |||
if mapp[mapp.curAppName] ~= nil then | |||
if mapp[mapp.curAppName].vsync ~= nil then | |||
-- print(string.format(" | emuObj.AddVsyncHook(mapp[mapp.curAppName].vsync) | ||
end | |||
if mapp[mapp.curAppName].hooks ~= nil then | |||
local hooks = mapp[mapp.curAppName].hooks | |||
-- print(string.format("hooks: %d", #hooks)) | |||
for k,v in pairs(hooks) do | |||
v.id = axObj.AddHook(v.addr, v.v, v.f) | |||
if mapp[ | |||
local | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
if mapp[mapp.curAppName] ~= nil then | |||
if mapp[mapp.curAppName].boot ~= nil then | |||
if mapp[ | mapp[mapp.curAppName].boot() | ||
if mapp[ | |||
end | end | ||
end | end | ||
end) | |||
end | |||
mapp | return mapp | ||
</pre> | |||
'''pad.lua''' | |||
<pre> | |||
-- Recommended method to import this module: | |||
-- local pad = require("pad") | |||
-- | |||
-- Buttons marked PS4 are not used by the emulator, but can be read from Lua | |||
-- | |||
-- Read the Pad state with getEmuObject().PadRead() | |||
-- ie: | |||
-- local padstate = getEmuObject().PadRead() | |||
-- | |||
pad = {} | |||
pad.L3 = 0x00000002 -- L3 (PS4) | |||
pad.R3 = 0x00000004 -- R3 (PS4) | |||
-- | pad.OPTIONS = 0x00000008 -- Options (PS4) | ||
pad.UP = 0x00000010 -- Up | |||
pad.RIGHT = 0x00000020 -- Right | |||
pad.DOWN = 0x00000040 -- Down | |||
pad.LEFT = 0x00000080 -- Left | |||
pad.L2 = 0x00000100 -- L2 (PS4) | |||
pad.R2 = 0x00000200 -- R2 (PS4) | |||
pad.L1 = 0x00000400 -- L1 | |||
pad.R1 = 0x00000800 -- R1 | |||
-- | pad.TRIANGLE = 0x00001000 -- Triangle | ||
pad.CIRCLE = 0x00002000 -- Circle | |||
pad.CROSS = 0x00004000 -- Cross | |||
pad.SQUARE = 0x00008000 -- Square | |||
pad.SELECT = 0x00010000 -- Select | |||
pad.START = 0x00020000 -- Start | |||
-- Automap SELECT or START to the Options Button, leaving the full touchar for the opposite, with getEmuObject().PadSetButtonsMode(mode) | |||
-- ie: | |||
-- getEmuObject().PadSetButtonsMode(pad.BUTTONS_MODE_OPTION_IS_SELECT) | |||
pad.BUTTONS_MODE_NORMAL = 0 -- Touch bar is split in two for Start/Select. Option is unmapped (default behaviour) | |||
pad.BUTTONS_MODE_OPTION_IS_SELECT = 1 -- Touch bar is Start. Option is Select | |||
pad.BUTTONS_MODE_OPTION_IS_START = 2 -- Touch bar is Select. Option is Start | |||
-- | return pad | ||
</pre> | |||
=Information= | |||
Note: Missing entries | |||
==Folder/File layout== | |||
-- | |||
return | |||
</pre> | |||
<pre> | <pre> | ||
-- | ├── assets | ||
│ ├── common | |||
│ └── PSPHD | |||
├── app | |||
│ └── USER_L0.IMG | |||
├── lua_include | |||
- | │ ├── ax-gpr-alias.lua | ||
- | │ ├── multiapp.lua | ||
│ └── pad.lua | |||
├── scripts | |||
│ ├──XXXXYYYYY_patches.lua | |||
│ ├──XXXXYYYYY_features.lua | |||
│ ├──XXXXYYYYY_tooling.lua | |||
│ └──XXXXYYYYY_trophies.lua | |||
├── sce_module | |||
├── sce_sys | |||
├── vms | |||
├── trophy_data | |||
├── usermodule | |||
│ └──libfont.lib | |||
├── sce_discmap.plt | |||
├── eboot.bin | |||
├── revision.conf | |||
├── package-ps4.conf | |||
└── config-title.txt | |||
</pre> | |||
==Other== | |||
<pre> | |||
XXXXYYYYY_config.txt | |||
videos/ | |||
.mp4 | |||
videos/%08x.mp4 | |||
audio/%08x.ogg | |||
Paths: | |||
/app0/ | |||
/download0/ | |||
/savedata | |||
/host/ | |||
/hostapp/ | |||
/data/ | |||
</pre> | </pre> | ||
= | ==Sample== | ||
<pre>; PS4 configuration file for PSPHD | |||
<pre> | |||
; PS4 configuration file for PSPHD | |||
; Game Image | ; Game Image | ||
Line 1,746: | Line 1,357: | ||
--parappaalphahack=true | --parappaalphahack=true | ||
</pre> | </pre> | ||
==NIDs in HLE== | |||
== NIDs in HLE == | |||
<pre> | <pre> | ||
|HLEInterruptManager| | |HLEInterruptManager| | ||
Line 2,352: | Line 1,901: | ||
* https://forums.ppsspp.org/showthread.php?tid=11961 | * https://forums.ppsspp.org/showthread.php?tid=11961 | ||
* https://github.com/LunaMoo/PPSSPP_workarounds/blob/master/cheat.db | * https://github.com/LunaMoo/PPSSPP_workarounds/blob/master/cheat.db | ||
* https://www.psdevwiki.com/ps4/ | * https://www.psdevwiki.com/ps4/Talk:PSP_Emulator_Compatibility_List#Official_PSPemu_Configuration_Files | ||
* https://www.psdevwiki.com/ps4/PSP_Emulator_Compatibility_List | * https://www.psdevwiki.com/ps4/PSP_Emulator_Compatibility_List | ||