From 3f028fbb831ba81e9eaf9f8f45f889ed97c92a88 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 23 Nov 2020 20:02:05 +0200 Subject: [PATCH] Fix SPU LS MMIO --- rpcs3/Emu/Cell/SPUThread.cpp | 46 ++++++++++++++++++---------------- rpcs3/Emu/Cell/lv2/sys_spu.cpp | 2 +- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 0963e54b66..5d28d56b55 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1668,12 +1668,12 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u if (!group) { - vm::get(vm::spu)->falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, SPU_LS_SIZE, &shm); + verify(HERE), vm::get(vm::spu)->falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, SPU_LS_SIZE, &shm); } else { // 0x1000 indicates falloc to allocate page with no access rights in base memory - vm::get(vm::spu)->falloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (cpu_thread::id & 0xffffff), SPU_LS_SIZE, &shm, 0x1000); + verify(HERE), vm::get(vm::spu)->falloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (cpu_thread::id & 0xffffff), SPU_LS_SIZE, &shm, 0x1000); } vm::writer_lock(0); @@ -1811,6 +1811,23 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* u32 eal = args.eal; u32 lsa = args.lsa & 0x3ffff; + // Keep src point to const + u8* dst = nullptr; + const u8* src = nullptr; + + std::tie(dst, src) = [&]() -> std::pair + { + u8* dst = vm::_ptr(eal); + u8* src = ls + lsa; + + if (is_get) + { + std::swap(src, dst); + } + + return {dst, src}; + }(); + // SPU Thread Group MMIO (LS and SNR) and RawSPU MMIO if (_this && eal >= RAW_SPU_BASE_ADDR) { @@ -1851,9 +1868,13 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* { auto& spu = static_cast(*_this->group->threads[_this->group->threads_map[index]]); - if (offset + args.size - 1 < SPU_LS_SIZE) // LS access + if (offset + args.size <= SPU_LS_SIZE) // LS access { - eal = SPU_FAKE_BASE_ADDR * (spu.id & 0xffffff) + offset; // redirect access + // redirect access + if (auto ptr = spu.ls + offset; is_get) + src = ptr; + else + dst = ptr; } else if (!is_get && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2)) { @@ -1871,29 +1892,12 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* } } - // Keep src point to const - u8* dst = nullptr; - const u8* src = nullptr; - // Cleanup: if PUT or GET happens after PUTLLC failure, it's too complicated and it's easier to just give up if (_this) { _this->last_faddr = 0; } - std::tie(dst, src) = [&]() -> std::pair - { - u8* dst = vm::_ptr(eal); - u8* src = ls + lsa; - - if (is_get) - { - std::swap(src, dst); - } - - return {dst, src}; - }(); - // It is so rare that optimizations are not implemented (TODO) alignas(64) static constexpr u8 zero_buf[0x10000]{}; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index afe3151fd0..a84da52b6d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -682,7 +682,7 @@ error_code sys_spu_thread_group_destroy(ppu_thread& ppu, u32 id) if (auto thread = t.get()) { // Deallocate LS - vm::get(vm::spu)->dealloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (thread->id & 0xffffff), &thread->shm); + verify(HERE), vm::get(vm::spu)->dealloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (thread->id & 0xffffff), &thread->shm); // Remove ID from IDM (destruction will occur in group destructor) idm::remove>(thread->id);