Skip to content

Commit

Permalink
Merge pull request #19707 from hrydgard/core-improvements
Browse files Browse the repository at this point in the history
Core improvements: Run-from-breakpoint fix, add two new step types
  • Loading branch information
hrydgard authored Dec 8, 2024
2 parents 50fadd1 + e0a1d65 commit d21de81
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 34 deletions.
49 changes: 33 additions & 16 deletions Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ static std::set<CoreStopRequestFunc> stopFuncs;

// This can be read and written from ANYWHERE.
volatile CoreState coreState = CORE_STEPPING_CPU;
CoreState preGeCoreState = CORE_BOOT_ERROR;
// If true, core state has been changed, but JIT has probably not noticed yet.
volatile bool coreStatePending = false;

static bool powerSaving = false;
static bool g_breakAfterFrame = false;

static MIPSExceptionInfo g_exceptionInfo;

Expand Down Expand Up @@ -175,6 +177,10 @@ void Core_RunLoopUntil(u64 globalticks) {
return;
case CORE_RUNNING_CPU:
mipsr4k.RunLoopUntil(globalticks);
if (g_breakAfterFrame && coreState == CORE_NEXTFRAME) {
g_breakAfterFrame = false;
coreState = CORE_STEPPING_CPU;
}
break; // Will loop around to go to RUNNING_GE or NEXTFRAME, which will exit.
case CORE_RUNNING_GE:
switch (gpu->ProcessDLQueue()) {
Expand All @@ -184,33 +190,47 @@ void Core_RunLoopUntil(u64 globalticks) {
case DLResult::Error:
// We should elegantly report the error, or I guess ignore it.
hleFinishSyscallAfterGe();
coreState = CORE_RUNNING_CPU;
coreState = preGeCoreState;
break;
case DLResult::Stall:
case DLResult::Done:
// Done executing for now
hleFinishSyscallAfterGe();
coreState = CORE_RUNNING_CPU;
coreState = preGeCoreState;
break;
default:
_dbg_assert_(false);
hleFinishSyscallAfterGe();
coreState = CORE_RUNNING_CPU;
coreState = preGeCoreState;
break;
}
break;
}
}
}

// Should only be called from GPUCommon functions (called from sceGe functions).
void Core_SwitchToGe() {
// TODO: This should be an atomic exchange. Or we add bitflags into coreState.
preGeCoreState = coreState;
coreState = CORE_RUNNING_GE;
}

bool Core_RequestCPUStep(CPUStepType type, int stepSize) {
std::lock_guard<std::mutex> guard(g_stepMutex);
if (g_cpuStepCommand.type != CPUStepType::None) {
ERROR_LOG(Log::CPU, "Can't submit two steps in one host frame");
return false;
}
// Out-steps don't need a size.
_dbg_assert_(stepSize != 0 || type == CPUStepType::Out);
// Some step types don't need a size.
switch (type) {
case CPUStepType::Out:
case CPUStepType::Frame:
break;
default:
_dbg_assert_(stepSize != 0);
break;
}
g_cpuStepCommand = { type, stepSize };
return true;
}
Expand Down Expand Up @@ -291,27 +311,22 @@ static void Core_PerformCPUStep(MIPSDebugInterface *cpu, CPUStepType stepType, i

u32 breakpointAddress = frames[1].pc;

// If the current PC is on a breakpoint, the user doesn't want to do nothing.
g_breakpoints.SetSkipFirst(currentMIPS->pc);
g_breakpoints.AddBreakPoint(breakpointAddress, true);
Core_Resume();
break;
}
case CPUStepType::Frame:
{
g_breakAfterFrame = true;
Core_Resume();
break;
}
default:
// Not yet implemented
break;
}
}

static void Core_PerformGeStep(CPUStepType stepType) {
// TODO
}

// Should only be called from GPUCommon functions (called from sceGe functions).
void Core_SwitchToGe() {
coreState = CORE_RUNNING_GE;
}

