mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-19 19:15:26 +00:00
Merge branch 'master' into RSX
This commit is contained in:
commit
97b89790a5
13 changed files with 128 additions and 39 deletions
|
@ -528,7 +528,7 @@ bool package_reader::read_entries(std::vector<PKGEntry>& entries)
|
|||
entries.clear();
|
||||
entries.resize(m_header.file_count + BUF_PADDING / sizeof(PKGEntry) + 1);
|
||||
|
||||
const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_dec_key.data(), entries.data());
|
||||
const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data(), entries.data());
|
||||
|
||||
if (read_size < m_header.file_count * sizeof(PKGEntry))
|
||||
{
|
||||
|
|
|
@ -484,6 +484,7 @@ auto ppu_feed_data(ppu_thread& ppu, u64 addr)
|
|||
{
|
||||
// Reservation was lost
|
||||
ppu.raddr = 0;
|
||||
ppu.res_cached = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -503,6 +504,7 @@ auto ppu_feed_data(ppu_thread& ppu, u64 addr)
|
|||
if (std::memcmp(buffer + offs, src, size))
|
||||
{
|
||||
ppu.raddr = 0;
|
||||
ppu.res_cached = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3103,7 +3103,18 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr)
|
|||
ppu.last_faddr = 0;
|
||||
}
|
||||
|
||||
ppu.rtime = vm::reservation_acquire(addr) & -128;
|
||||
const u32 res_cached = ppu.res_cached;
|
||||
|
||||
if ((addr & -128) == (res_cached & -128))
|
||||
{
|
||||
// Reload "cached" reservation of previous succeeded conditional store
|
||||
// This seems like a hardware feature according to cellSpursAddUrgentCommand function
|
||||
ppu.rtime -= 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu.rtime = vm::reservation_acquire(addr) & -128;
|
||||
}
|
||||
|
||||
be_t<u64> rdata;
|
||||
|
||||
|
@ -3376,7 +3387,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
}
|
||||
|
||||
// Test if store address is on the same aligned 8-bytes memory as load
|
||||
if (const u32 raddr = std::exchange(ppu.raddr, 0); raddr / 8 != addr / 8)
|
||||
if (const u32 raddr = ppu.raddr; raddr / 8 != addr / 8)
|
||||
{
|
||||
// If not and it is on the same aligned 128-byte memory, proceed only if 128-byte reservations are enabled
|
||||
// In realhw the store address can be at any address of the 128-byte cache line
|
||||
|
@ -3389,12 +3400,16 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
data += 0;
|
||||
}
|
||||
|
||||
ppu.raddr = 0;
|
||||
ppu.res_cached = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_data != data || rtime != (res & -128))
|
||||
{
|
||||
ppu.raddr = 0;
|
||||
ppu.res_cached = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3650,6 +3665,9 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
}
|
||||
|
||||
ppu.last_faddr = 0;
|
||||
ppu.res_cached = ppu.raddr;
|
||||
ppu.rtime += 128;
|
||||
ppu.raddr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3669,6 +3687,8 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
ppu.res_notify = 0;
|
||||
}
|
||||
|
||||
ppu.raddr = 0;
|
||||
ppu.res_cached = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -264,6 +264,7 @@ public:
|
|||
u64 rtime{0};
|
||||
alignas(64) std::byte rdata[128]{}; // Reservation data
|
||||
bool use_full_rdata{};
|
||||
u32 res_cached{0}; // Reservation "cached" addresss
|
||||
u32 res_notify{0};
|
||||
u64 res_notify_time{0};
|
||||
|
||||
|
|
|
@ -1531,8 +1531,6 @@ public:
|
|||
return add_loc->compiled;
|
||||
}
|
||||
|
||||
std::string log;
|
||||
|
||||
bool add_to_file = false;
|
||||
|
||||
if (auto& cache = g_fxo->get<spu_cache>(); cache && g_cfg.core.spu_cache && !add_loc->cached.exchange(1))
|
||||
|
@ -1566,10 +1564,35 @@ public:
|
|||
|
||||
m_pp_id = 0;
|
||||
|
||||
std::string function_log;
|
||||
|
||||
this->dump(func, function_log);
|
||||
bool to_log_func = false;
|
||||
|
||||
if (g_cfg.core.spu_debug && !add_loc->logged.exchange(1))
|
||||
{
|
||||
this->dump(func, log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu.log", fs::write + fs::append, log);
|
||||
if (!fs::write_file(m_spurt->get_cache_path() + "spu.log", fs::write + fs::append, function_log))
|
||||
{
|
||||
// Fallback: write to main log
|
||||
to_log_func = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 data : func.data)
|
||||
{
|
||||
const spu_opcode_t op{std::bit_cast<be_t<u32>>(data)};
|
||||
|
||||
const auto itype = g_spu_itype.decode(op.opcode);
|
||||
|
||||
if (itype == spu_itype::RDCH && op.ra == SPU_RdDec)
|
||||
{
|
||||
to_log_func = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (to_log_func)
|
||||
{
|
||||
spu_log.notice("Function %s dump:\n%s", m_hash, function_log);
|
||||
}
|
||||
|
||||
using namespace llvm;
|
||||
|
@ -2715,11 +2738,13 @@ public:
|
|||
m_function_queue.clear();
|
||||
m_function_table = nullptr;
|
||||
|
||||
raw_string_ostream out(log);
|
||||
// Append for now
|
||||
std::string& llvm_log = function_log;
|
||||
raw_string_ostream out(llvm_log);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fmt::append(log, "LLVM IR at 0x%x:\n", func.entry_point);
|
||||
fmt::append(llvm_log, "LLVM IR at 0x%x:\n", func.entry_point);
|
||||
out << *_module; // print IR
|
||||
out << "\n\n";
|
||||
}
|
||||
|
@ -2727,11 +2752,11 @@ public:
|
|||
if (verifyModule(*_module, &out))
|
||||
{
|
||||
out.flush();
|
||||
spu_log.error("LLVM: Verification failed at 0x%x:\n%s", func.entry_point, log);
|
||||
spu_log.error("LLVM: Verification failed at 0x%x:\n%s", func.entry_point, llvm_log);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append, log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append, llvm_log);
|
||||
}
|
||||
|
||||
if (auto& cache = g_fxo->get<spu_cache>())
|
||||
|
@ -2786,7 +2811,7 @@ public:
|
|||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
out.flush();
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, llvm_log);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
@ -3182,13 +3207,12 @@ public:
|
|||
run_transforms(f);
|
||||
}
|
||||
|
||||
std::string log;
|
||||
|
||||
raw_string_ostream out(log);
|
||||
std::string llvm_log;
|
||||
raw_string_ostream out(llvm_log);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fmt::append(log, "LLVM IR (interpreter):\n");
|
||||
fmt::append(llvm_log, "LLVM IR (interpreter):\n");
|
||||
out << *_module; // print IR
|
||||
out << "\n\n";
|
||||
}
|
||||
|
@ -3196,11 +3220,11 @@ public:
|
|||
if (verifyModule(*_module, &out))
|
||||
{
|
||||
out.flush();
|
||||
spu_log.error("LLVM: Verification failed:\n%s", log);
|
||||
spu_log.error("LLVM: Verification failed:\n%s", llvm_log);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, llvm_log);
|
||||
}
|
||||
|
||||
fmt::throw_exception("Compilation failed");
|
||||
|
@ -3235,7 +3259,7 @@ public:
|
|||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
out.flush();
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, llvm_log);
|
||||
}
|
||||
|
||||
return spu_runtime::g_interpreter;
|
||||
|
|
|
@ -1204,18 +1204,30 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
|
|||
|
||||
std::vector<v128> gpr_saved(128);
|
||||
be_t<u32> rdata_saved[32]{};
|
||||
be_t<u32> lsa_saved[32]{};
|
||||
spu_mfc_cmd mfc_regs_saved{};
|
||||
u32 saved_pc = umax;
|
||||
const u8* lsa_state_ptr = nullptr;
|
||||
|
||||
const u8* lsa_ptr = _ptr<u8>(ch_mfc_cmd.lsa);
|
||||
|
||||
// Load PC, GPRs and reservation data atomically
|
||||
// We may not load the entire context atomically, but there is importance their state being intact for debugging
|
||||
do
|
||||
{
|
||||
saved_pc = pc;
|
||||
|
||||
// Account for list transfer: record EAL instead
|
||||
mfc_regs_saved = ch_mfc_cmd;
|
||||
lsa_state_ptr = _ptr<const u8>(mfc_regs_saved.eal < SPU_LS_SIZE && mfc_regs_saved.eal % 8 == 0 ? mfc_regs_saved.eal : mfc_regs_saved.lsa);
|
||||
|
||||
std::memcpy(gpr_saved.data(), gpr.data(), sizeof(v128) * gpr.size());
|
||||
std::memcpy(rdata_saved, rdata, sizeof(rdata));
|
||||
std::memcpy(lsa_saved, lsa_state_ptr, std::min<usz>(128, SPU_LS_SIZE - (lsa_state_ptr - _ptr<u8>(0))));
|
||||
atomic_fence_acquire();
|
||||
}
|
||||
while (saved_pc != pc || std::memcmp(rdata_saved, rdata, sizeof(rdata)) != 0 || std::memcmp(gpr_saved.data(), gpr.data(), sizeof(v128) * gpr.size()) != 0);
|
||||
while (saved_pc != pc || std::memcmp(rdata_saved, rdata, sizeof(rdata)) != 0 || std::memcmp(gpr_saved.data(), gpr.data(), sizeof(v128) * gpr.size()) != 0
|
||||
|| std::memcmp(&mfc_regs_saved, &ch_mfc_cmd, sizeof(mfc_regs_saved)) != 0 || std::memcmp(lsa_saved, lsa_state_ptr, std::min<usz>(128, SPU_LS_SIZE - (lsa_state_ptr - _ptr<u8>(0)))) != 0);
|
||||
|
||||
for (u32 i = 0; i < 128; i++, ret += '\n')
|
||||
{
|
||||
|
@ -1350,6 +1362,7 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
|
|||
fmt::append(ret, "SNR config: 0x%llx\n", snr_config);
|
||||
fmt::append(ret, "SNR1: %s\n", ch_snr1);
|
||||
fmt::append(ret, "SNR2: %s\n", ch_snr2);
|
||||
fmt::append(ret, "Last WrDec: %-9d (0x%08x) (%s)\n", ch_dec_value, ch_dec_value, is_dec_frozen ? "suspend" : "running");
|
||||
|
||||
if (get_type() != spu_type::threaded)
|
||||
{
|
||||
|
@ -1388,6 +1401,14 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
|
|||
fmt::append(ret, "[0x%02x] %08x %08x %08x %08x\n", i * sizeof(rdata_saved[0])
|
||||
, rdata_saved[i + 0], rdata_saved[i + 1], rdata_saved[i + 2], rdata_saved[i + 3]);
|
||||
}
|
||||
|
||||
fmt::append(ret, "\nLSA Data:\n");
|
||||
|
||||
for (usz i = 0; i < std::size(lsa_saved); i += 4)
|
||||
{
|
||||
fmt::append(ret, "[0x%02x] %08x %08x %08x %08x\n", i * sizeof(lsa_saved[0])
|
||||
, lsa_saved[i + 0], lsa_saved[i + 1], lsa_saved[i + 2], lsa_saved[i + 3]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string spu_thread::dump_callstack() const
|
||||
|
|
|
@ -137,6 +137,7 @@ void fmt_class_string<game_boot_result>::format(std::string& out, u64 arg)
|
|||
case game_boot_result::decryption_error: return "Failed to decrypt content";
|
||||
case game_boot_result::file_creation_error: return "Could not create important files";
|
||||
case game_boot_result::firmware_missing: return "Firmware is missing";
|
||||
case game_boot_result::firmware_version: return "Firmware is too old";
|
||||
case game_boot_result::unsupported_disc_type: return "This disc type is not supported yet";
|
||||
case game_boot_result::savestate_corrupted: return "Savestate data is corrupted or it's not an RPCS3 savestate";
|
||||
case game_boot_result::savestate_version_unsupported: return "Savestate versioning data differs from your RPCS3 build.\nTry to use an older or newer RPCS3 build.\nEspecially if you know the build that created the savestate.";
|
||||
|
@ -1965,7 +1966,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
|
|||
// Initialize performance monitor
|
||||
g_fxo->init<named_thread<perf_monitor>>();
|
||||
|
||||
// Set title to actual disc title if necessary
|
||||
const std::string disc_sfo_dir = vfs::get("/dev_bdvd/PS3_GAME/PARAM.SFO");
|
||||
|
||||
const auto disc_psf_obj = psf::load_object(disc_sfo_dir);
|
||||
|
@ -2100,6 +2100,21 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
|
|||
}
|
||||
}
|
||||
|
||||
// Check firmware version
|
||||
if (const std::string_view game_fw_version = psf::get_string(_psf, "PS3_SYSTEM_VER", ""); !game_fw_version.empty())
|
||||
{
|
||||
if (const std::string fw_version = utils::get_firmware_version(); fw_version.empty())
|
||||
{
|
||||
sys_log.warning("Firmware not installed. Skipping required firmware check. (title_id='%s', game_fw='%s')", m_title_id, game_fw_version);
|
||||
}
|
||||
else if (rpcs3::utils::version_is_bigger(game_fw_version, fw_version, m_title_id, true))
|
||||
{
|
||||
sys_log.error("The game's required firmware version is higher than the installed firmware's version. (title_id='%s', game_fw='%s', fw='%s')", m_title_id, game_fw_version, fw_version);
|
||||
return game_boot_result::firmware_version;
|
||||
}
|
||||
}
|
||||
|
||||
// Set title to actual disc title if necessary
|
||||
if (!disc_psf_obj.empty())
|
||||
{
|
||||
const auto bdvd_title = psf::get_string(disc_psf_obj, "TITLE");
|
||||
|
|
|
@ -51,6 +51,7 @@ enum class game_boot_result : u32
|
|||
decryption_error,
|
||||
file_creation_error,
|
||||
firmware_missing,
|
||||
firmware_version,
|
||||
unsupported_disc_type,
|
||||
savestate_corrupted,
|
||||
savestate_version_unsupported,
|
||||
|
|
|
@ -172,7 +172,7 @@ struct cfg_root : cfg::node
|
|||
cfg::_int<1, 1024> min_scalable_dimension{ this, "Minimum Scalable Dimension", 16 };
|
||||
cfg::_int<0, 16> shader_compiler_threads_count{ this, "Shader Compiler Threads", 0 };
|
||||
cfg::_int<0, 30000000> driver_recovery_timeout{ this, "Driver Recovery Timeout", 1000000, true };
|
||||
cfg::uint<0, 16667> driver_wakeup_delay{ this, "Driver Wake-Up Delay", 1, true };
|
||||
cfg::uint<0, 16667> driver_wakeup_delay{ this, "Driver Wake-Up Delay", 0, true };
|
||||
cfg::_int<1, 6000> vblank_rate{ this, "Vblank Rate", 60, true }; // Changing this from 60 may affect game speed in unexpected ways
|
||||
cfg::_bool vblank_ntsc{ this, "Vblank NTSC Fixup", false, true };
|
||||
cfg::_bool decr_memory_layout{ this, "DECR memory layout", false}; // Force enable increased allowed main memory range as DECR console
|
||||
|
|
|
@ -418,4 +418,19 @@ namespace rpcs3::utils
|
|||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool version_is_bigger(std::string_view v0, std::string_view v1, std::string_view serial, bool is_fw)
|
||||
{
|
||||
std::add_pointer_t<char> ev0, ev1;
|
||||
const double ver0 = std::strtod(v0.data(), &ev0);
|
||||
const double ver1 = std::strtod(v1.data(), &ev1);
|
||||
|
||||
if (v0.data() + v0.size() == ev0 && v1.data() + v1.size() == ev1)
|
||||
{
|
||||
return ver0 > ver1;
|
||||
}
|
||||
|
||||
sys_log.error("Failed to compare the %s numbers for title ID %s: '%s'-'%s'", is_fw ? "firmware version" : "version", serial, v0, v1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,4 +42,6 @@ namespace rpcs3::utils
|
|||
std::string get_custom_input_config_path(const std::string& title_id);
|
||||
|
||||
std::string get_game_content_path(game_content_type type);
|
||||
|
||||
bool version_is_bigger(std::string_view v0, std::string_view v1, std::string_view serial, bool is_fw);
|
||||
}
|
||||
|
|
|
@ -864,30 +864,15 @@ void game_list_frame::OnRefreshFinished()
|
|||
if (entry->info.serial != other->info.serial) continue;
|
||||
|
||||
// The patch is game data and must have the same serial and an app version
|
||||
static constexpr auto version_is_bigger = [](const std::string& v0, const std::string& v1, const std::string& serial, bool is_fw)
|
||||
{
|
||||
std::add_pointer_t<char> ev0, ev1;
|
||||
const double ver0 = std::strtod(v0.c_str(), &ev0);
|
||||
const double ver1 = std::strtod(v1.c_str(), &ev1);
|
||||
|
||||
if (v0.c_str() + v0.size() == ev0 && v1.c_str() + v1.size() == ev1)
|
||||
{
|
||||
return ver0 > ver1;
|
||||
}
|
||||
|
||||
game_list_log.error("Failed to update the displayed %s numbers for title ID %s\n'%s'-'%s'", is_fw ? "firmware version" : "version", serial, v0, v1);
|
||||
return false;
|
||||
};
|
||||
|
||||
if (other->info.app_ver != cat_unknown_localized)
|
||||
{
|
||||
// Update the app version if it's higher than the disc's version (old games may not have an app version)
|
||||
if (entry->info.app_ver == cat_unknown_localized || version_is_bigger(other->info.app_ver, entry->info.app_ver, entry->info.serial, true))
|
||||
if (entry->info.app_ver == cat_unknown_localized || rpcs3::utils::version_is_bigger(other->info.app_ver, entry->info.app_ver, entry->info.serial, false))
|
||||
{
|
||||
entry->info.app_ver = other->info.app_ver;
|
||||
}
|
||||
// Update the firmware version if possible and if it's higher than the disc's version
|
||||
if (other->info.fw != cat_unknown_localized && version_is_bigger(other->info.fw, entry->info.fw, entry->info.serial, false))
|
||||
if (other->info.fw != cat_unknown_localized && rpcs3::utils::version_is_bigger(other->info.fw, entry->info.fw, entry->info.serial, true))
|
||||
{
|
||||
entry->info.fw = other->info.fw;
|
||||
}
|
||||
|
|
|
@ -538,6 +538,9 @@ void main_window::show_boot_error(game_boot_result status)
|
|||
case game_boot_result::still_running:
|
||||
message = tr("A game or PS3 application is still running or has yet to be fully stopped.");
|
||||
break;
|
||||
case game_boot_result::firmware_version:
|
||||
message = tr("The game or PS3 application needs a more recent firmware version.");
|
||||
break;
|
||||
case game_boot_result::firmware_missing: // Handled elsewhere
|
||||
case game_boot_result::already_added: // Handled elsewhere
|
||||
case game_boot_result::currently_restricted:
|
||||
|
|
Loading…
Add table
Reference in a new issue