Skip to content

Commit b66381b

Browse files
committed
Add support for breakpoint synchronization across emulator instances.
1 parent 3a8a5dd commit b66381b

File tree

16 files changed

+123
-28
lines changed

16 files changed

+123
-28
lines changed

external/rlguipp/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cmake_minimum_required(VERSION 3.16)
22
project(RlGuiPp)
33

4-
add_library(rlguipp STATIC rlguipp.cpp rlguipp.hpp raygui4.h rlunicode.h dm_property_list.h syshelper.cpp syshelper.hpp)
4+
add_library(rlguipp STATIC rlguipp.cpp rlguipp.hpp raygui4.h rlunicode.h dm_property_list.h syshelper.cpp syshelper.hpp icons.h)
55
target_include_directories(rlguipp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
66
target_link_libraries(rlguipp PUBLIC raylib_static ghc_filesystem fmt::fmt)
77

external/rlguipp/icons.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ typedef enum {
279279
ICON_BURGER_MENU = 248,
280280
ICON_HELP2 = 249,
281281
ICON_FOLDER_DOWNLOADS = 250,
282-
ICON_251 = 251,
282+
ICON_ARROW_RIGHT_FILL_SMALL = 251,
283283
ICON_252 = 252,
284284
ICON_253 = 253,
285285
ICON_254 = 254,
@@ -542,7 +542,7 @@ unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = {
542542
0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU
543543
0x00000000, 0x07e003c0, 0x0c300c30, 0x06000c00, 0x01800300, 0x00000180, 0x01800180, 0x00000000, // ICON_HELP2
544544
0x00000000, 0x0042007e, 0x40027fc2, 0x42a24082, 0x408241c2, 0x47f24412, 0x7ffe4002, 0x00000000, // ICON_FOLDER_DOWNLOADS
545-
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
545+
0x00000000, 0x00000000, 0x00400000, 0x01c000c0, 0x01c003c0, 0x004000c0, 0x00000000, 0x00000000, // ICON_ARROW_RIGHT_FILL_SMALL
546546
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
547547
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253
548548
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254

src/cadmium.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,13 +1500,17 @@ void main()
15001500
_partialFrameTime -= 1000;
15011501
for(int i = 0; i < getFrameBoost(); ++i) {
15021502
_chipEmu->executeFrame();
1503+
bool breakpoint = false;
15031504
for(auto& unit : *_chipEmu) {
15041505
if(unit.isBreakpointTriggered()) {
15051506
_mainView = eDEBUGGER;
15061507
_debugger.setBreakpointTriggered(true);
1508+
breakpoint = true;
15071509
break;
15081510
}
15091511
}
1512+
if (!breakpoint)
1513+
_debugger.setBreakpointTriggered(false);
15101514
}
15111515
_fps.add(GetTime()*1000);
15121516
}

src/debugger.cpp

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -376,33 +376,40 @@ void Debugger::showBreakpoints(Font& font, const int lineSpacing)
376376
BeginTableView(area.height - (10 * 14.0f + 6), 3, &scroll);
377377
SetRowHeight(11);
378378
int count = -1;
379+
bool foundTriggeredBP = false;
379380
for (const auto& [address, bpinfo] : _breakpointCache) {
380381
auto execUnit = _core->executionUnit(bpinfo->unit);
381382
auto isChip8 = dynamic_cast<emu::IChip8Emulator*>(execUnit) != nullptr;
382383
++count;
383-
if (bpinfo->isEnabled && _isBreakpointTriggered && execUnit->getPC() == address)
384-
_selectedBreakpoint = count;
384+
//if (bpinfo->isEnabled && _triggeredBreakpointAddress == address && execUnit->getPC() == address)
385+
// _selectedBreakpoint = count;
385386
TableNextRow(11.0f, count == _selectedBreakpoint ? StyleManager::getStyleColor(gui::Style::BORDER_COLOR_NORMAL): Color{0,0,0,0});
386-
TableNextColumn(16, [&](Rectangle rect){
387+
TableNextColumn(24, [&](Rectangle rect){
388+
GuiDrawIcon(address == _triggeredBreakpointAddress ? ICON_ARROW_RIGHT_FILL_SMALL : ICON_NONE, rect.x - 2, rect.y - 3, 1, YELLOW);
389+
if (address == _triggeredBreakpointAddress && execUnit->getPC() == address)
390+
foundTriggeredBP = true;
387391
if (!GuiIsLocked() && IsMouseButtonPressed(0) && CheckCollisionPointRec(GetMousePosition(), rect)) {
388392
bpinfo->isEnabled = !bpinfo->isEnabled;
389-
_selectedBreakpoint = count;
393+
selectBreakpoint(count);
390394
}
391-
GuiDrawIcon(bpinfo->isEnabled ? ICON_BREAKPOINT : ICON_BREAKPOINT_OFF, rect.x, rect.y - 3, 1, RED);
395+
GuiDrawIcon(bpinfo->isEnabled ? ICON_BREAKPOINT : ICON_BREAKPOINT_OFF, rect.x + 6, rect.y - 3, 1, RED);
392396
});
393397
TableNextColumn(32, [&](Rectangle rect){
394398
if (!GuiIsLocked() && IsMouseButtonPressed(0) && CheckCollisionPointRec(GetMousePosition(), rect)) {
395-
_selectedBreakpoint = count;
399+
selectBreakpoint(count);
396400
}
397401
DrawTextClipped(font, fmt::format("{:04x}", address).c_str(), {rect.x + 2, rect.y + 2}, WHITE);
398402
});
399403
TableNextColumn(area.width - 50, [&](Rectangle rect){
400404
if (!GuiIsLocked() && IsMouseButtonPressed(0) && CheckCollisionPointRec(GetMousePosition(), rect)) {
401-
_selectedBreakpoint = count;
405+
selectBreakpoint(count);
402406
}
403407
DrawTextClipped(font, fmt::format("{} breakpoint", isChip8 ? "CHIP-8" : execUnit->name()).c_str(), {rect.x + 2, rect.y + 2}, WHITE);
404408
});
405409
}
410+
if (!foundTriggeredBP) {
411+
setBreakpointTriggered(false);
412+
}
406413
EndTableView();
407414
SetRowHeight(14);
408415
if (_selectedBreakpoint >= 0 && _selectedBreakpoint < _breakpointCache.size()) {
@@ -460,6 +467,17 @@ void Debugger::showBreakpoints(Font& font, const int lineSpacing)
460467
Space(GetContentAvailable().height);
461468
}
462469

470+
void Debugger::selectBreakpoint(int idx)
471+
{
472+
if (idx < 0 || idx >= _breakpointCache.size()) {
473+
_selectedBreakpoint = -1;
474+
_bpHitCount = "";
475+
return;
476+
}
477+
_selectedBreakpoint = idx;
478+
_bpHitCount = fmt::format("{}", _breakpointCache[idx].second->numHits);
479+
}
480+
463481
void Debugger::showGenericRegs(emu::GenericCpu& cpu, const RegPack& regs, const RegPack& oldRegs, Font& font, const int lineSpacing, const Vector2& pos) const
464482
{
465483
using namespace gui;
@@ -512,7 +530,7 @@ void Debugger::refreshBreakpoints()
512530
return a.first < b.first;
513531
}
514532
);
515-
_selectedBreakpoint = _breakpointCache.empty() ? -1 : 0;
533+
selectBreakpoint(_breakpointCache.empty() ? -1 : 0);
516534
}
517535

518536
const std::vector<std::pair<uint32_t,std::string>>& Debugger::disassembleNLinesBackwardsGeneric(emu::GenericCpu& cpu, uint32_t addr, int n)
@@ -544,6 +562,7 @@ void Debugger::toggleBreakpoint(emu::GenericCpu& cpu, uint32_t address)
544562
else {
545563
cpu.setBreakpoint(address, {.label = fmt::format("BP@{:x}", address), .type = emu::GenericCpu::BreakpointInfo::eTRANSIENT, .isEnabled = true, .unit = static_cast<uint8_t>(_activeInstructionsTab)});
546564
}
565+
selectBreakpoint(-1);
547566
refreshBreakpoints();
548567
}
549568

@@ -568,10 +587,31 @@ void Debugger::updateOctoBreakpoints(const emu::OctoCompiler& compiler)
568587
}
569588
}
570589
}
590+
selectBreakpoint(-1);
571591
refreshBreakpoints();
572592
}
573593

