diff --git a/CommonUtil/AddressMap.cs b/CommonUtil/AddressMap.cs
index db7d85e..245b675 100644
--- a/CommonUtil/AddressMap.cs
+++ b/CommonUtil/AddressMap.cs
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 faddenSoft
+ * 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.
@@ -17,323 +17,1435 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Text;
+
namespace CommonUtil {
///
- /// Map file offsets to 65xx addresses and vice-versa. Useful for sources with
- /// multiple ORG directives.
- ///
- /// It's possible to generate code that would overlap once relocated at run time,
- /// which means a given address can map to multiple offsets (overlays, bank-switched
- /// RAM, etc). For this reason it's useful to know the offset of the referring code
- /// when evaluating a reference, so that "local" matches take priority.
+ /// Map file offsets to 65xx addresses and vice-versa. Supports multiple regions
+ /// with overlapping address ranges.
///
///
- /// This was part of the main SourceGen application, but I want to share it with
- /// the extension script mechanism.
+ /// The basic structure is a list of regions, identified by start offset and length, that
+ /// specify the memory address.
+ ///
+ /// This gets complicated because it's possible to have multiple regions that are assembled
+ /// to occupy the same address range (because of overlays or bank-switching). Some regions
+ /// may be nested inside other regions. A reference to a given address could potentially
+ /// resolve to multiple offsets. Any address-to-offset lookup will need to take into
+ /// account the location of the reference, so that references can be resolved in the region
+ /// with the appropriate scope.
+ ///
+ /// There are three basic API modes:
+ /// (1) Structural. Add, modify, and remove regions. Needed by the "edit region" dialog.
+ /// This matches exactly with the contents of the project file.
+ /// (2) Hierarchical. Used when converting an offset to an address, which can't be
+ /// accomplished with a simple map because we need to take into account the offset of
+ /// the reference. The tree best represents the relationship between regions.
+ /// (3) Linear. When generating assembly sources or the display list, we need to identify
+ /// the lines that have an address change event (even if the address doesn't change).
+ /// This will be done as we walk through the code. For easy interaction with an
+ /// iterator, we flatten it out.
+ ///
+ /// These are different enough that it's best to use three different data structures. The
+ /// list of regions is the primary structure, and the other two are generated from it. Changes
+ /// to the map are very infrequent, and analyzing the file contents may hit the map
+ /// frequently, so we want to optimize for "read" accesses.
+ ///
+ /// A region can be uniquely identified by {offset,length}. There can be multiple regions
+ /// starting at a given offset, or ending at a given offset, but we disallow regions that
+ /// are 100% overlapping. This assertion is complicated slightly by the existence of
+ /// regions with "floating" end points.
+ ///
+ /// It is valid for parts of the file to have no address mapping. This is useful for things
+ /// like system file headers that are part of the file but wouldn't be part of the source
+ /// code (such as the C64 PRG address header), or data not addressable by the 6502 (such as
+ /// the CHR graphics block in NES programs). The most significant impact this has on
+ /// SourceGen is that we never resolve address-to-offset lookups in such a region.
+ ///
+ /// For design notes, see https://github.com/fadden/6502bench/issues/107
///
public class AddressMap : IEnumerable {
- public const int NO_ENTRY_ADDR = -1; // address value indicating no entry
+ private const int OFFSET_MAX = (1 << 24) - 1; // max valid offset (16MB file)
+ private const int ADDR_MAX = (1 << 24) - 1; // max valid addr (24-bit address space)
+
+ ///
+ /// Length value to use for regions with a floating end point.
+ ///
+ public const int FLOATING_LEN = -1024;
+
+ ///
+ /// Address value to use for non-addressable regions of the file, such as file headers
+ /// stripped by the system loader or chunks loaded into non-addressable memory.
+ ///
+ public const int NON_ADDR = -1025;
+
+ #region Structural
///
/// Code starting at the specified offset will have the specified address.
- ///
- /// The entries are held in the list in order, sorted by offset, with no gaps.
- /// This makes the "length" field redundant, as it can be computed by
- /// (entry[N+1].mOffset - entry[N].mOffset), with a special case for the last
- /// entry in the list. It's convenient to maintain it explicitly however, as
- /// the list is read far more often than it is updated.
- ///
+ ///
+ /// The entries are held in the list in order, sorted primarily by increasing start offset,
+ /// secondarily by decreasing end offset. If there are multiple regions at the same
+ /// offset, the larger (parent) region will appear first (convenient if you're pushing
+ /// things onto a stack as you traverse the list).
+ ///
+ /// It is valid for the map to be completely empty, or for there to be ranges of offsets
+ /// for which there is no entry.
+ ///
/// Instances are immutable.
///
[Serializable]
public class AddressMapEntry {
+ // Offset at which region starts.
public int Offset { get; private set; }
- public int Addr { get; private set; }
+ // Length of region; invalid for a "floating" end point.
public int Length { get; private set; }
+ // Address to map start of region to.
+ public int Address { get; private set; }
+ // Is the end point floating?
+ public bool IsFloating { get; private set; }
+ // Should we try to generate this with a relative .ORG statement? (This is strictly
+ // for code generation, and has no effect on anything here.)
+ public bool IsRelative { get; private set; }
- public AddressMapEntry(int offset, int addr, int len) {
+ // THOUGHT: we need to be able to do certain info queries from edit dialog. We
+ // can uniquely identify a node in the region list by offset/len, but that gets
+ // funny with floating lengths. We can use a "was floating" flag here to make
+ // it possible to match the offset/float_len to a node in the hierarchical tree.
+ // (add another constructor)
+
+ public AddressMapEntry(int offset, int len, int addr, bool isFloating,
+ bool isRelative) {
Offset = offset;
- Addr = addr;
Length = len;
+ Address = addr;
+ IsFloating = isFloating;
+ IsRelative = isRelative;
+ }
+ public override string ToString() {
+ return "[AddrMapEnt: +" + Offset.ToString("x6") + " len=$" + Length.ToString("x4") +
+ " addr=$" + Address.ToString("x4") + " isFloat=" + IsFloating +
+ " isRel=" + IsRelative + "]";
}
}
///
- /// Total length, in bytes, spanned by this map.
+ /// Total length, in bytes, of the file spanned by this map.
///
- private int mTotalLength;
+ private int mSpanLength;
///
/// List of definitions, in sorted order.
///
- private List mAddrList = new List();
+ private List mRegionList = new List();
+
///
- /// Constructor.
+ /// Constructor. Creates an empty map.
///
- /// Total length, in bytes, spanned by this map.
+ /// Total length, in bytes, of the file spanned by this map.
public AddressMap(int length) {
- /// There must always be at least one entry, defining the target address
- /// for file offset 0. This can be changed, but can't be removed.
- mTotalLength = length;
- mAddrList.Add(new AddressMapEntry(0, 0, length));
+ mSpanLength = length;
+ Regenerate();
}
///
- /// Constructor.
+ /// Constructor. Creates a map from a list of entries.
///
+ /// Total length, in bytes, of the file spanned by this map.
/// List of AddressMapEntry.
- public AddressMap(List entries) {
- mTotalLength = entries[entries.Count - 1].Offset + entries[entries.Count - 1].Length;
+ public AddressMap(int length, List entries) {
+ mSpanLength = length;
+
+ // Add entries one at a time, rather than just cloning the list, to ensure correctness.
+ // (Shouldn't be necessary since we're only doing this to pass the address map to
+ // plugins, but... better safe.)
foreach (AddressMapEntry ent in entries) {
- mAddrList.Add(ent);
+ AddResult result = AddRegion(ent.Offset, ent.Length, ent.Address, ent.IsRelative);
+ if (result != AddResult.Okay) {
+ throw new Exception("Unable to add entry (" + result + "): " + ent);
+ }
}
- DebugValidate();
+ Debug.Assert(entries.Count == mRegionList.Count);
+ Regenerate();
+ }
+
+ public void Clear() {
+ mRegionList.Clear();
+ Regenerate();
}
///
- /// Returns a copy of the list of entries.
+ /// Generates a copy of the list of entries, suitable for passing to a constructor.
///
- ///
- public List GetEntryList() {
- List newList = new List(mAddrList.Count);
- foreach (AddressMapEntry ent in mAddrList) {
+ /// Receives the map's span length.
+ /// Copy of list.
+ public List GetEntryList(out int spanLength) {
+ List newList = new List(mRegionList.Count);
+ foreach (AddressMapEntry ent in mRegionList) {
newList.Add(ent);
}
+ spanLength = mSpanLength;
return newList;
}
// IEnumerable
public IEnumerator GetEnumerator() {
- return ((IEnumerable)mAddrList).GetEnumerator();
+ return ((IEnumerable)mRegionList).GetEnumerator();
}
// IEnumerable
IEnumerator IEnumerable.GetEnumerator() {
- return ((IEnumerable)mAddrList).GetEnumerator();
- }
-
- ///
- /// Returns the Nth entry in the address map.
- ///
- public AddressMapEntry this[int i] {
- get { return mAddrList[i]; }
+ return ((IEnumerable)mRegionList).GetEnumerator();
}
///
/// Number of entries in the address map.
///
- public int Count { get { return mAddrList.Count; } }
+ public int RegionCount { get { return mRegionList.Count; } }
///
- /// Returns the Address value of the address map entry associated with the specified
- /// offset, or NO_ENTRY_ADDR if there is no address map entry there. The offset must
- /// match exactly.
+ /// Error codes for AddRegion().
///
- public int Get(int offset) {
- foreach (AddressMapEntry ad in mAddrList) {
- if (ad.Offset == offset) {
- return ad.Addr;
- }
- }
- return NO_ENTRY_ADDR;
+ public enum AddResult {
+ Unknown = 0,
+ Okay, // success!
+ InvalidValue, // offset, length, or address parameter is invalid
+ OverlapExisting, // new region overlaps existing region exactly
+ OverlapFloating, // new start matches existing; one or both are floating
+ StraddleExisting, // new region straddles one or more existing regions
+ };
+
+ ///
+ /// Validate offset/length/addr arguments.
+ ///
+ ///
+ /// We need to verify:
+ /// - offset >= 0
+ /// - offset < total length of file
+ /// - either length is floating, or:
+ /// - length > 0
+ /// - length < total length of file
+ /// - offset + length < total length of file
+ /// - either address is NON_ADDR, or:
+ /// - addr > 0
+ /// - addr <= ADDR_MAX
+ ///
+ /// True if everything looks good.
+ private bool ValidateArgs(int offset, int length, int addr) {
+ return offset >= 0 && offset < mSpanLength &&
+ (length != FLOATING_LEN ? offset + length <= mSpanLength : true) &&
+ ((length > 0 && length <= mSpanLength) || length == FLOATING_LEN) &&
+ ((addr >= 0 && addr <= ADDR_MAX) || addr == NON_ADDR);
}
///
- /// Returns the index of the address map entry that contains the given offset.
- /// We assume the offset is valid.
+ /// Adds a new region.
///
- private int IndexForOffset(int offset) {
- for (int i = 1; i < mAddrList.Count; i++) {
- if (mAddrList[i].Offset > offset) {
- return i - 1;
+ /// File offset of region start.
+ /// Length of region, or -1 for a floating end point.
+ /// Address of region start.
+ /// True if code generator should output relative
+ /// assembler directive operand.
+ /// Failure code.
+ public AddResult AddRegion(int offset, int length, int addr, bool isRelative) {
+ if (!ValidateArgs(offset, length, addr)) {
+ Debug.WriteLine("AddRegion: invalid arg");
+ return AddResult.InvalidValue;
+ }
+
+ AddressMapEntry newEntry = new AddressMapEntry(offset, length, addr,
+ length == FLOATING_LEN, isRelative);
+
+ // Empty list?
+ if (mRegionList.Count == 0) {
+ mRegionList.Add(newEntry);
+ Regenerate();
+ return AddResult.Okay;
+ }
+
+ // Find insertion point.
+ int insIdx;
+ for (insIdx = 0; insIdx < mRegionList.Count; insIdx++) {
+ AddressMapEntry ent = mRegionList[insIdx];
+ if (ent.Offset > offset) {
+ // Insert before this one.
+ break;
+ } else if (ent.Offset == offset) {
+ // We share a start point with this entry. See if we fit inside it or
+ // wrap around it.
+ if (length == FLOATING_LEN || ent.Length == FLOATING_LEN) {
+ // Can't share a start point with a variable-length region.
+ return AddResult.OverlapFloating;
+ } else if (ent.Length == length) {
+ // Same offset/length as existing entry.
+ return AddResult.OverlapExisting;
+ } else if (ent.Length < length) {
+ // New region is larger, would become parent, so insert before this.
+ break;
+ } else {
+ // New region is smaller and will be a child of this entry, so we want
+ // to insert *after* this point. Loop again to see if the following
+ // entry is also a parent for this new one.
+ Debug.Assert(ent.Length > length);
+ }
}
}
- return mAddrList.Count - 1;
+ // The insertion index indicates the entry we want to insert before. We need to
+ // confirm that the new block doesn't straddle the blocks on either side. If we're
+ // inserting into a bunch of blocks with coincident start points, it's possible for
+ // the blocks appearing before and after to share the same start offset.
+
+ if (insIdx > 0) {
+ // Check previous block. We know that its offset is <= the new offset, so
+ // either its a parent or a sibling.
+ AddressMapEntry ent = mRegionList[insIdx - 1];
+ if (ent.Offset == offset) {
+ // Previous is our parent. These things were checked earlier.
+ Debug.Assert(length != FLOATING_LEN && ent.Length != FLOATING_LEN);
+ Debug.Assert(ent.Length > length);
+ } else {
+ // Existing block starts before this new one. The existing block must either
+ // be floating, be completely before this, or completely envelop this.
+ Debug.Assert(ent.Offset < offset);
+ if (ent.Length == FLOATING_LEN) {
+ // sibling -- must end before us
+ } else if (ent.Offset + ent.Length <= offset) {
+ // sibling
+ } else if (length == FLOATING_LEN) {
+ // existing is parent, we stop at their end
+ } else if (ent.Offset + ent.Length >= offset + length) {
+ // existing is parent, ending at or after our end
+ } else {
+ // whoops
+ return AddResult.StraddleExisting;
+ }
+ }
+ }
+ if (insIdx < mRegionList.Count) {
+ // Check following block. We know that its offset is >= the new offset, so it's
+ // either a child or a sibling.
+ AddressMapEntry ent = mRegionList[insIdx];
+ if (ent.Offset == offset) {
+ // Following block is our child. These things were checked earlier.
+ Debug.Assert(length != FLOATING_LEN && ent.Length != FLOATING_LEN);
+ Debug.Assert(ent.Length < length);
+ } else {
+ // Existing block starts after this new one. The existing block must either
+ // be floating, be completely after this, or be completely enveloped by this.
+ Debug.Assert(ent.Offset > offset);
+ if (ent.Length == FLOATING_LEN) {
+ // child or sibling, depending on start offset
+ } else if (offset + length <= ent.Offset) {
+ // sibling
+ } else if (length == FLOATING_LEN) {
+ // sibling
+ } else if (ent.Offset + ent.Length <= offset + length) {
+ // existing is child, ending at or before our end
+ } else {
+ // whoops
+ return AddResult.StraddleExisting;
+ }
+ }
+ }
+
+ mRegionList.Insert(insIdx, newEntry);
+ Regenerate();
+ return AddResult.Okay;
}
///
- /// Adds, updates, or removes a map entry.
+ /// Edits the region with the specified offset/len, changing the values of addr and isRel.
///
- /// File offset at which the address changes.
- /// 24-bit address.
- public void Set(int offset, int addr) {
- Debug.Assert(offset >= 0);
- if (addr == NO_ENTRY_ADDR) {
- if (offset != 0) { // ignore attempts to remove entry at offset zero
- Remove(offset);
- }
- return;
+ /// Offset of region to edit.
+ /// Length of region to edit.
+ /// New value for address.
+ /// New value for IsRelative.
+ /// True if a region was edited, false otherwise.
+ public bool EditRegion(int offset, int length, int addr, bool isRelative) {
+ if (!ValidateArgs(offset, length, addr)) {
+ throw new Exception("Bad EditRegion args +" + offset.ToString("x6") +
+ " " + length + " $" + addr);
}
- Debug.Assert(addr >= 0 && addr < 0x01000000); // 24-bit address space
- int i;
- for (i = 0; i < mAddrList.Count; i++) {
- AddressMapEntry ad = mAddrList[i];
- if (ad.Offset == offset) {
- // update existing
- mAddrList[i] = new AddressMapEntry(ad.Offset, addr, ad.Length);
- return;
- } else if (ad.Offset > offset) {
- // The i'th entry is one past the interesting part.
+ int idx = FindRegion(offset, length);
+ if (idx < 0) {
+ return false;
+ }
+ mRegionList[idx] = new AddressMapEntry(offset, length, addr, length == FLOATING_LEN,
+ isRelative);
+ Regenerate();
+ return true;
+ }
+
+ ///
+ /// Removes the region with the specified offset/len.
+ ///
+ /// Offset of region to remove.
+ /// Length of region to remove.
+ /// True if a region was removed, false otherwise.
+ public bool RemoveRegion(int offset, int length) {
+ if (!ValidateArgs(offset, length, 0)) {
+ throw new Exception("Bad RemoveRegion args +" + offset.ToString("x6") +
+ " " + length);
+ }
+
+ int idx = FindRegion(offset, length);
+ if (idx < 0) {
+ return false;
+ }
+ mRegionList.RemoveAt(idx);
+ Regenerate();
+ return true;
+ }
+
+ ///
+ /// Finds a region with a matching offset and length.
+ ///
+ /// Offset to match.
+ /// Length to match (may be FLOATING_LEN).
+ /// Index of matching region, or -1 if not found.
+ private int FindRegion(int offset, int length) {
+ for (int i = 0; i < mRegionList.Count; i++) {
+ if (mRegionList[i].Offset == offset && mRegionList[i].Length == length) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // Returns true if adding the specified region is a valid action.
+ // ??? do we want to do this, or just ask "does region exist"? Depends on
+ // flow in edit dialog.
+ //public bool CanAddRegion(int offset, int length) {
+ // return false;
+ //}
+
+ ///
+ /// Gets the first region with the specified offset and length.
+ ///
+ ///
+ ///
+ ///
+ //public AddressMapEntry GetFirstRegion(int offset, int length) {
+ // int idx = FindRegion(offset, length);
+ // if (idx < 0) {
+ // return null;
+ // } else {
+ // return mRegionList[idx];
+ // }
+ //}
+
+ ///
+ /// Gets a list of the regions with the specified offset value.
+ ///
+ /// File offset.
+ /// List of entries; may be empty.
+ public List GetRegions(int offset) {
+ List regions = new List();
+ for (int i = 0; i < mRegionList.Count; i++) {
+ if (mRegionList[i].Offset == offset) {
+ regions.Add(mRegionList[i]);
+ }
+ if (mRegionList[i].Offset > offset) {
+ // Regions are in sorted order, we're done.
break;
}
}
-
- // Carve a chunk out of the previous entry.
- AddressMapEntry prev = mAddrList[i - 1];
- int prevOldLen = prev.Length;
- int prevNewLen = offset - prev.Offset;
- mAddrList[i - 1] = new AddressMapEntry(prev.Offset, prev.Addr, prevNewLen);
-
- mAddrList.Insert(i,
- new AddressMapEntry(offset, addr, prevOldLen - prevNewLen));
-
- DebugValidate();
+ return regions;
}
///
- /// Removes an entry from the set.
+ /// Regenerates sub-structures after every change.
///
- /// The initial offset of the mapping to remove. This
- /// must be the initial value, not a mid-range value.
- /// True if something was removed.
- public bool Remove(int offset) {
- if (offset == 0) {
- throw new Exception("Not allowed to remove entry 0");
+ private void Regenerate() {
+ GenerateTree();
+ GenerateLinear();
+ Debug.Assert(DebugValidate());
+ }
+
+ ///
+ /// Performs internal consistency checks. Prints a message and returns false on failure.
+ ///
+ private bool DebugValidate() {
+ bool result = true;
+ result &= DebugValidateStructural();
+ result &= DebugValidateHierarchical();
+ return result;
+ }
+
+ private bool DebugValidateStructural() {
+ int lastStart = -1;
+ int lastLength = OFFSET_MAX + 1;
+ for (int i = 0; i < mRegionList.Count; i++) {
+ AddressMapEntry ent = mRegionList[i];
+
+ // Do basic range checks on arguments.
+ if (ent.Offset < 0 || ent.Offset > OFFSET_MAX) {
+ Debug.WriteLine("Bad offset +" + ent.Offset.ToString("x6"));
+ return false;
+ }
+ if (ent.Length <= 0 && ent.Length != FLOATING_LEN) {
+ Debug.WriteLine("Bad length " + ent.Length);
+ return false;
+ }
+ if (ent.Length > OFFSET_MAX || (long)ent.Offset + (long)ent.Length > OFFSET_MAX) {
+ Debug.WriteLine("Bad length +" + ent.Offset.ToString("x6") +
+ " len=" + ent.Length);
+ return false;
+ }
+ if ((ent.Address < 0 && ent.Address != NON_ADDR) || ent.Address > ADDR_MAX) {
+ Debug.WriteLine("Bad address $" + ent.Address.ToString("x4"));
+ return false;
+ }
+
+ // Compare to EOF.
+ if (ent.Length != FLOATING_LEN && ent.Offset + ent.Length > mSpanLength) {
+ Debug.WriteLine("Entry exceeds file bounds");
+ return false;
+ }
+
+ // Verify ordering.
+ if (ent.Offset < lastStart) {
+ Debug.WriteLine("Bad sort: start");
+ return false;
+ } else if (ent.Offset == lastStart) {
+ if (ent.Length == FLOATING_LEN || lastLength == FLOATING_LEN) {
+ Debug.WriteLine("Overlapping float and non-float");
+ return false;
+ }
+ if (ent.Length == lastLength) {
+ Debug.WriteLine("Overlapping regions");
+ return false;
+ } else if (ent.Length > lastLength) {
+ Debug.WriteLine("Bad sort: end");
+ return false;
+ }
+ }
+ lastStart = ent.Offset;
+ lastLength = ent.Length;
+ }
+ return true;
+ }
+
+ public override string ToString() {
+ return "[AddressMap: " + mRegionList.Count + " entries]";
+ }
+
+ #endregion Structural
+
+ #region Hierarchical
+
+ ///
+ /// Tree data structure. Only visible internally.
+ ///
+ ///
+ /// Modifications are rare and trees are expected to be small, so the entire tree is
+ /// reconstructed whenever a change is made.
+ ///
+ /// We can reference the AddressMapEntry objects from the structural list unless it
+ /// has a floating length. If it does, we create a new one with the actual length.
+ ///
+ private class TreeNode {
+ public AddressMapEntry Entry { get; set; }
+ public TreeNode Parent { get; set; }
+ public List Children { get; set; }
+
+ public TreeNode(AddressMapEntry entry, TreeNode parent) {
+ Entry = entry;
+ Parent = parent;
+ // all other fields null/false
+ }
+ }
+
+ ///
+ /// Top of the hierarchy. The topmost node is a no-address node that spans the entire
+ /// file.
+ ///
+ private TreeNode mTopNode;
+
+
+ ///
+ /// Generates a tree that spans the entire region.
+ ///
+ private void GenerateTree() {
+ // Create a "fake" node that spans the file, so that any region not covered
+ // explicitly is caught here. It also avoids the need to special-case the top
+ // part of the file.
+ AddressMapEntry globalEnt = new AddressMapEntry(0, mSpanLength, NON_ADDR, false, false);
+ TreeNode topNode = new TreeNode(globalEnt, null);
+
+ // Generate the children of this node.
+ int index = -1;
+ GenerateChildren(topNode, ref index);
+
+ if (index != mRegionList.Count) {
+ Debug.Assert(false, "Not all regions traversed");
}
- for (int i = 1; i < mAddrList.Count; i++) {
- if (mAddrList[i].Offset == offset) {
- // Add the length to the previous entry.
- AddressMapEntry prev = mAddrList[i - 1];
- mAddrList[i - 1] = new AddressMapEntry(prev.Offset, prev.Addr,
- prev.Length + mAddrList[i].Length);
+ // Replace previous tree.
+ mTopNode = topNode;
+ }
- mAddrList.RemoveAt(i);
- DebugValidate();
- return true;
+ ///
+ /// Generates a tree node for the specified region. This might be a single item, or
+ /// the top of a tree.
+ ///
+ /// Parent of this node. May be null for top-level entries.
+ /// On entry, index of current (parent) node. On exit, index of
+ /// region that is past the tree spanned by this node.
+ /// Newly-created node.
+ private void GenerateChildren(TreeNode parent, ref int index) {
+ List children = new List();
+
+ index++;
+ while (index < mRegionList.Count) {
+ AddressMapEntry childEnt = mRegionList[index];
+
+ if (childEnt.Offset >= parent.Entry.Offset + parent.Entry.Length) {
+ // Starts after end of parent, not a child.
+ break;
+ }
+
+ if (childEnt.Length == FLOATING_LEN) {
+ // Compute actual length. We stop at the end of the parent, or at the start
+ // of the following region, whichever comes first.
+ //
+ // Regions with floating ends can't have children, so we don't need to
+ // check for sub-regions.
+ int nextStart = parent.Entry.Offset + parent.Entry.Length;
+ index++;
+ if (index < mRegionList.Count) {
+ // Check next sibling.
+ int sibStart = mRegionList[index].Offset;
+ if (sibStart < nextStart) {
+ nextStart = sibStart;
+ }
+ }
+ AddressMapEntry fixedEnt = new AddressMapEntry(childEnt.Offset,
+ nextStart - childEnt.Offset, childEnt.Address, true, childEnt.IsRelative);
+ children.Add(new TreeNode(fixedEnt, parent));
+
+ // "index" now points to entry past the child we just added.
+ } else {
+ // Add this region to the list, and check for descendants.
+ TreeNode thisNode = new TreeNode(childEnt, parent);
+ children.Add(thisNode);
+
+ // Check for grandchildren. "index" will point to first entry beyond this
+ // child and its descendants.
+ GenerateChildren(thisNode, ref index);
}
}
- return false;
+
+ // Set child list if it's non-empty.
+ if (children.Count > 0) {
+ parent.Children = children;
+ }
}
- ///
- /// Returns true if the given address falls into the range spanned by the
- /// address map entry.
- ///
- /// Address map entry index.
- /// Address to check.
- ///
- private bool IndexContainsAddress(int index, int addr) {
- return addr >= mAddrList[index].Addr &&
- addr < mAddrList[index].Addr + mAddrList[index].Length;
- }
+ /*
+ Thoughts on AddressToOffset optimization...
+
+ We can create a simple linear range map, but we have to do it separately for
+ every node in the tree (i.e. every unique srcOffset). We can do this on demand.
+
+ The idea would be to find the leaf node for the source offset, add the address
+ range for that node, and then expand outward as we would do when attempting to
+ resolve an address. As we traverse each node we add the address ranges to the
+ set, but we don't replace existing entries. (In some cases a single entry may
+ generate multiple disjoint ranges if it overlaps several things.)
+
+ Once the map is generated, we store a reference to it in the tree node, and then
+ use that for all future lookups. Since changes to the tree are rare, and we only
+ generate these tables on the first series of lookups after a change, the overhead
+ of generating these should be small. Since it's a list of address ranges
+ (similar in principle to TypedRangeSet), it shouldn't be very large, even for
+ larger address spaces.
+ */
///
/// Determines the file offset that best contains the specified target address.
///
+ ///
+ /// Algorithm:
+ /// - Start in the node that contains the source offset.
+ /// - Loop:
+ /// - Recursively scan all children of the current node, in order of increasing Offset.
+ /// - Check the current node. If it matches, we're done.
+ /// - Move up to the parent.
+ /// - If we run off the top of the tree, return -1.
+ ///
+ /// We're doing a depth-first search, checking the children before the current node.
+ ///
+ /// Because each node holds an arbitrary address range, we need to search all of them.
+ /// There is no early-exit for the not-found case.
+ ///
+ /// We can't simply compare the Address/Length values to check for a match, because
+ /// children may have created "holes". If the address falls in a node's range, we need
+ /// to walk the child list and see if the address is present.
+ ///
/// Offset of the address reference.
/// Address to look up.
/// The file offset, or -1 if the address falls outside the file.
public int AddressToOffset(int srcOffset, int targetAddr) {
- if (mAddrList.Count == 1) {
- // Trivial case.
- if (IndexContainsAddress(0, targetAddr)) {
- Debug.Assert(targetAddr >= mAddrList[0].Addr);
- return targetAddr - mAddrList[0].Addr;
- } else {
+ TreeNode startNode = OffsetToNode(srcOffset, mTopNode);
+
+ TreeNode ignoreNode = null;
+ while (true) {
+ int offset = FindAddress(startNode, ignoreNode, targetAddr);
+ if (offset >= 0) {
+ // Return the offset we found.
+ return offset;
+ }
+
+ // Didn't find it. Move up one level, but ignore the branch we've already checked.
+ ignoreNode = startNode;
+ startNode = startNode.Parent;
+ if (startNode == null) {
return -1;
}
}
+ }
- // We have multiple, potentially overlapping address ranges. Start by
- // looking for a match in the srcOffset range; if that fails, scan
- // forward from the start.
- int srcOffIndex = IndexForOffset(srcOffset);
- if (IndexContainsAddress(srcOffIndex, targetAddr)) {
- Debug.Assert(targetAddr >= mAddrList[srcOffIndex].Addr);
- return (targetAddr - mAddrList[srcOffIndex].Addr) + mAddrList[srcOffIndex].Offset;
- }
-
- for (int i = 0; i < mAddrList.Count; i++) {
- if (i == srcOffIndex) {
- // optimization -- we already checked this one
- continue;
- }
- if (IndexContainsAddress(i, targetAddr)) {
- Debug.Assert(targetAddr >= mAddrList[i].Addr);
- return (targetAddr - mAddrList[i].Addr) + mAddrList[i].Offset;
+ ///
+ /// Finds a matching address range, starting from a specific point in the tree and
+ /// searching downward. One child can be ignored.
+ ///
+ /// Start point.
+ /// Child to ignore (because it was examined earlier).
+ /// Address to find.
+ /// Offset, or -1 if not found.
+ private int FindAddress(TreeNode node, TreeNode ignore, int targetAddr) {
+ if (node.Children != null) {
+ foreach (TreeNode childNode in node.Children) {
+ if (childNode == ignore) {
+ continue;
+ }
+ int offset = FindAddress(childNode, null, targetAddr);
+ if (offset >= 0) {
+ // Found match in child, return that.
+ return offset;
+ }
}
}
- return -1;
+ // Wasn't in any of the children, see if it's in this node.
+ AddressMapEntry ent = node.Entry;
+ if (ent.Address == NON_ADDR) {
+ // Non-addressable space.
+ return -1;
+ }
+ if (targetAddr < ent.Address || targetAddr >= ent.Address + ent.Length) {
+ // Outside our range of addresses, return failure.
+ return -1;
+ }
+
+ // We span the correct range of addresses. See if the requested address
+ // falls into a hole spanned by a child.
+ if (node.Children != null) {
+ int subPosn = targetAddr - ent.Address; // position of target inside node
+ foreach (TreeNode childNode in node.Children) {
+ AddressMapEntry childEnt = childNode.Entry;
+ int childStartPosn = childEnt.Offset - ent.Offset;
+ int childEndPosn = childStartPosn + childEnt.Length;
+
+ if (childStartPosn > subPosn) {
+ // Child is past the target, it's not in a hole; no need to check
+ // additional children because the children are sorted by Offset.
+ break;
+ } else if (subPosn >= childStartPosn && subPosn < childEndPosn) {
+ // Target is in a hole occupied by the child. No good.
+ return -1;
+ }
+ }
+ }
+ return ent.Offset + (targetAddr - ent.Address);
}
///
/// Converts a file offset to an address.
///
/// File offset.
- /// 24-bit address.
+ /// 24-bit address, which may be NON_ADDR.
public int OffsetToAddress(int offset) {
- int srcOffIndex = IndexForOffset(offset);
- return mAddrList[srcOffIndex].Addr + (offset - mAddrList[srcOffIndex].Offset);
+ if (offset < 0 || offset >= mSpanLength) {
+ // Invalid offset. Could throw or return an error.
+ Debug.WriteLine("Warning: OffsetToAddress invalid offset +" +
+ offset.ToString("x6"));
+ return NON_ADDR;
+ }
+
+ // Scan tree to find appropriate node. The tree is guaranteed to cover all offsets.
+ TreeNode node = OffsetToNode(offset, mTopNode);
+
+ // Calculate address in this node.
+ int ourAddr = NON_ADDR;
+ if (node.Entry.Address != NON_ADDR) {
+ ourAddr = node.Entry.Address + (offset - node.Entry.Offset);
+ Debug.Assert(ourAddr < node.Entry.Address + node.Entry.Length);
+ }
+ return ourAddr;
}
///
- /// Checks to see if the specified range of offsets is in a single address range. Use
- /// this to see if something crosses an address-change boundary. This does not
- /// handle no-op address changes specially.
+ /// Recursively descends into the tree to find the node that contains the offset.
///
+ /// File offset.
+ /// Node to examine.
+ /// Matching node.
+ private TreeNode OffsetToNode(int offset, TreeNode node) {
+ if (node.Children != null) {
+ foreach (TreeNode child in node.Children) {
+ AddressMapEntry childEnt = child.Entry;
+ if (offset >= childEnt.Offset && offset < childEnt.Offset + childEnt.Length) {
+ // It's in or below this child. Check it with tail recursion.
+ return OffsetToNode(offset, child);
+ }
+ }
+ }
+ return node;
+ }
+
+ ///
+ /// Checks to see if the specified range of offsets is in an uninterrupted address
+ /// range. Use this to see if something crosses an address-change boundary. This
+ /// does not smooth over no-op address changes.
+ ///
+ ///
+ /// 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 .ORG 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
+ /// then check to see if there are any children that start between the two.
+ /// 2. Walk through the linear list and see if there are any events between offset
+ /// and offset+length.
+ /// Walking the linear list is simpler but likely slower.
+ ///
/// Start offset.
/// Length of region.
- /// True if the data area is unbroken.
- public bool IsSingleAddrRange(int offset, int length) {
- Debug.Assert(offset >= 0 && offset < mTotalLength);
- Debug.Assert(length > 0 && offset + length <= mTotalLength);
- return (IndexForOffset(offset) == IndexForOffset(offset + length - 1));
+ /// True if the range of offsets is unbroken.
+ public bool IsRangeUnbroken(int offset, int length) {
+ if (!ValidateArgs(offset, length, 0)) {
+ Debug.Assert(false, "Invalid args to IsUnbrokenRange");
+ return true; // most ranges are unbroken, so just go with that
+ }
+
+ TreeNode node = OffsetToNode(offset, mTopNode);
+ AddressMapEntry ent = node.Entry;
+ Debug.Assert(offset >= ent.Offset && offset < ent.Offset + ent.Length);
+ int lastOffset = offset + length - 1; // offset of last byte in range
+ if (lastOffset >= ent.Offset + ent.Length) {
+ // end of region is not in this node
+ return false;
+ }
+
+ // The specified range fits inside this node. See if it's interrupted by a child.
+ if (node.Children != null) {
+ foreach (TreeNode childNode in node.Children) {
+ AddressMapEntry childEnt = childNode.Entry;
+
+ if (childEnt.Offset > lastOffset) {
+ // Child is past the target, so range is not in a hole; no need to check
+ // additional children because the children are sorted by Offset.
+ break;
+ } else if (offset <= childEnt.Offset + childEnt.Length - 1 &&
+ lastOffset >= childEnt.Offset) {
+ // Target is in a hole occupied by the child. No good.
+ return false;
+ }
+ }
+ }
+
+ return true;
}
+ private bool DebugValidateHierarchical() {
+ if (mTopNode.Entry.Offset != 0 || mTopNode.Entry.Length != mSpanLength) {
+ Debug.WriteLine("Malformed top node");
+ return false;
+ }
+
+ int nodeCount = 0;
+ if (mTopNode.Children != null) {
+ DebugValidateHierarchy(mTopNode.Children, 0, mSpanLength, ref nodeCount);
+ }
+
+ // Check node count. It should have one entry for every entry in the region list
+ // (we don't count mTopNode).
+ if (nodeCount != mRegionList.Count) {
+ Debug.WriteLine("Hierarchical is missing entries: nodeCount=" + nodeCount +
+ " regionCount=" + mRegionList.Count);
+ return false;
+ }
+ return true;
+ }
+
+ private bool DebugValidateHierarchy(List nodeList, int startOffset,
+ int nextOffset, ref int nodeCount) {
+ foreach (TreeNode node in nodeList) {
+ Debug.Assert(node.Entry.Length >= 0); // no floaters
+
+ nodeCount++;
+
+ if (node.Entry.Offset < startOffset ||
+ node.Entry.Offset + node.Entry.Length > nextOffset) {
+ Debug.WriteLine("Child node did not fit in parent bounds");
+ return false;
+ }
+ if (node.Children != null) {
+ // Descend recursively.
+ if (!DebugValidateHierarchy(node.Children, node.Entry.Offset,
+ node.Entry.Offset + node.Entry.Length, ref nodeCount)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ #endregion Hierarchical
+
+ #region Linear
///
- /// Internal consistency checks.
+ /// Ordered list of change events.
///
- private void DebugValidate() {
- if (mAddrList.Count < 1) {
- throw new Exception("AddressMap: empty");
- }
- if (mAddrList[0].Offset != 0) {
- throw new Exception("AddressMap: bad offset 0");
- }
+ private List mChangeList = new List();
- if (mAddrList.Count == 1) {
- if (mAddrList[0].Length != mTotalLength) {
- throw new Exception("AddressMap: single entry len bad");
- }
- } else {
- int totalLen = 0;
- for (int i = 0; i < mAddrList.Count; i++) {
- AddressMapEntry ent = mAddrList[i];
- if (i != 0) {
- if (ent.Offset != mAddrList[i - 1].Offset + mAddrList[i - 1].Length) {
- throw new Exception("Bad offset step to " + i);
- }
+ ///
+ /// Address change "event".
+ ///
+ /// Instances are immutable.
+ ///
+ public class AddressChange {
+ // True if this is a region start, false if a region end.
+ public bool IsStart { get; private set; }
+
+ // Offset at which change occurs. For end points, this at the offset AFTER
+ // the last offset in a region.
+ public int Offset { get; private set; }
+
+ // Address at Offset after change. For a region-end change, this is an address
+ // in the parent's range.
+ public int Address { get; private set; }
+
+ // Reference to the AddressMapEntry that generated this entry. The reference
+ // will be the same for the "start" and "end" entries.
+ public AddressMapEntry Entry { get; private set; }
+
+ public AddressChange(bool isStart, int offset, int addr, AddressMapEntry ent) {
+ IsStart = isStart;
+ Offset = offset;
+ Address = addr;
+ Entry = ent;
+ }
+ }
+
+ ///
+ /// Generates a linear list of changes, using the data from the hierarchical representation.
+ ///
+ private void GenerateLinear() {
+ // The top layer is treated specially, because we don't want to show the outer
+ // no-address zone. Instead, we synthesize fake zones in the gaps.
+ List changeList = new List();
+ int startOffset = 0;
+ int extraNodes = 0;
+
+ if (mTopNode.Children != null) {
+ foreach (TreeNode node in mTopNode.Children) {
+ Debug.Assert(node.Entry.Length > 0); // all floaters should be resolved
+
+ if (node.Entry.Offset != startOffset) {
+ // Insert a no-address zone here.
+ Debug.Assert(node.Entry.Offset > startOffset);
+ AddressMapEntry tmpEnt = new AddressMapEntry(startOffset,
+ node.Entry.Offset - startOffset, NON_ADDR, false, false);
+ changeList.Add(new AddressChange(true, startOffset, NON_ADDR, tmpEnt));
+ changeList.Add(new AddressChange(false, node.Entry.Offset, NON_ADDR, tmpEnt));
+ extraNodes++;
}
- totalLen += ent.Length;
+ AddChangeEntry(changeList, node, NON_ADDR);
+
+ startOffset = node.Entry.Offset + node.Entry.Length;
+ }
+ }
+
+ // Finish with a no-address zone if there's a gap.
+ if (startOffset != mSpanLength) {
+ Debug.Assert(startOffset < mSpanLength);
+ AddressMapEntry tmpEnt = new AddressMapEntry(startOffset,
+ mSpanLength - startOffset, NON_ADDR, false, false);
+ changeList.Add(new AddressChange(true, startOffset, NON_ADDR, tmpEnt));
+ changeList.Add(new AddressChange(false, mSpanLength, NON_ADDR, tmpEnt));
+ extraNodes++;
+ }
+
+ if (changeList.Count != (mRegionList.Count + extraNodes) * 2) {
+ Debug.Assert(false, "Incorrect linear count: regions*2=" + (mRegionList.Count * 2) +
+ " extraNodes=" + extraNodes + " changeList=" + changeList.Count);
+ }
+
+ mChangeList = changeList;
+ }
+
+ public IEnumerator AddressChangeIterator {
+ get { return mChangeList.GetEnumerator(); }
+ }
+
+ ///
+ /// Recursively adds tree nodes.
+ ///
+ /// List to which changes are added.
+ /// Node to add
+ /// Address at which node's start offset appears in
+ /// parent's region.
+ private void AddChangeEntry(List changeList, TreeNode node,
+ int parentStartAddr) {
+ Debug.Assert(node.Entry.Length != FLOATING_LEN);
+ int nextAddr = NON_ADDR;
+ if (parentStartAddr != NON_ADDR) {
+ nextAddr = parentStartAddr + node.Entry.Length;
+ }
+ AddressChange startChange = new AddressChange(true,
+ node.Entry.Offset, node.Entry.Address, node.Entry);
+ AddressChange endChange = new AddressChange(false,
+ node.Entry.Offset + node.Entry.Length, nextAddr, node.Entry);
+
+ changeList.Add(startChange);
+ int curAddr = node.Entry.Address;
+ if (node.Children != null) {
+ foreach (TreeNode childNode in node.Children) {
+ int mySpaceAddr = NON_ADDR;
+ if (curAddr != NON_ADDR) {
+ // Adjust address in parent space by difference between start of
+ // parent and start of this node.
+ mySpaceAddr = curAddr + childNode.Entry.Offset - node.Entry.Offset;
+ }
+ AddChangeEntry(changeList, childNode, mySpaceAddr);
+ }
+ }
+ changeList.Add(endChange);
+ }
+
+ private const string CRLF = "\r\n";
+
+ ///
+ /// Formats the address map for debugging. (Does not use Asm65.Formatter, so is not
+ /// suitable for display to the user.)
+ ///
+ public string FormatAddressMap() {
+ StringBuilder sb = new StringBuilder();
+ int depth = 0;
+ AddressChange prevChange = null;
+
+ sb.AppendLine("Address map, len=$" + mSpanLength.ToString("x4"));
+ IEnumerator iter = this.AddressChangeIterator;
+ while (iter.MoveNext()) {
+ AddressChange change = iter.Current;
+ if (change.IsStart) {
+ if (prevChange != null && change.Offset != prevChange.Offset) {
+ // Start of region at new offset. Output address info for space
+ // between previous start or end.
+ PrintAddressInfo(sb, depth, prevChange.Address,
+ change.Offset - prevChange.Offset);
+ }
+
+ // Start following end, or start following start after a gap.
+ PrintDepthLines(sb, depth);
+ sb.Append("+- +" + change.Offset.ToString("x6") + " START (");
+ PrintAddress(sb, change.Address);
+ sb.Append(")");
+ sb.Append(CRLF);
+
+ depth++;
+ } else {
+ Debug.Assert(prevChange != null);
+ depth--;
+
+ if (change.Offset != prevChange.Offset) {
+ // End of region at new offset. Output address info for space
+ // between previous start or end.
+ PrintAddressInfo(sb, depth + 1, prevChange.Address,
+ change.Offset - prevChange.Offset);
+ }
+
+ PrintDepthLines(sb, depth);
+ sb.Append("+- +" + change.Offset.ToString("x6") + " END (now ");
+ PrintAddress(sb, change.Address);
+ sb.Append(")");
+ sb.Append(CRLF);
}
- if (totalLen != mTotalLength) {
- throw new Exception("AddressMap: bad length sum (" + totalLen + " vs " +
- mTotalLength + ")");
- }
+ prevChange = change;
+ }
+ Debug.Assert(depth == 0);
+
+ return sb.ToString();
+ }
+
+ private static void PrintDepthLines(StringBuilder sb, int depth) {
+ while (depth-- > 0) {
+ sb.Append("| ");
}
}
- public override string ToString() {
- return "[AddressMap: " + mAddrList.Count + " entries]";
+ private static void PrintAddressInfo(StringBuilder sb, int depth,
+ int startAddr, int length) {
+ PrintDepthLines(sb, depth);
+ sb.Append(' ');
+ if (startAddr == NON_ADDR) {
+ sb.Append("-NA-");
+ } else {
+ PrintAddress(sb, startAddr);
+ sb.Append(" - ");
+ PrintAddress(sb, startAddr + length - 1);
+ }
+ sb.Append(" (length=$" + length.ToString("x4") + "/" + length + " bytes)");
+ sb.Append(CRLF);
}
+
+ private static void PrintAddress(StringBuilder sb, int addr) {
+ if (addr == NON_ADDR) {
+ sb.Append("-NA-");
+ } else {
+ sb.Append("$");
+ sb.Append(addr.ToString("x4"));
+ }
+ }
+
+ #endregion Linear
+
+ #region Unit tests
+
+ private static void Test_Expect(AddResult expected, ref bool result, AddResult actual) {
+ if (expected != actual) {
+ Debug.WriteLine("test failed (expected=" + expected + ", actual=" + actual + ")");
+ result = false;
+ }
+ }
+ private static void Test_Expect(bool expected, ref bool result, bool actual) {
+ if (expected != actual) {
+ Debug.WriteLine("test failed (expected=" + expected + ", actual=" + actual + ")");
+ result = false;
+ }
+ }
+
+ private static void Test_Expect(int expected, ref bool result, int actual) {
+ if (expected != actual) {
+ Debug.WriteLine("test failed (expected=$" + expected.ToString("x4") + "/" +
+ expected + ", actual=$" + actual.ToString("x4") + "/" + actual + ")");
+ result = false;
+ }
+ }
+
+ private static bool Test_SimpleLinear() {
+ const int mapLen = 0x8000;
+ AddressMap map = new AddressMap(mapLen);
+ bool result = true;
+
+ const int off0 = 0x000000;
+ const int len0 = 0x0200;
+ const int adr0 = 0x1000;
+ const int off1 = 0x000200;
+ const int len1 = 0x0500;
+ const int adr1 = 0x1200;
+ const int off2 = 0x000700;
+ const int len2 = 0x0300;
+ const int adr2 = 0x1700;
+
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off0, len0, adr0, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off1, len1, adr1, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off2, len2, adr2, false));
+ result &= map.DebugValidate();
+
+ Test_Expect(AddResult.OverlapExisting, ref result,
+ map.AddRegion(off0, len0, 0x1000, false));
+ Test_Expect(AddResult.OverlapFloating, ref result,
+ map.AddRegion(off0, FLOATING_LEN, 0x1000, false));
+ Test_Expect(AddResult.StraddleExisting, ref result,
+ map.AddRegion(off0 + 1, len0, 0x1000, false));
+ Test_Expect(AddResult.InvalidValue, ref result,
+ map.AddRegion(off0, mapLen + 1, 0x1000, false));
+
+ // One region to wrap them all. Add then remove.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off0, mapLen, 0x0000, false));
+ Test_Expect(true, ref result, map.RemoveRegion(off0, mapLen));
+ Test_Expect(false, ref result, map.RemoveRegion(off0, mapLen));
+
+ Test_Expect(adr0, ref result, map.OffsetToAddress(off0));
+ Test_Expect(adr1, ref result, map.OffsetToAddress(off1));
+ Test_Expect(adr2, ref result, map.OffsetToAddress(off2));
+ Test_Expect(adr0 + 0x100, ref result, map.OffsetToAddress(off0 + 0x100));
+ Test_Expect(NON_ADDR, ref result, map.OffsetToAddress(0x004000)); // hole in map
+ Test_Expect(NON_ADDR, ref result, map.OffsetToAddress(mapLen)); // bad offset
+
+ Test_Expect(0x000000, ref result, map.AddressToOffset(0x000000, 0x1000));
+ Test_Expect(0x000000, ref result, map.AddressToOffset(0x000200, 0x1000));
+ Test_Expect(0x000000, ref result, map.AddressToOffset(0x000700, 0x1000));
+ Test_Expect(0x000250, ref result, map.AddressToOffset(0x000000, 0x1250));
+ Test_Expect(0x000250, ref result, map.AddressToOffset(0x000200, 0x1250));
+ Test_Expect(0x000250, ref result, map.AddressToOffset(0x000700, 0x1250));
+ Test_Expect(0x0009ff, ref result, map.AddressToOffset(0x0001ff, 0x19ff));
+ Test_Expect(0x0009ff, ref result, map.AddressToOffset(0x0006ff, 0x19ff));
+ Test_Expect(0x0009ff, ref result, map.AddressToOffset(0x0009ff, 0x19ff));
+ Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0x7000));
+
+ result &= map.DebugValidate();
+ return result;
+ }
+
+ private static bool Test_SimpleFloatGap() {
+ const int mapLen = 0x8000;
+ AddressMap map = new AddressMap(mapLen);
+ bool result = true;
+
+ const int off0 = 0x001000;
+ const int len0 = FLOATING_LEN;
+ const int adr0 = 0x1000;
+ const int off1 = 0x004000;
+ const int len1 = 0x3000;
+ const int adr1 = 0x1200;
+ const int off2 = 0x005000;
+ const int len2 = 0x0100;
+ const int adr2 = NON_ADDR;
+
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off0, len0, adr0, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off1, len1, adr1, false));
+
+ // Try to remove the implicit no-address zone.
+ Test_Expect(false, ref result, map.RemoveRegion(0, off0));
+
+ // Add non-addressable area into the middle of the second region.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(off2, len2, adr2, false));
+
+ Test_Expect(adr0, ref result, map.OffsetToAddress(off0));
+ Test_Expect(adr1, ref result, map.OffsetToAddress(off1));
+ Test_Expect(adr2, ref result, map.OffsetToAddress(off2));
+ Test_Expect(adr0 + 1, ref result, map.OffsetToAddress(off0 + 1));
+ Test_Expect(adr1 + len2, ref result, map.OffsetToAddress(off1 + len2));
+ Test_Expect(NON_ADDR, ref result, map.OffsetToAddress(off1 + len1));
+
+ Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0x0000));
+ Test_Expect(0x001005, ref result, map.AddressToOffset(0x000000, 0x1005));
+ // Find the "correct" $21ff.
+ Test_Expect(0x0021ff, ref result, map.AddressToOffset(0x000000, 0x21ff));
+ Test_Expect(0x004fff, ref result, map.AddressToOffset(0x004000, 0x21ff));
+ // There's only one $2205.
+ Test_Expect(0x002205, ref result, map.AddressToOffset(0x000000, 0x2205));
+ Test_Expect(0x002205, ref result, map.AddressToOffset(0x004000, 0x2205));
+
+ result &= map.DebugValidate();
+ return result;
+ }
+
+ private static bool Test_Nested() {
+ AddressMap map = new AddressMap(0x8000);
+ bool result = true;
+ // Nested with shared start offset.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000100, 0x0400, 0x4000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000100, 0x0100, 0x7000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000100, 0x0300, 0x5000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000100, 0x0200, 0x6000, false));
+ // Add a couple of floaters.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x0000ff, FLOATING_LEN, 0x30ff, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000101, FLOATING_LEN, 0x3101, false));
+ Test_Expect(AddResult.OverlapFloating, ref result,
+ map.AddRegion(0x000100, FLOATING_LEN, 0x3100, false));
+
+ // Nested with shared end offset.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000fff, FLOATING_LEN, 0x3fff, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x001200, 0x0200, 0x6000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x001000, 0x0400, 0x4000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x001100, 0x0300, 0x5000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x001300, 0x0100, 0x7000, false));
+ // Single-byte region at start and end.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x001200, 1, 0x8200, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x0013ff, 1, 0x83ff, false));
+
+ // Nested with no common edge, building from outside-in.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002000, 0x0800, 0x4000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002100, 0x0600, 0x5000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002200, 0x0400, 0x6000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002300, 0x0200, 0x7000, false));
+
+ // Nested with no common edge, building from inside-out.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x003300, 0x0200, 0x7000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x003200, 0x0400, 0x6000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x003100, 0x0600, 0x5000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x003000, 0x0800, 0x4000, false));
+
+ // Try floater then overlap.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x004000, FLOATING_LEN, 0x8000, false));
+ Test_Expect(AddResult.OverlapFloating, ref result,
+ map.AddRegion(0x004000, 0x100, 0x8000, false));
+ Test_Expect(true, ref result, map.RemoveRegion(0x004000, FLOATING_LEN));
+
+ Test_Expect(0x30ff, ref result, map.OffsetToAddress(0x0000ff));
+ Test_Expect(0x7000, ref result, map.OffsetToAddress(0x000100));
+ Test_Expect(0x3101, ref result, map.OffsetToAddress(0x000101));
+ Test_Expect(0x5000, ref result, map.OffsetToAddress(0x001100));
+ Test_Expect(0x7000, ref result, map.OffsetToAddress(0x001300));
+
+ // The first chunk has $5000, but it's a shared start with children. So we'll
+ // find it in the second chunk.
+ Test_Expect(0x001100, ref result, map.AddressToOffset(0x000000, 0x5000));
+ // It's also in the 3rd/4th chunks, so we'll find it there if we start there.
+ Test_Expect(0x002100, ref result, map.AddressToOffset(0x002300, 0x5000));
+ Test_Expect(0x003100, ref result, map.AddressToOffset(0x003000, 0x5000));
+
+ result &= map.DebugValidate();
+ return result;
+ }
+
+ private static bool Test_Cross() {
+ const int mapLen = 0x4000;
+ AddressMap map = new AddressMap(mapLen);
+ bool result = true;
+
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000000, 0x2000, 0x8000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002000, 0x2000, 0x8000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002100, 0x0200, 0xe100, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x003100, 0x0200, 0xf100, false));
+
+ Test_Expect(0x003105, ref result, map.AddressToOffset(0x000000, 0xf105));
+ Test_Expect(0x003105, ref result, map.AddressToOffset(0x002100, 0xf105));
+ Test_Expect(0x003105, ref result, map.AddressToOffset(0x003100, 0xf105));
+
+ Test_Expect(0x002105, ref result, map.AddressToOffset(0x000000, 0xe105));
+ Test_Expect(0x002105, ref result, map.AddressToOffset(0x002100, 0xe105));
+ Test_Expect(0x002105, ref result, map.AddressToOffset(0x003100, 0xe105));
+
+ // $8105 doesn't exist in the second chunk because there's a hole there. We
+ // find it in the first chunk instead.
+ Test_Expect(0x000105, ref result, map.AddressToOffset(0x000000, 0x8105));
+ Test_Expect(0x000105, ref result, map.AddressToOffset(0x002000, 0x8105));
+
+ // $8400 exists in the first chunk, and in a child of the second chunk. If
+ // we start anywhere in the second chunk we'll find the second address.
+ Test_Expect(0x000400, ref result, map.AddressToOffset(0x000000, 0x8400));
+ Test_Expect(0x002400, ref result, map.AddressToOffset(0x002000, 0x8400));
+ Test_Expect(0x002400, ref result, map.AddressToOffset(0x002100, 0x8400));
+ Test_Expect(0x002400, ref result, map.AddressToOffset(0x003100, 0x8400));
+
+ Test_Expect(0x001100, ref result, map.AddressToOffset(0x000000, 0x9100));
+
+ result &= map.DebugValidate();
+ return result;
+ }
+
+ private static bool Test_Pyramids() {
+ const int mapLen = 0xc000;
+ AddressMap map = new AddressMap(mapLen);
+ bool result = true;
+
+ // Pyramid shape, all regions start at same address except last.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x000000, 0x6000, 0x8000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x001000, 0x4000, 0x8000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x002000, 0x2000, 0x7fff, false));
+
+ // Second pyramid.
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x006000, 0x6000, 0x8000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x007000, 0x4000, 0x8000, false));
+ Test_Expect(AddResult.Okay, ref result,
+ map.AddRegion(0x008000, 0x2000, 0x8000, false));
+
+ string mapStr = map.FormatAddressMap(); // DEBUG - format the map and
+ Debug.WriteLine(mapStr); // DEBUG - print it to the console
+
+ // Children take priority over the start node.
+ Test_Expect(0x002001, ref result, map.AddressToOffset(0x000000, 0x8000));
+ Test_Expect(0x003000, ref result, map.AddressToOffset(0x000000, 0x8fff));
+ Test_Expect(0x002001, ref result, map.AddressToOffset(0x001000, 0x8000));
+ Test_Expect(0x003000, ref result, map.AddressToOffset(0x001000, 0x8fff));
+ Test_Expect(0x002001, ref result, map.AddressToOffset(0x002000, 0x8000));
+ Test_Expect(0x002000, ref result, map.AddressToOffset(0x000000, 0x7fff));
+
+ Test_Expect(0x005000, ref result, map.AddressToOffset(0x000000, 0xd000));
+ Test_Expect(0x005000, ref result, map.AddressToOffset(0x003000, 0xd000));
+
+ Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0xc000));
+ Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0xcfff));
+
+ Test_Expect(0x008000, ref result, map.AddressToOffset(0x006000, 0x8000));
+ Test_Expect(0x008000, ref result, map.AddressToOffset(0x007000, 0x8000));
+ Test_Expect(0x008000, ref result, map.AddressToOffset(0x008000, 0x8000));
+ Test_Expect(0x008000, ref result, map.AddressToOffset(0x00bfff, 0x8000));
+
+ // $7fff doesn't exist in second chunk, so we have to go back to first to find it.
+ Test_Expect(0x002000, ref result, map.AddressToOffset(0x008000, 0x7fff));
+ Test_Expect(-1, ref result, map.AddressToOffset(0x008000, 0xa000));
+
+ // inside
+ Test_Expect(true, ref result, map.IsRangeUnbroken(0x000000, 1));
+ Test_Expect(true, ref result, map.IsRangeUnbroken(0x007000, 0x0800));
+ // at edges
+ Test_Expect(true, ref result, map.IsRangeUnbroken(0x000ffe, 2));
+ Test_Expect(true, ref result, map.IsRangeUnbroken(0x001000, 2));
+ Test_Expect(true, ref result, map.IsRangeUnbroken(0x007000, 0x1000));
+ // crossing edge
+ Test_Expect(false, ref result, map.IsRangeUnbroken(0x000fff, 2));
+ // fully encapsulating
+ Test_Expect(false, ref result, map.IsRangeUnbroken(0x005500, 0x1000));
+
+ result &= map.DebugValidate();
+ return result;
+ }
+
+ public static bool Test() {
+ bool ok = true;
+ ok &= Test_SimpleLinear();
+ ok &= Test_SimpleFloatGap();
+ ok &= Test_Nested();
+ ok &= Test_Cross();
+ ok &= Test_Pyramids();
+
+ Debug.WriteLine("AddressMap: test complete (ok=" + ok + ")");
+ return ok;
+ }
+
+ #endregion Unit tests
}
}
diff --git a/PluginCommon/PluginManager.cs b/PluginCommon/PluginManager.cs
index 14da3b2..39b3826 100644
--- a/PluginCommon/PluginManager.cs
+++ b/PluginCommon/PluginManager.cs
@@ -179,11 +179,12 @@ namespace PluginCommon {
/// Invokes the Prepare() method on all active plugins.
///
/// Reference to host object providing app services.
+ /// Length of data spanned by address map.
/// Serialized AddressMap entries.
/// SymbolTable contents, converted to PlSymbol.
- public void PreparePlugins(IApplication appRef,
+ public void PreparePlugins(IApplication appRef, int spanLength,
List addrEntries, List plSyms) {
- AddressMap addrMap = new AddressMap(addrEntries);
+ AddressMap addrMap = new AddressMap(spanLength, addrEntries);
AddressTranslate addrTrans = new AddressTranslate(addrMap);
foreach (KeyValuePair kvp in mActivePlugins) {
IPlugin ipl = kvp.Value;
diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs
index 3f9ff09..f39a263 100644
--- a/SourceGen/AsmGen/AsmAcme.cs
+++ b/SourceGen/AsmGen/AsmAcme.cs
@@ -92,6 +92,20 @@ namespace SourceGen.AsmGen {
///
private StreamWriter mOutStream;
+ ///
+ /// Output mode; determines how ORG is handled.
+ ///
+ private enum OutputMode {
+ Unknown = 0, Loadable = 1, Streamable = 2
+ }
+ private OutputMode mOutputMode;
+
+ ///
+ /// Current pseudo-PC depth. 0 is the "real" PC.
+ ///
+ private int mPcDepth;
+ private bool mFirstIsOpen;
+
///
/// Holds detected version of configured assembler.
///
@@ -101,9 +115,6 @@ namespace SourceGen.AsmGen {
private static CommonUtil.Version V0_96_4 = new CommonUtil.Version(0, 96, 4);
private static CommonUtil.Version V0_97 = new CommonUtil.Version(0, 97);
- // Set if we're inside a "pseudopc" block, which will need to be closed.
- private bool mInPseudoPcBlock;
-
// v0.97 started treating '\' in constants as an escape character.
private bool mBackslashEscapes = true;
@@ -191,6 +202,20 @@ namespace SourceGen.AsmGen {
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Acme);
mColumnWidths = (int[])config.ColumnWidths.Clone();
+
+ // ACME wants the entire file to be loadable into a 64KB memory area. If the
+ // initial address is too large, a file smaller than 64KB might overrun the bank
+ // boundary and cause a failure. In that case we want to set the initial address
+ // to zero and "stream" the rest.
+ int firstAddr = project.AddrMap.OffsetToAddress(0);
+ if (firstAddr == AddressMap.NON_ADDR) {
+ firstAddr = 0;
+ }
+ if (firstAddr + project.FileDataLength > 65536) {
+ mOutputMode = OutputMode.Streamable;
+ } else {
+ mOutputMode = OutputMode.Loadable;
+ }
}
///
@@ -244,6 +269,9 @@ namespace SourceGen.AsmGen {
mLocalizer.QuirkNoOpcodeMnemonics = true;
mLocalizer.Analyze();
+ mPcDepth = 0;
+ mFirstIsOpen = true;
+
// Use UTF-8 encoding, without a byte-order mark.
using (StreamWriter sw = new StreamWriter(pathName, false, new UTF8Encoding(false))) {
mOutStream = sw;
@@ -258,16 +286,15 @@ namespace SourceGen.AsmGen {
// don't try
OutputLine(SourceFormatter.FullLineCommentDelimiter +
"ACME can't handle 65816 code that lives outside bank zero");
- int orgAddr = Project.AddrMap.Get(0);
- OutputOrgDirective(0, orgAddr);
+ int orgAddr = Project.AddrMap.OffsetToAddress(0);
+ AddressMap.AddressMapEntry fakeEnt = new AddressMap.AddressMapEntry(0,
+ Project.FileData.Length, orgAddr, false, false);
+ OutputOrgDirective(fakeEnt, true);
OutputDenseHex(0, Project.FileData.Length, string.Empty, string.Empty);
+ OutputOrgDirective(fakeEnt, false);
} else {
GenCommon.Generate(this, sw, worker);
}
-
- if (mInPseudoPcBlock) {
- OutputLine(string.Empty, CLOSE_PSEUDOPC, string.Empty, string.Empty);
- }
}
mOutStream = null;
@@ -283,7 +310,7 @@ namespace SourceGen.AsmGen {
return false;
}
foreach (AddressMap.AddressMapEntry ent in Project.AddrMap) {
- if (ent.Addr > 0xffff) {
+ if (ent.Address > 0xffff) {
return true;
}
}
@@ -541,29 +568,39 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(int offset, int address) {
- // If there's only one address range, just set the "real" PC. If there's more
- // than one we can run out of space if the source file has a chunk in high memory
- // followed by a chunk in low memory, because the "real" PC determines when the
- // 64KB bank is overrun.
- if (offset == 0) {
- // first one
- if (Project.AddrMap.Count == 1) {
- OutputLine("*", "=", SourceFormatter.FormatHexValue(address, 4), string.Empty);
- return;
+ public void OutputOrgDirective(AddressMap.AddressMapEntry addrEntry, bool isStart) {
+ // This is similar in operation to the AsmTass64 implementation. See comments there.
+ Debug.Assert(mPcDepth >= 0);
+ if (isStart) {
+ if (mPcDepth == 0 && mFirstIsOpen) {
+ mPcDepth++;
+
+ // Set the "real" PC for the first address change. If we're in "loadable"
+ // mode, just set "*=". If we're in "streaming" mode, we set "*=" to zero
+ // and then use a pseudo-PC.
+ if (mOutputMode == OutputMode.Loadable) {
+ OutputLine("*", "=", SourceFormatter.FormatHexValue(addrEntry.Address, 4),
+ string.Empty);
+ return;
+ } else {
+ // set the real PC to address zero to ensure we get a full 64KB
+ OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
+ }
+ }
+ OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4) + " {", string.Empty);
+ mPcDepth++;
+ } else {
+ mPcDepth--;
+ if (mPcDepth > 0 || !mFirstIsOpen) {
+ // close previous block
+ OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(CLOSE_PSEUDOPC),
+ string.Empty, string.Empty);
} else {
- // set the real PC to address zero to ensure we get a full 64KB
- OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
+ // mark initial "*=" region as closed, but don't output anything
+ mFirstIsOpen = false;
}
}
-
- if (mInPseudoPcBlock) {
- // close previous block
- OutputLine(string.Empty, CLOSE_PSEUDOPC, string.Empty, string.Empty);
- }
- OutputLine(string.Empty, sDataOpNames.OrgDirective,
- SourceFormatter.FormatHexValue(address, 4) + " {", string.Empty);
- mInPseudoPcBlock = true;
}
// IGenerator
diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs
index 21d842b..1059828 100644
--- a/SourceGen/AsmGen/AsmCc65.cs
+++ b/SourceGen/AsmGen/AsmCc65.cs
@@ -250,18 +250,20 @@ namespace SourceGen.AsmGen {
sw.WriteLine("MEMORY {");
sw.WriteLine(" MAIN: file=%O, start=%S, size=65536;");
- for (int i = 0; i < Project.AddrMap.Count; i++) {
- AddressMap.AddressMapEntry ame = Project.AddrMap[i];
- sw.WriteLine(string.Format("# MEM{0:D3}: file=%O, start=${1:x4}, size={2};",
- i, ame.Addr, ame.Length));
- }
+ //int i = 0;
+ //foreach (AddressMap.AddressMapEntry ame in Project.AddrMap) {
+ // sw.WriteLine(string.Format("# MEM{0:D3}: file=%O, start=${1:x4}, size={2};",
+ // i, ame.Address, ame.Length));
+ // i++;
+ //}
sw.WriteLine("}");
sw.WriteLine("SEGMENTS {");
sw.WriteLine(" CODE: load=MAIN, type=rw;");
- for (int i = 0; i < Project.AddrMap.Count; i++) {
- sw.WriteLine(string.Format("# SEG{0:D3}: load=MEM{0:D3}, type=rw;", i));
- }
+ //foreach (AddressMap.AddressMapEntry ame in Project.AddrMap) {
+ // sw.WriteLine(string.Format("# SEG{0:D3}: load=MEM{0:D3}, type=rw;", i));
+ // i++;
+ //}
sw.WriteLine("}");
sw.WriteLine("FEATURES {}");
@@ -559,27 +561,31 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(int offset, int address) {
- // Linear search for offset. List should be small, so this should be quick.
- int index = 0;
- foreach (AddressMap.AddressMapEntry ame in Project.AddrMap) {
- if (ame.Offset == offset) {
- break;
- }
- index++;
+ public void OutputOrgDirective(AddressMap.AddressMapEntry addrEntry, bool isStart) {
+ if (!isStart) {
+ return;
}
- mLineBuilder.Clear();
- TextUtil.AppendPaddedString(mLineBuilder, ";", 0);
- // using +1 to make it look like the comment ';' shifted it over
- TextUtil.AppendPaddedString(mLineBuilder, SourceFormatter.FormatPseudoOp(".segment"),
- mColumnWidths[0] + 1);
- TextUtil.AppendPaddedString(mLineBuilder, string.Format("\"SEG{0:D3}\"", index),
- mColumnWidths[0] + mColumnWidths[1] + 1);
- OutputLine(mLineBuilder.ToString());
+ //// Linear search for offset. List should be small, so this should be quick.
+ //int index = 0;
+ //foreach (AddressMap.AddressMapEntry ame in Project.AddrMap) {
+ // if (ame.Offset == addrEntry.Offset && ame.Length == addrEntry.Length) {
+ // break;
+ // }
+ // index++;
+ //}
+
+ //mLineBuilder.Clear();
+ //TextUtil.AppendPaddedString(mLineBuilder, ";", 0);
+ //// using +1 to make it look like the comment ';' shifted it over
+ //TextUtil.AppendPaddedString(mLineBuilder, SourceFormatter.FormatPseudoOp(".segment"),
+ // mColumnWidths[0] + 1);
+ //TextUtil.AppendPaddedString(mLineBuilder, string.Format("\"SEG{0:D3}\"", index),
+ // mColumnWidths[0] + mColumnWidths[1] + 1);
+ //OutputLine(mLineBuilder.ToString());
OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
- SourceFormatter.FormatHexValue(address, 4), string.Empty);
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
}
// IGenerator
diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs
index 59d07f0..4c55bfc 100644
--- a/SourceGen/AsmGen/AsmMerlin32.cs
+++ b/SourceGen/AsmGen/AsmMerlin32.cs
@@ -484,9 +484,11 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(int offset, int address) {
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
- SourceFormatter.FormatHexValue(address, 4), string.Empty);
+ public void OutputOrgDirective(AddressMap.AddressMapEntry addrEntry, bool isStart) {
+ if (isStart) {
+ OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
+ }
}
// IGenerator
diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs
index 5fcb6ba..84c43fb 100644
--- a/SourceGen/AsmGen/AsmTass64.cs
+++ b/SourceGen/AsmGen/AsmTass64.cs
@@ -102,11 +102,6 @@ namespace SourceGen.AsmGen {
///
private StreamWriter mOutStream;
- ///
- /// If we output a ".logical", we will need a ".here" eventually.
- ///
- private bool mNeedHereOp;
-
///
/// What encoding are we currently set up for.
///
@@ -115,10 +110,16 @@ namespace SourceGen.AsmGen {
///
/// Output mode; determines how ORG is handled.
///
- private enum TassOutputMode {
+ private enum OutputMode {
Unknown = 0, Loadable = 1, Streamable = 2
}
- private TassOutputMode mOutputMode;
+ private OutputMode mOutputMode;
+
+ ///
+ /// Current pseudo-PC depth. 0 is the "real" PC.
+ ///
+ private int mPcDepth;
+ private bool mFirstIsOpen;
///
/// Holds detected version of configured assembler.
@@ -220,13 +221,13 @@ namespace SourceGen.AsmGen {
// of offset +000002.
bool hasPrgHeader = GenCommon.HasPrgHeader(project);
int offAdj = hasPrgHeader ? 2 : 0;
- int startAddr = project.AddrMap.Get(offAdj);
+ int startAddr = project.AddrMap.OffsetToAddress(offAdj);
if (startAddr + project.FileDataLength - offAdj > 65536) {
// Does not fit into memory at load address.
- mOutputMode = TassOutputMode.Streamable;
+ mOutputMode = OutputMode.Streamable;
mHasPrgHeader = false;
} else {
- mOutputMode = TassOutputMode.Loadable;
+ mOutputMode = OutputMode.Loadable;
mHasPrgHeader = hasPrgHeader;
}
//Debug.WriteLine("startAddr=$" + startAddr.ToString("x6") +
@@ -298,6 +299,9 @@ namespace SourceGen.AsmGen {
(needLongAddress ? AsmTass64.LONG_ADDRESS : string.Empty) +
(mHasPrgHeader ? string.Empty : AsmTass64.NOSTART);
+ mPcDepth = 0;
+ mFirstIsOpen = true;
+
// Use UTF-8 encoding, without a byte-order mark.
using (StreamWriter sw = new StreamWriter(pathName, false, new UTF8Encoding(false))) {
mOutStream = sw;
@@ -309,11 +313,6 @@ namespace SourceGen.AsmGen {
}
GenCommon.Generate(this, sw, worker);
-
- if (mNeedHereOp) {
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(HERE_PSEUDO_OP),
- string.Empty, string.Empty);
- }
}
mOutStream = null;
@@ -654,34 +653,58 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(int offset, int address) {
+ public void OutputOrgDirective(AddressMap.AddressMapEntry addrEntry, bool isStart) {
// 64tass separates the "compile offset", which determines where the output fits
// into the generated binary, and "program counter", which determines the code
// the assembler generates. Since we need to explicitly specify every byte in
- // the output file, having a distinct compile offset isn't very useful. We want
+ // the output file, having a distinct compile offset isn't useful here. We want
// to set it once before the first line of code, then leave it alone.
//
// Any subsequent ORG changes are made to the program counter, and take the form
- // of a pair of ops (.logical to open, .here to end). Omitting the .here
+ // of a pair of ops (".logical " to open, ".here" to end). Omitting the .here
// causes an error.
//
// If this is a "streamable" file, meaning it won't actually load into 64K of RAM
// without wrapping around, then we skip the "* = addr" (same as "* = 0") and just
// start with ".logical" segments.
- Debug.Assert(offset >= StartOffset);
- if (offset == StartOffset && mOutputMode == TassOutputMode.Loadable) {
- // Set the "compile offset" to the initial address.
- OutputLine("*", "=",
- SourceFormatter.FormatHexValue(Project.AddrMap.Get(StartOffset), 4),
- string.Empty);
- } else {
- if (mNeedHereOp) {
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(HERE_PSEUDO_OP),
- string.Empty, string.Empty);
+ //
+ // The assembler's approach is best represented by having an address region that
+ // spans the entire file, with one or more "logical" regions inside. In practice
+ // (especially for multi-bank 65816 code) that may not be the case, but the
+ // assembler is still expecting us to start with a "* =" and then fit everything
+ // inside that. So we treat the first region specially, whether or not it wraps
+ // the rest of the file.
+ Debug.Assert(mPcDepth >= 0);
+ if (isStart) {
+ if (mPcDepth == 0 && mFirstIsOpen) {
+ mPcDepth++;
+
+ // Set the "real" PC for the first address change. If we're in "loadable"
+ // mode, just set "*=". If we're in "streaming" mode, we set "*=" to zero
+ // and then use a pseudo-PC.
+ if (mOutputMode == OutputMode.Loadable) {
+ OutputLine("*", "=",
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
+ return;
+ } else {
+ // Set the real PC to address zero to ensure we get a full 64KB. The
+ // assembler assumes this as a default, so it can be omitted.
+ //OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
+ }
}
OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
- SourceFormatter.FormatHexValue(address, 4), string.Empty);
- mNeedHereOp = true;
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
+ mPcDepth++;
+ } else {
+ mPcDepth--;
+ if (mPcDepth > 0 || !mFirstIsOpen) {
+ // close previous block
+ OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(HERE_PSEUDO_OP),
+ string.Empty, string.Empty);
+ } else {
+ // mark initial "*=" region as closed, but don't output anything
+ mFirstIsOpen = false;
+ }
}
}
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index 8a55161..839957e 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -51,6 +51,14 @@ namespace SourceGen.AsmGen {
int lastProgress = 0;
+ // Create an address map iterator and advance it to match gen.StartOffset.
+ IEnumerator addrIter = proj.AddrMap.AddressChangeIterator;
+ while (addrIter.MoveNext()) {
+ if (addrIter.Current.IsStart && addrIter.Current.Offset >= offset) {
+ break;
+ }
+ }
+
while (offset < proj.FileData.Length) {
Anattrib attr = proj.GetAnattrib(offset);
@@ -68,10 +76,12 @@ namespace SourceGen.AsmGen {
}
}
- // Check for address change.
- int orgAddr = proj.AddrMap.Get(offset);
- if (orgAddr >= 0) {
- gen.OutputOrgDirective(offset, orgAddr);
+ // Check for address changes. There may be more than one at a given offset.
+ AddressMap.AddressChange change = addrIter.Current;
+ while (change != null && change.Offset == offset) {
+ gen.OutputOrgDirective(change.Entry, change.IsStart);
+ addrIter.MoveNext();
+ change = addrIter.Current;
}
List lvars = lvLookup.GetVariablesDefinedAtOffset(offset);
@@ -132,6 +142,20 @@ namespace SourceGen.AsmGen {
//System.Threading.Thread.Sleep(500);
}
}
+
+ // Close off any open ORG blocks.
+ while (addrIter.Current != null) {
+ AddressMap.AddressChange change = addrIter.Current;
+ if (change.Offset != offset) {
+ Debug.WriteLine("Closing offset mismatch: change=+" +
+ change.Offset.ToString("x6") + ", cur offset=+" + offset.ToString("x6"));
+ Debug.Assert(false);
+ }
+ Debug.Assert(change.Offset == offset);
+ gen.OutputOrgDirective(change.Entry, change.IsStart);
+ addrIter.MoveNext();
+ change = addrIter.Current;
+ }
}
private static void GenerateHeader(IGenerator gen, StreamWriter sw) {
@@ -533,14 +557,25 @@ namespace SourceGen.AsmGen {
//Debug.WriteLine("PRG test: +0/1 has label");
return false;
}
+ // The first part of the address map should be a two-byte region, either added
+ // explicitly or a hole left at the start of the file. Address doesn't matter.
+ IEnumerator iter = project.AddrMap.AddressChangeIterator;
+ if (!iter.MoveNext()) {
+ Debug.Assert(false);
+ return false;
+ }
+ AddressMap.AddressChange change = iter.Current;
+ if (change.Entry.Length != 2) {
+ Debug.WriteLine("PRG test: first entry is not a two-byte region");
+ }
// Confirm there's an address map entry at offset 2.
- if (project.AddrMap.Get(2) == AddressMap.NO_ENTRY_ADDR) {
+ if (project.AddrMap.GetRegions(0x000002).Count == 0) {
//Debug.WriteLine("PRG test: no ORG at +2");
return false;
}
// See if the address at offset 2 matches the value at 0/1.
int value01 = project.FileData[0] | (project.FileData[1] << 8);
- int addr2 = project.AddrMap.OffsetToAddress(2);
+ int addr2 = project.AddrMap.OffsetToAddress(0x000002);
if (value01 != addr2) {
//Debug.WriteLine("PRG test: +0/1 value is " + value01.ToString("x4") +
// ", address at +2 is " + addr2);
diff --git a/SourceGen/AsmGen/IGenerator.cs b/SourceGen/AsmGen/IGenerator.cs
index 2269a75..249498b 100644
--- a/SourceGen/AsmGen/IGenerator.cs
+++ b/SourceGen/AsmGen/IGenerator.cs
@@ -168,9 +168,9 @@ namespace SourceGen.AsmGen {
///
/// Outputs a code origin directive.
///
- /// Offset of code targeted to new address.
- /// 24-bit address.
- void OutputOrgDirective(int offset, int address);
+ /// Address map entry object.
+ /// True if we're outputing a region-start directive.
+ void OutputOrgDirective(CommonUtil.AddressMap.AddressMapEntry addrEntry, bool isStart);
///
/// Notify the assembler of a change in register width.
diff --git a/SourceGen/CodeAnalysis.cs b/SourceGen/CodeAnalysis.cs
index 82be70a..c1a1571 100644
--- a/SourceGen/CodeAnalysis.cs
+++ b/SourceGen/CodeAnalysis.cs
@@ -355,13 +355,20 @@ namespace SourceGen {
/// Sets the address for every byte in the input.
///
private void SetAddresses() {
- // The AddressMap will have at least one entry, will start at offset 0, and
- // will exactly span the file.
- foreach (AddressMap.AddressMapEntry ent in mAddrMap) {
- int addr = ent.Addr;
- for (int i = ent.Offset; i < ent.Offset + ent.Length; i++) {
- mAnattribs[i].Address = addr++;
+ IEnumerator addrIter = mAddrMap.AddressChangeIterator;
+ addrIter.MoveNext();
+ int addr = 0;
+
+ for (int offset = 0; offset < mAnattribs.Length; offset++) {
+ // Process all change events at this offset.
+ AddressMap.AddressChange change = addrIter.Current;
+ while (change != null && change.Offset == offset) {
+ addr = change.Address;
+ addrIter.MoveNext();
+ change = addrIter.Current;
}
+
+ mAnattribs[offset].Address = addr++;
}
}
@@ -1105,7 +1112,7 @@ namespace SourceGen {
" label='" + label + "'; file length is" + mFileData.Length);
}
- if (!mAddrMap.IsSingleAddrRange(offset, length)) {
+ if (!mAddrMap.IsRangeUnbroken(offset, length)) {
LogW(offset, "SIDF: format crosses address map boundary (len=" + length + ")");
return false;
}
@@ -1362,7 +1369,7 @@ namespace SourceGen {
dbrChanges[kvp.Key] = kvp.Value;
}
- // Create an array for fast access.
+ // Create a full-file array for fast access.
short[] bval = new short[mAnattribs.Length];
Misc.Memset(bval, DbrValue.UNKNOWN);
foreach (KeyValuePair kvp in dbrChanges) {
@@ -1370,12 +1377,17 @@ namespace SourceGen {
}
// Run through file, updating instructions as needed.
- short curVal = (byte)(mAddrMap.Get(0) >> 16); // start with B=K
+ // TODO(org): this is wrong if the file starts with a non-addr region; can walk
+ // through anattribs and set to mAnattribs[].Address of first instruction; maybe
+ // just init to DbrValue.UNKNOWN and set it inside the loop on first relevant instr
+ int firstAddr = mAddrMap.OffsetToAddress(0);
+ short curVal = (byte)(firstAddr >> 16); // start with B=K
for (int offset = 0; offset < mAnattribs.Length; offset++) {
if (bval[offset] != DbrValue.UNKNOWN) {
curVal = bval[offset];
}
if (!mAnattribs[offset].UsesDataBankReg) {
+ // Not a relevant instruction, move on to next.
continue;
}
Debug.Assert(mAnattribs[offset].IsInstructionStart);
diff --git a/SourceGen/DataAnalysis.cs b/SourceGen/DataAnalysis.cs
index e001d27..41272be 100644
--- a/SourceGen/DataAnalysis.cs
+++ b/SourceGen/DataAnalysis.cs
@@ -682,7 +682,7 @@ namespace SourceGen {
// Check to see if we just crossed an address change.
if (offset < mAnattribs.Length &&
- !mProject.AddrMap.IsSingleAddrRange(offset - 1, 2)) {
+ !mProject.AddrMap.IsRangeUnbroken(offset - 1, 2)) {
// Must be an ORG here. End region and scan.
AnalyzeRange(startOffset, offset - 1);
startOffset = -1;
diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs
index deaf04a..250d9e1 100644
--- a/SourceGen/DisasmProject.cs
+++ b/SourceGen/DisasmProject.cs
@@ -270,7 +270,8 @@ namespace SourceGen {
ProjectPathName = string.Empty;
AddrMap = new AddressMap(fileDataLen);
- AddrMap.Set(0, 0x1000); // default load address to $1000; override later
+ // set default load address to $1000; override later
+ AddrMap.AddRegion(0x000000, fileDataLen, 0x1000, false);
// Default value is "no tag".
AnalyzerTags = new CodeAnalysis.AnalyzerTag[fileDataLen];
@@ -387,6 +388,7 @@ namespace SourceGen {
ProjectProps.EntryFlags = SystemDefaults.GetEntryFlags(sysDef);
// Configure the load address.
+ AddrMap.Clear();
if (SystemDefaults.GetFirstWordIsLoadAddr(sysDef) && mFileData.Length > 2) {
// First two bytes are the load address, with the actual file data starting
// at +000002. We need to assign an address to the bytes, but don't want them
@@ -396,8 +398,13 @@ namespace SourceGen {
// So we just give it an offset of (start - 2) and leave it to the user to
// update if necessary.
int loadAddr = RawData.GetWord(mFileData, 0, 2, false);
- AddrMap.Set(0, loadAddr < 2 ? 0 : loadAddr - 2);
- AddrMap.Set(2, loadAddr);
+ // TODO(org): use NON_ADDR for first two bytes
+ AddressMap.AddResult addRes =
+ AddrMap.AddRegion(0, 2, loadAddr < 2 ? 0 : loadAddr - 2, false);
+ Debug.Assert(addRes == AddressMap.AddResult.Okay);
+ addRes = AddrMap.AddRegion(2, mFileData.Length - 2, loadAddr, false);
+ Debug.Assert(addRes == AddressMap.AddResult.Okay);
+
OperandFormats[0] = FormatDescriptor.Create(2, FormatDescriptor.Type.NumericLE,
FormatDescriptor.SubType.None);
Comments[0] = Res.Strings.LOAD_ADDRESS;
@@ -405,7 +412,9 @@ namespace SourceGen {
AnalyzerTags[2] = CodeAnalysis.AnalyzerTag.Code;
} else {
int loadAddr = SystemDefaults.GetLoadAddress(sysDef);
- AddrMap.Set(0, loadAddr);
+ AddressMap.AddResult addRes =
+ AddrMap.AddRegion(0, mFileData.Length, loadAddr, false);
+ Debug.Assert(addRes == AddressMap.AddResult.Okay);
}
foreach (string str in sysDef.SymbolFiles) {
@@ -750,11 +759,16 @@ namespace SourceGen {
/// Checks to see if any part of the address map runs across a bank boundary.
///
private void ValidateAddressMap() {
- foreach (AddressMap.AddressMapEntry entry in AddrMap) {
- if ((entry.Addr & 0xff0000) != ((entry.Addr + entry.Length - 1) & 0xff0000)) {
+ // Use the change list, because the region list can have "floating" length values.
+ IEnumerator addrIter = AddrMap.AddressChangeIterator;
+ while (addrIter.MoveNext()) {
+ AddressMap.AddressChange change = addrIter.Current;
+ AddressMap.AddressMapEntry entry = change.Entry;
+ if (change.IsStart &&
+ (entry.Address & 0xff0000) != ((entry.Address + entry.Length - 1) & 0xff0000)) {
string fmt = Res.Strings.MSG_BANK_OVERRUN_DETAIL_FMT;
- int firstNext = (entry.Addr & 0xff0000) + 0x010000;
- int badOffset = entry.Offset + (firstNext - entry.Addr);
+ int firstNext = (entry.Address & 0xff0000) + 0x010000;
+ int badOffset = entry.Offset + (firstNext - entry.Address);
Messages.Add(new MessageList.MessageEntry(
MessageList.MessageEntry.SeverityLevel.Error,
entry.Offset,
@@ -1035,7 +1049,7 @@ namespace SourceGen {
continue;
}
- if (!AddrMap.IsSingleAddrRange(offset, dfd.Length)) {
+ if (!AddrMap.IsRangeUnbroken(offset, dfd.Length)) {
string msg = "descriptor straddles address change; len=" + dfd.Length;
genLog.LogE("+" + offset.ToString("x6") + ": " + msg);
Messages.Add(new MessageList.MessageEntry(
@@ -2130,13 +2144,27 @@ namespace SourceGen {
//}
break;
case UndoableChange.ChangeType.SetAddress: {
+ // TODO(org): rewrite this
+
AddressMap addrMap = AddrMap;
- if (addrMap.Get(offset) != (int)oldValue) {
- Debug.WriteLine("GLITCH: old address value mismatch (" +
- addrMap.Get(offset) + " vs " + (int)oldValue + ")");
- Debug.Assert(false);
+ if ((int)oldValue == AddressMap.NON_ADDR) {
+ // adding new entry
+ if (addrMap.AddRegion(offset, AddressMap.FLOATING_LEN,
+ (int)newValue, false) != AddressMap.AddResult.Okay) {
+ Debug.Assert(false, "failed adding region");
+ }
+ } else if ((int)newValue == AddressMap.NON_ADDR) {
+ // removing existing entry
+ if (!addrMap.RemoveRegion(offset, AddressMap.FLOATING_LEN)) {
+ Debug.Assert(false, "failed removing region");
+ }
+ } else {
+ // updating existing entry
+ if (!addrMap.EditRegion(offset, AddressMap.FLOATING_LEN,
+ (int) newValue, false)) {
+ Debug.Assert(false, "failed editing region");
+ }
}
- addrMap.Set(offset, (int)newValue);
Debug.WriteLine("Map offset +" + offset.ToString("x6") + " to $" +
((int)newValue).ToString("x6"));
diff --git a/SourceGen/LineListGen.cs b/SourceGen/LineListGen.cs
index 7fd99d3..5f32516 100644
--- a/SourceGen/LineListGen.cs
+++ b/SourceGen/LineListGen.cs
@@ -1194,7 +1194,7 @@ namespace SourceGen {
}
Line topLine = lines[index];
Line newLine = new Line(topLine.FileOffset, 0, Line.Type.OrgDirective);
- string addrStr = mFormatter.FormatHexValue(ent.Addr, 4);
+ string addrStr = mFormatter.FormatHexValue(ent.Address, 4);
newLine.Parts = FormattedParts.CreateDirective(
mFormatter.FormatPseudoOp(mPseudoOpNames.OrgDirective), addrStr);
lines.Insert(index, newLine);
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index ed6053e..f49f631 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -259,6 +259,8 @@ namespace SourceGen {
/// to this point so we can report fatal errors directly to the user.
///
public void WindowLoaded() {
+ // Run library unit tests.
+ Debug.Assert(CommonUtil.AddressMap.Test());
Debug.Assert(CommonUtil.RangeSet.Test());
Debug.Assert(CommonUtil.TypedRangeSet.Test());
Debug.Assert(CommonUtil.Version.Test());
@@ -1803,12 +1805,16 @@ namespace SourceGen {
int lastOffset = CodeLineList[lastIndex].FileOffset;
int nextOffset = lastOffset + CodeLineList[lastIndex].OffsetSpan;
int nextAddr;
+ AddressMap addrMap = mProject.AddrMap;
+
+ // TODO(org): rewrite this - need to identify the specific .ORG statement since
+ // there can now be several at a single offset
if (firstOffset == lastOffset || nextOffset == mProject.FileDataLength) {
- // Single item (which may not be a single *line*) is selected, or the
+ // Single item (which might not be a single *line*) is selected, or the
// last selected item is the end of the file.
nextOffset = -1;
- nextAddr = AddressMap.NO_ENTRY_ADDR;
+ nextAddr = AddressMap.NON_ADDR;
} else {
// Compute "nextAddr". If there's an existing entry at nextOffset, we use
// that. If not, we use the "load address", which is determined by the very
@@ -1829,7 +1835,7 @@ namespace SourceGen {
nextAddr = cloneMap.OffsetToAddress(nextOffset);
}
#else
- int fileStartAddr = mProject.AddrMap.OffsetToAddress(0);
+ int fileStartAddr = addrMap.OffsetToAddress(0);
nextAddr = ((fileStartAddr + nextOffset) & 0xffff) | (fileStartAddr & 0xff0000);
#endif
}
@@ -1849,37 +1855,40 @@ namespace SourceGen {
ChangeSet cs = new ChangeSet(1);
- if (mProject.AddrMap.Get(firstOffset) != dlg.NewAddress) {
- // Added / removed / changed existing entry.
- //
- // We allow creation of an apparently redundant address override, because
- // sometimes it's helpful to add one to "anchor" an area before relocating
- // something that appears earlier in the file.
- int prevAddress = mProject.AddrMap.Get(firstOffset);
- UndoableChange uc = UndoableChange.CreateAddressChange(firstOffset,
- prevAddress, dlg.NewAddress);
- cs.Add(uc);
- Debug.WriteLine("EditAddress: changing addr at offset +" +
- firstOffset.ToString("x6") + " to $" + dlg.NewAddress.ToString("x4"));
- }
+ // TODO(org): I'm just commenting this out for now; needs to be totally redone
+
+
+ //if (addrMap.Get(firstOffset) != dlg.NewAddress) {
+ // // Added / removed / changed existing entry.
+ // //
+ // // We allow creation of an apparently redundant address override, because
+ // // sometimes it's helpful to add one to "anchor" an area before relocating
+ // // something that appears earlier in the file.
+ // int prevAddress = addrMap.Get(firstOffset);
+ // UndoableChange uc = UndoableChange.CreateAddressChange(firstOffset,
+ // prevAddress, dlg.NewAddress);
+ // cs.Add(uc);
+ // Debug.WriteLine("EditAddress: changing addr at offset +" +
+ // firstOffset.ToString("x6") + " to $" + dlg.NewAddress.ToString("x4"));
+ //}
// We want to create an entry for the chunk that follows the selected area.
// We don't modify the trailing address if an entry already exists.
// (Note the "can edit" code prevented us from being called if there's an
// address map entry in the middle of the selected area.)
//
- // If they're removing an existing entry, don't add a new entry at the end.
- if (nextAddr >= 0 && dlg.NewAddress != AddressMap.NO_ENTRY_ADDR &&
- mProject.AddrMap.Get(nextOffset) == AddressMap.NO_ENTRY_ADDR) {
- // We don't screen for redundant entries here. That should only happen if
- // they select a range and then don't change the address. Maybe it's useful?
- int prevAddress = mProject.AddrMap.Get(nextOffset);
- UndoableChange uc = UndoableChange.CreateAddressChange(nextOffset,
- prevAddress, nextAddr);
- cs.Add(uc);
- Debug.WriteLine("EditAddress: setting trailing addr at offset +" +
- nextOffset.ToString("x6") + " to $" + nextAddr.ToString("x4"));
- }
+ //// If they're removing an existing entry, don't add a new entry at the end.
+ //if (nextAddr >= 0 && dlg.NewAddress != AddressMap.NO_ENTRY_ADDR &&
+ // addrMap.Get(nextOffset) == AddressMap.NO_ENTRY_ADDR) {
+ // // We don't screen for redundant entries here. That should only happen if
+ // // they select a range and then don't change the address. Maybe it's useful?
+ // int prevAddress = addrMap.Get(nextOffset);
+ // UndoableChange uc = UndoableChange.CreateAddressChange(nextOffset,
+ // prevAddress, nextAddr);
+ // cs.Add(uc);
+ // Debug.WriteLine("EditAddress: setting trailing addr at offset +" +
+ // nextOffset.ToString("x6") + " to $" + nextAddr.ToString("x4"));
+ //}
if (cs.Count > 0) {
ApplyUndoableChanges(cs);
@@ -2614,7 +2623,7 @@ namespace SourceGen {
// This must match what GroupedOffsetSetFromSelected() does.
if (!mProject.UserLabels.ContainsKey(nextOffset) &&
!mProject.HasCommentNoteOrVis(nextOffset) &&
- mProject.AddrMap.IsSingleAddrRange(nextOffset - 1, 2)) {
+ mProject.AddrMap.IsRangeUnbroken(nextOffset - 1, 2)) {
// Good to go.
Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6"));
trs.Add(nextOffset, rng.Type);
@@ -3606,7 +3615,7 @@ namespace SourceGen {
// + expectedAddr.ToString("x4"));
expectedAddr = attr.Address;
groupNum++;
- } else if (offset > 0 && !mProject.AddrMap.IsSingleAddrRange(offset - 1, 2)) {
+ } else if (offset > 0 && !mProject.AddrMap.IsRangeUnbroken(offset - 1, 2)) {
// Was the previous byte in a different address range? This is only
// strictly necessary if the previous byte was in the selection set (which
// it won't be if the selection starts at the beginning of an address
diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs
index e507d1d..930ceb7 100644
--- a/SourceGen/ProjectFile.cs
+++ b/SourceGen/ProjectFile.cs
@@ -246,7 +246,7 @@ namespace SourceGen {
public SerAddressMap() { }
public SerAddressMap(AddressMap.AddressMapEntry ent) {
Offset = ent.Offset;
- Addr = ent.Addr;
+ Addr = ent.Address;
}
}
public class SerTypeHintRange {
@@ -668,8 +668,20 @@ namespace SourceGen {
}
// Deserialize address map.
+ proj.AddrMap.Clear();
foreach (SerAddressMap addr in spf.AddressMap) {
- proj.AddrMap.Set(addr.Offset, addr.Addr);
+ // TODO(org): serialize length and isRelative
+ int length = CommonUtil.AddressMap.FLOATING_LEN;
+
+ AddressMap.AddResult addResult = proj.AddrMap.AddRegion(addr.Offset,
+ length, addr.Addr, false);
+ if (addResult != CommonUtil.AddressMap.AddResult.Okay) {
+ string msg = "off=+" + addr.Offset.ToString("x6") + " addr=$" +
+ addr.Addr.ToString("x4") + " len=" +
+ (length == CommonUtil.AddressMap.FLOATING_LEN ? "(floating)" : length.ToString());
+ string errMsg = string.Format(Res.Strings.ERR_BAD_ADDRESS_REGION_FMT, msg);
+ report.Add(FileLoadItem.Type.Warning, errMsg);
+ }
}
// Deserialize analyzer tags (formerly known as "type hints"). The default value
diff --git a/SourceGen/Res/Strings.xaml b/SourceGen/Res/Strings.xaml
index 9ba1846..a81acba 100644
--- a/SourceGen/Res/Strings.xaml
+++ b/SourceGen/Res/Strings.xaml
@@ -47,6 +47,7 @@ limitations under the License.
addr
const
stkrl
+ Bad address region {0}
Unknown I/O direction in symbol
Bad format descriptor at +{0:x6}.
Bad format descriptor type
diff --git a/SourceGen/Res/Strings.xaml.cs b/SourceGen/Res/Strings.xaml.cs
index 49ab7d7..764cfb1 100644
--- a/SourceGen/Res/Strings.xaml.cs
+++ b/SourceGen/Res/Strings.xaml.cs
@@ -75,6 +75,8 @@ namespace SourceGen.Res {
(string)Application.Current.FindResource("str_EquConstant");
public static string EQU_STACK_RELATIVE =
(string)Application.Current.FindResource("str_EquStackRelative");
+ public static string ERR_BAD_ADDRESS_REGION_FMT =
+ (string)Application.Current.FindResource("str_ErrBadAddressRegionFmt");
public static string ERR_BAD_DEF_SYMBOL_DIR =
(string)Application.Current.FindResource("str_ErrBadDefSymbolDir");
public static string ERR_BAD_FD_FMT =
diff --git a/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.S b/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.S
index 14e3c85..7273ec5 100644
--- a/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.S
+++ b/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502X"
-; .segment "SEG000"
.org $1000
jsr L1035
jsr L1038
diff --git a/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.cfg b/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.cfg
index 2df3772..20e466d 100644
--- a/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10000-allops-value-6502_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10000-allops-value-6502
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=598;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.S b/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.S
index df5bf26..1c7be6a 100644
--- a/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.S
+++ b/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65C02"
-; .segment "SEG000"
.org $1000
jsr L1014
jsr L108A
diff --git a/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.cfg b/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.cfg
index b828bb6..cdeec22 100644
--- a/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10001-allops-value-65C02_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10001-allops-value-65C02
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=489;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.S b/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.S
index 60166b9..184c706 100644
--- a/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.S
+++ b/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.cfg b/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.cfg
index ec0095d..85fb414 100644
--- a/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10002-allops-value-65816_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10002-allops-value-65816
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=588;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.S b/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.S
index d5f55b6..e168a09 100644
--- a/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.S
+++ b/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65C02"
-; .segment "SEG000"
.org $1000
jsr L1017
jsr L1099
diff --git a/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.cfg b/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.cfg
index 20bd9fd..f780e84 100644
--- a/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10003-allops-value-W65C02_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10003-allops-value-W65C02
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=541;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.S b/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.S
index c729141..6ff3a02 100644
--- a/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.S
+++ b/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502X"
-; .segment "SEG000"
.org $1000
jsr L1035
jsr L1038
diff --git a/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.cfg b/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.cfg
index 00f32ff..862feb7 100644
--- a/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10010-allops-zero-6502_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10010-allops-zero-6502
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=598;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.S b/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.S
index 20dd594..19fa055 100644
--- a/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.S
+++ b/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65C02"
-; .segment "SEG000"
.org $1000
jsr L1014
jsr L108A
diff --git a/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.cfg b/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.cfg
index 99fa289..f2c0c7b 100644
--- a/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10011-allops-zero-65C02_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10011-allops-zero-65C02
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=489;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.S b/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.S
index 2f974d0..63223ce 100644
--- a/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.S
+++ b/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.cfg b/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.cfg
index 7f7009f..8e18bce 100644
--- a/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10012-allops-zero-65816_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10012-allops-zero-65816
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=588;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.S b/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.S
index c2ab767..7efe5f2 100644
--- a/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.S
+++ b/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65C02"
-; .segment "SEG000"
.org $1000
jsr L1017
jsr L1099
diff --git a/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.cfg b/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.cfg
index 4369149..ac5a7f5 100644
--- a/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10013-allops-zero-W65C02_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10013-allops-zero-W65C02
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=541;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.S b/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.S
index 0594f42..79b114b 100644
--- a/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.S
+++ b/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502X"
-; .segment "SEG000"
.org $1000
jsr L100F
jsr L1017
diff --git a/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.cfg b/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.cfg
index 7325f97..8117d20 100644
--- a/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10020-embedded-instructions_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10020-embedded-instructions
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=82;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.S b/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.S
index 50dbefe..126fdd3 100644
--- a/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.S
+++ b/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.cfg b/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.cfg
index 2ae844f..33f24de 100644
--- a/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10022-embedded-instructions_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10022-embedded-instructions
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=33;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.S b/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.S
index e164f6d..67d8f49 100644
--- a/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.S
+++ b/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502X"
-; .segment "SEG000"
.org $1000
clv
cld
diff --git a/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.cfg b/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.cfg
index d2fa51d..2a5b723 100644
--- a/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10030-flags-and-branches_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10030-flags-and-branches
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=193;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.S b/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.S
index 890bde6..6da02a4 100644
--- a/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.S
+++ b/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.cfg b/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.cfg
index fd70fc3..6d89600 100644
--- a/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10032-flags-and-branches_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10032-flags-and-branches
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=180;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.S b/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.S
index e862851..674b6ac 100644
--- a/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.S
+++ b/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502X"
-; .segment "SEG000"
.org $1000
lda L10AC
ora L10BC
diff --git a/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.cfg b/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.cfg
index 5553474..7cb6cf4 100644
--- a/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/10040-data-recognition_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 10040-data-recognition
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=196;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S b/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S
index 5912ce9..69ed4b0 100644
--- a/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S
+++ b/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S
@@ -1,8 +1,7 @@
;Project file was edited to get all big-endian data types, and to have an
;incorrect .junk alignment directive.
!cpu 6502
-* = $0000
- !pseudopc $1000 {
+* = $1000
bit L1448
jsr L14A8
nop
@@ -61,7 +60,6 @@ LABEL !hex 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
!fill 2,$dd ;incorrect alignment
!align 255,0,$00
!fill 8,$82
- } ;!pseudopc
!pseudopc $1408 {
!fill 8,$82 ;note no-op .ORG
!fill 8,$83
diff --git a/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.S b/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.S
index 32edd7f..65ad205 100644
--- a/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.S
+++ b/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.S
@@ -1,7 +1,6 @@
;Project file was edited to get all big-endian data types, and to have an
;incorrect .junk alignment directive.
.setcpu "6502"
-; .segment "SEG000"
.org $1000
bit L1448
jsr L14A8
@@ -63,11 +62,9 @@ LABEL: .byte $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$aa,$bb,$cc,$dd,$ee,$ff
.res 2,$dd ;incorrect alignment
.res 140,$00
.res 8,$82
-; .segment "SEG001"
.org $1408
.res 8,$82 ;note no-op .ORG
.res 8,$83
-; .segment "SEG002"
.org $1428
.res 8,$83 ;meaningful .ORG
.res 8,$84
diff --git a/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.cfg b/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.cfg
index 5aa65fb..abf8cab 100644
--- a/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20000-numeric-types_cc65.cfg
@@ -1,15 +1,9 @@
# 6502bench SourceGen generated linker script for 20000-numeric-types
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=1032;
-# MEM001: file=%O, start=$1408, size=16;
-# MEM002: file=%O, start=$1428, size=152;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20010-string-types_cc65.S b/SourceGen/SGTestData/Expected/20010-string-types_cc65.S
index 83801a6..99490fe 100644
--- a/SourceGen/SGTestData/Expected/20010-string-types_cc65.S
+++ b/SourceGen/SGTestData/Expected/20010-string-types_cc65.S
@@ -1,6 +1,5 @@
;Project file was edited to get zero-length strings and reverse DCI.
.setcpu "6502"
-; .segment "SEG000"
.org $1000
rts
diff --git a/SourceGen/SGTestData/Expected/20010-string-types_cc65.cfg b/SourceGen/SGTestData/Expected/20010-string-types_cc65.cfg
index de91b84..7c82594 100644
--- a/SourceGen/SGTestData/Expected/20010-string-types_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20010-string-types_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20010-string-types
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=3132;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.S b/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.S
index c967835..d4aa968 100644
--- a/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.S
+++ b/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.S
@@ -1,6 +1,5 @@
;Project file was edited to force ASCII formatting for some operands.
.setcpu "6502"
-; .segment "SEG000"
.org $1000
lda $01
lda $0102
diff --git a/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.cfg b/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.cfg
index b8edb7a..843d189 100644
--- a/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20020-operand-formats_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20020-operand-formats
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=165;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.S b/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.S
index 4899dd9..8cc699c 100644
--- a/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.S
+++ b/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.S
@@ -1,6 +1,5 @@
;Project file was edited to force ASCII formatting for some operands.
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.cfg b/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.cfg
index 408a655..bb39eaa 100644
--- a/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20022-operand-formats_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20022-operand-formats
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=62;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S
index 5cc0712..34d52e5 100644
--- a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S
+++ b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S
@@ -9,8 +9,7 @@ absh = $feed
plataddr = $3000 ;address only in platform file
projalsa = $3200 ;same val as projalso
-* = $0000
- !pseudopc $2345 {
+* = $2345
start lda #zip
lda #zip+16
lda #zip-192
@@ -59,7 +58,6 @@ start lda #zip
@L23A3 jmp @L1000_1
- } ;!pseudopc
!pseudopc $1000 {
@L1000_1 nop
@L1000 nop
diff --git a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.S b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.S
index b9019ad..4d52898 100644
--- a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.S
+++ b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.S
@@ -9,7 +9,6 @@ absh = $feed
plataddr = $3000 ;address only in platform file
projalsa = $3200 ;same val as projalso
-; .segment "SEG000"
.org $2345
start: lda #zip
lda #zip+16
@@ -59,7 +58,6 @@ start: lda #zip
@L23A3: jmp @L1000_1
-; .segment "SEG001"
.org $1000
@L1000_1: nop
@L1000: nop
diff --git a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.cfg b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.cfg
index cf76195..866807b 100644
--- a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20030-labels-and-symbols
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$2345, size=97;
-# MEM001: file=%O, start=$1000, size=355;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.S b/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.S
index 760d2d9..37ee728 100644
--- a/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.S
+++ b/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.S
@@ -11,7 +11,6 @@ thirty2 = $12345678 ;32-bit constant test
plataddr = $3000 ;address only in platform file
projalsa = $3200 ;same val as projalso
-; .segment "SEG000"
.org $012345
.a8
.i8
@@ -126,7 +125,6 @@ start: clc
@nextchunk: jml @L1000_1
-; .segment "SEG001"
.org $1000
@L1000_1: nop
@L1000: nop
diff --git a/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.cfg b/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.cfg
index 91e5948..e812a66 100644
--- a/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20032-labels-and-symbols_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20032-labels-and-symbols
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$12345, size=279;
-# MEM001: file=%O, start=$1000, size=416;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_acme.S b/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
index 3aab4e6..cbc3bb0 100644
--- a/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
@@ -1,9 +1,7 @@
!cpu 6502
-* = $0000
- !pseudopc $1000 {
+* = $1000
!word $1000 ;PRG-style header
- } ;!pseudopc
!pseudopc $1000 {
jsr L1100
jsr L1107
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S
index 6ca2af2..332eba2 100644
--- a/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S
@@ -1,15 +1,12 @@
.setcpu "6502"
-; .segment "SEG000"
.org $1000
.word $1000 ;PRG-style header
-; .segment "SEG001"
.org $1000
jsr L1100
jsr L1107
jmp L2000
-; .segment "SEG002"
.org $1100
L1100: bit L1100
L1103: lda #$11
@@ -18,7 +15,6 @@ L1107: ldy #$11
clv
bvc L1103
-; .segment "SEG003"
.org $1100
@L1100_0: bit @L1100_0
lda #$22
@@ -26,7 +22,6 @@ L1107: ldy #$11
ldy #$22
jmp @L1105
-; .segment "SEG004"
.org $1100
@L1100_1: bit @L1100_1
lda #$33
@@ -35,20 +30,17 @@ L1107: ldy #$11
sec
bcs @L1107_0
-; .segment "SEG005"
.org $2000
L2000: bit L2000
beq $2018
bne @L2020
-; .segment "SEG006"
.org $2020
@L2020: bit @L2020
beq $2028
bne L2080
offend: nop
-; .segment "SEG007"
.org $2080
L2080: bit L2080
lda offend
@@ -63,22 +55,18 @@ L2080: bit L2080
beq @L2100
.byte $ad
-; .segment "SEG008"
.org $2100
@L2100: nop
nop
jmp @L3000
-; .segment "SEG009"
.org $2800
.byte $00
.byte $28
.res 14,$00
-; .segment "SEG010"
.org $2820
.res 18,$00
-; .segment "SEG011"
.org $3000
@L3000: bit @L3000
lda #$44
@@ -88,7 +76,6 @@ L2080: bit L2080
ulabel: .byte $00
.byte $01
-; .segment "SEG012"
.org $3100
.byte $02
@@ -101,7 +88,6 @@ fwd: bit fwd
beq @L3182
.byte $ea
.byte $ea
-; .segment "SEG013"
.org $3180
.byte $00
.byte $01
@@ -116,7 +102,6 @@ fwd: bit fwd
label1: .byte $ea
.byte $ea
-; .segment "SEG014"
.org $3200
L3200: bit L3200
.byte $00
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg
index 31120e0..6679fb2 100644
--- a/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg
@@ -1,39 +1,9 @@
# 6502bench SourceGen generated linker script for 20040-address-changes
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=2;
-# MEM001: file=%O, start=$1000, size=9;
-# MEM002: file=%O, start=$1100, size=12;
-# MEM003: file=%O, start=$1100, size=12;
-# MEM004: file=%O, start=$1100, size=12;
-# MEM005: file=%O, start=$2000, size=7;
-# MEM006: file=%O, start=$2020, size=8;
-# MEM007: file=%O, start=$2080, size=32;
-# MEM008: file=%O, start=$2100, size=5;
-# MEM009: file=%O, start=$2800, size=16;
-# MEM010: file=%O, start=$2820, size=18;
-# MEM011: file=%O, start=$3000, size=14;
-# MEM012: file=%O, start=$3100, size=23;
-# MEM013: file=%O, start=$3180, size=19;
-# MEM014: file=%O, start=$3200, size=5;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
-# SEG004: load=MEM004, type=rw;
-# SEG005: load=MEM005, type=rw;
-# SEG006: load=MEM006, type=rw;
-# SEG007: load=MEM007, type=rw;
-# SEG008: load=MEM008, type=rw;
-# SEG009: load=MEM009, type=rw;
-# SEG010: load=MEM010, type=rw;
-# SEG011: load=MEM011, type=rw;
-# SEG012: load=MEM012, type=rw;
-# SEG013: load=MEM013, type=rw;
-# SEG014: load=MEM014, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S
index d56d36a..af1cc11 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $021000
.a8
.i8
@@ -10,7 +9,6 @@
jsr L21107 & $ffff
jmp L22000 & $ffff
-; .segment "SEG001"
.org $021100
L21100: bit L21100 & $ffff
L21103: lda #$11
@@ -19,7 +17,6 @@ L21107: ldy #$11
per L21103
bra L21103
-; .segment "SEG002"
.org $021100
@L21100_0: bit @L21100_0 & $ffff
lda #$22
@@ -28,7 +25,6 @@ L21107: ldy #$11
per @L21105
jmp @L21105 & $ffff
-; .segment "SEG003"
.org $021100
@L21100_1: bit @L21100_1 & $ffff
lda #$33
@@ -37,20 +33,17 @@ L21107: ldy #$11
per @L21107_0
bra @L21107_0
-; .segment "SEG004"
.org $022000
L22000: bit L22000 & $ffff
beq $022018
bra @L22020
-; .segment "SEG005"
.org $022020
@L22020: bit @L22020 & $ffff
beq $022029
brl @L22080
@offend: nop
-; .segment "SEG006"
.org $022080
@L22080: bit @L22080 & $ffff
lda @offend & $ffff
@@ -65,22 +58,18 @@ L22000: bit L22000 & $ffff
beq @L22100
.byte $ad
-; .segment "SEG007"
.org $022100
@L22100: nop
nop
jmp @L23000 & $ffff
-; .segment "SEG008"
.org $022800
.byte $00
.byte $28
.res 14,$00
-; .segment "SEG009"
.org $022820
.res 18,$00
-; .segment "SEG010"
.org $023000
@L23000: bit @L23000 & $ffff
lda #$44
@@ -90,7 +79,6 @@ L22000: bit L22000 & $ffff
@ulabel: .byte $00
.byte $01
-; .segment "SEG011"
.org $023100
.byte $02
@@ -103,7 +91,6 @@ L22000: bit L22000 & $ffff
beq @L23182
.byte $ea
.byte $ea
-; .segment "SEG012"
.org $023180
.byte $00
.byte $01
@@ -117,7 +104,6 @@ L22000: bit L22000 & $ffff
@label1: .byte $ea
.byte $ea
-; .segment "SEG013"
.org $023200
@L23200: bit @L23200 & $ffff
.byte $00
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg
index b8ef32f..cda5fa6 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg
@@ -1,37 +1,9 @@
# 6502bench SourceGen generated linker script for 20042-address-changes
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$21000, size=13;
-# MEM001: file=%O, start=$21100, size=14;
-# MEM002: file=%O, start=$21100, size=15;
-# MEM003: file=%O, start=$21100, size=14;
-# MEM004: file=%O, start=$22000, size=7;
-# MEM005: file=%O, start=$22020, size=9;
-# MEM006: file=%O, start=$22080, size=32;
-# MEM007: file=%O, start=$22100, size=5;
-# MEM008: file=%O, start=$22800, size=16;
-# MEM009: file=%O, start=$22820, size=18;
-# MEM010: file=%O, start=$23000, size=14;
-# MEM011: file=%O, start=$23100, size=23;
-# MEM012: file=%O, start=$23180, size=18;
-# MEM013: file=%O, start=$23200, size=5;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
-# SEG004: load=MEM004, type=rw;
-# SEG005: load=MEM005, type=rw;
-# SEG006: load=MEM006, type=rw;
-# SEG007: load=MEM007, type=rw;
-# SEG008: load=MEM008, type=rw;
-# SEG009: load=MEM009, type=rw;
-# SEG010: load=MEM010, type=rw;
-# SEG011: load=MEM011, type=rw;
-# SEG012: load=MEM012, type=rw;
-# SEG013: load=MEM013, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S b/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S
index 884c806..e9a014f 100644
--- a/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S
+++ b/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S
@@ -1,9 +1,7 @@
!cpu 6502
-* = $0000
- !pseudopc $1000 {
+* = $1000
jmp L0000
- } ;!pseudopc
!pseudopc $0000 {
L0000 bit+2 L0000
L0003 lda+1 L0000
diff --git a/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.S b/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.S
index e8aca36..13b586e 100644
--- a/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.S
+++ b/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.S
@@ -1,9 +1,7 @@
.setcpu "6502"
-; .segment "SEG000"
.org $1000
jmp L0000
-; .segment "SEG001"
.org $0000
L0000: bit a:L0000
L0003: lda L0000
@@ -21,12 +19,10 @@ L0012: lda lodat+1
clc
.byte $90,$a9
-; .segment "SEG002"
.org $0080
L0080: bit a:L0080
jmp LFFC6
-; .segment "SEG003"
.org $ffc0
LFFC0: bit LFFC0
LFFC3: clc
diff --git a/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.cfg b/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.cfg
index 1c1e1ba..35db8f4 100644
--- a/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20050-branches-and-banks_cc65.cfg
@@ -1,17 +1,9 @@
# 6502bench SourceGen generated linker script for 20050-branches-and-banks
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=3;
-# MEM001: file=%O, start=$0000, size=23;
-# MEM002: file=%O, start=$0080, size=6;
-# MEM003: file=%O, start=$ffc0, size=7;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20052-branches-and-banks_acme.S b/SourceGen/SGTestData/Expected/20052-branches-and-banks_acme.S
index a2c23e1..9ee17f4 100644
--- a/SourceGen/SGTestData/Expected/20052-branches-and-banks_acme.S
+++ b/SourceGen/SGTestData/Expected/20052-branches-and-banks_acme.S
@@ -1,6 +1,5 @@
;ACME can't handle 65816 code that lives outside bank zero
-* = $0000
- !pseudopc $1000 {
+* = $1000
!hex 18fbe2305c000044000102cf000044af000044ad0000a50030f562b2ffd0b082
!hex a9ff1700170044cfc0ff44f005303c8239005c0020002c0020f41700f44400d0
!hex 03dc0810ea201220201520200f20225634125c103254cf1032548006eaea6016
@@ -10,4 +9,3 @@
!hex 7d3254eaea60200e20eac23008a90000e230a90028a9eaeae23008a900c230a9
!hex 000028a9eaeac230eaad0e20ad2220200e20202220fc0e20d0037c0e2020cbed
!hex adcbedd0037ccbedea6b
- } ;!pseudopc
diff --git a/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.S b/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.S
index 7fba5fd..7630a5d 100644
--- a/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.S
+++ b/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.S
@@ -2,7 +2,6 @@
zero = $00
longsym = $123456
-; .segment "SEG000"
.org $1000
.a8
.i8
@@ -15,7 +14,6 @@ lodat: .byte $00
.byte $01
.byte $02
-; .segment "SEG001"
.org $440000
L440000: cmp L440000
L440004: lda L440000
@@ -29,7 +27,6 @@ L440004: lda L440000
dat44: .word dat44 & $ffff
.faraddr dat44
-; .segment "SEG002"
.org $44ffc0
L44FFC0: cmp L44FFC0
high44: beq @L44FFCB
@@ -38,7 +35,6 @@ high44: beq @L44FFCB
@L44FFCB: jml @L2000
-; .segment "SEG003"
.org $2000
@L2000: bit @L2000
pea dat44 & $ffff
@@ -53,7 +49,6 @@ j2: jsr j2+3
jsl longsym
jml bank54
-; .segment "SEG004"
.org $543210
bank54: cmp bank54
bra L54321C
diff --git a/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.cfg b/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.cfg
index cff2daf..000b0f7 100644
--- a/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20052-branches-and-banks_cc65.cfg
@@ -1,19 +1,9 @@
# 6502bench SourceGen generated linker script for 20052-branches-and-banks
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=11;
-# MEM001: file=%O, start=$440000, size=28;
-# MEM002: file=%O, start=$44ffc0, size=15;
-# MEM003: file=%O, start=$2000, size=32;
-# MEM004: file=%O, start=$543210, size=180;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
-# SEG004: load=MEM004, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S b/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S
index cc683e4..78806ce 100644
--- a/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S
+++ b/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S
@@ -1,6 +1,5 @@
!cpu 6502
-* = $0000
- !pseudopc $1000 {
+* = $1000
load11 lda #$11
@L1002 ldx #$22
@load33 ldy #$33
@@ -47,7 +46,6 @@ load11 lda #$11
!byte $80
@dat81 !byte $81
- } ;!pseudopc
!pseudopc $2000 {
@L2000 !byte $82
!byte $83
diff --git a/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.S b/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.S
index 5838a2a..479faff 100644
--- a/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.S
+++ b/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502"
-; .segment "SEG000"
.org $1000
load11: lda #$11
@L1002: ldx #$22
@@ -47,7 +46,6 @@ load11: lda #$11
.byte $80
@dat81: .byte $81
-; .segment "SEG001"
.org $2000
@L2000: .byte $82
.byte $83
diff --git a/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.cfg b/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.cfg
index ef319d9..e77e7fb 100644
--- a/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20060-target-adjustment_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20060-target-adjustment
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=133;
-# MEM001: file=%O, start=$2000, size=58;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.S b/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.S
index 9128c8f..d955272 100644
--- a/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.S
+++ b/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.S
@@ -1,6 +1,5 @@
;6502bench SourceGen v1.7.3-dev2
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.cfg b/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.cfg
index 66cf999..8c944c0 100644
--- a/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20062-target-adjustment_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20062-target-adjustment
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=23;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20070-hinting_cc65.S b/SourceGen/SGTestData/Expected/20070-hinting_cc65.S
index 25e6cd5..cbfddfe 100644
--- a/SourceGen/SGTestData/Expected/20070-hinting_cc65.S
+++ b/SourceGen/SGTestData/Expected/20070-hinting_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502"
-; .segment "SEG000"
.org $1000
.byte $03
.byte $02
diff --git a/SourceGen/SGTestData/Expected/20070-hinting_cc65.cfg b/SourceGen/SGTestData/Expected/20070-hinting_cc65.cfg
index 626f749..1a837a9 100644
--- a/SourceGen/SGTestData/Expected/20070-hinting_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20070-hinting_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20070-hinting
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=72;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.S b/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.S
index fcbea3b..f555bde 100644
--- a/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.S
+++ b/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.S
@@ -1,7 +1,6 @@
.setcpu "65C02"
REALLYLONGLABELNAME = $8888 ;that's a long name
-; .segment "SEG000"
.org $1000
nop
_start: lda @start
diff --git a/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.cfg b/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.cfg
index ec96ed3..e95c929 100644
--- a/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20081-label-localizer_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20081-label-localizer
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=103;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S b/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S
index c79f288..53c06b5 100644
--- a/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S
+++ b/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S
@@ -19,7 +19,6 @@ plataddr = $3000 ;address only in platform file
;Short, unboxed comment here!!
;Two spaces after. More hyp-
;hens?
-; .segment "SEG000"
.org $1000
lda #$01 ;Comment!
;Comment rulers can be helpful in findin the edges of notes. Comments are hyph-
diff --git a/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.cfg b/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.cfg
index c6d6b68..5b09b5d 100644
--- a/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20090-notes-and-comments
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=98;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20100-label-dp_acme.S b/SourceGen/SGTestData/Expected/20100-label-dp_acme.S
index 4565e15..d8c7740 100644
--- a/SourceGen/SGTestData/Expected/20100-label-dp_acme.S
+++ b/SourceGen/SGTestData/Expected/20100-label-dp_acme.S
@@ -1,6 +1,5 @@
!cpu 6510
-* = $0000
- !pseudopc $1000 {
+* = $1000
jsr L1035
jsr L1038
jsr L1059
@@ -295,7 +294,6 @@ L1238 isc (L0080),y
sbc+2 L0086,x
inc+2 L0086,x
isc+2 L0086,x
- } ;!pseudopc
!pseudopc $0080 {
L0080 bit+1 @L0082
@L0082 bit+1 @L0082
diff --git a/SourceGen/SGTestData/Expected/20100-label-dp_cc65.S b/SourceGen/SGTestData/Expected/20100-label-dp_cc65.S
index ae50bb5..f8b8d17 100644
--- a/SourceGen/SGTestData/Expected/20100-label-dp_cc65.S
+++ b/SourceGen/SGTestData/Expected/20100-label-dp_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502X"
-; .segment "SEG000"
.org $1000
jsr L1035
jsr L1038
@@ -295,7 +294,6 @@ L1238: isc (L0080),y
sbc a:L0086,x
inc a:L0086,x
isc a:L0086,x
-; .segment "SEG001"
.org $0080
L0080: bit z:@L0082
@L0082: bit @L0082
diff --git a/SourceGen/SGTestData/Expected/20100-label-dp_cc65.cfg b/SourceGen/SGTestData/Expected/20100-label-dp_cc65.cfg
index 7b1b152..b11f918 100644
--- a/SourceGen/SGTestData/Expected/20100-label-dp_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20100-label-dp_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20100-label-dp
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=598;
-# MEM001: file=%O, start=$0080, size=9;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20102-label-dp_acme.S b/SourceGen/SGTestData/Expected/20102-label-dp_acme.S
index 371b974..30553c2 100644
--- a/SourceGen/SGTestData/Expected/20102-label-dp_acme.S
+++ b/SourceGen/SGTestData/Expected/20102-label-dp_acme.S
@@ -1,6 +1,5 @@
!cpu 65816
-* = $0000
- !pseudopc $1000 {
+* = $1000
!as
!rs
sec
@@ -286,7 +285,6 @@ L11FC cmp+2 L0086,x
sbc+2 L0086,x
inc+2 L0086,x
sbc+3 L0089,x
- } ;!pseudopc
!pseudopc $0080 {
L0080 bit+1 @L0082
@L0082 bit+1 @L0082
diff --git a/SourceGen/SGTestData/Expected/20102-label-dp_cc65.S b/SourceGen/SGTestData/Expected/20102-label-dp_cc65.S
index 167e0c3..223618e 100644
--- a/SourceGen/SGTestData/Expected/20102-label-dp_cc65.S
+++ b/SourceGen/SGTestData/Expected/20102-label-dp_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
@@ -286,7 +285,6 @@ L11FC: cmp a:L0086,x
sbc a:L0086,x
inc a:L0086,x
sbc f:L0089,x
-; .segment "SEG001"
.org $0080
L0080: bit z:@L0082
@L0082: bit @L0082
diff --git a/SourceGen/SGTestData/Expected/20102-label-dp_cc65.cfg b/SourceGen/SGTestData/Expected/20102-label-dp_cc65.cfg
index bccce59..5fa2af3 100644
--- a/SourceGen/SGTestData/Expected/20102-label-dp_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20102-label-dp_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20102-label-dp
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=588;
-# MEM001: file=%O, start=$0080, size=13;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.S b/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.S
index 0fe9e86..edd9d6c 100644
--- a/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.S
+++ b/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502"
-; .segment "SEG000"
.org $0000
nop
nop
diff --git a/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.cfg b/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.cfg
index d8449c9..c9e4974 100644
--- a/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20110-64k-nops_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20110-64k-nops
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$0000, size=65536;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.S b/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.S
index ded807f..3965cf6 100644
--- a/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.S
+++ b/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.S
@@ -1,6 +1,5 @@
;Projected edited to format non-char operands as chars.
.setcpu "6502"
-; .segment "SEG000"
.org $1000
lda #'A'
lda #'A' | $80
diff --git a/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.cfg b/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.cfg
index 5f4cb6f..df5f867 100644
--- a/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20120-char-encoding-a_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20120-char-encoding-a
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=1417;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.S b/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.S
index da3bea1..7d64516 100644
--- a/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.S
+++ b/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.cfg b/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.cfg
index 9e7a7cf..c0c87a0 100644
--- a/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20122-char-encoding_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20122-char-encoding
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=19;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.S b/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.S
index 60e8bba..462d6d5 100644
--- a/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.S
+++ b/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.S
@@ -1,6 +1,5 @@
;Projected edited to format non-char operands as chars.
.setcpu "6502"
-; .segment "SEG000"
.org $1000
lda #'A'
lda #'A' | $80
diff --git a/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.cfg b/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.cfg
index dfbe7bb..f29f7fb 100644
--- a/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20130-char-encoding-p_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20130-char-encoding-p
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=1417;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.S b/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.S
index 18e5686..2a7355d 100644
--- a/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.S
+++ b/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.S
@@ -1,6 +1,5 @@
;Projected edited to format non-char operands as chars.
.setcpu "6502"
-; .segment "SEG000"
.org $1000
lda #'A'
lda #'A' | $80
diff --git a/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.cfg b/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.cfg
index e3e6e84..6fe10c9 100644
--- a/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20140-char-encoding-s_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20140-char-encoding-s
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=1417;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20150-local-variables_acme.S b/SourceGen/SGTestData/Expected/20150-local-variables_acme.S
index 5977b1f..1ac3ca1 100644
--- a/SourceGen/SGTestData/Expected/20150-local-variables_acme.S
+++ b/SourceGen/SGTestData/Expected/20150-local-variables_acme.S
@@ -5,8 +5,7 @@ CONST_ZERO = $f0 ;project const
PROJ_ZERO = $00 ;project addr
PROJ_ONE = $01 ;project addr
-* = $0000
- !pseudopc $1000 {
+* = $1000
ldy PROJ_ZERO
lda (PROJ_ONE),y
sta $03 ;could be PROJ_ONE+2, but "nearby" is off
@@ -186,7 +185,6 @@ L103C lda #$fe
jsr DPCODE
rts
- } ;!pseudopc
!pseudopc $0080 {
DPCODE nop
lda+1 DPCODE
diff --git a/SourceGen/SGTestData/Expected/20150-local-variables_cc65.S b/SourceGen/SGTestData/Expected/20150-local-variables_cc65.S
index 539c900..befb248 100644
--- a/SourceGen/SGTestData/Expected/20150-local-variables_cc65.S
+++ b/SourceGen/SGTestData/Expected/20150-local-variables_cc65.S
@@ -5,7 +5,6 @@ CONST_ZERO = $f0 ;project const
PROJ_ZERO = $00 ;project addr
PROJ_ONE = $01 ;project addr
-; .segment "SEG000"
.org $1000
ldy PROJ_ZERO
lda (PROJ_ONE),y
@@ -99,7 +98,6 @@ DPNOP .set $80 ;same as org
jsr DPCODE
rts
-; .segment "SEG001"
.org $0080
DPCODE: nop
lda DPCODE
diff --git a/SourceGen/SGTestData/Expected/20150-local-variables_cc65.cfg b/SourceGen/SGTestData/Expected/20150-local-variables_cc65.cfg
index 7dd034c..8a03da0 100644
--- a/SourceGen/SGTestData/Expected/20150-local-variables_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20150-local-variables_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20150-local-variables
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=126;
-# MEM001: file=%O, start=$0080, size=25;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20152-local-variables_acme.S b/SourceGen/SGTestData/Expected/20152-local-variables_acme.S
index 2b5c8b2..1a2308c 100644
--- a/SourceGen/SGTestData/Expected/20152-local-variables_acme.S
+++ b/SourceGen/SGTestData/Expected/20152-local-variables_acme.S
@@ -5,8 +5,7 @@ CONST_ZERO = $f0 ;project const
PROJ_ZERO = $00 ;project addr
PROJ_ONE = $01 ;project addr
-* = $0000
- !pseudopc $1000 {
+* = $1000
!as
!rs
ldy PROJ_ZERO
@@ -188,7 +187,6 @@ L103C lda #$fe
jsr DPCODE
rts
- } ;!pseudopc
!pseudopc $0080 {
DPCODE nop
lda+1 DPCODE
diff --git a/SourceGen/SGTestData/Expected/20152-local-variables_cc65.S b/SourceGen/SGTestData/Expected/20152-local-variables_cc65.S
index 697983e..1e22824 100644
--- a/SourceGen/SGTestData/Expected/20152-local-variables_cc65.S
+++ b/SourceGen/SGTestData/Expected/20152-local-variables_cc65.S
@@ -5,7 +5,6 @@ CONST_ZERO = $f0 ;project const
PROJ_ZERO = $00 ;project addr
PROJ_ONE = $01 ;project addr
-; .segment "SEG000"
.org $1000
.a8
.i8
@@ -101,7 +100,6 @@ DPNOP .set $80 ;same as org
jsr DPCODE
rts
-; .segment "SEG001"
.org $0080
DPCODE: nop
lda DPCODE
diff --git a/SourceGen/SGTestData/Expected/20152-local-variables_cc65.cfg b/SourceGen/SGTestData/Expected/20152-local-variables_cc65.cfg
index b8d33a4..3aa4720 100644
--- a/SourceGen/SGTestData/Expected/20152-local-variables_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20152-local-variables_cc65.cfg
@@ -1,13 +1,9 @@
# 6502bench SourceGen generated linker script for 20152-local-variables
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=126;
-# MEM001: file=%O, start=$0080, size=111;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.S b/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.S
index 8ef3238..d486caf 100644
--- a/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.S
+++ b/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $10f0
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.cfg b/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.cfg
index fdb654f..2694ddf 100644
--- a/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20162-cycle-counts-65816_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20162-cycle-counts-65816
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$10f0, size=126;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.S b/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.S
index 1068270..1378fa4 100644
--- a/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.S
+++ b/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.S
@@ -38,7 +38,6 @@ MoreMultiZero = $c100
AlsoMoreMultiZero = $c110 ;winner
BankWrap = $fff0
-; .segment "SEG000"
.org $1000
L1000: lda CodeWrap+255
ldx L1000
diff --git a/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.cfg b/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.cfg
index ca810ca..66df45c 100644
--- a/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20170-external-symbols_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20170-external-symbols
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=353;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.S b/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.S
index 10a64a6..d457a60 100644
--- a/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.S
+++ b/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.S
@@ -9,7 +9,6 @@ hiaddr = $e0c030
addr_e2 = $e2c030
addr_e3 = $e3c030
-; .segment "SEG000"
.org $1000
.a8
.i8
diff --git a/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.cfg b/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.cfg
index 3a1ab21..72068c1 100644
--- a/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20172-external-symbols_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20172-external-symbols
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=258;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S b/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S
index bffe456..5ae107f 100644
--- a/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S
+++ b/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S
@@ -3,8 +3,7 @@ PrintInlineL1String = $011000
PrintInlineL2String = $012000
PrintInlineDciString = $013000
-* = $0000
- !pseudopc $1000 {
+* = $1000
!as
!rs
clc
@@ -102,7 +101,6 @@ Next1 jsr L10BA
!fill 289,$00
- } ;!pseudopc
!pseudopc $1800 {
L1800 jsr PrintInlineNullString
per $8778
diff --git a/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.S b/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.S
index 2958a9e..dd81e5b 100644
--- a/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.S
+++ b/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.S
@@ -3,7 +3,6 @@ PrintInlineL1String = $011000
PrintInlineL2String = $012000
PrintInlineDciString = $013000
-; .segment "SEG000"
.org $1000
.a8
.i8
@@ -105,7 +104,6 @@ Next1: jsr L10BA
.res 289,$00
-; .segment "SEG001"
.org $1800
L1800: jsr PrintInlineNullString
per $8778
@@ -115,7 +113,6 @@ L1800: jsr PrintInlineNullString
.byte $6e
.byte $20
.byte $01
-; .segment "SEG002"
.org $1840
.byte "string"
.byte $00
diff --git a/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.cfg b/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.cfg
index fc2a598..5050c53 100644
--- a/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20182-extension-scripts_cc65.cfg
@@ -1,15 +1,9 @@
# 6502bench SourceGen generated linker script for 20182-extension-scripts
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=512;
-# MEM001: file=%O, start=$1800, size=11;
-# MEM002: file=%O, start=$1840, size=21;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.S b/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.S
index 577d395..ea72427 100644
--- a/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.S
+++ b/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.S
@@ -1,5 +1,4 @@
.setcpu "6502"
-; .segment "SEG000"
.org $1000
L1000: lda #$00
@L1000: lda #$01
diff --git a/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.cfg b/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.cfg
index 363f3e1..d7ef73a 100644
--- a/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20190-non-unique-labels_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20190-non-unique-labels
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=180;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S
index e5abe21..b714551 100644
--- a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S
+++ b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S
@@ -1,10 +1,8 @@
!cpu 6502
-* = $0000
- !pseudopc $2000 {
+* = $2000
jmp L2100
!text "hello, " ;string should be split by no-op addr change
- } ;!pseudopc
!pseudopc $200a {
!text "world"
!byte $80
diff --git a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.S b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.S
index aff9ea9..fea5485 100644
--- a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.S
+++ b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.S
@@ -1,15 +1,12 @@
.setcpu "6502"
-; .segment "SEG000"
.org $2000
jmp L2100
.byte "hello, " ;string should be split by no-op addr change
-; .segment "SEG001"
.org $200a
.byte "world"
.byte $80
-; .segment "SEG002"
.org $2100
L2100: lda #$00
sta addr1-1 ;edit this operand
diff --git a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.cfg b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.cfg
index 823fa3d..8beae5e 100644
--- a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_cc65.cfg
@@ -1,15 +1,9 @@
# 6502bench SourceGen generated linker script for 20200-ui-edge-cases
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$2000, size=10;
-# MEM001: file=%O, start=$200a, size=6;
-# MEM002: file=%O, start=$2100, size=34;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.S b/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.S
index a534c09..ff322e2 100644
--- a/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.S
+++ b/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $030000
.a16
.i16
@@ -76,7 +75,6 @@ L30000: clc
@L3008E: rts
-; .segment "SEG001"
.org $04ffe0
@L4FFE0: .faraddr @L4FFE0
.byte $00
@@ -108,7 +106,6 @@ L30000: clc
.byte $19
.byte $1a
.byte $1b
-; .segment "SEG002"
.org $050000
.byte $1c
.byte $1d
@@ -116,7 +113,6 @@ L30000: clc
.byte $1f
.byte " !",$22,"#$%&'()*+,-./"
-; .segment "SEG003"
.org $023456
.a8
.i8
@@ -132,7 +128,6 @@ L30000: clc
@L23477: nop
rts
-; .segment "SEG004"
.org $080000
@L80000: lda @L80000
lda a:@L80019 & $ffff
@@ -154,6 +149,5 @@ L30000: clc
.byte $00
@L80026: .byte "This is a test."
.byte $00
-; .segment "SEG005"
.org $060000
.byte "hello, world!"
diff --git a/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.cfg b/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.cfg
index 474aca6..6320b92 100644
--- a/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20212-reloc-data_cc65.cfg
@@ -1,21 +1,9 @@
# 6502bench SourceGen generated linker script for 20212-reloc-data
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$30000, size=143;
-# MEM001: file=%O, start=$4ffe0, size=32;
-# MEM002: file=%O, start=$50000, size=20;
-# MEM003: file=%O, start=$23456, size=35;
-# MEM004: file=%O, start=$80000, size=54;
-# MEM005: file=%O, start=$60000, size=13;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
-# SEG004: load=MEM004, type=rw;
-# SEG005: load=MEM005, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20222-data-bank_acme.S b/SourceGen/SGTestData/Expected/20222-data-bank_acme.S
index d80b9d3..b89ed2b 100644
--- a/SourceGen/SGTestData/Expected/20222-data-bank_acme.S
+++ b/SourceGen/SGTestData/Expected/20222-data-bank_acme.S
@@ -1,9 +1,7 @@
;ACME can't handle 65816 code that lives outside bank zero
-* = $0000
- !pseudopc $1000 {
+* = $1000
!hex 18fbe230ad0010ad00204babad0010ad0020a90248abad0010ad0020a208aa48
!hex ab2200200222004002a90248ab220030034bab2c00105c0f40023c10602e2002
!hex af002002ad0020a200202b20202520202820eaa90348abad2830c230a9a90048
!hex ababe2306b6c3a10dc3d107c3020ea602e20af003003ad0020202030f0184bab
!hex ea8000ad30206b2830af0040028b4babad0020ad0030ab6b60
- } ;!pseudopc
diff --git a/SourceGen/SGTestData/Expected/20222-data-bank_cc65.S b/SourceGen/SGTestData/Expected/20222-data-bank_cc65.S
index 726c682..4a6f2d1 100644
--- a/SourceGen/SGTestData/Expected/20222-data-bank_cc65.S
+++ b/SourceGen/SGTestData/Expected/20222-data-bank_cc65.S
@@ -1,5 +1,4 @@
.setcpu "65816"
-; .segment "SEG000"
.org $1000
.a8
.i8
@@ -38,7 +37,6 @@ L103A: .word @L103C
L103D: .faraddr L2202E
-; .segment "SEG001"
.org $022000
bank2: lda bank2
lda bank2 & $ffff
@@ -74,14 +72,12 @@ L2202E: nop
bank2addr: .word L2202E & $ffff
-; .segment "SEG002"
.org $033000
bank3: lda bank3
lda bank2 & $ffff
jsr @L33020 & $ffff
beq @L33024
phk
-; .segment "SEG003"
.org $033020
@L33020: plb
nop
@@ -92,7 +88,6 @@ bank3: lda bank3
L33028: .word L33028 & $ffff
-; .segment "SEG004"
.org $024000
L24000: lda L24000
phb
diff --git a/SourceGen/SGTestData/Expected/20222-data-bank_cc65.cfg b/SourceGen/SGTestData/Expected/20222-data-bank_cc65.cfg
index 7a2c4d9..94dcab8 100644
--- a/SourceGen/SGTestData/Expected/20222-data-bank_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20222-data-bank_cc65.cfg
@@ -1,19 +1,9 @@
# 6502bench SourceGen generated linker script for 20222-data-bank
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=64;
-# MEM001: file=%O, start=$22000, size=50;
-# MEM002: file=%O, start=$33000, size=13;
-# MEM003: file=%O, start=$33020, size=10;
-# MEM004: file=%O, start=$24000, size=16;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
-# SEG004: load=MEM004, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20233-rockwell_cc65.S b/SourceGen/SGTestData/Expected/20233-rockwell_cc65.S
index 57bf0de..1ff4900 100644
--- a/SourceGen/SGTestData/Expected/20233-rockwell_cc65.S
+++ b/SourceGen/SGTestData/Expected/20233-rockwell_cc65.S
@@ -1,7 +1,6 @@
.setcpu "65C02"
G_DP = $20
-; .segment "SEG000"
.org $1000
bbr0 $10,L1004
rts
diff --git a/SourceGen/SGTestData/Expected/20233-rockwell_cc65.cfg b/SourceGen/SGTestData/Expected/20233-rockwell_cc65.cfg
index fcafbed..8356762 100644
--- a/SourceGen/SGTestData/Expected/20233-rockwell_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20233-rockwell_cc65.cfg
@@ -1,11 +1,9 @@
# 6502bench SourceGen generated linker script for 20233-rockwell
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=44;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.S b/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.S
index 747537a..ea28714 100644
--- a/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.S
+++ b/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.S
@@ -1,26 +1,18 @@
.setcpu "6502"
-; .segment "SEG000"
.org $8000
.byte $ea
.res 8191,$00
-; .segment "SEG001"
.org $8000
.res 8192,$01
-; .segment "SEG002"
.org $8000
.res 8192,$02
-; .segment "SEG003"
.org $8000
.res 8192,$03
-; .segment "SEG004"
.org $8000
.res 8192,$04
-; .segment "SEG005"
.org $8000
.res 8192,$05
-; .segment "SEG006"
.org $8000
.res 8192,$06
-; .segment "SEG007"
.org $8000
.res 8192,$07
diff --git a/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.cfg b/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.cfg
index d7476ab..75c6ce0 100644
--- a/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20240-large-overlay_cc65.cfg
@@ -1,25 +1,9 @@
# 6502bench SourceGen generated linker script for 20240-large-overlay
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$8000, size=8192;
-# MEM001: file=%O, start=$8000, size=8192;
-# MEM002: file=%O, start=$8000, size=8192;
-# MEM003: file=%O, start=$8000, size=8192;
-# MEM004: file=%O, start=$8000, size=8192;
-# MEM005: file=%O, start=$8000, size=8192;
-# MEM006: file=%O, start=$8000, size=8192;
-# MEM007: file=%O, start=$8000, size=8192;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
-# SEG000: load=MEM000, type=rw;
-# SEG001: load=MEM001, type=rw;
-# SEG002: load=MEM002, type=rw;
-# SEG003: load=MEM003, type=rw;
-# SEG004: load=MEM004, type=rw;
-# SEG005: load=MEM005, type=rw;
-# SEG006: load=MEM006, type=rw;
-# SEG007: load=MEM007, type=rw;
}
FEATURES {}
SYMBOLS {}
diff --git a/SourceGen/Sandbox/ScriptManager.cs b/SourceGen/Sandbox/ScriptManager.cs
index b777101..c144eac 100644
--- a/SourceGen/Sandbox/ScriptManager.cs
+++ b/SourceGen/Sandbox/ScriptManager.cs
@@ -272,8 +272,10 @@ namespace SourceGen.Sandbox {
}
} else {
CheckHealth();
- List addrEnts = mProject.AddrMap.GetEntryList();
- DomainMgr.PluginMgr.PreparePlugins(appRef, addrEnts, plSyms);
+ int spanLength;
+ List addrEnts =
+ mProject.AddrMap.GetEntryList(out spanLength);
+ DomainMgr.PluginMgr.PreparePlugins(appRef, spanLength, addrEnts, plSyms);
}
}
diff --git a/SourceGen/Tools/Omf/Loader.cs b/SourceGen/Tools/Omf/Loader.cs
index 423577c..4f228d6 100644
--- a/SourceGen/Tools/Omf/Loader.cs
+++ b/SourceGen/Tools/Omf/Loader.cs
@@ -607,7 +607,7 @@ namespace SourceGen.Tools.Omf {
while (true) {
// Generate an ORG directive.
- int origAddr = proj.AddrMap.Get(bufOffset);
+ int origAddr = proj.AddrMap.OffsetToAddress(bufOffset);
UndoableChange uc = UndoableChange.CreateAddressChange(bufOffset,
origAddr, addr);
cs.Add(uc);
diff --git a/SourceGen/WpfGui/EditAddress.xaml.cs b/SourceGen/WpfGui/EditAddress.xaml.cs
index a44b9f4..92c833b 100644
--- a/SourceGen/WpfGui/EditAddress.xaml.cs
+++ b/SourceGen/WpfGui/EditAddress.xaml.cs
@@ -164,7 +164,7 @@ namespace SourceGen.WpfGui {
private void OkButton_Click(object sender, RoutedEventArgs e) {
if (AddressText.Length == 0) {
- NewAddress = CommonUtil.AddressMap.NO_ENTRY_ADDR;
+ NewAddress = CommonUtil.AddressMap.NON_ADDR;
} else {
bool ok = Asm65.Address.ParseAddress(AddressText, mMaxAddressValue, out int addr);
Debug.Assert(ok);
diff --git a/SourceGen/WpfGui/EditDataBank.xaml.cs b/SourceGen/WpfGui/EditDataBank.xaml.cs
index 93ce234..fa2607a 100644
--- a/SourceGen/WpfGui/EditDataBank.xaml.cs
+++ b/SourceGen/WpfGui/EditDataBank.xaml.cs
@@ -99,7 +99,7 @@ namespace SourceGen.WpfGui {
bool[] done = new bool[256];
foreach (AddressMap.AddressMapEntry ent in mProject.AddrMap) {
- byte bank = (byte)(ent.Addr >> 16);
+ byte bank = (byte)(ent.Address >> 16);
if (done[bank]) {
continue;
}