diff --git a/PluginCommon/PlSymbol.cs b/PluginCommon/PlSymbol.cs
index fe28f17..c88b139 100644
--- a/PluginCommon/PlSymbol.cs
+++ b/PluginCommon/PlSymbol.cs
@@ -81,6 +81,11 @@ namespace PluginCommon {
///
public string Tag { get; private set; }
+ ///
+ /// Symbol offset, for user labels and pre-labels; -1 otherwise.
+ ///
+ public int Offset { get; private set; }
+
///
/// Nullary constructor, for deserialization.
@@ -92,14 +97,20 @@ namespace PluginCommon {
///
/// Symbol label.
/// Symbol value.
+ /// Width, for platform/project symbols.
+ /// Symbol source.
+ /// Symbol type.
/// Symbol group tag.
- public PlSymbol(string label, int value, int width, Source source, Type type, string tag) {
+ /// Offset, for user labels and pre-labels; -1 otherwise.
+ public PlSymbol(string label, int value, int width, Source source, Type type, string tag,
+ int offset) {
Label = label;
Value = value;
Width = width;
SymbolSource = source;
SymbolType = type;
Tag = tag;
+ Offset = offset;
}
///
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index 04225c0..5754518 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -407,6 +407,10 @@ namespace SourceGen.AsmGen {
if (attr.Length != instrBytes) {
// This instruction has another instruction inside it. Throw out what we
// computed and just output as bytes.
+ // TODO: in some odd situations we can split something that doesn't need
+ // to be split (see note at end of #107). Working around the problem at
+ // this stage is a little awkward because I think we need to check for the
+ // presence of labels on one or more later lines.
gen.GenerateShortSequence(offset, instrBytes, out opcodeStr, out operandStr);
} else if (isPcRelBankWrap && gen.Quirks.NoPcRelBankWrap) {
// Some assemblers have trouble generating PC-relative operands that wrap
diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs
index 3c2ab6f..43343dd 100644
--- a/SourceGen/DisasmProject.cs
+++ b/SourceGen/DisasmProject.cs
@@ -759,7 +759,7 @@ namespace SourceGen {
IEnumerator addrIter = AddrMap.AddressChangeIterator;
while (addrIter.MoveNext()) {
AddressMap.AddressChange change = addrIter.Current;
- if (!change.IsStart) {
+ if (!change.IsStart || change.Address == Address.NON_ADDR) {
continue;
}
AddressMap.AddressRegion region = change.Region;
@@ -1552,46 +1552,7 @@ namespace SourceGen {
}
}
- // Create a mapping from label (which must be unique) to file offset. This
- // is different from UserLabels (which only has user-created labels, and is
- // sorted by offset) and SymbolTable (which has constants and platform symbols,
- // and uses the address as the value rather than the offset).
- SortedList labelList = new SortedList(mFileData.Length,
- Asm65.Label.LABEL_COMPARER);
- for (int offset = 0; offset < mAnattribs.Length; offset++) {
- Anattrib attr = mAnattribs[offset];
- if (attr.Symbol != null) {
- try {
- labelList.Add(attr.Symbol.Label, offset);
- } catch (ArgumentException ex) {
- // Duplicate UserLabel entries are stripped when projects are loaded, but
- // it might be possible to cause this by hiding/unhiding a label (e.g.
- // using a code start tag to place it in the middle of an instruction).
- // Just ignore the duplicate.
- Debug.WriteLine("Xref ignoring duplicate label '" + attr.Symbol.Label +
- "': " + ex.Message);
- }
- }
- }
- // Add all valid address region pre-labels. Duplicates of user labels will be
- // rejected. Note the references will appear on the line for the next file offset,
- // not the pre-label itself, because we need to associate it with a file offset.
- IEnumerator addrIter = AddrMap.AddressChangeIterator;
- while (addrIter.MoveNext()) {
- AddressMap.AddressChange change = addrIter.Current;
- if (!change.IsStart) {
- continue;
- }
- if (change.Region.HasValidPreLabel) {
- try {
- labelList.Add(change.Region.PreLabel, change.Region.Offset);
- } catch (ArgumentException ex) {
- Debug.WriteLine("Xref ignoring pre-label duplicate '" +
- change.Region.PreLabel + "': " + ex.Message);
- }
-
- }
- }
+ SortedList labelList = CreateLabelToOffsetMap();
// No particular reason to do this here, but it's convenient.
ByteCounts.Reset();
@@ -1802,6 +1763,54 @@ namespace SourceGen {
return xset; // will be null if not found
}
+ ///
+ /// Creates a mapping from label (which must be unique) to file offset. This
+ /// is different from UserLabels (which only has user-created labels, and is
+ /// sorted by offset) and SymbolTable (which has constants and platform symbols,
+ /// and uses the address as the value rather than the offset).
+ ///
+ /// We use Anattribs to ensure that we only include visible labels.
+ ///
+ private SortedList CreateLabelToOffsetMap() {
+ SortedList labelList = new SortedList(mFileData.Length,
+ Asm65.Label.LABEL_COMPARER);
+ for (int offset = 0; offset < mAnattribs.Length; offset++) {
+ Anattrib attr = mAnattribs[offset];
+ if (attr.Symbol != null) {
+ try {
+ labelList.Add(attr.Symbol.Label, offset);
+ } catch (ArgumentException ex) {
+ // Duplicate UserLabel entries are stripped when projects are loaded, but
+ // it might be possible to cause this by hiding/unhiding a label (e.g.
+ // using a code start tag to place it in the middle of an instruction).
+ // Just ignore the duplicate.
+ Debug.WriteLine("Xref ignoring duplicate label '" + attr.Symbol.Label +
+ "': " + ex.Message);
+ }
+ }
+ }
+ // Add all valid address region pre-labels. Duplicates of user labels will be
+ // rejected. Note the references will appear on the line for the next file offset,
+ // not the pre-label itself, because we need to associate it with a file offset.
+ IEnumerator addrIter = AddrMap.AddressChangeIterator;
+ while (addrIter.MoveNext()) {
+ AddressMap.AddressChange change = addrIter.Current;
+ if (!change.IsStart) {
+ continue;
+ }
+ if (change.Region.HasValidPreLabel) {
+ try {
+ labelList.Add(change.Region.PreLabel, change.Region.Offset);
+ } catch (ArgumentException ex) {
+ Debug.WriteLine("Xref ignoring pre-label duplicate '" +
+ change.Region.PreLabel + "': " + ex.Message);
+ }
+
+ }
+ }
+ return labelList;
+ }
+
///
/// Replaces generic auto-labels with fancier versions generated from xrefs.
///
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index 3dd0a81..c8c723b 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -3177,7 +3177,7 @@ namespace SourceGen {
public void GoToLabel(Symbol sym) {
int offset = mProject.FindLabelOffsetByName(sym.Label);
if (offset >= 0) {
- // TODO(someday): jump to correct line for address region pre-labels
+ // TODO(someday): jump to symbol line, not arstart, for address region pre-labels
GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToCodeData),
true);
} else {
diff --git a/SourceGen/RuntimeData/Nintendo/VisNES.cs b/SourceGen/RuntimeData/Nintendo/VisNES.cs
index 6ca1d0e..9ad53ae 100644
--- a/SourceGen/RuntimeData/Nintendo/VisNES.cs
+++ b/SourceGen/RuntimeData/Nintendo/VisNES.cs
@@ -115,8 +115,7 @@ namespace RuntimeData.Nintendo {
foreach (PlSymbol sym in plSyms) {
if (sym.Label == CHR_ROM) {
- int addr = sym.Value;
- mChrRomOffset = mAddrTrans.AddressToOffset(0, addr);
+ mChrRomOffset = sym.Offset;
break;
}
}
diff --git a/SourceGen/Sandbox/ScriptManager.cs b/SourceGen/Sandbox/ScriptManager.cs
index bd4bb6b..ac80d40 100644
--- a/SourceGen/Sandbox/ScriptManager.cs
+++ b/SourceGen/Sandbox/ScriptManager.cs
@@ -327,18 +327,51 @@ namespace SourceGen.Sandbox {
///
/// Gathers a list of symbols from the project's symbol table.
///
+ ///
+ /// Remember that we need to set this up before code analysis runs, so many of the
+ /// secondary data structures (like Anattribs) won't be available.
+ ///
private List GeneratePlSymbolList() {
List plSymbols = new List();
SymbolTable symTab = mProject.SymbolTable;
+ // UserLabels maps offset to Symbol. Create the reverse mapping.
+ Dictionary symbolOffsets =
+ new Dictionary(mProject.UserLabels.Count);
+ foreach (KeyValuePair kvp in mProject.UserLabels) {
+ symbolOffsets[kvp.Value] = kvp.Key;
+ }
+
+ // Add in the address region pre-labels.
+ IEnumerator addrIter = mProject.AddrMap.AddressChangeIterator;
+ while (addrIter.MoveNext()) {
+ AddressMap.AddressChange change = addrIter.Current;
+ if (!change.IsStart) {
+ continue;
+ }
+ if (change.Region.HasValidPreLabel) {
+ Symbol newSym = new Symbol(change.Region.PreLabel,
+ change.Region.PreLabelAddress, Symbol.Source.AddrPreLabel,
+ Symbol.Type.ExternalAddr, Symbol.LabelAnnotation.None);
+ symbolOffsets[newSym] = change.Region.Offset;
+ }
+ }
+
foreach (Symbol sym in symTab) {
PlSymbol.Source plsSource;
+ int symOff, offset = -1;
switch (sym.SymbolSource) {
case Symbol.Source.User:
plsSource = PlSymbol.Source.User;
+ if (symbolOffsets.TryGetValue(sym, out symOff)) {
+ offset = symOff;
+ }
break;
case Symbol.Source.AddrPreLabel:
plsSource = PlSymbol.Source.AddrPreLabel;
+ if (symbolOffsets.TryGetValue(sym, out symOff)) {
+ offset = symOff;
+ }
break;
case Symbol.Source.Project:
plsSource = PlSymbol.Source.Project;
@@ -381,8 +414,8 @@ namespace SourceGen.Sandbox {
tag = defSym.Tag;
}
-
- plSymbols.Add(new PlSymbol(sym.Label, sym.Value, width, plsSource, plsType, tag));
+ plSymbols.Add(new PlSymbol(sym.Label, sym.Value, width, plsSource, plsType, tag,
+ offset));
}
return plSymbols;