mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +00:00
Data Bank Register management, part 3
Added a "fake" assembler pseudo-op for DBR changes. Display entries in line list. Added entry to double-click handler so that you can double-click on a PLB instruction operand to open the data bank editor.
This commit is contained in:
parent
973d162edb
commit
ee58d9e803
@ -109,6 +109,7 @@ namespace SourceGen.AsmGen {
|
||||
//VarDirective
|
||||
{ "OrgDirective", "!pseudopc" },
|
||||
//RegWidthDirective // !al, !as, !rl, !rs
|
||||
//DataBankDirective
|
||||
{ "DefineData1", "!byte" },
|
||||
{ "DefineData2", "!word" },
|
||||
{ "DefineData3", "!24" },
|
||||
|
@ -106,6 +106,7 @@ namespace SourceGen.AsmGen {
|
||||
{ "VarDirective", ".set" },
|
||||
{ "OrgDirective", ".org" },
|
||||
//RegWidthDirective // .a8, .a16, .i8, .i16
|
||||
//DataBankDirective
|
||||
{ "DefineData1", ".byte" },
|
||||
{ "DefineData2", ".word" },
|
||||
{ "DefineData3", ".faraddr" },
|
||||
|
@ -97,6 +97,7 @@ namespace SourceGen.AsmGen {
|
||||
{ "VarDirective", "equ" },
|
||||
{ "OrgDirective", "org" },
|
||||
//RegWidthDirective
|
||||
//DataBankDirective
|
||||
{ "DefineData1", "dfb" },
|
||||
{ "DefineData2", "dw" },
|
||||
{ "DefineData3", "adr" },
|
||||
|
@ -123,6 +123,7 @@ namespace SourceGen.AsmGen {
|
||||
{ "VarDirective", ".var" },
|
||||
{ "OrgDirective", ".logical" },
|
||||
//RegWidthDirective // .as, .al, .xs, .xl
|
||||
//DataBankDirective
|
||||
{ "DefineData1", ".byte" },
|
||||
{ "DefineData2", ".word" },
|
||||
{ "DefineData3", ".long" },
|
||||
|
@ -1238,7 +1238,7 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
public byte Bank { get; private set; }
|
||||
|
||||
public enum Source { Unknown = 0, User, Auto, Smart };
|
||||
public enum Source { Unknown = 0, User, Auto };
|
||||
/// <summary>
|
||||
/// From whence this value originates.
|
||||
/// </summary>
|
||||
@ -1295,9 +1295,12 @@ namespace SourceGen {
|
||||
/// Determines the value of the Data Bank Register (DBR, register 'B') for relevant
|
||||
/// instructions, and updates the Anattrib OperandOffset value.
|
||||
/// </summary>
|
||||
public void ApplyDataBankRegister(Dictionary<int, DbrValue> userValues) {
|
||||
public void ApplyDataBankRegister(Dictionary<int, DbrValue> userValues,
|
||||
Dictionary<int, DbrValue> dbrChanges) {
|
||||
Debug.Assert(!mCpuDef.HasAddr16); // 65816 only
|
||||
|
||||
dbrChanges.Clear();
|
||||
|
||||
short[] bval = new short[mAnattribs.Length];
|
||||
|
||||
// Initialize all entries to "unknown".
|
||||
@ -1310,24 +1313,29 @@ namespace SourceGen {
|
||||
if (mapBank != prevBank) {
|
||||
bval[ent.Offset] = mapBank;
|
||||
prevBank = mapBank;
|
||||
dbrChanges.Add(ent.Offset, new DbrValue(false, (byte)mapBank,
|
||||
DbrValue.Source.Auto));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the user-specified values.
|
||||
// Apply the user-specified values, overwriting existing values.
|
||||
foreach (KeyValuePair<int, DbrValue> kvp in userValues) {
|
||||
dbrChanges[kvp.Key] = kvp.Value;
|
||||
bval[kvp.Key] = kvp.Value.AsShort;
|
||||
}
|
||||
|
||||
// Run through the file, looking for PHK/PLB pairs. When we find one, set an
|
||||
// entry for the PLB instruction unless an entry already exists there.
|
||||
|
||||
// add to dbrChanges with "Auto" or "smart"
|
||||
|
||||
// ? look for LDA #imm8 / PHA / PLB?
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
// Run through file, updating instructions as needed.
|
||||
short curVal = DbrValue.UNKNOWN;
|
||||
short curVal = 0;
|
||||
for (int offset = 0; offset < mAnattribs.Length; offset++) {
|
||||
if (bval[offset] != DbrValue.UNKNOWN) {
|
||||
curVal = bval[offset];
|
||||
|
@ -77,7 +77,7 @@ namespace SourceGen {
|
||||
/// <summary>
|
||||
/// Data Bank Register overrides.
|
||||
/// </summary>
|
||||
public Dictionary<int, CodeAnalysis.DbrValue> DbrValues { get; private set; }
|
||||
public Dictionary<int, CodeAnalysis.DbrValue> DbrOverrides { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Full line, possibly multi-line comments.
|
||||
@ -195,6 +195,12 @@ namespace SourceGen {
|
||||
// before data analysis has begun.
|
||||
private Anattrib[] mCodeOnlyAnattribs;
|
||||
|
||||
/// <summary>
|
||||
/// Changes to the Data Bank Register, by offset. These can come from DbrOverrides
|
||||
/// or be automatically generated.
|
||||
/// </summary>
|
||||
public Dictionary<int, CodeAnalysis.DbrValue> DbrChanges { get; private set; }
|
||||
|
||||
// Symbol lists loaded from platform symbol files. This is essentially a list
|
||||
// of lists, of symbols.
|
||||
private List<PlatformSymbols> PlatformSyms { get; set; }
|
||||
@ -279,7 +285,8 @@ namespace SourceGen {
|
||||
Comments[i] = string.Empty;
|
||||
}
|
||||
|
||||
DbrValues = new Dictionary<int, CodeAnalysis.DbrValue>();
|
||||
DbrOverrides = new Dictionary<int, CodeAnalysis.DbrValue>();
|
||||
DbrChanges = new Dictionary<int, CodeAnalysis.DbrValue>();
|
||||
LongComments = new Dictionary<int, MultiLineComment>();
|
||||
Notes = new SortedList<int, MultiLineComment>();
|
||||
|
||||
@ -816,7 +823,7 @@ namespace SourceGen {
|
||||
if (!CpuDef.HasAddr16) {
|
||||
// 24-bit address space, so DBR matters
|
||||
reanalysisTimer.StartTask("CodeAnalysis.ApplyDataBankRegister");
|
||||
ca.ApplyDataBankRegister(DbrValues);
|
||||
ca.ApplyDataBankRegister(DbrOverrides, DbrChanges);
|
||||
reanalysisTimer.EndTask("CodeAnalysis.ApplyDataBankRegister");
|
||||
}
|
||||
|
||||
@ -2120,16 +2127,16 @@ namespace SourceGen {
|
||||
break;
|
||||
case UndoableChange.ChangeType.SetDataBank: {
|
||||
// If there's no entry, treat it as an entry with value = Unknown.
|
||||
DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue current);
|
||||
DbrOverrides.TryGetValue(offset, out CodeAnalysis.DbrValue current);
|
||||
if (current != (CodeAnalysis.DbrValue)oldValue) {
|
||||
Debug.WriteLine("GLITCH: old DBR value mismatch (" +
|
||||
current + " vs " + oldValue + ")");
|
||||
Debug.Assert(false);
|
||||
}
|
||||
if (newValue == null) {
|
||||
DbrValues.Remove(offset);
|
||||
DbrOverrides.Remove(offset);
|
||||
} else {
|
||||
DbrValues[offset] = (CodeAnalysis.DbrValue)newValue;
|
||||
DbrOverrides[offset] = (CodeAnalysis.DbrValue)newValue;
|
||||
}
|
||||
|
||||
// ignore affectedOffsets
|
||||
|
@ -350,6 +350,7 @@ namespace SourceGen {
|
||||
case LineListGen.Line.Type.Data:
|
||||
case LineListGen.Line.Type.EquDirective:
|
||||
case LineListGen.Line.Type.RegWidthDirective:
|
||||
case LineListGen.Line.Type.DataBankDirective:
|
||||
case LineListGen.Line.Type.OrgDirective:
|
||||
case LineListGen.Line.Type.LocalVariableTable:
|
||||
if (parts.IsLongComment) {
|
||||
@ -710,6 +711,7 @@ namespace SourceGen {
|
||||
case LineListGen.Line.Type.Data:
|
||||
case LineListGen.Line.Type.EquDirective:
|
||||
case LineListGen.Line.Type.RegWidthDirective:
|
||||
case LineListGen.Line.Type.DataBankDirective:
|
||||
case LineListGen.Line.Type.OrgDirective:
|
||||
case LineListGen.Line.Type.LocalVariableTable:
|
||||
if (parts.IsLongComment) {
|
||||
|
@ -119,10 +119,11 @@ namespace SourceGen {
|
||||
OrgDirective = 1 << 5,
|
||||
EquDirective = 1 << 6,
|
||||
RegWidthDirective = 1 << 7,
|
||||
DataBankDirective = 1 << 8,
|
||||
|
||||
// Additional metadata.
|
||||
LocalVariableTable = 1 << 8,
|
||||
VisualizationSet = 1 << 9,
|
||||
LocalVariableTable = 1 << 9,
|
||||
VisualizationSet = 1 << 10,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -516,6 +517,7 @@ namespace SourceGen {
|
||||
break;
|
||||
case Line.Type.OrgDirective:
|
||||
case Line.Type.RegWidthDirective:
|
||||
case Line.Type.DataBankDirective:
|
||||
case Line.Type.LongComment:
|
||||
case Line.Type.Note:
|
||||
// should have been done already
|
||||
@ -1006,7 +1008,9 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
if (attr.IsInstructionStart) {
|
||||
// Generate reg width directive, if necessary.
|
||||
// Generate reg width directive, if necessary. These are generated after the
|
||||
// SEP/REP/PLP instruction has taken effect, so we want it to appear *before*
|
||||
// the current instruction.
|
||||
if (mProject.CpuDef.HasEmuFlag) {
|
||||
// Changing from "ambiguous but assumed short" to "definitively short"
|
||||
// merits a directive, notably at the start of the file. The tricky
|
||||
@ -1044,6 +1048,34 @@ namespace SourceGen {
|
||||
prevFlags = curFlags;
|
||||
}
|
||||
|
||||
// Add data bank register change. This is generally applied to a PLB
|
||||
// instruction, so we'd like it to appear on the line following the
|
||||
// instruction, but that looks funny for e.g. the auto-added B=K at the
|
||||
// start of each bank, and would be wrong if placed on a "LDA abs" line.
|
||||
// (We could handle PLB lines differently, but apparently inconsistent
|
||||
// behavior is unwise.)
|
||||
if (mProject.DbrChanges.TryGetValue(offset,
|
||||
out CodeAnalysis.DbrValue dbrValue)) {
|
||||
string operandStr;
|
||||
if (dbrValue.FollowPbr) {
|
||||
operandStr = Res.Strings.DATA_BANK_USER_K;
|
||||
} else {
|
||||
string fmt;
|
||||
if (dbrValue.ValueSource == CodeAnalysis.DbrValue.Source.Auto) {
|
||||
fmt = Res.Strings.DATA_BANK_AUTO_FMT;
|
||||
} else {
|
||||
fmt = Res.Strings.DATA_BANK_USER_FMT;
|
||||
}
|
||||
operandStr = string.Format(fmt,
|
||||
mFormatter.FormatHexValue(dbrValue.Bank, 2));
|
||||
}
|
||||
Line dbrLine = new Line(offset, 0, Line.Type.DataBankDirective);
|
||||
dbrLine.Parts = FormattedParts.CreateDirective(
|
||||
mFormatter.FormatPseudoOp(mPseudoOpNames.DataBankDirective),
|
||||
mFormatter.FormatPseudoOp(operandStr));
|
||||
lines.Add(dbrLine);
|
||||
}
|
||||
|
||||
// Look for embedded instructions.
|
||||
int len;
|
||||
for (len = 1; len < attr.Length; len++) {
|
||||
|
@ -1508,6 +1508,11 @@ namespace SourceGen {
|
||||
EditStatusFlags();
|
||||
}
|
||||
break;
|
||||
case LineListGen.Line.Type.DataBankDirective:
|
||||
if (CanEditDataBank()) {
|
||||
EditDataBank();
|
||||
}
|
||||
break;
|
||||
case LineListGen.Line.Type.LongComment:
|
||||
if (CanEditLongComment()) {
|
||||
EditLongComment();
|
||||
@ -1559,7 +1564,14 @@ namespace SourceGen {
|
||||
}
|
||||
break;
|
||||
case CodeListColumn.Opcode:
|
||||
if (IsPlbInstruction(line) && CanEditDataBank()) {
|
||||
// Special handling for PLB instruction, so you can update the bank
|
||||
// value just be double-clicking on it. Only used for PLBs without
|
||||
// user- or auto-assigned bank changes.
|
||||
EditDataBank();
|
||||
} else {
|
||||
JumpToOperandTarget(line, false);
|
||||
}
|
||||
break;
|
||||
case CodeListColumn.Operand:
|
||||
if (CanEditOperand()) {
|
||||
@ -1571,7 +1583,6 @@ namespace SourceGen {
|
||||
EditComment();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1581,6 +1592,26 @@ namespace SourceGen {
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsPlbInstruction(LineListGen.Line line) {
|
||||
if (line.LineType != LineListGen.Line.Type.Code) {
|
||||
return false;
|
||||
}
|
||||
int offset = line.FileOffset;
|
||||
Anattrib attr = mProject.GetAnattrib(offset);
|
||||
|
||||
// should always be an instruction start since this is a code line
|
||||
if (!attr.IsInstructionStart) {
|
||||
Debug.Assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
OpDef op = mProject.CpuDef.GetOpDef(mProject.FileData[offset]);
|
||||
if (op != OpDef.OpPLB_StackPull) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Jumps to the line referenced by the operand of the selected line.
|
||||
/// </summary>
|
||||
@ -1865,8 +1896,8 @@ namespace SourceGen {
|
||||
if (SelectionAnalysis.mNumItemsSelected != 1) {
|
||||
return false;
|
||||
}
|
||||
return (SelectionAnalysis.mLineType == LineListGen.Line.Type.Code /*||
|
||||
is data bank */);
|
||||
return (SelectionAnalysis.mLineType == LineListGen.Line.Type.Code ||
|
||||
SelectionAnalysis.mLineType == LineListGen.Line.Type.DataBankDirective);
|
||||
}
|
||||
|
||||
public void EditDataBank() {
|
||||
@ -1874,7 +1905,7 @@ namespace SourceGen {
|
||||
int offset = CodeLineList[selIndex].FileOffset;
|
||||
|
||||
// Get current user-specified value, or null.
|
||||
mProject.DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue curValue);
|
||||
mProject.DbrOverrides.TryGetValue(offset, out CodeAnalysis.DbrValue curValue);
|
||||
|
||||
EditDataBank dlg = new EditDataBank(mMainWin, mProject, mFormatter, curValue);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
@ -3782,6 +3813,9 @@ namespace SourceGen {
|
||||
case LineListGen.Line.Type.RegWidthDirective:
|
||||
lineTypeStr = "register width directive";
|
||||
break;
|
||||
case LineListGen.Line.Type.DataBankDirective:
|
||||
lineTypeStr = "data bank directive";
|
||||
break;
|
||||
|
||||
case LineListGen.Line.Type.LocalVariableTable:
|
||||
isSimple = false;
|
||||
|
@ -549,8 +549,8 @@ namespace SourceGen {
|
||||
|
||||
// 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 = new Dictionary<string, SerDbrValue>(proj.DbrOverrides.Count);
|
||||
foreach (KeyValuePair<int, CodeAnalysis.DbrValue> kvp in proj.DbrOverrides) {
|
||||
spf.DbrValues.Add(kvp.Key.ToString(), new SerDbrValue(kvp.Value));
|
||||
}
|
||||
|
||||
@ -883,7 +883,7 @@ namespace SourceGen {
|
||||
}
|
||||
CodeAnalysis.DbrValue newDbr = new CodeAnalysis.DbrValue(kvp.Value.FollowPbr,
|
||||
kvp.Value.Bank, CodeAnalysis.DbrValue.Source.User);
|
||||
proj.DbrValues.Add(intKey, newDbr);
|
||||
proj.DbrOverrides.Add(intKey, newDbr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,7 @@ namespace SourceGen {
|
||||
public string VarDirective { get; private set; }
|
||||
public string OrgDirective { get; private set; }
|
||||
public string RegWidthDirective { get; private set; }
|
||||
public string DataBankDirective { get; private set; }
|
||||
|
||||
public string DefineData1 { get; private set; }
|
||||
public string DefineData2 { get; private set; }
|
||||
@ -118,6 +119,7 @@ namespace SourceGen {
|
||||
a.VarDirective == b.VarDirective &&
|
||||
a.OrgDirective == b.OrgDirective &&
|
||||
a.RegWidthDirective == b.RegWidthDirective &&
|
||||
a.DataBankDirective == b.DataBankDirective &&
|
||||
a.DefineData1 == b.DefineData1 &&
|
||||
a.DefineData2 == b.DefineData2 &&
|
||||
a.DefineData3 == b.DefineData3 &&
|
||||
@ -228,6 +230,7 @@ namespace SourceGen {
|
||||
{ "VarDirective", ".var" },
|
||||
{ "OrgDirective", ".org" },
|
||||
{ "RegWidthDirective", ".rwid" },
|
||||
{ "DataBankDirective", ".dbank" },
|
||||
|
||||
{ "DefineData1", ".dd1" },
|
||||
{ "DefineData2", ".dd2" },
|
||||
|
@ -34,6 +34,9 @@ limitations under the License.
|
||||
<system:String x:Key="str_ClipformatAllColumns">All Columns</system:String>
|
||||
<system:String x:Key="str_ClipformatAssemblerSource">Assembler Source</system:String>
|
||||
<system:String x:Key="str_ClipformatDisassembly">Disassembly</system:String>
|
||||
<system:String x:Key="str_DataBankAutoFmt">{0} (auto)</system:String>
|
||||
<system:String x:Key="str_DataBankUserFmt">{0}</system:String>
|
||||
<system:String x:Key="str_DataBankUserK">K</system:String>
|
||||
<system:String x:Key="str_DefaultHeaderCommentFmt">6502bench SourceGen v{0}</system:String>
|
||||
<system:String x:Key="str_DefaultAsciiDelimPat">‘#’</system:String>
|
||||
<system:String x:Key="str_DefaultHighAsciiDelimPat">“#”</system:String>
|
||||
|
@ -43,6 +43,12 @@ namespace SourceGen.Res {
|
||||
(string)Application.Current.FindResource("str_AsmMismatchLengthFmt");
|
||||
public static string ASM_OUTPUT_NOT_FOUND =
|
||||
(string)Application.Current.FindResource("str_AsmOutputNotFound");
|
||||
public static string DATA_BANK_AUTO_FMT =
|
||||
(string)Application.Current.FindResource("str_DataBankAutoFmt");
|
||||
public static string DATA_BANK_USER_FMT =
|
||||
(string)Application.Current.FindResource("str_DataBankUserFmt");
|
||||
public static string DATA_BANK_USER_K =
|
||||
(string)Application.Current.FindResource("str_DataBankUserK");
|
||||
public static string DEFAULT_HEADER_COMMENT_FMT =
|
||||
(string)Application.Current.FindResource("str_DefaultHeaderCommentFmt");
|
||||
public static string DEFAULT_ASCII_DELIM_PAT =
|
||||
|
@ -758,6 +758,12 @@ limitations under the License.
|
||||
VerticalAlignment="Center" Margin="{StaticResource TBS}"
|
||||
Text=".placeho" MaxLength="12"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||
<TextBlock Grid.Column="6" Grid.Row="5" Text="Data bank:"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"/>
|
||||
<TextBox Name="dataBankTextBox" Grid.Column="7" Grid.Row="5"
|
||||
VerticalAlignment="Center" Margin="{StaticResource TBS}"
|
||||
Text=".placeho" MaxLength="12"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||
</Grid>
|
||||
|
||||
<GroupBox DockPanel.Dock="Bottom" Header="Quick Set"
|
||||
|
@ -1138,6 +1138,7 @@ namespace SourceGen.WpfGui {
|
||||
new TextBoxPropertyMap(varDirectiveTextBox, "VarDirective"),
|
||||
new TextBoxPropertyMap(orgDirectiveTextBox, "OrgDirective"),
|
||||
new TextBoxPropertyMap(regWidthDirectiveTextBox, "RegWidthDirective"),
|
||||
new TextBoxPropertyMap(dataBankTextBox, "DataBankDirective"),
|
||||
new TextBoxPropertyMap(defineData1TextBox, "DefineData1"),
|
||||
new TextBoxPropertyMap(defineData2TextBox, "DefineData2"),
|
||||
new TextBoxPropertyMap(defineData3TextBox, "DefineData3"),
|
||||
|
@ -176,7 +176,10 @@ namespace SourceGen.WpfGui {
|
||||
/// <returns>DBR value, or null if invalid.</returns>
|
||||
private static CodeAnalysis.DbrValue StringToDbrValue(string valueStr) {
|
||||
valueStr = valueStr.Trim();
|
||||
if (valueStr.Equals(PROG_BANK_STR, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
if (string.IsNullOrEmpty(valueStr)) {
|
||||
return null;
|
||||
} else if (valueStr.Equals(PROG_BANK_STR,
|
||||
StringComparison.InvariantCultureIgnoreCase)) {
|
||||
return new CodeAnalysis.DbrValue(true, 0, CodeAnalysis.DbrValue.Source.User);
|
||||
} else {
|
||||
if (!Number.TryParseIntHex(valueStr, out int val)) {
|
||||
|
Loading…
Reference in New Issue
Block a user