static void Core_ProcessStepping(MIPSDebugInterface *cpu) {
Core_StateProcessed();

Expand Down Expand Up @@ -399,6 +414,8 @@ void Core_Break(const char *reason, u32 relatedAddress) {

// Free-threaded (or at least should be)
void Core_Resume() {
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
g_breakpoints.SetSkipFirst(currentMIPS->pc);
// Handle resuming from GE.
if (coreState == CORE_STEPPING_GE) {
coreState = CORE_RUNNING_GE;
Expand Down
1 change: 1 addition & 0 deletions Core/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum class CPUStepType {
Into,
Over,
Out,
Frame,
};

// Async, called from gui
Expand Down
5 changes: 3 additions & 2 deletions Core/HLE/HLE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ static int idleOp;
// Split syscall support. NOTE: This needs to be saved in DoState somehow!
static int splitSyscallEatCycles = 0;

// Stats
static double hleSteppingTime = 0.0;
static double hleFlipTime = 0.0;

struct HLEMipsCallInfo {
u32 func;
Expand Down Expand Up @@ -752,12 +755,10 @@ void *GetQuickSyscallFunc(MIPSOpcode op) {
return (void *)&CallSyscallWithoutFlags;
}

static double hleSteppingTime = 0.0;
void hleSetSteppingTime(double t) {
hleSteppingTime += t;
}

static double hleFlipTime = 0.0;
void hleSetFlipTime(double t) {
hleFlipTime = t;
}
Expand Down
98 changes: 82 additions & 16 deletions UI/ImDebugger/ImDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,50 @@ static const char *ThreadStatusToString(u32 status) {
return "(unk)";
}

void WaitIDToString(WaitType waitType, SceUID waitID, char *buffer, size_t bufSize) {
switch (waitType) {
case WAITTYPE_AUDIOCHANNEL:
snprintf(buffer, bufSize, "chan %d", (int)waitID);
return;
case WAITTYPE_IO:
// TODO: More detail
snprintf(buffer, bufSize, "fd: %d", (int)waitID);
return;
case WAITTYPE_ASYNCIO:
snprintf(buffer, bufSize, "id: %d", (int)waitID);
return;
case WAITTYPE_THREADEND:
case WAITTYPE_MUTEX:
case WAITTYPE_LWMUTEX:
case WAITTYPE_MODULE:
case WAITTYPE_MSGPIPE:
case WAITTYPE_FPL:
case WAITTYPE_VPL:
case WAITTYPE_MBX:
case WAITTYPE_EVENTFLAG:
case WAITTYPE_SEMA:
// Get the name of the thread
if (kernelObjects.IsValid(waitID)) {
auto obj = kernelObjects.GetFast<KernelObject>(waitID);
if (obj && obj->GetName()) {
truncate_cpy(buffer, bufSize, obj->GetName());
return;
}
}
break;
case WAITTYPE_DELAY:
case WAITTYPE_SLEEP:
case WAITTYPE_HLEDELAY:
case WAITTYPE_UMD:
truncate_cpy(buffer, bufSize, "-");
return;
default:
truncate_cpy(buffer, bufSize, "(unimpl)");
return;
}

}

void DrawThreadView(ImConfig &cfg) {
ImGui::SetNextWindowSize(ImVec2(420, 300), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Threads", &cfg.threadsOpen)) {
Expand All @@ -168,7 +212,8 @@ void DrawThreadView(ImConfig &cfg) {
}

std::vector<DebugThreadInfo> info = GetThreadsInfo();
if (ImGui::BeginTable("threads", 7, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
if (ImGui::BeginTable("threads", 8, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("Id", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("PC", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Entry", ImGuiTableColumnFlags_WidthFixed);
Expand All @@ -183,6 +228,8 @@ void DrawThreadView(ImConfig &cfg) {
const DebugThreadInfo &thread = info[i];
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%d", thread.id);
ImGui::TableNextColumn();
ImGui::PushID(i);
if (ImGui::Selectable(thread.name, cfg.selectedThread == i, ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_SpanAllColumns)) {
cfg.selectedThread = i;
Expand All @@ -200,16 +247,11 @@ void DrawThreadView(ImConfig &cfg) {
ImGui::TableNextColumn();
ImGui::TextUnformatted(ThreadStatusToString(thread.status));
ImGui::TableNextColumn();
if (thread.waitType != WAITTYPE_NONE) {
ImGui::TextUnformatted(getWaitTypeName(thread.waitType));
} else {
ImGui::TextUnformatted("N/A");
}
ImGui::TextUnformatted(getWaitTypeName(thread.waitType));
ImGui::TableNextColumn();
switch (thread.waitType) {
default:
ImGui::TextUnformatted("N/A");
}
char temp[64];
WaitIDToString(thread.waitType, thread.waitID, temp, sizeof(temp));
ImGui::TextUnformatted(temp);
if (ImGui::BeginPopup("threadPopup")) {
DebugThreadInfo &thread = info[i];
ImGui::Text("Thread: %s", thread.name);
Expand All @@ -218,16 +260,19 @@ void DrawThreadView(ImConfig &cfg) {
snprintf(temp, sizeof(temp), "%08x", thread.entrypoint);
System_CopyStringToClipboard(temp);
}
if (ImGui::MenuItem("Copy PC to clipboard")) {
if (ImGui::MenuItem("Copy thread PC to clipboard")) {
char temp[64];
snprintf(temp, sizeof(temp), "%08x", thread.curPC);
System_CopyStringToClipboard(temp);
}
if (ImGui::MenuItem("Kill thread")) {
// Dangerous!
sceKernelTerminateThread(thread.id);
}
if (ImGui::MenuItem("Force run")) {
__KernelResumeThreadFromWait(thread.id, 0);
if (thread.status == THREADSTATUS_WAIT) {
if (ImGui::MenuItem("Force run now")) {
__KernelResumeThreadFromWait(thread.id, 0);
}
}
ImGui::EndPopup();
}
Expand Down Expand Up @@ -1030,22 +1075,43 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, CoreStat
ImGui::BeginDisabled(coreState != CORE_STEPPING_CPU);

ImGui::SameLine();
if (ImGui::SmallButton("Step Into")) {
ImGui::Text("Step: ");
ImGui::SameLine();

if (ImGui::SmallButton("Into")) {
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
Core_RequestCPUStep(CPUStepType::Into, stepSize);
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("F11");
}

ImGui::SameLine();
if (ImGui::SmallButton("Step Over")) {
if (ImGui::SmallButton("Over")) {
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
Core_RequestCPUStep(CPUStepType::Over, stepSize);
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("F10");
}

ImGui::SameLine();
if (ImGui::SmallButton("Step Out")) {
if (ImGui::SmallButton("Out")) {
Core_RequestCPUStep(CPUStepType::Out, 0);
}

ImGui::SameLine();
if (ImGui::SmallButton("Frame")) {
Core_RequestCPUStep(CPUStepType::Frame, 0);
}

ImGui::SameLine();
ImGui::SmallButton("Skim");
if (ImGui::IsItemActive()) {
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
Core_RequestCPUStep(CPUStepType::Into, stepSize);
}

ImGui::EndDisabled();

ImGui::SameLine();
Expand Down

0 comments on commit d21de81

Please sign in to comment.