2019-07-08 22:40:30 +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.ComponentModel;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Controls;
|
2019-07-09 00:02:25 +00:00
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
using Asm65;
|
|
|
|
|
|
2019-07-20 20:28:10 +00:00
|
|
|
|
namespace SourceGen.WpfGui {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Instruction operand editor.
|
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public partial class EditInstructionOperand : Window, INotifyPropertyChanged {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Updated format descriptor. Will be null if the user selected "default".
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public FormatDescriptor FormatDescriptorResult { get; private set; }
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updated local variable table. Will be null if no changes were made.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public LocalVariableTable LocalVariableResult { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Offset of the local variable table we updated in LocalVariableResult.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int LocalVariableTableOffsetResult { get; private set; }
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Offset of label that was edited. A non-negative value here indicates that an
|
|
|
|
|
/// edit has been made.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int SymbolEditOffsetResult { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Edited project property, or null if no changes were made.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DefSymbol ProjectPropertyResult { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The project property that was modified, or null if none.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DefSymbol PrevProjectPropertyResult { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updated label.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Symbol SymbolEditResult { get; private set; }
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private readonly string SYMBOL_NOT_USED;
|
|
|
|
|
private readonly string SYMBOL_UNKNOWN;
|
|
|
|
|
private readonly string SYMBOL_INVALID;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
private readonly string CREATE_LOCAL_VARIABLE;
|
|
|
|
|
private readonly string EDIT_LOCAL_VARIABLE;
|
2019-09-08 23:41:54 +00:00
|
|
|
|
private readonly string LV_MATCH_FOUND_ADDRESS;
|
|
|
|
|
private readonly string LV_MATCH_FOUND_CONSTANT;
|
|
|
|
|
|
|
|
|
|
private readonly string CREATE_LABEL;
|
|
|
|
|
private readonly string EDIT_LABEL;
|
|
|
|
|
private readonly string CREATE_PROJECT_SYMBOL;
|
|
|
|
|
private readonly string EDIT_PROJECT_SYMBOL;
|
|
|
|
|
private readonly string CURRENT_LABEL;
|
|
|
|
|
private readonly string CURRENT_LABEL_ADJUSTED_FMT;
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Project reference.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private DisasmProject mProject;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Offset of instruction being edited.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private int mOffset;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Format object.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private Formatter mFormatter;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Operation definition, from file data.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private OpDef mOpDef;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Status flags at the point where the instruction is defined. This tells us whether
|
|
|
|
|
/// an operand is 8-bit or 16-bit.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private StatusFlags mOpStatusFlags;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Operand value, extracted from file data. For a relative branch, this will be
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// an address instead.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
private int mOperandValue;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// True when the input is valid. Controls whether the OK button is enabled.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public bool IsValid {
|
|
|
|
|
get { return mIsValid; }
|
|
|
|
|
set { mIsValid = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsValid;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Set when our load-time initialization is complete.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private bool mLoadDone;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
// INotifyPropertyChanged implementation
|
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
|
}
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Constructor.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// <param name="owner">Parent window.</param>
|
|
|
|
|
/// <param name="project">Project reference.</param>
|
|
|
|
|
/// <param name="offset">File offset of instruction start.</param>
|
|
|
|
|
/// <param name="formatter">Formatter object, for preview window.</param>
|
|
|
|
|
public EditInstructionOperand(Window owner, DisasmProject project, int offset,
|
|
|
|
|
Formatter formatter) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
InitializeComponent();
|
|
|
|
|
Owner = owner;
|
|
|
|
|
DataContext = this;
|
|
|
|
|
|
|
|
|
|
mProject = project;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
mOffset = offset;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
mFormatter = formatter;
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
SYMBOL_NOT_USED = (string)FindResource("str_SymbolNotUsed");
|
|
|
|
|
SYMBOL_INVALID = (string)FindResource("str_SymbolNotValid");
|
|
|
|
|
SYMBOL_UNKNOWN = (string)FindResource("str_SymbolUnknown");
|
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
CREATE_LOCAL_VARIABLE = (string)FindResource("str_CreateLocalVariable");
|
|
|
|
|
EDIT_LOCAL_VARIABLE = (string)FindResource("str_EditLocalVariable");
|
2019-09-08 23:41:54 +00:00
|
|
|
|
LV_MATCH_FOUND_ADDRESS = (string)FindResource("str_LvMatchFoundAddress");
|
|
|
|
|
LV_MATCH_FOUND_CONSTANT = (string)FindResource("str_LvMatchFoundConstant");
|
|
|
|
|
|
|
|
|
|
CREATE_LABEL = (string)FindResource("str_CreateLabel");
|
|
|
|
|
EDIT_LABEL = (string)FindResource("str_EditLabel");
|
|
|
|
|
CREATE_PROJECT_SYMBOL = (string)FindResource("str_CreateProjectSymbol");
|
|
|
|
|
EDIT_PROJECT_SYMBOL = (string)FindResource("str_EditProjectSymbol");
|
|
|
|
|
CURRENT_LABEL = (string)FindResource("str_CurrentLabel");
|
|
|
|
|
CURRENT_LABEL_ADJUSTED_FMT = (string)FindResource("str_CurrentLabelAdjustedFmt");
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
Debug.Assert(offset >= 0 && offset < project.FileDataLength);
|
|
|
|
|
mOpDef = project.CpuDef.GetOpDef(project.FileData[offset]);
|
|
|
|
|
Anattrib attr = project.GetAnattrib(offset);
|
|
|
|
|
mOpStatusFlags = attr.StatusFlags;
|
|
|
|
|
Debug.Assert(offset + mOpDef.GetLength(mOpStatusFlags) <= project.FileDataLength);
|
|
|
|
|
|
|
|
|
|
if (attr.OperandAddress >= 0) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
// Use this as the operand value when available. This lets us present
|
|
|
|
|
// relative branch instructions in the expected form.
|
2019-09-07 20:39:22 +00:00
|
|
|
|
mOperandValue = attr.OperandAddress;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
} else {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
// For BlockMove this will have both parts.
|
|
|
|
|
mOperandValue = mOpDef.GetOperand(project.FileData, offset, attr.StatusFlags);
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
BasicFormat_Loaded();
|
2019-09-08 23:41:54 +00:00
|
|
|
|
NumericReferences_Loaded();
|
|
|
|
|
LocalVariables_Loaded();
|
2019-09-07 20:39:22 +00:00
|
|
|
|
mLoadDone = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Window_ContentRendered(object sender, EventArgs e) {
|
|
|
|
|
UpdateControls();
|
2019-09-07 20:39:22 +00:00
|
|
|
|
symbolTextBox.SelectAll();
|
|
|
|
|
symbolTextBox.Focus();
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatDescriptorResult = CreateDescriptorFromControls();
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
|
|
|
|
|
// Export the updated local variable table if we made changes.
|
|
|
|
|
if (mEditedLvTable != null) {
|
|
|
|
|
LocalVariableTable lvt = mProject.LvTables[mLvTableOffset];
|
|
|
|
|
if (mEditedLvTable != lvt) {
|
|
|
|
|
LocalVariableResult = mEditedLvTable;
|
|
|
|
|
LocalVariableTableOffsetResult = mLvTableOffset;
|
|
|
|
|
|
|
|
|
|
Debug.WriteLine("NEW TABLE:");
|
|
|
|
|
mEditedLvTable.DebugDump(mLvTableOffset);
|
|
|
|
|
} else {
|
|
|
|
|
Debug.WriteLine("No change to LvTable, not exporting");
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-08 23:41:54 +00:00
|
|
|
|
|
|
|
|
|
if (mLabelHasBeenEdited) {
|
|
|
|
|
SymbolEditOffsetResult = mEditedLabelOffset;
|
|
|
|
|
SymbolEditResult = mEditedLabel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProjectPropertyResult = mEditedProjectSymbol;
|
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
DialogResult = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Updates the state of the UI controls as the user interacts with the dialog.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
private void UpdateControls() {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (!mLoadDone) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
// Parts panel IsEnabled depends directly on formatSymbolButton.IsChecked.
|
|
|
|
|
IsValid = true;
|
|
|
|
|
IsSymbolAuto = false;
|
2019-09-08 23:41:54 +00:00
|
|
|
|
IsSymbolVar = false;
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
IsPartPanelEnabled = false;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
SymbolValueDecimal = string.Empty;
|
|
|
|
|
if (FormatSymbol) {
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
IsPartPanelEnabled = mOpDef.IsExtendedImmediate;
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (!Asm65.Label.ValidateLabel(SymbolLabel)) {
|
|
|
|
|
SymbolValueHex = SYMBOL_INVALID;
|
|
|
|
|
IsValid = false;
|
|
|
|
|
} else if (mProject.SymbolTable.TryGetValue(SymbolLabel, out Symbol sym)) {
|
|
|
|
|
if (sym.SymbolSource == Symbol.Source.Auto) {
|
|
|
|
|
// We try to block references to auto labels, but it's possible to get
|
|
|
|
|
// around it because FormatDescriptors are weak references (replace auto
|
|
|
|
|
// label with user label, reference non-existent auto label, remove user
|
|
|
|
|
// label). We could try harder, but currently not necessary.
|
2019-09-08 23:41:54 +00:00
|
|
|
|
//
|
|
|
|
|
// Referencing an auto label is unwise because we use weak references
|
|
|
|
|
// by name, and auto labels can appear, disappear, or be renamed.
|
2019-09-07 20:39:22 +00:00
|
|
|
|
IsValid = false;
|
|
|
|
|
IsSymbolAuto = true;
|
2019-09-08 23:41:54 +00:00
|
|
|
|
} else if (sym.SymbolSource == Symbol.Source.Variable) {
|
|
|
|
|
// Local variables can be de-duplicated and uniquified, so referring to
|
|
|
|
|
// them by name doesn't make sense. The numeric operand formatter will
|
|
|
|
|
// disregard attempts to use them in this way.
|
|
|
|
|
IsValid = false;
|
|
|
|
|
IsSymbolVar = true;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SymbolValueHex = mFormatter.FormatHexValue(sym.Value, 4);
|
|
|
|
|
SymbolValueDecimal = mFormatter.FormatDecimalValue(sym.Value);
|
|
|
|
|
} else {
|
|
|
|
|
// Valid but unknown symbol. This is fine -- symbols don't have to exist.
|
|
|
|
|
SymbolValueHex = SYMBOL_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
SymbolValueHex = SYMBOL_NOT_USED;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
|
|
|
|
UpdatePreview();
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Updates the contents of the preview text box.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private void UpdatePreview() {
|
|
|
|
|
// Generate a descriptor from the controls. This isn't strictly necessary, but it
|
|
|
|
|
// gets all of the data in one small package.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
FormatDescriptor dfd = CreateDescriptorFromControls();
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
if (dfd == null) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
// Showing the right thing for the default format is surprisingly hard. There
|
|
|
|
|
// are a bunch of complicated steps that are performed in sequence, including
|
|
|
|
|
// the "nearby label" lookups, the elision of hidden symbols, and other
|
|
|
|
|
// obscure bits that may get tweaked from time to time. These things are not
|
|
|
|
|
// easy to factor out because we're slicing the data at a different angle: the
|
|
|
|
|
// initial pass walks the entire file looking for one thing at a point before
|
|
|
|
|
// analysis has completed, while here we're trying to mimic all of the
|
|
|
|
|
// steps for a single offset, after analysis has finished. It's a lot of work
|
|
|
|
|
// to show text that they'll see as soon as they hit "OK".
|
|
|
|
|
PreviewText = string.Empty;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
StringBuilder sb = new StringBuilder(16);
|
|
|
|
|
|
|
|
|
|
// Show the opcode. Don't bother trying to figure out width disambiguation here.
|
|
|
|
|
sb.Append(mFormatter.FormatOpcode(mOpDef, OpDef.WidthDisambiguation.None));
|
|
|
|
|
sb.Append(' ');
|
|
|
|
|
|
|
|
|
|
bool showHashPrefix = mOpDef.IsImmediate ||
|
|
|
|
|
mOpDef.AddrMode == OpDef.AddressMode.BlockMove;
|
|
|
|
|
if (showHashPrefix) {
|
|
|
|
|
sb.Append('#');
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
Anattrib attr = mProject.GetAnattrib(mOffset);
|
|
|
|
|
int previewHexDigits = (attr.Length - 1) * 2;
|
|
|
|
|
int operandValue = mOperandValue;
|
|
|
|
|
bool isPcRelative = false;
|
|
|
|
|
bool isBlockMove = false;
|
|
|
|
|
if (attr.OperandAddress >= 0) {
|
|
|
|
|
if (mOpDef.AddrMode == OpDef.AddressMode.PCRel) {
|
|
|
|
|
previewHexDigits = 4; // show branches as $xxxx even when on zero page
|
|
|
|
|
isPcRelative = true;
|
|
|
|
|
} else if (mOpDef.AddrMode == OpDef.AddressMode.PCRelLong ||
|
|
|
|
|
mOpDef.AddrMode == OpDef.AddressMode.StackPCRelLong) {
|
|
|
|
|
isPcRelative = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (mOpDef.AddrMode == OpDef.AddressMode.BlockMove) {
|
|
|
|
|
// MVN and MVP screw things up by having two operands in one instruction.
|
|
|
|
|
// We deal with this by passing in the value from the second byte
|
|
|
|
|
// (source bank) as the value, and applying the chosen format to both bytes.
|
|
|
|
|
isBlockMove = true;
|
|
|
|
|
operandValue = mOperandValue >> 8;
|
|
|
|
|
previewHexDigits = 2;
|
|
|
|
|
}
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dfd.FormatSubType) {
|
|
|
|
|
case FormatDescriptor.SubType.Hex:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
sb.Append(mFormatter.FormatHexValue(operandValue, previewHexDigits));
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.Decimal:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
sb.Append(mFormatter.FormatDecimalValue(operandValue));
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.Binary:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
sb.Append(mFormatter.FormatBinaryValue(operandValue, 8));
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
2019-08-12 00:59:20 +00:00
|
|
|
|
case FormatDescriptor.SubType.Ascii:
|
2019-08-10 21:24:19 +00:00
|
|
|
|
case FormatDescriptor.SubType.HighAscii:
|
2019-08-12 00:59:20 +00:00
|
|
|
|
case FormatDescriptor.SubType.C64Petscii:
|
|
|
|
|
case FormatDescriptor.SubType.C64Screen:
|
|
|
|
|
CharEncoding.Encoding enc = PseudoOp.SubTypeToEnc(dfd.FormatSubType);
|
2019-09-07 20:39:22 +00:00
|
|
|
|
sb.Append(mFormatter.FormatCharacterValue(operandValue, enc));
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.Symbol:
|
|
|
|
|
if (mProject.SymbolTable.TryGetValue(dfd.SymbolRef.Label, out Symbol sym)) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
// Block move is a little weird. "MVN label1,label2" is supposed to use
|
|
|
|
|
// the bank byte, while "MVN #const1,#const2" uses the entire symbol.
|
|
|
|
|
// The easiest thing to do is require the user to specify the "bank"
|
|
|
|
|
// part for 24-bit symbols, and always generate this as an immediate.
|
|
|
|
|
//
|
|
|
|
|
// MVN/MVP are also the only instructions with two operands, something
|
|
|
|
|
// we don't really handle.
|
|
|
|
|
// TODO(someday): allow a different symbol for each part of the operand.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
// Hack to make relative branches look right in the preview window.
|
|
|
|
|
// Otherwise they show up like "<LABEL" because they appear to be
|
|
|
|
|
// only 8 bits.
|
|
|
|
|
int operandLen = dfd.Length - 1;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (operandLen == 1 && isPcRelative) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
operandLen = 2;
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
|
|
|
|
// Set the operand length to 1 for block move so we use the part
|
|
|
|
|
// operators (<, >, ^) rather than bit-shifting.
|
|
|
|
|
if (isBlockMove) {
|
|
|
|
|
operandLen = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
PseudoOp.FormatNumericOpFlags flags;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (isPcRelative) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
flags = PseudoOp.FormatNumericOpFlags.IsPcRel;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (showHashPrefix) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
flags = PseudoOp.FormatNumericOpFlags.HasHashPrefix;
|
|
|
|
|
} else {
|
|
|
|
|
flags = PseudoOp.FormatNumericOpFlags.None;
|
|
|
|
|
}
|
|
|
|
|
string str = PseudoOp.FormatNumericOperand(mFormatter,
|
|
|
|
|
mProject.SymbolTable, null, dfd,
|
2019-09-07 20:39:22 +00:00
|
|
|
|
operandValue, operandLen, flags);
|
|
|
|
|
sb.Append(str);
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
if (sym.SymbolSource == Symbol.Source.Auto) {
|
|
|
|
|
mIsSymbolAuto = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
sb.Append(dfd.SymbolRef.Label + " (?)");
|
2019-07-08 22:40:30 +00:00
|
|
|
|
Debug.Assert(!string.IsNullOrEmpty(dfd.SymbolRef.Label));
|
|
|
|
|
//symbolValueLabel.Text = Properties.Resources.MSG_SYMBOL_NOT_FOUND;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Debug.Assert(false);
|
2019-09-07 20:39:22 +00:00
|
|
|
|
sb.Append("BUG");
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
|
|
|
|
if (isBlockMove) {
|
|
|
|
|
sb.Append(",#<dest>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PreviewText = sb.ToString();
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
#region Basic Format
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public bool FormatDefault {
|
|
|
|
|
get { return mFormatDefault; }
|
|
|
|
|
set { mFormatDefault = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatDefault;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public bool FormatHex {
|
|
|
|
|
get { return mFormatHex; }
|
|
|
|
|
set { mFormatHex = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatHex;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public bool FormatDecimal {
|
|
|
|
|
get { return mFormatDecimal; }
|
|
|
|
|
set { mFormatDecimal = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatDecimal;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public bool FormatBinary {
|
|
|
|
|
get { return mFormatBinary; }
|
|
|
|
|
set { mFormatBinary = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatBinary;
|
|
|
|
|
|
|
|
|
|
public bool IsFormatAsciiAllowed {
|
|
|
|
|
get { return mIsFormatAsciiAllowed; }
|
|
|
|
|
set { mIsFormatAsciiAllowed = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsFormatAsciiAllowed;
|
|
|
|
|
|
|
|
|
|
public bool FormatAscii {
|
|
|
|
|
get { return mFormatAscii; }
|
|
|
|
|
set { mFormatAscii = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatAscii;
|
|
|
|
|
|
|
|
|
|
public bool IsFormatPetsciiAllowed {
|
|
|
|
|
get { return mIsFormatPetsciiAllowed; }
|
|
|
|
|
set { mIsFormatPetsciiAllowed = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsFormatPetsciiAllowed;
|
|
|
|
|
|
|
|
|
|
public bool FormatPetscii {
|
|
|
|
|
get { return mFormatPetscii; }
|
|
|
|
|
set { mFormatPetscii = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatPetscii;
|
|
|
|
|
|
|
|
|
|
public bool IsFormatScreenCodeAllowed {
|
|
|
|
|
get { return mIsFormatScreenCodeAllowed; }
|
|
|
|
|
set { mIsFormatScreenCodeAllowed = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsFormatScreenCodeAllowed;
|
|
|
|
|
|
|
|
|
|
public bool FormatScreenCode {
|
|
|
|
|
get { return mFormatScreenCode; }
|
|
|
|
|
set { mFormatScreenCode = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatScreenCode;
|
|
|
|
|
|
|
|
|
|
public bool FormatSymbol {
|
|
|
|
|
get { return mFormatSymbol; }
|
|
|
|
|
set { mFormatSymbol = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatSymbol;
|
|
|
|
|
|
|
|
|
|
public string SymbolLabel {
|
|
|
|
|
get { return mSymbolLabel; }
|
|
|
|
|
set {
|
|
|
|
|
mSymbolLabel = value;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
// Set the radio button when the user starts typing.
|
|
|
|
|
if (mLoadDone) {
|
|
|
|
|
FormatSymbol = true;
|
|
|
|
|
}
|
|
|
|
|
UpdateControls();
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private string mSymbolLabel;
|
|
|
|
|
|
|
|
|
|
public bool IsSymbolAuto {
|
|
|
|
|
get { return mIsSymbolAuto; }
|
|
|
|
|
set { mIsSymbolAuto = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsSymbolAuto;
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
public bool IsSymbolVar{
|
|
|
|
|
get { return mIsSymbolVar; }
|
|
|
|
|
set { mIsSymbolVar = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsSymbolVar;
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public string SymbolValueHex {
|
|
|
|
|
get { return mSymbolValueHex; }
|
|
|
|
|
set { mSymbolValueHex = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mSymbolValueHex;
|
|
|
|
|
|
|
|
|
|
public string SymbolValueDecimal {
|
|
|
|
|
get { return mSymbolValueDecimal; }
|
|
|
|
|
set { mSymbolValueDecimal = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mSymbolValueDecimal;
|
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
public bool IsPartPanelEnabled {
|
|
|
|
|
get { return mIsPartPanelEnabled; }
|
|
|
|
|
set { mIsPartPanelEnabled = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsPartPanelEnabled;
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
public bool FormatPartLow {
|
|
|
|
|
get { return mFormatPartLow; }
|
|
|
|
|
set { mFormatPartLow = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatPartLow;
|
|
|
|
|
|
|
|
|
|
public bool FormatPartHigh {
|
|
|
|
|
get { return mFormatPartHigh; }
|
|
|
|
|
set { mFormatPartHigh = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatPartHigh;
|
|
|
|
|
|
|
|
|
|
public bool FormatPartBank {
|
|
|
|
|
get { return mFormatPartBank; }
|
|
|
|
|
set { mFormatPartBank = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mFormatPartBank;
|
|
|
|
|
|
|
|
|
|
public string PreviewText {
|
|
|
|
|
get { return mPreviewText; }
|
|
|
|
|
set { mPreviewText = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mPreviewText;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// Configures the basic formatting options, based on the existing format descriptor.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
private void BasicFormat_Loaded() {
|
|
|
|
|
// Can this be represented as a character? We only allow the printable set
|
|
|
|
|
// here, not the extended set (which includes control characters).
|
|
|
|
|
if (mOperandValue == (byte) mOperandValue) {
|
|
|
|
|
IsFormatAsciiAllowed =
|
|
|
|
|
CharEncoding.IsPrintableLowOrHighAscii((byte)mOperandValue);
|
|
|
|
|
IsFormatPetsciiAllowed =
|
|
|
|
|
CharEncoding.IsPrintableC64Petscii((byte)mOperandValue);
|
|
|
|
|
IsFormatScreenCodeAllowed =
|
|
|
|
|
CharEncoding.IsPrintableC64ScreenCode((byte)mOperandValue);
|
|
|
|
|
} else {
|
|
|
|
|
IsFormatAsciiAllowed = IsFormatPetsciiAllowed = IsFormatScreenCodeAllowed =
|
|
|
|
|
false;
|
|
|
|
|
}
|
2019-07-08 22:40:30 +00:00
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
SymbolLabel = string.Empty;
|
|
|
|
|
FormatPartLow = true; // could default to high for MVN/MVP
|
|
|
|
|
FormatDefault = true; // if nothing better comes along
|
|
|
|
|
|
|
|
|
|
// Is there an operand format at this location? If not, we're done.
|
|
|
|
|
if (!mProject.OperandFormats.TryGetValue(mOffset, out FormatDescriptor dfd)) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: it's entirely possible to have a weird format (e.g. string) if the
|
|
|
|
|
// instruction used to be hinted as data. Handle it gracefully.
|
|
|
|
|
switch (dfd.FormatType) {
|
|
|
|
|
case FormatDescriptor.Type.NumericLE:
|
|
|
|
|
switch (dfd.FormatSubType) {
|
|
|
|
|
case FormatDescriptor.SubType.Hex:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatHex = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.Decimal:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatDecimal = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.Binary:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatBinary = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
2019-08-12 00:59:20 +00:00
|
|
|
|
case FormatDescriptor.SubType.Ascii:
|
2019-08-10 21:24:19 +00:00
|
|
|
|
case FormatDescriptor.SubType.HighAscii:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (IsFormatAsciiAllowed) {
|
|
|
|
|
FormatAscii = true;
|
|
|
|
|
}
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
2019-08-16 00:53:12 +00:00
|
|
|
|
case FormatDescriptor.SubType.C64Petscii:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (IsFormatPetsciiAllowed) {
|
|
|
|
|
FormatPetscii = true;
|
|
|
|
|
}
|
2019-08-16 00:53:12 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.C64Screen:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (IsFormatScreenCodeAllowed) {
|
|
|
|
|
FormatScreenCode = true;
|
|
|
|
|
}
|
2019-08-16 00:53:12 +00:00
|
|
|
|
break;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
case FormatDescriptor.SubType.Symbol:
|
|
|
|
|
Debug.Assert(dfd.HasSymbol);
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatSymbol = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
switch (dfd.SymbolRef.ValuePart) {
|
|
|
|
|
case WeakSymbolRef.Part.Low:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatPartLow = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case WeakSymbolRef.Part.High:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatPartHigh = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case WeakSymbolRef.Part.Bank:
|
2019-09-07 20:39:22 +00:00
|
|
|
|
FormatPartBank = true;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Debug.Assert(false);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
SymbolLabel = dfd.SymbolRef.Label;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.SubType.None:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FormatDescriptor.Type.NumericBE:
|
Change the way string formats are defined
We used to use type="String", with the sub-type indicating whether
the string was null-terminated, prefixed with a length, or whatever.
This didn't leave much room for specifying a character encoding,
which is orthogonal to the sub-type.
What we actually want is to have the type specify the string type,
and then have the sub-type determine the character encoding. These
sub-types can also be used with the Numeric type to specify the
encoding of character operands.
This change updates the enum definitions and the various bits of
code that use them, but does not add any code for working with
non-ASCII character encodings.
The project file version number was incremented to 2, since the new
FormatDescriptor serialization is mildly incompatible with the old.
(Won't explode, but it'll post a complaint and ignore the stuff
it doesn't recognize.)
While I was at it, I finished removing DciReverse. It's still part
of the 2005-string-types regression test, which currently fails
because the generated source doesn't match.
2019-08-07 22:23:23 +00:00
|
|
|
|
case FormatDescriptor.Type.StringGeneric:
|
|
|
|
|
case FormatDescriptor.Type.StringReverse:
|
|
|
|
|
case FormatDescriptor.Type.StringNullTerm:
|
|
|
|
|
case FormatDescriptor.Type.StringL8:
|
|
|
|
|
case FormatDescriptor.Type.StringL16:
|
|
|
|
|
case FormatDescriptor.Type.StringDci:
|
|
|
|
|
case FormatDescriptor.Type.Dense:
|
2019-07-08 22:40:30 +00:00
|
|
|
|
case FormatDescriptor.Type.Fill:
|
|
|
|
|
default:
|
|
|
|
|
// Unexpected; used to be data?
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
|
|
|
|
// In theory, if FormatDefault is still checked, we failed to find a useful match
|
|
|
|
|
// for the format descriptor. In practice, the radio button checkification stuff
|
|
|
|
|
// happens later. If we want to tell the user that there's a bad descriptor present,
|
|
|
|
|
// we'll need to track it locally, or test all known radio buttons for True.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a FormatDescriptor from the current state of the dialog controls.
|
|
|
|
|
/// </summary>
|
2019-09-07 20:39:22 +00:00
|
|
|
|
/// <returns>New FormatDescriptor. Will return null if the default format is
|
|
|
|
|
/// selected, or symbol is selected with an empty label.</returns>
|
2019-07-08 22:40:30 +00:00
|
|
|
|
private FormatDescriptor CreateDescriptorFromControls() {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
int instructionLength = mProject.GetAnattrib(mOffset).Length;
|
|
|
|
|
|
|
|
|
|
if (FormatSymbol) {
|
|
|
|
|
if (string.IsNullOrEmpty(SymbolLabel)) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
// empty symbol --> default format (intuitive way to delete label reference)
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
WeakSymbolRef.Part part;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (FormatPartLow) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
part = WeakSymbolRef.Part.Low;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatPartHigh) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
part = WeakSymbolRef.Part.High;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatPartBank) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
part = WeakSymbolRef.Part.Bank;
|
|
|
|
|
} else {
|
|
|
|
|
Debug.Assert(false);
|
|
|
|
|
part = WeakSymbolRef.Part.Low;
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
return FormatDescriptor.Create(instructionLength,
|
|
|
|
|
new WeakSymbolRef(SymbolLabel, part), false);
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FormatDescriptor.SubType subType;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
if (FormatDefault) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
return null;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatHex) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
subType = FormatDescriptor.SubType.Hex;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatDecimal) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
subType = FormatDescriptor.SubType.Decimal;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatBinary) {
|
2019-07-08 22:40:30 +00:00
|
|
|
|
subType = FormatDescriptor.SubType.Binary;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatAscii) {
|
2019-08-10 21:24:19 +00:00
|
|
|
|
if (mOperandValue > 0x7f) {
|
|
|
|
|
subType = FormatDescriptor.SubType.HighAscii;
|
|
|
|
|
} else {
|
2019-08-12 00:59:20 +00:00
|
|
|
|
subType = FormatDescriptor.SubType.Ascii;
|
2019-08-10 21:24:19 +00:00
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatPetscii) {
|
2019-08-16 00:53:12 +00:00
|
|
|
|
subType = FormatDescriptor.SubType.C64Petscii;
|
2019-09-07 20:39:22 +00:00
|
|
|
|
} else if (FormatScreenCode) {
|
2019-08-16 00:53:12 +00:00
|
|
|
|
subType = FormatDescriptor.SubType.C64Screen;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
} else {
|
|
|
|
|
Debug.Assert(false);
|
|
|
|
|
subType = FormatDescriptor.SubType.None;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
return FormatDescriptor.Create(instructionLength,
|
2019-07-08 22:40:30 +00:00
|
|
|
|
FormatDescriptor.Type.NumericLE, subType);
|
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
|
|
|
|
#endregion Basic Format
|
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
#region Numeric References
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
public bool ShowNarNotAddress {
|
|
|
|
|
get { return mShowNarNotAddress; }
|
|
|
|
|
set { mShowNarNotAddress = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarNotAddress;
|
|
|
|
|
|
|
|
|
|
public bool ShowNarEditLabel {
|
|
|
|
|
get { return mShowNarEditLabel; }
|
|
|
|
|
set { mShowNarEditLabel = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarEditLabel;
|
|
|
|
|
|
|
|
|
|
public bool ShowNarCurrentLabel {
|
|
|
|
|
get { return mShowNarCurrentLabel; }
|
|
|
|
|
set { mShowNarCurrentLabel = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarCurrentLabel;
|
|
|
|
|
|
|
|
|
|
public string NarLabelOffsetText {
|
|
|
|
|
get { return mNarLabelOffsetText; }
|
|
|
|
|
set { mNarLabelOffsetText = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mNarLabelOffsetText;
|
|
|
|
|
|
|
|
|
|
public string NarTargetLabel {
|
|
|
|
|
get { return mNarTargetLabel; }
|
|
|
|
|
set { mNarTargetLabel = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mNarTargetLabel;
|
|
|
|
|
|
|
|
|
|
public string CreateEditLabelText {
|
|
|
|
|
get { return mCreateEditLabelText; }
|
|
|
|
|
set { mCreateEditLabelText = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mCreateEditLabelText;
|
|
|
|
|
|
|
|
|
|
public bool ShowNarExternalSymbol {
|
|
|
|
|
get { return mShowNarExternalSymbol; }
|
|
|
|
|
set { mShowNarExternalSymbol = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarExternalSymbol;
|
|
|
|
|
|
|
|
|
|
public bool ShowNarPlatformSymbol {
|
|
|
|
|
get { return mShowNarPlatformSymbol; }
|
|
|
|
|
set { mShowNarPlatformSymbol = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarPlatformSymbol;
|
|
|
|
|
|
|
|
|
|
public string NarPlatformSymbol {
|
|
|
|
|
get { return mNarPlatformSymbol; }
|
|
|
|
|
set { mNarPlatformSymbol = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mNarPlatformSymbol;
|
|
|
|
|
|
|
|
|
|
public bool ShowNarNoProjectMatch {
|
|
|
|
|
get { return mShowNarNoProjectMatch; }
|
|
|
|
|
set { mShowNarNoProjectMatch = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarNoProjectMatch;
|
|
|
|
|
|
|
|
|
|
public bool ShowNarProjectSymbol {
|
|
|
|
|
get { return mShowNarProjectSymbol; }
|
|
|
|
|
set { mShowNarProjectSymbol = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowNarProjectSymbol;
|
|
|
|
|
|
|
|
|
|
public string NarProjectSymbol {
|
|
|
|
|
get { return mNarProjectSymbol; }
|
|
|
|
|
set { mNarProjectSymbol = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mNarProjectSymbol;
|
|
|
|
|
|
|
|
|
|
public string CreateEditProjectSymbolText {
|
|
|
|
|
get { return mCreateEditProjectSymbolText; }
|
|
|
|
|
set { mCreateEditProjectSymbolText = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mCreateEditProjectSymbolText;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Edited label value. Will be null if the label hasn't been created, or has been
|
|
|
|
|
/// deleted (by entering a blank string in the label edit box).
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Symbol mEditedLabel;
|
|
|
|
|
private bool mLabelHasBeenEdited;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Address associated with the label (for the Symbol's value).
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int mLabelTargetAddress = -1;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Offset of edited label.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int mEditedLabelOffset = -1;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Edited project symbol. Will be null if the symbol doesn't exist. Symbols can't
|
|
|
|
|
/// be deleted.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private DefSymbol mEditedProjectSymbol;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Configures the UI in the local variables box at load time.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void NumericReferences_Loaded() {
|
|
|
|
|
SymbolEditOffsetResult = -1;
|
|
|
|
|
|
|
|
|
|
Anattrib attr = mProject.GetAnattrib(mOffset);
|
|
|
|
|
|
|
|
|
|
if (attr.OperandOffset >= 0) {
|
|
|
|
|
// Operand target is inside the file.
|
|
|
|
|
ShowNarEditLabel = true;
|
|
|
|
|
|
|
|
|
|
// Seek back to the start of the instruction or data item if the operand points
|
|
|
|
|
// into the middle of one. This is *not* the same as the "nearby" search,
|
|
|
|
|
// which will traverse multiple items to find a match.
|
|
|
|
|
mEditedLabelOffset =
|
|
|
|
|
DataAnalysis.GetBaseOperandOffset(mProject, attr.OperandOffset);
|
|
|
|
|
mLabelTargetAddress = mProject.GetAnattrib(mEditedLabelOffset).Address;
|
|
|
|
|
if (mProject.UserLabels.TryGetValue(mEditedLabelOffset, out Symbol sym)) {
|
|
|
|
|
// Has a label.
|
|
|
|
|
ShowNarCurrentLabel = true;
|
|
|
|
|
if (mEditedLabelOffset != attr.OperandOffset) {
|
|
|
|
|
NarLabelOffsetText = string.Format(CURRENT_LABEL_ADJUSTED_FMT,
|
|
|
|
|
mFormatter.FormatAdjustment(attr.OperandOffset - mEditedLabelOffset));
|
|
|
|
|
} else {
|
|
|
|
|
NarLabelOffsetText = CURRENT_LABEL;
|
|
|
|
|
}
|
|
|
|
|
NarTargetLabel = sym.Label;
|
|
|
|
|
mEditedLabel = sym;
|
|
|
|
|
CreateEditLabelText = EDIT_LABEL;
|
|
|
|
|
} else {
|
|
|
|
|
NarLabelOffsetText = CURRENT_LABEL;
|
|
|
|
|
CreateEditLabelText = CREATE_LABEL;
|
|
|
|
|
}
|
|
|
|
|
} else if (attr.OperandAddress >= 0) {
|
|
|
|
|
ShowNarExternalSymbol = true;
|
|
|
|
|
|
|
|
|
|
// There can be multiple symbols with the same value, so we walk through the
|
|
|
|
|
// list and identify the first matching platform and project symbols. We're
|
|
|
|
|
// only interested in address symbols, not constants.
|
|
|
|
|
Symbol firstPlatform = null;
|
|
|
|
|
Symbol firstProject = null;
|
|
|
|
|
foreach (Symbol sym in mProject.SymbolTable) {
|
|
|
|
|
if (sym.Value == attr.OperandAddress &&
|
|
|
|
|
sym.SymbolType != Symbol.Type.Constant) {
|
|
|
|
|
if (firstPlatform == null && sym.SymbolSource == Symbol.Source.Platform) {
|
|
|
|
|
firstPlatform = sym;
|
|
|
|
|
} else if (firstProject == null &&
|
|
|
|
|
sym.SymbolSource == Symbol.Source.Project) {
|
|
|
|
|
firstProject = sym;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (firstPlatform != null && firstProject != null) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (firstPlatform != null) {
|
|
|
|
|
ShowNarPlatformSymbol = true;
|
|
|
|
|
NarPlatformSymbol = firstPlatform.Label;
|
|
|
|
|
}
|
|
|
|
|
if (firstProject != null) {
|
|
|
|
|
ShowNarProjectSymbol = true;
|
|
|
|
|
NarProjectSymbol = firstProject.Label;
|
|
|
|
|
CreateEditProjectSymbolText = EDIT_PROJECT_SYMBOL;
|
|
|
|
|
|
|
|
|
|
mEditedProjectSymbol = (DefSymbol)firstProject;
|
|
|
|
|
PrevProjectPropertyResult = mEditedProjectSymbol;
|
|
|
|
|
} else {
|
|
|
|
|
ShowNarNoProjectMatch = true;
|
|
|
|
|
CreateEditProjectSymbolText = CREATE_PROJECT_SYMBOL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Probably an immediate operand.
|
|
|
|
|
ShowNarNotAddress = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EditLabel_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
EditLabel dlg = new EditLabel(this, mEditedLabel, mLabelTargetAddress,
|
|
|
|
|
mProject.SymbolTable);
|
|
|
|
|
if (dlg.ShowDialog() != true || mEditedLabel == dlg.LabelSym) {
|
|
|
|
|
Debug.WriteLine("No change to label, ignoring edit");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mEditedLabel = dlg.LabelSym;
|
|
|
|
|
mLabelHasBeenEdited = true;
|
|
|
|
|
|
|
|
|
|
// Update UI to match current state.
|
|
|
|
|
if (mEditedLabel == null) {
|
|
|
|
|
ShowNarCurrentLabel = false;
|
|
|
|
|
CreateEditLabelText = CREATE_LABEL;
|
|
|
|
|
} else {
|
|
|
|
|
ShowNarCurrentLabel = true;
|
|
|
|
|
CreateEditLabelText = EDIT_LABEL;
|
|
|
|
|
NarTargetLabel = mEditedLabel.Label;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EditProjectSymbol_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
DefSymbol origSym = mEditedProjectSymbol;
|
|
|
|
|
if (origSym == null) {
|
|
|
|
|
// Need to start with a symbol so we can set the value field.
|
2019-09-09 04:56:47 +00:00
|
|
|
|
string symName = "SYM";
|
|
|
|
|
if (!string.IsNullOrEmpty(SymbolLabel)) {
|
|
|
|
|
symName = SymbolLabel; // may not be valid, but it doesn't have to be
|
|
|
|
|
}
|
|
|
|
|
origSym = new DefSymbol(symName, mOperandValue, Symbol.Source.Project,
|
2019-09-08 23:41:54 +00:00
|
|
|
|
Symbol.Type.ExternalAddr, FormatDescriptor.SubType.None,
|
|
|
|
|
string.Empty, string.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter,
|
|
|
|
|
mProject.ProjectProps.ProjectSyms, origSym, null, false, true);
|
|
|
|
|
if (dlg.ShowDialog() != true) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Debug.Assert(dlg.NewSym != null); // can't delete a symbol from dialog
|
|
|
|
|
|
|
|
|
|
if (mEditedProjectSymbol == dlg.NewSym) {
|
|
|
|
|
Debug.WriteLine("No change to project symbol, ignoring edit");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
mEditedProjectSymbol = dlg.NewSym;
|
|
|
|
|
ShowNarProjectSymbol = true;
|
|
|
|
|
ShowNarNoProjectMatch = false;
|
|
|
|
|
NarProjectSymbol = mEditedProjectSymbol.Label;
|
|
|
|
|
CreateEditProjectSymbolText = EDIT_PROJECT_SYMBOL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Numeric References
|
|
|
|
|
|
|
|
|
|
#region Local Variables
|
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
public bool ShowLvNotApplicable {
|
|
|
|
|
get { return mShowLvNotApplicable; }
|
|
|
|
|
set { mShowLvNotApplicable = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowLvNotApplicable;
|
|
|
|
|
|
|
|
|
|
public bool ShowLvTableNotFound {
|
|
|
|
|
get { return mShowLvTableNotFound; }
|
|
|
|
|
set { mShowLvTableNotFound = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowLvTableNotFound;
|
|
|
|
|
|
|
|
|
|
public bool ShowLvNoMatchFound {
|
|
|
|
|
get { return mShowLvNoMatchFound; }
|
|
|
|
|
set { mShowLvNoMatchFound = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowLvNoMatchFound;
|
|
|
|
|
|
|
|
|
|
public bool ShowLvMatchFound {
|
|
|
|
|
get { return mShowLvMatchFound; }
|
|
|
|
|
set { mShowLvMatchFound = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowLvMatchFound;
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
public string LvMatchFoundText {
|
|
|
|
|
get { return mLvMatchFoundText; }
|
|
|
|
|
set { mLvMatchFoundText = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mLvMatchFoundText;
|
|
|
|
|
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
public string LocalVariableLabel {
|
|
|
|
|
get { return mLocalVariableLabel; }
|
|
|
|
|
set { mLocalVariableLabel = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mLocalVariableLabel;
|
|
|
|
|
|
|
|
|
|
public bool ShowLvCreateEditButton {
|
|
|
|
|
get { return mShowLvCreateEditButton; }
|
|
|
|
|
set { mShowLvCreateEditButton = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowLvCreateEditButton;
|
|
|
|
|
|
|
|
|
|
public string CreateEditLocalVariableText {
|
|
|
|
|
get { return mCreateEditLocalVariableText; }
|
|
|
|
|
set { mCreateEditLocalVariableText = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mCreateEditLocalVariableText;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Offset of LocalVariableTable we're going to modify.
|
|
|
|
|
/// </summary>
|
2019-09-08 23:41:54 +00:00
|
|
|
|
private int mLvTableOffset = -1;
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Local variable value. If there's already a definition, this will be pre-filled
|
|
|
|
|
/// with the current contents. Otherwise it will be null.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private DefSymbol mEditedLocalVar;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Clone of original table, with local edits.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private LocalVariableTable mEditedLvTable;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// Configures the UI in the local variables box at load time.
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
/// </summary>
|
2019-09-08 23:41:54 +00:00
|
|
|
|
private void LocalVariables_Loaded() {
|
|
|
|
|
if (!mOpDef.IsDirectPageInstruction && !mOpDef.IsStackRelInstruction) {
|
|
|
|
|
ShowLvNotApplicable = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
LvMatchFoundText = mOpDef.IsDirectPageInstruction ?
|
|
|
|
|
LV_MATCH_FOUND_ADDRESS : LV_MATCH_FOUND_CONSTANT;
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
LocalVariableLookup lvLookup =
|
|
|
|
|
new LocalVariableLookup(mProject.LvTables, mProject, false);
|
|
|
|
|
|
|
|
|
|
// If the operand is already a local variable, use whichever one the
|
|
|
|
|
// analyzer found.
|
|
|
|
|
Anattrib attr = mProject.GetAnattrib(mOffset);
|
|
|
|
|
if (attr.DataDescriptor != null && attr.DataDescriptor.HasSymbol &&
|
|
|
|
|
attr.DataDescriptor.SymbolRef.IsVariable) {
|
|
|
|
|
// Select the table that defines the local variable that's currently
|
|
|
|
|
// associated with this operand.
|
|
|
|
|
mLvTableOffset = lvLookup.GetDefiningTableOffset(mOffset,
|
|
|
|
|
attr.DataDescriptor.SymbolRef);
|
|
|
|
|
Debug.Assert(mLvTableOffset >= 0);
|
|
|
|
|
Debug.WriteLine("Symbol " + attr.DataDescriptor.SymbolRef +
|
|
|
|
|
" from var table at +" + mLvTableOffset.ToString("x6"));
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
} else {
|
2019-09-08 23:41:54 +00:00
|
|
|
|
// Operand is not a local variable. Find the closest table.
|
|
|
|
|
mLvTableOffset = lvLookup.GetNearestTableOffset(mOffset);
|
|
|
|
|
Debug.WriteLine("Closest table is at +" + mLvTableOffset.ToString("x6"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mLvTableOffset < 0) {
|
|
|
|
|
ShowLvTableNotFound = true;
|
|
|
|
|
} else {
|
|
|
|
|
// Found a table. Do we have a matching symbol?
|
|
|
|
|
ShowLvCreateEditButton = true;
|
|
|
|
|
mEditedLocalVar = lvLookup.GetSymbol(mOffset, mOperandValue,
|
|
|
|
|
mOpDef.IsDirectPageInstruction ?
|
|
|
|
|
Symbol.Type.ExternalAddr : Symbol.Type.Constant);
|
|
|
|
|
if (mEditedLocalVar == null) {
|
|
|
|
|
ShowLvNoMatchFound = true;
|
|
|
|
|
CreateEditLocalVariableText = CREATE_LOCAL_VARIABLE;
|
|
|
|
|
} else {
|
|
|
|
|
ShowLvMatchFound = true;
|
|
|
|
|
CreateEditLocalVariableText = EDIT_LOCAL_VARIABLE;
|
|
|
|
|
LocalVariableLabel = mEditedLocalVar.Label;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to update the symbol table while we work to make the uniqueness
|
|
|
|
|
// check come out right. Otherwise if you edit, rename FOO to BAR,
|
|
|
|
|
// then edit again, you won't be able to rename BAR back to FOO because
|
|
|
|
|
// it's already in the list and it's not self.
|
|
|
|
|
//
|
|
|
|
|
// We don't need the full LVT, just the list of symbols, but we'll want
|
|
|
|
|
// to hand the modified table to the caller when we exit.
|
|
|
|
|
LocalVariableTable lvt = mProject.LvTables[mLvTableOffset];
|
|
|
|
|
mEditedLvTable = new LocalVariableTable(lvt);
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EditLocalVariableButton_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
Debug.Assert(mOpDef.IsDirectPageInstruction || mOpDef.IsStackRelInstruction);
|
|
|
|
|
Debug.Assert(mLvTableOffset >= 0);
|
|
|
|
|
|
|
|
|
|
DefSymbol initialVar = mEditedLocalVar;
|
|
|
|
|
|
|
|
|
|
if (initialVar == null) {
|
|
|
|
|
Symbol.Type symType;
|
|
|
|
|
if (mOpDef.IsDirectPageInstruction) {
|
|
|
|
|
symType = Symbol.Type.ExternalAddr;
|
|
|
|
|
} else {
|
|
|
|
|
symType = Symbol.Type.Constant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to pre-load the value and type, but we can't create a symbol with
|
|
|
|
|
// an empty name. We don't really need to create something unique since the
|
|
|
|
|
// dialog will handle it.
|
|
|
|
|
initialVar = new DefSymbol("VAR", mOperandValue,
|
|
|
|
|
Symbol.Source.Variable, symType, FormatDescriptor.SubType.None,
|
|
|
|
|
string.Empty, string.Empty, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter,
|
|
|
|
|
mEditedLvTable.GetSortedByLabel(), initialVar, mProject.SymbolTable,
|
|
|
|
|
true, true);
|
|
|
|
|
if (dlg.ShowDialog() == true) {
|
|
|
|
|
if (mEditedLocalVar != dlg.NewSym) {
|
|
|
|
|
// Integrate result. Future edits will start with this.
|
|
|
|
|
// We can't delete a symbol, just create or modify.
|
|
|
|
|
Debug.Assert(dlg.NewSym != null);
|
|
|
|
|
mEditedLocalVar = dlg.NewSym;
|
|
|
|
|
mEditedLvTable.AddOrReplace(dlg.NewSym);
|
|
|
|
|
LocalVariableLabel = mEditedLocalVar.Label;
|
|
|
|
|
CreateEditLocalVariableText = EDIT_LOCAL_VARIABLE;
|
2019-09-08 23:41:54 +00:00
|
|
|
|
ShowLvNoMatchFound = false;
|
|
|
|
|
ShowLvMatchFound = true;
|
Instruction operand editor rework, part 2
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
2019-09-08 01:57:22 +00:00
|
|
|
|
} else {
|
|
|
|
|
Debug.WriteLine("No change to def symbol, ignoring edit");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
#endregion Local Variables
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|