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;