1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-11 02:29:53 +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:
Andy McFadden 2021-10-07 12:39:08 -07:00
parent d2326c389f
commit 0ac0686c7a
26 changed files with 821 additions and 121 deletions

View File

@ -977,7 +977,7 @@ namespace CommonUtil {
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is NOT intended to say whether the sequence of addresses has a hiccup. The goal /// 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: /// 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 /// 1. Find the node that holds the offset, confirm that it spans offset+length, and

View File

@ -112,8 +112,8 @@ namespace SourceGen.AsmGen {
{ "EquDirective", "=" }, { "EquDirective", "=" },
{ "VarDirective", ".set" }, { "VarDirective", ".set" },
{ "ArStartDirective", ".org" }, { "ArStartDirective", ".org" },
//ArEndDirective { "ArEndDirective", ".adrend" }, // on-screen display only
//RegWidthDirective // .a8, .a16, .i8, .i16 //RegWidthDirective // .a8, .a16, .i8, .i16
//DataBankDirective //DataBankDirective
{ "DefineData1", ".byte" }, { "DefineData1", ".byte" },
{ "DefineData2", ".word" }, { "DefineData2", ".word" },
@ -123,12 +123,12 @@ namespace SourceGen.AsmGen {
//DefineBigData3 //DefineBigData3
//DefineBigData4 //DefineBigData4
{ "Fill", ".res" }, { "Fill", ".res" },
{ "Dense", ".byte" }, // not really dense, just comma-separated bytes { "Dense", ".byte" }, // really just just comma-separated bytes
//Junk //Junk
{ "StrGeneric", ".byte" }, { "StrGeneric", ".byte" },
//StrReverse //StrReverse
{ "StrNullTerm", ".asciiz" }, { "StrNullTerm", ".asciiz" },
//StrLen8 // macro with .strlen? //StrLen8 // TODO(maybe): macro with .strlen?
//StrLen16 //StrLen16
//StrDci //StrDci
}); });

View File

