diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index 7f8d80bbb9..8ec6f4c2f8 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -87,6 +87,11 @@ namespace rsx return false; } + void FIFO_control::abort() + { + m_remaining_commands = 0; + } + void FIFO_control::read(register_pair& data) { const u32 put = read_put(); @@ -392,11 +397,8 @@ namespace rsx } case FIFO::FIFO_ERROR: { - // Error. Should reset the queue LOG_ERROR(RSX, "FIFO error: possible desync event"); - fifo_ctrl->set_get(restore_point); - fifo_ret_addr = saved_fifo_ret; - std::this_thread::sleep_for(1ms); + recover_fifo(); return; } } @@ -563,6 +565,13 @@ namespace rsx if (auto method = methods[reg]) { method(this, reg, value); + + if (invalid_command_interrupt_raised) + { + fifo_ctrl->abort(); + recover_fifo(); + return; + } } } while (fifo_ctrl->read_unsafe(command)); diff --git a/rpcs3/Emu/RSX/RSXFIFO.h b/rpcs3/Emu/RSX/RSXFIFO.h index 3308eb2a66..d9ba900ee2 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.h +++ b/rpcs3/Emu/RSX/RSXFIFO.h @@ -131,6 +131,7 @@ namespace rsx void inc_get(bool wait); void set_get(u32 get); void set_put(u32 put); + void abort(); template u32 read_put(); void read(register_pair& data); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index ed193c88e2..961e0f7007 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2340,6 +2340,15 @@ namespace rsx fifo_ctrl->sync_get(); } + void thread::recover_fifo() + { + // Error. Should reset the queue + fifo_ctrl->set_get(restore_point); + fifo_ret_addr = saved_fifo_ret; + std::this_thread::sleep_for(1ms); + invalid_command_interrupt_raised = false; + } + void thread::read_barrier(u32 memory_address, u32 memory_range) { zcull_ctrl->read_barrier(this, memory_address, memory_range); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index fbc48427ea..a3e614c6fb 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -519,6 +519,7 @@ namespace rsx atomic_t external_interrupt_lock{ false }; atomic_t external_interrupt_ack{ false }; void flush_fifo(); + void recover_fifo(); // Performance approximation counters struct diff --git a/rpcs3/Emu/RSX/gcm_enums.cpp b/rpcs3/Emu/RSX/gcm_enums.cpp index e0319adfbd..d0f36dd8b0 100644 --- a/rpcs3/Emu/RSX/gcm_enums.cpp +++ b/rpcs3/Emu/RSX/gcm_enums.cpp @@ -21,8 +21,8 @@ rsx::index_array_type rsx::to_index_array_type(u8 in) { switch (in) { - case 0: return rsx::index_array_type::u32; - case 1: return rsx::index_array_type::u16; + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return rsx::index_array_type::u32; + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return rsx::index_array_type::u16; } fmt::throw_exception("Unknown index array type %d" HERE, in); } diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index be539d4d43..bcb771d32b 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -448,6 +448,13 @@ enum CELL_GCM_SYSTEM_MODE_IOMAP_512MB = 1, }; +enum +{ + // Index Array Type + CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 = 0, + CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16 = 1, +}; + // GCM Texture enum { diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 9eda7663fd..079dcc8cf5 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -713,6 +713,19 @@ namespace rsx } } + void check_index_array_dma(thread* rsx, u32 reg, u32 arg) + { + // Check if either location or index type are invalid + if (arg & ~(CELL_GCM_LOCATION_MAIN | (CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16 << 4))) + { + // Ignore invalid value, recover + method_registers.registers[reg] = method_registers.register_previous_value; + rsx->invalid_command_interrupt_raised = true; + + LOG_ERROR(RSX, "Invalid NV4097_SET_INDEX_ARRAY_DMA value: 0x%x", arg); + } + } + template struct set_texture_dirty_bit { @@ -2911,6 +2924,7 @@ namespace rsx bind_array(); bind_range(); bind_range(); + bind(); //NV308A bind_range();