SPU: don't allocate SPU LS in vm::main

Create its own shared memory object.
Use vm::spu to allocate all SPU types.
Use vm::writer_lock for shm::map_critical.
This commit is contained in:
Nekotekina 2020-11-15 07:37:56 +03:00
parent b1710bb712
commit eaf0bbc108
5 changed files with 45 additions and 24 deletions

View file

@ -28,7 +28,7 @@ inline void try_start(spu_thread& spu)
bool spu_thread::read_reg(const u32 addr, u32& value)
{
const u32 offset = addr - this->offset - RAW_SPU_PROB_OFFSET;
const u32 offset = addr - (RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) - RAW_SPU_PROB_OFFSET;
spu_log.trace("RawSPU[%u]: Read32(0x%x, offset=0x%x)", index, addr, offset);
@ -165,7 +165,7 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
bool spu_thread::write_reg(const u32 addr, const u32 value)
{
const u32 offset = addr - this->offset - RAW_SPU_PROB_OFFSET;
const u32 offset = addr - (RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) - RAW_SPU_PROB_OFFSET;
spu_log.trace("RawSPU[%u]: Write32(0x%x, offset=0x%x, value=0x%x)", index, addr, offset, value);
@ -321,7 +321,7 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
void spu_load_exec(const spu_exec_object& elf)
{
auto ls0 = vm::cast(vm::falloc(RAW_SPU_BASE_ADDR, SPU_LS_SIZE, vm::spu));
auto ls0 = vm::addr_t{RAW_SPU_BASE_ADDR};
spu_thread::g_raw_spu_ctr++;
@ -333,7 +333,7 @@ void spu_load_exec(const spu_exec_object& elf)
}
}
auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", ls0, nullptr, 0, "", 0);
auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", nullptr, 0, "", 0);
spu_thread::g_raw_spu_id[0] = spu->id;

View file

@ -1384,6 +1384,8 @@ std::string spu_thread::dump_misc() const
fmt::append(ret, "...chunk-0x%05x", (name & 0xffff) * 4);
}
const u32 offset = group ? SPU_FAKE_BASE_ADDR + (id & 0xffffff) * SPU_LS_SIZE : RAW_SPU_BASE_ADDR + index * RAW_SPU_OFFSET;
fmt::append(ret, "\n[%s]", ch_mfc_cmd);
fmt::append(ret, "\nLocal Storage: 0x%08x..0x%08x", offset, offset + 0x3ffff);
@ -1624,16 +1626,19 @@ void spu_thread::cpu_task()
spu_thread::~spu_thread()
{
{
const auto [_, shm] = vm::get(vm::any, offset)->get(offset);
vm::writer_lock(0);
for (s32 i = -1; i < 2; i++)
{
// Unmap LS mirrors
shm->unmap_critical(ls + (i * SPU_LS_SIZE));
}
}
// Deallocate Local Storage
vm::dealloc_verbose_nothrow(offset);
if (!group)
{
// Deallocate local storage (thread groups are handled in sys_spu.cpp)
vm::dealloc_verbose_nothrow(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, vm::spu);
}
// Release LS mirrors area
@ -1653,14 +1658,25 @@ spu_thread::~spu_thread()
perf_log.notice("Perf stats for PUTLLC reload: successs %u, failure %u", last_succ, last_fail);
}
spu_thread::spu_thread(vm::addr_t _ls, lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated, u32 option)
spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated, u32 option)
: cpu_thread(idm::last_id())
, index(index)
, shm(std::make_shared<utils::shm>(SPU_LS_SIZE))
, ls([&]()
{
const auto [_, shm] = vm::get(vm::any, _ls)->get(_ls);
const auto addr = static_cast<u8*>(utils::memory_reserve(SPU_LS_SIZE * 5));
if (!group)
{
vm::get(vm::spu)->falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, SPU_LS_SIZE, &shm);
}
else
{
vm::get(vm::spu)->falloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (cpu_thread::id & 0xffffff), SPU_LS_SIZE, &shm);
}
vm::writer_lock(0);
for (u32 i = 1; i < 4; i++)
{
// Map LS mirrors
@ -1672,7 +1688,6 @@ spu_thread::spu_thread(vm::addr_t _ls, lv2_spu_group* group, u32 index, std::str
return addr + (SPU_LS_SIZE * 2);
}())
, thread_type(group ? spu_type::threaded : is_isolated ? spu_type::isolated : spu_type::raw)
, offset(_ls)
, group(group)
, option(option)
, lv2_id(lv2_id)
@ -1837,7 +1852,7 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8*
if (offset + args.size - 1 < SPU_LS_SIZE) // LS access
{
eal = spu.offset + offset; // redirect access
eal = SPU_FAKE_BASE_ADDR * (spu.id & 0xffffff) + offset; // redirect access
}
else if (!is_get && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2))
{

View file

@ -14,6 +14,11 @@ struct lv2_event_queue;
struct lv2_spu_group;
struct lv2_int_tag;
namespace utils
{
class shm;
}
// JIT Block
using spu_function_t = void(*)(spu_thread&, void*, u8*);
@ -157,6 +162,8 @@ enum : u32
RAW_SPU_OFFSET = 0x00100000,
RAW_SPU_LS_OFFSET = 0x00000000,
RAW_SPU_PROB_OFFSET = 0x00040000,
SPU_FAKE_BASE_ADDR = 0xE8000000,
};
struct spu_channel
@ -629,9 +636,9 @@ public:
static const u32 id_base = 0x02000000; // TODO (used to determine thread type)
static const u32 id_step = 1;
static const u32 id_count = 2048;
static const u32 id_count = (0xF0000000 - SPU_FAKE_BASE_ADDR) / SPU_LS_SIZE;
spu_thread(vm::addr_t ls, lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated = false, u32 option = 0);
spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated = false, u32 option = 0);
u32 pc = 0;
@ -730,10 +737,10 @@ public:
atomic_t<u32> last_exit_status; // Value to be written in exit_status after checking group termination
const u32 index; // SPU index
std::shared_ptr<utils::shm> shm; // SPU memory
const std::add_pointer_t<u8> ls; // SPU LS pointer
const spu_type thread_type;
private:
const u32 offset; // SPU LS offset
lv2_spu_group* const group; // SPU Thread Group (only safe to access in the spu thread itself)
public:
const u32 option; // sys_spu_thread_initialize option