@ -106,7 +106,7 @@ namespace SourceGen.AsmGen {
{ "EquDirective", "equ" }, { "EquDirective", "equ" },
{ "VarDirective", "equ" }, { "VarDirective", "equ" },
{ "ArStartDirective", "org" }, { "ArStartDirective", "org" },
{ "ArEndDirective", "org_end" }, // not actually used { "ArEndDirective", "adrend" }, // on-screen display only
//RegWidthDirective //RegWidthDirective
//DataBankDirective //DataBankDirective
{ "DefineData1", "dfb" }, { "DefineData1", "dfb" },

View File

@ -735,9 +735,15 @@ namespace SourceGen {
} }
if ((mLeftFlags & ActiveColumnFlags.Address) != 0) { if ((mLeftFlags & ActiveColumnFlags.Address) != 0) {
if (!string.IsNullOrEmpty(parts.Addr)) { 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], colPos = AddSpacedString(sb, colPos, mColStart[(int)Col.Address],
str, str.Length); str, parts.Addr.Length + 1);
} }
} }
if ((mLeftFlags & ActiveColumnFlags.Bytes) != 0) { if ((mLeftFlags & ActiveColumnFlags.Bytes) != 0) {

View File

@ -282,8 +282,8 @@ namespace SourceGen {
int topOffset = dl[topIndex].FileOffset; int topOffset = dl[topIndex].FileOffset;
int firstIndex = dl.FindLineIndexByOffset(topOffset); int firstIndex = dl.FindLineIndexByOffset(topOffset);
Debug.Assert(topIndex >= firstIndex); Debug.Assert(topIndex >= firstIndex);
savedSel.mTopPosition = savedSel.mTopPosition = new NavStack.Location(topOffset, topIndex - firstIndex,
new NavStack.Location(topOffset, topIndex - firstIndex, false); NavStack.GoToMode.JumpToAdjIndex);
List<Line> lineList = dl.mLineList; List<Line> lineList = dl.mLineList;
Debug.Assert(lineList.Count == sel.Length); Debug.Assert(lineList.Count == sel.Length);
@ -832,7 +832,7 @@ namespace SourceGen {
// Blank lines and comments can appear before or after code/data. They // 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. // must have the offset of the associated line, and a span of zero.
if (line.FileOffset != expectedOffset && line.FileOffset != lastOffset) { 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. // we need to make a special exemption for them.
if (line.LineType == Line.Type.ArEndDirective && if (line.LineType == Line.Type.ArEndDirective &&
line.FileOffset == expectedOffset - 1) { line.FileOffset == expectedOffset - 1) {
@ -1035,7 +1035,7 @@ namespace SourceGen {
// Insert long comments and notes. These may span multiple display lines, // 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. // 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 // TODO: integrate into FormattedOperandCache so we don't have to
// regenerate them unless they change. Use the MLC as the dependency. // regenerate them unless they change. Use the MLC as the dependency.
@ -1066,7 +1066,7 @@ namespace SourceGen {
AddressMap.AddressRegion region = change.Region; AddressMap.AddressRegion region = change.Region;
if (region.Offset == 0 && hasPrgHeader) { 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. // at offset +000002, and that it matches the value at +0/1.
addrIter.MoveNext(); addrIter.MoveNext();
continue; continue;
@ -1079,7 +1079,7 @@ namespace SourceGen {
lines.Add(GenerateBlankLine(offset)); lines.Add(GenerateBlankLine(offset));
} }
spaceAdded = false; // next one will need a blank line 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) { if (region.HasValidPreLabel) {
Line preLine = Line preLine =
@ -1109,16 +1109,19 @@ namespace SourceGen {
} else { } else {
addrStr = mFormatter.FormatHexValue(region.Address, 4); addrStr = mFormatter.FormatHexValue(region.Address, 4);
} }
#if DEBUG #if DEBUG1
string comment = mFormatter.FormatEolComment("ends at " + string comment = mFormatter.FormatEolComment("ends at " +
mFormatter.FormatOffset24(region.Offset + region.ActualLength - 1) + mFormatter.FormatOffset24(region.Offset + region.ActualLength - 1) +
(region.IsFloating ? " (floating)" : string.Empty)); (region.IsFloating ? " (floating)" : string.Empty));
#else
string comment = string.Empty;
#endif
if (change.IsSynthetic) { if (change.IsSynthetic) {
comment += " (auto-generated)"; comment += " (auto-generated)";
} }
#else
string comment = string.Empty;
if (change.IsSynthetic) {
comment = mFormatter.FormatEolComment("(auto-generated)");
}
#endif
newLine.Parts = FormattedParts.CreateFullDirective(string.Empty, newLine.Parts = FormattedParts.CreateFullDirective(string.Empty,
mFormatter.FormatPseudoOp(mPseudoOpNames.ArStartDirective), mFormatter.FormatPseudoOp(mPseudoOpNames.ArStartDirective),
addrStr, comment); addrStr, comment);
@ -1284,10 +1287,10 @@ namespace SourceGen {
// Check for address region ends, which will be positioned one byte before the // Check for address region ends, which will be positioned one byte before the
// updated offset (unless they somehow got embedded inside something else). // 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. // 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. // 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 they differ.)
if (addrIter.Current != null && addrIter.Current.Region.Length != 1) { if (addrIter.Current != null && addrIter.Current.Region.Length != 1) {
arSubLine = 0; arSubLine = 0;
@ -1302,7 +1305,7 @@ namespace SourceGen {
} }
if (change.Region.Offset == 0 && hasPrgHeader) { if (change.Region.Offset == 0 && hasPrgHeader) {
// Suppress the .arend at offset +000001. // Suppress the arend at offset +000001.
addrIter.MoveNext(); addrIter.MoveNext();
arSubLine++; // need to track address map arSubLine++; // need to track address map
continue; continue;
@ -1330,7 +1333,7 @@ namespace SourceGen {
// Put a blank line before the next thing. // Put a blank line before the next thing.
// TODO(maybe): this gets lost in a partial update, e.g. you add a // 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 // then hit "undo", because the blank is logically part of the
// following offset. // following offset.
addBlank = true; addBlank = true;
@ -1649,7 +1652,7 @@ namespace SourceGen {
} }
public AddressMap.AddressRegion GetAddrRegionFromLine(Line line, out bool isSynth) { 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 // 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. // overlap. If there's both start and end present, we have a 1-byte region.
int offset = line.FileOffset; int offset = line.FileOffset;
@ -1666,14 +1669,14 @@ namespace SourceGen {
while (addrIter.Current != null && addrIter.Current.Offset == offset) { while (addrIter.Current != null && addrIter.Current.Offset == offset) {
AddressMap.AddressChange change = addrIter.Current; AddressMap.AddressChange change = addrIter.Current;
if (count == 0) { 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; isSynth = change.IsSynthetic;
return change.Region; return change.Region;
} }
if (change.IsStart && change.Region.HasValidPreLabel) { if (change.IsStart && change.Region.HasValidPreLabel) {
count--; count--;
if (count == 0) { if (count == 0) {
// This is the .arstart following the pre-label. // This is the arstart following the pre-label.
isSynth = change.IsSynthetic; isSynth = change.IsSynthetic;
return change.Region; return change.Region;
} }

View File

@ -1664,7 +1664,8 @@ namespace SourceGen {
} }
if (line.IsAddressRangeDirective) { 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, AddressMap.AddressRegion region = CodeLineList.GetAddrRegionFromLine(line,
out bool unused); out bool unused);
if (region == null) { if (region == null) {
@ -1674,13 +1675,12 @@ namespace SourceGen {
if (!testOnly) { if (!testOnly) {
if (line.LineType == LineListGen.Line.Type.ArStartDirective) { if (line.LineType == LineListGen.Line.Type.ArStartDirective) {
// jump to end // jump to end
GoToLocation( GoToLocation(new NavStack.Location(region.Offset + region.ActualLength - 1,
new NavStack.Location(region.Offset + region.ActualLength - 1, 0, true), 0, NavStack.GoToMode.JumpToArEnd), true);
GoToMode.JumpToCodeData, true);
} else { } else {
// jump to start // jump to start
GoToLocation(new NavStack.Location(region.Offset, 0, true), GoToLocation(new NavStack.Location(region.Offset,
GoToMode.JumpToCodeData, true); 0, NavStack.GoToMode.JumpToArStart), true);
} }
} }
return true; return true;
@ -1706,9 +1706,11 @@ namespace SourceGen {
int labelOffset = mProject.FindLabelOffsetByName(dfd.SymbolRef.Label); int labelOffset = mProject.FindLabelOffsetByName(dfd.SymbolRef.Label);
if (labelOffset >= 0) { if (labelOffset >= 0) {
if (!testOnly) { if (!testOnly) {
// TODO(org): jump to .arstart NavStack.GoToMode mode = NavStack.GoToMode.JumpToCodeData;
GoToLocation(new NavStack.Location(labelOffset, 0, false), if (sym.SymbolSource == Symbol.Source.AddrPreLabel) {
GoToMode.JumpToCodeData, true); mode = NavStack.GoToMode.JumpToArStart;
}
GoToLocation(new NavStack.Location(labelOffset, 0, mode), true);
} }
return true; return true;
} }
@ -1719,8 +1721,8 @@ namespace SourceGen {
if (mProject.ActiveDefSymbolList[i] == sym) { if (mProject.ActiveDefSymbolList[i] == sym) {
int offset = LineListGen.DefSymOffsetFromIndex(i); int offset = LineListGen.DefSymOffsetFromIndex(i);
if (!testOnly) { if (!testOnly) {
GoToLocation(new NavStack.Location(offset, 0, false), GoToLocation(new NavStack.Location(offset, 0,
GoToMode.JumpToCodeData, true); NavStack.GoToMode.JumpToCodeData), true);
} }
return true; return true;
} }
@ -1737,8 +1739,8 @@ namespace SourceGen {
// Operand has an in-file target offset. We can resolve it as a numeric reference. // 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. // Find the line for that offset and jump to it.
if (!testOnly) { if (!testOnly) {
GoToLocation(new NavStack.Location(attr.OperandOffset, 0, false), GoToLocation(new NavStack.Location(attr.OperandOffset, 0,
GoToMode.JumpToCodeData, true); NavStack.GoToMode.JumpToCodeData), true);
} }
return true; return true;
} else if (attr.IsDataStart || attr.IsInlineDataStart) { } else if (attr.IsDataStart || attr.IsInlineDataStart) {
@ -1748,8 +1750,8 @@ namespace SourceGen {
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset); int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset);
if (operandOffset >= 0) { if (operandOffset >= 0) {
if (!testOnly) { if (!testOnly) {
GoToLocation(new NavStack.Location(operandOffset, 0, false), GoToLocation(new NavStack.Location(operandOffset, 0,
GoToMode.JumpToCodeData, true); NavStack.GoToMode.JumpToCodeData), true);
} }
return true; return true;
} }
@ -1809,15 +1811,15 @@ namespace SourceGen {
int lastIndex = mMainWin.CodeListView_GetLastSelectedIndex(); 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) { if (selIndex != lastIndex && selLine.LineType == LineListGen.Line.Type.ArEndDirective) {
return false; 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 // 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 // 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. // so long as the corresponding arstart is at the current offset.
if (selLine.LineType == LineListGen.Line.Type.ArStartDirective) { if (selLine.LineType == LineListGen.Line.Type.ArStartDirective) {
// Skip overlapping region check. // Skip overlapping region check.
return true; return true;
@ -1856,7 +1858,7 @@ namespace SourceGen {
int nextOffset = lastOffset + CodeLineList[lastIndex].OffsetSpan; int nextOffset = lastOffset + CodeLineList[lastIndex].OffsetSpan;
AddressMap addrMap = mProject.AddrMap; 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 // 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 // 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.) // be avoided by using an exclusive end offset, but that causes other problems.)
@ -1865,13 +1867,13 @@ namespace SourceGen {
nextOffset++; 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; int selectedLen = nextOffset - firstOffset;
AddressMap.AddressRegion curRegion; AddressMap.AddressRegion curRegion;
if (CodeLineList[selIndex].LineType == LineListGen.Line.Type.ArStartDirective || if (CodeLineList[selIndex].LineType == LineListGen.Line.Type.ArStartDirective ||
CodeLineList[selIndex].LineType == LineListGen.Line.Type.ArEndDirective) { 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], curRegion = CodeLineList.GetAddrRegionFromLine(CodeLineList[selIndex],
out bool isSynth); out bool isSynth);
Debug.Assert(curRegion != null); Debug.Assert(curRegion != null);
@ -1888,7 +1890,7 @@ namespace SourceGen {
} else { } else {
if (selectedLen == 0) { if (selectedLen == 0) {
// A length of zero is only possible if nothing but directives were selected, // 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); Debug.Assert(false);
return; return;
} }
@ -2820,20 +2822,20 @@ namespace SourceGen {
GotoBox dlg = new GotoBox(mMainWin, mProject, offset, mFormatter); GotoBox dlg = new GotoBox(mMainWin, mProject, offset, mFormatter);
if (dlg.ShowDialog() == true) { if (dlg.ShowDialog() == true) {
GoToLocation(new NavStack.Location(dlg.TargetOffset, 0, false), GoToLocation(new NavStack.Location(dlg.TargetOffset, 0,
GoToMode.JumpToCodeData, true); NavStack.GoToMode.JumpToCodeData), true);
//mMainWin.CodeListView_Focus(); //mMainWin.CodeListView_Focus();
} }
} }
public enum GoToMode { Unknown = 0, JumpToCodeData, JumpToNote, JumpToAdjIndex };
/// <summary> /// <summary>
/// Moves the view and selection to the specified offset. We want to select stuff /// 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. /// differently if we're jumping to a note vs. jumping to an instruction.
/// </summary> /// </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> /// <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(); NavStack.Location prevLoc = GetCurrentlySelectedLocation();
//Debug.WriteLine("GoToLocation: " + loc + " mode=" + mode + " doPush=" + doPush + //Debug.WriteLine("GoToLocation: " + loc + " mode=" + mode + " doPush=" + doPush +
// " (curLoc=" + prevLoc + ")"); // " (curLoc=" + prevLoc + ")");
@ -2844,8 +2846,7 @@ namespace SourceGen {
// entry in the symbol table for the current offset, we want to move the selection, // 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 // 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. // do the move but not push it.
bool jumpToNote = (mode == GoToMode.JumpToNote); if (newLoc.Offset == prevLoc.Offset && newLoc.Mode == prevLoc.Mode) {
if (loc.Offset == prevLoc.Offset && jumpToNote == prevLoc.IsNote) {
// we're jumping to ourselves? // we're jumping to ourselves?
if (doPush) { if (doPush) {
Debug.WriteLine("Ignoring push for goto to current offset"); 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) { if (topLineIndex < 0) {
Debug.Assert(false, "failed goto offset +" + loc.Offset.ToString("x6")); Debug.Assert(false, "failed goto offset +" + newLoc.Offset.ToString("x6"));
return; return;
} }
int lastLineIndex; int lastLineIndex;
if (mode == GoToMode.JumpToNote) { if (newLoc.Mode == NavStack.GoToMode.JumpToNote) {
// Select all note lines, disregard the rest. // Select all note lines, disregard the rest.
while (CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Note) { while (CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Note) {
if (CodeLineList[topLineIndex].FileOffset != newLoc.Offset) {
// This can happen if the note got deleted.
break;
}
topLineIndex++; topLineIndex++;
Debug.Assert(CodeLineList[topLineIndex].FileOffset == loc.Offset);
} }
lastLineIndex = topLineIndex + 1; lastLineIndex = topLineIndex + 1;
while (lastLineIndex < CodeLineList.Count && while (lastLineIndex < CodeLineList.Count &&
CodeLineList[lastLineIndex].LineType == LineListGen.Line.Type.Note) { CodeLineList[lastLineIndex].LineType == LineListGen.Line.Type.Note) {
lastLineIndex++; 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. // This is the offset of the header comment or a .EQ directive. Don't mess with it.
lastLineIndex = topLineIndex + 1; lastLineIndex = topLineIndex + 1;
} else if (mode == GoToMode.JumpToCodeData) { } else if (newLoc.Mode == NavStack.GoToMode.JumpToCodeData) {
// Advance to the code or data line. // Advance to the code or data line.
while (CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Code && while (CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Code &&
CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Data) { CodeLineList[topLineIndex].LineType != LineListGen.Line.Type.Data) {
@ -2881,14 +2885,35 @@ namespace SourceGen {
} }
lastLineIndex = topLineIndex + 1; 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 // Adjust the line position by the line delta. If the adjustment moves us to
// a different element, ignore the adjustment. // a different element, ignore the adjustment.
if (CodeLineList[topLineIndex].FileOffset == if (CodeLineList[topLineIndex].FileOffset ==
CodeLineList[topLineIndex + loc.LineDelta].FileOffset) { CodeLineList[topLineIndex + newLoc.LineDelta].FileOffset) {
topLineIndex += loc.LineDelta; topLineIndex += newLoc.LineDelta;
} }
lastLineIndex = topLineIndex + 1; 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 { } else {
Debug.Assert(false); Debug.Assert(false);
lastLineIndex = topLineIndex + 1; lastLineIndex = topLineIndex + 1;
@ -3029,7 +3054,8 @@ namespace SourceGen {
int offset = CodeLineList[index].FileOffset; int offset = CodeLineList[index].FileOffset;
int lineDelta = index - CodeLineList.FindLineIndexByOffset(offset); int lineDelta = index - CodeLineList.FindLineIndexByOffset(offset);
bool isNote = (CodeLineList[index].LineType == LineListGen.Line.Type.Note); 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() { public void GotoLastChange() {
@ -3076,11 +3102,11 @@ namespace SourceGen {
} }
if (isNote) { if (isNote) {
GoToLocation(new NavStack.Location(offset, 0, true), GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToNote),
GoToMode.JumpToNote, true); true);
} else { } else {
GoToLocation(new NavStack.Location(offset, 0, false), GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToCodeData),
GoToMode.JumpToCodeData, true); true);
} }
} }
@ -3090,8 +3116,7 @@ namespace SourceGen {
public void NavigateBackward() { public void NavigateBackward() {
Debug.Assert(mNavStack.HasBackward); Debug.Assert(mNavStack.HasBackward);
NavStack.Location backLoc = mNavStack.MoveBackward(GetCurrentlySelectedLocation()); NavStack.Location backLoc = mNavStack.MoveBackward(GetCurrentlySelectedLocation());
GoToLocation(backLoc, GoToLocation(backLoc, false);
backLoc.IsNote ? GoToMode.JumpToNote : GoToMode.JumpToAdjIndex, false);
} }
public bool CanNavigateForward() { public bool CanNavigateForward() {
@ -3100,8 +3125,7 @@ namespace SourceGen {
public void NavigateForward() { public void NavigateForward() {
Debug.Assert(mNavStack.HasForward); Debug.Assert(mNavStack.HasForward);
NavStack.Location fwdLoc = mNavStack.MoveForward(GetCurrentlySelectedLocation()); NavStack.Location fwdLoc = mNavStack.MoveForward(GetCurrentlySelectedLocation());
GoToLocation(fwdLoc, GoToLocation(fwdLoc, false);
fwdLoc.IsNote ? GoToMode.JumpToNote : GoToMode.JumpToAdjIndex, false);
} }
/// <summary> /// <summary>
@ -3111,8 +3135,9 @@ 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) {
GoToLocation(new NavStack.Location(offset, 0, false), // TODO(someday): jump to correct line for address region pre-labels
GoToMode.JumpToCodeData, true); GoToLocation(new NavStack.Location(offset, 0, NavStack.GoToMode.JumpToCodeData),
true);
} else { } else {
Debug.WriteLine("DClick symbol: " + sym + ": label not found"); Debug.WriteLine("DClick symbol: " + sym + ": label not found");
} }
@ -4045,14 +4070,23 @@ namespace SourceGen {
esb.Append(" (floating)"); esb.Append(" (floating)");
} }
esb.Append(CRLF); 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("Synthetic: " + isSynth);
esb.Append(CRLF); 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("Relative: " + region.IsRelative);
esb.Append(CRLF); esb.Append(CRLF);
mMainWin.InfoPanelDetail1 = esb.ToString(); mMainWin.InfoPanelDetail1 = esb.ToString();

View File

@ -38,6 +38,15 @@ namespace SourceGen {
// TODO(someday): change the back button to a pop-up list of locations (like the way // TODO(someday): change the back button to a pop-up list of locations (like the way
// VS 2017 does it). // 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> /// <summary>
/// Holds enough information to get us back where we were, in style. /// Holds enough information to get us back where we were, in style.
/// </summary> /// </summary>
@ -49,7 +58,7 @@ namespace SourceGen {
/// <summary> /// <summary>
/// Number of lines between the first line at the specified offset, and the /// 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> /// </summary>
/// <remarks> /// <remarks>
/// It's possible this line no longer exists. Easiest test is to compare the /// 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; } public int LineDelta { get; set; }
/// <summary> /// <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> /// </summary>
/// <remarks> public GoToMode Mode { get; set; }
/// This is an alternative to LineDelta.
/// </remarks>
public bool IsNote { get; set; }
public Location(int offset, int lineDelta, bool isNote) { public Location(int offset, int lineDelta, GoToMode mode) {
Offset = offset; Offset = offset;
LineDelta = lineDelta; LineDelta = lineDelta;
IsNote = isNote; Mode = mode;
//if (lineDelta != 0 && mode != GoToMode.JumpToAdjIndex) {
// Debug.WriteLine("HEY: lineDelta=" + lineDelta + " mode=" + mode);
//}
} }
public override string ToString() { 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) { public static bool operator ==(Location a, Location b) {
@ -83,7 +93,7 @@ namespace SourceGen {
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) { if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) {
return false; // one is 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) { public static bool operator !=(Location a, Location b) {
return !(a == b); return !(a == b);
@ -92,7 +102,7 @@ namespace SourceGen {
return obj is Location && this == (Location)obj; return obj is Location && this == (Location)obj;
} }
public override int GetHashCode() { public override int GetHashCode() {
return Offset + (LineDelta * 1000000) + (IsNote ? (1<<24) : 0); return Offset + (LineDelta * 1000000) + ((int)Mode << 24);
} }
} }

View File

@ -228,8 +228,8 @@ namespace SourceGen {
new PseudoOpNames(new Dictionary<string, string> { new PseudoOpNames(new Dictionary<string, string> {
{ "EquDirective", ".eq" }, { "EquDirective", ".eq" },
{ "VarDirective", ".var" }, { "VarDirective", ".var" },
{ "ArStartDirective", ".arstart" }, { "ArStartDirective", ".addrs" },
{ "ArEndDirective", ".arend" }, { "ArEndDirective", ".adrend" },
{ "RegWidthDirective", ".rwid" }, { "RegWidthDirective", ".rwid" },
{ "DataBankDirective", ".dbank" }, { "DataBankDirective", ".dbank" },

View File

@ -45,7 +45,7 @@ namespace SourceGen {
int prevAddr = 0; int prevAddr = 0;
int lastEndOffset = -1; int lastEndOffset = -1;
sb.AppendLine("Address region map for " + project.DataFileName); sb.AppendLine("Address region map for \"" + project.DataFileName + "\"");
sb.Append(CRLF); sb.Append(CRLF);
IEnumerator<AddressChange> iter = addrMap.AddressChangeIterator; IEnumerator<AddressChange> iter = addrMap.AddressChangeIterator;
@ -67,12 +67,6 @@ namespace SourceGen {
} }
// Start following end, or start following start after a gap. // 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)); sb.Append(formatter.FormatOffset24(change.Offset));
PrintDepthLines(sb, depth, false); PrintDepthLines(sb, depth, false);
sb.Append("+- " + "start"); sb.Append("+- " + "start");
@ -83,10 +77,16 @@ namespace SourceGen {
// If there's a label here, show it. // If there's a label here, show it.
Anattrib attr = project.GetAnattrib(change.Offset); Anattrib attr = project.GetAnattrib(change.Offset);
if (attr.Symbol != null && !string.IsNullOrEmpty(attr.Symbol.Label)) { if (attr.Symbol != null && !string.IsNullOrEmpty(attr.Symbol.Label)) {
sb.Append(" : "); sb.Append(" '");
sb.Append(attr.Symbol.Label); 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); sb.Append(CRLF);

View File

@ -1,6 +1,10 @@
/* /*
* 6502bench SourceGen disassembly output style. * 6502bench SourceGen disassembly output style.
*/ */
/*
* General formatting.
*/
body { body {
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
font-size: 14px; /* 16 recommended for mobile */ font-size: 14px; /* 16 recommended for mobile */
@ -11,6 +15,9 @@ table, th, td {
border: 1px solid black; border: 1px solid black;
border-collapse: collapse; border-collapse: collapse;
} }
.greytext {
color: grey;
}
/* /*
* Blue underlined text is distracting. Change internal links to be * Blue underlined text is distracting. Change internal links to be

View File

@ -52,7 +52,8 @@ OverVar @ $40 4
BankWrap @ $fff0 $20 BankWrap @ $fff0 $20
; Width specifiers on constants should be ignored. ; 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. ; Overlapping multi-byte items with exact and inexact matches.
OverA_0 @ $6000 8 ;should win, alphabetically OverA_0 @ $6000 8 ;should win, alphabetically

View File

@ -27,7 +27,7 @@
"OperandFormats":{ "OperandFormats":{
"207":{ "207":{
"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ "Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
"Label":"FatConst","Part":"Low"}}}, "Label":"_FatConst","Part":"Low"}}},
"LvTables":{ "LvTables":{
"192":{ "192":{
"Variables":[{ "Variables":[{

Binary file not shown.

View 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":{
}}

View File

@ -1,5 +1,5 @@
.cpu "6502" .cpu "6502"
FatConst = $4000 X_FatConst = $4000
OverVar = $40 OverVar = $40
CodeWrap = $0f00 ;encases program CodeWrap = $0f00 ;encases program
@ -116,7 +116,7 @@ LocalVar .var $41
ldx OverVar+3 ldx OverVar+3
ldx $44 ldx $44
nop nop
lda FatConst-1 lda X_FatConst-1
lda $4000 lda $4000
lda $4001 lda $4001
lda BankWrap+8 lda BankWrap+8

View File

@ -1,5 +1,5 @@
!cpu 6502 !cpu 6502
FatConst = $4000 _FatConst = $4000
OverVar = $40 OverVar = $40
CodeWrap = $0f00 ;encases program CodeWrap = $0f00 ;encases program
@ -117,7 +117,7 @@ L1000 lda CodeWrap+255
ldx OverVar+3 ldx OverVar+3
ldx $44 ldx $44
nop nop
lda FatConst-1 lda _FatConst-1
lda $4000 lda $4000
lda $4001 lda $4001
lda BankWrap+8 lda BankWrap+8

View File

@ -1,5 +1,5 @@
.setcpu "6502" .setcpu "6502"
FatConst = $4000 _FatConst = $4000
OverVar = $40 OverVar = $40
CodeWrap = $0f00 ;encases program CodeWrap = $0f00 ;encases program
@ -116,7 +116,7 @@ LocalVar .set $41
ldx OverVar+3 ldx OverVar+3
ldx $44 ldx $44
nop nop
lda FatConst-1 lda _FatConst-1
lda $4000 lda $4000
lda $4001 lda $4001
lda BankWrap+8 lda BankWrap+8

View File

@ -1,4 +1,4 @@
FatConst equ $4000 _FatConst equ $4000
OverVar equ $40 OverVar equ $40
CodeWrap equ $0f00 ;encases program CodeWrap equ $0f00 ;encases program
@ -115,7 +115,7 @@ L1000 lda CodeWrap+255
ldx OverVar+3 ldx OverVar+3
ldx $44 ldx $44
nop nop
lda FatConst-1 lda _FatConst-1
lda $4000 lda $4000
lda $4001 lda $4001
lda BankWrap+8 lda BankWrap+8

View 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

View 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
}

View 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

View 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 {}

View 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

View 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

View File

@ -309,7 +309,7 @@ namespace SourceGen.WpfGui {
mPreLabelAddress = curRegion.PreLabelAddress; mPreLabelAddress = curRegion.PreLabelAddress;
if (isSingleLine) { 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 // the region properties, second action is to convert floating end
// to fixed. // to fixed.
mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset, mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset,
@ -332,7 +332,7 @@ namespace SourceGen.WpfGui {
} }
} else { } 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. // action is to resize region. Second action is edit without resize.
// If resize is illegal (e.g. new region exactly overlaps another), // If resize is illegal (e.g. new region exactly overlaps another),
// first action is disabled. // first action is disabled.

View File

@ -1672,8 +1672,8 @@ namespace SourceGen.WpfGui {
ReferencesListItem rli = (ReferencesListItem)item; ReferencesListItem rli = (ReferencesListItem)item;
// Jump to the offset, then shift the focus back to the code list. // Jump to the offset, then shift the focus back to the code list.
mMainCtrl.GoToLocation(new NavStack.Location(rli.OffsetValue, 0, false), mMainCtrl.GoToLocation(new NavStack.Location(rli.OffsetValue, 0,
MainController.GoToMode.JumpToCodeData, true); NavStack.GoToMode.JumpToCodeData), true);
codeListView.Focus(); codeListView.Focus();
} }
@ -1716,8 +1716,8 @@ namespace SourceGen.WpfGui {
NotesListItem nli = (NotesListItem)item; NotesListItem nli = (NotesListItem)item;
// Jump to the offset, then shift the focus back to the code list. // Jump to the offset, then shift the focus back to the code list.
mMainCtrl.GoToLocation(new NavStack.Location(nli.OffsetValue, 0, true), mMainCtrl.GoToLocation(new NavStack.Location(nli.OffsetValue, 0,
MainController.GoToMode.JumpToNote, true); NavStack.GoToMode.JumpToNote), true);
codeListView.Focus(); codeListView.Focus();
} }
@ -2098,8 +2098,8 @@ namespace SourceGen.WpfGui {
MessageListItem mli = (MessageListItem)item; MessageListItem mli = (MessageListItem)item;
// Jump to the offset, then shift the focus back to the code list. // Jump to the offset, then shift the focus back to the code list.
mMainCtrl.GoToLocation(new NavStack.Location(mli.OffsetValue, 0, false), mMainCtrl.GoToLocation(new NavStack.Location(mli.OffsetValue, 0,
MainController.GoToMode.JumpToCodeData, true); NavStack.GoToMode.JumpToCodeData), true);
codeListView.Focus(); codeListView.Focus();
} }