diff --git a/src/Spice86/ViewModels/BreakpintsViewModel.cs b/src/Spice86/ViewModels/BreakpintsViewModel.cs new file mode 100644 index 000000000..7fdbafea6 --- /dev/null +++ b/src/Spice86/ViewModels/BreakpintsViewModel.cs @@ -0,0 +1,37 @@ +namespace Spice86.ViewModels; + +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +using Spice86.Core.Emulator.VM; +using Spice86.Core.Emulator.VM.Breakpoint; + +using System.Collections.ObjectModel; + +public partial class BreakpintsViewModel : ViewModelBase { + private readonly EmulatorBreakpointsManager _emulatorBreakpointsManager; + + public BreakpintsViewModel(EmulatorBreakpointsManager emulatorBreakpointsManager) { + _emulatorBreakpointsManager = emulatorBreakpointsManager; + } + + [ObservableProperty] + private ObservableCollection _breakpointsViewModels = new(); + + [ObservableProperty] + private BreakpointViewModel? _currentBreakpointViewModel; + + [RelayCommand] + private void AddAddressBreakpoint(AddressBreakPoint addressBreakPoint) { + var breakpointViewModel = new BreakpointViewModel(_emulatorBreakpointsManager, addressBreakPoint); + BreakpointsViewModels.Add(breakpointViewModel); + CurrentBreakpointViewModel = BreakpointsViewModels.Last(); + } + + [RelayCommand] + private void RemoveBreakpoint() { + if (CurrentBreakpointViewModel is not null) { + BreakpointsViewModels.Remove(CurrentBreakpointViewModel); + } + } +} \ No newline at end of file diff --git a/src/Spice86/ViewModels/BreakpointViewModel.cs b/src/Spice86/ViewModels/BreakpointViewModel.cs new file mode 100644 index 000000000..7c83572d6 --- /dev/null +++ b/src/Spice86/ViewModels/BreakpointViewModel.cs @@ -0,0 +1,21 @@ +namespace Spice86.ViewModels; +using CommunityToolkit.Mvvm.Input; + +using Spice86.Core.Emulator.VM; +using Spice86.Core.Emulator.VM.Breakpoint; + +public partial class BreakpointViewModel : ViewModelBase { + private readonly BreakPoint _breakPoint; + private readonly EmulatorBreakpointsManager _emulatorBreakpointsManager; + + public BreakpointViewModel(EmulatorBreakpointsManager emulatorBreakpointsManager, BreakPoint breakPoint) { + _breakPoint = breakPoint; + _emulatorBreakpointsManager = emulatorBreakpointsManager; + } + + [RelayCommand] + private void Enable() => _emulatorBreakpointsManager.ToggleBreakPoint(_breakPoint, on: true); + + [RelayCommand] + private void Disable() => _emulatorBreakpointsManager.ToggleBreakPoint(_breakPoint, on: false); +} \ No newline at end of file diff --git a/src/Spice86/ViewModels/DisassemblyViewModel.cs b/src/Spice86/ViewModels/DisassemblyViewModel.cs index 99fc79758..6bed96ff8 100644 --- a/src/Spice86/ViewModels/DisassemblyViewModel.cs +++ b/src/Spice86/ViewModels/DisassemblyViewModel.cs @@ -16,6 +16,7 @@ namespace Spice86.ViewModels; using Spice86.MemoryWrappers; using Spice86.Messages; using Spice86.Models.Debugging; +using Spice86.Shared.Emulator.Memory; using Spice86.Shared.Utils; public partial class DisassemblyViewModel : ViewModelBase { @@ -42,19 +43,28 @@ public partial class DisassemblyViewModel : ViewModelBase { [NotifyCanExecuteChangedFor(nameof(StepIntoCommand))] private bool _isPaused; - [ObservableProperty] private int _numberOfInstructionsShown = 50; + [ObservableProperty] + private int _numberOfInstructionsShown = 50; + + [ObservableProperty] + private bool _isUsingLinearAddressing = true; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(UpdateDisassemblyCommand))] + private SegmentedAddress? _segmentedStartAddress; private uint? _startAddress; public uint? StartAddress { get => _startAddress; set { - Header = value is null ? "" : $"0x{value:X}"; SetProperty(ref _startAddress, value); + UpdateDisassemblyCommand.NotifyCanExecuteChanged(); } } - [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(CloseTabCommand))] + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CloseTabCommand))] private bool _canCloseTab; public DisassemblyViewModel(IInstructionExecutor cpu, IMemory memory, State state, EmulatorBreakpointsManager emulatorBreakpointsManager, IPauseHandler pauseHandler, IUIDispatcher uiDispatcher, @@ -72,6 +82,11 @@ public DisassemblyViewModel(IInstructionExecutor cpu, IMemory memory, State stat pauseHandler.Pausing += () => _uiDispatcher.Post(() => IsPaused = true); pauseHandler.Resumed += () => _uiDispatcher.Post(() => IsPaused = false); CanCloseTab = canCloseTab; + UpdateDisassembly(); + } + + private void UpdateHeader(uint? address) { + Header = address is null ? "" : $"0x{address:X}"; } [RelayCommand(CanExecute = nameof(CanCloseTab))] @@ -95,17 +110,34 @@ private void NewDisassemblyView() { [RelayCommand(CanExecute = nameof(IsPaused))] private void GoToCsIp() { StartAddress = _state.IpPhysicalAddress; + SegmentedStartAddress = new(_state.CS, _state.IP); UpdateDisassembly(); } - [RelayCommand(CanExecute = nameof(IsPaused))] + private uint? GetStartAddress() { + return IsUsingLinearAddressing switch { + true => StartAddress, + false => SegmentedStartAddress is null + ? null + : MemoryUtils.ToPhysicalAddress(SegmentedStartAddress.Value.Segment, + SegmentedStartAddress.Value.Offset), + }; + } + + private bool CanExecuteUpdateDisassembly() { + return IsPaused && GetStartAddress() is not null; + } + + [RelayCommand(CanExecute = nameof(CanExecuteUpdateDisassembly))] private void UpdateDisassembly() { - if (StartAddress is null) { + uint? startAddress = GetStartAddress(); + if (startAddress is null) { return; } - Instructions = new(DecodeInstructions(_state, _memory, StartAddress.Value, NumberOfInstructionsShown)); + Instructions = new(DecodeInstructions(_state, _memory, startAddress.Value, NumberOfInstructionsShown)); SelectedInstruction = Instructions.FirstOrDefault(); + UpdateHeader(SelectedInstruction?.Address); } [ObservableProperty] @@ -114,7 +146,7 @@ private void UpdateDisassembly() { [RelayCommand(CanExecute = nameof(IsPaused))] private async Task CopyLine() { if (SelectedInstruction is not null) { - await _textClipboard.SetTextAsync(SelectedInstruction.StringRepresentation).ConfigureAwait(false); + await _textClipboard.SetTextAsync(SelectedInstruction.StringRepresentation); } } diff --git a/src/Spice86/Views/DisassemblyView.axaml b/src/Spice86/Views/DisassemblyView.axaml index 0a10d2df6..a92139b86 100644 --- a/src/Spice86/Views/DisassemblyView.axaml +++ b/src/Spice86/Views/DisassemblyView.axaml @@ -9,12 +9,14 @@ x:DataType="viewModels:DisassemblyViewModel"> + +