Debugger: Implement SPU breakpoints

This commit is contained in:
Eladash 2021-10-15 02:26:51 +03:00 committed by Ivan
parent ec6d6adebc
commit ccb2724fc4
10 changed files with 136 additions and 32 deletions

View file

@ -52,6 +52,7 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
case cpu_flag::signal: return "sig";
case cpu_flag::memory: return "mem";
case cpu_flag::pending: return "pend";
case cpu_flag::pending_recheck: return "pend-re";
case cpu_flag::dbg_global_pause: return "G-PAUSE";
case cpu_flag::dbg_pause: return "PAUSE";
case cpu_flag::dbg_step: return "STEP";
@ -624,6 +625,11 @@ cpu_thread::cpu_thread(u32 id)
}
g_threads_created++;
if (u32* pc2 = get_pc2())
{
*pc2 = umax;
}
}
void cpu_thread::cpu_wait(bs_t<cpu_flag> old)
@ -762,10 +768,18 @@ bool cpu_thread::check_state() noexcept
cpu_counter::add(this);
}
if ((state0 & (cpu_flag::pending + cpu_flag::temp)) == cpu_flag::pending)
constexpr auto pending_and_temp = (cpu_flag::pending + cpu_flag::temp);
if ((state0 & pending_and_temp) == cpu_flag::pending)
{
// Execute pending work
cpu_work();
if ((state1 ^ state) - pending_and_temp)
{
// Work could have changed flags
continue;
}
}
if (retval)

View file

@ -22,6 +22,7 @@ enum class cpu_flag : u32
signal, // Thread received a signal (HLE)
memory, // Thread must unlock memory mutex
pending, // Thread has postponed work
pending_recheck, // Thread needs to recheck if there is pending work before ::pending removal
dbg_global_pause, // Emulation paused
dbg_pause, // Thread paused

View file

@ -1503,10 +1503,30 @@ void spu_thread::cpu_work()
const u32 old_iter_count = cpu_work_iteration_count++;
const auto timeout = +g_cfg.core.mfc_transfers_timeout;
bool work_left = false;
if (has_active_local_bps)
{
if (local_breakpoints[pc / 4])
{
// Ignore repeatations until a different instruction is issued
if (pc != current_bp_pc)
{
// Breakpoint hit
state += cpu_flag::dbg_pause;
}
}
current_bp_pc = pc;
work_left = true;
}
else
{
current_bp_pc = umax;
}
const auto timeout = +g_cfg.core.mfc_transfers_timeout;
if (u32 shuffle_count = g_cfg.core.mfc_transfers_shuffling)
{
// If either MFC size exceeds limit or timeout has been reached execute pending MFC commands
@ -1544,7 +1564,19 @@ void spu_thread::cpu_work()
if (!work_left)
{
state -= cpu_flag::pending;
// No more pending work
state.atomic_op([](bs_t<cpu_flag>& flags)
{
if (flags & cpu_flag::pending_recheck)
{
// Do not really remove ::pending because external thread may have pushed more pending work
flags -= cpu_flag::pending_recheck;
}
else
{
flags -= cpu_flag::pending;
}
});
}
if (gen_interrupt)

View file

@ -843,6 +843,11 @@ public:
atomic_t<u8> debugger_float_mode = 0;
// PC-based breakpoint list
std::array<atomic_t<bool>, SPU_LS_SIZE / 4> local_breakpoints{};
atomic_t<bool> has_active_local_bps = false;
u32 current_bp_pc = umax;
void push_snr(u32 number, u32 value);
static void do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* ls);
bool do_dma_check(const spu_mfc_cmd& args);