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;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
using System.Collections.Generic;
|
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 {
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// <summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// Updated address map entry. Will be null if we want to delete the entry.
|
2019-06-16 23:34:47 +00:00
|
|
|
|
/// </summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
public AddressMap.AddressMapEntry NewEntry { get; private set; }
|
|
|
|
|
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Offset being edited.
|
|
|
|
|
/// </summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
private int mRegionStartOffset;
|
|
|
|
|
public string RegionStartOffsetStr {
|
|
|
|
|
get { return mFormatter.FormatOffset24(mRegionStartOffset); }
|
|
|
|
|
}
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Offset after the end of the selection, or -1 if only one line is selected.
|
|
|
|
|
/// </summary>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
private int mRegionEndOffset;
|
|
|
|
|
public string RegionEndOffsetStr {
|
|
|
|
|
get { return mFormatter.FormatOffset24(mRegionEndOffset); }
|
2019-12-26 01:15:37 +00:00
|
|
|
|
}
|
2021-09-22 21:39:39 +00:00
|
|
|
|
|
|
|
|
|
public string RegionLengthStr {
|
2019-12-26 01:15:37 +00:00
|
|
|
|
get {
|
2021-09-22 21:39:39 +00:00
|
|
|
|
int count = mRegionEndOffset - mRegionStartOffset;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
return count.ToString() + " (" + mFormatter.FormatHexValue(count, 2) + ")";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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 {
|
|
|
|
|
get { return mFormatter.FormatOffset24(mRegionEndOffset); }
|
|
|
|
|
}
|
|
|
|
|
|
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>
|
|
|
|
|
/// Set to true when requested region is valid. Everything but the cancel button is
|
|
|
|
|
/// disabled if not.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsRegionValid {
|
|
|
|
|
get { return mIsRegionValid; }
|
|
|
|
|
set { mIsRegionValid = value; OnPropertyChanged(); }
|
2019-10-22 20:52:19 +00:00
|
|
|
|
}
|
2021-09-22 21:39:39 +00:00
|
|
|
|
private bool mIsRegionValid;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Determines whether the "(floating)" message appears next to the length.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Visibility FloatTextVis {
|
|
|
|
|
get { return mFloatTextVis; }
|
2019-10-22 20:52:19 +00:00
|
|
|
|
}
|
2021-09-22 21:39:39 +00:00
|
|
|
|
private Visibility mFloatTextVis;
|
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-22 21:39:39 +00:00
|
|
|
|
private AddressMap.AddressRegion mNewRegion;
|
|
|
|
|
|
|
|
|
|
/// <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-22 21:39:39 +00:00
|
|
|
|
/// <param name="entry">Map entry definition. This may be an existing entry, or values
|
|
|
|
|
/// representing the selection.</param>
|
|
|
|
|
/// <param name="newLength">Length of region. Only used if we're resizing an
|
|
|
|
|
/// existing region.</param>
|
2019-12-26 01:15:37 +00:00
|
|
|
|
/// <param name="project">Project reference.</param>
|
|
|
|
|
/// <param name="formatter">Text formatter object.</param>
|
2021-09-22 21:39:39 +00:00
|
|
|
|
public EditAddress(Window owner, AddressMap.AddressMapEntry entry, bool isNew,
|
|
|
|
|
int newLength, DisasmProject project, Formatter formatter) {
|
2019-12-26 01:15:37 +00:00
|
|
|
|
InitializeComponent();
|
|
|
|
|
Owner = owner;
|
|
|
|
|
DataContext = this;
|
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
mProject = project;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
mMaxAddressValue = project.CpuDef.MaxAddressValue;
|
2021-09-22 21:39:39 +00:00
|
|
|
|
mFormatter = formatter;
|
2019-10-22 20:52:19 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
Configure(entry, isNew, newLength);
|
|
|
|
|
}
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
private void Configure(AddressMap.AddressMapEntry entry, bool isNew, int newLength) {
|
|
|
|
|
mRegionStartOffset = mRegionEndOffset = entry.Offset;
|
|
|
|
|
mPreLabelAddress = 0;
|
|
|
|
|
IsRegionValid = false;
|
2019-12-26 01:15:37 +00:00
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
// The passed-in region could have Length=FLOATING_LEN, so we need to resolve
|
|
|
|
|
// that now. We also need to figure out if it's valid. The easiest way to do
|
|
|
|
|
// that is to clone the address map, add the region to it, and see how the values
|
|
|
|
|
// resolve. This also gets us an address for the pre-label.
|
|
|
|
|
List<AddressMap.AddressMapEntry> entries;
|
|
|
|
|
int spanLength;
|
|
|
|
|
entries = mProject.AddrMap.GetEntryList(out spanLength);
|
|
|
|
|
AddressMap tmpMap = new AddressMap(spanLength, entries);
|
|
|
|
|
if (!isNew) {
|
|
|
|
|
// Remove the old entry.
|
|
|
|
|
if (!tmpMap.RemoveEntry(entry.Offset, entry.Length)) {
|
|
|
|
|
// Shouldn't happen.
|
|
|
|
|
Debug.Assert(false);
|
|
|
|
|
// TODO(org): some sort of failure indicator
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-10-22 20:52:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
// Add the new / replacement entry.
|
|
|
|
|
AddressMap.AddResult result = tmpMap.AddEntry(entry);
|
|
|
|
|
if (result != AddressMap.AddResult.Okay) {
|
|
|
|
|
// TODO(org): various things with failures
|
|
|
|
|
Debug.Assert(false); // remove
|
|
|
|
|
} else {
|
|
|
|
|
// Find it in the region tree.
|
|
|
|
|
mNewRegion = tmpMap.FindRegion(entry.Offset, entry.Length);
|
|
|
|
|
if (mNewRegion == null) {
|
|
|
|
|
// Shouldn't happen.
|
|
|
|
|
Debug.Assert(false);
|
|
|
|
|
// TODO(org): some sort of failure indicator
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
// Set offset / length values based on what we got.
|
|
|
|
|
IsRegionValid = true;
|
|
|
|
|
mRegionStartOffset = mNewRegion.Offset;
|
|
|
|
|
mRegionEndOffset = mNewRegion.Offset + mNewRegion.ActualLength;
|
|
|
|
|
mPreLabelAddress = mNewRegion.PreLabelAddress;
|
|
|
|
|
mFloatTextVis = mNewRegion.IsFloating ? Visibility.Visible : Visibility.Hidden;
|
|
|
|
|
// Init editable stuff.
|
|
|
|
|
AddressText = Asm65.Address.AddressToString(mNewRegion.Address, false);
|
|
|
|
|
PreLabelText = mNewRegion.PreLabel;
|
|
|
|
|
UseRelativeAddressing = mNewRegion.IsRelative;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-21 22:24:39 +00:00
|
|
|
|
private void Window_ContentRendered(object sender, EventArgs e) {
|
2019-07-07 00:24:42 +00:00
|
|
|
|
addrTextBox.SelectAll();
|
|
|
|
|
addrTextBox.Focus();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 23:34:47 +00:00
|
|
|
|
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
2021-09-22 21:39:39 +00:00
|
|
|
|
bool ok = ParseAddress(out int addr);
|
|
|
|
|
Debug.Assert(ok);
|
|
|
|
|
if (addr == AddressMap.INVALID_ADDR) {
|
|
|
|
|
// field was blank, want to delete the entry
|
|
|
|
|
NewEntry = null;
|
2019-06-16 23:34:47 +00:00
|
|
|
|
} else {
|
2021-09-22 21:39:39 +00:00
|
|
|
|
NewEntry = new AddressMap.AddressMapEntry(mNewRegion.Offset,
|
|
|
|
|
mNewRegion.Length, addr, PreLabelText,
|
|
|
|
|
UseRelativeAddressing);
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
DialogResult = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <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-22 21:39:39 +00:00
|
|
|
|
IsValid = IsRegionValid && ParseAddress(out int unused);
|
|
|
|
|
// TODO(org): check pre-label syntax
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 21:39:39 +00:00
|
|
|
|
private const string NON_ADDR_STR = "NA";
|
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>
|
|
|
|
|
/// <param name="addr">Receives the parsed address. Will be NON_ADDR for "NA", and
|
|
|
|
|
/// INVALID_ADDR if blank.</param>
|
|
|
|
|
/// <returns>True if the string parsed successfully.</returns>
|
|
|
|
|
private bool ParseAddress(out int addr) {
|
|
|
|
|
// Left blank?
|
|
|
|
|
if (AddressText.Length == 0) {
|
|
|
|
|
addr = AddressMap.INVALID_ADDR;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// "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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-16 23:34:47 +00:00
|
|
|
|
}
|