mirror of
https://github.com/fadden/6502bench.git
synced 2025-01-13 00:29:44 +00:00
ORG rework, part 9
Modified "jump to" code to understand address range start/end lines. If there are multiple starts or ends at the same offset, we jump to the first one in the set, which is suboptimal but simpler to do. Simplified the API, embedding GoToMode in the Location object (which is where it really needs to be, to make fwd/back work right). Updated HTML export to grey out addresses in NON_ADDR sections. Changed default pseudo-op strings for address regions to ".addrs" and ".adrend", after trying a bunch of things that were worse. Added definitions for region-end pseudo-ops to Merlin32 and cc65 for display on screen. Added regression test 20260 for address region pre-labels. Fixed handling of leading underscores in platform/project symbols. These need to be escaped in 64tass output. Updated regression test 20170-external-symbols to check it.
This commit is contained in:
parent
d2326c389f
commit
0ac0686c7a
@ -977,7 +977,7 @@ namespace CommonUtil {
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is NOT intended to say whether the sequence of addresses has a hiccup. The goal
|
||||
/// is to identify multi-byte elements that have a .arstart/.arend statement in the middle.
|
||||
/// is to identify multi-byte elements that have an arstart/arend statement in the middle.
|
||||
///
|
||||
/// We can do this in a couple of different ways:
|
||||
/// 1. Find the node that holds the offset, confirm that it spans offset+length, and
|
||||
|
@ -112,8 +112,8 @@ namespace SourceGen.AsmGen {
|
||||
{ "EquDirective", "=" },
|
||||
{ "VarDirective", ".set" },
|
||||
{ "ArStartDirective", ".org" },
|
||||
//ArEndDirective
|
||||
//RegWidthDirective // .a8, .a16, .i8, .i16
|
||||
{ "ArEndDirective", ".adrend" }, // on-screen display only
|
||||
//RegWidthDirective // .a8, .a16, .i8, .i16
|
||||
//DataBankDirective
|
||||
{ "DefineData1", ".byte" },
|
||||
{ "DefineData2", ".word" },
|
||||
@ -123,12 +123,12 @@ namespace SourceGen.AsmGen {
|
||||
//DefineBigData3
|
||||
//DefineBigData4
|
||||
{ "Fill", ".res" },
|
||||
{ "Dense", ".byte" }, // not really dense, just comma-separated bytes
|
||||
{ "Dense", ".byte" }, // really just just comma-separated bytes
|
||||
//Junk
|
||||
{ "StrGeneric", ".byte" },
|
||||
//StrReverse
|
||||
{ "StrNullTerm", ".asciiz" },
|
||||
//StrLen8 // macro with .strlen?
|
||||
//StrLen8 // TODO(maybe): macro with .strlen?
|
||||
//StrLen16
|
||||
//StrDci
|
||||
});
|
||||
|
@ -106,7 +106,7 @@ namespace SourceGen.AsmGen {
|
||||
{ "EquDirective", "equ" },
|
||||
{ "VarDirective", "equ" },
|
||||
{ "ArStartDirective", "org" },
|
||||
{ "ArEndDirective", "org_end" }, // not actually used
|
||||
{ "ArEndDirective", "adrend" }, // on-screen display only
|
||||
//RegWidthDirective
|
||||
//DataBankDirective
|
||||
{ "DefineData1", "dfb" },
|
||||
|
@ -735,9 +735,15 @@ namespace SourceGen {
|
||||
}
|
||||
if ((mLeftFlags & ActiveColumnFlags.Address) != 0) {
|
||||
if (!string.IsNullOrEmpty(parts.Addr)) {
|
||||
string str = parts.Addr + ":";
|
||||
string str;
|
||||
if (parts.IsNonAddressable) {
|
||||
str = "<span class=\"greytext\">" + parts.Addr + "</span>";
|
||||
} else {
|
||||
str = parts.Addr;
|
||||
}
|
||||
str += ":";
|
||||
colPos = AddSpacedString(sb, colPos, mColStart[(int)Col.Address],
|
||||
str, str.Length);
|
||||
str, parts.Addr.Length + 1);
|
||||
}
|
||||
}
|
||||
if ((mLeftFlags & ActiveColumnFlags.Bytes) != 0) {
|
||||
|
@ -282,8 +282,8 @@ namespace SourceGen {
|
||||
int topOffset = dl[topIndex].FileOffset;
|
||||
int firstIndex = dl.FindLineIndexByOffset(topOffset);
|
||||
Debug.Assert(topIndex >= firstIndex);
|
||||
savedSel.mTopPosition =
|
||||
new NavStack.Location(topOffset, topIndex - firstIndex, false);
|
||||
savedSel.mTopPosition = new NavStack.Location(topOffset, topIndex - firstIndex,
|
||||
NavStack.GoToMode.JumpToAdjIndex);
|
||||
|
||||
List<Line> lineList = dl.mLineList;
|
||||
Debug.Assert(lineList.Count == sel.Length);
|
||||
@ -832,7 +832,7 @@ namespace SourceGen {
|
||||
// Blank lines and comments can appear before or after code/data. They
|
||||
// must have the offset of the associated line, and a span of zero.
|
||||
if (line.FileOffset != expectedOffset && line.FileOffset != lastOffset) {
|
||||
// .arend directives are associated with the last byte of a region, so
|
||||
// arend directives are associated with the last byte of a region, so
|
||||
// we need to make a special exemption for them.
|
||||
if (line.LineType == Line.Type.ArEndDirective &&
|
||||
line.FileOffset == expectedOffset - 1) {
|
||||
@ -1035,7 +1035,7 @@ namespace SourceGen {
|
||||
|
||||
// Insert long comments and notes. These may span multiple display lines,
|
||||
// and require word-wrap, so it's easiest just to render them fully here.
|
||||
// Set "spaceAdded" to true so .arstart doesn't try to add one after the comment.
|
||||
// Set "spaceAdded" to true so arstart doesn't try to add one after the comment.
|
||||
//
|
||||
// TODO: integrate into FormattedOperandCache so we don't have to
|
||||
// regenerate them unless they change. Use the MLC as the dependency.
|
||||
@ -1066,7 +1066,7 @@ namespace SourceGen {
|
||||
|
||||
AddressMap.AddressRegion region = change.Region;
|
||||
if (region.Offset == 0 && hasPrgHeader) {
|
||||
// Suppress the .arstart at offset zero. We know there's another one
|
||||
// Suppress the arstart at offset zero. We know there's another one
|
||||
// at offset +000002, and that it matches the value at +0/1.
|
||||
addrIter.MoveNext();
|
||||
continue;
|
||||
@ -1079,7 +1079,7 @@ namespace SourceGen {
|
||||
lines.Add(GenerateBlankLine(offset));
|
||||
}
|
||||
spaceAdded = false; // next one will need a blank line
|
||||
multiStart = true; // unless it's another .arstart immediately
|
||||
multiStart = true; // unless it's another arstart immediately
|
||||
|
||||
if (region.HasValidPreLabel) {
|
||||
Line preLine =
|
||||
@ -1109,16 +1109,19 @@ namespace SourceGen {
|
||||
} else {
|
||||
addrStr = mFormatter.FormatHexValue(region.Address, 4);
|
||||
}
|
||||
#if DEBUG
|
||||
#if DEBUG1
|
||||
string comment = mFormatter.FormatEolComment("ends at " +
|
||||
mFormatter.FormatOffset24(region.Offset + region.ActualLength - 1) +
|
||||
(region.IsFloating ? " (floating)" : string.Empty));
|
||||
#else
|
||||
string comment = string.Empty;
|
||||
#endif
|
||||
if (change.IsSynthetic) {
|
||||
comment += " (auto-generated)";
|
||||
}
|
||||
#else
|
||||
string comment = string.Empty;
|
||||
if (change.IsSynthetic) {
|
||||
comment = mFormatter.FormatEolComment("(auto-generated)");
|
||||
}
|
||||
#endif
|
||||
newLine.Parts = FormattedParts.CreateFullDirective(string.Empty,
|
||||
mFormatter.FormatPseudoOp(mPseudoOpNames.ArStartDirective),
|
||||
addrStr, comment);
|
||||
@ -1284,10 +1287,10 @@ namespace SourceGen {
|
||||
// Check for address region ends, which will be positioned one byte before the
|
||||
// updated offset (unless they somehow got embedded inside something else).
|
||||
//
|
||||
// The .arend can only appear on the same offset as .arstart in a single-byte
|
||||
// The arend can only appear on the same offset as arstart in a single-byte
|
||||
// region, and we can't have more than one of those at the same offset.
|
||||
// If this is not a single-byte region, we need to reset the sub-line count.
|
||||
// (Alternatively: track the offset of the last .arstart, and reset subline
|
||||
// (Alternatively: track the offset of the last arstart, and reset subline
|
||||
// if they differ.)
|
||||
if (addrIter.Current != null && addrIter.Current.Region.Length != 1) {
|
||||
arSubLine = 0;
|
||||
@ -1302,7 +1305,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
if (change.Region.Offset == 0 && hasPrgHeader) {
|
||||
// Suppress the .arend at offset +000001.
|
||||
// Suppress the arend at offset +000001.
|
||||
addrIter.MoveNext();
|
||||
arSubLine++; // need to track address map
|
||||
continue;
|
||||
@ -1330,7 +1333,7 @@ namespace SourceGen {
|
||||
|
||||
// Put a blank line before the next thing.
|
||||
// TODO(maybe): this gets lost in a partial update, e.g. you add a
|
||||
// long comment right after a .arend with no following .arstart and
|
||||
// long comment right after a arend with no following arstart and
|
||||
// then hit "undo", because the blank is logically part of the
|
||||
// following offset.
|
||||
addBlank = true;
|
||||
@ -1649,7 +1652,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
public AddressMap.AddressRegion GetAddrRegionFromLine(Line line, out bool isSynth) {
|
||||
// A given offset can have one or more .arstart lines and one or more .arend lines.
|
||||
// A given offset can have one or more arstart lines and one or more arend lines.
|
||||
// You can't have an end followed by a start, because that would mean the regions
|
||||
// overlap. If there's both start and end present, we have a 1-byte region.
|
||||
int offset = line.FileOffset;
|
||||
@ -1666,14 +1669,14 @@ namespace SourceGen {
|
||||
while (addrIter.Current != null && addrIter.Current.Offset == offset) {
|
||||
AddressMap.AddressChange change = addrIter.Current;
|
||||
if (count == 0) {
|
||||
// Could be pre-label or .arstart that follows it. Both go to the same place.
|
||||
// Could be pre-label or arstart that follows it. Both go to the same place.
|
||||
isSynth = change.IsSynthetic;
|
||||
return change.Region;
|
||||
}
|
||||
if (change.IsStart && change.Region.HasValidPreLabel) {
|
||||
count--;
|
||||
if (count == 0) {
|
||||
// This is the .arstart following the pre-label.
|
||||
// This is the arstart following the pre-label.
|
||||
isSynth = change.IsSynthetic;
|
||||
return change.Region;
|
||||
}
|
||||
|
@ -1664,7 +1664,8 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
if (line.IsAddressRangeDirective) {
|
||||
// TODO(someday): make this jump to the actual directive rather than nearby code
|
||||
// TODO(someday): make this jump to the specific directive rather than the first
|
||||
// (should be able to do it with LineDelta)
|
||||
AddressMap.AddressRegion region = CodeLineList.GetAddrRegionFromLine(line,
|
||||
out bool unused);
|
||||
if (region == null) {
|
||||
@ -1674,13 +1675,12 @@ namespace SourceGen {
|
||||
if (!testOnly) {
|
||||
if (line.LineType == LineListGen.Line.Type.ArStartDirective) {
|
||||
// jump to end
|
||||
GoToLocation(
|
||||
new NavStack.Location(region.Offset + region.ActualLength - 1, 0, true),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(region.Offset + region.ActualLength - 1,
|
||||
0, NavStack.GoToMode.JumpToArEnd), true);
|
||||
} else {
|
||||
// jump to start
|
||||
GoToLocation(new NavStack.Location(region.Offset, 0, true),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(region.Offset,
|
||||
0, NavStack.GoToMode.JumpToArStart), true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -1706,9 +1706,11 @@ namespace SourceGen {
|
||||
int labelOffset = mProject.FindLabelOffsetByName(dfd.SymbolRef.Label);
|
||||
if (labelOffset >= 0) {
|
||||
if (!testOnly) {
|
||||
// TODO(org): jump to .arstart
|
||||
GoToLocation(new NavStack.Location(labelOffset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
NavStack.GoToMode mode = NavStack.GoToMode.JumpToCodeData;
|
||||
if (sym.SymbolSource == Symbol.Source.AddrPreLabel) {
|
||||
mode = NavStack.GoToMode.JumpToArStart;
|
||||
}
|
||||
GoToLocation(new NavStack.Location(labelOffset, 0, mode), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1719,8 +1721,8 @@ namespace SourceGen {
|
||||
if (mProject.ActiveDefSymbolList[i] == sym) {
|
||||
int offset = LineListGen.DefSymOffsetFromIndex(i);
|
||||
if (!testOnly) {
|
||||
GoToLocation(new NavStack.Location(offset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(offset, 0,
|
||||
NavStack.GoToMode.JumpToCodeData), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1737,8 +1739,8 @@ namespace SourceGen {
|
||||
// Operand has an in-file target offset. We can resolve it as a numeric reference.
|
||||
// Find the line for that offset and jump to it.
|
||||
if (!testOnly) {
|
||||
GoToLocation(new NavStack.Location(attr.OperandOffset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(attr.OperandOffset, 0,
|
||||
NavStack.GoToMode.JumpToCodeData), true);
|
||||
}
|
||||
return true;
|
||||
} else if (attr.IsDataStart || attr.IsInlineDataStart) {
|
||||
@ -1748,8 +1750,8 @@ namespace SourceGen {
|
||||
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset);
|
||||
if (operandOffset >= 0) {
|
||||
if (!testOnly) {
|
||||
GoToLocation(new NavStack.Location(operandOffset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(operandOffset, 0,
|
||||
NavStack.GoToMode.JumpToCodeData), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1809,15 +1811,15 @@ namespace SourceGen {
|
||||
|
||||
int lastIndex = mMainWin.CodeListView_GetLastSelectedIndex();
|
||||
|
||||
// Can only start with .arend if it's single-selection.
|
||||
// Can only start with arend if it's single-selection.
|
||||
if (selIndex != lastIndex && selLine.LineType == LineListGen.Line.Type.ArEndDirective) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If multiple lines with code/data are selected, there must not be a .arstart
|
||||
// If multiple lines with code/data are selected, there must not be an arstart
|
||||
// between them unless we're resizing a region. Determining whether or not a resize
|
||||
// is valid is left to the edit dialog. It's okay for a .arend to be in the middle
|
||||
// so long as the corresponding .arstart is at the current offset.
|
||||
// is valid is left to the edit dialog. It's okay for an arend to be in the middle
|
||||
// so long as the corresponding arstart is at the current offset.
|
||||
if (selLine.LineType == LineListGen.Line.Type.ArStartDirective) {
|
||||
// Skip overlapping region check.
|
||||
return true;
|
||||
@ -1856,7 +1858,7 @@ namespace SourceGen {
|
||||
int nextOffset = lastOffset + CodeLineList[lastIndex].OffsetSpan;
|
||||
AddressMap addrMap = mProject.AddrMap;
|
||||
|
||||
// The offset of a .arend directive is the last byte in the address region. It
|
||||
// The offset of an arend directive is the last byte in the address region. It
|
||||
// has a span length of zero because it's a directive, so if it's selected as
|
||||
// the last offset then our nextOffset calculation will be off by one. (This would
|
||||
// be avoided by using an exclusive end offset, but that causes other problems.)
|
||||
@ -1865,13 +1867,13 @@ namespace SourceGen {
|
||||
nextOffset++;
|
||||
}
|
||||
|
||||
// Compute length of selection. May be zero if it's entirely .arstart/.arend.
|
||||
// Compute length of selection. May be zero if it's entirely arstart/arend.
|
||||
int selectedLen = nextOffset - firstOffset;
|
||||
|
||||
AddressMap.AddressRegion curRegion;
|
||||
if (CodeLineList[selIndex].LineType == LineListGen.Line.Type.ArStartDirective ||
|
||||
CodeLineList[selIndex].LineType == LineListGen.Line.Type.ArEndDirective) {
|
||||
// First selected line was .arstart/.arend, find the address map entry.
|
||||
// First selected line was arstart/arend, find the address map entry.
|
||||
curRegion = CodeLineList.GetAddrRegionFromLine(CodeLineList[selIndex],
|
||||
out bool isSynth);
|
||||
Debug.Assert(curRegion != null);
|
||||
@ -1888,7 +1890,7 @@ namespace SourceGen {
|
||||
} else {
|
||||
if (selectedLen == 0) {
|
||||
// A length of zero is only possible if nothing but directives were selected,
|
||||
// but since the first entry wasn't .arstart/.arend this can't happen.
|
||||
// but since the first entry wasn't arstart/arend this can't happen.
|
||||
Debug.Assert(false);
|
||||
return;
|
||||
}
|
||||
@ -2820,20 +2822,20 @@ namespace SourceGen {
|
||||
|
||||
GotoBox dlg = new GotoBox(mMainWin, mProject, offset, mFormatter);
|
||||
if (dlg.ShowDialog() == true) {
|
||||
GoToLocation(new NavStack.Location(dlg.TargetOffset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(dlg.TargetOffset, 0,
|
||||
NavStack.GoToMode.JumpToCodeData), true);
|
||||
//mMainWin.CodeListView_Focus();
|
||||
}
|
||||
}
|
||||
|
||||
public enum GoToMode { Unknown = 0, JumpToCodeData, JumpToNote, JumpToAdjIndex };
|
||||
/// <summary>
|
||||
/// Moves the view and selection to the specified offset. We want to select stuff
|
||||
/// differently if we're jumping to a note vs. jumping to an instruction.
|
||||
/// </summary>
|
||||
/// <param name="gotoOffset">Offset to jump to.</param>
|
||||
/// <param name="newLoc">Location to jump to.</param>
|
||||
/// <param name="mode">Interesting set of lines within that offset.</param>
|
||||
/// <param name="doPush">If set, push new offset onto navigation stack.</param>
|
||||
public void GoToLocation(NavStack.Location loc, GoToMode mode, bool doPush) {
|
||||
public void GoToLocation(NavStack.Location newLoc, bool doPush) {
|
||||
NavStack.Location prevLoc = GetCurrentlySelectedLocation();
|
||||
//Debug.WriteLine("GoToLocation: " + loc + " mode=" + mode + " doPush=" + doPush +
|
||||
// " (curLoc=" + prevLoc + ")");
|
||||
@ -2844,8 +2846,7 @@ namespace SourceGen {
|
||||
// entry in the symbol table for the current offset, we want to move the selection,
|
||||
// so we don't want to bail out if the offset matches. Easiest thing to do is to
|
||||
// do the move but not push it.
|
||||
bool jumpToNote = (mode == GoToMode.JumpToNote);
|
||||
if (loc.Offset == prevLoc.Offset && jumpToNote == prevLoc.IsNote) {
|
||||
if (newLoc.Offset == prevLoc.Offset && newLoc.Mode == prevLoc.Mode) {
|
||||
// we're jumping to ourselves?
|
||||
if (doPush) {
|
||||
Debug.WriteLine("Ignoring push for goto to current offset");
|
||||
@ -2853,27 +2854,30 @@ namespace SourceGen {
|
||||
}
|
||||
}
|
||||
|
||||
int topLineIndex = CodeLineList.FindLineIndexByOffset(loc.Offset);
|
||||
int topLineIndex = CodeLineList.FindLineIndexByOffset(newLoc.Offset);
|
||||
if (topLineIndex < 0) {
|
||||
Debug.Assert(false, "failed goto offset +" + loc.Offset.ToString("x6"));
|
||||
Debug.Assert(false, "failed goto offset +" + newLoc.Offset.ToString("x6"));
|
||||
return;
|
||||
}
|
||||
int lastLineIndex;
|
||||
if (mode == GoToMode.JumpToNote) {
|
||||
if (newLoc.Mode == NavStack.GoToMode.JumpToNote) {
|
||||
// Select all note lines, disregard the rest.
|
||||
while (CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Note) {
|
||||
if (CodeLineList[topLineIndex].FileOffset != newLoc.Offset) {
|
||||
// This can happen if the note got deleted.
|
||||
break;
|
||||
}
|
||||
topLineIndex++;
|
||||
Debug.Assert(CodeLineList[topLineIndex].FileOffset == loc.Offset);
|
||||
}
|
||||
lastLineIndex = topLineIndex + 1;
|
||||
while (lastLineIndex < CodeLineList.Count &&
|
||||
CodeLineList[lastLineIndex].LineType == LineListGen.Line.Type.Note) {
|
||||
lastLineIndex++;
|
||||
}
|
||||
} else if (loc.Offset < 0) {
|
||||
} else if (newLoc.Offset < 0) {
|
||||
// This is the offset of the header comment or a .EQ directive. Don't mess with it.
|
||||
lastLineIndex = topLineIndex + 1;
|
||||
} else if (mode == GoToMode.JumpToCodeData) {
|
||||
} else if (newLoc.Mode == NavStack.GoToMode.JumpToCodeData) {
|
||||
// Advance to the code or data line.
|
||||
while (CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Code &&
|
||||
CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Data) {
|
||||
@ -2881,14 +2885,35 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
lastLineIndex = topLineIndex + 1;
|
||||
} else if (mode == GoToMode.JumpToAdjIndex) {
|
||||
} else if (newLoc.Mode == NavStack.GoToMode.JumpToAdjIndex) {
|
||||
// Adjust the line position by the line delta. If the adjustment moves us to
|
||||
// a different element, ignore the adjustment.
|
||||
if (CodeLineList[topLineIndex].FileOffset ==
|
||||
CodeLineList[topLineIndex + loc.LineDelta].FileOffset) {
|
||||
topLineIndex += loc.LineDelta;
|
||||
CodeLineList[topLineIndex + newLoc.LineDelta].FileOffset) {
|
||||
topLineIndex += newLoc.LineDelta;
|
||||
}
|
||||
lastLineIndex = topLineIndex + 1;
|
||||
} else if (newLoc.Mode == NavStack.GoToMode.JumpToArStart ||
|
||||
newLoc.Mode == NavStack.GoToMode.JumpToArEnd) {
|
||||
LineListGen.Line.Type matchType = LineListGen.Line.Type.ArStartDirective;
|
||||
if (newLoc.Mode != NavStack.GoToMode.JumpToArStart) {
|
||||
matchType = LineListGen.Line.Type.ArEndDirective;
|
||||
}
|
||||
// Find first instance of specified type.
|
||||
LineListGen.Line tmpLine = CodeLineList[topLineIndex];
|
||||
while (CodeLineList[topLineIndex].LineType != matchType) {
|
||||
if (CodeLineList[topLineIndex].FileOffset > newLoc.Offset) {
|
||||
// This can happen if the region got deleted.
|
||||
break;
|
||||
}
|
||||
topLineIndex++;
|
||||
}
|
||||
lastLineIndex = topLineIndex + 1;
|
||||
// If there's multiple lines, make sure they're all on screen.
|
||||
while (lastLineIndex < CodeLineList.Count &&
|
||||
CodeLineList[lastLineIndex].LineType == matchType) {
|
||||
lastLineIndex++;
|
||||
}
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
lastLineIndex = topLineIndex + 1;
|
||||
@ -3029,7 +3054,8 @@ namespace SourceGen {
|
||||
int offset = CodeLineList[index].FileOffset;
|
||||
int lineDelta = index - CodeLineList.FindLineIndexByOffset(offset);
|
||||
bool isNote = (CodeLineList[index].LineType == LineListGen.Line.Type.Note);
|
||||
return new NavStack.Location(offset, lineDelta, isNote);
|
||||
return new NavStack.Location(offset, lineDelta,
|
||||
isNote ? NavStack.GoToMode.JumpToNote : NavStack.GoToMode.JumpToAdjIndex);
|
||||
}
|
||||
|
||||
public void GotoLastChange() {
|
||||
@ -3076,11 +3102,11 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
if (isNote) {
|
||||
GoToLocation(new NavStack.Location(offset, 0, true),
|
||||
GoToMode.JumpToNote, true);
|
||||
GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToNote),
|
||||
true);
|
||||
} else {
|
||||
GoToLocation(new NavStack.Location(offset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToCodeData),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3090,8 +3116,7 @@ namespace SourceGen {
|
||||
public void NavigateBackward() {
|
||||
Debug.Assert(mNavStack.HasBackward);
|
||||
NavStack.Location backLoc = mNavStack.MoveBackward(GetCurrentlySelectedLocation());
|
||||
GoToLocation(backLoc,
|
||||
backLoc.IsNote ? GoToMode.JumpToNote : GoToMode.JumpToAdjIndex, false);
|
||||
GoToLocation(backLoc, false);
|
||||
}
|
||||
|
||||
public bool CanNavigateForward() {
|
||||
@ -3100,8 +3125,7 @@ namespace SourceGen {
|
||||
public void NavigateForward() {
|
||||
Debug.Assert(mNavStack.HasForward);
|
||||
NavStack.Location fwdLoc = mNavStack.MoveForward(GetCurrentlySelectedLocation());
|
||||
GoToLocation(fwdLoc,
|
||||
fwdLoc.IsNote ? GoToMode.JumpToNote : GoToMode.JumpToAdjIndex, false);
|
||||
GoToLocation(fwdLoc, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -3111,8 +3135,9 @@ namespace SourceGen {
|
||||
public void GoToLabel(Symbol sym) {
|
||||
int offset = mProject.FindLabelOffsetByName(sym.Label);
|
||||
if (offset >= 0) {
|
||||
GoToLocation(new NavStack.Location(offset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
// TODO(someday): jump to correct line for address region pre-labels
|
||||
GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToCodeData),
|
||||
true);
|
||||
} else {
|
||||
Debug.WriteLine("DClick symbol: " + sym + ": label not found");
|
||||
}
|
||||
@ -4045,14 +4070,23 @@ namespace SourceGen {
|
||||
esb.Append(" (floating)");
|
||||
}
|
||||
esb.Append(CRLF);
|
||||
esb.Append("Pre-label: ");
|
||||
if (!string.IsNullOrEmpty(region.PreLabel)) {
|
||||
esb.Append("'");
|
||||
esb.Append(region.PreLabel);
|
||||
if (region.PreLabelAddress == Address.NON_ADDR) {
|
||||
esb.Append("' (non-addressable)");
|
||||
} else {
|
||||
esb.Append("' addr=$");
|
||||
esb.Append(mFormatter.FormatAddress(region.PreLabelAddress,
|
||||
!mProject.CpuDef.HasAddr16));
|
||||
}
|
||||
} else {
|
||||
esb.Append("none");
|
||||
}
|
||||
esb.Append(CRLF);
|
||||
esb.Append("Synthetic: " + isSynth);
|
||||
esb.Append(CRLF);
|
||||
if (!string.IsNullOrEmpty(region.PreLabel)) {
|
||||
esb.Append("Pre-label: '" + region.PreLabel + "' addr=$");
|
||||
esb.Append(mFormatter.FormatAddress(region.PreLabelAddress,
|
||||
!mProject.CpuDef.HasAddr16));
|
||||
esb.Append(CRLF);
|
||||
}
|
||||
esb.Append("Relative: " + region.IsRelative);
|
||||
esb.Append(CRLF);
|
||||
mMainWin.InfoPanelDetail1 = esb.ToString();
|
||||
|
@ -38,6 +38,15 @@ namespace SourceGen {
|
||||
// TODO(someday): change the back button to a pop-up list of locations (like the way
|
||||
// VS 2017 does it).
|
||||
|
||||
public enum GoToMode {
|
||||
Unknown = 0,
|
||||
JumpToCodeData, // destination is first byte of code or data at target offset
|
||||
JumpToNote, // destination is Note at target offset
|
||||
JumpToAdjIndex, // destination is first line at target offset plus LineDelta
|
||||
JumpToArStart, // destination is arstart at target offset.
|
||||
JumpToArEnd, // destination is arend at target offset
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Holds enough information to get us back where we were, in style.
|
||||
/// </summary>
|
||||
@ -49,7 +58,7 @@ namespace SourceGen {
|
||||
|
||||
/// <summary>
|
||||
/// Number of lines between the first line at the specified offset, and the
|
||||
/// line we actually want to land on.
|
||||
/// line we actually want to land on. Used when Mode=JumpToAdjIndex.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It's possible this line no longer exists. Easiest test is to compare the
|
||||
@ -59,21 +68,22 @@ namespace SourceGen {
|
||||
public int LineDelta { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the target is the note at the given offset, rather than the code/data.
|
||||
/// Specifies interesting things to find at the target offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is an alternative to LineDelta.
|
||||
/// </remarks>
|
||||
public bool IsNote { get; set; }
|
||||
public GoToMode Mode { get; set; }
|
||||
|
||||
public Location(int offset, int lineDelta, bool isNote) {
|
||||
public Location(int offset, int lineDelta, GoToMode mode) {
|
||||
Offset = offset;
|
||||
LineDelta = lineDelta;
|
||||
IsNote = isNote;
|
||||
Mode = mode;
|
||||
|
||||
//if (lineDelta != 0 && mode != GoToMode.JumpToAdjIndex) {
|
||||
// Debug.WriteLine("HEY: lineDelta=" + lineDelta + " mode=" + mode);
|
||||
//}
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("[+{0:x6},{1},{2}]", Offset, LineDelta, IsNote);
|
||||
return string.Format("[+{0:x6},{1},{2}]", Offset, LineDelta, Mode);
|
||||
}
|
||||
|
||||
public static bool operator ==(Location a, Location b) {
|
||||
@ -83,7 +93,7 @@ namespace SourceGen {
|
||||
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) {
|
||||
return false; // one is null
|
||||
}
|
||||
return a.Offset == b.Offset && a.LineDelta == b.LineDelta && a.IsNote == b.IsNote;
|
||||
return a.Offset == b.Offset && a.LineDelta == b.LineDelta && a.Mode == b.Mode;
|
||||
}
|
||||
public static bool operator !=(Location a, Location b) {
|
||||
return !(a == b);
|
||||
@ -92,7 +102,7 @@ namespace SourceGen {
|
||||
return obj is Location && this == (Location)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return Offset + (LineDelta * 1000000) + (IsNote ? (1<<24) : 0);
|
||||
return Offset + (LineDelta * 1000000) + ((int)Mode << 24);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,8 +228,8 @@ namespace SourceGen {
|
||||
new PseudoOpNames(new Dictionary<string, string> {
|
||||
{ "EquDirective", ".eq" },
|
||||
{ "VarDirective", ".var" },
|
||||
{ "ArStartDirective", ".arstart" },
|
||||
{ "ArEndDirective", ".arend" },
|
||||
{ "ArStartDirective", ".addrs" },
|
||||
{ "ArEndDirective", ".adrend" },
|
||||
{ "RegWidthDirective", ".rwid" },
|
||||
{ "DataBankDirective", ".dbank" },
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace SourceGen {
|
||||
int prevAddr = 0;
|
||||
int lastEndOffset = -1;
|
||||
|
||||
sb.AppendLine("Address region map for " + project.DataFileName);
|
||||
sb.AppendLine("Address region map for \"" + project.DataFileName + "\"");
|
||||
sb.Append(CRLF);
|
||||
|
||||
IEnumerator<AddressChange> iter = addrMap.AddressChangeIterator;
|
||||
@ -67,12 +67,6 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
// Start following end, or start following start after a gap.
|
||||
if (!string.IsNullOrEmpty(change.Region.PreLabel)) {
|
||||
PrintDepthLines(sb, depth, true);
|
||||
sb.Append("| pre='" + change.Region.PreLabel + "' ");
|
||||
PrintAddress(sb, formatter, change.Region.PreLabelAddress, showBank);
|
||||
sb.Append(CRLF);
|
||||
}
|
||||
sb.Append(formatter.FormatOffset24(change.Offset));
|
||||
PrintDepthLines(sb, depth, false);
|
||||
sb.Append("+- " + "start");
|
||||
@ -83,10 +77,16 @@ namespace SourceGen {
|
||||
// If there's a label here, show it.
|
||||
Anattrib attr = project.GetAnattrib(change.Offset);
|
||||
if (attr.Symbol != null && !string.IsNullOrEmpty(attr.Symbol.Label)) {
|
||||
sb.Append(" : ");
|
||||
sb.Append(attr.Symbol.Label);
|
||||
sb.Append(" '");
|
||||
sb.Append(attr.Symbol.GenerateDisplayLabel(formatter));
|
||||
sb.Append("'");
|
||||
}
|
||||
}
|
||||
if (change.Region.HasValidPreLabel) {
|
||||
sb.Append(" pre='");
|
||||
sb.Append(change.Region.PreLabel);
|
||||
sb.Append("'");
|
||||
}
|
||||
|
||||
sb.Append(CRLF);
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
/*
|
||||
* 6502bench SourceGen disassembly output style.
|
||||
*/
|
||||
|
||||
/*
|
||||
* General formatting.
|
||||
*/
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 14px; /* 16 recommended for mobile */
|
||||
@ -11,6 +15,9 @@ table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.greytext {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Blue underlined text is distracting. Change internal links to be
|
||||
|
@ -52,7 +52,8 @@ OverVar @ $40 4
|
||||
BankWrap @ $fff0 $20
|
||||
|
||||
; Width specifiers on constants should be ignored.
|
||||
FatConst = $4000 8
|
||||
; Uses a leading '_' to test special 64tass handling.
|
||||
_FatConst = $4000 8
|
||||
|
||||
; Overlapping multi-byte items with exact and inexact matches.
|
||||
OverA_0 @ $6000 8 ;should win, alphabetically
|
||||
|
@ -27,7 +27,7 @@
|
||||
"OperandFormats":{
|
||||
"207":{
|
||||
"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
|
||||
"Label":"FatConst","Part":"Low"}}},
|
||||
"Label":"_FatConst","Part":"Low"}}},
|
||||
"LvTables":{
|
||||
"192":{
|
||||
"Variables":[{
|
||||
|
BIN
SourceGen/SGTestData/20260-pre-labels
Normal file
BIN
SourceGen/SGTestData/20260-pre-labels
Normal file
Binary file not shown.
219
SourceGen/SGTestData/20260-pre-labels.dis65
Normal file
219
SourceGen/SGTestData/20260-pre-labels.dis65
Normal file
@ -0,0 +1,219 @@
|
||||
### 6502bench SourceGen dis65 v1.0 ###
|
||||
{
|
||||
"_ContentVersion":5,
|
||||
"FileDataLength":95,
|
||||
"FileDataCrc32":482033261,
|
||||
"ProjectProps":{
|
||||
"CpuName":"6502",
|
||||
"IncludeUndocumentedInstr":false,
|
||||
"TwoByteBrk":false,
|
||||
"EntryFlags":32702671,
|
||||
"AutoLabelStyle":"Simple",
|
||||
"AnalysisParams":{
|
||||
"AnalyzeUncategorizedData":true,
|
||||
"DefaultTextScanMode":"LowHighAscii",
|
||||
"MinCharsForString":4,
|
||||
"SeekNearbyTargets":false,
|
||||
"UseRelocData":false,
|
||||
"SmartPlpHandling":false,
|
||||
"SmartPlbHandling":true},
|
||||
|
||||
"PlatformSymbolFileIdentifiers":[],
|
||||
"ExtensionScriptFileIdentifiers":[],
|
||||
"ProjectSyms":{
|
||||
"part2":{
|
||||
"DataDescriptor":{
|
||||
"Length":1,
|
||||
"Format":"NumericLE",
|
||||
"SubFormat":"Hex",
|
||||
"SymbolRef":null},
|
||||
|
||||
"Comment":"precedence test",
|
||||
"HasWidth":false,
|
||||
"Direction":"ReadWrite",
|
||||
"MultiMask":null,
|
||||
"Label":"part2",
|
||||
"Value":4155,
|
||||
"Source":"Project",
|
||||
"Type":"ExternalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"zzz":{
|
||||
"DataDescriptor":{
|
||||
"Length":1,
|
||||
"Format":"NumericLE",
|
||||
"SubFormat":"Hex",
|
||||
"SymbolRef":null},
|
||||
|
||||
"Comment":"",
|
||||
"HasWidth":false,
|
||||
"Direction":"ReadWrite",
|
||||
"MultiMask":null,
|
||||
"Label":"zzz",
|
||||
"Value":4155,
|
||||
"Source":"Project",
|
||||
"Type":"ExternalAddr",
|
||||
"LabelAnno":"None"}}},
|
||||
|
||||
"AddressMap":[{
|
||||
"Offset":0,
|
||||
"Addr":-1025,
|
||||
"Length":2,
|
||||
"PreLabel":"",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":2,
|
||||
"Addr":4096,
|
||||
"Length":-1024,
|
||||
"PreLabel":"b4_begin",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":11,
|
||||
"Addr":8192,
|
||||
"Length":48,
|
||||
"PreLabel":"b4_part2",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":35,
|
||||
"Addr":12288,
|
||||
"Length":-1024,
|
||||
"PreLabel":"b4_part3",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":59,
|
||||
"Addr":16384,
|
||||
"Length":31,
|
||||
"PreLabel":"b4_part4b",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":59,
|
||||
"Addr":20480,
|
||||
"Length":21,
|
||||
"PreLabel":"b4_part4a",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":59,
|
||||
"Addr":24576,
|
||||
"Length":12,
|
||||
"PreLabel":"_b4_part4",
|
||||
"IsRelative":false},
|
||||
|
||||
{
|
||||
"Offset":90,
|
||||
"Addr":61440,
|
||||
"Length":3,
|
||||
"PreLabel":"",
|
||||
"IsRelative":false}],
|
||||
"TypeHints":[{
|
||||
"Low":2,
|
||||
"High":2,
|
||||
"Hint":"Code"}],
|
||||
"StatusFlagOverrides":{
|
||||
},
|
||||
|
||||
"Comments":{
|
||||
},
|
||||
|
||||
"LongComments":{
|
||||
},
|
||||
|
||||
"Notes":{
|
||||
},
|
||||
|
||||
"UserLabels":{
|
||||
"2":{
|
||||
"Label":"begin",
|
||||
"Value":4096,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"11":{
|
||||
"Label":"part2",
|
||||
"Value":8192,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"33":{
|
||||
"Label":"local1",
|
||||
"Value":8214,
|
||||
"Source":"User",
|
||||
"Type":"NonUniqueLocalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"34":{
|
||||
"Label":"local2",
|
||||
"Value":8215,
|
||||
"Source":"User",
|
||||
"Type":"NonUniqueLocalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"57":{
|
||||
"Label":"local3",
|
||||
"Value":12310,
|
||||
"Source":"User",
|
||||
"Type":"NonUniqueLocalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"58":{
|
||||
"Label":"local4",
|
||||
"Value":12311,
|
||||
"Source":"User",
|
||||
"Type":"NonUniqueLocalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"35":{
|
||||
"Label":"part3",
|
||||
"Value":12288,
|
||||
"Source":"User",
|
||||
"Type":"NonUniqueLocalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"81":{
|
||||
"Label":"part4b",
|
||||
"Value":16406,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"71":{
|
||||
"Label":"part4a",
|
||||
"Value":20492,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"59":{
|
||||
"Label":"part4",
|
||||
"Value":24576,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"}},
|
||||
|
||||
"OperandFormats":{
|
||||
"0":{
|
||||
"Length":2,
|
||||
"Format":"NumericLE",
|
||||
"SubFormat":"None",
|
||||
"SymbolRef":null}},
|
||||
|
||||
"LvTables":{
|
||||
},
|
||||
|
||||
"Visualizations":[],
|
||||
"VisualizationAnimations":[],
|
||||
"VisualizationSets":{
|
||||
},
|
||||
|
||||
"RelocList":{
|
||||
},
|
||||
|
||||
"DbrValues":{
|
||||
}}
|
@ -1,5 +1,5 @@
|
||||
.cpu "6502"
|
||||
FatConst = $4000
|
||||
X_FatConst = $4000
|
||||
|
||||
OverVar = $40
|
||||
CodeWrap = $0f00 ;encases program
|
||||
@ -116,7 +116,7 @@ LocalVar .var $41
|
||||
ldx OverVar+3
|
||||
ldx $44
|
||||
nop
|
||||
lda FatConst-1
|
||||
lda X_FatConst-1
|
||||
lda $4000
|
||||
lda $4001
|
||||
lda BankWrap+8
|
||||
|
@ -1,5 +1,5 @@
|
||||
!cpu 6502
|
||||
FatConst = $4000
|
||||
_FatConst = $4000
|
||||
|
||||
OverVar = $40
|
||||
CodeWrap = $0f00 ;encases program
|
||||
@ -117,7 +117,7 @@ L1000 lda CodeWrap+255
|
||||
ldx OverVar+3
|
||||
ldx $44
|
||||
nop
|
||||
lda FatConst-1
|
||||
lda _FatConst-1
|
||||
lda $4000
|
||||
lda $4001
|
||||
lda BankWrap+8
|
||||
|
@ -1,5 +1,5 @@
|
||||
.setcpu "6502"
|
||||
FatConst = $4000
|
||||
_FatConst = $4000
|
||||
|
||||
OverVar = $40
|
||||
CodeWrap = $0f00 ;encases program
|
||||
@ -116,7 +116,7 @@ LocalVar .set $41
|
||||
ldx OverVar+3
|
||||
ldx $44
|
||||
nop
|
||||
lda FatConst-1
|
||||
lda _FatConst-1
|
||||
lda $4000
|
||||
lda $4001
|
||||
lda BankWrap+8
|
||||
|
@ -1,4 +1,4 @@
|
||||
FatConst equ $4000
|
||||
_FatConst equ $4000
|
||||
|
||||
OverVar equ $40
|
||||
CodeWrap equ $0f00 ;encases program
|
||||
@ -115,7 +115,7 @@ L1000 lda CodeWrap+255
|
||||
ldx OverVar+3
|
||||
ldx $44
|
||||
nop
|
||||
lda FatConst-1
|
||||
lda _FatConst-1
|
||||
lda $4000
|
||||
lda $4001
|
||||
lda BankWrap+8
|
||||
|
76
SourceGen/SGTestData/Expected/20260-pre-labels_64tass.S
Normal file
76
SourceGen/SGTestData/Expected/20260-pre-labels_64tass.S
Normal file
@ -0,0 +1,76 @@
|
||||
.cpu "6502"
|
||||
zzz = $103b
|
||||
|
||||
|
||||
* = $1000
|
||||
begin bit begin
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part2
|
||||
|
||||
.logical $2000
|
||||
part2 bit part2
|
||||
nop
|
||||
lda _local1
|
||||
lda local2
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit b4_part3
|
||||
jmp part3
|
||||
|
||||
_local1 .byte $81
|
||||
local2 .byte $82
|
||||
|
||||
b4_part3
|
||||
.logical $3000
|
||||
part3 bit part3
|
||||
nop
|
||||
lda local2
|
||||
lda _local3
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit X_b4_part4
|
||||
jmp part4
|
||||
|
||||
_local3 .byte $83
|
||||
local4 .byte $84
|
||||
.here
|
||||
.here
|
||||
|
||||
.logical $4000
|
||||
b4_part4a
|
||||
.logical $5000
|
||||
X_b4_part4
|
||||
.logical $6000
|
||||
part4 bit part4
|
||||
bit X_b4_part4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part4a
|
||||
|
||||
.here
|
||||
part4a bit part4a
|
||||
bit b4_part4a
|
||||
jsr part4b
|
||||
.here
|
||||
.byte $00
|
||||
|
||||
part4b bit part4b
|
||||
bit zzz
|
||||
jmp _LF000
|
||||
|
||||
.here
|
||||
.logical $f000
|
||||
_LF000 nop
|
||||
bne $f003
|
||||
.here
|
||||
.logical $0000
|
||||
.byte $ea
|
||||
.byte $00
|
||||
.here
|
79
SourceGen/SGTestData/Expected/20260-pre-labels_acme.S
Normal file
79
SourceGen/SGTestData/Expected/20260-pre-labels_acme.S
Normal file
@ -0,0 +1,79 @@
|
||||
!cpu 6502
|
||||
zzz = $103b
|
||||
|
||||
* = $0000
|
||||
!word $1000
|
||||
|
||||
!pseudopc $1000 {
|
||||
begin bit begin
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part2
|
||||
|
||||
}
|
||||
!pseudopc $2000 {
|
||||
part2 bit part2
|
||||
nop
|
||||
lda @local1
|
||||
lda local2
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit b4_part3
|
||||
jmp part3
|
||||
|
||||
@local1 !byte $81
|
||||
local2 !byte $82
|
||||
|
||||
b4_part3
|
||||
!pseudopc $3000 {
|
||||
part3 bit part3
|
||||
nop
|
||||
lda local2
|
||||
lda @local3
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit _b4_part4
|
||||
jmp part4
|
||||
|
||||
@local3 !byte $83
|
||||
local4 !byte $84
|
||||
}
|
||||
}
|
||||
|
||||
!pseudopc $4000 {
|
||||
b4_part4a
|
||||
!pseudopc $5000 {
|
||||
_b4_part4
|
||||
!pseudopc $6000 {
|
||||
part4 bit part4
|
||||
bit _b4_part4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part4a
|
||||
|
||||
}
|
||||
part4a bit part4a
|
||||
bit b4_part4a
|
||||
jsr part4b
|
||||
}
|
||||
!byte $00
|
||||
|
||||
part4b bit part4b
|
||||
bit zzz
|
||||
jmp @LF000
|
||||
|
||||
}
|
||||
!pseudopc $f000 {
|
||||
@LF000 nop
|
||||
bne $f003
|
||||
}
|
||||
!pseudopc $0000 {
|
||||
!byte $ea
|
||||
!byte $00
|
||||
}
|
73
SourceGen/SGTestData/Expected/20260-pre-labels_cc65.S
Normal file
73
SourceGen/SGTestData/Expected/20260-pre-labels_cc65.S
Normal file
@ -0,0 +1,73 @@
|
||||
.setcpu "6502"
|
||||
zzz = $103b
|
||||
|
||||
.org $0000
|
||||
.word $1000
|
||||
|
||||
.org $1000
|
||||
begin: bit begin
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part2
|
||||
|
||||
.org $2000
|
||||
part2: bit part2
|
||||
nop
|
||||
lda @local1
|
||||
lda local2
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit b4_part3
|
||||
jmp part3
|
||||
|
||||
@local1: .byte $81
|
||||
local2: .byte $82
|
||||
|
||||
b4_part3:
|
||||
.org $3000
|
||||
part3: bit part3
|
||||
nop
|
||||
lda local2
|
||||
lda @local3
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit _b4_part4
|
||||
jmp part4
|
||||
|
||||
@local3: .byte $83
|
||||
local4: .byte $84
|
||||
|
||||
.org $4000
|
||||
b4_part4a:
|
||||
.org $5000
|
||||
_b4_part4:
|
||||
.org $6000
|
||||
part4: bit part4
|
||||
bit _b4_part4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part4a
|
||||
|
||||
.org $500c
|
||||
part4a: bit part4a
|
||||
bit b4_part4a
|
||||
jsr part4b
|
||||
.org $4015
|
||||
.byte $00
|
||||
|
||||
part4b: bit part4b
|
||||
bit zzz
|
||||
jmp @LF000
|
||||
|
||||
.org $f000
|
||||
@LF000: nop
|
||||
bne $f003
|
||||
.org $0000
|
||||
.byte $ea
|
||||
.byte $00
|
9
SourceGen/SGTestData/Expected/20260-pre-labels_cc65.cfg
Normal file
9
SourceGen/SGTestData/Expected/20260-pre-labels_cc65.cfg
Normal file
@ -0,0 +1,9 @@
|
||||
# 6502bench SourceGen generated linker script for 20260-pre-labels
|
||||
MEMORY {
|
||||
MAIN: file=%O, start=%S, size=65536;
|
||||
}
|
||||
SEGMENTS {
|
||||
CODE: load=MAIN, type=rw;
|
||||
}
|
||||
FEATURES {}
|
||||
SYMBOLS {}
|
72
SourceGen/SGTestData/Expected/20260-pre-labels_merlin32.S
Normal file
72
SourceGen/SGTestData/Expected/20260-pre-labels_merlin32.S
Normal file
@ -0,0 +1,72 @@
|
||||
zzz equ $103b
|
||||
|
||||
org $0000
|
||||
dw $1000
|
||||
|
||||
org $1000
|
||||
begin bit begin
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part2
|
||||
|
||||
org $2000
|
||||
part2 bit part2
|
||||
nop
|
||||
lda :local1
|
||||
lda local2
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit b4_part3
|
||||
jmp part3
|
||||
|
||||
:local1 dfb $81
|
||||
local2 dfb $82
|
||||
|
||||
b4_part3
|
||||
org $3000
|
||||
part3 bit part3
|
||||
nop
|
||||
lda local2
|
||||
lda :local3
|
||||
lda local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit _b4_part4
|
||||
jmp part4
|
||||
|
||||
:local3 dfb $83
|
||||
local4 dfb $84
|
||||
|
||||
org $4000
|
||||
b4_part4a
|
||||
org $5000
|
||||
_b4_part4
|
||||
org $6000
|
||||
part4 bit part4
|
||||
bit _b4_part4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part4a
|
||||
|
||||
org $500c
|
||||
part4a bit part4a
|
||||
bit b4_part4a
|
||||
jsr part4b
|
||||
org $4015
|
||||
dfb $00
|
||||
|
||||
part4b bit part4b
|
||||
bit zzz
|
||||
jmp :LF000
|
||||
|
||||
org $f000
|
||||
:LF000 nop
|
||||
bne $f003
|
||||
org $0000
|
||||
dfb $ea
|
||||
dfb $00
|
111
SourceGen/SGTestData/Source/20260-pre-labels.S
Normal file
111
SourceGen/SGTestData/Source/20260-pre-labels.S
Normal file
@ -0,0 +1,111 @@
|
||||
; Copyright 2021 faddenSoft. All Rights Reserved.
|
||||
; See the LICENSE.txt file for distribution terms (Apache 2.0).
|
||||
;
|
||||
; Test address region pre-labels.
|
||||
;
|
||||
; Assembler: 64tass
|
||||
; % tass64 --ascii --case-sensitive --nostart 20260-nested-regions.S
|
||||
|
||||
.cpu "6502"
|
||||
* = $1000
|
||||
|
||||
; EDIT: create project symbol with same name as pre-label (pre-label should win)
|
||||
; FILE-EDIT: change pre-label to match user label
|
||||
|
||||
; EDIT: create explicit 2-byte NON_ADDR region here.
|
||||
START
|
||||
.word $1000
|
||||
|
||||
|
||||
.logical $1000
|
||||
; EDIT: create floating address region with pre-label here ($1000)
|
||||
; (label should not appear because parent is non-addr)
|
||||
begin bit begin
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part2
|
||||
.here
|
||||
|
||||
; EDIT: create fixed address region with pre-label here ($2000)
|
||||
; (label should not appear because parent is non-addr)
|
||||
.logical $2000
|
||||
part2 bit part2
|
||||
nop
|
||||
lda _local1
|
||||
lda _local2
|
||||
lda _local4 ;this should force global conv
|
||||
; (don't do _local3 here, or it gets promoted to global and interferes
|
||||
; with local access to both _local3 and _local 4 later on)
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit _b4_part3
|
||||
jmp _part3
|
||||
|
||||
_local1 .byte $81 ;data item with local label
|
||||
_local2 .byte $82 ;data item with local label
|
||||
|
||||
; EDIT: create floating address region with pre-label here ($3000)
|
||||
_b4_part3
|
||||
.logical $3000
|
||||
_part3 bit _part3 ;NOTE: label must be declared local
|
||||
nop
|
||||
lda _local2 ;this should force global conv
|
||||
lda _local3
|
||||
lda _local4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bit b4_part4
|
||||
jmp part4
|
||||
|
||||
_local3 .byte $83 ;data item with local label
|
||||
_local4 .byte $84 ;data item with local label
|
||||
|
||||
; the $2000 range ends here; the $3000 floater also ends here
|
||||
.here
|
||||
.here
|
||||
|
||||
; Stack up multiple pre-labels at same offset.
|
||||
|
||||
|
||||
; EDIT: create fixed address region with pre-label here ($4000)
|
||||
; (label should not appear)
|
||||
b4_part4b ;(not accessible)
|
||||
.logical $4000
|
||||
; EDIT: create fixed address region with pre-label here ($5000)
|
||||
b4_part4a
|
||||
.logical $5000
|
||||
; EDIT: create fixed address region with pre-label here ($6000)
|
||||
b4_part4
|
||||
.logical $6000
|
||||
part4 bit part4
|
||||
bit b4_part4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jmp part4a
|
||||
.here
|
||||
part4a bit part4a
|
||||
bit b4_part4a
|
||||
jsr part4b ;JSR to test code analysis halt
|
||||
.here
|
||||
brk ;shouldn't reach here
|
||||
part4b bit part4b
|
||||
bit b4_part4b
|
||||
jmp end
|
||||
.here
|
||||
|
||||
|
||||
|
||||
; EDIT: created fixed 3-byte address region
|
||||
.logical $f000
|
||||
end
|
||||
nop
|
||||
bne past ;BNE operand should be shown as hex value
|
||||
|
||||
; EDIT: put actual end here, before the nop
|
||||
past nop
|
||||
.here
|
||||
brk
|
@ -309,7 +309,7 @@ namespace SourceGen.WpfGui {
|
||||
mPreLabelAddress = curRegion.PreLabelAddress;
|
||||
|
||||
if (isSingleLine) {
|
||||
// Only thing selected was .arstart/.arend. First action is to edit
|
||||
// Only thing selected was arstart/arend. First action is to edit
|
||||
// the region properties, second action is to convert floating end
|
||||
// to fixed.
|
||||
mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset,
|
||||
@ -332,7 +332,7 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
} else {
|
||||
// Selection started with .arstart and included multiple lines. First
|
||||
// Selection started with arstart and included multiple lines. First
|
||||
// action is to resize region. Second action is edit without resize.
|
||||
// If resize is illegal (e.g. new region exactly overlaps another),
|
||||
// first action is disabled.
|
||||
|
@ -1672,8 +1672,8 @@ namespace SourceGen.WpfGui {
|
||||
ReferencesListItem rli = (ReferencesListItem)item;
|
||||
|
||||
// Jump to the offset, then shift the focus back to the code list.
|
||||
mMainCtrl.GoToLocation(new NavStack.Location(rli.OffsetValue, 0, false),
|
||||
MainController.GoToMode.JumpToCodeData, true);
|
||||
mMainCtrl.GoToLocation(new NavStack.Location(rli.OffsetValue, 0,
|
||||
NavStack.GoToMode.JumpToCodeData), true);
|
||||
codeListView.Focus();
|
||||
}
|
||||
|
||||
@ -1716,8 +1716,8 @@ namespace SourceGen.WpfGui {
|
||||
NotesListItem nli = (NotesListItem)item;
|
||||
|
||||
// Jump to the offset, then shift the focus back to the code list.
|
||||
mMainCtrl.GoToLocation(new NavStack.Location(nli.OffsetValue, 0, true),
|
||||
MainController.GoToMode.JumpToNote, true);
|
||||
mMainCtrl.GoToLocation(new NavStack.Location(nli.OffsetValue, 0,
|
||||
NavStack.GoToMode.JumpToNote), true);
|
||||
codeListView.Focus();
|
||||
}
|
||||
|
||||
@ -2098,8 +2098,8 @@ namespace SourceGen.WpfGui {
|
||||
MessageListItem mli = (MessageListItem)item;
|
||||
|
||||
// Jump to the offset, then shift the focus back to the code list.
|
||||
mMainCtrl.GoToLocation(new NavStack.Location(mli.OffsetValue, 0, false),
|
||||
MainController.GoToMode.JumpToCodeData, true);
|
||||
mMainCtrl.GoToLocation(new NavStack.Location(mli.OffsetValue, 0,
|
||||
NavStack.GoToMode.JumpToCodeData), true);
|
||||
codeListView.Focus();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user