Skip to content

Commit

Permalink
feat: DISASM view segmented addressing mode
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 8, 2024
1 parent 3e58dd8 commit 4013630
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 22 deletions.
37 changes: 37 additions & 0 deletions src/Spice86/ViewModels/BreakpintsViewModel.cs
Original file line number Diff line number Diff line change
@@ -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<BreakpointViewModel> _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);
}
}
}
21 changes: 21 additions & 0 deletions src/Spice86/ViewModels/BreakpointViewModel.cs
Original file line number Diff line number Diff line change
@@ -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);
}
46 changes: 39 additions & 7 deletions src/Spice86/ViewModels/DisassemblyViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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))]
Expand All @@ -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]
Expand All @@ -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);
}
}

Expand Down
40 changes: 25 additions & 15 deletions src/Spice86/Views/DisassemblyView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
x:DataType="viewModels:DisassemblyViewModel">
<UserControl.Resources>
<converters:InstructionToStringConverter x:Key="InstructionToStringConverter" />
<converters:SegmentedAddressConverter x:Key="SegmentedAddressConverter" />
</UserControl.Resources>
<DockPanel>
<StackPanel Orientation="Horizontal"
DockPanel.Dock="Top" IsVisible="{Binding IsPaused}"
HorizontalAlignment="Center"
VerticalAlignment="Top">
<StackPanel Orientation="Vertical">
<Button
Command="{Binding NewDisassemblyViewCommand}"
Content="New Disassembly View"
Expand All @@ -23,23 +25,32 @@
Command="{Binding CloseTabCommand}"
Content="Close View"
IsEnabled="{Binding CanCloseTab}"/>
<StackPanel Orientation="Vertical" IsEnabled="{Binding IsPaused}">
<Label HorizontalAlignment="Center" Content="Number of instructions shown" Margin="5" />
<NumericUpDown Margin="5" Value="{Binding NumberOfInstructionsShown}" />
</StackPanel>
<StackPanel Orientation="Vertical" IsEnabled="{Binding IsPaused}">
<Label HorizontalAlignment="Center" Content="Start Address" />
<TextBox Text="{Binding StartAddress}" />
<Button Content="Go to CS:IP" Command="{Binding GoToCsIpCommand}" />
</StackPanel>
<Button Content="Step into" Command="{Binding StepIntoCommand}" />
<StackPanel Orientation="Vertical" IsEnabled="{Binding IsPaused}">
<Label HorizontalAlignment="Center" Content="Number of instructions shown" Margin="5" />
<NumericUpDown Margin="5" Value="{Binding NumberOfInstructionsShown}" />
</StackPanel>
<StackPanel Orientation="Vertical" IsEnabled="{Binding IsPaused}">
<RadioButton GroupName="AddressingMode" Content="Segmented addressing" IsChecked="{Binding !IsUsingLinearAddressing}" />
<RadioButton GroupName="AddressingMode" Content="Linear addressing" IsChecked="{Binding IsUsingLinearAddressing}" />
<Label HorizontalAlignment="Center" Content="Start Address" />
<StackPanel Orientation="Horizontal">
<TextBox IsEnabled="{Binding !IsUsingLinearAddressing}"
Text="{Binding SegmentedStartAddress, Mode=TwoWay, UpdateSourceTrigger=LostFocus,
Converter={StaticResource SegmentedAddressConverter}}"
Watermark="segment:offset" />
<TextBox IsEnabled="{Binding IsUsingLinearAddressing, Mode=TwoWay}"
Text="{Binding StartAddress, UpdateSourceTrigger=PropertyChanged}"
Watermark="linear address"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical">
<Button Content="Go to CS:IP" Command="{Binding GoToCsIpCommand}" />
<Button Content="Update" HotKey="Enter" IsDefault="True" Command="{Binding UpdateDisassemblyCommand}" />
</StackPanel>
<Grid DockPanel.Dock="Bottom" IsVisible="{Binding IsPaused}" RowDefinitions="Auto,*" IsEnabled="{Binding IsPaused}">
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Step into" Command="{Binding StepIntoCommand}" />
</StackPanel>
<DataGrid
Grid.Row="1"
</StackPanel>
<DataGrid DockPanel.Dock="Bottom"
AutoGenerateColumns="False"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
Expand Down Expand Up @@ -77,6 +88,5 @@
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</DockPanel>
</UserControl>

0 comments on commit 4013630

Please sign in to comment.