From bcac8bc6a08950ae71772b3d63c98c601003ca96 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Mon, 21 Oct 2019 15:15:09 -0700 Subject: [PATCH] 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. --- Asm65/CpuDef.cs | 11 +- Asm65/OpDescription.cs | 1 + SourceGen/AppSettings.cs | 30 ++- SourceGen/DisasmProject.cs | 2 +- SourceGen/MainController.cs | 25 +++ SourceGen/RuntimeData/Help/index.html | 1 + SourceGen/RuntimeData/Help/tools.html | 8 +- SourceGen/SourceGen.csproj | 7 + SourceGen/Tools/WpfGui/InstructionChart.xaml | 83 ++++++++ .../Tools/WpfGui/InstructionChart.xaml.cs | 184 ++++++++++++++++++ SourceGen/WpfGui/MainWindow.xaml | 5 + SourceGen/WpfGui/MainWindow.xaml.cs | 5 + 12 files changed, 349 insertions(+), 13 deletions(-) create mode 100644 SourceGen/Tools/WpfGui/InstructionChart.xaml create mode 100644 SourceGen/Tools/WpfGui/InstructionChart.xaml.cs diff --git a/Asm65/CpuDef.cs b/Asm65/CpuDef.cs index 1d9ae8e..1f26d2d 100644 --- a/Asm65/CpuDef.cs +++ b/Asm65/CpuDef.cs @@ -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 { /// - /// 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. /// /// Instruction opcode number (0-255). /// Instruction definition. public OpDef GetOpDef(int op) { return mOpDefs[op]; } + /// + /// Indexer. Returns the definition of opcode N. + /// + public OpDef this[int op] { + get { return mOpDefs[op]; } + } + /// /// 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 diff --git a/Asm65/OpDescription.cs b/Asm65/OpDescription.cs index f7dff42..349157b 100644 --- a/Asm65/OpDescription.cs +++ b/Asm65/OpDescription.cs @@ -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" }, diff --git a/SourceGen/AppSettings.cs b/SourceGen/AppSettings.cs index 4f5b442..1ac0013 100644 --- a/SourceGen/AppSettings.cs +++ b/SourceGen/AppSettings.cs @@ -152,7 +152,7 @@ namespace SourceGen { /// - /// Dirty flag, set to true by every "set" call. + /// Dirty flag, set to true by every "set" call that changes a value. /// public bool Dirty { get; set; } @@ -228,8 +228,11 @@ namespace SourceGen { /// Setting name. /// Setting value. 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; + } } /// @@ -256,8 +259,11 @@ namespace SourceGen { /// Setting name. /// Setting value. 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; + } } /// @@ -290,8 +296,11 @@ namespace SourceGen { /// Enum type. /// Setting value (integer enum index). 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; + } } /// @@ -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; } /// diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs index 6b35fb8..6b0518f 100644 --- a/SourceGen/DisasmProject.cs +++ b/SourceGen/DisasmProject.cs @@ -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, diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index cd4b624..73c6565 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -94,6 +94,16 @@ namespace SourceGen { /// public bool IsAsciiChartOpen { get { return mAsciiChartDialog != null; } } + /// + /// Instruction chart reference window. Not tied to the project. + /// + private Tools.WpfGui.InstructionChart mInstructionChartDialog; + + /// + /// Returns true if the instruction chart window is currently open. + /// + public bool IsInstructionChartOpen { get { return mInstructionChartDialog != null; } } + /// /// List of recently-opened projects. /// @@ -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); diff --git a/SourceGen/RuntimeData/Help/index.html b/SourceGen/RuntimeData/Help/index.html index ee277b9..23c4e6c 100644 --- a/SourceGen/RuntimeData/Help/index.html +++ b/SourceGen/RuntimeData/Help/index.html @@ -130,6 +130,7 @@ and 65816 code. The official web site is
  • Advanced Topics diff --git a/SourceGen/RuntimeData/Help/tools.html b/SourceGen/RuntimeData/Help/tools.html index 7d5693c..987f2f4 100644 --- a/SourceGen/RuntimeData/Help/tools.html +++ b/SourceGen/RuntimeData/Help/tools.html @@ -53,9 +53,15 @@ external files.

    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.

    + +

    Instruction Chart

    +

    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.

    +