diff --git a/Asm65/Address.cs b/Asm65/Address.cs
index 204ca50..955855d 100644
--- a/Asm65/Address.cs
+++ b/Asm65/Address.cs
@@ -17,12 +17,16 @@ using System;
using System.Diagnostics;
namespace Asm65 {
+ ///
+ /// Memory address primitives.
+ ///
public static class Address {
///
/// Converts a 16- or 24-bit address to a string.
///
- ///
- ///
+ /// Address
+ /// If true, force 24-bit output mode.
+ /// Formatted string.
public static string AddressToString(int addr, bool always24) {
if (!always24 && addr < 65536) {
return addr.ToString("x4");
diff --git a/CommonUtil/AddressMap.cs b/CommonUtil/AddressMap.cs
index b661401..d2609c0 100644
--- a/CommonUtil/AddressMap.cs
+++ b/CommonUtil/AddressMap.cs
@@ -83,6 +83,11 @@ namespace CommonUtil {
///
public const int NON_ADDR = -1025;
+ ///
+ /// Address value to use for an invalid address.
+ ///
+ public const int INVALID_ADDR = -2048;
+
#region Structural
///
@@ -141,6 +146,27 @@ namespace CommonUtil {
" addr=$" + Address.ToString("x4") + " preLab='" + PreLabel +
"' isRel=" + IsRelative + "]";
}
+
+ public static bool operator ==(AddressMapEntry a, AddressMapEntry b) {
+ if (ReferenceEquals(a, b)) {
+ return true; // same object, or both null
+ }
+ if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) {
+ return false; // one is null
+ }
+ // All fields must be equal.
+ return a.Offset == b.Offset && a.Length == b.Length && a.Address == b.Address &&
+ a.PreLabel == b.PreLabel && a.IsRelative == b.IsRelative;
+ }
+ public static bool operator !=(AddressMapEntry a, AddressMapEntry b) {
+ return !(a == b);
+ }
+ public override bool Equals(object obj) {
+ return obj is AddressMapEntry && this == (AddressMapEntry)obj;
+ }
+ public override int GetHashCode() {
+ return Offset ^ Length ^ Address ^ PreLabel.GetHashCode() ^ (IsRelative ? 1 : 0);
+ }
}
///
@@ -154,52 +180,49 @@ namespace CommonUtil {
///
public class AddressRegion : AddressMapEntry {
///
- /// Is the end point floating?
+ /// Actual length (after FLOATING_LEN is resolved).
///
- ///
- /// (In the structural list this is redundant with the FLOATING_LEN Length value,
- /// but in the other structures a new instance that has the actual length is created.)
- ///
- public bool IsFloating { get; private set; }
+ public int ActualLength { get; private set; }
///
/// Address associated with pre-label.
///
public int PreLabelAddress { get; private set; }
+ ///
+ /// Is the end point floating?
+ ///
+ public bool IsFloating {
+ get {
+ return Length == FLOATING_LEN;
+ }
+ }
+
+
///
/// Full constructor.
///
- public AddressRegion(int offset, int len, int addr, bool isFloating,
- string preLabel, int prevAddr, bool isRelative)
+ public AddressRegion(int offset, int len, int addr, string preLabel, bool isRelative,
+ int actualLen, int preLabelAddr)
: base(offset, len, addr, preLabel, isRelative) {
- IsFloating = isFloating;
- PreLabelAddress = prevAddr;
+ ActualLength = actualLen;
+ PreLabelAddress = preLabelAddr;
- Debug.Assert(Length != FLOATING_LEN);
+ Debug.Assert(ActualLength != FLOATING_LEN);
}
///
- /// Basic constructor.
+ /// Basic constructor. Not for use when len==FLOATING_LEN.
///
public AddressRegion(int offset, int len, int addr)
- : this(offset, len, addr, addr == FLOATING_LEN ? true : false,
- string.Empty, NON_ADDR, false) {
- }
-
- ///
- /// Construct from AddressRegion.
- ///
- public AddressRegion(AddressMapEntry region)
- : this(region.Offset, region.Length, region.Address,
- region.Address == FLOATING_LEN ? true : false,
- region.PreLabel, NON_ADDR, region.IsRelative) {
+ : this(offset, len, addr, string.Empty, false, len, NON_ADDR) {
+ Debug.Assert(len != FLOATING_LEN);
}
public override string ToString() {
- return "[AddrRegion: +" + Offset.ToString("x6") + " len=$" + Length.ToString("x4") +
- " addr=$" + Address.ToString("x4") + " isFloat=" + IsFloating +
- " isRel=" + IsRelative + "]";
+ return "[AddrRegion: +" + Offset.ToString("x6") + " len=$" +
+ Length.ToString("x4") + " addr=$" + Address.ToString("x4") +
+ " actualLen=$" + ActualLength.ToString("x4") + " isRel=" + IsRelative + "]";
}
}
@@ -235,7 +258,7 @@ namespace CommonUtil {
// (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) {
- AddResult result = AddRegion(ent.Offset, ent.Length, ent.Address, ent.PreLabel,
+ AddResult result = AddEntry(ent.Offset, ent.Length, ent.Address, ent.PreLabel,
ent.IsRelative);
if (result != AddResult.Okay) {
throw new Exception("Unable to add entry (" + result + "): " + ent);
@@ -277,10 +300,10 @@ namespace CommonUtil {
///
/// Number of entries in the address map.
///
- public int RegionCount { get { return mMapEntries.Count; } }
+ public int EntryCount { get { return mMapEntries.Count; } }
///
- /// Error codes for AddRegion().
+ /// Error codes for AddEntry().
///
public enum AddResult {
Unknown = 0,
@@ -319,18 +342,30 @@ namespace CommonUtil {
}
///
- /// Adds a new region.
+ /// Adds a new entry to the map.
///
/// File offset of region start.
/// Length of region, or FLOATING_LEN for a floating end point.
/// Address of region start.
/// Failure code.
- public AddResult AddRegion(int offset, int length, int addr) {
- return AddRegion(offset, length, addr, string.Empty, false);
+ public AddResult AddEntry(int offset, int length, int addr) {
+ return AddEntry(offset, length, addr, string.Empty, false);
}
///
- /// Adds a new region.
+ /// Adds a new entry to the map.
+ ///
+ /// Entry object.
+ /// Failure code.
+ public AddResult AddEntry(AddressMapEntry entry) {
+ // Slightly inefficient to extract the fields and reassemble them, which we can
+ // avoid since instances are immutable, but it's not worth coding around.
+ return AddEntry(entry.Offset, entry.Length, entry.Address, entry.PreLabel,
+ entry.IsRelative);
+ }
+
+ ///
+ /// Adds a new entry to the map.
///
/// File offset of region start.
/// Length of region, or FLOATING_LEN for a floating end point.
@@ -339,10 +374,10 @@ namespace CommonUtil {
/// True if code generator should output relative
/// assembler directive operand.
/// Failure code.
- public AddResult AddRegion(int offset, int length, int addr, string preLabel,
+ public AddResult AddEntry(int offset, int length, int addr, string preLabel,
bool isRelative) {
if (!ValidateArgs(offset, length, addr, preLabel)) {
- Debug.WriteLine("AddRegion: invalid arg");
+ Debug.WriteLine("AddEntry: invalid arg");
return AddResult.InvalidValue;
}
int insIdx;
@@ -472,13 +507,13 @@ namespace CommonUtil {
/// Pre-block label.
/// New value for IsRelative.
/// True if a region was edited, false otherwise.
- public bool EditRegion(int offset, int length, int addr, string preLabel, bool isRelative) {
+ public bool EditEntry(int offset, int length, int addr, string preLabel, bool isRelative) {
if (!ValidateArgs(offset, length, addr, preLabel)) {
throw new Exception("Bad EditRegion args +" + offset.ToString("x6") +
" " + length + " $" + addr);
}
- int idx = FindRegion(offset, length);
+ int idx = FindEntry(offset, length);
if (idx < 0) {
return false;
}
@@ -493,13 +528,13 @@ namespace CommonUtil {
/// 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) {
+ public bool RemoveEntry(int offset, int length) {
if (!ValidateArgs(offset, length, 0, string.Empty)) {
throw new Exception("Bad RemoveRegion args +" + offset.ToString("x6") +
" " + length);
}
- int idx = FindRegion(offset, length);
+ int idx = FindEntry(offset, length);
if (idx < 0) {
return false;
}
@@ -509,12 +544,12 @@ namespace CommonUtil {
}
///
- /// Finds a region with a matching offset and length.
+ /// Finds an entry 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) {
+ /// Index of matching entry, or -1 if not found.
+ private int FindEntry(int offset, int length) {
for (int i = 0; i < mMapEntries.Count; i++) {
if (mMapEntries[i].Offset == offset && mMapEntries[i].Length == length) {
return i;
@@ -531,26 +566,11 @@ namespace CommonUtil {
//}
///
- /// 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.
+ /// Gets a list of the entries with the specified offset value.
///
/// File offset.
/// List of entries; may be empty.
- public List GetRegions(int offset) {
+ public List GetEntries(int offset) {
List regions = new List();
for (int i = 0; i < mMapEntries.Count; i++) {
if (mMapEntries[i].Offset == offset) {
@@ -653,7 +673,7 @@ namespace CommonUtil {
/// reconstructed whenever a change is made.
///
/// We need to resolve floating lengths and pre-label addresses, so the tree holds
- /// AddressMapEntry rather than AddressRegion.
+ /// AddressRegion rather than AddressMapEntry.
///
private class TreeNode {
public AddressRegion Region { get; set; }
@@ -682,8 +702,8 @@ namespace CommonUtil {
// 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.
- AddressRegion globalReg = new AddressRegion(0, mSpanLength, NON_ADDR, false,
- string.Empty, NON_ADDR, false);
+ AddressRegion globalReg = new AddressRegion(0, mSpanLength, NON_ADDR, string.Empty,
+ false, mSpanLength, NON_ADDR);
TreeNode topNode = new TreeNode(globalReg, null);
// Generate the children of this node.
@@ -730,7 +750,7 @@ namespace CommonUtil {
//
// Regions with floating ends can't have children, so we don't need to
// check for sub-regions.
- int nextStart = parent.Region.Offset + parent.Region.Length;
+ int nextStart = parent.Region.Offset + parent.Region.ActualLength;
index++;
if (index < mMapEntries.Count) {
// Check next sibling.
@@ -740,16 +760,16 @@ namespace CommonUtil {
}
}
AddressRegion fixedReg = new AddressRegion(childEnt.Offset,
- nextStart - childEnt.Offset, childEnt.Address, true,
- childEnt.PreLabel, preLabelAddr, childEnt.IsRelative);
+ FLOATING_LEN, childEnt.Address, childEnt.PreLabel, childEnt.IsRelative,
+ nextStart - childEnt.Offset, preLabelAddr);
children.Add(new TreeNode(fixedReg, parent));
// "index" now points to entry past the child we just added.
} else {
// Add this region to the list, and check for descendants.
AddressRegion newReg = new AddressRegion(childEnt.Offset,
- childEnt.Length, childEnt.Address, false,
- childEnt.PreLabel, preLabelAddr, childEnt.IsRelative);
+ childEnt.Length, childEnt.Address, childEnt.PreLabel,
+ childEnt.IsRelative, childEnt.Length, preLabelAddr);
TreeNode thisNode = new TreeNode(newReg, parent);
children.Add(thisNode);
@@ -857,7 +877,7 @@ namespace CommonUtil {
// Non-addressable space.
return -1;
}
- if (targetAddr < region.Address || targetAddr >= region.Address + region.Length) {
+ if (targetAddr < region.Address || targetAddr >= region.Address + region.ActualLength) {
// Outside our range of addresses, return failure.
return -1;
}
@@ -869,7 +889,7 @@ namespace CommonUtil {
foreach (TreeNode childNode in node.Children) {
AddressRegion childReg = childNode.Region;
int childStartPosn = childReg.Offset - region.Offset;
- int childEndPosn = childStartPosn + childReg.Length;
+ int childEndPosn = childStartPosn + childReg.ActualLength;
if (childStartPosn > subPosn) {
// Child is past the target, it's not in a hole; no need to check
@@ -904,7 +924,7 @@ namespace CommonUtil {
int ourAddr = NON_ADDR;
if (node.Region.Address != NON_ADDR) {
ourAddr = node.Region.Address + (offset - node.Region.Offset);
- Debug.Assert(ourAddr < node.Region.Address + node.Region.Length);
+ Debug.Assert(ourAddr < node.Region.Address + node.Region.ActualLength);
}
return ourAddr;
}
@@ -919,7 +939,8 @@ namespace CommonUtil {
if (node.Children != null) {
foreach (TreeNode child in node.Children) {
AddressRegion childReg = child.Region;
- if (offset >= childReg.Offset && offset < childReg.Offset + childReg.Length) {
+ if (offset >= childReg.Offset &&
+ offset < childReg.Offset + childReg.ActualLength) {
// It's in or below this child. Check it with tail recursion.
return OffsetToNode(offset, child);
}
@@ -928,6 +949,48 @@ namespace CommonUtil {
return node;
}
+ ///
+ /// Finds a region with a matching offset and length.
+ ///
+ ///
+ /// We want the AddressRegion object, not the AddressMapEntry, so we need to walk through
+ /// the tree to find it.
+ ///
+ /// Region start offset.
+ /// Region length. May be FLOATING_LEN.
+ /// Region found, or null if not.
+ public AddressRegion FindRegion(int offset, int length) {
+ if (!ValidateArgs(offset, length, 0, string.Empty)) {
+ Debug.Assert(false, "Invalid args to FindRegion");
+ return null;
+ }
+ TreeNode curNode = mTopNode;
+ while (curNode != null) {
+ // Check for exact match.
+ if (curNode.Region.Offset == offset && curNode.Region.Length == length) {
+ // found it
+ return curNode.Region;
+ }
+
+ // Look for a child that includes the offset.
+ if (curNode.Children == null) {
+ // Not found, bail.
+ break;
+ }
+ TreeNode foundNode = null;
+ foreach (TreeNode childNode in curNode.Children) {
+ if (offset >= childNode.Region.Offset &&
+ offset < childNode.Region.Offset + childNode.Region.ActualLength) {
+ foundNode = childNode;
+ break;
+ }
+ }
+ curNode = foundNode;
+ }
+
+ return null;
+ }
+
///
/// 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
@@ -955,9 +1018,9 @@ namespace CommonUtil {
TreeNode node = OffsetToNode(offset, mTopNode);
AddressRegion region = node.Region;
- Debug.Assert(offset >= region.Offset && offset < region.Offset + region.Length);
+ Debug.Assert(offset >= region.Offset && offset < region.Offset + region.ActualLength);
int lastOffset = offset + length - 1; // offset of last byte in range
- if (lastOffset >= region.Offset + region.Length) {
+ if (lastOffset >= region.Offset + region.ActualLength) {
// end of region is not in this node
return false;
}
@@ -971,7 +1034,7 @@ namespace CommonUtil {
// 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 <= childReg.Offset + childReg.Length - 1 &&
+ } else if (offset <= childReg.Offset + childReg.ActualLength - 1 &&
lastOffset >= childReg.Offset) {
// Target is in a hole occupied by the child. No good.
return false;
@@ -983,7 +1046,7 @@ namespace CommonUtil {
}
private bool DebugValidateHierarchical() {
- if (mTopNode.Region.Offset != 0 || mTopNode.Region.Length != mSpanLength) {
+ if (mTopNode.Region.Offset != 0 || mTopNode.Region.ActualLength != mSpanLength) {
Debug.WriteLine("Malformed top node");
return false;
}
@@ -1006,19 +1069,19 @@ namespace CommonUtil {
private bool DebugValidateHierarchy(List nodeList, int startOffset,
int nextOffset, ref int nodeCount) {
foreach (TreeNode node in nodeList) {
- Debug.Assert(node.Region.Length >= 0); // no floaters
+ Debug.Assert(node.Region.ActualLength >= 0);
nodeCount++;
if (node.Region.Offset < startOffset ||
- node.Region.Offset + node.Region.Length > nextOffset) {
+ node.Region.Offset + node.Region.ActualLength > nextOffset) {
Debug.WriteLine("Child node did not fit in parent bounds");
return false;
}
if (node.Children != null) {
// Descend recursively.
if (!DebugValidateHierarchy(node.Children, node.Region.Offset,
- node.Region.Offset + node.Region.Length, ref nodeCount)) {
+ node.Region.Offset + node.Region.ActualLength, ref nodeCount)) {
return false;
}
}
@@ -1076,7 +1139,7 @@ namespace CommonUtil {
if (mTopNode.Children != null) {
foreach (TreeNode node in mTopNode.Children) {
- Debug.Assert(node.Region.Length > 0); // all floaters should be resolved
+ Debug.Assert(node.Region.ActualLength > 0);
if (node.Region.Offset != startOffset) {
// Insert a no-address zone here.
@@ -1090,7 +1153,7 @@ namespace CommonUtil {
AddChangeEntry(changeList, node, NON_ADDR);
- startOffset = node.Region.Offset + node.Region.Length;
+ startOffset = node.Region.Offset + node.Region.ActualLength;
}
}
@@ -1125,15 +1188,15 @@ namespace CommonUtil {
/// parent's region.
private void AddChangeEntry(List changeList, TreeNode node,
int parentStartAddr) {
- Debug.Assert(node.Region.Length != FLOATING_LEN);
+ Debug.Assert(node.Region.ActualLength != FLOATING_LEN);
int nextAddr = NON_ADDR;
if (parentStartAddr != NON_ADDR) {
- nextAddr = parentStartAddr + node.Region.Length;
+ nextAddr = parentStartAddr + node.Region.ActualLength;
}
AddressChange startChange = new AddressChange(true,
node.Region.Offset, node.Region.Address, node.Region);
AddressChange endChange = new AddressChange(false,
- node.Region.Offset + node.Region.Length, nextAddr, node.Region);
+ node.Region.Offset + node.Region.ActualLength, nextAddr, node.Region);
changeList.Add(startChange);
int curAddr = node.Region.Address;
@@ -1278,6 +1341,80 @@ namespace CommonUtil {
}
}
+ private static bool Test_Primitives() {
+ bool result = true;
+
+ AddressMapEntry ent1 = new AddressMapEntry(0, 1, 2, "three", true);
+ AddressMapEntry ent2 = new AddressMapEntry(0, 1, 2, "three", true);
+ AddressMapEntry ent3 = new AddressMapEntry(0, 1, 2, "three-A", true);
+
+ result &= ent1 == ent2;
+ result &= ent1 != ent3;
+ result &= ent1.Equals(ent2);
+ Test_Expect(true, ref result, result);
+
+ AddressRegion reg1 = new AddressRegion(ent1.Offset, ent1.Length, ent1.Address,
+ ent1.PreLabel, ent1.IsRelative, ent1.Length, 0);
+ AddressRegion reg2 = new AddressRegion(ent2.Offset, ent2.Length, ent2.Address,
+ ent2.PreLabel, ent2.IsRelative, ent2.Length, 0);
+ AddressRegion reg3 = new AddressRegion(ent3.Offset, ent3.Length, ent3.Address,
+ ent3.PreLabel, ent3.IsRelative, ent3.Length, 0);
+
+ result &= reg1 == reg2;
+ result &= reg1 == ent1;
+ result &= reg1 == ent2;
+ result &= reg1 != ent3;
+ result &= reg3 != ent1;
+ result &= reg1.Equals(ent2);
+ result &= ent3 != reg1;
+ Test_Expect(true, ref result, result);
+
+ result &= ent1.GetHashCode() == ent2.GetHashCode();
+ result &= ent2.GetHashCode() != ent3.GetHashCode();
+ Test_Expect(true, ref result, result);
+
+ return result;
+ }
+
+ private static bool Test_Find() {
+ const int mapLen = 0x1000;
+ AddressMap map = new AddressMap(mapLen);
+ bool result = true;
+
+ const int off0 = 0x000100;
+ const int len0 = 0x0f00;
+ const int adr0 = 0x2100;
+ const int off1 = 0x000200;
+ const int len1 = 0x0400;
+ const int adr1 = 0x2200;
+ const int off2 = 0x000400;
+ const int len2 = FLOATING_LEN;
+ const int adr2 = 0x2400;
+
+ AddressMapEntry ent0 = new AddressMapEntry(off0, len0, adr0, string.Empty, false);
+ AddressMapEntry ent1 = new AddressMapEntry(off1, len1, adr1, string.Empty, false);
+ AddressMapEntry ent2 = new AddressMapEntry(off2, len2, adr2, string.Empty, false);
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(ent0));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(ent1));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(ent2));
+
+ AddressRegion reg;
+ reg = map.FindRegion(off0, len0);
+ Test_Expect(true, ref result, reg == ent0);
+ reg = map.FindRegion(off1, len1);
+ Test_Expect(true, ref result, reg == ent1);
+ reg = map.FindRegion(off2, len2);
+ Test_Expect(true, ref result, reg == ent2);
+
+ // Look for non-existent regions.
+ reg = map.FindRegion(0x000000, 0x100);
+ Test_Expect(true, ref result, reg == null);
+ reg = map.FindRegion(off0, len1);
+ Test_Expect(true, ref result, reg == null);
+
+ return result;
+ }
+
private static bool Test_SimpleLinear() {
const int mapLen = 0x8000;
AddressMap map = new AddressMap(mapLen);
@@ -1294,27 +1431,27 @@ namespace CommonUtil {
const int adr2 = 0x1700;
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off0, len0, adr0));
+ map.AddEntry(off0, len0, adr0));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off1, len1, adr1));
+ map.AddEntry(off1, len1, adr1));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off2, len2, adr2));
+ map.AddEntry(off2, len2, adr2));
result &= map.DebugValidate();
Test_Expect(AddResult.OverlapExisting, ref result,
- map.AddRegion(off0, len0, 0x1000));
+ map.AddEntry(off0, len0, 0x1000));
Test_Expect(AddResult.OverlapFloating, ref result,
- map.AddRegion(off0, FLOATING_LEN, 0x1000));
+ map.AddEntry(off0, FLOATING_LEN, 0x1000));
Test_Expect(AddResult.StraddleExisting, ref result,
- map.AddRegion(off0 + 1, len0, 0x1000));
+ map.AddEntry(off0 + 1, len0, 0x1000));
Test_Expect(AddResult.InvalidValue, ref result,
- map.AddRegion(off0, mapLen + 1, 0x1000));
+ map.AddEntry(off0, mapLen + 1, 0x1000));
// One region to wrap them all. Add then remove.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off0, mapLen, 0x0000));
- Test_Expect(true, ref result, map.RemoveRegion(off0, mapLen));
- Test_Expect(false, ref result, map.RemoveRegion(off0, mapLen));
+ map.AddEntry(off0, mapLen, 0x0000));
+ Test_Expect(true, ref result, map.RemoveEntry(off0, mapLen));
+ Test_Expect(false, ref result, map.RemoveEntry(off0, mapLen));
Test_Expect(adr0, ref result, map.OffsetToAddress(off0));
Test_Expect(adr1, ref result, map.OffsetToAddress(off1));
@@ -1354,16 +1491,16 @@ namespace CommonUtil {
const int adr2 = NON_ADDR;
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off0, len0, adr0));
+ map.AddEntry(off0, len0, adr0));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off1, len1, adr1));
+ map.AddEntry(off1, len1, adr1));
// Try to remove the implicit no-address zone.
- Test_Expect(false, ref result, map.RemoveRegion(0, off0));
+ Test_Expect(false, ref result, map.RemoveEntry(0, off0));
// Add non-addressable area into the middle of the second region.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(off2, len2, adr2));
+ map.AddEntry(off2, len2, adr2));
Test_Expect(adr0, ref result, map.OffsetToAddress(off0));
Test_Expect(adr1, ref result, map.OffsetToAddress(off1));
@@ -1390,56 +1527,56 @@ namespace CommonUtil {
bool result = true;
// Nested with shared start offset.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000100, 0x0400, 0x4000, "preA0", false));
+ map.AddEntry(0x000100, 0x0400, 0x4000, "preA0", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000100, 0x0100, 0x7000, "preA1", false));
+ map.AddEntry(0x000100, 0x0100, 0x7000, "preA1", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000100, 0x0300, 0x5000, "preA2", false));
+ map.AddEntry(0x000100, 0x0300, 0x5000, "preA2", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000100, 0x0200, 0x6000, "preA3", false));
+ map.AddEntry(0x000100, 0x0200, 0x6000, "preA3", false));
// Add a couple of floaters.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x0000ff, FLOATING_LEN, 0x30ff, "preA4", false));
+ map.AddEntry(0x0000ff, FLOATING_LEN, 0x30ff, "preA4", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000101, FLOATING_LEN, 0x3101, "preA5", false));
+ map.AddEntry(0x000101, FLOATING_LEN, 0x3101, "preA5", false));
Test_Expect(AddResult.OverlapFloating, ref result,
- map.AddRegion(0x000100, FLOATING_LEN, 0x3100, "preA6", false));
+ map.AddEntry(0x000100, FLOATING_LEN, 0x3100, "preA6", false));
// Nested with shared end offset.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000fff, FLOATING_LEN, 0x3fff, "preB0", false));
+ map.AddEntry(0x000fff, FLOATING_LEN, 0x3fff, "preB0", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x001200, 0x0200, 0x6000, "preB1", false));
+ map.AddEntry(0x001200, 0x0200, 0x6000, "preB1", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x001000, 0x0400, 0x4000, "preB2", false));
+ map.AddEntry(0x001000, 0x0400, 0x4000, "preB2", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x001100, 0x0300, 0x5000, "preB3", false));
+ map.AddEntry(0x001100, 0x0300, 0x5000, "preB3", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x001300, 0x0100, 0x7000, "preB4", false));
+ map.AddEntry(0x001300, 0x0100, 0x7000, "preB4", false));
// Single-byte region at start and end.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x001200, 1, 0x8200, "preB5", false));
+ map.AddEntry(0x001200, 1, 0x8200, "preB5", false));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x0013ff, 1, 0x83ff, "preB6", false));
+ map.AddEntry(0x0013ff, 1, 0x83ff, "preB6", false));
// Nested with no common edge, building from outside-in.
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x002000, 0x0800, 0x4000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x002100, 0x0600, 0x5000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x002200, 0x0400, 0x6000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x002300, 0x0200, 0x7000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002000, 0x0800, 0x4000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002100, 0x0600, 0x5000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002200, 0x0400, 0x6000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002300, 0x0200, 0x7000));
// Nested with no common edge, building from inside-out.
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x003300, 0x0200, 0x7000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x003200, 0x0400, 0x6000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x003100, 0x0600, 0x5000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x003000, 0x0800, 0x4000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x003300, 0x0200, 0x7000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x003200, 0x0400, 0x6000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x003100, 0x0600, 0x5000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x003000, 0x0800, 0x4000));
// Try floater then overlap.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x004000, FLOATING_LEN, 0x8000));
+ map.AddEntry(0x004000, FLOATING_LEN, 0x8000));
Test_Expect(AddResult.OverlapFloating, ref result,
- map.AddRegion(0x004000, 0x100, 0x8000));
- Test_Expect(true, ref result, map.RemoveRegion(0x004000, FLOATING_LEN));
+ map.AddEntry(0x004000, 0x100, 0x8000));
+ Test_Expect(true, ref result, map.RemoveEntry(0x004000, FLOATING_LEN));
Test_Expect(0x30ff, ref result, map.OffsetToAddress(0x0000ff));
Test_Expect(0x7000, ref result, map.OffsetToAddress(0x000100));
@@ -1466,10 +1603,10 @@ namespace CommonUtil {
AddressMap map = new AddressMap(mapLen);
bool result = true;
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x000000, 0x2000, 0x8000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x002000, 0x2000, 0x8000));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x002100, 0x0200, 0xe100));
- Test_Expect(AddResult.Okay, ref result, map.AddRegion(0x003100, 0x0200, 0xf100));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000000, 0x2000, 0x8000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002000, 0x2000, 0x8000));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002100, 0x0200, 0xe100));
+ Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x003100, 0x0200, 0xf100));
Test_Expect(0x003105, ref result, map.AddressToOffset(0x000000, 0xf105));
Test_Expect(0x003105, ref result, map.AddressToOffset(0x002100, 0xf105));
@@ -1504,19 +1641,19 @@ namespace CommonUtil {
// Pyramid shape, all regions start at same address except last.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x000000, 0x6000, 0x8000));
+ map.AddEntry(0x000000, 0x6000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x001000, 0x4000, 0x8000));
+ map.AddEntry(0x001000, 0x4000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x002000, 0x2000, 0x7fff));
+ map.AddEntry(0x002000, 0x2000, 0x7fff));
// Second pyramid.
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x006000, 0x6000, 0x8000));
+ map.AddEntry(0x006000, 0x6000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x007000, 0x4000, 0x8000));
+ map.AddEntry(0x007000, 0x4000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
- map.AddRegion(0x008000, 0x2000, 0x8000));
+ map.AddEntry(0x008000, 0x2000, 0x8000));
// Children take priority over the start node.
Test_Expect(0x002001, ref result, map.AddressToOffset(0x000000, 0x8000));
@@ -1559,6 +1696,8 @@ namespace CommonUtil {
public static bool Test() {
bool ok = true;
+ ok &= Test_Primitives();
+ ok &= Test_Find();
ok &= Test_SimpleLinear();
ok &= Test_SimpleFloatGap();
ok &= Test_Nested();
diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs
index 7e31cdf..d75a0ac 100644
--- a/SourceGen/AsmGen/AsmAcme.cs
+++ b/SourceGen/AsmGen/AsmAcme.cs
@@ -37,7 +37,6 @@ namespace SourceGen.AsmGen {
// makefile rules. Since ".S" is pretty universal for assembly language sources,
// I'm sticking with that.
private const string ASM_FILE_SUFFIX = "_acme.S"; // must start with underscore
- private const string CLOSE_PSEUDOPC = "} ;!pseudopc";
// IGenerator
public DisasmProject Project { get; private set; }
@@ -124,7 +123,8 @@ namespace SourceGen.AsmGen {
new PseudoOp.PseudoOpNames(new Dictionary {
{ "EquDirective", "=" },
//VarDirective
- { "OrgDirective", "!pseudopc" },
+ { "ArStartDirective", "!pseudopc" },
+ { "ArEndDirective", "}" },
//RegWidthDirective // !al, !as, !rl, !rs
//DataBankDirective
{ "DefineData1", "!byte" },
@@ -286,12 +286,12 @@ namespace SourceGen.AsmGen {
// don't try
OutputLine(SourceFormatter.FullLineCommentDelimiter +
"ACME can't handle 65816 code that lives outside bank zero");
- int orgAddr = Project.AddrMap.OffsetToAddress(0);
- AddressMap.AddressRegion fakeEnt = new AddressMap.AddressRegion(0,
- Project.FileData.Length, orgAddr);
- OutputOrgDirective(fakeEnt, true);
+ int firstAddr = Project.AddrMap.OffsetToAddress(0);
+ AddressMap.AddressRegion fakeRegion = new AddressMap.AddressRegion(0,
+ Project.FileData.Length, firstAddr);
+ OutputArDirective(fakeRegion, true);
OutputDenseHex(0, Project.FileData.Length, string.Empty, string.Empty);
- OutputOrgDirective(fakeEnt, false);
+ OutputArDirective(fakeRegion, false);
} else {
GenCommon.Generate(this, sw, worker);
}
@@ -568,7 +568,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
+ public void OutputArDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
// This is similar in operation to the AsmTass64 implementation. See comments there.
Debug.Assert(mPcDepth >= 0);
if (isStart) {
@@ -587,15 +587,19 @@ namespace SourceGen.AsmGen {
OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
}
}
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
- SourceFormatter.FormatHexValue(addrEntry.Address, 4) + " {", string.Empty);
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4) + " {",
+ string.Empty);
mPcDepth++;
} else {
mPcDepth--;
if (mPcDepth > 0 || !mFirstIsOpen) {
// close previous block
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(CLOSE_PSEUDOPC),
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArEndDirective),
string.Empty, string.Empty);
+ //";" + SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective));
} else {
// mark initial "*=" region as closed, but don't output anything
mFirstIsOpen = false;
diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs
index be5e599..760d47c 100644
--- a/SourceGen/AsmGen/AsmCc65.cs
+++ b/SourceGen/AsmGen/AsmCc65.cs
@@ -106,7 +106,8 @@ namespace SourceGen.AsmGen {
new PseudoOp.PseudoOpNames(new Dictionary {
{ "EquDirective", "=" },
{ "VarDirective", ".set" },
- { "OrgDirective", ".org" },
+ { "ArStartDirective", ".org" },
+ //ArEndDirective
//RegWidthDirective // .a8, .a16, .i8, .i16
//DataBankDirective
{ "DefineData1", ".byte" },
@@ -250,20 +251,10 @@ namespace SourceGen.AsmGen {
sw.WriteLine("MEMORY {");
sw.WriteLine(" MAIN: file=%O, start=%S, size=65536;");
- //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;");
- //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 {}");
@@ -493,24 +484,6 @@ namespace SourceGen.AsmGen {
OutputLine(labelStr, opcodeStr, operandStr, commentStr);
labelStr = commentStr = string.Empty;
}
-
- //StringBuilder sb = new StringBuilder(MAX_OPERAND_LEN);
- //int maxPerLine = MAX_OPERAND_LEN / 4;
- //int numChunks = (length + maxPerLine - 1) / maxPerLine;
- //for (int chunk = 0; chunk < numChunks; chunk++) {
- // int chunkStart = chunk * maxPerLine;
- // int chunkEnd = Math.Min((chunk + 1) * maxPerLine, length);
- // for (int i = chunkStart; i < chunkEnd; i++) {
- // if (i != chunkStart) {
- // sb.Append(',');
- // }
- // sb.Append(formatter.FormatHexValue(data[offset + i], 2));
- // }
-
- // OutputLine(labelStr, opcodeStr, sb.ToString(), commentStr);
- // labelStr = commentStr = string.Empty;
- // sb.Clear();
- //}
}
///
@@ -561,30 +534,12 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
+ public void OutputArDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
if (!isStart) {
return;
}
- //// 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),
+ OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
}
diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs
index 6eb583f..437d1f5 100644
--- a/SourceGen/AsmGen/AsmMerlin32.cs
+++ b/SourceGen/AsmGen/AsmMerlin32.cs
@@ -100,7 +100,8 @@ namespace SourceGen.AsmGen {
new PseudoOp.PseudoOpNames(new Dictionary {
{ "EquDirective", "equ" },
{ "VarDirective", "equ" },
- { "OrgDirective", "org" },
+ { "ArStartDirective", "org" },
+ //ArEndDirective
//RegWidthDirective
//DataBankDirective
{ "DefineData1", "dfb" },
@@ -484,10 +485,12 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
+ public void OutputArDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
if (isStart) {
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
- SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ SourceFormatter.FormatHexValue(addrEntry.Address, 4),
+ string.Empty);
}
}
diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs
index 21d8d64..32d0063 100644
--- a/SourceGen/AsmGen/AsmTass64.cs
+++ b/SourceGen/AsmGen/AsmTass64.cs
@@ -137,7 +137,8 @@ namespace SourceGen.AsmGen {
new PseudoOp.PseudoOpNames(new Dictionary {
{ "EquDirective", "=" },
{ "VarDirective", ".var" },
- { "OrgDirective", ".logical" },
+ { "ArStartDirective", ".logical" },
+ { "ArEndDirective", ".here" },
//RegWidthDirective // .as, .al, .xs, .xl
//DataBankDirective
{ "DefineData1", ".byte" },
@@ -158,7 +159,6 @@ namespace SourceGen.AsmGen {
//StrLen16
{ "StrDci", ".shift" }
});
- private const string HERE_PSEUDO_OP = ".here";
// IGenerator
@@ -653,7 +653,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public void OutputOrgDirective(AddressMap.AddressRegion addrEntry, bool isStart) {
+ public void OutputArDirective(AddressMap.AddressRegion 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
@@ -692,14 +692,17 @@ namespace SourceGen.AsmGen {
//OutputLine("*", "=", SourceFormatter.FormatHexValue(0, 4), string.Empty);
}
}
- OutputLine(string.Empty, SourceFormatter.FormatPseudoOp(sDataOpNames.OrgDirective),
- SourceFormatter.FormatHexValue(addrEntry.Address, 4), string.Empty);
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ 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),
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArEndDirective),
string.Empty, string.Empty);
} else {
// mark initial "*=" region as closed, but don't output anything
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index a177f17..390db74 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -76,12 +76,16 @@ namespace SourceGen.AsmGen {
}
}
- // Check for address changes. There may be more than one at a given offset.
+ // Check for address range starts. There may be more than one at a given offset.
AddressMap.AddressChange change = addrIter.Current;
while (change != null && change.Offset == offset) {
- gen.OutputOrgDirective(change.Region, change.IsStart);
- addrIter.MoveNext();
- change = addrIter.Current;
+ if (change.IsStart) {
+ gen.OutputArDirective(change.Region, change.IsStart);
+ addrIter.MoveNext();
+ change = addrIter.Current;
+ } else {
+ break;
+ }
}
List lvars = lvLookup.GetVariablesDefinedAtOffset(offset);
@@ -130,6 +134,22 @@ namespace SourceGen.AsmGen {
offset += attr.Length;
}
+ // Check for address region ends. There may be more than one at a given offset.
+ // The end-region offset is listed as the byte *following* the instruction
+ // or data item, so it should match the updated offset.
+ //
+ // If we encounter a region start, we'll handle that at the top of the next
+ // loop iteration.
+ while (change != null && change.Offset == offset) {
+ if (!change.IsStart) {
+ gen.OutputArDirective(change.Region, change.IsStart);
+ addrIter.MoveNext();
+ change = addrIter.Current;
+ } else {
+ break;
+ }
+ }
+
// Update progress meter. We don't want to spam it, so just ping it 10x.
int curProgress = (offset * 10) / proj.FileData.Length;
if (lastProgress != curProgress) {
@@ -143,19 +163,7 @@ namespace SourceGen.AsmGen {
}
}
- // 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.Region, change.IsStart);
- addrIter.MoveNext();
- change = addrIter.Current;
- }
+ Debug.Assert(offset == proj.FileDataLength);
}
private static void GenerateHeader(IGenerator gen, StreamWriter sw) {
@@ -565,11 +573,11 @@ namespace SourceGen.AsmGen {
return false;
}
AddressMap.AddressChange change = iter.Current;
- if (change.Region.Length != 2) {
+ if (change.Region.ActualLength != 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.GetRegions(0x000002).Count == 0) {
+ if (project.AddrMap.GetEntries(0x000002).Count == 0) {
//Debug.WriteLine("PRG test: no ORG at +2");
return false;
}
diff --git a/SourceGen/AsmGen/IGenerator.cs b/SourceGen/AsmGen/IGenerator.cs
index 361fccd..4f1cdf5 100644
--- a/SourceGen/AsmGen/IGenerator.cs
+++ b/SourceGen/AsmGen/IGenerator.cs
@@ -166,11 +166,11 @@ namespace SourceGen.AsmGen {
LocalVariableTable allDefs);
///
- /// Outputs a code origin directive.
+ /// Outputs an address region directive.
///
- /// Address map entry object.
- /// True if we're outputing a region-start directive.
- void OutputOrgDirective(CommonUtil.AddressMap.AddressRegion addrEntry, bool isStart);
+ /// Address region object.
+ /// True if this is the start of a region.
+ void OutputArDirective(CommonUtil.AddressMap.AddressRegion region, bool isStart);
///
/// Notify the assembler of a change in register width.
diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs
index 4b5c619..fed6cf8 100644
--- a/SourceGen/DisasmProject.cs
+++ b/SourceGen/DisasmProject.cs
@@ -271,7 +271,7 @@ namespace SourceGen {
AddrMap = new AddressMap(fileDataLen);
// set default load address to $1000; override later
- AddrMap.AddRegion(0x000000, fileDataLen, 0x1000);
+ AddrMap.AddEntry(0x000000, fileDataLen, 0x1000);
// Default value is "no tag".
AnalyzerTags = new CodeAnalysis.AnalyzerTag[fileDataLen];
@@ -400,9 +400,9 @@ namespace SourceGen {
int loadAddr = RawData.GetWord(mFileData, 0, 2, false);
// TODO(org): use NON_ADDR for first two bytes
AddressMap.AddResult addRes =
- AddrMap.AddRegion(0, 2, loadAddr < 2 ? 0 : loadAddr - 2);
+ AddrMap.AddEntry(0, 2, loadAddr < 2 ? 0 : loadAddr - 2);
Debug.Assert(addRes == AddressMap.AddResult.Okay);
- addRes = AddrMap.AddRegion(2, mFileData.Length - 2, loadAddr);
+ addRes = AddrMap.AddEntry(2, mFileData.Length - 2, loadAddr);
Debug.Assert(addRes == AddressMap.AddResult.Okay);
OperandFormats[0] = FormatDescriptor.Create(2, FormatDescriptor.Type.NumericLE,
@@ -413,7 +413,7 @@ namespace SourceGen {
} else {
int loadAddr = SystemDefaults.GetLoadAddress(sysDef);
AddressMap.AddResult addRes =
- AddrMap.AddRegion(0, mFileData.Length, loadAddr);
+ AddrMap.AddEntry(0, mFileData.Length, loadAddr);
Debug.Assert(addRes == AddressMap.AddResult.Okay);
}
@@ -756,16 +756,19 @@ namespace SourceGen {
}
///
- /// Checks to see if any part of the address map runs across a bank boundary.
+ /// Checks to see if any section of the address map runs across a bank boundary.
///
private void ValidateAddressMap() {
- // Use the change list, because the map entry list can have "floating" length values.
+ // Use the change list, because the map entry list can have "floating" length values
+ // (which don't automatically stop at bank boundaries).
IEnumerator addrIter = AddrMap.AddressChangeIterator;
while (addrIter.MoveNext()) {
AddressMap.AddressChange change = addrIter.Current;
+ if (!change.IsStart) {
+ continue;
+ }
AddressMap.AddressRegion region = change.Region;
- if (change.IsStart &&
- (region.Address & 0xff0000) != ((region.Address + region.Length - 1) & 0xff0000)) {
+ if ((region.Address & 0xff0000) != ((region.Address + region.ActualLength - 1) & 0xff0000)) {
string fmt = Res.Strings.MSG_BANK_OVERRUN_DETAIL_FMT;
int firstNext = (region.Address & 0xff0000) + 0x010000;
int badOffset = region.Offset + (firstNext - region.Address);
@@ -2149,18 +2152,18 @@ namespace SourceGen {
AddressMap addrMap = AddrMap;
if ((int)oldValue == AddressMap.NON_ADDR) {
// adding new entry
- if (addrMap.AddRegion(offset, AddressMap.FLOATING_LEN,
+ if (addrMap.AddEntry(offset, AddressMap.FLOATING_LEN,
(int)newValue) != 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)) {
+ if (!addrMap.RemoveEntry(offset, AddressMap.FLOATING_LEN)) {
Debug.Assert(false, "failed removing region");
}
} else {
// updating existing entry
- if (!addrMap.EditRegion(offset, AddressMap.FLOATING_LEN,
+ if (!addrMap.EditEntry(offset, AddressMap.FLOATING_LEN,
(int) newValue, string.Empty, false)) {
Debug.Assert(false, "failed editing region");
}
diff --git a/SourceGen/Exporter.cs b/SourceGen/Exporter.cs
index c7346ab..2ab8ef8 100644
--- a/SourceGen/Exporter.cs
+++ b/SourceGen/Exporter.cs
@@ -353,10 +353,12 @@ namespace SourceGen {
case LineListGen.Line.Type.EquDirective:
case LineListGen.Line.Type.RegWidthDirective:
case LineListGen.Line.Type.DataBankDirective:
- case LineListGen.Line.Type.OrgDirective:
+ case LineListGen.Line.Type.ArStartDirective:
+ case LineListGen.Line.Type.ArEndDirective:
case LineListGen.Line.Type.LocalVariableTable:
if (parts.IsLongComment) {
- // This happens for long comments embedded in LV tables.
+ // This happens for long comments generated for LV tables (e.g. "empty
+ // variable table").
TextUtil.AppendPaddedString(sb, parts.Comment, mColStart[(int)Col.Label]);
break;
}
@@ -714,7 +716,8 @@ namespace SourceGen {
case LineListGen.Line.Type.EquDirective:
case LineListGen.Line.Type.RegWidthDirective:
case LineListGen.Line.Type.DataBankDirective:
- case LineListGen.Line.Type.OrgDirective:
+ case LineListGen.Line.Type.ArStartDirective:
+ case LineListGen.Line.Type.ArEndDirective:
case LineListGen.Line.Type.LocalVariableTable:
if (parts.IsLongComment) {
// This happens for long comments embedded in LV tables, e.g.
diff --git a/SourceGen/LineListGen.cs b/SourceGen/LineListGen.cs
index 6fd3dfe..e7a4daf 100644
--- a/SourceGen/LineListGen.cs
+++ b/SourceGen/LineListGen.cs
@@ -92,7 +92,7 @@ namespace SourceGen {
/// One of these per line of output in the display. It should be possible to draw
/// all of the output without needing to refer back to the project data. (Currently
/// making an exception for some selection-dependent field highlighting.)
- ///
+ ///
/// Base fields are immutable, but the Parts property is set after creation.
///
public class Line {
@@ -116,14 +116,15 @@ namespace SourceGen {
Blank = 1 << 4,
// Assembler directives.
- OrgDirective = 1 << 5,
- EquDirective = 1 << 6,
- RegWidthDirective = 1 << 7,
- DataBankDirective = 1 << 8,
+ ArStartDirective = 1 << 5,
+ ArEndDirective = 1 << 6,
+ EquDirective = 1 << 7,
+ RegWidthDirective = 1 << 8,
+ DataBankDirective = 1 << 9,
// Additional metadata.
- LocalVariableTable = 1 << 9,
- VisualizationSet = 1 << 10,
+ LocalVariableTable = 1 << 10,
+ VisualizationSet = 1 << 11,
}
///
@@ -535,7 +536,8 @@ namespace SourceGen {
// Nothing to do.
parts = FormattedParts.CreateBlankLine();
break;
- case Line.Type.OrgDirective:
+ case Line.Type.ArStartDirective:
+ case Line.Type.ArEndDirective:
case Line.Type.RegWidthDirective:
case Line.Type.DataBankDirective:
case Line.Type.LongComment:
@@ -989,29 +991,53 @@ namespace SourceGen {
int offset = startOffset;
while (offset <= endOffset) {
- bool blankAdded = false;
+ bool spaceAdded = false;
Anattrib attr = mProject.GetAnattrib(offset);
if (attr.IsInstructionStart && offset > 0 &&
mProject.GetAnattrib(offset - 1).IsData) {
// Transition from data to code. (Don't add blank line for inline data.)
lines.Add(GenerateBlankLine(offset));
- blankAdded = true;
+ spaceAdded = true;
} else if (mProject.VisualizationSets.ContainsKey(offset) && !addBlank) {
// Blank line before visualization set helps keep image visually grouped
// with its data.
lines.Add(GenerateBlankLine(offset));
- blankAdded = true;
+ spaceAdded = true;
} else if (addBlank) {
// Previous instruction wanted to be followed by a blank line.
lines.Add(GenerateBlankLine(offset));
- blankAdded = true;
+ spaceAdded = true;
}
addBlank = false;
- // Start with address region changes.
+ // Insert long comments and notes. These may span multiple display lines,
+ // and require word-wrap, so it's easiest just to render them fully here.
+ // Set "spaceAdded" to true so .arstart doesn't try to add one after the comment.
+ //
+ // TODO: integrate into FormattedOperandCache so we don't have to
+ // regenerate them unless they change. Use the MLC as the dependency.
+ if (mProject.Notes.TryGetValue(offset, out MultiLineComment noteData)) {
+ List formatted = noteData.FormatText(mFormatter, "NOTE: ");
+ StringListToLines(formatted, offset, Line.Type.Note,
+ noteData.BackgroundColor, NoteColorMultiplier, lines);
+ spaceAdded = true;
+ }
+ if (mProject.LongComments.TryGetValue(offset, out MultiLineComment longComment)) {
+ List formatted = longComment.FormatText(mFormatter, string.Empty);
+ StringListToLines(formatted, offset, Line.Type.LongComment,
+ longComment.BackgroundColor, NoteColorMultiplier, lines);
+ spaceAdded = true;
+ }
+ if (mProject.VisualizationSets.TryGetValue(offset, out VisualizationSet visSet)) {
+ lines.Add(new Line(offset, 0, Line.Type.VisualizationSet));
+ spaceAdded = true;
+ }
+
+ // Handle address region starts.
while (addrIter.Current != null && addrIter.Current.Offset <= offset) {
AddressMap.AddressChange change = addrIter.Current;
- Debug.Assert(change.Offset == offset); // shouldn't be embedded in something
+ // Range starts/ends shouldn't be embedded in something.
+ Debug.Assert(change.Offset == offset);
AddressMap.AddressRegion region = change.Region;
if (region.Offset == 0 && AsmGen.GenCommon.HasPrgHeader(mProject)) {
@@ -1024,40 +1050,22 @@ namespace SourceGen {
if (change.IsStart) {
// Blank line above ORG directive, except at top of file or when we've
// already added one for another reason.
- if (region.Offset != 0 && !blankAdded) {
+ if (region.Offset != 0 && !spaceAdded) {
lines.Add(GenerateBlankLine(offset));
}
- blankAdded = false; // next one will need a blank line
+ spaceAdded = false; // next one will need a blank line
// TODO(org): pre-label (address / label only, logically part of ORG)
- Line newLine = new Line(offset, 0, Line.Type.OrgDirective);
+ Line newLine = new Line(offset, 0, Line.Type.ArStartDirective);
string addrStr = mFormatter.FormatHexValue(region.Address, 4);
newLine.Parts = FormattedParts.CreateDirective(
- mFormatter.FormatPseudoOp(mPseudoOpNames.OrgDirective), addrStr);
+ mFormatter.FormatPseudoOp(mPseudoOpNames.ArStartDirective), addrStr);
lines.Add(newLine);
+ addrIter.MoveNext();
} else {
- // TODO(org)
+ // Next entry is an end marker.
+ break;
}
-
- addrIter.MoveNext();
- }
-
- // Insert long comments and notes. These may span multiple display lines,
- // and require word-wrap, so it's easiest just to render them fully here.
- // TODO: integrate into FormattedOperandCache so we don't have to
- // regenerate them unless they change. Use the MLC as the dependency.
- if (mProject.Notes.TryGetValue(offset, out MultiLineComment noteData)) {
- List formatted = noteData.FormatText(mFormatter, "NOTE: ");
- StringListToLines(formatted, offset, Line.Type.Note,
- noteData.BackgroundColor, NoteColorMultiplier, lines);
- }
- if (mProject.LongComments.TryGetValue(offset, out MultiLineComment longComment)) {
- List formatted = longComment.FormatText(mFormatter, string.Empty);
- StringListToLines(formatted, offset, Line.Type.LongComment,
- longComment.BackgroundColor, NoteColorMultiplier, lines);
- }
- if (mProject.VisualizationSets.TryGetValue(offset, out VisualizationSet visSet)) {
- lines.Add(new Line(offset, 0, Line.Type.VisualizationSet));
}
// Local variable tables come next. Defer rendering.
@@ -1210,6 +1218,26 @@ namespace SourceGen {
}
offset += attr.Length;
}
+
+ // Check for address region ends, which will be positioned at the updated offset
+ // (unless they somehow got embedded inside something else).
+ while (addrIter.Current != null && addrIter.Current.Offset <= offset) {
+ AddressMap.AddressChange change = addrIter.Current;
+ // Range starts/ends shouldn't be embedded in something.
+ Debug.Assert(change.Offset == offset);
+
+ if (!change.IsStart) {
+ // NOTE: last end(s) are at an offset outside file bounds.
+ Line newLine = new Line(offset, 0, Line.Type.ArEndDirective);
+ newLine.Parts = FormattedParts.CreateDirective(
+ mFormatter.FormatPseudoOp(mPseudoOpNames.ArEndDirective),
+ string.Empty);
+ lines.Add(newLine);
+ addrIter.MoveNext();
+ } else {
+ break;
+ }
+ }
}
}
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index f49f631..7b27634 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -1530,10 +1530,11 @@ namespace SourceGen {
EditProjectSymbol((CodeListColumn)col);
}
break;
- case LineListGen.Line.Type.OrgDirective:
+ case LineListGen.Line.Type.ArStartDirective:
if (CanEditAddress()) {
EditAddress();
}
+ // TODO(org): handle ArEndDirective
break;
case LineListGen.Line.Type.RegWidthDirective:
if (CanEditStatusFlags()) {
@@ -1771,7 +1772,8 @@ namespace SourceGen {
LineListGen.Line selLine = CodeLineList[selIndex];
if (selLine.LineType != LineListGen.Line.Type.Code &&
selLine.LineType != LineListGen.Line.Type.Data &&
- selLine.LineType != LineListGen.Line.Type.OrgDirective) {
+ selLine.LineType != LineListGen.Line.Type.ArStartDirective) {
+ // TODO(org): handle ArEnd
return false;
}
@@ -1803,55 +1805,31 @@ namespace SourceGen {
int lastIndex = mMainWin.CodeListView_GetLastSelectedIndex();
int firstOffset = CodeLineList[selIndex].FileOffset;
int lastOffset = CodeLineList[lastIndex].FileOffset;
- int nextOffset = lastOffset + CodeLineList[lastIndex].OffsetSpan;
- int nextAddr;
+ //int nextOffset = lastOffset + CodeLineList[lastIndex].OffsetSpan;
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 might not be a single *line*) is selected, or the
- // last selected item is the end of the file.
- nextOffset = -1;
- 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
- // first address.
- //
- // I tried this by just removing the selected entry and seeing what the address
- // would be without it, useful for relocations inside relocations. This worked
- // poorly when relocations were chained, i.e. two consecutive blocks were
- // relocated to different places. The end address of the second block gets
- // set based on the first address of the first block, which doesn't seem useful.
-#if false
- nextAddr = mProject.AddrMap.Get(nextOffset);
- if (nextAddr == AddressMap.NO_ENTRY_ADDR) {
- AddressMap cloneMap = new AddressMap(mProject.AddrMap.GetEntryList());
- if (firstOffset != 0) {
- cloneMap.Remove(firstOffset);
- }
- nextAddr = cloneMap.OffsetToAddress(nextOffset);
- }
-#else
- int fileStartAddr = addrMap.OffsetToAddress(0);
- nextAddr = ((fileStartAddr + nextOffset) & 0xffff) | (fileStartAddr & 0xff0000);
-#endif
+ int addr = addrMap.OffsetToAddress(firstOffset);
+ int newLen = lastOffset - firstOffset;
+ if (newLen == 0) {
+ newLen = 123;
}
-
- EditAddress dlg = new EditAddress(mMainWin, firstOffset, nextOffset, nextAddr,
+ AddressMap.AddressMapEntry newEntry = new AddressMap.AddressMapEntry(firstOffset,
+ newLen /*DEBUG - replace*/, addr, string.Empty, false);
+ EditAddress dlg = new EditAddress(mMainWin, newEntry, true, newLen,
mProject, mFormatter);
if (dlg.ShowDialog() != true) {
return;
}
- if (firstOffset == 0 && dlg.NewAddress < 0) {
- // Not allowed. The AddressMap will just put it back, which confuses
- // the undo operation.
- Debug.WriteLine("EditAddress: not allowed to remove address at offset +000000");
- return;
- }
+ //if (firstOffset == 0 && dlg.NewAddress < 0) {
+ // // Not allowed. The AddressMap will just put it back, which confuses
+ // // the undo operation.
+ // Debug.WriteLine("EditAddress: not allowed to remove address at offset +000000");
+ // return;
+ //}
ChangeSet cs = new ChangeSet(1);
@@ -3899,8 +3877,11 @@ namespace SourceGen {
case LineListGen.Line.Type.Blank:
lineTypeStr = "blank line";
break;
- case LineListGen.Line.Type.OrgDirective:
- lineTypeStr = "address directive";
+ case LineListGen.Line.Type.ArStartDirective:
+ lineTypeStr = "address range start directive";
+ break;
+ case LineListGen.Line.Type.ArEndDirective:
+ lineTypeStr = "address range end directive";
break;
case LineListGen.Line.Type.RegWidthDirective:
lineTypeStr = "register width directive";
diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs
index 86470df..42a3d7c 100644
--- a/SourceGen/ProjectFile.cs
+++ b/SourceGen/ProjectFile.cs
@@ -673,7 +673,7 @@ namespace SourceGen {
// TODO(org): serialize length, isRelative, and preLabel
int length = CommonUtil.AddressMap.FLOATING_LEN;
- AddressMap.AddResult addResult = proj.AddrMap.AddRegion(addr.Offset,
+ AddressMap.AddResult addResult = proj.AddrMap.AddEntry(addr.Offset,
length, addr.Addr);
if (addResult != CommonUtil.AddressMap.AddResult.Okay) {
string msg = "off=+" + addr.Offset.ToString("x6") + " addr=$" +
diff --git a/SourceGen/PseudoOp.cs b/SourceGen/PseudoOp.cs
index 13c4fbb..04a8c90 100644
--- a/SourceGen/PseudoOp.cs
+++ b/SourceGen/PseudoOp.cs
@@ -64,7 +64,8 @@ namespace SourceGen {
public class PseudoOpNames {
public string EquDirective { get; private set; }
public string VarDirective { get; private set; }
- public string OrgDirective { get; private set; }
+ public string ArStartDirective { get; private set; }
+ public string ArEndDirective { get; private set; }
public string RegWidthDirective { get; private set; }
public string DataBankDirective { get; private set; }
@@ -115,7 +116,8 @@ namespace SourceGen {
}
return a.EquDirective == b.EquDirective &&
a.VarDirective == b.VarDirective &&
- a.OrgDirective == b.OrgDirective &&
+ a.ArStartDirective == b.ArStartDirective &&
+ a.ArEndDirective == b.ArEndDirective &&
a.RegWidthDirective == b.RegWidthDirective &&
a.DataBankDirective == b.DataBankDirective &&
a.DefineData1 == b.DefineData1 &&
@@ -145,7 +147,7 @@ namespace SourceGen {
public override int GetHashCode() {
// should be enough
return (EquDirective == null ? 0 : EquDirective.GetHashCode()) ^
- (OrgDirective == null ? 0 : OrgDirective.GetHashCode()) ^
+ (ArStartDirective == null ? 0 : ArStartDirective.GetHashCode()) ^
(DefineData1 == null ? 0 : DefineData1.GetHashCode()) ^
(Fill == null ? 0 : Fill.GetHashCode());
}
@@ -226,7 +228,8 @@ namespace SourceGen {
new PseudoOpNames(new Dictionary {
{ "EquDirective", ".eq" },
{ "VarDirective", ".var" },
- { "OrgDirective", ".org" },
+ { "ArStartDirective", ".arstart" },
+ { "ArEndDirective", ".arend" },
{ "RegWidthDirective", ".rwid" },
{ "DataBankDirective", ".dbank" },
diff --git a/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S b/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S
index 69ed4b0..65415a8 100644
--- a/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S
+++ b/SourceGen/SGTestData/Expected/20000-numeric-types_acme.S
@@ -63,7 +63,7 @@ LABEL !hex 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
!pseudopc $1408 {
!fill 8,$82 ;note no-op .ORG
!fill 8,$83
- } ;!pseudopc
+ }
!pseudopc $1428 {
!fill 8,$83 ;meaningful .ORG
!fill 8,$84
@@ -84,4 +84,4 @@ L14A8 !fill 8,$8b
!fill 8,$8c
!byte %10001100
!fill 7,$8c
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S
index 34d52e5..794febe 100644
--- a/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S
+++ b/SourceGen/SGTestData/Expected/20030-labels-and-symbols_acme.S
@@ -106,4 +106,4 @@ calls jsr L1015
L1160 adc #BMI1
rts
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20032-labels-and-symbols_acme.S b/SourceGen/SGTestData/Expected/20032-labels-and-symbols_acme.S
index 85e248c..5a94abd 100644
--- a/SourceGen/SGTestData/Expected/20032-labels-and-symbols_acme.S
+++ b/SourceGen/SGTestData/Expected/20032-labels-and-symbols_acme.S
@@ -23,4 +23,4 @@
!hex 656172206f6e20746865206669727374206c696e652e20205468652071756963
!hex 6b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920
!hex 646f67732ea97aa959a934c230a97b56a95a34a9341260
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S b/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S
index 3c3476e..2e802a7 100644
--- a/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S
@@ -57,8 +57,8 @@ L2080 bit L2080
lda $00
beq _L2100
.byte $ad
-
.here
+
.logical $2100
_L2100 nop
nop
@@ -72,8 +72,8 @@ _L2100 nop
.here
.logical $2820
.fill 18,$00
-
.here
+
.logical $3000
_L3000 bit _L3000
lda #$44
@@ -110,8 +110,8 @@ _L3182 bit _L3182
label1 .byte $ea
.byte $ea
-
.here
+
.logical $3200
L3200 bit L3200
.byte $00
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_acme.S b/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
index cbc3bb0..bb38993 100644
--- a/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
@@ -7,7 +7,7 @@
jsr L1107
jmp L2000
- } ;!pseudopc
+ }
!pseudopc $1100 {
L1100 bit L1100
L1103 lda #$11
@@ -16,7 +16,7 @@ L1107 ldy #$11
clv
bvc L1103
- } ;!pseudopc
+ }
!pseudopc $1100 {
@L1100_0 bit @L1100_0
lda #$22
@@ -24,7 +24,7 @@ L1107 ldy #$11
ldy #$22
jmp @L1105
- } ;!pseudopc
+ }
!pseudopc $1100 {
@L1100_1 bit @L1100_1
lda #$33
@@ -33,20 +33,20 @@ L1107 ldy #$11
sec
bcs @L1107_0
- } ;!pseudopc
+ }
!pseudopc $2000 {
L2000 bit L2000
beq $2018
bne @L2020
- } ;!pseudopc
+ }
!pseudopc $2020 {
@L2020 bit @L2020
beq $2028
bne L2080
offend nop
- } ;!pseudopc
+ }
!pseudopc $2080 {
L2080 bit L2080
lda offend
@@ -60,23 +60,23 @@ L2080 bit L2080
lda $00
beq @L2100
!byte $ad
+ }
- } ;!pseudopc
!pseudopc $2100 {
@L2100 nop
nop
jmp @L3000
- } ;!pseudopc
+ }
!pseudopc $2800 {
!byte $00
!byte $28
!fill 14,$00
- } ;!pseudopc
+ }
!pseudopc $2820 {
!fill 18,$00
+ }
- } ;!pseudopc
!pseudopc $3000 {
@L3000 bit @L3000
lda #$44
@@ -86,7 +86,7 @@ L2080 bit L2080
ulabel !byte $00
!byte $01
- } ;!pseudopc
+ }
!pseudopc $3100 {
!byte $02
@@ -99,7 +99,7 @@ fwd bit fwd
beq @L3182
!byte $ea
!byte $ea
- } ;!pseudopc
+ }
!pseudopc $3180 {
!byte $00
!byte $01
@@ -113,10 +113,10 @@ fwd bit fwd
label1 !byte $ea
!byte $ea
+ }
- } ;!pseudopc
!pseudopc $3200 {
L3200 bit L3200
!byte $00
!byte $01 ;execution continues off end of file
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S b/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S
index 0816df0..d51d36b 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S
@@ -63,8 +63,8 @@ _L22080 bit _L22080 & $ffff
lda $00
beq _L22100
.byte $ad
-
.here
+
.logical $022100
_L22100 nop
nop
@@ -78,8 +78,8 @@ _L22100 nop
.here
.logical $022820
.fill 18,$00
-
.here
+
.logical $023000
_L23000 bit _L23000 & $ffff
lda #$44
@@ -115,8 +115,8 @@ _L23182 bit _L23182 & $ffff
_label1 .byte $ea
.byte $ea
-
.here
+
.logical $023200
_L23200 bit _L23200 & $ffff
.byte $00
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_acme.S b/SourceGen/SGTestData/Expected/20042-address-changes_acme.S
index 26e1087..6e80a44 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_acme.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_acme.S
@@ -8,4 +8,4 @@
!hex 0000000000000000000000000000002c0030a944a244a04482f5000001022c01
!hex 31ad0c30ad0d30ad0e30ad0f30ad0031f06deaea00012c8231ad9031ad9131ad
!hex 00328070eaea2c00320001
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S b/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S
index e9a014f..32fae05 100644
--- a/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S
+++ b/SourceGen/SGTestData/Expected/20050-branches-and-banks_acme.S
@@ -19,12 +19,12 @@ L0012 lda+1 lodat+1
clc
bcc LFFC0
- } ;!pseudopc
+ }
!pseudopc $0080 {
L0080 bit+2 L0080
jmp LFFC6
- } ;!pseudopc
+ }
!pseudopc $ffc0 {
LFFC0 bit LFFC0
LFFC3 clc
@@ -32,4 +32,4 @@ LFFC3 clc
LFFC6 rts
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20052-branches-and-banks_64tass.S b/SourceGen/SGTestData/Expected/20052-branches-and-banks_64tass.S
index 7750ff5..b281aac 100644
--- a/SourceGen/SGTestData/Expected/20052-branches-and-banks_64tass.S
+++ b/SourceGen/SGTestData/Expected/20052-branches-and-banks_64tass.S
@@ -26,8 +26,8 @@ L440004 lda L440000
dat44 .word dat44 & $ffff
.long dat44
-
.here
+
.logical $44ffc0
L44FFC0 cmp L44FFC0
high44 beq _L44FFCB
diff --git a/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S b/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S
index 78806ce..cd705af 100644
--- a/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S
+++ b/SourceGen/SGTestData/Expected/20060-target-adjustment_acme.S
@@ -81,4 +81,4 @@ load11 lda #$11
lda @L2017
rts
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20100-label-dp_acme.S b/SourceGen/SGTestData/Expected/20100-label-dp_acme.S
index d8c7740..155eb1d 100644
--- a/SourceGen/SGTestData/Expected/20100-label-dp_acme.S
+++ b/SourceGen/SGTestData/Expected/20100-label-dp_acme.S
@@ -299,4 +299,4 @@ L0080 bit+1 @L0082
@L0082 bit+1 @L0082
bit+1 @L0082
L0086 bit+2 L0086
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20102-label-dp_acme.S b/SourceGen/SGTestData/Expected/20102-label-dp_acme.S
index 30553c2..0030d43 100644
--- a/SourceGen/SGTestData/Expected/20102-label-dp_acme.S
+++ b/SourceGen/SGTestData/Expected/20102-label-dp_acme.S
@@ -291,4 +291,4 @@ L0080 bit+1 @L0082
bit+1 @L0082
L0086 bit+2 L0086
L0089 lda+3 L0089
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20150-local-variables_acme.S b/SourceGen/SGTestData/Expected/20150-local-variables_acme.S
index 1ac3ca1..cd8cec0 100644
--- a/SourceGen/SGTestData/Expected/20150-local-variables_acme.S
+++ b/SourceGen/SGTestData/Expected/20150-local-variables_acme.S
@@ -223,4 +223,4 @@ DPCODE nop
beq @SPLIT2
rts
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20152-local-variables_acme.S b/SourceGen/SGTestData/Expected/20152-local-variables_acme.S
index 1a2308c..280ee4e 100644
--- a/SourceGen/SGTestData/Expected/20152-local-variables_acme.S
+++ b/SourceGen/SGTestData/Expected/20152-local-variables_acme.S
@@ -294,4 +294,4 @@ L00E6 bit .ARG+2
bit $0100
rts
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S b/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S
index 5ae107f..396872f 100644
--- a/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S
+++ b/SourceGen/SGTestData/Expected/20182-extension-scripts_acme.S
@@ -110,7 +110,7 @@ L1800 jsr PrintInlineNullString
!byte $6e
!byte $20
!byte $01
- } ;!pseudopc
+ }
!pseudopc $1840 {
!text "string"
!byte $00
@@ -123,4 +123,4 @@ L1848 jsl PrintInlineL2String
L184F jsr PrintInlineNullString
adc $6e
!byte $64
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_64tass.S b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_64tass.S
index a9d0a0b..7e44b62 100644
--- a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_64tass.S
+++ b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_64tass.S
@@ -8,8 +8,8 @@
.logical $200a
.text "world"
.byte $80
-
.here
+
.logical $2100
L2100 lda #$00
sta addr1-1 ;edit this operand
diff --git a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S
index b714551..9158e77 100644
--- a/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S
+++ b/SourceGen/SGTestData/Expected/20200-ui-edge-cases_acme.S
@@ -6,8 +6,8 @@
!pseudopc $200a {
!text "world"
!byte $80
+ }
- } ;!pseudopc
!pseudopc $2100 {
L2100 lda #$00
sta addr1-1 ;edit this operand
@@ -20,4 +20,4 @@ addr1 !text "!?---"
L2121 rts
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20212-reloc-data_64tass.S b/SourceGen/SGTestData/Expected/20212-reloc-data_64tass.S
index 87ea74a..fdf2e0c 100644
--- a/SourceGen/SGTestData/Expected/20212-reloc-data_64tass.S
+++ b/SourceGen/SGTestData/Expected/20212-reloc-data_64tass.S
@@ -116,8 +116,8 @@ _L4FFE0 .long _L4FFE0
.byte $1e
.byte $1f
.text " !",$22,"#$%&'()*+,-./"
-
.here
+
.logical $023456
.as
.xs
diff --git a/SourceGen/SGTestData/Expected/20212-reloc-data_acme.S b/SourceGen/SGTestData/Expected/20212-reloc-data_acme.S
index c8e86d1..e6de493 100644
--- a/SourceGen/SGTestData/Expected/20212-reloc-data_acme.S
+++ b/SourceGen/SGTestData/Expected/20212-reloc-data_acme.S
@@ -11,4 +11,4 @@
!hex 00000000ea60af000008ad1900eaaf000001af000002af000003af0000086b19
!hex 00080056340200800010080054686973206973206120746573742e0068656c6c
!hex 6f2c20776f726c6421
- } ;!pseudopc
+ }
diff --git a/SourceGen/SGTestData/Expected/20222-data-bank_64tass.S b/SourceGen/SGTestData/Expected/20222-data-bank_64tass.S
index b1522c2..393c385 100644
--- a/SourceGen/SGTestData/Expected/20222-data-bank_64tass.S
+++ b/SourceGen/SGTestData/Expected/20222-data-bank_64tass.S
@@ -71,8 +71,8 @@ L2202E nop
rts
bank2addr .word L2202E & $ffff
-
.here
+
.logical $033000
bank3 lda bank3
lda bank2 & $ffff
@@ -89,8 +89,8 @@ _L33024 lda $2030
rtl
L33028 .word L33028 & $ffff
-
.here
+
.logical $024000
L24000 lda L24000
phb
diff --git a/SourceGen/SGTestData/Expected/20240-large-overlay_acme.S b/SourceGen/SGTestData/Expected/20240-large-overlay_acme.S
index 7e57f80..7884903 100644
--- a/SourceGen/SGTestData/Expected/20240-large-overlay_acme.S
+++ b/SourceGen/SGTestData/Expected/20240-large-overlay_acme.S
@@ -3,25 +3,25 @@
!pseudopc $8000 {
!byte $ea
!fill 8191,$00
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$01
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$02
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$03
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$04
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$05
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$06
- } ;!pseudopc
+ }
!pseudopc $8000 {
!fill 8192,$07
- } ;!pseudopc
+ }
diff --git a/SourceGen/WpfGui/EditAddress.xaml b/SourceGen/WpfGui/EditAddress.xaml
index 978981d..ed2ab69 100644
--- a/SourceGen/WpfGui/EditAddress.xaml
+++ b/SourceGen/WpfGui/EditAddress.xaml
@@ -19,60 +19,99 @@ limitations under the License.
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SourceGen.WpfGui"
mc:Ignorable="d"
- Title="Set Address"
+ Title="Edit Address Range"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
ContentRendered="Window_ContentRendered">
+
+ Creating new address range, with properties:
+ Editing existing address range, with properties:
+ Resizing existing address range, with properties:
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SourceGen/WpfGui/EditAddress.xaml.cs b/SourceGen/WpfGui/EditAddress.xaml.cs
index 92c833b..651c2d7 100644
--- a/SourceGen/WpfGui/EditAddress.xaml.cs
+++ b/SourceGen/WpfGui/EditAddress.xaml.cs
@@ -14,71 +14,58 @@
* limitations under the License.
*/
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;
-using System.Windows.Controls;
using Asm65;
+using CommonUtil;
namespace SourceGen.WpfGui {
///
- /// Edit Address dialog.
+ /// Edit Address Region dialog.
///
public partial class EditAddress : Window, INotifyPropertyChanged {
///
- /// Address typed by user. Only valid after the dialog returns OK. Will be set to
- /// AddressMap.NO_ENTRY_ADDR if the user is attempting to delete the address.
+ /// Updated address map entry. Will be null if we want to delete the entry.
///
- public int NewAddress { get; private set; }
+ public AddressMap.AddressMapEntry NewEntry { get; private set; }
+
///
/// Offset being edited.
///
- private int mFirstOffset;
+ private int mRegionStartOffset;
+ public string RegionStartOffsetStr {
+ get { return mFormatter.FormatOffset24(mRegionStartOffset); }
+ }
///
/// Offset after the end of the selection, or -1 if only one line is selected.
///
- private int mNextOffset;
-
- ///
- /// Address after the end of the selection, or -1 if only one line is selected.
- ///
- private int mNextAddress;
-
- ///
- /// Maximum allowed address value.
- ///
- private int mMaxAddressValue;
-
- ///
- /// What the address would be if there were no addresses set after the initial one.
- ///
- private int mBaseAddr;
-
- ///
- /// Text formatter.
- ///
- private Formatter mFormatter;
-
- public string FirstOffsetStr {
- get { return mFormatter.FormatOffset24(mFirstOffset); }
+ private int mRegionEndOffset;
+ public string RegionEndOffsetStr {
+ get { return mFormatter.FormatOffset24(mRegionEndOffset); }
}
- public string NextOffsetStr {
- get { return mFormatter.FormatOffset24(mNextOffset); }
- }
- public string NextAddressStr {
- get { return '$' + mFormatter.FormatAddress(mNextAddress, mNextAddress > 0xffff); }
- }
- public string BytesSelectedStr {
+
+ public string RegionLengthStr {
get {
- int count = mNextOffset - mFirstOffset;
+ int count = mRegionEndOffset - mRegionStartOffset;
return count.ToString() + " (" + mFormatter.FormatHexValue(count, 2) + ")";
}
}
+ ///
+ /// Address at which a pre-label would be placed. This is determined by the parent
+ /// region, so its value is fixed.
+ ///
+ private int mPreLabelAddress;
+ public string PreLabelAddressStr {
+ get { return mFormatter.FormatOffset24(mRegionEndOffset); }
+ }
+
///
/// Address input TextBox.
///
@@ -88,6 +75,21 @@ namespace SourceGen.WpfGui {
}
private string mAddressText;
+ public bool UseRelativeAddressing {
+ get { return mUseRelativeAddressing; }
+ set { mUseRelativeAddressing = value; OnPropertyChanged(); UpdateControls(); }
+ }
+ private bool mUseRelativeAddressing;
+
+ ///
+ /// Pre-label input TextBox.
+ ///
+ public string PreLabelText {
+ get { return mPreLabelText; }
+ set { mPreLabelText = value; OnPropertyChanged(); UpdateControls(); }
+ }
+ private string mPreLabelText;
+
///
/// Set to true when input is valid. Controls whether the OK button is enabled.
///
@@ -97,17 +99,23 @@ namespace SourceGen.WpfGui {
}
private bool mIsValid;
- public Visibility NextAddressVis {
- get { return mNextAddressVis; }
- set { mNextAddressVis = value; OnPropertyChanged(); }
+ ///
+ /// Set to true when requested region is valid. Everything but the cancel button is
+ /// disabled if not.
+ ///
+ public bool IsRegionValid {
+ get { return mIsRegionValid; }
+ set { mIsRegionValid = value; OnPropertyChanged(); }
}
- public Visibility mNextAddressVis = Visibility.Collapsed;
+ private bool mIsRegionValid;
- public string LoadAddressText {
- get { return mLoadAddressText; }
- set { mLoadAddressText = value; OnPropertyChanged(); }
+ ///
+ /// Determines whether the "(floating)" message appears next to the length.
+ ///
+ public Visibility FloatTextVis {
+ get { return mFloatTextVis; }
}
- public string mLoadAddressText = string.Empty;
+ private Visibility mFloatTextVis;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
@@ -115,46 +123,96 @@ namespace SourceGen.WpfGui {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
+ private AddressMap.AddressRegion mNewRegion;
+
+ ///
+ /// Maximum allowed address value, based on CPU type.
+ ///
+ private int mMaxAddressValue;
+
+ ///
+ /// Reference to project. We need the address map and symbol table.
+ ///
+ private DisasmProject mProject;
+
+ ///
+ /// Reference to text formatter.
+ ///
+ private Formatter mFormatter;
+
///
/// Constructor.
///
/// Parent window.
- /// Offset at top of selection.
- /// Offset past bottom of selection, or -1 if only one
- /// line is selected.
+ /// Map entry definition. This may be an existing entry, or values
+ /// representing the selection.
+ /// Length of region. Only used if we're resizing an
+ /// existing region.
/// Project reference.
/// Text formatter object.
- public EditAddress(Window owner, int firstOffset, int nextOffset, int nextAddr,
- DisasmProject project, Formatter formatter) {
+ public EditAddress(Window owner, AddressMap.AddressMapEntry entry, bool isNew,
+ int newLength, DisasmProject project, Formatter formatter) {
InitializeComponent();
Owner = owner;
DataContext = this;
- mFirstOffset = firstOffset;
- mNextOffset = nextOffset;
- mNextAddress = nextAddr;
- mFormatter = formatter;
+ mProject = project;
mMaxAddressValue = project.CpuDef.MaxAddressValue;
+ mFormatter = formatter;
- // Compute load address, i.e. where the byte would have been placed if the entire
- // file were loaded at the address of the first address map entry. We assume
- // offsets wrap at the bank boundary.
- int fileStartAddr = project.AddrMap.OffsetToAddress(0);
- mBaseAddr = ((fileStartAddr + firstOffset) & 0xffff) | (fileStartAddr & 0xff0000);
+ Configure(entry, isNew, newLength);
+ }
- int firstAddr = project.GetAnattrib(firstOffset).Address;
- Debug.Assert(project.AddrMap.OffsetToAddress(firstOffset) == firstAddr);
+ private void Configure(AddressMap.AddressMapEntry entry, bool isNew, int newLength) {
+ mRegionStartOffset = mRegionEndOffset = entry.Offset;
+ mPreLabelAddress = 0;
+ IsRegionValid = false;
- AddressText = Asm65.Address.AddressToString(firstAddr, false);
-
- LoadAddressText = '$' + mFormatter.FormatAddress(mBaseAddr, mBaseAddr > 0xffff);
-
- if (nextOffset >= 0) {
- NextAddressVis = Visibility.Visible;
+ // The passed-in region could have Length=FLOATING_LEN, so we need to resolve
+ // that now. We also need to figure out if it's valid. The easiest way to do
+ // that is to clone the address map, add the region to it, and see how the values
+ // resolve. This also gets us an address for the pre-label.
+ List entries;
+ int spanLength;
+ entries = mProject.AddrMap.GetEntryList(out spanLength);
+ AddressMap tmpMap = new AddressMap(spanLength, entries);
+ if (!isNew) {
+ // Remove the old entry.
+ if (!tmpMap.RemoveEntry(entry.Offset, entry.Length)) {
+ // Shouldn't happen.
+ Debug.Assert(false);
+ // TODO(org): some sort of failure indicator
+ return;
+ }
}
- NewAddress = -2;
+ // Add the new / replacement entry.
+ AddressMap.AddResult result = tmpMap.AddEntry(entry);
+ if (result != AddressMap.AddResult.Okay) {
+ // TODO(org): various things with failures
+ Debug.Assert(false); // remove
+ } else {
+ // Find it in the region tree.
+ mNewRegion = tmpMap.FindRegion(entry.Offset, entry.Length);
+ if (mNewRegion == null) {
+ // Shouldn't happen.
+ Debug.Assert(false);
+ // TODO(org): some sort of failure indicator
+ return;
+ } else {
+ // Set offset / length values based on what we got.
+ IsRegionValid = true;
+ mRegionStartOffset = mNewRegion.Offset;
+ mRegionEndOffset = mNewRegion.Offset + mNewRegion.ActualLength;
+ mPreLabelAddress = mNewRegion.PreLabelAddress;
+ mFloatTextVis = mNewRegion.IsFloating ? Visibility.Visible : Visibility.Hidden;
+ // Init editable stuff.
+ AddressText = Asm65.Address.AddressToString(mNewRegion.Address, false);
+ PreLabelText = mNewRegion.PreLabel;
+ UseRelativeAddressing = mNewRegion.IsRelative;
+ }
+ }
}
private void Window_ContentRendered(object sender, EventArgs e) {
@@ -163,12 +221,15 @@ namespace SourceGen.WpfGui {
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
- if (AddressText.Length == 0) {
- NewAddress = CommonUtil.AddressMap.NON_ADDR;
+ bool ok = ParseAddress(out int addr);
+ Debug.Assert(ok);
+ if (addr == AddressMap.INVALID_ADDR) {
+ // field was blank, want to delete the entry
+ NewEntry = null;
} else {
- bool ok = Asm65.Address.ParseAddress(AddressText, mMaxAddressValue, out int addr);
- Debug.Assert(ok);
- NewAddress = addr;
+ NewEntry = new AddressMap.AddressMapEntry(mNewRegion.Offset,
+ mNewRegion.Length, addr, PreLabelText,
+ UseRelativeAddressing);
}
DialogResult = true;
}
@@ -181,32 +242,32 @@ namespace SourceGen.WpfGui {
/// for TextBox is LostFocus.
///
private void UpdateControls() {
- IsValid = (AddressText.Length == 0) ||
- Asm65.Address.ParseAddress(AddressText, mMaxAddressValue, out int unused);
+ IsValid = IsRegionValid && ParseAddress(out int unused);
+ // TODO(org): check pre-label syntax
+ }
+
+ private const string NON_ADDR_STR = "NA";
+
+ ///
+ /// Parses the address out of the AddressText text box.
+ ///
+ /// Receives the parsed address. Will be NON_ADDR for "NA", and
+ /// INVALID_ADDR if blank.
+ /// True if the string parsed successfully.
+ private bool ParseAddress(out int addr) {
+ // Left blank?
+ if (AddressText.Length == 0) {
+ addr = AddressMap.INVALID_ADDR;
+ return true;
+ }
+ // "NA" for non-addressable?
+ string upper = AddressText.ToUpper();
+ if (upper == NON_ADDR_STR) {
+ addr = AddressMap.NON_ADDR;
+ return true;
+ }
+ // Parse numerically.
+ return Asm65.Address.ParseAddress(AddressText, mMaxAddressValue, out addr);
}
}
-
-
- // This might be better with validation rules, but it's sort of awkward to pass parameters
- // (like MaxAddressValue) in.
- // https://social.technet.microsoft.com/wiki/contents/articles/31422.wpf-passing-a-data-bound-value-to-a-validation-rule.aspx
- //
- // Speaking of awkward, updating the OK button's IsEnable value through validation
- // requires MultiDataTrigger.
-
-
- //public class AddressValidationRule : ValidationRule {
- // public int MaxAddress { get; set; }
-
- // public override ValidationResult Validate(object value, CultureInfo cultureInfo) {
- // string text = value.ToString();
- // Debug.WriteLine("VALIDATE " + text);
- // if ((text.Length == 0) ||
- // Asm65.Address.ParseAddress(text, MaxAddress, out int unused)) {
- // return new ValidationResult(true, null);
- // } else {
- // return new ValidationResult(false, "Invalid address");
- // }
- // }
- //}
}
\ No newline at end of file
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml b/SourceGen/WpfGui/EditAppSettings.xaml
index 6656416..c6ba446 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml
+++ b/SourceGen/WpfGui/EditAppSettings.xaml
@@ -585,125 +585,138 @@ limitations under the License.
VerticalAlignment="Center" Margin="{StaticResource TBS}"
Text=".placeho" MaxLength="12"
FontFamily="{StaticResource GeneralMonoFont}"/>
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
+
+
+
+
+
+
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml.cs b/SourceGen/WpfGui/EditAppSettings.xaml.cs
index 02fe5bb..acf1bbf 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml.cs
+++ b/SourceGen/WpfGui/EditAppSettings.xaml.cs
@@ -1180,7 +1180,8 @@ namespace SourceGen.WpfGui {
mPseudoNameMap = new TextBoxPropertyMap[] {
new TextBoxPropertyMap(equDirectiveTextBox, "EquDirective"),
new TextBoxPropertyMap(varDirectiveTextBox, "VarDirective"),
- new TextBoxPropertyMap(orgDirectiveTextBox, "OrgDirective"),
+ new TextBoxPropertyMap(arStartDirectiveTextBox, "ArStartDirective"),
+ new TextBoxPropertyMap(arEndDirectiveTextBox, "ArEndDirective"),
new TextBoxPropertyMap(regWidthDirectiveTextBox, "RegWidthDirective"),
new TextBoxPropertyMap(dataBankTextBox, "DataBankDirective"),
new TextBoxPropertyMap(defineData1TextBox, "DefineData1"),
diff --git a/SourceGen/WpfGui/EditDataOperand.xaml.cs b/SourceGen/WpfGui/EditDataOperand.xaml.cs
index fb14e81..6bc6da6 100644
--- a/SourceGen/WpfGui/EditDataOperand.xaml.cs
+++ b/SourceGen/WpfGui/EditDataOperand.xaml.cs
@@ -222,10 +222,6 @@ namespace SourceGen.WpfGui {
SetControlsFromDescriptor(mFirstFormatDescriptor);
if (mPreferredFormatUnavailable) {
- // This can happen when e.g. a bunch of stuff is formatted as null-terminated
- // strings. We don't recognize a lone zero as a string, but we allow it if
- // it's next to a bunch of others. If you come back later and try to format
- // just that one byte, you end up here.
// TODO(maybe): make it more obvious what's going on?
Debug.WriteLine("NOTE: preferred format unavailable");
}