diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index c79604d85b..658b0bd654 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -49,23 +49,6 @@ const u32 tiled_pitches[] = { 0x00010000 }; -struct gcm_config -{ - u32 zculls_addr; - vm::ptr gcm_buffers = vm::null; - u32 tiles_addr; - u32 ctxt_addr; - CellGcmConfig current_config; - CellGcmContextData current_context; - gcmInfo gcm_info; -}; - -u64 system_mode = 0; -u32 local_size = 0; -u32 local_addr = 0; - -atomic_t reserved_size = 0; - // Auxiliary functions /* @@ -93,22 +76,31 @@ u32 gcmGetLocalMemorySize(u32 sdk_version) return 0x0E000000; // 224MB } -CellGcmOffsetTable offsetTable; -atomic_t IoMapTable[0xC00]{}; - error_code gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict); +u32 gcmIoOffsetToAddress(u32 ioOffset) +{ + const u32 upper12Bits = g_fxo->get()->offsetTable.eaAddress[ioOffset >> 20]; + + if (static_cast(upper12Bits) < 0) + { + return 0; + } + + return (upper12Bits << 20) | (ioOffset & 0xFFFFF); +} + void InitOffsetTable() { - offsetTable.ioAddress.set(vm::alloc(3072 * sizeof(u16), vm::main)); - offsetTable.eaAddress.set(vm::alloc(512 * sizeof(u16), vm::main)); + const auto cfg = g_fxo->get(); - memset(offsetTable.ioAddress.get_ptr(), 0xFF, 3072 * sizeof(u16)); - memset(offsetTable.eaAddress.get_ptr(), 0xFF, 512 * sizeof(u16)); - memset(IoMapTable, 0, 3072 * sizeof(u16)); + cfg->offsetTable.ioAddress.set(vm::alloc(3072 * sizeof(u16), vm::main)); + cfg->offsetTable.eaAddress.set(vm::alloc(512 * sizeof(u16), vm::main)); - memset(&RSXIOMem, 0xFF, sizeof(RSXIOMem)); - reserved_size = 0; + std::memset(cfg->offsetTable.ioAddress.get_ptr(), 0xFF, 3072 * sizeof(u16)); + std::memset(cfg->offsetTable.eaAddress.get_ptr(), 0xFF, 512 * sizeof(u16)); + + cfg->reserved_size = 0; } //---------------------------------------------------------------------------- @@ -132,7 +124,7 @@ vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 lo cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index); } - return vm::ptr::make(RSXIOMem.RealAddr(0x0e000000 + index * 0x10)); + return vm::cast(gcmIoOffsetToAddress(0x0e000000 + index * 0x10)); } // Anything else is Local @@ -142,7 +134,7 @@ vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 lo cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong local index (%d)", index); } - return vm::ptr::make(g_fxo->get()->gcm_info.label_addr + ::offset32(&RsxReports::report) + index * 0x10); + return vm::cast(g_fxo->get()->gcm_info.label_addr + ::offset32(&RsxReports::report) + index * 0x10); } u64 cellGcmGetTimeStamp(u32 index) @@ -168,7 +160,7 @@ u32 cellGcmGetNotifyDataAddress(u32 index) cellGcmSys.warning("cellGcmGetNotifyDataAddress(index=%d)", index); // If entry not in use, return NULL - u16 entry = offsetTable.eaAddress[241]; + u16 entry = g_fxo->get()->offsetTable.eaAddress[241]; if (entry == 0xFFFF) { return 0; } @@ -225,24 +217,8 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location) { cellGcmSys.warning("cellGcmGetTimeStampLocation(index=%d, location=%d)", index, location); - if (location == CELL_GCM_LOCATION_LOCAL) { - if (index >= 2048) { - cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong local index (%d)", index); - return 0; - } - return vm::read64(g_fxo->get()->gcm_info.label_addr + ::offset32(&RsxReports::report) + index * 0x10); - } - - if (location == CELL_GCM_LOCATION_MAIN) { - if (index >= 1024 * 1024) { - cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index); - return 0; - } - return vm::read64(RSXIOMem.RealAddr(index * 0x10)); - } - - cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong location (%d)", location); - return 0; + // NOTE: No error checkings + return cellGcmGetReportDataAddressLocation(index, location)->timer; } //---------------------------------------------------------------------------- @@ -365,25 +341,26 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr contex cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress); const auto gcm_cfg = g_fxo->get(); + std::lock_guard lock(gcm_cfg->gcmio_mutex); gcm_cfg->current_config.ioAddress = 0; gcm_cfg->current_config.localAddress = 0; - local_size = 0; - local_addr = 0; + gcm_cfg->local_size = 0; + gcm_cfg->local_addr = 0; - if (!local_size && !local_addr) + //if (!gcm_cfg->local_size && !gcm_cfg->local_addr) { - local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize - local_addr = rsx::constants::local_mem_base; - vm::falloc(local_addr, local_size, vm::video); + gcm_cfg->local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize + gcm_cfg->local_addr = rsx::constants::local_mem_base; + vm::falloc(gcm_cfg->local_addr, gcm_cfg->local_size, vm::video); } - cellGcmSys.warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size); + cellGcmSys.warning("*** local memory(addr=0x%x, size=0x%x)", gcm_cfg->local_addr, gcm_cfg->local_size); InitOffsetTable(); const auto render = rsx::get_current_renderer(); - if (system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB) + if (gcm_cfg->system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB) { cellGcmSys.warning("cellGcmInit(): 512MB io address space used"); render->main_mem_size = 0x20000000; @@ -401,8 +378,8 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr contex gcm_cfg->current_config.ioSize = ioSize; gcm_cfg->current_config.ioAddress = ioAddress; - gcm_cfg->current_config.localSize = local_size; - gcm_cfg->current_config.localAddress = local_addr; + gcm_cfg->current_config.localSize = gcm_cfg->local_size; + gcm_cfg->current_config.localAddress = gcm_cfg->local_addr; gcm_cfg->current_config.memoryFrequency = 650000000; gcm_cfg->current_config.coreFrequency = 500000000; @@ -446,7 +423,7 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr contex render->isHLE = true; render->label_addr = gcm_cfg->gcm_info.label_addr; render->device_addr = gcm_cfg->gcm_info.context_addr; - render->local_mem_size = local_size; + render->local_mem_size = gcm_cfg->local_size; render->init(gcm_cfg->gcm_info.control_addr - 0x40); return CELL_OK; @@ -855,7 +832,7 @@ error_code cellGcmInitSystemMode(u64 mode) { cellGcmSys.trace("cellGcmInitSystemMode(mode=0x%x)", mode); - system_mode = mode; + g_fxo->get()->system_mode = mode; return CELL_OK; } @@ -930,7 +907,7 @@ error_code cellGcmAddressToOffset(u32 address, vm::ptr offset) // Address in main memory else check else { - const u32 upper12Bits = offsetTable.ioAddress[address >> 20]; + const u32 upper12Bits = g_fxo->get()->offsetTable.ioAddress[address >> 20]; // If the address is mapped in IO if (upper12Bits != 0xFFFF) @@ -951,29 +928,31 @@ u32 cellGcmGetMaxIoMapSize() { cellGcmSys.trace("cellGcmGetMaxIoMapSize()"); - return rsx::get_current_renderer()->main_mem_size - reserved_size; + return rsx::get_current_renderer()->main_mem_size - g_fxo->get()->reserved_size; } void cellGcmGetOffsetTable(vm::ptr table) { cellGcmSys.trace("cellGcmGetOffsetTable(table=*0x%x)", table); - table->ioAddress = offsetTable.ioAddress; - table->eaAddress = offsetTable.eaAddress; + const auto cfg = g_fxo->get(); + + table->ioAddress = cfg->offsetTable.ioAddress; + table->eaAddress = cfg->offsetTable.eaAddress; } error_code cellGcmIoOffsetToAddress(u32 ioOffset, vm::ptr address) { cellGcmSys.trace("cellGcmIoOffsetToAddress(ioOffset=0x%x, address=*0x%x)", ioOffset, address); - const u32 upper12Bits = offsetTable.eaAddress[ioOffset >> 20]; + const u32 addr = gcmIoOffsetToAddress(ioOffset); - if (static_cast(upper12Bits) < 0) + if (!addr) { return CELL_GCM_ERROR_FAILURE; } - *address = (upper12Bits << 20) | (ioOffset & 0xFFFFF); + *address = addr; return CELL_OK; } @@ -990,16 +969,18 @@ error_code gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict) return error; } + // Assume lock is acquired + const auto cfg = g_fxo->get(); ea >>= 20, io >>= 20, size >>= 20; // Fill the offset table for (u32 i = 0; i < size; i++) { - offsetTable.ioAddress[ea + i] = io + i; - offsetTable.eaAddress[io + i] = ea + i; + cfg->offsetTable.ioAddress[ea + i] = io + i; + cfg->offsetTable.eaAddress[io + i] = ea + i; } - IoMapTable[ea] = size; + cfg->IoMapTable[ea] = size; return CELL_OK; } @@ -1007,6 +988,9 @@ error_code cellGcmMapEaIoAddress(u32 ea, u32 io, u32 size) { cellGcmSys.warning("cellGcmMapEaIoAddress(ea=0x%x, io=0x%x, size=0x%x)", ea, io, size); + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + return gcmMapEaIoAddress(ea, io, size, false); } @@ -1016,6 +1000,9 @@ error_code cellGcmMapEaIoAddressWithFlags(u32 ea, u32 io, u32 size, u32 flags) verify(HERE), flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/; + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + return gcmMapEaIoAddress(ea, io, size, true); } @@ -1023,17 +1010,17 @@ error_code cellGcmMapLocalMemory(vm::ptr address, vm::ptr size) { cellGcmSys.warning("cellGcmMapLocalMemory(address=*0x%x, size=*0x%x)", address, size); - if (!local_addr && !local_size && vm::falloc(local_addr = rsx::constants::local_mem_base, local_size = 0xf900000 /* TODO */, vm::video)) + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + + if (!cfg->local_addr && !cfg->local_size && vm::falloc(cfg->local_addr = rsx::constants::local_mem_base, cfg->local_size = 0xf900000 /* TODO */, vm::video)) { - *address = local_addr; - *size = local_size; - } - else - { - return CELL_GCM_ERROR_FAILURE; + *address = cfg->local_addr; + *size = cfg->local_size; + return CELL_OK; } - return CELL_OK; + return CELL_GCM_ERROR_FAILURE; } error_code cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) @@ -1042,10 +1029,13 @@ error_code cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) if (!size || (ea & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE; + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + // Use the offset table to find the next free io address - for (u32 io = 0, end = (rsx::get_current_renderer()->main_mem_size - reserved_size) >> 20, unmap_count = 1; io < end; unmap_count++) + for (u32 io = 0, end = (rsx::get_current_renderer()->main_mem_size - cfg->reserved_size) >> 20, unmap_count = 1; io < end; unmap_count++) { - if (static_cast(offsetTable.eaAddress[io + unmap_count - 1]) < 0) + if (static_cast(cfg->offsetTable.eaAddress[io + unmap_count - 1]) < 0) { if (unmap_count >= (size >> 20)) { @@ -1079,12 +1069,15 @@ error_code cellGcmReserveIoMapSize(u32 size) return CELL_GCM_ERROR_INVALID_ALIGNMENT; } + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + if (size > cellGcmGetMaxIoMapSize()) { return CELL_GCM_ERROR_INVALID_VALUE; } - reserved_size += size; + cfg->reserved_size += size; return CELL_OK; } @@ -1092,48 +1085,60 @@ error_code cellGcmUnmapEaIoAddress(u32 ea) { cellGcmSys.warning("cellGcmUnmapEaIoAddress(ea=0x%x)", ea); - if (const u32 size = IoMapTable[ea >>= 20].exchange(0)) + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + + if (const u32 size = cfg->IoMapTable[ea >> 20]) { - const u32 io = offsetTable.ioAddress[ea]; + u32 io = cfg->offsetTable.ioAddress[ea]; + + if (auto error = sys_rsx_context_iounmap(0x55555555, io, size)) + { + return error; + } + + ea >>= 20, io >>= 20; + + const auto render = rsx::get_current_renderer(); for (u32 i = 0; i < size; i++) { - RSXIOMem.io[ea + i].raw() = offsetTable.ioAddress[ea + i] = 0xFFFF; - RSXIOMem.ea[io + i].raw() = offsetTable.eaAddress[io + i] = 0xFFFF; + cfg->offsetTable.ioAddress[ea + i] = 0xFFFF; + cfg->offsetTable.eaAddress[io + i] = 0xFFFF; } - std::atomic_thread_fence(std::memory_order_seq_cst); - } - else - { - return CELL_GCM_ERROR_FAILURE; + cfg->IoMapTable[ea] = 0; + return CELL_OK; } - return CELL_OK; + return CELL_GCM_ERROR_FAILURE; } error_code cellGcmUnmapIoAddress(u32 io) { cellGcmSys.warning("cellGcmUnmapIoAddress(io=0x%x)", io); - if (u32 size = IoMapTable[RSXIOMem.ea[io >>= 20]].exchange(0)) - { - const u32 ea = offsetTable.eaAddress[io]; + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); - for (u32 i = 0; i < size; i++) + if (u32 ea = cfg->offsetTable.eaAddress[io >>= 20], size = cfg->IoMapTable[ea]; size) + { + if (auto error = sys_rsx_context_iounmap(0x55555555, io, size)) { - RSXIOMem.io[ea + i].raw() = offsetTable.ioAddress[ea + i] = 0xFFFF; - RSXIOMem.ea[io + i].raw() = offsetTable.eaAddress[io + i] = 0xFFFF; + return error; } - std::atomic_thread_fence(std::memory_order_seq_cst); - } - else - { - return CELL_GCM_ERROR_FAILURE; + const auto render = rsx::get_current_renderer(); + for (u32 i = 0; i < size; i++) + { + cfg->offsetTable.ioAddress[ea + i] = 0xFFFF; + cfg->offsetTable.eaAddress[io + i] = 0xFFFF; + } + + return CELL_OK; } - return CELL_OK; + return CELL_GCM_ERROR_FAILURE; } error_code cellGcmUnreserveIoMapSize(u32 size) @@ -1145,12 +1150,15 @@ error_code cellGcmUnreserveIoMapSize(u32 size) return CELL_GCM_ERROR_INVALID_ALIGNMENT; } - if (size > reserved_size) + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + + if (size > cfg->reserved_size) { return CELL_GCM_ERROR_INVALID_VALUE; } - reserved_size -= size; + cfg->reserved_size -= size; return CELL_OK; } @@ -1375,7 +1383,7 @@ static std::pair getNextCommandBufferBeginEnd(u32 current) static u32 getOffsetFromAddress(u32 address) { - const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits + const u32 upper = g_fxo->get()->offsetTable.ioAddress[address >> 20]; // 12 bits verify(HERE), (upper != 0xFFFF); return (upper << 20) | (address & 0xFFFFF); } diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.h b/rpcs3/Emu/Cell/Modules/cellGcmSys.h index 3f8606835d..3786c4003c 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.h +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.h @@ -19,4 +19,26 @@ struct CellGcmOffsetTable vm::bptr eaAddress; }; +struct gcm_config +{ + u32 zculls_addr; + vm::ptr gcm_buffers = vm::null; + u32 tiles_addr; + u32 ctxt_addr; + + CellGcmConfig current_config; + CellGcmContextData current_context; + gcmInfo gcm_info; + + CellGcmOffsetTable offsetTable; + u16 IoMapTable[0xC00]{}; + shared_mutex gcmio_mutex; + + u64 system_mode = 0; + u32 local_size = 0; + u32 local_addr = 0; + + atomic_t reserved_size = 0; +}; + void InitOffsetTable(); diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 2ac4124ce7..e24f76f89a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -188,8 +188,6 @@ error_code sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_d dmaControl.put = 0; dmaControl.ref = 0; // Set later to -1 by cellGcmSys - memset(&RSXIOMem, 0xFF, sizeof(RSXIOMem)); - if (false/*system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB*/) rsx::get_current_renderer()->main_mem_size = 0x20000000; //512MB else @@ -251,8 +249,10 @@ error_code sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 f { sys_rsx.warning("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags); + const auto render = rsx::get_current_renderer(); + if (!size || io & 0xFFFFF || ea + u64{size} > rsx::constants::local_mem_base || ea & 0xFFFFF || size & 0xFFFFF || - context_id != 0x55555555 || rsx::get_current_renderer()->main_mem_size < io + u64{size}) + context_id != 0x55555555 || render->main_mem_size < io + u64{size}) { return CELL_EINVAL; } @@ -273,9 +273,13 @@ error_code sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 f for (u32 i = 0; i < size; i++) { - const u32 prev_ea = std::exchange(RSXIOMem.ea[io + i].raw(), ea + i); - if (prev_ea < 0xC00) RSXIOMem.io[prev_ea].raw() = 0xFFFF; // Clear previous mapping if exists - RSXIOMem.io[ea + i].raw() = io + i; + auto& table = render->iomap_table; + + // TODO: Investigate relaxed memory ordering + const u32 prev_ea = table.ea[io + i]; + table.ea[io + i].release((ea + i) << 20); + if (prev_ea + 1) table.io[prev_ea >> 20].release(-1); // Clear previous mapping if exists + table.io[ea + i].release((io + i) << 20); } return CELL_OK; @@ -291,8 +295,10 @@ error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size) { sys_rsx.warning("sys_rsx_context_iounmap(context_id=0x%x, io=0x%x, size=0x%x)", context_id, io, size); + const auto render = rsx::get_current_renderer(); + if (!size || size & 0xFFFFF || io & 0xFFFFF || context_id != 0x55555555 || - rsx::get_current_renderer()->main_mem_size < io + u64{size}) + render->main_mem_size < io + u64{size}) { return CELL_EINVAL; } @@ -301,12 +307,13 @@ error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size) std::scoped_lock lock(s_rsxmem_mtx); - const u32 end = (io >>= 20) + (size >>= 20); - - while (io < end) + for (const u32 end = (io >>= 20) + (size >>= 20); io < end;) { - const u32 ea_entry = std::exchange(RSXIOMem.ea[io++].raw(), 0xFFFF); - if (ea_entry < 0xC00) RSXIOMem.io[ea_entry].raw() = 0xFFFF; + auto& table = render->iomap_table; + + const u32 ea_entry = table.ea[io]; + table.ea[io++].release(-1); + if (ea_entry + 1) table.io[ea_entry >> 20].release(-1); } return CELL_OK; diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index e0e017c2b6..70e59c1843 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -11,6 +11,7 @@ namespace rsx FIFO_control::FIFO_control(::rsx::thread* pctrl) { m_ctrl = pctrl->ctrl; + m_iotable = &pctrl->iomap_table; } void FIFO_control::inc_get(bool wait) @@ -57,7 +58,7 @@ namespace rsx { if (m_ctrl->get == get) { - if (const auto addr = RSXIOMem.RealAddr(m_memwatch_addr)) + if (const u32 addr = m_iotable->get_addr(m_memwatch_addr); addr + 1) { m_memwatch_addr = get; m_memwatch_cmp = vm::read32(addr); @@ -119,7 +120,7 @@ namespace rsx { if (m_internal_get == m_memwatch_addr) { - if (const auto addr = RSXIOMem.RealAddr(m_memwatch_addr)) + if (const u32 addr = m_iotable->get_addr(m_memwatch_addr); addr + 1) { if (vm::read32(addr) == m_memwatch_cmp) { @@ -134,7 +135,7 @@ namespace rsx m_memwatch_cmp = 0; } - if (u32 addr = RSXIOMem.RealAddr(m_internal_get)) + if (const u32 addr = m_iotable->get_addr(m_internal_get); addr + 1) { m_cmd = vm::read32(addr); } @@ -163,8 +164,8 @@ namespace rsx } // Validate the args ptr if the command attempts to read from it - m_args_ptr = RSXIOMem.RealAddr(m_internal_get + 4); - if (!m_args_ptr) [[unlikely]] + m_args_ptr = m_iotable->get_addr(m_internal_get + 4); + if (m_args_ptr == -1) [[unlikely]] { // Optional recovery data.reg = FIFO_ERROR; diff --git a/rpcs3/Emu/RSX/RSXFIFO.h b/rpcs3/Emu/RSX/RSXFIFO.h index d70918f72f..72c0eebcfb 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.h +++ b/rpcs3/Emu/RSX/RSXFIFO.h @@ -9,6 +9,7 @@ namespace rsx { class thread; + struct rsx_iomap_table; namespace FIFO { @@ -112,6 +113,7 @@ namespace rsx { private: RsxDmaControl* m_ctrl = nullptr; + rsx::rsx_iomap_table* m_iotable; u32 m_internal_get = 0; u32 m_memwatch_addr = 0; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f637ea4b85..f37ff0547a 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -35,7 +35,6 @@ bool user_asked_for_frame_capture = false; bool capture_current_frame = false; rsx::frame_trace_data frame_debug; rsx::frame_capture_data frame_capture; -RSXIOTable RSXIOMem; extern CellGcmOffsetTable offsetTable; extern thread_local std::string(*g_tls_log_prefix)(); @@ -68,9 +67,9 @@ namespace rsx case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER: case CELL_GCM_LOCATION_MAIN: { - if (u32 result = RSXIOMem.RealAddr(offset)) + if (const u32 ea = render->iomap_table.get_addr(offset); ea + 1) { - return result; + return ea; } msg = "RSXIO memory not mapped!"sv; @@ -90,9 +89,9 @@ namespace rsx case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN: { - if (u32 result = offset < 0x1000000 ? RSXIOMem.RealAddr(0x0e000000 + offset) : 0) + if (const u32 ea = offset < 0x1000000 ? render->iomap_table.get_addr(0x0e000000 + offset) : -1; ea + 1) { - return result; + return ea; } msg = "RSXIO REPORT memory not mapped!"sv; @@ -617,10 +616,11 @@ namespace rsx while (true) { // Wait for external pause events - if (external_interrupt_lock.load()) + if (external_interrupt_lock) { external_interrupt_ack.store(true); - while (external_interrupt_lock.load()) _mm_pause(); + + while (external_interrupt_lock) _mm_pause(); } // Note a possible rollback address @@ -2390,13 +2390,13 @@ namespace rsx for (u32 ea = address >> 20, end = ea + (size >> 20); ea < end; ea++) { - u32 io = RSXIOMem.io[ea]; + const u32 io = utils::ror32(iomap_table.io[ea], 20); - if (io < 512) + if (io + 1) { unmap_status[io / 64] |= 1ull << (io & 63); - RSXIOMem.ea[io].raw() = 0xFFFF; - RSXIOMem.io[ea].raw() = 0xFFFF; + iomap_table.ea[io].release(-1); + iomap_table.io[ea].release(-1); } } @@ -2414,12 +2414,20 @@ namespace rsx else { // TODO: Fix this - u32 ea = address >> 20, io = RSXIOMem.io[ea]; + u32 ea = address >> 20, io = iomap_table.io[ea]; - for (const u32 end = ea + (size >> 20); ea < end;) + if (io + 1) { - offsetTable.ioAddress[ea++] = 0xFFFF; - offsetTable.eaAddress[io++] = 0xFFFF; + io >>= 20; + + const auto cfg = g_fxo->get(); + std::lock_guard lock(cfg->gcmio_mutex); + + for (const u32 end = ea + (size >> 20); ea < end;) + { + cfg->offsetTable.ioAddress[ea++] = 0xFFFF; + cfg->offsetTable.eaAddress[io++] = 0xFFFF; + } } } @@ -2460,14 +2468,19 @@ namespace rsx //Pause/cont wrappers for FIFO ctrl. Never call this from rsx thread itself! void thread::pause() { - external_interrupt_lock.store(true); - while (!external_interrupt_ack.load()) + while (external_interrupt_lock.exchange(true)) [[unlikely]] + { + _mm_pause(); + } + + while (!external_interrupt_ack) { if (Emu.IsStopped()) break; _mm_pause(); } + external_interrupt_ack.store(false); } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 527b564e44..9fe3a7afa6 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -27,38 +27,32 @@ extern u64 get_guest_system_time(); extern u64 get_system_time(); -struct RSXIOTable -{ - atomic_t ea[4096]; - atomic_t io[3072]; - - // try to get the real address given a mapped address - // return non zero on success - inline u32 RealAddr(u32 offs) - { - u32 result = this->ea[offs >> 20].load(); - - if (static_cast(result) < 0) - { - return 0; - } - - result <<= 20; result |= (offs & 0xFFFFF); - - ASSUME(result != 0); - - return result; - } -}; - extern bool user_asked_for_frame_capture; extern bool capture_current_frame; extern rsx::frame_trace_data frame_debug; extern rsx::frame_capture_data frame_capture; -extern RSXIOTable RSXIOMem; namespace rsx { + struct rsx_iomap_table + { + std::array, 4096> ea; + std::array, 4096> io; + + rsx_iomap_table() noexcept + { + std::fill(ea.begin(), ea.end(), -1); + std::fill(io.begin(), io.end(), -1); + } + + // Try to get the real address given a mapped address + // Returns -1 on failure + u32 get_addr(u32 offs) const noexcept + { + return this->ea[offs >> 20] | (offs & 0xFFFFF); + } + }; + enum framebuffer_creation_context : u8 { context_draw = 0, @@ -603,6 +597,7 @@ namespace rsx public: RsxDmaControl* ctrl = nullptr; + rsx_iomap_table iomap_table; u32 restore_point = 0; atomic_t external_interrupt_lock{ false }; atomic_t external_interrupt_ack{ false }; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index ecc2415d99..ef7d7077c7 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -208,7 +208,11 @@ namespace rsx return; } - vm::_ref>(verify(HERE, RSXIOMem.RealAddr(0xf100000 + (index * 0x40)))).store( + const u32 addr = rsx->iomap_table.get_addr(0xf100000 + (index * 0x40)); + + verify(HERE), addr != -1; + + vm::_ref>(addr).store( { rsx->timestamp(), 0 diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 637266f5ca..ff25abccc8 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -120,12 +120,10 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* return table; }; - if (const auto render = rsx::get_current_renderer()) + if (const auto render = rsx::get_current_renderer(); render && + render->iomap_table.get_addr(render->ctrl->get) + 1) { - if (RSXIOMem.RealAddr(render->ctrl->get.load())) - { - m_addr = render->ctrl->get.load(); - } + m_addr = render->ctrl->get; } m_list_commands = l_addRSXTab(m_list_commands, tr("RSX Commands"), 4); @@ -210,24 +208,20 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* //Events connect(b_goto_get, &QAbstractButton::clicked, [this]() { - if (const auto render = rsx::get_current_renderer()) + if (const auto render = rsx::get_current_renderer(); render && + render->iomap_table.get_addr(render->ctrl->get) + 1) { - if (RSXIOMem.RealAddr(render->ctrl->get.load())) - { - m_addr = render->ctrl->get.load(); - UpdateInformation(); - } + m_addr = render->ctrl->get; + UpdateInformation(); } }); connect(b_goto_put, &QAbstractButton::clicked, [this]() { - if (const auto render = rsx::get_current_renderer()) + if (const auto render = rsx::get_current_renderer(); render && + render->iomap_table.get_addr(render->ctrl->put) + 1) { - if (RSXIOMem.RealAddr(render->ctrl->put.load())) - { - m_addr = render->ctrl->put.load(); - UpdateInformation(); - } + m_addr = render->ctrl->put; + UpdateInformation(); } }); connect(m_addr_line, &QLineEdit::returnPressed, [this]() @@ -604,9 +598,10 @@ void rsx_debugger::GetMemory() address_item->setData(Qt::UserRole, addr); m_list_commands->setItem(i, 0, address_item); - if (vm::check_addr(RSXIOMem.RealAddr(addr))) + if (const u32 ea = rsx::get_current_renderer()->iomap_table.get_addr(addr); + ea + 1) { - u32 cmd = *vm::get_super_ptr(RSXIOMem.RealAddr(addr)); + u32 cmd = *vm::get_super_ptr(ea); u32 count = (cmd >> 18) & 0x7ff; m_list_commands->setItem(i, 1, new QTableWidgetItem(qstr(fmt::format("%08x", cmd)))); m_list_commands->setItem(i, 2, new QTableWidgetItem(DisAsmCommand(cmd, count, addr))); @@ -843,7 +838,7 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 ioAddr) } else { - auto args = vm::get_super_ptr(RSXIOMem.RealAddr(ioAddr + 4)); + const auto args = vm::get_super_ptr(rsx::get_current_renderer()->iomap_table.get_addr(ioAddr + 4)); u32 index = 0; switch((cmd & 0x3ffff) >> 2)