/* * 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 { /// /// Functions for generating a human-readable form of the address map. /// /// A graphical / interactive visualization would be nicer, but this can be pasted /// into bug reports. /// public static class RenderAddressMap { private const string CRLF = "\r\n"; /// /// Formats the address map for viewing. /// 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 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. 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.GenerateDisplayLabel(formatter)); sb.Append("'"); } } if (change.Region.HasValidPreLabel) { sb.Append(" pre='"); sb.Append(change.Region.PreLabel); sb.Append("'"); } if (change.Region.DisallowInward) { sb.Append(" [!in]"); } if (change.Region.DisallowOutward) { sb.Append(" [!out]"); } 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"); if (change.Region.IsFloating) { sb.Append(" (floating)"); } //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)); } } } }