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;
|
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>
|
2022-03-01 23:03:12 +00:00
|
|
|
|
/// Project symbol for this operand, when this dialog was opened. Will be null if
|
|
|
|
|
/// there was no matching project symbol. This is used as the "before" value for
|
|
|
|
|
/// updates to the project symbol set.
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// </summary>
|
2022-03-01 23:03:12 +00:00
|
|
|
|
public DefSymbol OrigProjectSymbolResult { get; private set; }
|
2019-09-08 23:41:54 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2022-03-01 23:03:12 +00:00
|
|
|
|
/// Edited project symbol, or null if no changes were made. This is used as the "after"
|
|
|
|
|
/// value for updates to the project symbol. This dialog is not allowed to delete
|
|
|
|
|
/// project symbols, so if this is null there's nothing to do.
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// </summary>
|
2022-03-01 23:03:12 +00:00
|
|
|
|
public DefSymbol ProjectSymbolResult { get; private set; }
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
|
|
|
|
|
/// <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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 23:03:12 +00:00
|
|
|
|
ProjectSymbolResult = mEditedProjectSymbol;
|
2019-09-08 23:41:54 +00:00
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
DialogResult = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-15 00:48:54 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Looks up the symbol in the symbol table. If not found there, it checks for a
|
|
|
|
|
/// match against the existing or edited project symbol.
|
|
|
|
|
/// </summary>
|
2019-11-17 00:34:42 +00:00
|
|
|
|
private bool LookupSymbol(string label, bool isNonUnique, out Symbol sym) {
|
|
|
|
|
if (isNonUnique) {
|
|
|
|
|
// Only applies to labels, so no need to check mEditedProjectSymbol. We
|
|
|
|
|
// could check mEditedLabel, but there's no reason to add a symbolic reference
|
|
|
|
|
// on top of the numeric reference.
|
|
|
|
|
int targetOffset;
|
|
|
|
|
Anattrib attr = mProject.GetAnattrib(mOffset);
|
|
|
|
|
if (attr.OperandOffset >= 0) {
|
|
|
|
|
targetOffset = attr.OperandOffset;
|
|
|
|
|
} else {
|
|
|
|
|
targetOffset = mOffset;
|
|
|
|
|
}
|
|
|
|
|
sym = mProject.FindBestNonUniqueLabel(label, targetOffset);
|
|
|
|
|
if (sym != null) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (mProject.SymbolTable.TryGetValue(label, out sym)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (mEditedProjectSymbol != null && label.Equals(mEditedProjectSymbol.Label)) {
|
|
|
|
|
sym = mEditedProjectSymbol;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-09-15 00:48:54 +00:00
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-08 22:40:30 +00:00
|
|
|
|
/// <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-11-17 00:34:42 +00:00
|
|
|
|
string trimLabel = Symbol.TrimAndValidateLabel(SymbolLabel,
|
|
|
|
|
mFormatter.NonUniqueLabelPrefix, out bool isValid, out bool unused1,
|
|
|
|
|
out bool unused2, out bool hasNonUniquePrefix,
|
|
|
|
|
out Symbol.LabelAnnotation unused3);
|
|
|
|
|
|
|
|
|
|
if (!isValid) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
SymbolValueHex = SYMBOL_INVALID;
|
|
|
|
|
IsValid = false;
|
2019-11-17 00:34:42 +00:00
|
|
|
|
} else if (LookupSymbol(trimLabel, hasNonUniquePrefix, out Symbol sym)) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
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 {
|
2019-11-17 00:34:42 +00:00
|
|
|
|
// Valid but unknown symbol. This is fine -- symbols don't have to exist --
|
|
|
|
|
// but it's a little weird for non-unique symbols.
|
2019-09-07 20:39:22 +00:00
|
|
|
|
SymbolValueHex = SYMBOL_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
SymbolValueHex = SYMBOL_NOT_USED;
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
2019-09-07 20:39:22 +00:00
|
|
|
|
|
2021-10-16 20:40:27 +00:00
|
|
|
|
// We want to disable the create/edit label button if a symbol has been
|
|
|
|
|
// specified, because the label being edited is the one that the numeric
|
|
|
|
|
// reference points to, not the one the symbol points to.
|
|
|
|
|
// TODO(maybe): leave it enabled if the symbolic ref matches the numeric ref.
|
|
|
|
|
IsDiddleLabelEnabled = !FormatSymbol;
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
UpdatePreview();
|
2019-09-15 00:48:54 +00:00
|
|
|
|
UpdateCopyToOperand();
|
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) {
|
2020-10-11 21:35:17 +00:00
|
|
|
|
if (mOpDef.AddrMode == OpDef.AddressMode.PCRel ||
|
|
|
|
|
mOpDef.AddrMode == OpDef.AddressMode.DPPCRel) {
|
2019-09-07 20:39:22 +00:00
|
|
|
|
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:
|
2019-11-17 00:34:42 +00:00
|
|
|
|
string trimLabel = Symbol.TrimAndValidateLabel(SymbolLabel,
|
|
|
|
|
mFormatter.NonUniqueLabelPrefix, out bool isValid, out bool unused1,
|
|
|
|
|
out bool unused2, out bool hasNonUniquePrefix,
|
|
|
|
|
out Symbol.LabelAnnotation unused3);
|
2020-01-01 17:08:22 +00:00
|
|
|
|
if (string.IsNullOrEmpty(trimLabel)) {
|
|
|
|
|
sb.Append("?");
|
|
|
|
|
} else if (LookupSymbol(trimLabel, hasNonUniquePrefix, 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
|
|
|
|
//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;
|
2019-11-17 00:34:42 +00:00
|
|
|
|
// this calls UpdateControls; don't do it twice
|
|
|
|
|
} else {
|
|
|
|
|
UpdateControls();
|
2019-09-07 20:39:22 +00:00
|
|
|
|
}
|
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
|
2020-10-15 21:03:32 +00:00
|
|
|
|
// instruction used to be tagged as code-stop. Handle it gracefully.
|
2019-07-08 22:40:30 +00:00
|
|
|
|
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-11-17 00:34:42 +00:00
|
|
|
|
SymbolLabel = Symbol.ConvertLabelForDisplay(dfd.SymbolRef.Label,
|
|
|
|
|
Symbol.LabelAnnotation.None, true, mFormatter);
|
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:
|
2021-10-13 21:48:05 +00:00
|
|
|
|
case FormatDescriptor.Type.Uninit:
|
|
|
|
|
case FormatDescriptor.Type.Junk:
|
2019-07-08 22:40:30 +00:00
|
|
|
|
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-11-17 00:34:42 +00:00
|
|
|
|
|
|
|
|
|
// Deal with non-unique labels. If the label refers to an existing
|
|
|
|
|
// symbol, use its label, which will have the tag. If the label doesn't
|
|
|
|
|
// have a match, discard it -- we don't support weak refs to ambiguous
|
|
|
|
|
// non-unique symbols.
|
|
|
|
|
string trimLabel = Symbol.TrimAndValidateLabel(SymbolLabel,
|
|
|
|
|
mFormatter.NonUniqueLabelPrefix, out bool isValid, out bool unused1,
|
|
|
|
|
out bool unused2, out bool hasNonUniquePrefix,
|
|
|
|
|
out Symbol.LabelAnnotation unused3);
|
|
|
|
|
if (isValid && hasNonUniquePrefix) {
|
|
|
|
|
if (LookupSymbol(trimLabel, hasNonUniquePrefix, out Symbol sym)) {
|
2019-12-26 03:14:51 +00:00
|
|
|
|
trimLabel = sym.Label;
|
2019-11-17 00:34:42 +00:00
|
|
|
|
} else {
|
|
|
|
|
Debug.WriteLine("Attempt to create ref to non-existant non-unique sym");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-07 20:39:22 +00:00
|
|
|
|
return FormatDescriptor.Create(instructionLength,
|
2019-12-26 03:14:51 +00:00
|
|
|
|
new WeakSymbolRef(trimLabel, 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;
|
|
|
|
|
|
2019-09-15 00:48:54 +00:00
|
|
|
|
public bool IsCopyToOperandEnabled {
|
|
|
|
|
get { return mIsCopyToOperandEnabled; }
|
|
|
|
|
set { mIsCopyToOperandEnabled = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsCopyToOperandEnabled;
|
|
|
|
|
|
2021-10-16 20:40:27 +00:00
|
|
|
|
public bool IsDiddleLabelEnabled {
|
|
|
|
|
get { return mIsDiddleLabelEnabled; }
|
|
|
|
|
set { mIsDiddleLabelEnabled = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mIsDiddleLabelEnabled;
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// <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;
|
2019-09-15 00:48:54 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set to true if the label has been edited.
|
|
|
|
|
/// </summary>
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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>
|
2019-09-15 00:48:54 +00:00
|
|
|
|
/// Edited project symbol. If a symbol already exists, this will be initialized to the
|
|
|
|
|
/// existing value. Otherwise this will be null.
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// </summary>
|
2019-09-15 00:48:54 +00:00
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Project symbols can't be deleted from here, so a null reference always means that
|
|
|
|
|
/// there's no symbol and we haven't made an edit.
|
|
|
|
|
/// </remarks>
|
2019-09-08 23:41:54 +00:00
|
|
|
|
private DefSymbol mEditedProjectSymbol;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-10-16 20:40:27 +00:00
|
|
|
|
/// Configures the UI in the Numeric Address Reference box at load time.
|
2019-09-08 23:41:54 +00:00
|
|
|
|
/// </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.
|
2020-02-29 00:11:35 +00:00
|
|
|
|
// TODO: this can create a situation where the code list shows FUBAR-1 but we
|
|
|
|
|
// edit an earlier label, if the earlier label has a multi-byte format that
|
2022-01-12 22:07:30 +00:00
|
|
|
|
// includes the target address. (An example can be found in 20200-ui-edge-cases.)
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2019-11-17 00:34:42 +00:00
|
|
|
|
NarTargetLabel = sym.GenerateDisplayLabel(mFormatter);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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) {
|
2019-10-23 04:27:49 +00:00
|
|
|
|
if (sym.Value == attr.OperandAddress && !sym.IsConstant) {
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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;
|
2022-03-01 23:03:12 +00:00
|
|
|
|
OrigProjectSymbolResult = mEditedProjectSymbol;
|
2019-09-08 23:41:54 +00:00
|
|
|
|
} else {
|
|
|
|
|
ShowNarNoProjectMatch = true;
|
|
|
|
|
CreateEditProjectSymbolText = CREATE_PROJECT_SYMBOL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Probably an immediate operand.
|
|
|
|
|
ShowNarNotAddress = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-15 00:48:54 +00:00
|
|
|
|
private void UpdateCopyToOperand() {
|
|
|
|
|
IsCopyToOperandEnabled = false;
|
|
|
|
|
if (mEditedProjectSymbol != null) {
|
|
|
|
|
// We have a pre-existing or recently-edited symbol. See if the current
|
|
|
|
|
// operand configuration already matches.
|
|
|
|
|
if (!FormatSymbol || !mEditedProjectSymbol.Label.Equals(SymbolLabel)) {
|
|
|
|
|
IsCopyToOperandEnabled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-08 23:41:54 +00:00
|
|
|
|
private void EditLabel_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
EditLabel dlg = new EditLabel(this, mEditedLabel, mLabelTargetAddress,
|
2019-11-13 01:24:41 +00:00
|
|
|
|
mEditedLabelOffset, mProject.SymbolTable, mFormatter);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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;
|
2019-11-17 00:34:42 +00:00
|
|
|
|
NarTargetLabel = mEditedLabel.GenerateDisplayLabel(mFormatter);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
}
|
2019-09-17 21:38:16 +00:00
|
|
|
|
|
2019-09-18 02:01:14 +00:00
|
|
|
|
// Sort of nice to just hit return twice after entering a label, so move the focus
|
2019-09-17 21:38:16 +00:00
|
|
|
|
// to the OK button.
|
|
|
|
|
okButton.Focus();
|
2019-09-08 23:41:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EditProjectSymbol_Click(object sender, RoutedEventArgs e) {
|
2022-03-01 23:03:12 +00:00
|
|
|
|
DefSymbol initVals = mEditedProjectSymbol;
|
|
|
|
|
if (initVals == null) {
|
2019-09-08 23:41:54 +00:00
|
|
|
|
// Need to start with a symbol so we can set the value field.
|
2019-09-09 04:56:47 +00:00
|
|
|
|
string symName = "SYM";
|
2020-01-26 02:23:27 +00:00
|
|
|
|
if (!string.IsNullOrEmpty(SymbolLabel) &&
|
|
|
|
|
Asm65.Label.ValidateLabel(SymbolLabel)) {
|
|
|
|
|
symName = SymbolLabel;
|
2019-09-09 04:56:47 +00:00
|
|
|
|
}
|
2022-03-01 23:03:12 +00:00
|
|
|
|
initVals = new DefSymbol(symName, mOperandValue, Symbol.Source.Project,
|
Allow explicit widths in project/platform symbols, part 1
The ability to give explicit widths to local variables worked out
pretty well, so we're going to try adding the same thing to project
and platform symbols.
The first step is to allow widths to be specified in platform files,
and set with the project symbol editor. The DefSymbol editor is
also used for local variables, so a bit of dancing is required.
For platform/project symbols the width is optional, and is totally
ignored for constants. (For variables, constants are used for the
StackRel args, so the width is meaningful and required.)
We also now show the symbol's type (address or constant) and width
in the listing. This gets really distracting when overused, so we
only show it when the width is explicitly set. The default width
is 1, which most things will be, so users can make an aesthetic
choice there. (The place where widths make very little sense is when
the symbol represents a code entry point, rather than a data item.)
The maximum width of a local variable is now 256, but it's not
allowed to overlap with other variables or run of the end of the
direct page. The maximum width of a platform/project symbol is
65536, with bank-wrap behavior TBD.
The local variable table editor now refers to stack-relative
constants as such, rather than simply "constant", to make it clear
that it's not just defining an 8-bit constant.
Widths have been added to a handful of Apple II platform defs.
2019-10-01 21:58:24 +00:00
|
|
|
|
Symbol.Type.ExternalAddr, FormatDescriptor.SubType.None);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 23:03:12 +00:00
|
|
|
|
// Edit the symbol, locking the value so it can only apply to this operand.
|
|
|
|
|
// We want to pass in the symbol as it was before we made any edits, so that
|
|
|
|
|
// the user can always change the label back to what it was when this dialog
|
|
|
|
|
// was first opened.
|
2019-09-08 23:41:54 +00:00
|
|
|
|
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter,
|
2022-03-01 23:03:12 +00:00
|
|
|
|
mProject.ProjectProps.ProjectSyms, OrigProjectSymbolResult, initVals, null,
|
|
|
|
|
false, true);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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;
|
2019-09-15 00:48:54 +00:00
|
|
|
|
|
|
|
|
|
// The preview and symbol value display will use mEditedProjectSymbol if it's the
|
|
|
|
|
// only place the symbol exists, so we want to keep the other controls updated.
|
|
|
|
|
UpdateControls();
|
2019-09-18 02:01:14 +00:00
|
|
|
|
|
|
|
|
|
// Move the focus to the OK button.
|
|
|
|
|
okButton.Focus();
|
2019-09-15 00:48:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CopyToOperandButton_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
FormatSymbol = true;
|
|
|
|
|
SymbolLabel = mEditedProjectSymbol.Label;
|
|
|
|
|
IsCopyToOperandEnabled = false;
|
|
|
|
|
// changes to controls will call UpdateControls() for us
|
2019-09-08 23:41:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#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>
|
2021-10-16 20:40:27 +00:00
|
|
|
|
/// Configures the UI in the Local Variable 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 =
|
Label rework, part 6
Correct handling of local variables. We now correctly uniquify them
with regard to non-unique labels. Because local vars can effectively
have global scope we mostly want to treat them as global, but they're
uniquified relative to other globals very late in the process, so we
can't just throw them in the symbol table and be done. Fortunately
local variables exist in a separate namespace, so we just need to
uniquify the variables relative to the post-localization symbol table.
In other words, we take the symbol table, apply the label map, and
rename any variable that clashes.
This also fixes an older problem where we weren't masking the
leading '_' on variable labels when generating 64tass output.
The code list now makes non-unique labels obvious, but you can't tell
the difference between unique global and unique local. What's more,
the default type value in Edit Label is now adjusted to Global for
unique locals that were auto-generated. To make it a bit easier to
figure out what's what, the Info panel now has a "label type" line
that reports the type.
The 2023-non-unique-labels test had some additional tests added to
exercise conflicts with local variables. The 2019-local-variables
test output changed slightly because the de-duplicated variable
naming convention was simplified.
2019-11-18 21:26:03 +00:00
|
|
|
|
new LocalVariableLookup(mProject.LvTables, mProject, null, false, false);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
Fix various local variable de-duplication bugs
In 1.5.0-dev1, as part of changes to the way label localization
works, the local variable de-duplicator started checking against a
filtered copy of the symbol table. Unfortunately it never
re-generated the table, so a long-lived LocalVariableLookup (like
the one used by LineListGen) would set up the dup map wrong and
be inconsistent with other parts of the program.
We now regenerate the table on every Reset().
The de-duplication stuff also had problems when opcodes and
operands were double-clicked on. When the opcode is clicked, the
selection should jump to the appropriate variable declaration, but
it wasn't being found because the label generated in the list was
in its original form. Fixed.
When an instruction operand is double-clicked, the instruction operand
editor opens with an "edit variable" shortcut. This was showing
the de-duplicated name, which isn't necessarily a bad thing, but it
was passing that value on to the DefSymbol editor, which thought it
was being asked to create a new entry. Fixed. (Entering the editor
through the LvTable editor works correctly, with nary a de-duplicated
name in sight. You'll be forced to rename it because it'll fail the
uniqueness test.)
References to de-duplicated local variables were getting lost when
the symbol's label was replaced (due largely to a convenient but
flawed shortcut: xrefs are attached to DefSymbol objects). Fixed by
linking the XrefSets.
Given the many issues and their relative subtlety, I decided to make
the modified names more obvious, and went back to the "_DUPn" naming
strategy. (I'm also considering just making it an error and
discarding conflicting entries during analysis... this is much more
complicated than I expected it to be.)
Quick tests can be performed in 2019-local-variables:
- go to +000026, double-click on the opcode, confirm sel change
- go to +000026, double-click on the operand, confirm orig name
shown in shortcut and that shortcut opens editor with orig name
- go to +00001a, down a line, click on PROJ_ZERO_DUP1 and confirm
that it has a single reference (from +000026)
- double-click on var table and confirm editing entry
2020-01-14 01:54:47 +00:00
|
|
|
|
DefSymbol existingVar = lvLookup.GetSymbol(mOffset, mOperandValue,
|
2019-09-08 23:41:54 +00:00
|
|
|
|
mOpDef.IsDirectPageInstruction ?
|
|
|
|
|
Symbol.Type.ExternalAddr : Symbol.Type.Constant);
|
Fix various local variable de-duplication bugs
In 1.5.0-dev1, as part of changes to the way label localization
works, the local variable de-duplicator started checking against a
filtered copy of the symbol table. Unfortunately it never
re-generated the table, so a long-lived LocalVariableLookup (like
the one used by LineListGen) would set up the dup map wrong and
be inconsistent with other parts of the program.
We now regenerate the table on every Reset().
The de-duplication stuff also had problems when opcodes and
operands were double-clicked on. When the opcode is clicked, the
selection should jump to the appropriate variable declaration, but
it wasn't being found because the label generated in the list was
in its original form. Fixed.
When an instruction operand is double-clicked, the instruction operand
editor opens with an "edit variable" shortcut. This was showing
the de-duplicated name, which isn't necessarily a bad thing, but it
was passing that value on to the DefSymbol editor, which thought it
was being asked to create a new entry. Fixed. (Entering the editor
through the LvTable editor works correctly, with nary a de-duplicated
name in sight. You'll be forced to rename it because it'll fail the
uniqueness test.)
References to de-duplicated local variables were getting lost when
the symbol's label was replaced (due largely to a convenient but
flawed shortcut: xrefs are attached to DefSymbol objects). Fixed by
linking the XrefSets.
Given the many issues and their relative subtlety, I decided to make
the modified names more obvious, and went back to the "_DUPn" naming
strategy. (I'm also considering just making it an error and
discarding conflicting entries during analysis... this is much more
complicated than I expected it to be.)
Quick tests can be performed in 2019-local-variables:
- go to +000026, double-click on the opcode, confirm sel change
- go to +000026, double-click on the operand, confirm orig name
shown in shortcut and that shortcut opens editor with orig name
- go to +00001a, down a line, click on PROJ_ZERO_DUP1 and confirm
that it has a single reference (from +000026)
- double-click on var table and confirm editing entry
2020-01-14 01:54:47 +00:00
|
|
|
|
if (existingVar == null) {
|
2019-09-08 23:41:54 +00:00
|
|
|
|
ShowLvNoMatchFound = true;
|
|
|
|
|
CreateEditLocalVariableText = CREATE_LOCAL_VARIABLE;
|
|
|
|
|
} else {
|
Fix various local variable de-duplication bugs
In 1.5.0-dev1, as part of changes to the way label localization
works, the local variable de-duplicator started checking against a
filtered copy of the symbol table. Unfortunately it never
re-generated the table, so a long-lived LocalVariableLookup (like
the one used by LineListGen) would set up the dup map wrong and
be inconsistent with other parts of the program.
We now regenerate the table on every Reset().
The de-duplication stuff also had problems when opcodes and
operands were double-clicked on. When the opcode is clicked, the
selection should jump to the appropriate variable declaration, but
it wasn't being found because the label generated in the list was
in its original form. Fixed.
When an instruction operand is double-clicked, the instruction operand
editor opens with an "edit variable" shortcut. This was showing
the de-duplicated name, which isn't necessarily a bad thing, but it
was passing that value on to the DefSymbol editor, which thought it
was being asked to create a new entry. Fixed. (Entering the editor
through the LvTable editor works correctly, with nary a de-duplicated
name in sight. You'll be forced to rename it because it'll fail the
uniqueness test.)
References to de-duplicated local variables were getting lost when
the symbol's label was replaced (due largely to a convenient but
flawed shortcut: xrefs are attached to DefSymbol objects). Fixed by
linking the XrefSets.
Given the many issues and their relative subtlety, I decided to make
the modified names more obvious, and went back to the "_DUPn" naming
strategy. (I'm also considering just making it an error and
discarding conflicting entries during analysis... this is much more
complicated than I expected it to be.)
Quick tests can be performed in 2019-local-variables:
- go to +000026, double-click on the opcode, confirm sel change
- go to +000026, double-click on the operand, confirm orig name
shown in shortcut and that shortcut opens editor with orig name
- go to +00001a, down a line, click on PROJ_ZERO_DUP1 and confirm
that it has a single reference (from +000026)
- double-click on var table and confirm editing entry
2020-01-14 01:54:47 +00:00
|
|
|
|
mEditedLocalVar = lvLookup.GetOriginalForm(existingVar);
|
2019-09-08 23:41:54 +00:00
|
|
|
|
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,
|
2019-11-09 04:44:45 +00:00
|
|
|
|
Symbol.Source.Variable, symType, Symbol.LabelAnnotation.None,
|
|
|
|
|
FormatDescriptor.SubType.None, 1, true, string.Empty,
|
|
|
|
|
DefSymbol.DirectionFlags.ReadWrite, null, string.Empty);
|
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
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 23:03:12 +00:00
|
|
|
|
// Unlike project symbols, we don't pass the original symbol value in. This is
|
|
|
|
|
// because we update a local copy of the LV table immediately, and pass that in
|
|
|
|
|
// for the uniqueness checks.
|
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
|
|
|
|
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter,
|
2022-03-01 23:03:12 +00:00
|
|
|
|
mEditedLvTable.GetSortedByLabel(), mEditedLocalVar, initialVar,
|
|
|
|
|
mProject.SymbolTable, true, 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
|
|
|
|
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-19 22:53:23 +00:00
|
|
|
|
|
|
|
|
|
okButton.Focus();
|
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
|
|
|
|
#endregion Local Variables
|
2019-07-08 22:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|