2019-06-16 23:34:47 +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;
|
2019-07-05 22:05:42 +00:00
|
|
|
|
using System.ComponentModel;
|
2019-06-16 23:34:47 +00:00
|
|
|
|
using System.Diagnostics;
|
2019-07-05 22:05:42 +00:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2019-06-16 23:34:47 +00:00
|
|
|
|
using System.Windows;
|
|
|
|
|
|
2019-10-22 20:52:19 +00:00
|
|
|
|
using Asm65;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
using CommonUtil;
|
2019-10-22 20:52:19 +00:00
|
|
|
|
|
2019-07-20 20:28:10 +00:00
|
|
|
|
namespace SourceGen.WpfGui {
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// <summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// Edit Address Region dialog.
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// </summary>
|
2019-07-05 22:05:42 +00:00
|
|
|
|
public partial class EditAddress : Window, INotifyPropertyChanged {
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private const string NON_ADDR_STR = "NA";
|
|
|
|
|
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// <summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// Updated address map entry. Will be null if we want to delete the existing entry.
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// </summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
public AddressMap.AddressMapEntry ResultEntry { get; private set; }
|
2021-09-22 21:39:39 +00:00
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Dialog header.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string OperationStr {
|
|
|
|
|
get { return mOperationStr; }
|
|
|
|
|
set { mOperationStr = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mOperationStr;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// Offset of first selected byte. (Does not change.)
|
2019-12-26 01:15:37 +00:00
|
|
|
|
/// </summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
public string RegionStartOffsetStr {
|
|
|
|
|
get { return mFormatter.FormatOffset24(mRegionStartOffset); }
|
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private int mRegionStartOffset;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// Offset of last selected byte. (Does not change.)
|
2019-12-26 01:15:37 +00:00
|
|
|
|
/// </summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
public string RegionEndOffsetStr {
|
|
|
|
|
get { return mFormatter.FormatOffset24(mRegionEndOffset); }
|
2019-12-26 01:15:37 +00:00
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private int mRegionEndOffset;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
|
|
|
|
|
public string RegionLengthStr {
|
2019-12-26 01:15:37 +00:00
|
|
|
|
get {
|
2021-09-27 00:06:43 +00:00
|
|
|
|
int count = mRegionEndOffset - mRegionStartOffset + 1;
|
|
|
|
|
return FormatLength(count);
|
2019-12-26 01:15:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set to true to show the offset/length stats for a current region.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool ShowExistingRegion {
|
|
|
|
|
get { return mShowExistingRegion; }
|
|
|
|
|
set { mShowExistingRegion = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowExistingRegion;
|
|
|
|
|
|
|
|
|
|
public bool ShowOption1 {
|
|
|
|
|
get { return mShowOption1; }
|
|
|
|
|
set { mShowOption1 = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowOption1;
|
|
|
|
|
|
|
|
|
|
public bool ShowOption2 {
|
|
|
|
|
get { return mShowOption2; }
|
|
|
|
|
set { mShowOption2 = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mShowOption2;
|
|
|
|
|
|
|
|
|
|
public bool EnableOption1 {
|
|
|
|
|
get { return mEnableOption1; }
|
|
|
|
|
set { mEnableOption1 = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mEnableOption1;
|
|
|
|
|
|
|
|
|
|
public bool EnableOption2 {
|
|
|
|
|
get { return mEnableOption2; }
|
|
|
|
|
set { mEnableOption2 = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mEnableOption2;
|
|
|
|
|
|
|
|
|
|
public bool CheckOption1 {
|
|
|
|
|
get { return mCheckOption1; }
|
|
|
|
|
set { mCheckOption1 = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mCheckOption1;
|
|
|
|
|
|
|
|
|
|
public bool CheckOption2 {
|
|
|
|
|
get { return mCheckOption2; }
|
|
|
|
|
set { mCheckOption2 = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mCheckOption2;
|
|
|
|
|
|
|
|
|
|
public string Option1Str {
|
|
|
|
|
get { return mOption1Str; }
|
|
|
|
|
set { mOption1Str = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mOption1Str;
|
|
|
|
|
|
|
|
|
|
public string Option2Str {
|
|
|
|
|
get { return mOption2Str; }
|
|
|
|
|
set { mOption2Str = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mOption2Str;
|
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Address at which a pre-label would be placed. This is determined by the parent
|
|
|
|
|
/// region, so its value is fixed.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int mPreLabelAddress;
|
|
|
|
|
public string PreLabelAddressStr {
|
2021-09-27 00:06:43 +00:00
|
|
|
|
get {
|
|
|
|
|
if (mPreLabelAddress == AddressMap.NON_ADDR) {
|
|
|
|
|
return "NA";
|
|
|
|
|
} else {
|
|
|
|
|
return "$" + mFormatter.FormatAddress(mPreLabelAddress, mShowBank);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private bool mShowBank;
|
|
|
|
|
|
|
|
|
|
public bool ShowErrorMessage {
|
|
|
|
|
get { return mShowErrorMessage; }
|
|
|
|
|
set { mShowErrorMessage = value; OnPropertyChanged(); }
|
2021-09-22 21:39:39 +00:00
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private bool mShowErrorMessage;
|
|
|
|
|
|
|
|
|
|
public string ErrorMessageStr {
|
|
|
|
|
get { return mErrorMessageStr; }
|
|
|
|
|
set { mErrorMessageStr = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private string mErrorMessageStr;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// <summary>
|
2019-12-26 01:15:37 +00:00
|
|
|
|
/// Address input TextBox.
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// </summary>
|
2019-12-26 01:15:37 +00:00
|
|
|
|
public string AddressText {
|
|
|
|
|
get { return mAddressText; }
|
|
|
|
|
set { mAddressText = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private string mAddressText;
|
2019-06-16 23:34:47 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
public bool UseRelativeAddressing {
|
|
|
|
|
get { return mUseRelativeAddressing; }
|
|
|
|
|
set { mUseRelativeAddressing = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mUseRelativeAddressing;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Pre-label input TextBox.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string PreLabelText {
|
|
|
|
|
get { return mPreLabelText; }
|
|
|
|
|
set { mPreLabelText = value; OnPropertyChanged(); UpdateControls(); }
|
|
|
|
|
}
|
|
|
|
|
private string mPreLabelText;
|
|
|
|
|
|
2019-07-05 22:05:42 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set to true when input is valid. Controls whether the OK button is enabled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsValid {
|
|
|
|
|
get { return mIsValid; }
|
2019-10-22 20:52:19 +00:00
|
|
|
|
set { mIsValid = value; OnPropertyChanged(); }
|
2019-07-05 22:05:42 +00:00
|
|
|
|
}
|
|
|
|
|
private bool mIsValid;
|
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// <summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// Set to true unless there are no valid options (e.g. invalid new region).
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// </summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
public bool EnableAttributeControls {
|
|
|
|
|
get { return mEnableAttributeControls; }
|
|
|
|
|
set { mEnableAttributeControls = value; OnPropertyChanged(); }
|
2019-10-22 20:52:19 +00:00
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private bool mEnableAttributeControls;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// <summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// Set to true if the region has a floating end point.
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// </summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
public bool IsFloating {
|
|
|
|
|
get { return mIsFloating; }
|
|
|
|
|
set { mIsFloating = value; OnPropertyChanged(); }
|
2019-10-22 20:52:19 +00:00
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private bool mIsFloating;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set to true if the region is not new, and thus can be deleted.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool CanDeleteRegion {
|
|
|
|
|
get { return mCanDeleteRegion; }
|
|
|
|
|
set { mCanDeleteRegion = value; OnPropertyChanged(); }
|
|
|
|
|
}
|
|
|
|
|
private bool mCanDeleteRegion;
|
2019-10-22 20:52:19 +00:00
|
|
|
|
|
2019-07-05 22:05:42 +00:00
|
|
|
|
// INotifyPropertyChanged implementation
|
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Result for option #1.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private AddressMap.AddressMapEntry mResultEntry1;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Result for option #2.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private AddressMap.AddressMapEntry mResultEntry2;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Maximum allowed address value, based on CPU type.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int mMaxAddressValue;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reference to project. We need the address map and symbol table.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private DisasmProject mProject;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reference to text formatter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Formatter mFormatter;
|
|
|
|
|
|
2019-06-16 23:34:47 +00:00
|
|
|
|
|
2019-12-26 01:15:37 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="owner">Parent window.</param>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// <param name="curRegion">Current region; will be null for new entries.</param>
|
|
|
|
|
/// <param name="newEntry">Prototype entry to create.</param>
|
|
|
|
|
/// <param name="selectionLen">Length, in bytes, of the selection.</param>
|
|
|
|
|
/// <param name="isSingleLine">True if the selection is a single line.</param>
|
2019-12-26 01:15:37 +00:00
|
|
|
|
/// <param name="project">Project reference.</param>
|
|
|
|
|
/// <param name="formatter">Text formatter object.</param>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
public EditAddress(Window owner, AddressMap.AddressRegion curRegion,
|
|
|
|
|
AddressMap.AddressMapEntry newEntry, int selectionLen, bool isSingleLine,
|
|
|
|
|
DisasmProject project, Formatter formatter) {
|
2019-12-26 01:15:37 +00:00
|
|
|
|
InitializeComponent();
|
|
|
|
|
Owner = owner;
|
|
|
|
|
DataContext = this;
|
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
Debug.Assert((curRegion == null) ^ (newEntry == null)); // exactly one must be true
|
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
mProject = project;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
mMaxAddressValue = project.CpuDef.MaxAddressValue;
|
2021-09-27 00:06:43 +00:00
|
|
|
|
mShowBank = !project.CpuDef.HasAddr16;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
mFormatter = formatter;
|
2019-10-22 20:52:19 +00:00
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
Configure(curRegion, newEntry, selectionLen, isSingleLine);
|
|
|
|
|
UpdateControls();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Configure(AddressMap.AddressRegion curRegion,
|
|
|
|
|
AddressMap.AddressMapEntry newEntry, int selectionLen, bool isSingleLine) {
|
|
|
|
|
Debug.WriteLine("Configuring AR: reg=" + curRegion + " newEnt=" + newEntry +
|
|
|
|
|
" selLen=" + selectionLen + " isSingle=" + isSingleLine);
|
|
|
|
|
|
|
|
|
|
ShowOption1 = ShowOption2 = true;
|
|
|
|
|
EnableOption1 = EnableOption2 = true;
|
|
|
|
|
CheckOption1 = true;
|
|
|
|
|
EnableAttributeControls = true;
|
|
|
|
|
|
|
|
|
|
if (curRegion != null) {
|
|
|
|
|
// Editing an existing region.
|
|
|
|
|
CanDeleteRegion = true;
|
|
|
|
|
ShowExistingRegion = true;
|
|
|
|
|
|
|
|
|
|
AddressText = Asm65.Address.AddressToString(curRegion.Address, false);
|
|
|
|
|
PreLabelText = curRegion.PreLabel;
|
|
|
|
|
UseRelativeAddressing = curRegion.IsRelative;
|
|
|
|
|
|
|
|
|
|
OperationStr = (string)FindResource("str_HdrEdit");
|
|
|
|
|
mRegionStartOffset = curRegion.Offset;
|
|
|
|
|
mRegionEndOffset = curRegion.Offset + curRegion.ActualLength - 1;
|
|
|
|
|
mPreLabelAddress = curRegion.PreLabelAddress;
|
|
|
|
|
|
|
|
|
|
if (isSingleLine) {
|
|
|
|
|
// Only thing selected was .arstart/.arend. First action is to edit
|
|
|
|
|
// the region properties, second action is to convert floating end
|
|
|
|
|
// to fixed.
|
|
|
|
|
mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset,
|
|
|
|
|
curRegion.Length, curRegion.Address, curRegion.PreLabel,
|
|
|
|
|
curRegion.IsRelative);
|
|
|
|
|
Option1Str = (string)FindResource("str_OptEditAsIs");
|
|
|
|
|
Option2Str = (string)FindResource("str_OptEditAndFix");
|
|
|
|
|
|
|
|
|
|
if (curRegion.IsFloating) {
|
|
|
|
|
mResultEntry2 = new AddressMap.AddressMapEntry(curRegion.Offset,
|
|
|
|
|
curRegion.ActualLength, curRegion.Address, curRegion.PreLabel,
|
|
|
|
|
curRegion.IsRelative);
|
|
|
|
|
} else {
|
|
|
|
|
mResultEntry2 = null;
|
|
|
|
|
EnableOption2 = false; // show it, but disabled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// Selection started with .arstart and included multiple lines. First
|
|
|
|
|
// action is to resize region. Second action is edit without resize.
|
|
|
|
|
// If resize is illegal (e.g. new region exactly overlaps another),
|
|
|
|
|
// first action is disabled.
|
|
|
|
|
mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset,
|
|
|
|
|
selectionLen, curRegion.Address, curRegion.PreLabel,
|
|
|
|
|
curRegion.IsRelative);
|
|
|
|
|
mResultEntry2 = new AddressMap.AddressMapEntry(curRegion.Offset,
|
|
|
|
|
curRegion.Length, curRegion.Address, curRegion.PreLabel,
|
|
|
|
|
curRegion.IsRelative);
|
|
|
|
|
|
|
|
|
|
string fmt = (string)FindResource("str_OptResize");
|
|
|
|
|
Option1Str = string.Format(fmt,
|
|
|
|
|
mFormatter.FormatOffset24(curRegion.Offset + selectionLen - 1),
|
|
|
|
|
FormatLength(selectionLen));
|
|
|
|
|
Option2Str = (string)FindResource("str_OptEditAsIs");
|
|
|
|
|
|
|
|
|
|
Debug.Assert(selectionLen > 0);
|
|
|
|
|
AddressMap.AddResult ares;
|
|
|
|
|
TryCreateRegion(curRegion, curRegion.Offset, selectionLen,
|
|
|
|
|
curRegion.Address, out ares);
|
|
|
|
|
if (ares != AddressMap.AddResult.Okay) {
|
|
|
|
|
// Can't create the new region, so disable that option (still visible).
|
|
|
|
|
EnableOption1 = false;
|
|
|
|
|
CheckOption2 = true;
|
|
|
|
|
}
|
2021-09-22 21:39:39 +00:00
|
|
|
|
}
|
2019-10-22 20:52:19 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
} else {
|
2021-09-27 00:06:43 +00:00
|
|
|
|
// Creating a new region. Prototype entry specifies offset, length, and address.
|
|
|
|
|
// First action is to create a fixed-length region, second action is to create
|
|
|
|
|
// a floating region. Default changes for single-item selections.
|
|
|
|
|
CanDeleteRegion = false;
|
|
|
|
|
ShowExistingRegion = false;
|
|
|
|
|
|
|
|
|
|
AddressText = Asm65.Address.AddressToString(newEntry.Address, false);
|
|
|
|
|
PreLabelText = string.Empty;
|
|
|
|
|
UseRelativeAddressing = false;
|
|
|
|
|
|
|
|
|
|
OperationStr = (string)FindResource("str_HdrCreate");
|
|
|
|
|
|
|
|
|
|
AddressMap.AddResult ares1;
|
|
|
|
|
AddressMap.AddressRegion newRegion1 = TryCreateRegion(null, newEntry.Offset,
|
|
|
|
|
newEntry.Length, newEntry.Address, out ares1);
|
|
|
|
|
AddressMap.AddResult ares2;
|
|
|
|
|
AddressMap.AddressRegion newRegion2 = TryCreateRegion(null, newEntry.Offset,
|
|
|
|
|
AddressMap.FLOATING_LEN, newEntry.Address, out ares2);
|
|
|
|
|
|
|
|
|
|
if (isSingleLine) {
|
|
|
|
|
// For single-line selection, create a floating region by default.
|
|
|
|
|
CheckOption2 = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If it failed, report the error. Most common reason will be a start offset
|
|
|
|
|
// that overlaps an existing region. You can create a fixed region inside
|
|
|
|
|
// a fixed region with the same start offset, but can't create a float there.
|
|
|
|
|
if (ares1 == AddressMap.AddResult.Okay) {
|
|
|
|
|
mResultEntry1 = new AddressMap.AddressMapEntry(newEntry.Offset,
|
|
|
|
|
newRegion1.ActualLength, newEntry.Address, string.Empty, false);
|
|
|
|
|
|
|
|
|
|
string fmt = (string)FindResource("str_CreateFixed");
|
|
|
|
|
Option1Str = string.Format(fmt,
|
|
|
|
|
mFormatter.FormatOffset24(newEntry.Offset),
|
|
|
|
|
FormatLength(newRegion1.ActualLength));
|
2021-09-22 21:39:39 +00:00
|
|
|
|
} else {
|
2021-09-27 00:06:43 +00:00
|
|
|
|
Option1Str = (string)FindResource("str_CreateFixedFail");
|
|
|
|
|
CheckOption2 = true;
|
|
|
|
|
EnableOption1 = false;
|
|
|
|
|
}
|
|
|
|
|
if (ares2 == AddressMap.AddResult.Okay) {
|
|
|
|
|
mResultEntry2 = new AddressMap.AddressMapEntry(newEntry.Offset,
|
|
|
|
|
AddressMap.FLOATING_LEN, newEntry.Address, string.Empty, false);
|
|
|
|
|
|
|
|
|
|
string fmt = (string)FindResource("str_CreateFloating");
|
|
|
|
|
Option2Str = string.Format(fmt,
|
|
|
|
|
mFormatter.FormatOffset24(newEntry.Offset),
|
|
|
|
|
FormatLength(newRegion2.ActualLength));
|
|
|
|
|
} else {
|
|
|
|
|
Option2Str = (string)FindResource("str_CreateFloatingFail");
|
|
|
|
|
CheckOption1 = true;
|
|
|
|
|
CheckOption2 = false; // required for some reason
|
|
|
|
|
EnableOption2 = false;
|
|
|
|
|
}
|
|
|
|
|
if (ares1 != AddressMap.AddResult.Okay && ares2 != AddressMap.AddResult.Okay) {
|
|
|
|
|
// Unable to create region here. Explain why not.
|
|
|
|
|
EnableAttributeControls = false;
|
|
|
|
|
CheckOption1 = CheckOption2 = false;
|
|
|
|
|
|
|
|
|
|
SetErrorString(ares1);
|
2021-09-22 21:39:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private string FormatLength(int len) {
|
|
|
|
|
return len + " (" + mFormatter.FormatHexValue(len, 2) + ")";
|
2019-07-07 00:24:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private AddressMap.AddressRegion TryCreateRegion(AddressMap.AddressRegion delRegion,
|
|
|
|
|
int offset, int length, int addr, out AddressMap.AddResult result) {
|
|
|
|
|
AddressMap tmpMap = mProject.AddrMap.Clone();
|
|
|
|
|
|
|
|
|
|
if (delRegion != null && !tmpMap.RemoveEntry(delRegion.Offset, delRegion.Length)) {
|
|
|
|
|
Debug.Assert(false, "Failed to remove existing region");
|
|
|
|
|
result = AddressMap.AddResult.InternalError;
|
|
|
|
|
return null;
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
|
|
|
|
|
result = tmpMap.AddEntry(offset, length, addr);
|
|
|
|
|
if (result != AddressMap.AddResult.Okay) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
AddressMap.AddressRegion newRegion = tmpMap.FindRegion(offset, length);
|
|
|
|
|
if (newRegion == null) {
|
|
|
|
|
// Shouldn't happen.
|
|
|
|
|
Debug.Assert(false, "Failed to find region we just created");
|
|
|
|
|
result = AddressMap.AddResult.InternalError;
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return newRegion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetErrorString(AddressMap.AddResult result) {
|
|
|
|
|
string rsrc;
|
|
|
|
|
switch (result) {
|
|
|
|
|
case AddressMap.AddResult.InternalError:
|
|
|
|
|
rsrc = "str_ErrInternal";
|
|
|
|
|
break;
|
|
|
|
|
case AddressMap.AddResult.InvalidValue:
|
|
|
|
|
rsrc = "str_ErrInvalidValue";
|
|
|
|
|
break;
|
|
|
|
|
case AddressMap.AddResult.OverlapExisting:
|
|
|
|
|
rsrc = "str_ErrOverlapExisting";
|
|
|
|
|
break;
|
|
|
|
|
case AddressMap.AddResult.OverlapFloating:
|
|
|
|
|
rsrc = "str_ErrOverlapFloating";
|
|
|
|
|
break;
|
|
|
|
|
case AddressMap.AddResult.StraddleExisting:
|
|
|
|
|
rsrc = "str_ErrStraddelExisting";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Debug.Assert(false);
|
|
|
|
|
rsrc = "str_ErrInternal";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorMessageStr = (string)FindResource(rsrc); // throws exception on failure
|
|
|
|
|
ShowErrorMessage = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Window_ContentRendered(object sender, EventArgs e) {
|
|
|
|
|
addrTextBox.SelectAll();
|
|
|
|
|
addrTextBox.Focus();
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Handles a TextChanged event on the address text box.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Must have UpdateSourceTrigger=PropertyChanged set for this to work. The default
|
|
|
|
|
/// for TextBox is LostFocus.
|
|
|
|
|
/// </remarks>
|
2019-12-26 01:15:37 +00:00
|
|
|
|
private void UpdateControls() {
|
2021-09-27 00:06:43 +00:00
|
|
|
|
IsValid = EnableAttributeControls && ParseAddress(out int unused);
|
2021-09-22 21:39:39 +00:00
|
|
|
|
// TODO(org): check pre-label syntax
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 00:06:43 +00:00
|
|
|
|
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
bool ok = ParseAddress(out int addr);
|
|
|
|
|
Debug.Assert(ok);
|
|
|
|
|
|
|
|
|
|
AddressMap.AddressMapEntry baseEntry;
|
|
|
|
|
if (CheckOption1) {
|
|
|
|
|
baseEntry = mResultEntry1;
|
|
|
|
|
} else {
|
|
|
|
|
baseEntry = mResultEntry2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Combine base entry with pre-label string and relative addressing checkbox.
|
|
|
|
|
ResultEntry = new AddressMap.AddressMapEntry(baseEntry.Offset,
|
|
|
|
|
baseEntry.Length, addr, PreLabelText, UseRelativeAddressing);
|
|
|
|
|
Debug.WriteLine("Dialog result: " + ResultEntry);
|
|
|
|
|
DialogResult = true;
|
|
|
|
|
}
|
2019-06-16 23:34:47 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parses the address out of the AddressText text box.
|
|
|
|
|
/// </summary>
|
2021-09-27 00:06:43 +00:00
|
|
|
|
/// <param name="addr">Receives the parsed address. Will be NON_ADDR for "NA".</param>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// <returns>True if the string parsed successfully.</returns>
|
|
|
|
|
private bool ParseAddress(out int addr) {
|
|
|
|
|
// "NA" for non-addressable?
|
|
|
|
|
string upper = AddressText.ToUpper();
|
|
|
|
|
if (upper == NON_ADDR_STR) {
|
|
|
|
|
addr = AddressMap.NON_ADDR;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Parse numerically.
|
|
|
|
|
return Asm65.Address.ParseAddress(AddressText, mMaxAddressValue, out addr);
|
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
|
|
|
|
|
private void DeleteRegion_Click(object sender, RoutedEventArgs e) {
|
|
|
|
|
ResultEntry = null;
|
|
|
|
|
DialogResult = true;
|
|
|
|
|
}
|
2021-09-22 21:39:39 +00:00
|
|
|
|
}
|
2021-09-27 00:06:43 +00:00
|
|
|
|
}
|