mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-04 11:45:18 +02:00
Add cpu.runUntilTime: run to a point in emulated time and break there
Lining a scripted repro up with a bug report ("about five seconds in, press
X") had no support at all. The only way to do it was to poll cpu.status in a
loop from the client, which is slow - a process spawn per poll, minutes for a
single run - and lands somewhere different every time, so the repro isn't one.
cpu.runUntilTime takes either an absolute `us` (as reported by cpu.status) or
`relativeUs` from now, resumes, and breaks when emulated time gets there. It
answers immediately with the target, and the usual cpu.stepping event follows
when it arrives. Anything else that stops the CPU first - a breakpoint, an
exception - cancels the deadline, the same way it cancels a pending step.
The deadline is held in microseconds, not ticks, and recomputed whenever
SetClockFrequencyHz() runs. Converting to a tick count once up front looks
right and isn't: games change the CPU clock while running, and CrossCraft
Classic goes 222 -> 333MHz during startup, which made a request for 3.0s stop
at 2.24s. With the recompute it stops at exactly 3000000us. Advance() also
shortens its slice to land on the deadline instead of up to a slice past it,
so repeated runs stop at the same instruction rather than somewhere in the
following frame.
Nothing is added to CoreTiming's event list, so savestates are unaffected -
the deadline is debugger session state and isn't serialized.
Also adds DebuggerRequest::ParamF64, since microseconds outgrow 32 bits after
about 71 minutes. Like the other Param* helpers it fails loudly on a missing
or unparseable value rather than defaulting.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
co-authored by
Claude Opus 5
parent
38cdc8bf68
commit
8120338530
@@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
#include "Common/Data/Text/Parsers.h"
|
||||
@@ -173,6 +174,41 @@ bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatB
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerRequest::ParamF64(const char *name, double *out, DebuggerParamType type) {
|
||||
const bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;
|
||||
|
||||
const JsonNode *node = data.get(name);
|
||||
if (!node) {
|
||||
if (required)
|
||||
Fail(StringFromFormat("Missing '%s' parameter", name));
|
||||
return !required;
|
||||
}
|
||||
|
||||
const auto tag = node->value.getTag();
|
||||
if (tag == JSON_NUMBER) {
|
||||
*out = node->value.toNumber();
|
||||
return true;
|
||||
}
|
||||
if (tag == JSON_STRING) {
|
||||
// Same escape hatch as the integer params: a string for values a JSON number would mangle.
|
||||
const char *s = node->value.toString();
|
||||
char *end = nullptr;
|
||||
const double val = strtod(s, &end);
|
||||
if (end != s && *end == '\0') {
|
||||
*out = val;
|
||||
return true;
|
||||
}
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: number required", name));
|
||||
return false;
|
||||
}
|
||||
if (tag == JSON_NULL && !required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerRequest::ParamBool(const char *name, bool *out, DebuggerParamType type) {
|
||||
bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;
|
||||
bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;
|
||||
|
||||
Reference in New Issue
Block a user