2019-10-21 22:15:09 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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; }
|
|
|
|
|
|
2020-02-18 21:25:20 +00:00
|
|
|
|
public bool ShowUndocumented {
|
|
|
|
|
get { return mShowUndocumented; }
|
|
|
|
|
set { mShowUndocumented = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowUndocumented;
|
|
|
|
|
|
2019-10-21 22:15:09 +00:00
|
|
|
|
/// <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>
|
2019-12-29 01:14:29 +00:00
|
|
|
|
/// <param name="owner">Parent window.</param>
|
|
|
|
|
/// <param name="formatter">Text formatter.</param>
|
2019-10-21 22:15:09 +00:00
|
|
|
|
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),
|
2020-10-10 22:33:08 +00:00
|
|
|
|
new CpuItem((string)FindResource("str_W65C02"), CpuDef.CpuType.CpuW65C02),
|
2019-10-21 22:15:09 +00:00
|
|
|
|
new CpuItem((string)FindResource("str_65816"), CpuDef.CpuType.Cpu65816),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Window_Loaded(object sender, RoutedEventArgs e) {
|
2020-02-18 21:25:20 +00:00
|
|
|
|
// Restore chart settings.
|
2019-10-21 22:15:09 +00:00
|
|
|
|
CpuDef.CpuType type = (CpuDef.CpuType)AppSettings.Global.GetEnum(
|
2020-02-18 21:25:20 +00:00
|
|
|
|
AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType), (int)CpuDef.CpuType.Cpu6502);
|
|
|
|
|
ShowUndocumented = AppSettings.Global.GetBool(AppSettings.INSTCH_SHOW_UNDOC, true);
|
|
|
|
|
|
2019-10-21 22:15:09 +00:00
|
|
|
|
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.
|
2020-02-18 21:25:20 +00:00
|
|
|
|
AppSettings.Global.SetEnum(AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType),
|
2019-10-21 22:15:09 +00:00
|
|
|
|
(int)item.Type);
|
2020-02-18 21:25:20 +00:00
|
|
|
|
AppSettings.Global.SetBool(AppSettings.INSTCH_SHOW_UNDOC, mShowUndocumented);
|
2019-10-21 22:15:09 +00:00
|
|
|
|
|
|
|
|
|
// Populate the items source.
|
|
|
|
|
InstructionItems.Clear();
|
|
|
|
|
CpuDef cpuDef = CpuDef.GetBestMatch(item.Type, true, false);
|
Fix display of instruction attributes
The "affected flags" constants were incorrect for BIT, BRK, COP,
RTI, XCE, and the undocmented instructions ANE, DCP, and SAX. The
constants are used for the changed-flag summary shown in the info
window and the instruction chart.
Of greater import: the status flag updater for BIT was incorrectly
marking N/V/C as indeterminate instead of N/V/Z. The undocmented
instructions ANE, DCP, and SAX were also incorrect.
The cycle counts shown in line comments are computed correctly, but
the counts shown in the info window and instruction chart were
displaying the full set of modifiers, ignoring the CPU type. That's
okay for the info window, which spells the modifiers out, though
it'd be better if the bits were explicitly marked as being applicable
to the current CPU or a different one.
2019-10-22 16:58:23 +00:00
|
|
|
|
for (int opc = 0; opc < 256; opc++) {
|
|
|
|
|
OpDef op = cpuDef[opc];
|
2020-02-18 21:25:20 +00:00
|
|
|
|
if (!mShowUndocumented && op.IsUndocumented) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-10-21 22:15:09 +00:00
|
|
|
|
|
2020-10-14 22:02:13 +00:00
|
|
|
|
int instrLen = op.GetLength(StatusFlags.AllIndeterminate);
|
|
|
|
|
if (op.AddrMode == OpDef.AddressMode.PCRel) {
|
|
|
|
|
// Single-byte branch instructions are formatted with a 16-bit
|
|
|
|
|
// absolute addres.
|
|
|
|
|
instrLen = 3;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 22:15:09 +00:00
|
|
|
|
string sampleValue = "$12";
|
|
|
|
|
if (op.AddrMode == OpDef.AddressMode.BlockMove) {
|
|
|
|
|
sampleValue = "#$12,#$34";
|
2020-10-10 22:33:08 +00:00
|
|
|
|
} else if (op.AddrMode == OpDef.AddressMode.DPPCRel) {
|
|
|
|
|
sampleValue = "$12,$1234";
|
2020-10-14 22:02:13 +00:00
|
|
|
|
} else if (instrLen == 3) {
|
2019-10-21 22:15:09 +00:00
|
|
|
|
sampleValue = "$1234";
|
2020-10-14 22:02:13 +00:00
|
|
|
|
} else if (instrLen == 4) {
|
2019-10-21 22:15:09 +00:00
|
|
|
|
sampleValue = "$123456";
|
|
|
|
|
}
|
2020-02-18 21:25:20 +00:00
|
|
|
|
string instrSample = mFormatter.FormatMnemonic(op.Mnemonic,
|
|
|
|
|
OpDef.WidthDisambiguation.None) + " " +
|
2019-10-21 22:15:09 +00:00
|
|
|
|
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();
|
Fix display of instruction attributes
The "affected flags" constants were incorrect for BIT, BRK, COP,
RTI, XCE, and the undocmented instructions ANE, DCP, and SAX. The
constants are used for the changed-flag summary shown in the info
window and the instruction chart.
Of greater import: the status flag updater for BIT was incorrectly
marking N/V/C as indeterminate instead of N/V/Z. The undocmented
instructions ANE, DCP, and SAX were also incorrect.
The cycle counts shown in line comments are computed correctly, but
the counts shown in the info window and instruction chart were
displaying the full set of modifiers, ignoring the CPU type. That's
okay for the info window, which spells the modifiers out, though
it'd be better if the bits were explicitly marked as being applicable
to the current CPU or a different one.
2019-10-22 16:58:23 +00:00
|
|
|
|
OpDef.CycleMod mods = cpuDef.GetOpCycleMod(opc);
|
|
|
|
|
if (mods != 0) {
|
2019-10-21 22:15:09 +00:00
|
|
|
|
cycles += '+';
|
|
|
|
|
}
|
|
|
|
|
|
Fix display of instruction attributes
The "affected flags" constants were incorrect for BIT, BRK, COP,
RTI, XCE, and the undocmented instructions ANE, DCP, and SAX. The
constants are used for the changed-flag summary shown in the info
window and the instruction chart.
Of greater import: the status flag updater for BIT was incorrectly
marking N/V/C as indeterminate instead of N/V/Z. The undocmented
instructions ANE, DCP, and SAX were also incorrect.
The cycle counts shown in line comments are computed correctly, but
the counts shown in the info window and instruction chart were
displaying the full set of modifiers, ignoring the CPU type. That's
okay for the info window, which spells the modifiers out, though
it'd be better if the bits were explicitly marked as being applicable
to the current CPU or a different one.
2019-10-22 16:58:23 +00:00
|
|
|
|
InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(opc, 2),
|
2019-10-21 22:15:09 +00:00
|
|
|
|
instrSample, flags.ToString(), cycles,
|
|
|
|
|
mOpDesc.GetShortDescription(op.Mnemonic),
|
|
|
|
|
mOpDesc.GetAddressModeDescription(op.AddrMode),
|
|
|
|
|
op.IsUndocumented));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|