Skip to content

Commit

Permalink
cpu: cache software/hardware breakpoint enabled status for faster exe…
Browse files Browse the repository at this point in the history
…cution
  • Loading branch information
JaCzekanski committed Apr 22, 2020
1 parent ebe8889 commit 2296d8c
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 40 deletions.
44 changes: 17 additions & 27 deletions src/cpu/cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,26 @@ void CPU::saveStateForException() {
}

void CPU::handleHardwareBreakpoints() {
if (cop0.dcic.codeBreakpointEnabled()) {
if (((PC ^ cop0.bpcm) & cop0.bpc) == 0) {
cop0.dcic.codeBreakpointHit = 1;
cop0.dcic.breakpointHit = 1;
instructions::exception(this, COP0::CAUSE::Exception::breakpoint);
}
if (((PC ^ cop0.bpcm) & cop0.bpc) == 0) {
cop0.dcic.codeBreakpointHit = 1;
cop0.dcic.breakpointHit = 1;
instructions::exception(this, COP0::CAUSE::Exception::breakpoint);
}
}

INLINE bool CPU::handleSoftwareBreakpoints() {
if (breakpoints.empty()) {
return false;
}
bool CPU::handleSoftwareBreakpoints() {
if (breakpoints.empty()) return false;

auto bp = breakpoints.find(PC);
if (bp != breakpoints.end() && bp->second.enabled) {
if (bp->second.singleTime) {
breakpoints.erase(bp);
sys->state = System::State::pause;
return true;
}
if (!bp->second.hit) {
bp->second.hitCount++;
bp->second.hit = true;
sys->state = System::State::pause;
if (bp == breakpoints.end()) return false;
if (!bp->second.enabled) return false;

return true;
}
bp->second.hit = false;
bp->second.hitCount++;
if (bp->second.singleTime) {
removeBreakpoint(PC);
}
return false;
sys->state = System::State::pause;
return true;
}

INLINE uint32_t CPU::fetchInstruction(uint32_t address) {
Expand Down Expand Up @@ -95,9 +84,10 @@ bool CPU::executeInstructions(int count) {

saveStateForException();
checkForInterrupts();
handleHardwareBreakpoints();

if (unlikely(handleSoftwareBreakpoints())) return false;
if (unlikely(breakpointsEnabled)) {
handleHardwareBreakpoints();
if (handleSoftwareBreakpoints()) return false;
}

_opcode = Opcode(fetchInstruction(PC));
const auto& op = instructions::OpcodeTable[_opcode.op];
Expand Down
16 changes: 14 additions & 2 deletions src/cpu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ struct CPU {
bool icacheEnabled;
CacheLine icache[1024];

bool breakpointsEnabled = false;

CPU(System* sys);
void checkForInterrupts();
INLINE void moveLoadDelaySlots();
Expand Down Expand Up @@ -118,7 +120,7 @@ struct CPU {

void saveStateForException();
void handleHardwareBreakpoints();
INLINE bool handleSoftwareBreakpoints();
bool handleSoftwareBreakpoints();
INLINE uint32_t fetchInstruction(uint32_t address);
bool executeInstructions(int count);

Expand All @@ -127,14 +129,24 @@ struct CPU {
struct Breakpoint {
bool enabled = true;
int hitCount = 0;
bool hit = false;
bool singleTime = false;

Breakpoint() = default;
Breakpoint(bool singleTime) : singleTime(singleTime) {}
};
std::unordered_map<uint32_t, Breakpoint> breakpoints;

// Helper
void addBreakpoint(uint32_t address, Breakpoint bp = Breakpoint(true)) {
breakpoints[address] = bp;
updateBreakpointsFlag();
}
void removeBreakpoint(uint32_t address) {
breakpoints.erase(address);
updateBreakpointsFlag();
}
void updateBreakpointsFlag() { breakpointsEnabled = !breakpoints.empty() || cop0.dcic.codeBreakpointEnabled(); }

template <class Archive>
void serialize(Archive& ar) {
ar(PC, nextPC, inBranchDelay, branchTaken);
Expand Down
1 change: 1 addition & 0 deletions src/cpu/instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ void op_cop0(CPU *cpu, Opcode i) {
// Move to co-processor zero (from cpu reg)
// MTC0 rt, cop0.rd
cpu->cop0.write(i.rd, cpu->reg[i.rt]);
cpu->updateBreakpointsFlag();
break;

case 16:
Expand Down
2 changes: 1 addition & 1 deletion src/platform/headless/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ int main(int argc, char **argv) {
}

// Breakpoint on BIOS Shell execution
cpu->breakpoints.emplace(0x80030000, mips::CPU::Breakpoint(true));
cpu->addBreakpoint(0x80030000);

cpu->biosLog = false;
cpu->debugOutput = false;
Expand Down
17 changes: 8 additions & 9 deletions src/platform/windows/gui/debug/cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void CPU::debuggerWindow(System* sys) {
}
ImGui::SameLine();
if (ImGui::Button("Step over")) {
sys->cpu->breakpoints.emplace(sys->cpu->PC + 4, mips::CPU::Breakpoint(true));
sys->cpu->addBreakpoint(sys->cpu->PC + 4);
sys->state = System::State::run;
}
ImGui::SameLine();
Expand Down Expand Up @@ -229,9 +229,9 @@ void CPU::debuggerWindow(System* sys) {
.c_str())) {
auto bp = sys->cpu->breakpoints.find(address);
if (bp == sys->cpu->breakpoints.end()) {
sys->cpu->breakpoints.emplace(address, mips::CPU::Breakpoint());
sys->cpu->addBreakpoint(address, {});
} else {
sys->cpu->breakpoints.erase(bp);
sys->cpu->removeBreakpoint(address);
}
}

Expand All @@ -256,13 +256,12 @@ void CPU::debuggerWindow(System* sys) {
auto breakpointExist = bp != sys->cpu->breakpoints.end();

if (ImGui::Selectable("Run to line")) {
sys->cpu->breakpoints.emplace(contextMenuAddress, mips::CPU::Breakpoint(true));
sys->cpu->addBreakpoint(contextMenuAddress);
sys->state = System::State::run;
}

if (breakpointExist && ImGui::Selectable("Remove breakpoint")) sys->cpu->breakpoints.erase(bp);
if (!breakpointExist && ImGui::Selectable("Add breakpoint"))
sys->cpu->breakpoints.emplace(contextMenuAddress, mips::CPU::Breakpoint());
if (breakpointExist && ImGui::Selectable("Remove breakpoint")) sys->cpu->removeBreakpoint(contextMenuAddress);
if (!breakpointExist && ImGui::Selectable("Add breakpoint")) sys->cpu->addBreakpoint(contextMenuAddress, {});

ImGui::EndPopup();
}
Expand Down Expand Up @@ -335,7 +334,7 @@ void CPU::breakpointsWindow(System* sys) {
if (ImGui::BeginPopupContextItem("breakpoint_menu")) {
auto breakpointExist = sys->cpu->breakpoints.find(selectedBreakpoint) != sys->cpu->breakpoints.end();

if (breakpointExist && ImGui::Selectable("Remove")) sys->cpu->breakpoints.erase(selectedBreakpoint);
if (breakpointExist && ImGui::Selectable("Remove")) sys->cpu->removeBreakpoint(selectedBreakpoint);
if (ImGui::Selectable("Add")) showPopup = true;

ImGui::EndPopup();
Expand All @@ -351,7 +350,7 @@ void CPU::breakpointsWindow(System* sys) {
ImGui::PushItemWidth(80);
if (ImGui::InputText("", addressInput, 10, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue)
&& sscanf(addressInput, "%x", &address) == 1) {
sys->cpu->breakpoints.emplace(address, mips::CPU::Breakpoint());
sys->cpu->addBreakpoint(address, {});
ImGui::CloseCurrentPopup();
}
ImGui::PopItemWidth();
Expand Down
2 changes: 1 addition & 1 deletion src/system_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void bootstrap(std::unique_ptr<System>& sys) {
sys->loadBios(config.bios);

// Breakpoint on BIOS Shell execution
sys->cpu->breakpoints.emplace(0x80030000, mips::CPU::Breakpoint(true));
sys->cpu->addBreakpoint(0x80030000);

// Execute BIOS till breakpoint hit (shell is about to be executed)
while (sys->state == System::State::run) sys->emulateFrame();
Expand Down

0 comments on commit 2296d8c

Please sign in to comment.