mirror of
https://github.com/fadden/6502bench.git
synced 2024-05-31 22:41:37 +00:00
Data Bank Register management, part 2
Changed basic data item from an "extended enum" to a class, so we can keep track of where things come from (useful for the display list). Finished edit dialog. Added serialization to project file.
This commit is contained in:
parent
18e6951f17
commit
973d162edb
|
@ -58,6 +58,33 @@ namespace Asm65 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a hexadecimal integer. Leading '$' or "0x" will be ignored.
|
||||||
|
///
|
||||||
|
/// Trim whitespace before calling here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">String to parse.</param>
|
||||||
|
/// <param name="val">Integer value of string.</param>
|
||||||
|
/// <returns>True if the parsing was successful.</returns>
|
||||||
|
public static bool TryParseIntHex(string str, out int val) {
|
||||||
|
if (str.Length == 0) {
|
||||||
|
val = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (str[0] == '$') {
|
||||||
|
str = str.Substring(1);
|
||||||
|
}
|
||||||
|
// leading "0x" will be handled by Convert
|
||||||
|
|
||||||
|
try {
|
||||||
|
val = Convert.ToInt32(str, 16);
|
||||||
|
} catch (Exception) {
|
||||||
|
val = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a long integer in a variety of formats (hex, decimal, binary). We allow
|
/// Parses a long integer in a variety of formats (hex, decimal, binary). We allow
|
||||||
/// hex to be identified with a leading '$' as well as "0x".
|
/// hex to be identified with a leading '$' as well as "0x".
|
||||||
|
|
|
@ -1224,16 +1224,73 @@ namespace SourceGen {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data Bank Register value.
|
/// Data Bank Register value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
public class DbrValue {
|
||||||
/// This is primarily a value from $00-ff, but we also want to encode the B=K special
|
public const short UNKNOWN = -1;
|
||||||
/// mode.
|
public const short USE_PBR = -2;
|
||||||
/// </remarks>
|
|
||||||
public enum DbrValue : short {
|
/// <summary>
|
||||||
// $00-ff is bank number
|
/// If true, ignore Bank, use Program Bank Register instead.
|
||||||
Unknown = -1, // unknown / do-nothing
|
/// </summary>
|
||||||
ProgramBankReg = -2 // set B=K
|
public bool FollowPbr;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bank number (0-255).
|
||||||
|
/// </summary>
|
||||||
|
public byte Bank { get; private set; }
|
||||||
|
|
||||||
|
public enum Source { Unknown = 0, User, Auto, Smart };
|
||||||
|
/// <summary>
|
||||||
|
/// From whence this value originates.
|
||||||
|
/// </summary>
|
||||||
|
public Source ValueSource { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Representation of the object state as a short integer. 0-255 specifies the
|
||||||
|
/// bank, while negative values are used for special conditions.
|
||||||
|
/// </summary>
|
||||||
|
public short AsShort {
|
||||||
|
get {
|
||||||
|
if (FollowPbr) {
|
||||||
|
return USE_PBR;
|
||||||
|
} else {
|
||||||
|
return Bank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbrValue(bool followPbr, byte bank, Source source) {
|
||||||
|
FollowPbr = followPbr;
|
||||||
|
Bank = bank;
|
||||||
|
ValueSource = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return "DBR:" + (FollowPbr ? "K" : "$" + Bank.ToString("x2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DbrValue a, DbrValue b) {
|
||||||
|
if (ReferenceEquals(a, b)) {
|
||||||
|
return true; // same object, or both null
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) {
|
||||||
|
return false; // one is null
|
||||||
|
}
|
||||||
|
// All fields must be equal.
|
||||||
|
return a.Bank == b.Bank && a.FollowPbr == b.FollowPbr &&
|
||||||
|
a.ValueSource == b.ValueSource;
|
||||||
|
}
|
||||||
|
public static bool operator !=(DbrValue a, DbrValue b) {
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj) {
|
||||||
|
return obj is Symbol && this == (DbrValue)obj;
|
||||||
|
}
|
||||||
|
public override int GetHashCode() {
|
||||||
|
return Bank + (FollowPbr ? 0x100 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the value of the Data Bank Register (DBR, register 'B') for relevant
|
/// Determines the value of the Data Bank Register (DBR, register 'B') for relevant
|
||||||
/// instructions, and updates the Anattrib OperandOffset value.
|
/// instructions, and updates the Anattrib OperandOffset value.
|
||||||
|
@ -1244,21 +1301,21 @@ namespace SourceGen {
|
||||||
short[] bval = new short[mAnattribs.Length];
|
short[] bval = new short[mAnattribs.Length];
|
||||||
|
|
||||||
// Initialize all entries to "unknown".
|
// Initialize all entries to "unknown".
|
||||||
Misc.Memset(bval, (short)DbrValue.Unknown);
|
Misc.Memset(bval, DbrValue.UNKNOWN);
|
||||||
|
|
||||||
// Set B=K every time we cross an address boundary and the program bank changes.
|
// Set B=K every time we cross an address boundary and the program bank changes.
|
||||||
DbrValue prevBank = DbrValue.Unknown;
|
short prevBank = DbrValue.UNKNOWN;
|
||||||
foreach (AddressMap.AddressMapEntry ent in mAddrMap) {
|
foreach (AddressMap.AddressMapEntry ent in mAddrMap) {
|
||||||
int mapBank = ent.Addr >> 16;
|
short mapBank = (short)(ent.Addr >> 16);
|
||||||
if (mapBank != (int)prevBank) {
|
if (mapBank != prevBank) {
|
||||||
bval[ent.Offset] = (short)mapBank;
|
bval[ent.Offset] = mapBank;
|
||||||
prevBank = (DbrValue)mapBank;
|
prevBank = mapBank;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the user-specified values.
|
// Apply the user-specified values.
|
||||||
foreach (KeyValuePair<int, DbrValue> kvp in userValues) {
|
foreach (KeyValuePair<int, DbrValue> kvp in userValues) {
|
||||||
bval[kvp.Key] = (short)kvp.Value;
|
bval[kvp.Key] = kvp.Value.AsShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run through the file, looking for PHK/PLB pairs. When we find one, set an
|
// Run through the file, looking for PHK/PLB pairs. When we find one, set an
|
||||||
|
@ -1270,19 +1327,19 @@ namespace SourceGen {
|
||||||
|
|
||||||
|
|
||||||
// Run through file, updating instructions as needed.
|
// Run through file, updating instructions as needed.
|
||||||
short curVal = (short)DbrValue.Unknown;
|
short curVal = DbrValue.UNKNOWN;
|
||||||
for (int offset = 0; offset < mAnattribs.Length; offset++) {
|
for (int offset = 0; offset < mAnattribs.Length; offset++) {
|
||||||
if (bval[offset] != (short)DbrValue.Unknown) {
|
if (bval[offset] != DbrValue.UNKNOWN) {
|
||||||
curVal = bval[offset];
|
curVal = bval[offset];
|
||||||
}
|
}
|
||||||
if (!mAnattribs[offset].UsesDataBankReg) {
|
if (!mAnattribs[offset].UsesDataBankReg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Debug.Assert(mAnattribs[offset].IsInstructionStart);
|
Debug.Assert(mAnattribs[offset].IsInstructionStart);
|
||||||
Debug.Assert(curVal != (short)DbrValue.Unknown);
|
Debug.Assert(curVal != DbrValue.UNKNOWN);
|
||||||
|
|
||||||
int bank;
|
int bank;
|
||||||
if (curVal == (short)DbrValue.ProgramBankReg) {
|
if (curVal == DbrValue.USE_PBR) {
|
||||||
bank = mAnattribs[offset].Address >> 16;
|
bank = mAnattribs[offset].Address >> 16;
|
||||||
} else {
|
} else {
|
||||||
Debug.Assert(curVal >= 0 && curVal < 256);
|
Debug.Assert(curVal >= 0 && curVal < 256);
|
||||||
|
|
|
@ -2120,15 +2120,13 @@ namespace SourceGen {
|
||||||
break;
|
break;
|
||||||
case UndoableChange.ChangeType.SetDataBank: {
|
case UndoableChange.ChangeType.SetDataBank: {
|
||||||
// If there's no entry, treat it as an entry with value = Unknown.
|
// If there's no entry, treat it as an entry with value = Unknown.
|
||||||
if (!DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue current)) {
|
DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue current);
|
||||||
current = CodeAnalysis.DbrValue.Unknown;
|
|
||||||
}
|
|
||||||
if (current != (CodeAnalysis.DbrValue)oldValue) {
|
if (current != (CodeAnalysis.DbrValue)oldValue) {
|
||||||
Debug.WriteLine("GLITCH: old DBR value mismatch (" +
|
Debug.WriteLine("GLITCH: old DBR value mismatch (" +
|
||||||
current + " vs " + oldValue + ")");
|
current + " vs " + oldValue + ")");
|
||||||
Debug.Assert(false);
|
Debug.Assert(false);
|
||||||
}
|
}
|
||||||
if ((CodeAnalysis.DbrValue)newValue == CodeAnalysis.DbrValue.Unknown) {
|
if (newValue == null) {
|
||||||
DbrValues.Remove(offset);
|
DbrValues.Remove(offset);
|
||||||
} else {
|
} else {
|
||||||
DbrValues[offset] = (CodeAnalysis.DbrValue)newValue;
|
DbrValues[offset] = (CodeAnalysis.DbrValue)newValue;
|
||||||
|
|
|
@ -1873,19 +1873,16 @@ namespace SourceGen {
|
||||||
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
|
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
|
||||||
int offset = CodeLineList[selIndex].FileOffset;
|
int offset = CodeLineList[selIndex].FileOffset;
|
||||||
|
|
||||||
CodeAnalysis.DbrValue curValue;
|
// Get current user-specified value, or null.
|
||||||
if (!mProject.DbrValues.TryGetValue(offset, out curValue)) {
|
mProject.DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue curValue);
|
||||||
curValue = CodeAnalysis.DbrValue.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditDataBank dlg = new EditDataBank(mMainWin, mProject.AddrMap, mFormatter, curValue);
|
EditDataBank dlg = new EditDataBank(mMainWin, mProject, mFormatter, curValue);
|
||||||
if (dlg.ShowDialog() != true) {
|
if (dlg.ShowDialog() != true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dlg.Result != curValue) {
|
if (dlg.Result != curValue) {
|
||||||
Debug.WriteLine("Changing DBR at +" + offset.ToString("x6") + " to $" +
|
Debug.WriteLine("Changing DBR at +" + offset.ToString("x6") + " to $" + dlg.Result);
|
||||||
((int)(dlg.Result)).ToString("x2"));
|
|
||||||
UndoableChange uc =
|
UndoableChange uc =
|
||||||
UndoableChange.CreateDataBankChange(offset, curValue, dlg.Result);
|
UndoableChange.CreateDataBankChange(offset, curValue, dlg.Result);
|
||||||
ChangeSet cs = new ChangeSet(uc);
|
ChangeSet cs = new ChangeSet(uc);
|
||||||
|
|
|
@ -401,6 +401,18 @@ namespace SourceGen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public class SerDbrValue {
|
||||||
|
// Skip the ValueSource property; should always be User in project file.
|
||||||
|
public bool FollowPbr;
|
||||||
|
public byte Bank;
|
||||||
|
|
||||||
|
public SerDbrValue() { }
|
||||||
|
public SerDbrValue(CodeAnalysis.DbrValue dbrValue) {
|
||||||
|
FollowPbr = dbrValue.FollowPbr;
|
||||||
|
Bank = dbrValue.Bank;
|
||||||
|
Debug.Assert(dbrValue.ValueSource == CodeAnalysis.DbrValue.Source.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fields are serialized to/from JSON. DO NOT change the field names.
|
// Fields are serialized to/from JSON. DO NOT change the field names.
|
||||||
public int _ContentVersion { get; set; }
|
public int _ContentVersion { get; set; }
|
||||||
|
@ -420,6 +432,7 @@ namespace SourceGen {
|
||||||
public List<SerVisBitmapAnimation> VisualizationAnimations { get; set; }
|
public List<SerVisBitmapAnimation> VisualizationAnimations { get; set; }
|
||||||
public Dictionary<string, SerVisualizationSet> VisualizationSets { get; set; }
|
public Dictionary<string, SerVisualizationSet> VisualizationSets { get; set; }
|
||||||
public Dictionary<string, DisasmProject.RelocData> RelocList { get; set; }
|
public Dictionary<string, DisasmProject.RelocData> RelocList { get; set; }
|
||||||
|
public Dictionary<string, SerDbrValue> DbrValues { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serializes a DisasmProject into an augmented JSON string.
|
/// Serializes a DisasmProject into an augmented JSON string.
|
||||||
|
@ -534,6 +547,13 @@ namespace SourceGen {
|
||||||
spf.RelocList.Add(kvp.Key.ToString(), kvp.Value);
|
spf.RelocList.Add(kvp.Key.ToString(), kvp.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We could output the value as a short, using DbrValue.AsShort, but it doesn't
|
||||||
|
// save much space and could make life harder down the road.
|
||||||
|
spf.DbrValues = new Dictionary<string, SerDbrValue>(proj.DbrValues.Count);
|
||||||
|
foreach (KeyValuePair<int, CodeAnalysis.DbrValue> kvp in proj.DbrValues) {
|
||||||
|
spf.DbrValues.Add(kvp.Key.ToString(), new SerDbrValue(kvp.Value));
|
||||||
|
}
|
||||||
|
|
||||||
JavaScriptSerializer ser = new JavaScriptSerializer();
|
JavaScriptSerializer ser = new JavaScriptSerializer();
|
||||||
string cereal = ser.Serialize(spf);
|
string cereal = ser.Serialize(spf);
|
||||||
sb.Append(cereal);
|
sb.Append(cereal);
|
||||||
|
@ -854,6 +874,19 @@ namespace SourceGen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deserialize data bank register values. This was added in v1.7.
|
||||||
|
if (spf.DbrValues != null) {
|
||||||
|
foreach (KeyValuePair<string, SerDbrValue> kvp in spf.DbrValues) {
|
||||||
|
if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
|
||||||
|
Res.Strings.PROJECT_FIELD_DBR_VALUE, report, out int intKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CodeAnalysis.DbrValue newDbr = new CodeAnalysis.DbrValue(kvp.Value.FollowPbr,
|
||||||
|
kvp.Value.Bank, CodeAnalysis.DbrValue.Source.User);
|
||||||
|
proj.DbrValues.Add(intKey, newDbr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,7 @@ limitations under the License.
|
||||||
<system:String x:Key="str_ProgressAssembling">Executing assembler...</system:String>
|
<system:String x:Key="str_ProgressAssembling">Executing assembler...</system:String>
|
||||||
<system:String x:Key="str_ProgressGeneratingFmt">Generating {0}...</system:String>
|
<system:String x:Key="str_ProgressGeneratingFmt">Generating {0}...</system:String>
|
||||||
<system:String x:Key="str_ProjectFieldComment">comment</system:String>
|
<system:String x:Key="str_ProjectFieldComment">comment</system:String>
|
||||||
|
<system:String x:Key="str_ProjectFieldDbrValue">DBR value</system:String>
|
||||||
<system:String x:Key="str_ProjectFieldLongComment">long comment</system:String>
|
<system:String x:Key="str_ProjectFieldLongComment">long comment</system:String>
|
||||||
<system:String x:Key="str_ProjectFieldLvTable">local variable table</system:String>
|
<system:String x:Key="str_ProjectFieldLvTable">local variable table</system:String>
|
||||||
<system:String x:Key="str_ProjectFieldNote">note</system:String>
|
<system:String x:Key="str_ProjectFieldNote">note</system:String>
|
||||||
|
|
|
@ -285,6 +285,8 @@ namespace SourceGen.Res {
|
||||||
(string)Application.Current.FindResource("str_ProgressGeneratingFmt");
|
(string)Application.Current.FindResource("str_ProgressGeneratingFmt");
|
||||||
public static string PROJECT_FIELD_COMMENT =
|
public static string PROJECT_FIELD_COMMENT =
|
||||||
(string)Application.Current.FindResource("str_ProjectFieldComment");
|
(string)Application.Current.FindResource("str_ProjectFieldComment");
|
||||||
|
public static string PROJECT_FIELD_DBR_VALUE =
|
||||||
|
(string)Application.Current.FindResource("str_ProjectFieldDbrValue");
|
||||||
public static string PROJECT_FIELD_LONG_COMMENT =
|
public static string PROJECT_FIELD_LONG_COMMENT =
|
||||||
(string)Application.Current.FindResource("str_ProjectFieldLongComment");
|
(string)Application.Current.FindResource("str_ProjectFieldLongComment");
|
||||||
public static string PROJECT_FIELD_LV_TABLE =
|
public static string PROJECT_FIELD_LV_TABLE =
|
||||||
|
|
|
@ -20,12 +20,17 @@ limitations under the License.
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SourceGen.WpfGui"
|
xmlns:local="clr-namespace:SourceGen.WpfGui"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Set Data Bank"
|
Title="Set Data Bank"
|
||||||
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
|
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
|
||||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||||
ContentRendered="Window_ContentRendered">
|
ContentRendered="Window_ContentRendered">
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<system:String x:Key="str_OtherBank">(other)</system:String>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid Margin="8">
|
<Grid Margin="8">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
@ -33,25 +38,25 @@ limitations under the License.
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
||||||
<TextBlock Text="Enter bank:"/>
|
<TextBlock Text="Data bank:"/>
|
||||||
<TextBox Name="bankValueBox" Margin="8,1,0,0" Width="24" MaxLength="2"
|
<TextBox Name="bankValueBox" Margin="8,1,0,0" Width="30" MaxLength="3"
|
||||||
Text="{Binding DataBankStr, FallbackValue=88}"
|
Text="{Binding DataBankStr, UpdateSourceTrigger=PropertyChanged, FallbackValue=$00}"
|
||||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Grid.Row="1" Margin="0,4,0,0" Text="• Enter hex value, or 'K' to track PBR"/>
|
<TextBlock Grid.Row="1" Margin="0,4,0,0" Text="• Enter two-digit hex value, or 'K' to track PBR"/>
|
||||||
<TextBlock Grid.Row="2" Margin="0,0,0,0" Text="• Leave blank to reset to default"/>
|
<TextBlock Grid.Row="2" Margin="0,0,0,0" Text="• Leave blank to reset to default"/>
|
||||||
|
|
||||||
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0,16,0,0">
|
<TextBlock Grid.Row="3" Text="Alternatively, select from list of in-use banks:" Margin="0,16,0,0"/>
|
||||||
<TextBlock Text="Banks in use:" Margin="0,3,0,0"/>
|
<ComboBox Grid.Row="4" Name="bankCombo" Margin="0,4,0,0"
|
||||||
<ComboBox Name="bankCombo" Margin="8,1,0,0" Width="200"
|
FontFamily="{StaticResource GeneralMonoFont}"
|
||||||
FontFamily="{StaticResource GeneralMonoFont}"
|
ItemsSource="{Binding BankLabels}" DisplayMemberPath="Label"
|
||||||
ItemsSource="{Binding BankLabels}" DisplayMemberPath="Label"/>
|
SelectionChanged="bankCombo_SelectionChanged"/>
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,0">
|
<StackPanel Grid.Row="5" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,0">
|
||||||
<Button Content="OK" IsDefault="True" Width="70"
|
<Button Content="OK" IsDefault="True" Width="70"
|
||||||
IsEnabled="{Binding IsValid}" Click="OkButton_Click"/>
|
IsEnabled="{Binding IsValid}" Click="OkButton_Click"/>
|
||||||
<Button Content="Cancel" IsCancel="True" Width="70" Margin="4,0,0,0"/>
|
<Button Content="Cancel" IsCancel="True" Width="70" Margin="4,0,0,0"/>
|
||||||
|
|
|
@ -19,7 +19,7 @@ using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
using Asm65;
|
using Asm65;
|
||||||
using CommonUtil;
|
using CommonUtil;
|
||||||
|
|
||||||
|
@ -38,13 +38,14 @@ namespace SourceGen.WpfGui {
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressMap mAddrMap;
|
private DisasmProject mProject;
|
||||||
private Formatter mFormatter;
|
private Formatter mFormatter;
|
||||||
|
private bool mSettingComboBox;
|
||||||
|
|
||||||
private string mDataBankStr;
|
private string mDataBankStr;
|
||||||
public string DataBankStr {
|
public string DataBankStr {
|
||||||
get { return mDataBankStr; }
|
get { return mDataBankStr; }
|
||||||
set { mDataBankStr = value; OnPropertyChanged(); }
|
set { mDataBankStr = value; OnPropertyChanged(); UpdateControls(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool mIsValid;
|
private bool mIsValid;
|
||||||
|
@ -53,50 +54,64 @@ namespace SourceGen.WpfGui {
|
||||||
set { mIsValid = value; OnPropertyChanged(); }
|
set { mIsValid = value; OnPropertyChanged(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BankLabel {
|
public class BankLabelItem : IComparable<BankLabelItem> {
|
||||||
public CodeAnalysis.DbrValue Bank { get; private set; }
|
//public CodeAnalysis.DbrValue Bank { get; private set; }
|
||||||
|
public byte Bank { get; private set; }
|
||||||
public string Label { get; private set; }
|
public string Label { get; private set; }
|
||||||
|
|
||||||
public BankLabel(CodeAnalysis.DbrValue bank, string label) {
|
public BankLabelItem(byte bank, string label) {
|
||||||
Bank = bank;
|
Bank = bank;
|
||||||
Label = label;
|
Label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int CompareTo(BankLabelItem other) {
|
||||||
|
return Bank - other.Bank;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public List<BankLabel> BankLabels { get; private set; } = new List<BankLabel>();
|
public List<BankLabelItem> BankLabels { get; private set; } = new List<BankLabelItem>();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="owner">Parent window.</param>
|
/// <param name="owner">Parent window.</param>
|
||||||
public EditDataBank(Window owner, AddressMap addrMap, Formatter formatter,
|
/// <param name="proj">Disassembly project.</param>
|
||||||
|
/// <param name="formatter">Text formatter.</param>
|
||||||
|
/// <param name="curValue">Current value, or null if none set.</param>
|
||||||
|
public EditDataBank(Window owner, DisasmProject proj, Formatter formatter,
|
||||||
CodeAnalysis.DbrValue curValue) {
|
CodeAnalysis.DbrValue curValue) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Owner = owner;
|
Owner = owner;
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
|
|
||||||
mAddrMap = addrMap;
|
mProject = proj;
|
||||||
mFormatter = formatter;
|
mFormatter = formatter;
|
||||||
|
|
||||||
if (curValue == CodeAnalysis.DbrValue.ProgramBankReg) {
|
PopulateComboBox();
|
||||||
DataBankStr = PROG_BANK_STR;
|
DataBankStr = DbrValueToString(curValue); // sets combo box
|
||||||
} else if (curValue == CodeAnalysis.DbrValue.Unknown) {
|
IsValid = true;
|
||||||
DataBankStr = string.Empty;
|
}
|
||||||
} else if ((int)curValue >= 0 && (int)curValue <= 255) {
|
|
||||||
// Format as address rather than hexvalue so we don't get leading '$'.
|
private void PopulateComboBox() {
|
||||||
DataBankStr = formatter.FormatAddress((int)curValue, false);
|
// Entry #0 is always the "other" option.
|
||||||
} else {
|
string otherStr = (string)FindResource("str_OtherBank");
|
||||||
Debug.Assert(false, "invalid DBR value " + curValue);
|
BankLabels.Add(new BankLabelItem(0, otherStr));
|
||||||
DataBankStr = string.Empty;
|
|
||||||
|
bool[] done = new bool[256];
|
||||||
|
foreach (AddressMap.AddressMapEntry ent in mProject.AddrMap) {
|
||||||
|
byte bank = (byte)(ent.Addr >> 16);
|
||||||
|
if (done[bank]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
done[bank] = true;
|
||||||
|
|
||||||
|
Anattrib attr = mProject.GetAnattrib(ent.Offset);
|
||||||
|
string label = (attr.Symbol != null) ? attr.Symbol.Label : string.Empty;
|
||||||
|
BankLabels.Add(new BankLabelItem(bank,
|
||||||
|
mFormatter.FormatHexValue(bank, 2) + " " + label));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: combo box
|
BankLabels.Sort();
|
||||||
BankLabels.Add(new BankLabel((CodeAnalysis.DbrValue)1, "(other)"));
|
|
||||||
BankLabels.Add(new BankLabel((CodeAnalysis.DbrValue)1, "$02 FirstBankLabel"));
|
|
||||||
BankLabels.Add(new BankLabel((CodeAnalysis.DbrValue)1, "$88 FancyBank"));
|
|
||||||
bankCombo.SelectedIndex = 0;
|
|
||||||
|
|
||||||
IsValid = true; // TODO: validate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_ContentRendered(object sender, EventArgs e) {
|
private void Window_ContentRendered(object sender, EventArgs e) {
|
||||||
|
@ -105,31 +120,86 @@ namespace SourceGen.WpfGui {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
||||||
Result = GetValue(DataBankStr);
|
Result = StringToDbrValue(DataBankStr);
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateControls() {
|
||||||
|
CodeAnalysis.DbrValue dbrVal = StringToDbrValue(DataBankStr);
|
||||||
|
IsValid = (string.IsNullOrEmpty(DataBankStr) || dbrVal != null);
|
||||||
|
SetComboBoxSelection(dbrVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the selected item in the combo box based on the value in the text edit box.
|
||||||
|
/// </summary>
|
||||||
|
private void SetComboBoxSelection(CodeAnalysis.DbrValue dbrVal) {
|
||||||
|
mSettingComboBox = true; // recursion guard
|
||||||
|
|
||||||
|
//CodeAnalysis.DbrValue dbrVal = StringToDbrValue(DataBankStr);
|
||||||
|
int index = 0;
|
||||||
|
if (dbrVal != null && !dbrVal.FollowPbr) {
|
||||||
|
// skip first entry
|
||||||
|
for (int i = 1; i < BankLabels.Count; i++) {
|
||||||
|
if (BankLabels[i].Bank == dbrVal.Bank) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bankCombo.SelectedIndex = index;
|
||||||
|
|
||||||
|
mSettingComboBox = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reacts to a combo box selection change.
|
||||||
|
/// </summary>
|
||||||
|
private void bankCombo_SelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||||
|
if (mSettingComboBox) {
|
||||||
|
// Selection changed programatically, don't update text edit box.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bankCombo.SelectedIndex == 0) {
|
||||||
|
// "other", don't update text edit box
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BankLabelItem item = (BankLabelItem)bankCombo.SelectedItem;
|
||||||
|
|
||||||
|
DataBankStr = mFormatter.FormatHexValue(item.Bank, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a DBR value string to a value.
|
/// Converts a DBR value string to a value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="valueStr">String to convert.</param>
|
/// <param name="valueStr">String to convert.</param>
|
||||||
/// <returns>DBR value.</returns>
|
/// <returns>DBR value, or null if invalid.</returns>
|
||||||
private static CodeAnalysis.DbrValue GetValue(string valueStr) {
|
private static CodeAnalysis.DbrValue StringToDbrValue(string valueStr) {
|
||||||
if (valueStr == PROG_BANK_STR) {
|
valueStr = valueStr.Trim();
|
||||||
return CodeAnalysis.DbrValue.ProgramBankReg;
|
if (valueStr.Equals(PROG_BANK_STR, StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
return new CodeAnalysis.DbrValue(true, 0, CodeAnalysis.DbrValue.Source.User);
|
||||||
} else {
|
} else {
|
||||||
// Try to parse as 1- or 2-digit hex value.
|
if (!Number.TryParseIntHex(valueStr, out int val)) {
|
||||||
try {
|
Debug.WriteLine("Unable to parse '" + valueStr + "' as hex value");
|
||||||
int val = Convert.ToInt32(valueStr, 16);
|
return null;
|
||||||
if (val < 0 || val > 255) {
|
|
||||||
// invalid value
|
|
||||||
return CodeAnalysis.DbrValue.Unknown;
|
|
||||||
}
|
|
||||||
return (CodeAnalysis.DbrValue)val;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Debug.WriteLine("Result parse failed: " + ex.Message);
|
|
||||||
return CodeAnalysis.DbrValue.Unknown;
|
|
||||||
}
|
}
|
||||||
|
if (val != (byte)val) {
|
||||||
|
Debug.WriteLine("Val " + val + " out of range of byte");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CodeAnalysis.DbrValue(false, (byte)val,
|
||||||
|
CodeAnalysis.DbrValue.Source.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string DbrValueToString(CodeAnalysis.DbrValue value) {
|
||||||
|
if (value == null) {
|
||||||
|
return string.Empty;
|
||||||
|
} else if (value.FollowPbr) {
|
||||||
|
return PROG_BANK_STR;
|
||||||
|
} else {
|
||||||
|
return mFormatter.FormatHexValue(value.Bank, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user