574594
bool Debugger::supportsStepOver() const
575595
{
576596
return _core->focussedExecutionUnit()->cpuID() != 1802;
577597
}
598+
599+
void Debugger::setBreakpointTriggered(bool triggered)
600+
{
601+
_isBreakpointTriggered = triggered;
602+
if (triggered) {
603+
int count = -1;
604+
for (const auto& [address, bpinfo] : _breakpointCache) {
605+
auto execUnit = _core->executionUnit(bpinfo->unit);
606+
auto isChip8 = dynamic_cast<emu::IChip8Emulator*>(execUnit) != nullptr;
607+
++count;
608+
if (bpinfo->isEnabled && execUnit->getPC() == address) {
609+
_triggeredBreakpointAddress = address;
610+
_selectedBreakpoint = count;
611+
}
612+
}
613+
}
614+
else {
615+
_triggeredBreakpointAddress = ~0;
616+
}
617+
}

src/debugger.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ class Debugger : public Highlighter
4848
void updateOctoBreakpoints(const emu::OctoCompiler& compiler);
4949
bool supportsStepOver() const;
5050
bool isControllingChip8() const { return dynamic_cast<emu::IChip8Emulator*>(_core->focussedExecutionUnit()) != nullptr; }
51-
void setBreakpointTriggered(bool triggered) { _isBreakpointTriggered = triggered; }
51+
void setBreakpointTriggered(bool triggered);
5252
bool isBreakpointTriggered() const { return _isBreakpointTriggered; }
5353
private:
5454
emu::IChip8Emulator* chip8Core();
5555
void showInstructions(emu::GenericCpu& cpu, Font& font, const int lineSpacing);
5656
void showBreakpoints(Font& font, const int lineSpacing);
57+
void selectBreakpoint(int idx);
5758
void showGenericRegs(emu::GenericCpu& cpu, const RegPack& regs, const RegPack& oldRegs, Font& font, const int lineSpacing, const Vector2& pos) const;
5859
void refreshBreakpoints();
5960
void toggleBreakpoint(emu::GenericCpu& cpu, uint32_t address);
@@ -72,6 +73,7 @@ class Debugger : public Highlighter
7273
std::vector<uint8_t> _memBackup;
7374
std::vector<std::pair<uint32_t, emu::GenericCpu::BreakpointInfo*>> _breakpointCache;
7475
int _selectedBreakpoint{-1};
76+
uint32_t _triggeredBreakpointAddress{std::numeric_limits<uint32_t>::max()};
7577
bool _isBreakpointTriggered{false};
7678
std::string _bpCondition;
7779
std::string _bpLogFormat;

