1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-05-31 22:41:37 +00:00
6502bench/SourceGen/RenderAddressMap.cs
Andy McFadden e6c5c7f8df ORG rework, part 6
Added support for non-addressable regions, which are useful for things
like file headers stripped out by the system loader, or chunks that
get loaded into non-addressable graphics RAM.  Regions are specified
with the "NA" address value.  The code list displays the address field
greyed out, starting from zero (which is kind of handy if you want to
know the relative offset within the region).

Putting labels in non-addressable regions doesn't make sense, but
symbol resolution is complicated enough that we really only have two
options: ignore the labels entirely, or allow them but warn of their
presence.  The problem isn't so much the label, which you could
legitimately want to access from an extension script, but rather the
references to them from code or data.  So we keep the label and add a
warning to the Messages list when we see a reference.

Moved NON_ADDR constants to Address class.  AddressMap now has a copy.
This is awkward because Asm65 and CommonUtil don't share.

Updated the asm code generators to understand NON_ADDR, and reworked
the API so that Merlin and cc65 output is correct for nested regions.

Address region changes are now noted in the anattribs array, which
makes certain operations faster than checking the address map.  It
also fixes a failure to recognize mid-instruction region changes in
the code analyzer.

Tweaked handling of synthetic regions, which are non-addressable areas
generated by the linear address map traversal to fill in any "holes".
The address region editor now treats attempts to edit them as
creation of a new region.
2021-09-30 21:11:26 -07:00

172 lines
6.6 KiB
C#

/*
* Copyright 2021 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Asm65;
using CommonUtil;
using AddressChange = CommonUtil.AddressMap.AddressChange;
namespace SourceGen {
/// <summary>
/// Functions for generating a human-readable form of the address map.
/// </summary>
/// A graphical / interactive visualization would be nicer, but this can be pasted
/// into bug reports.
/// </remarks>
public static class RenderAddressMap {
private const string CRLF = "\r\n";
/// <summary>
/// Formats the address map for viewing.
/// </summary>
public static string GenerateString(DisasmProject project, Formatter formatter) {
AddressMap addrMap = project.AddrMap;
bool showBank = !project.CpuDef.HasAddr16;
StringBuilder sb = new StringBuilder();
int depth = 0;
int prevOffset = -1;
int prevAddr = 0;
int lastEndOffset = -1;
sb.AppendLine("Address region map for " + project.DataFileName);
sb.Append(CRLF);
IEnumerator<AddressChange> iter = addrMap.AddressChangeIterator;
while (iter.MoveNext()) {
AddressChange change = iter.Current;
if (change.IsStart) {
//if (change.Offset == lastEndOffset) {
// // Extra vertical space for a START following an END at the same offset.
// PrintDepthLines(sb, depth, true);
// sb.Append(CRLF);
// lastEndOffset = -1;
//}
if (prevOffset >= 0 && change.Offset != prevOffset) {
// Start of region at new offset. Output address info for space
// between previous start or end.
PrintAddressInfo(sb, formatter, depth, prevAddr,
change.Offset - prevOffset, showBank);
}
// 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");
if (change.IsSynthetic) {
sb.Append(" (auto-generated)");
} else {
// 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(CRLF);
prevOffset = change.Offset;
prevAddr = change.Address;
depth++;
} else {
Debug.Assert(prevOffset >= 0);
depth--;
if (change.Offset + 1 != prevOffset) {
// End of region at new offset. Output address info for space
// between previous start or end.
PrintAddressInfo(sb, formatter, depth + 1, prevAddr,
change.Offset + 1 - prevOffset, showBank);
}
sb.Append(formatter.FormatOffset24(change.Offset));
PrintDepthLines(sb, depth, false);
sb.Append("+- " + "end");
//PrintAddress(sb, formatter, change.Address, showBank);
//sb.Append(")");
sb.Append(CRLF);
// Add a blank line, but with the depth lines.
if (depth > 0) {
PrintDepthLines(sb, depth, true);
}
sb.Append(CRLF);
// Use offset+1 here so it lines up with start records.
prevOffset = lastEndOffset = change.Offset + 1;
prevAddr = change.Address;
}
}
Debug.Assert(depth == 0);
return sb.ToString();
}
private static void PrintDepthLines(StringBuilder sb, int depth, bool doIndent) {
if (doIndent) {
sb.Append(" ");
}
sb.Append(" ");
while (depth-- > 0) {
sb.Append("| ");
}
}
private static void PrintAddressInfo(StringBuilder sb, Formatter formatter, int depth,
int startAddr, int length, bool showBank) {
//PrintDepthLines(sb, depth);
//sb.Append(CRLF);
PrintDepthLines(sb, depth, true);
sb.Append(' ');
if (startAddr == Address.NON_ADDR) {
sb.Append("-" + Address.NON_ADDR_STR + "-");
} else {
PrintAddress(sb, formatter, startAddr, showBank);
sb.Append(" - ");
PrintAddress(sb, formatter, startAddr + length - 1, showBank);
}
sb.Append(" length=" + length + " ($" + length.ToString("x4") + ")");
sb.Append(CRLF);
//PrintDepthLines(sb, depth, true);
//sb.Append(CRLF);
}
private static void PrintAddress(StringBuilder sb, Formatter formatter, int addr,
bool showBank) {
if (addr == Address.NON_ADDR) {
sb.Append("-" + Address.NON_ADDR_STR + "-");
} else {
sb.Append("$");
sb.Append(formatter.FormatAddress(addr, showBank));
}
}
}
}