Skip to content

Commit

Permalink
feature: DISASM view address breakpoint
Browse files Browse the repository at this point in the history
Signed-off-by: Maximilien Noal <noal.maximilien@gmail.com>
  • Loading branch information
maximilien-noal committed Oct 1, 2024
1 parent f49bd10 commit e7e60df
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 5 deletions.
9 changes: 9 additions & 0 deletions src/Spice86.Core/Emulator/VM/Breakpoint/BreakPointHolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,13 @@ public void TriggerBreakPointsWithAddressRange(long startAddress, long endAddres
TriggerMatchingBreakPoints(address);
}
}

/// <summary>
/// Determines whether there is an address breakpoint at the specified address.
/// </summary>
/// <param name="instructionAddress">The memory address to check.</param>
/// <returns>Whether there is an address breakpoint at the specified address.</returns>
public bool IsAddressBreakpointAt(long instructionAddress) {
return _addressBreakPoints.ContainsKey(instructionAddress);
}
}
9 changes: 9 additions & 0 deletions src/Spice86.Core/Emulator/VM/EmulatorBreakpointsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,13 @@ private void CheckBreakPoints() {
_cycleBreakPoints.TriggerMatchingBreakPoints(cycles);
}
}

/// <summary>
/// Determines whether there is an address breakpoint at the specified address.
/// </summary>
/// <param name="instructionAddress">The memory address to check.</param>
/// <returns>Whether there is an address breakpoint at the specified address.</returns>
public bool IsAddressBreakpointAt(long instructionAddress) {
return _executionBreakPoints.IsAddressBreakpointAt(instructionAddress);
}
}
1 change: 1 addition & 0 deletions src/Spice86/Models/Debugging/CpuInstructionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Spice86.Models.Debugging;

