mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-24 22:31:56 +00:00
Add offset to PlSymbol
It's useful for extension scripts to be able to get the file offset of symbols in non-addressable regions. One example of this is CHR ROM data for an NES cartridge. However, we were getting the offset by doing an address-to-offset mapping on the plugin side, which by definition doesn't work for non-addressable memory. So we now add the offset to PlSymbol objects for user labels and address region pre-labels. The NES visualizer has been updated to use the new field. Also, fixed a bogus complaint about bank overruns for non-addressable regions.
This commit is contained in:
parent
1258dd89cb
commit
6e9ff395d2
@ -81,6 +81,11 @@ namespace PluginCommon {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Tag { get; private set; }
|
public string Tag { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol offset, for user labels and pre-labels; -1 otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public int Offset { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Nullary constructor, for deserialization.
|
/// Nullary constructor, for deserialization.
|
||||||
@ -92,14 +97,20 @@ namespace PluginCommon {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="label">Symbol label.</param>
|
/// <param name="label">Symbol label.</param>
|
||||||
/// <param name="value">Symbol value.</param>
|
/// <param name="value">Symbol value.</param>
|
||||||
|
/// <param name="width">Width, for platform/project symbols.</param>
|
||||||
|
/// <param name="source">Symbol source.</param>
|
||||||
|
/// <param name="type">Symbol type.</param>
|
||||||
/// <param name="tag">Symbol group tag.</param>
|
/// <param name="tag">Symbol group tag.</param>
|
||||||
public PlSymbol(string label, int value, int width, Source source, Type type, string tag) {
|
/// <param name="offset">Offset, for user labels and pre-labels; -1 otherwise.</param>
|
||||||
|
public PlSymbol(string label, int value, int width, Source source, Type type, string tag,
|
||||||
|
int offset) {
|
||||||
Label = label;
|
Label = label;
|
||||||
Value = value;
|
Value = value;
|
||||||
Width = width;
|
Width = width;
|
||||||
SymbolSource = source;
|
SymbolSource = source;
|
||||||
SymbolType = type;
|
SymbolType = type;
|
||||||
Tag = tag;
|
Tag = tag;
|
||||||
|
Offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -407,6 +407,10 @@ namespace SourceGen.AsmGen {
|
|||||||
if (attr.Length != instrBytes) {
|
if (attr.Length != instrBytes) {
|
||||||
// This instruction has another instruction inside it. Throw out what we
|
// This instruction has another instruction inside it. Throw out what we
|
||||||
// computed and just output as bytes.
|
// 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);
|
gen.GenerateShortSequence(offset, instrBytes, out opcodeStr, out operandStr);
|
||||||
} else if (isPcRelBankWrap && gen.Quirks.NoPcRelBankWrap) {
|
} else if (isPcRelBankWrap && gen.Quirks.NoPcRelBankWrap) {
|
||||||
// Some assemblers have trouble generating PC-relative operands that wrap
|
// Some assemblers have trouble generating PC-relative operands that wrap
|
||||||
|
@ -759,7 +759,7 @@ namespace SourceGen {
|
|||||||
IEnumerator<AddressMap.AddressChange> addrIter = AddrMap.AddressChangeIterator;
|
IEnumerator<AddressMap.AddressChange> addrIter = AddrMap.AddressChangeIterator;
|
||||||
while (addrIter.MoveNext()) {
|
while (addrIter.MoveNext()) {
|
||||||
AddressMap.AddressChange change = addrIter.Current;
|
AddressMap.AddressChange change = addrIter.Current;
|
||||||
if (!change.IsStart) {
|
if (!change.IsStart || change.Address == Address.NON_ADDR) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AddressMap.AddressRegion region = change.Region;
|
AddressMap.AddressRegion region = change.Region;
|
||||||
@ -1552,46 +1552,7 @@ namespace SourceGen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a mapping from label (which must be unique) to file offset. This
|
SortedList<string, int> labelList = CreateLabelToOffsetMap();
|
||||||
// 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<string, int> labelList = new SortedList<string, int>(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<AddressMap.AddressChange> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No particular reason to do this here, but it's convenient.
|
// No particular reason to do this here, but it's convenient.
|
||||||
ByteCounts.Reset();
|
ByteCounts.Reset();
|
||||||
@ -1802,6 +1763,54 @@ namespace SourceGen {
|
|||||||
return xset; // will be null if not found
|
return xset; // will be null if not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
private SortedList<string, int> CreateLabelToOffsetMap() {
|
||||||
|
SortedList<string, int> labelList = new SortedList<string, int>(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<AddressMap.AddressChange> 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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces generic auto-labels with fancier versions generated from xrefs.
|
/// Replaces generic auto-labels with fancier versions generated from xrefs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3177,7 +3177,7 @@ namespace SourceGen {
|
|||||||
public void GoToLabel(Symbol sym) {
|
public void GoToLabel(Symbol sym) {
|
||||||
int offset = mProject.FindLabelOffsetByName(sym.Label);
|
int offset = mProject.FindLabelOffsetByName(sym.Label);
|
||||||
if (offset >= 0) {
|
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),
|
GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToCodeData),
|
||||||
true);
|
true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,8 +115,7 @@ namespace RuntimeData.Nintendo {
|
|||||||
|
|
||||||
foreach (PlSymbol sym in plSyms) {
|
foreach (PlSymbol sym in plSyms) {
|
||||||
if (sym.Label == CHR_ROM) {
|
if (sym.Label == CHR_ROM) {
|
||||||
int addr = sym.Value;
|
mChrRomOffset = sym.Offset;
|
||||||
mChrRomOffset = mAddrTrans.AddressToOffset(0, addr);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,18 +327,51 @@ namespace SourceGen.Sandbox {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gathers a list of symbols from the project's symbol table.
|
/// Gathers a list of symbols from the project's symbol table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 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.
|
||||||
|
/// </remarks>
|
||||||
private List<PlSymbol> GeneratePlSymbolList() {
|
private List<PlSymbol> GeneratePlSymbolList() {
|
||||||
List<PlSymbol> plSymbols = new List<PlSymbol>();
|
List<PlSymbol> plSymbols = new List<PlSymbol>();
|
||||||
SymbolTable symTab = mProject.SymbolTable;
|
SymbolTable symTab = mProject.SymbolTable;
|
||||||
|
|
||||||
|
// UserLabels maps offset to Symbol. Create the reverse mapping.
|
||||||
|
Dictionary<Symbol, int> symbolOffsets =
|
||||||
|
new Dictionary<Symbol, int>(mProject.UserLabels.Count);
|
||||||
|
foreach (KeyValuePair<int, Symbol> kvp in mProject.UserLabels) {
|
||||||
|
symbolOffsets[kvp.Value] = kvp.Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add in the address region pre-labels.
|
||||||
|
IEnumerator<AddressMap.AddressChange> 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) {
|
foreach (Symbol sym in symTab) {
|
||||||
PlSymbol.Source plsSource;
|
PlSymbol.Source plsSource;
|
||||||
|
int symOff, offset = -1;
|
||||||
switch (sym.SymbolSource) {
|
switch (sym.SymbolSource) {
|
||||||
case Symbol.Source.User:
|
case Symbol.Source.User:
|
||||||
plsSource = PlSymbol.Source.User;
|
plsSource = PlSymbol.Source.User;
|
||||||
|
if (symbolOffsets.TryGetValue(sym, out symOff)) {
|
||||||
|
offset = symOff;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Symbol.Source.AddrPreLabel:
|
case Symbol.Source.AddrPreLabel:
|
||||||
plsSource = PlSymbol.Source.AddrPreLabel;
|
plsSource = PlSymbol.Source.AddrPreLabel;
|
||||||
|
if (symbolOffsets.TryGetValue(sym, out symOff)) {
|
||||||
|
offset = symOff;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Symbol.Source.Project:
|
case Symbol.Source.Project:
|
||||||
plsSource = PlSymbol.Source.Project;
|
plsSource = PlSymbol.Source.Project;
|
||||||
@ -381,8 +414,8 @@ namespace SourceGen.Sandbox {
|
|||||||
tag = defSym.Tag;
|
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;
|
return plSymbols;
|
||||||
|
Loading…
Reference in New Issue
Block a user