src/emuhostex.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ void EmuHostEx::setPalette(const Palette& palette)
108108

109109
std::unique_ptr<IEmulationCore> EmuHostEx::create(Properties& properties, IEmulationCore* iother)
110110
{
111-
auto [variantName, emuCore] = CoreRegistry::create(*this, properties);
111+
auto [variantName, emuCore] = CoreRegistry::create(*this, properties, iother);
112112
if (emuCore) {
113113
emuCore->reset();
114114
_variantName = variantName;
@@ -202,6 +202,13 @@ std::unique_ptr<IEmulationCore> EmuHostEx::create(Properties& properties, IEmula
202202
#endif
203203
}
204204

205+
void EmuHostEx::resetAllBreakpoints()
206+
{
207+
if(!_chipEmu) return;
208+
for (auto& unit : *_chipEmu) {
209+
unit.removeAllBreakpoints();
210+
}
211+
}
205212

206213
void EmuHostEx::updateEmulatorOptions(const Properties& properties)
207214
{
@@ -267,6 +274,7 @@ bool EmuHostEx::loadRom(std::string_view filename, LoadOptions loadOpt)
267274
_colorPalette = _defaultPalette;
268275
auto fileData = loadFile(filename, Librarian::MAX_ROM_SIZE);
269276
if (fileData) {
277+
resetAllBreakpoints();
270278
return loadBinary(filename, *fileData, loadOpt);
271279
}
272280
}

src/emuhostex.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class EmuHostEx : public EmulatorHost
100100

101101
protected:
102102
std::unique_ptr<IEmulationCore> create(Properties& properties, IEmulationCore* iother = nullptr);
103+
void resetAllBreakpoints();
103104
virtual void whenRomLoaded(const std::string& filename, bool autoRun, emu::OctoCompiler* compiler, const std::string& source) {}
104105
virtual void whenEmuChanged(emu::IEmulationCore& emu) {}
105106
static int saturatedCast(double value) {

src/emulation/chip8generic.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,13 +361,18 @@ static uint32_t rgb332To888(uint8_t c)
361361
}
362362

363363

364-
Chip8GenericEmulator::Chip8GenericEmulator(EmulatorHost& host, Properties& props, IChip8Emulator* other)
364+
Chip8GenericEmulator::Chip8GenericEmulator(EmulatorHost& host, Properties& props, IEmulationCore* other)
365365
: Chip8GenericBase(Chip8GenericOptions::fromProperties(props).variant(), {})
366366
, _host(host)
367367
, _options(Chip8GenericOptions::fromProperties(props))
368368
, _opcodeHandler(0x10000, &Chip8GenericEmulator::opInvalid)
369369
{
370370
(void)registeredHleC8;
371+
if (other) {
372+
if (auto otherC8 = other->chip8Core()) {
373+
swapBreakpoints(*otherC8);
374+
}
375+
}
371376
ADDRESS_MASK = _options.ramSize - 1; //_options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 0xFFFFFF : _options.ramSize>4096 ? 0xFFFF : 0xFFF;
372377
SCREEN_WIDTH = _options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 256 : (_options.optAllowHires ? 128 : 64);
373378
SCREEN_HEIGHT = _options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 192 : (_options.optAllowHires ? 64 : (_options.optPalVideo ? 48 : 32));

src/emulation/chip8generic.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class Chip8GenericEmulator : public Chip8GenericBase
107107
int SCREEN_WIDTH;
108108
int SCREEN_HEIGHT;
109109

110-
Chip8GenericEmulator(EmulatorHost& host, Properties& props, IChip8Emulator* other = nullptr);
110+
Chip8GenericEmulator(EmulatorHost& host, Properties& props, IEmulationCore* other = nullptr);
111111
~Chip8GenericEmulator() override;
112112

113113
std::string name() const override

src/emulation/chip8strict.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ class Chip8StrictEmulator : public Chip8GenericBase
6363
, _host(host)
6464
, _options(Chip8StrictOptions::fromProperties(properties))
6565
{
66+
if (other) {
67+
if (auto otherC8 = other->chip8Core()) {
68+
swapBreakpoints(*otherC8);
69+
}
70+
}
6671
_memory.resize(_options.ramSize, 0);
6772
_rV = _memory.data() + _options.ramSize - 0x110;
6873
_systemTime.setFrequency(CPU_CLOCK_FREQUENCY>>3);

0 commit comments

Comments
 (0)