View file

@ -399,8 +399,6 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
sys_spu.warning("Unimplemented SPU Thread options (0x%x)", option);
}
const vm::addr_t ls_addr{verify("SPU LS" HERE, vm::alloc(SPU_LS_SIZE, vm::main))};
const u32 inited = group->init;
const u32 tid = (inited << 24) | (group_id & 0xffffff);
@ -414,7 +412,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
fmt::append(full_name, "%s ", thread_name);
}
const auto spu = std::make_shared<named_thread<spu_thread>>(full_name, ls_addr, group.get(), spu_num, thread_name, tid, false, option);
const auto spu = std::make_shared<named_thread<spu_thread>>(full_name, group.get(), spu_num, thread_name, tid, false, option);
group->threads[inited] = spu;
group->threads_map[spu_num] = static_cast<s8>(inited);
return spu;
@ -683,6 +681,9 @@ 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);
// Remove ID from IDM (destruction will occur in group destructor)
idm::remove<named_thread<spu_thread>>(thread->id);
}
@ -1845,9 +1846,7 @@ error_code sys_raw_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<void> at
index = 0;
}
const vm::addr_t ls_addr{verify(HERE, vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, SPU_LS_SIZE, vm::spu))};
const u32 tid = idm::make<named_thread<spu_thread>>(fmt::format("RawSPU[0x%x] ", index), ls_addr, nullptr, index, "", index);
const u32 tid = idm::make<named_thread<spu_thread>>(fmt::format("RawSPU[0x%x] ", index), nullptr, index, "", index);
spu_thread::g_raw_spu_id[index] = verify("RawSPU ID" HERE, tid);
@ -1893,9 +1892,9 @@ error_code sys_isolated_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<voi
index = 0;
}
const vm::addr_t ls_addr{verify(HERE, vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, SPU_LS_SIZE, vm::spu))};
const vm::addr_t ls_addr{RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index};
const auto thread = idm::make_ptr<named_thread<spu_thread>>(fmt::format("IsoSPU[0x%x] ", index), ls_addr, nullptr, index, "", index, true);
const auto thread = idm::make_ptr<named_thread<spu_thread>>(fmt::format("IsoSPU[0x%x] ", index), nullptr, index, "", index, true);
thread->gpr[3] = v128::from64(0, arg1);
thread->gpr[4] = v128::from64(0, arg2);

View file

@ -1313,10 +1313,10 @@ namespace vm
return {addr, nullptr};
}
// Special path
// Special case
if (m_common)
{
return {this->addr, m_common};
return {addr, nullptr};
}
// Range check