public partial class CpuInstructionInfo : ObservableObject {
[ObservableProperty] private string? _stringRepresentation;
[ObservableProperty] private bool _hasBreakpoint;
[ObservableProperty] private bool _isCsIp;
[ObservableProperty] private uint _address;
[ObservableProperty] private string? _segmentedAddress;
Expand Down
1 change: 1 addition & 0 deletions src/Spice86/Spice86DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ public Spice86DependencyInjection(ILoggerService loggerService, Configuration co
debugWindowViewModel = new DebugWindowViewModel(cpu, state, memory,
midiDevice, videoState.DacRegisters.ArgbPalette, softwareMixer, vgaRenderer, videoState,
cfgCpu.ExecutionContextManager, messenger, uiThreadDispatcher, textClipboard, hostStorageProvider,
emulatorBreakpointsManager,
new StructureViewModelFactory(configuration, loggerService, pauseHandler),
pauseHandler);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Spice86/ViewModels/DebugWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public partial class DebugWindowViewModel : ViewModelBase,
public DebugWindowViewModel(IInstructionExecutor cpu, State cpuState, IMemory memory, Midi externalMidiDevice,
ArgbPalette argbPalette, SoftwareMixer softwareMixer, IVgaRenderer vgaRenderer, VideoState videoState,
ExecutionContextManager executionContextManager, IMessenger messenger, IUIDispatcher uiDispatcher,
ITextClipboard textClipboard, IHostStorageProvider storageProvider,
ITextClipboard textClipboard, IHostStorageProvider storageProvider, EmulatorBreakpointsManager emulatorBreakpointsManager,
IStructureViewModelFactory structureViewModelFactory, IPauseHandler pauseHandler) {
messenger.Register<AddViewModelMessage<DisassemblyViewModel>>(this);
messenger.Register<AddViewModelMessage<MemoryViewModel>>(this);
Expand All @@ -69,7 +69,7 @@ public DebugWindowViewModel(IInstructionExecutor cpu, State cpuState, IMemory me
IsPaused = pauseHandler.IsPaused;
pauseHandler.Pausing += () => uiDispatcher.Post(() => IsPaused = true);
pauseHandler.Resumed += () => uiDispatcher.Post(() => IsPaused = false);
DisassemblyViewModel disassemblyVm = new(cpu, memory, cpuState, pauseHandler, uiDispatcher, messenger, textClipboard);
DisassemblyViewModel disassemblyVm = new(cpu, memory, cpuState, emulatorBreakpointsManager, pauseHandler, uiDispatcher, messenger, textClipboard);
DisassemblyViewModels.Add(disassemblyVm);
PaletteViewModel = new(argbPalette, uiDispatcher);
SoftwareMixerViewModel = new(softwareMixer);
Expand Down
27 changes: 24 additions & 3 deletions src/Spice86/ViewModels/DisassemblyViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Spice86.ViewModels;
using Spice86.Core.Emulator.CPU;
using Spice86.Core.Emulator.Memory;
using Spice86.Core.Emulator.VM;
using Spice86.Core.Emulator.VM.Breakpoint;
using Spice86.Infrastructure;
using Spice86.MemoryWrappers;
using Spice86.Messages;
Expand All @@ -25,6 +26,7 @@ public partial class DisassemblyViewModel : ViewModelBase {
private readonly ITextClipboard _textClipboard;
private readonly IUIDispatcher _uiDispatcher;
private readonly IInstructionExecutor _cpu;
private readonly EmulatorBreakpointsManager _emulatorBreakpointsManager;

[ObservableProperty]
private string _header = "Disassembly View";
Expand Down Expand Up @@ -55,10 +57,11 @@ public uint? StartAddress {
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(CloseTabCommand))]
private bool _canCloseTab;

public DisassemblyViewModel(IInstructionExecutor cpu, IMemory memory, State state, IPauseHandler pauseHandler, IUIDispatcher uiDispatcher,
public DisassemblyViewModel(IInstructionExecutor cpu, IMemory memory, State state, EmulatorBreakpointsManager emulatorBreakpointsManager, IPauseHandler pauseHandler, IUIDispatcher uiDispatcher,
IMessenger messenger, ITextClipboard textClipboard,
bool canCloseTab = false) {
_cpu = cpu;
_emulatorBreakpointsManager = emulatorBreakpointsManager;
_messenger = messenger;
_uiDispatcher = uiDispatcher;
_textClipboard = textClipboard;
Expand All @@ -82,7 +85,7 @@ private void StepInto() {

[RelayCommand(CanExecute = nameof(IsPaused))]
private void NewDisassemblyView() {
DisassemblyViewModel disassemblyViewModel = new(_cpu, _memory, _state, _pauseHandler, _uiDispatcher, _messenger,
DisassemblyViewModel disassemblyViewModel = new(_cpu, _memory, _state, _emulatorBreakpointsManager, _pauseHandler, _uiDispatcher, _messenger,
_textClipboard, canCloseTab: true) {
IsPaused = IsPaused
};
Expand Down Expand Up @@ -115,7 +118,7 @@ private async Task CopyLine() {
}
}

private static List<CpuInstructionInfo> DecodeInstructions(State state, IMemory memory, uint startAddress,
private List<CpuInstructionInfo> DecodeInstructions(State state, IMemory memory, uint startAddress,
int numberOfInstructionsShown) {
CodeReader codeReader = CreateCodeReader(memory, out CodeMemoryStream emulatedMemoryStream);
using CodeMemoryStream codeMemoryStream = emulatedMemoryStream;
Expand All @@ -127,6 +130,7 @@ private static List<CpuInstructionInfo> DecodeInstructions(State state, IMemory
long instructionAddress = codeMemoryStream.Position;
decoder.Decode(out Instruction instruction);
CpuInstructionInfo instructionInfo = new() {
HasBreakpoint = _emulatorBreakpointsManager.IsAddressBreakpointAt(instructionAddress),
Instruction = instruction,
Address = (uint)instructionAddress,
Length = instruction.Length,
Expand Down Expand Up @@ -154,6 +158,23 @@ private static List<CpuInstructionInfo> DecodeInstructions(State state, IMemory

return instructions;
}

/// <summary>
/// Handles a breakpoint being hit.
/// </summary>
/// <param name="breakPoint">The <see cref="BreakPoint"/> object representing the breakpoint that was hit.</param>
private void OnBreakPointReached(BreakPoint breakPoint) =>
_pauseHandler.RequestPause($"breakpoint {breakPoint.BreakPointType} hit");

[RelayCommand]
private void CreateAddressBreakpointHere() {
if (SelectedInstruction is null) {
return;
}
AddressBreakPoint breakPoint = new(BreakPointType.EXECUTION, SelectedInstruction.Address, OnBreakPointReached, false);
_emulatorBreakpointsManager.ToggleBreakPoint(breakPoint, true);
SelectedInstruction.HasBreakpoint = true;
}

private static Decoder InitializeDecoder(CodeReader codeReader, uint currentIp) {
Decoder decoder = Decoder.Create(16, codeReader, currentIp,
Expand Down
2 changes: 2 additions & 0 deletions src/Spice86/Views/DisassemblyView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<OnPlatform Default="{StaticResource RobotoMonoFont}" />
</TextElement.FontFamily>
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding HasBreakpoint}" Header="Has Breakpoint ?" />
<DataGridTextColumn Binding="{Binding Address}" Header="Address" />
<DataGridTextColumn Binding="{Binding SegmentedAddress}" Header="Based on CS:IP" />
<DataGridCheckBoxColumn Binding="{Binding IsCsIp}" Header="Is at CS:IP?" />
Expand All @@ -71,6 +72,7 @@
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy line" Command="{Binding CopyLineCommand}" />
<MenuItem Header="Address BreakPoint here" Command="{Binding CreateAddressBreakpointHereCommand}" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
Expand Down

0 comments on commit e7e60df

Please sign in to comment.