1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-10-31 19:04:44 +00:00

Add instruction chart

This adds a window that displays all of the instructions for a
given CPU in a summary grid.  Undocumented instructions are
included, but shown in grey italics.

Also, tweaked AppSettings to not mark itself as dirty if a "set"
operation doesn't actually change anything.
This commit is contained in:
Andy McFadden 2019-10-21 15:15:09 -07:00
parent a4f1de1238
commit bcac8bc6a0
12 changed files with 349 additions and 13 deletions

View File

@ -171,6 +171,7 @@ namespace Asm65 {
cpuDef = Cpu65C02;
break;
default:
// 6502, 6502B, 6502C, 6507, 6510, 8502, 2A03
cpuDef = Cpu6502;
break;
}
@ -235,13 +236,19 @@ namespace Asm65 {
/// <summary>
/// Returns an entry from the OpDef array for the specified opcode, 0-255. (We could
/// probably just make this the class indexer.)
/// Returns an entry from the OpDef array for the specified opcode, 0-255.
/// </summary>
/// <param name="op">Instruction opcode number (0-255).</param>
/// <returns>Instruction definition.</returns>
public OpDef GetOpDef(int op) { return mOpDefs[op]; }
/// <summary>
/// Indexer. Returns the definition of opcode N.
/// </summary>
public OpDef this[int op] {
get { return mOpDefs[op]; }
}
/// <summary>
/// Returns the number of cycles required to execute the instruction. If the value
/// is negative, the negated value represents the minimum number of cycles for an

View File

@ -147,6 +147,7 @@ namespace Asm65 {
{ OpName.INC, "Increment Accumulator" },
{ OpName.INX, "Increment Index X" },
{ OpName.INY, "Increment Index Y" },
{ OpName.JML, "Jump Long" },
{ OpName.JMP, "Jump" },
{ OpName.JSL, "Jump to Subroutine Long" },
{ OpName.JSR, "Jump to Subroutine" },

View File

@ -152,7 +152,7 @@ namespace SourceGen {
/// <summary>
/// Dirty flag, set to true by every "set" call.
/// Dirty flag, set to true by every "set" call that changes a value.
/// </summary>
public bool Dirty { get; set; }
@ -228,8 +228,11 @@ namespace SourceGen {
/// <param name="name">Setting name.</param>
/// <param name="value">Setting value.</param>
public void SetInt(string name, int value) {
mSettings[name] = value.ToString();
Dirty = true;
string newVal = value.ToString();
if (!mSettings.TryGetValue(name, out string oldValue) || oldValue != newVal) {
mSettings[name] = newVal;
Dirty = true;
}
}
/// <summary>
@ -256,8 +259,11 @@ namespace SourceGen {
/// <param name="name">Setting name.</param>
/// <param name="value">Setting value.</param>
public void SetBool(string name, bool value) {
mSettings[name] = value.ToString();
Dirty = true;
string newVal = value.ToString();
if (!mSettings.TryGetValue(name, out string oldValue) || oldValue != newVal) {
mSettings[name] = newVal;
Dirty = true;
}
}
/// <summary>
@ -290,8 +296,11 @@ namespace SourceGen {
/// <param name="enumType">Enum type.</param>
/// <param name="value">Setting value (integer enum index).</param>
public void SetEnum(string name, Type enumType, int value) {
mSettings[name] = Enum.GetName(enumType, value);
Dirty = true;
string newVal = Enum.GetName(enumType, value);
if (!mSettings.TryGetValue(name, out string oldValue) || oldValue != newVal) {
mSettings[name] = newVal;
Dirty = true;
}
}
/// <summary>
@ -317,10 +326,13 @@ namespace SourceGen {
public void SetString(string name, string value) {
if (value == null) {
mSettings.Remove(name);
Dirty = true;
} else {
mSettings[name] = value;
if (!mSettings.TryGetValue(name, out string oldValue) || oldValue != value) {
mSettings[name] = value;
Dirty = true;
}
}
Dirty = true;
}
/// <summary>

View File

@ -894,7 +894,7 @@ namespace SourceGen {
string msg = "descriptor straddles address change; len=" + kvp.Value.Length;
genLog.LogE("+" + offset.ToString("x6") + ": " + msg);
Messages.Add(new MessageList.MessageEntry(
MessageList.MessageEntry.SeverityLevel.Error,
MessageList.MessageEntry.SeverityLevel.Warning,
offset,
MessageList.MessageEntry.MessageType.InvalidOffsetOrLength,
msg,

View File

@ -94,6 +94,16 @@ namespace SourceGen {
/// </summary>
public bool IsAsciiChartOpen { get { return mAsciiChartDialog != null; } }
/// <summary>
/// Instruction chart reference window. Not tied to the project.
/// </summary>
private Tools.WpfGui.InstructionChart mInstructionChartDialog;
/// <summary>
/// Returns true if the instruction chart window is currently open.
/// </summary>
public bool IsInstructionChartOpen { get { return mInstructionChartDialog != null; } }
/// <summary>
/// List of recently-opened projects.
/// </summary>
@ -1238,6 +1248,7 @@ namespace SourceGen {
// WPF won't exit until all windows are closed, so any unowned windows need
// to be cleaned up here.
mAsciiChartDialog?.Close();
mInstructionChartDialog?.Close();
mHexDumpDialog?.Close();
mShowAnalysisTimersDialog?.Close();
mShowAnalyzerOutputDialog?.Close();
@ -3031,6 +3042,20 @@ namespace SourceGen {
}
}
public void ToggleInstructionChart() {
if (mInstructionChartDialog == null) {
// Create without owner so it doesn't have to be in front of main window.
mInstructionChartDialog = new Tools.WpfGui.InstructionChart(null,mOutputFormatter);
mInstructionChartDialog.Closing += (sender, e) => {
Debug.WriteLine("Instruction chart closed");
mInstructionChartDialog = null;
};
mInstructionChartDialog.Show();
} else {
mInstructionChartDialog.Close();
}
}
public void ToggleDataScan() {
ProjectProperties oldProps = mProject.ProjectProps;
ProjectProperties newProps = new ProjectProperties(oldProps);

View File

@ -130,6 +130,7 @@ and 65816 code. The official web site is
<ul>
<li><a href="tools.html#hexdump">Hex Dump Viewer</a></li>
<li><a href="tools.html#ascii-chart">ASCII Chart</a></li>
<li><a href="tools.html#instruction-chart">Instruction Chart</a></li>
</ul></li>
<li><a href="advanced.html">Advanced Topics</a>

View File

@ -53,9 +53,15 @@ external files.</p>
<p>This opens a window with the ASCII character set. Each character is
displayed next to its numeric value in decimal and hexadecimal. The
drop list at the bottom allows you to flip between standard and "high"
pop-up list at the bottom allows you to flip between standard and "high"
ASCII.</p>
<h2><a name="instruction-chart">Instruction Chart</a></h2>
<p>This opens a window with a summary of all 256 opcodes. The CPU can
be chosen from the pop-up list at the bottom. Undocumented opcodes are
shown in italics.</p>
</div>
<div id="footer">

View File

@ -85,6 +85,9 @@
<DependentUpon>GenTestRunner.xaml</DependentUpon>
</Compile>
<Compile Include="Tools\VirtualHexDump.cs" />
<Compile Include="Tools\WpfGui\InstructionChart.xaml.cs">
<DependentUpon>InstructionChart.xaml</DependentUpon>
</Compile>
<Compile Include="Tools\WpfGui\AsciiChart.xaml.cs">
<DependentUpon>AsciiChart.xaml</DependentUpon>
</Compile>
@ -246,6 +249,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Tools\WpfGui\InstructionChart.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Tools\WpfGui\AsciiChart.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -0,0 +1,83 @@
<!--
Copyright 2019 faddenSoft
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<Window x:Class="SourceGen.Tools.WpfGui.InstructionChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SourceGen.Tools.WpfGui"
mc:Ignorable="d"
Title="Instruction Chart"
Width="800" Height="563" MinWidth="400" MinHeight="180" ResizeMode="CanResizeWithGrip"
ShowInTaskbar="True"
Loaded="Window_Loaded"
PreviewKeyDown="Window_KeyEventHandler">
<Window.Resources>
<system:String x:Key="str_6502">MOS 6502</system:String>
<system:String x:Key="str_65C02">WDC W65C02S</system:String>
<system:String x:Key="str_65816">WDC W65C816S</system:String>
</Window.Resources>
<DockPanel Margin="8">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="0,4,0,0">
<TextBlock Margin="0,3,0,0">CPU:</TextBlock>
<ComboBox Name="cpuSelectionComboBox" Width="200" Margin="4,0,0,0"
HorizontalAlignment="Left"
ItemsSource="{Binding CpuItems}" DisplayMemberPath="Name"
SelectionChanged="CpuSelectionComboBox_SelectionChanged"/>
</StackPanel>
<DataGrid DockPanel.Dock="Top" Name="instructionGrid"
IsReadOnly="True"
ItemsSource="{Binding InstructionItems}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
GridLinesVisibility="All"
VerticalGridLinesBrush="#FF7F7F7F"
HorizontalGridLinesBrush="#FFE2E2E2"
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Extended"
VerticalScrollBarVisibility="Visible">
<DataGrid.Resources>
<Style x:Key="undocCellStyle" TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsUndocumented}" Value="True">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Opc" Binding="{Binding Opcode}"/>
<DataGridTextColumn Header="Instruction" Binding="{Binding Sample}"
CellStyle="{StaticResource undocCellStyle}"/>
<DataGridTextColumn Header="Flags" Binding="{Binding Flags}"/>
<DataGridTextColumn Header="Cyc" Binding="{Binding Cycles}"/>
<DataGridTextColumn Header="Description" Binding="{Binding ShortDesc}"
FontFamily="Segoe UI"/>
<DataGridTextColumn Header="Address Mode" Binding="{Binding AddressMode}"
FontFamily="Segoe UI"/>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>

View File

@ -0,0 +1,184 @@
/*
* Copyright 2019 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Asm65;
namespace SourceGen.Tools.WpfGui {
/// <summary>
/// CPU instruction chart.
/// </summary>
public partial class InstructionChart : Window, INotifyPropertyChanged {
/// <summary>
/// Item for CPU selection combo box.
/// </summary>
public class CpuItem {
public string Name { get; private set; }
public CpuDef.CpuType Type { get; private set; }
public CpuItem(string name, CpuDef.CpuType type) {
Name = name;
Type = type;
}
}
public CpuItem[] CpuItems { get; private set; }
/// <summary>
/// Item for main list.
/// </summary>
public class InstructionItem {
public string Opcode { get; private set; }
public string Sample { get; private set; }
public string Flags { get; private set; }
public string Cycles { get; private set; }
public string ShortDesc { get; private set; }
public string AddressMode { get; private set; }
public bool IsUndocumented { get; private set; }
public InstructionItem(string opcode, string sample, string flags, string cycles,
string shortDesc, string addrMode, bool isUndoc) {
Opcode = opcode;
Sample = sample;
Flags = flags;
Cycles = cycles;
ShortDesc = shortDesc;
AddressMode = addrMode;
IsUndocumented = isUndoc;
}
}
public ObservableCollection<InstructionItem> InstructionItems { get; private set; } =
new ObservableCollection<InstructionItem>();
private OpDescription mOpDesc = OpDescription.GetOpDescription(null);
private Formatter mFormatter;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Constructor.
/// </summary>
public InstructionChart(Window owner, Formatter formatter) {
InitializeComponent();
Owner = owner;
DataContext = this;
mFormatter = formatter;
CpuItems = new CpuItem[] {
new CpuItem((string)FindResource("str_6502"), CpuDef.CpuType.Cpu6502),
new CpuItem((string)FindResource("str_65C02"), CpuDef.CpuType.Cpu65C02),
new CpuItem((string)FindResource("str_65816"), CpuDef.CpuType.Cpu65816),
};
}
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart mode setting.
CpuDef.CpuType type = (CpuDef.CpuType)AppSettings.Global.GetEnum(
AppSettings.ASCCH_MODE, typeof(CpuDef.CpuType), (int)CpuDef.CpuType.Cpu6502);
int index = 0;
for (int i = 0; i < CpuItems.Length; i++) {
if (CpuItems[i].Type == type) {
index = i;
break;
}
}
cpuSelectionComboBox.SelectedIndex = index;
}
// Catch ESC key.
private void Window_KeyEventHandler(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) {
Close();
}
}
private void CpuSelectionComboBox_SelectionChanged(object sender,
SelectionChangedEventArgs e) {
UpdateControls();
}
private void UpdateControls() {
CpuItem item = (CpuItem)cpuSelectionComboBox.SelectedItem;
if (item == null) {
// initializing
return;
}
// Push current choice to settings.
AppSettings.Global.SetEnum(AppSettings.ASCCH_MODE, typeof(CpuDef.CpuType),
(int)item.Type);
// Populate the items source.
InstructionItems.Clear();
CpuDef cpuDef = CpuDef.GetBestMatch(item.Type, true, false);
for (int i = 0; i < 256; i++) {
OpDef op = cpuDef[i];
int opLen = op.GetLength(StatusFlags.AllIndeterminate);
string sampleValue = "$12";
if (op.AddrMode == OpDef.AddressMode.BlockMove) {
sampleValue = "#$12,#$34";
} else if (opLen == 3) {
sampleValue = "$1234";
} else if (opLen == 4) {
sampleValue = "$123456";
}
string instrSample = op.Mnemonic + " " +
mFormatter.FormatOperand(op, sampleValue, OpDef.WidthDisambiguation.None);
StringBuilder flags = new StringBuilder(8);
const string FLAGS = "NVMXDIZC";
Asm65.StatusFlags affectedFlags = op.FlagsAffected;
for (int fl = 0; fl < 8; fl++) {
if (affectedFlags.GetBit((StatusFlags.FlagBits)(7 - fl)) >= 0) {
flags.Append(FLAGS[fl]);
} else {
flags.Append("-");
}
}
string cycles = op.Cycles.ToString();
if (op.CycleMods != 0) {
cycles += '+';
}
InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(i, 2),
instrSample, flags.ToString(), cycles,
mOpDesc.GetShortDescription(op.Mnemonic),
mOpDesc.GetAddressModeDescription(op.AddrMode),
op.IsUndocumented));
}
}
}
}

View File

@ -162,6 +162,7 @@ limitations under the License.
<KeyGesture>Ctrl+D</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="ToggleInstructionChartCmd" Text="Instruction Chart"/>
<RoutedUICommand x:Key="ToggleSingleByteFormatCmd" Text="Toggle Single-Byte Format">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+B</KeyGesture>
@ -276,6 +277,8 @@ limitations under the License.
Executed="ToggleAsciiChartCmd_Executed"/>
<CommandBinding Command="{StaticResource ToggleDataScanCmd}"
CanExecute="IsProjectOpen" Executed="ToggleDataScanCmd_Executed"/>
<CommandBinding Command="{StaticResource ToggleInstructionChartCmd}"
Executed="ToggleInstructionChartCmd_Executed"/>
<CommandBinding Command="{StaticResource ToggleSingleByteFormatCmd}"
CanExecute="CanToggleSingleByteFormat" Executed="ToggleSingleByteFormatCmd_Executed"/>
<CommandBinding Command="{StaticResource UndoCmd}"
@ -372,6 +375,8 @@ limitations under the License.
<MenuItem Command="{StaticResource ShowFileHexDumpCmd}"/>
<MenuItem Name="toggleAsciiChartMenuItem"
Command="{StaticResource ToggleAsciiChartCmd}" IsCheckable="True"/>
<MenuItem Name="toggleInstructionChartMenuItem"
Command="{StaticResource ToggleInstructionChartCmd}" IsCheckable="True"/>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Command="Help"/>

View File

@ -1258,6 +1258,10 @@ namespace SourceGen.WpfGui {
mMainCtrl.ToggleDataScan();
}
private void ToggleInstructionChartCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.ToggleInstructionChart();
}
private void ToggleSingleByteFormatCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.ToggleSingleByteFormat();
}
@ -1384,6 +1388,7 @@ namespace SourceGen.WpfGui {
}
private void ToolsMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
toggleAsciiChartMenuItem.IsChecked = mMainCtrl.IsAsciiChartOpen;
toggleInstructionChartMenuItem.IsChecked = mMainCtrl.IsInstructionChartOpen;
}
private void DebugMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
debugCommentRulersMenuItem.IsChecked = MultiLineComment.DebugShowRuler;