1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-17 09:04:43 +00:00
6502bench/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
Andy McFadden 1b0ee7de21 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 10:48:02 -07:00

186 lines
6.6 KiB
C#

/*
* 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 opc = 0; opc < 256; opc++) {
OpDef op = cpuDef[opc];
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();
OpDef.CycleMod mods = cpuDef.GetOpCycleMod(opc);
if (mods != 0) {
cycles += '+';
}
InstructionItems.Add(new InstructionItem(mFormatter.FormatHexValue(opc, 2),
instrSample, flags.ToString(), cycles,
mOpDesc.GetShortDescription(op.Mnemonic),
mOpDesc.GetAddressModeDescription(op.AddrMode),
op.IsUndocumented));
}
}
}
}