1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-05-31 22:41:37 +00:00

Compare commits

...

30 Commits

Author SHA1 Message Date
Andy McFadden
fa5d9ba890 Version 1.9.0-dev1 2024-05-23 10:27:45 -07:00
Andy McFadden
3b20566b10 Minor tweaks
Note that address region isolation doesn't prevent explicit label
references from working (add update the test to prove it).

Added a note about pre-label xrefs.
2024-05-22 14:02:53 -07:00
Andy McFadden
7a7ff44d3a Address region isolation, part 3 (of 3)
If an address resolves to a user label in an isolated region, we
don't want to use it.  However, we still want to try to match it
to a project/platform symbol.

For example, suppose the isolated code wants to reference address
$1C00, which is a memory-mapped I/O location in one area, but a
regular bunch of code in the other.  We don't want it to map to
the regular code, but we do want it to resolve to our table of
platform I/O addresses.

We now handle this correctly.  The regression test has been updated
to check this.  The current implementation does a linear scan through
the symbol table, but I'm hoping this is not a common situation.

The reference manual has been updated to describe the new feature.
2024-05-21 14:14:32 -07:00
Andy McFadden
e137db2b5c Address region isolation, part 2
Added an address-to-offset test in the GeneratePlatformSymbolRefs()
method, which sets the operand symbols for anything that lands outside
the scope of the file.  Because the region isolation code prevented
symbols from being associated with the operands in the initial code
scan, those operands were being examined here.  Without the additional
test, the inappropriate label associations were getting a second chance.

Added "[!in]" and "[!out]" to the comment field of .addrs lines.  This
is only for the on-screen display and text exports, not asm gen.

Bumped the project file CONTENT_VERSION.

Added a regression test (20290-region-isolation).

The test turned up an existing problem: pre-labels are emitted by the
asm generators on their own line, but the code that puts excessively
long labels on a separate line wasn't taking that into account.  This
has been fixed.  No changes to existing regression tests, which didn't
happen to use long labels.
2024-05-21 10:32:18 -07:00
Andy McFadden
ea4ddc1071 Address region isolation, part 1
This adds a pair of flags to address regions that control how
address resolution is performed.

Generally, when we're trying to convert an address to a file offset,
we do a depth-first search through the hierarchy of address regions
to find a match.  For certain situations, such as multi-bank ROMs or
when code is executed in a separate subsystem, we don't want the
address resolver to specify an offset for something that's in a
different address space.

The search for a matching address starts from the region where the
address is referenced.  The flags will prevent the search from
progressing "outward" (to parent or sibling regions) or "inward"
(from parent or sibling regions).  Setting both flags effectively
makes the region an island.

Descending farther into the tree is not restricted by the "outward"
flag, i.e. addresses will still be found in child regions (assuming
they don't have the "disallow inward" flag set).

(issue #139)
2024-05-20 14:50:18 -07:00
Andy McFadden
d6cfc83368 Disable "prefer 32 bit" build flag
The build flag causes the application to run as a 32-bit app on 64-bit
systems, which we don't want.  We're still using "Any CPU" as the
platform target, so it will continue to work on 32-bit x86 systems;
we just no longer force it to always be 32-bit.

This only affects the main .NET Framework application executable.
The setting is not relevant for the libraries.

(Note to future self: the way things work changed with .NET Core,
which requires different executables for different targets, specified
with the RID.  The older .NET Framework is Windows-only, which makes
it easier to have a single multi-target EXE.)
2024-05-09 10:03:08 -07:00
Andy McFadden
17bd80e39f Version 1.8.6 2024-05-05 15:23:47 -07:00
Andy McFadden
ca38b7751c Tweak label file generation
Include an altered version of the uniquified local label, so that
VICE will keep the full set.

(issue #151)
2024-04-30 13:27:07 -07:00
Andy McFadden
948e4a2bf2
Update README.md
Mention Wine v9.
2024-04-22 17:50:15 -07:00
Andy McFadden
aa05aa7a80 Version 1.8.6-dev1 2024-04-22 17:39:25 -07:00
Andy McFadden
47b11b6797 Document new label placement setting 2024-04-22 17:35:21 -07:00
Andy McFadden
9e82ff8b88 Make label files look more like cc65 output
The cc65 docs say VICE labels start with '.'.  Also, output local
labels prefixed with '@', per ca65 convention.  The default output
file is now "labels.lbl".

Added some minimal documentation.

(issue #151)
2024-04-22 15:09:23 -07:00
Andy McFadden
4322a0c231 Add option to put labels on separate lines
We currently have two options for assembly code output, selected by
a checkbox in the application settings: always put labels on the same
lines as the instruction or data operand, or split the labels onto
their own line if they were wider than the label text field.

This change adds a third option, which puts labels on their own line
whenever possible.  Assemblers don't generally allow this for variable
assignment pseudo-ops like "foo = $1000", but it's accepted for most
other situations.  This is a cosmetic change to the output, and will
not affect the generated code.

The old true/false app setting will be disregarded.  "Split if too
long" will be used by default.

Added test 20280-label-placement to exercise the "split whenever
allowed" behavior.

The "export" function has a similar option that has not been updated
(for no particular reason other than laziness).

Also, simplified the app settings GetEnum / SetEnum calls, which
can infer the enumerated type from the arguments.  This should not
impact behavior.
2024-04-21 16:26:42 -07:00
Andy McFadden
e425237783 First cut at label file generation
Some debuggers allow you to import a list of labels for addresses.
This adds a command that generates a file full of labels in a
specific format.  Currently the VICE monitor format is supported.

(issue #151)
2024-04-20 16:37:08 -07:00
Andy McFadden
da91d9fc0e Allow arbitrary code list font sizes
The point size must be between 3 and 64, inclusive, just to avoid
doing anything too weird.  Also, added 14 to the drop-down.
2024-04-19 14:46:17 -07:00
Andy McFadden
8532cfb433 Rename menu item
Changed "File > Assemble" to "File > Generate Assembly".

Also, correctly mark a read-only text field as such.
2024-04-19 14:16:30 -07:00
David Youd
89df3278bc
Additional C64 .sym65 support files (#157)
* additional c64 symbols
2024-04-11 18:00:02 -07:00
Andy McFadden
9e9b12564e
Merge pull request #156 from c64cryptoboy/pr_c64_io_symbols
Added C64 IO symbols
2024-04-08 08:03:05 -07:00
David Youd
2f836d77a2 added c64 IO symbols 2024-04-07 20:09:34 -07:00
Andy McFadden
110a9ae818 Change the way app settings Apply button works
We were passing a reference to MainController in, and calling a
method on it, which is a little convoluted.  Now the main controller
subscribes to a "settings applied" event, and handles the update with
an event handler.

No change in behavior.
2024-03-02 14:48:06 -08:00
Andy McFadden
c637d6549c Minor updates 2024-03-02 11:17:52 -08:00
Andy McFadden
1c79cddb47
Added note about wine-mono 2023-05-24 10:52:29 -07:00
Andy McFadden
cee8fa3cbf Version 1.8.5 2023-05-12 15:56:43 -07:00
Andy McFadden
a8aa871109 Version 1.8.5-dev2 2023-05-10 10:08:30 -07:00
Andy McFadden
2f603b69c3 Fix format overwrite test
A SOS binary had situation were an instruction was being reformatted
as inline data by an extension script.  The code that was supposed
to detect and prevent this had a bug that caused it to only look at
the first byte.  The resulting confusion caused the program to crash.

(issue #150)
2023-05-10 10:07:15 -07:00
Andy McFadden
7ebf976279 Fix display of Rockwell long op descrs 2023-05-04 17:29:57 -07:00
Andy McFadden
72d8498fe0 Minor tweaks 2023-04-17 09:48:01 -07:00
Andy McFadden
ca50730611 Update comments 2023-04-14 13:46:40 -07:00
Andy McFadden
08243bf19c Remove unused PNG from project manifest 2023-03-30 17:25:19 -07:00
Andy McFadden
74cc55de29 Tweak grid border 2023-02-15 20:48:57 -08:00
85 changed files with 4486 additions and 308 deletions

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>

View File

@ -1121,8 +1121,17 @@ namespace Asm65 {
sb.Append(mHexDumpBuffer);
}
/// <summary>
/// Formats up to 16 bytes of data and appends it to the StringBuilder.
/// </summary>
/// <param name="data">Reference to data.</param>
/// <param name="offset">Start offset.</param>
/// <param name="addr">Address to put at start of line.</param>
/// <param name="length">Number of bytes to format.</param>
/// <param name="sb">StringBuilder to append the data to.</param>
public void FormatHexDump(byte[] data, int offset, int addr, int length,
StringBuilder sb) {
Debug.Assert(length <= 16);
FormatHexDumpCommon(data, offset, addr, length);
sb.Append(mHexDumpBuffer);
}

View File

@ -750,13 +750,13 @@ namespace Asm65 {
{ OpName.SMB7, SMB_DESC },
};
private static string BBR_DESC =
private const string BBR_DESC =
"Branches to a relative address if the specified bit in memory is zero.";
private static string BBS_DESC =
private const string BBS_DESC =
"Branches to a relative address if the specified bit in memory is one.";
private static string RMB_DESC =
private const string RMB_DESC =
"Clears a bit in memory.";
private static string SMB_DESC =
private const string SMB_DESC =
"Sets a bit in memory.";

View File

@ -39,18 +39,19 @@ namespace CommonUtil {
/// 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
/// (2) Hierarchical. Used when converting an address to an offset, 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.
/// the reference, and when determining the address of an offset. 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.
/// structural 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
@ -120,6 +121,16 @@ namespace CommonUtil {
/// </summary>
public string PreLabel { get; private set; }
/// <summary>
/// Should we prevent address resolution from entering this region?
/// </summary>
public bool DisallowInward { get; private set; }
/// <summary>
/// Should we prevent address resolution from traversing outside this region?
/// </summary>
public bool DisallowOutward { get; private set; }
/// <summary>
/// Should we try to generate the directive with an operand that is relative to
/// the current PC?
@ -130,20 +141,31 @@ namespace CommonUtil {
public bool IsRelative { get; private set; }
/// <summary>
/// Constructor.
/// Simple constructor.
/// </summary>
public AddressMapEntry(int offset, int len, int addr, string preLabel, bool isRelative) {
public AddressMapEntry(int offset, int len, int addr)
: this(offset, len, addr, string.Empty, false, false, false)
{ }
/// <summary>
/// Full constructor.
/// </summary>
public AddressMapEntry(int offset, int len, int addr, string preLabel,
bool disallowInward, bool disallowOutward, bool isRelative) {
Offset = offset;
Length = len;
Address = addr;
PreLabel = preLabel;
DisallowInward = disallowInward;
DisallowOutward = disallowOutward;
IsRelative = isRelative;
}
public override string ToString() {
return "[AddrMapEnt: +" + Offset.ToString("x6") + " len=$" + Length.ToString("x4") +
" addr=$" + Address.ToString("x4") + " preLab='" + PreLabel +
"' isRel=" + IsRelative + "]";
"' disIn=" + DisallowInward + " disOut=" + DisallowOutward +
" isRel=" + IsRelative + "]";
}
public static bool operator ==(AddressMapEntry a, AddressMapEntry b) {
@ -155,7 +177,8 @@ namespace CommonUtil {
}
// 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;
a.PreLabel == b.PreLabel && a.DisallowInward == b.DisallowInward &&
a.DisallowOutward == b.DisallowOutward && a.IsRelative == b.IsRelative;
}
public static bool operator !=(AddressMapEntry a, AddressMapEntry b) {
return !(a == b);
@ -164,7 +187,8 @@ namespace CommonUtil {
return obj is AddressMapEntry && this == (AddressMapEntry)obj;
}
public override int GetHashCode() {
return Offset ^ Length ^ Address ^ PreLabel.GetHashCode() ^ (IsRelative ? 1 : 0);
return Offset ^ Length ^ Address ^ PreLabel.GetHashCode() ^
(DisallowInward ? 1 : 0) ^ (DisallowOutward ? 2 : 0) ^ (IsRelative ? 4 : 0);
}
}
@ -225,9 +249,11 @@ namespace CommonUtil {
/// <summary>
/// Full constructor.
/// </summary>
public AddressRegion(int offset, int len, int addr, string preLabel, bool isRelative,
public AddressRegion(int offset, int len, int addr, string preLabel,
bool disallowInward, bool disallowOutward, bool isRelative,
int actualLen, int preLabelAddr)
: base(offset, len, addr, preLabel, isRelative) {
: base(offset, len, addr, preLabel, disallowInward, disallowOutward, isRelative)
{
ActualLength = actualLen;
PreLabelAddress = preLabelAddr;
@ -238,14 +264,17 @@ namespace CommonUtil {
/// Basic constructor. Not for use when len==FLOATING_LEN.
/// </summary>
public AddressRegion(int offset, int len, int addr)
: this(offset, len, addr, string.Empty, false, len, NON_ADDR) {
: this(offset, len, addr, string.Empty, false, false, 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") +
" actualLen=$" + ActualLength.ToString("x4") + " isRel=" + IsRelative + "]";
return "[AddrRegion: +" + Offset.ToString("x6") +
" len=" + (Length == FLOATING_LEN ? "float" : "$" + Length.ToString("x4")) +
" addr=" + (Address == NON_ADDR ? "NA" : "$" + Address.ToString("x4")) +
" actualLen=$" + ActualLength.ToString("x4") +
" disIn=" + DisallowInward + " disOut=" + DisallowOutward + " isRel=" +
IsRelative + "]";
}
}
@ -283,7 +312,7 @@ namespace CommonUtil {
foreach (AddressMapEntry ent in entries) {
// TODO(maybe): suppress Regenerate() call in AddEntry while we work
AddResult result = AddEntry(ent.Offset, ent.Length, ent.Address, ent.PreLabel,
ent.IsRelative);
ent.DisallowInward, ent.DisallowOutward, ent.IsRelative);
if (result != AddResult.Okay) {
throw new Exception("Unable to add entry (" + result + "): " + ent);
}
@ -360,16 +389,20 @@ namespace CommonUtil {
/// </summary>
/// <remarks>
/// We need to verify:
/// - offset &gt;= 0
/// - offset &lt; total length of file
/// - either length is floating, or:
/// - length > 0
/// - length &lt; total length of file
/// - offset + length &lt; total length of file
/// - either address is NON_ADDR, or:
/// - addr &gt; 0
/// - addr &lt;= ADDR_MAX
/// - preLabel is not null
/// <list type="bullet">
/// <item>offset &gt;= 0</item>
/// <item>offset &lt; total length of file</item>
/// <item>either length is floating, or:<list type="bullet">
/// <item>length &gt; 0</item>
/// <item>length &lt; total length of file</item>
/// <item>offset + length &lt; total length of file</item>
/// </list></item>
/// <item>either address is NON_ADDR, or:<list type="bullet">
/// <item>addr &gt; 0</item>
/// <item>addr &lt;= ADDR_MAX</item>
/// </list></item>
/// <item>preLabel is not null</item>
/// </list>
///
/// We might want to limit the length to fit within a single 64K bank, unless it's
/// a non-addressable region. That would probably be better as a warning than an error.
@ -390,7 +423,7 @@ namespace CommonUtil {
/// <param name="addr">Address of region start.</param>
/// <returns>Failure code.</returns>
public AddResult AddEntry(int offset, int length, int addr) {
return AddEntry(offset, length, addr, string.Empty, false);
return AddEntry(offset, length, addr, string.Empty, false, false, false);
}
/// <summary>
@ -402,7 +435,7 @@ namespace CommonUtil {
// 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);
entry.DisallowInward, entry.DisallowOutward, entry.IsRelative);
}
/// <summary>
@ -412,11 +445,15 @@ namespace CommonUtil {
/// <param name="length">Length of region, or FLOATING_LEN for a floating end point.</param>
/// <param name="addr">Address of region start.</param>
/// <param name="preLabel">Pre-region label.</param>
/// <param name="disallowInward">True if address resolution should not enter this
/// region.</param>
/// <param name="disallowOutward">True if address resolution should not traverse outside
/// of this region.</param>
/// <param name="isRelative">True if code generator should output relative
/// assembler directive operand.</param>
/// <returns>Failure code.</returns>
public AddResult AddEntry(int offset, int length, int addr, string preLabel,
bool isRelative) {
bool disallowInward, bool disallowOutward, bool isRelative) {
if (!ValidateArgs(offset, length, addr, preLabel)) {
Debug.WriteLine("AddEntry: invalid arg");
return AddResult.InvalidValue;
@ -425,7 +462,7 @@ namespace CommonUtil {
AddResult result = FindAddIndex(offset, length, out insIdx);
if (result == AddResult.Okay) {
AddressMapEntry newEntry = new AddressMapEntry(offset, length, addr,
preLabel, isRelative);
preLabel, disallowInward, disallowOutward, isRelative);
mMapEntries.Insert(insIdx, newEntry);
Regenerate();
}
@ -678,6 +715,11 @@ namespace CommonUtil {
Parent = parent;
// all other fields null/false
}
public override string ToString() {
return "[TreeNode children=" + Children.Count +
", Region=" + Region.ToString() + "]";
}
}
/// <summary>
@ -696,7 +738,7 @@ namespace CommonUtil {
// 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, string.Empty,
false, mSpanLength, NON_ADDR);
false, false, false, mSpanLength, NON_ADDR);
TreeNode topNode = new TreeNode(globalReg, null);
// Generate the children of this node.
@ -753,7 +795,8 @@ namespace CommonUtil {
}
}
AddressRegion fixedReg = new AddressRegion(childEnt.Offset,
FLOATING_LEN, childEnt.Address, childEnt.PreLabel, childEnt.IsRelative,
FLOATING_LEN, childEnt.Address, childEnt.PreLabel,
childEnt.DisallowInward, childEnt.DisallowOutward, childEnt.IsRelative,
nextStart - childEnt.Offset, preLabelAddr);
children.Add(new TreeNode(fixedReg, parent));
@ -762,7 +805,8 @@ namespace CommonUtil {
// Add this region to the list, and check for descendants.
AddressRegion newReg = new AddressRegion(childEnt.Offset,
childEnt.Length, childEnt.Address, childEnt.PreLabel,
childEnt.IsRelative, childEnt.Length, preLabelAddr);
childEnt.DisallowInward, childEnt.DisallowOutward, childEnt.IsRelative,
childEnt.Length, preLabelAddr);
TreeNode thisNode = new TreeNode(newReg, parent);
children.Add(thisNode);
@ -833,7 +877,12 @@ namespace CommonUtil {
return offset;
}
// Didn't find it. Move up one level, but ignore the branch we've already checked.
if (startNode.Region.DisallowOutward) {
return -1; // can't look at parent or siblings of this node
}
// Didn't find it. Move up one level, but ignore the branch we've already checked
// (for efficiency). We need to start checking the "disallow inward" flag.
ignoreNode = startNode;
startNode = startNode.Parent;
if (startNode == null) {
@ -851,11 +900,18 @@ namespace CommonUtil {
/// <param name="targetAddr">Address to find.</param>
/// <returns>Offset, or -1 if not found.</returns>
private int FindAddress(TreeNode node, TreeNode ignore, int targetAddr) {
// We can ignore the DisallowInward flag on the current node, because we're already
// in it. We don't want to descend into a child with the flag set. (It's okay to
// ascend into a parent that has it set, but that's not handled here.)
if (node.Children != null) {
foreach (TreeNode childNode in node.Children) {
if (childNode == ignore) {
continue;
}
if (childNode.Region.DisallowInward) {
continue; // can't look at siblings with DisallowInward set
}
int offset = FindAddress(childNode, null, targetAddr);
if (offset >= 0) {
// Found match in child, return that.
@ -876,7 +932,8 @@ namespace CommonUtil {
}
// We span the correct range of addresses. See if the requested address
// falls into a hole spanned by a child.
// falls into a hole spanned by a child. (This is independent of DisallowInward,
// since it's a hole in the address space whether we look at it or not.)
if (node.Children != null) {
int subPosn = targetAddr - region.Address; // position of target inside node
foreach (TreeNode childNode in node.Children) {
@ -923,7 +980,8 @@ namespace CommonUtil {
}
/// <summary>
/// Recursively descends into the tree to find the node that contains the offset.
/// Recursively descends into the tree to find the node that contains the offset. The
/// deepest child node that spans the offset will be returned.
/// </summary>
/// <param name="offset">File offset.</param>
/// <param name="node">Node to examine.</param>
@ -1260,6 +1318,12 @@ namespace CommonUtil {
if (change.IsSynthetic) {
sb.Append(" (auto-generated)");
}
if (change.Region.DisallowInward) {
sb.Append(" [!in]");
}
if (change.Region.DisallowOutward) {
sb.Append(" [!out]");
}
sb.Append(CRLF);
prevOffset = change.Offset;
@ -1330,6 +1394,9 @@ namespace CommonUtil {
#region Unit tests
// Unit test primitives. Set "result" to true at start of test; these will set it to
// false on failure.
private static void Test_Expect(AddResult expected, ref bool result, AddResult actual) {
if (expected != actual) {
Debug.WriteLine("test failed (expected=" + expected + ", actual=" + actual + ")");
@ -1342,7 +1409,6 @@ namespace CommonUtil {
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") + "/" +
@ -1351,12 +1417,14 @@ namespace CommonUtil {
}
}
// Test equality and hashcode ops on AddressMapEntry.
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);
AddressMapEntry ent1 = new AddressMapEntry(0, 1, 2, "three", false, false, true);
AddressMapEntry ent2 = new AddressMapEntry(0, 1, 2, "three", false, false, true);
AddressMapEntry ent3 = new AddressMapEntry(0, 1, 2, "three-A", false, false, true);
AddressMapEntry ent4 = new AddressMapEntry(0, 1, 2, "three-A", false, true, true);
result &= ent1 == ent2;
result &= ent1 != ent3;
@ -1364,11 +1432,14 @@ namespace CommonUtil {
Test_Expect(true, ref result, result);
AddressRegion reg1 = new AddressRegion(ent1.Offset, ent1.Length, ent1.Address,
ent1.PreLabel, ent1.IsRelative, ent1.Length, 0);
ent1.PreLabel, ent1.DisallowInward, ent1.DisallowOutward, ent1.IsRelative,
ent1.Length, 0);
AddressRegion reg2 = new AddressRegion(ent2.Offset, ent2.Length, ent2.Address,
ent2.PreLabel, ent2.IsRelative, ent2.Length, 0);
ent2.PreLabel, ent2.DisallowInward, ent2.DisallowOutward, ent2.IsRelative,
ent2.Length, 0);
AddressRegion reg3 = new AddressRegion(ent3.Offset, ent3.Length, ent3.Address,
ent3.PreLabel, ent3.IsRelative, ent3.Length, 0);
ent3.PreLabel, ent3.DisallowInward, ent3.DisallowOutward, ent3.IsRelative,
ent3.Length, 0);
result &= reg1 == reg2;
result &= reg1 == ent1;
@ -1377,33 +1448,37 @@ namespace CommonUtil {
result &= reg3 != ent1;
result &= reg1.Equals(ent2);
result &= ent3 != reg1;
result &= ent3 != ent4;
Test_Expect(true, ref result, result);
result &= ent1.GetHashCode() == ent2.GetHashCode();
result &= ent2.GetHashCode() != ent3.GetHashCode();
result &= ent3.GetHashCode() != ent4.GetHashCode();
Test_Expect(true, ref result, result);
return result;
}
// Test the AddressMap FindRegion() method.
private static bool Test_Find() {
const int mapLen = 0x1000;
AddressMap map = new AddressMap(mapLen);
bool result = true;
const int off0 = 0x000100;
// Map with three nested regions.
const int off0 = 0x000100; // region 0: +000100-000fff $2100-$2fff
const int len0 = 0x0f00;
const int adr0 = 0x2100;
const int off1 = 0x000200;
const int off1 = 0x000200; // region 1: +000200-0005ff $2200-$25ff
const int len1 = 0x0400;
const int adr1 = 0x2200;
const int off2 = 0x000400;
const int off2 = 0x000400; // region 2: +000400-0005ff* $2400-25ff
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);
AddressMapEntry ent0 = new AddressMapEntry(off0, len0, adr0);
AddressMapEntry ent1 = new AddressMapEntry(off1, len1, adr1);
AddressMapEntry ent2 = new AddressMapEntry(off2, len2, adr2);
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));
@ -1425,18 +1500,20 @@ namespace CommonUtil {
return result;
}
// Test basic behavior in a simple linear map.
private static bool Test_SimpleLinear() {
const int mapLen = 0x8000;
AddressMap map = new AddressMap(mapLen);
bool result = true;
const int off0 = 0x000000;
// Simple map with no gaps at start or between.
const int off0 = 0x000000; // region 0: +000000-0001ff $1000-$11ff
const int len0 = 0x0200;
const int adr0 = 0x1000;
const int off1 = 0x000200;
const int off1 = 0x000200; // region 1: +000200-0006ff $1200-$16ff
const int len1 = 0x0500;
const int adr1 = 0x1200;
const int off2 = 0x000700;
const int off2 = 0x000700; // region 3: +000700-0009ff $1700-$19ff
const int len2 = 0x0300;
const int adr2 = 0x1700;
@ -1465,6 +1542,7 @@ namespace CommonUtil {
Test_Expect(true, ref result, map.RemoveEntry(off0, mapLen));
Test_Expect(false, ref result, map.RemoveEntry(off0, mapLen));
// Check some address mappings.
Test_Expect(adr0, ref result, map.OffsetToAddress(off0));
Test_Expect(adr1, ref result, map.OffsetToAddress(off1));
Test_Expect(adr2, ref result, map.OffsetToAddress(off2));
@ -1487,25 +1565,26 @@ namespace CommonUtil {
return result;
}
// Test with floating region, and region with non-addressable gap.
private static bool Test_SimpleFloatGap() {
const int mapLen = 0x8000;
AddressMap map = new AddressMap(mapLen);
bool result = true;
const int off0 = 0x001000;
// Map has a non-addressable gap at the start; region #2 is nested non-addr.
// Regions 0 and 1 have overlapping address spaces.
const int off0 = 0x001000; // region 0: +001000-003fff* $1000-$3fff
const int len0 = FLOATING_LEN;
const int adr0 = 0x1000;
const int off1 = 0x004000;
const int off1 = 0x004000; // region 1: +004000-006fff $1200-51ff
const int len1 = 0x3000;
const int adr1 = 0x1200;
const int off2 = 0x005000;
const int off2 = 0x005000; // region 2: +005000-0050ff N/A
const int len2 = 0x0100;
const int adr2 = NON_ADDR;
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off0, len0, adr0));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off1, len1, adr1));
Test_Expect(AddResult.Okay, ref result, map.AddEntry(off0, len0, adr0));
Test_Expect(AddResult.Okay, ref result, map.AddEntry(off1, len1, adr1));
// Try to remove the implicit no-address zone.
Test_Expect(false, ref result, map.RemoveEntry(0, off0));
@ -1534,42 +1613,43 @@ namespace CommonUtil {
return result;
}
// Test construction with various nesting scenarios.
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.AddEntry(0x000100, 0x0400, 0x4000, "preA0", false));
map.AddEntry(0x000100, 0x0400, 0x4000, "preA0", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x000100, 0x0100, 0x7000, "preA1", false));
map.AddEntry(0x000100, 0x0100, 0x7000, "preA1", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x000100, 0x0300, 0x5000, "preA2", false));
map.AddEntry(0x000100, 0x0300, 0x5000, "preA2", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x000100, 0x0200, 0x6000, "preA3", false));
map.AddEntry(0x000100, 0x0200, 0x6000, "preA3", false, false, false));
// Add a couple of floaters.
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x0000ff, FLOATING_LEN, 0x30ff, "preA4", false));
map.AddEntry(0x0000ff, FLOATING_LEN, 0x30ff, "preA4", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x000101, FLOATING_LEN, 0x3101, "preA5", false));
map.AddEntry(0x000101, FLOATING_LEN, 0x3101, "preA5", false, false, false));
Test_Expect(AddResult.OverlapFloating, ref result,
map.AddEntry(0x000100, FLOATING_LEN, 0x3100, "preA6", false));
map.AddEntry(0x000100, FLOATING_LEN, 0x3100, "preA6", false, false, false));
// Nested with shared end offset.
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x000fff, FLOATING_LEN, 0x3fff, "preB0", false));
map.AddEntry(0x000fff, FLOATING_LEN, 0x3fff, "preB0", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x001200, 0x0200, 0x6000, "preB1", false));
map.AddEntry(0x001200, 0x0200, 0x6000, "preB1", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x001000, 0x0400, 0x4000, "preB2", false));
map.AddEntry(0x001000, 0x0400, 0x4000, "preB2", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x001100, 0x0300, 0x5000, "preB3", false));
map.AddEntry(0x001100, 0x0300, 0x5000, "preB3", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x001300, 0x0100, 0x7000, "preB4", false));
map.AddEntry(0x001300, 0x0100, 0x7000, "preB4", false, false, false));
// Single-byte region at start and end.
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x001200, 1, 0x8200, "preB5", false));
map.AddEntry(0x001200, 1, 0x8200, "preB5", false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x0013ff, 1, 0x83ff, "preB6", false));
map.AddEntry(0x0013ff, 1, 0x83ff, "preB6", false, false, false));
// Nested with no common edge, building from outside-in.
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002000, 0x0800, 0x4000));
@ -1607,20 +1687,27 @@ namespace CommonUtil {
return result;
}
// Look up addresses from different initial regions.
private static bool Test_Cross() {
const int mapLen = 0x4000;
AddressMap map = new AddressMap(mapLen);
bool result = true;
// Region 0: +000000-001fff $8000-9fff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000000, 0x2000, 0x8000));
// Region 1: +002000-003fff $8000-9fff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002000, 0x2000, 0x8000));
// Region 2: +002100-0022ff $e100-e2ff (overlaps with region 1).
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002100, 0x0200, 0xe100));
// Region 3: +003100-0032ff $f100-f2ff (overlaps with region 1).
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x003100, 0x0200, 0xf100));
// Look up address in region 3, from different regions.
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));
// Look up address in region 2, from different regions.
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));
@ -1643,28 +1730,29 @@ namespace CommonUtil {
return result;
}
// Test resolution across nested regions with no shared start/end.
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.AddEntry(0x000000, 0x6000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x001000, 0x4000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x002000, 0x2000, 0x7fff));
// Nested pyramid shape, all regions start at same address except last.
// Region 0: +000000-005fff $8000-dfff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000000, 0x6000, 0x8000));
// Region 1: +001000-005fff $8000-bfff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x001000, 0x4000, 0x8000));
// Region 2: +002000-003fff $7fff-9ffe
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x002000, 0x2000, 0x7fff));
// Second pyramid.
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x006000, 0x6000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x007000, 0x4000, 0x8000));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(0x008000, 0x2000, 0x8000));
// Region 3: +006000-00bfff $8000-dfff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x006000, 0x6000, 0x8000));
// Region 4: +007000-00afff $8000-bfff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x007000, 0x4000, 0x8000));
// Region 5: +008000-009fff $8000-9fff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x008000, 0x2000, 0x8000));
// Children take priority over the start node.
// Children take priority over the start node. These all resolve in region 2.
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));
@ -1672,19 +1760,26 @@ namespace CommonUtil {
Test_Expect(0x002001, ref result, map.AddressToOffset(0x002000, 0x8000));
Test_Expect(0x002000, ref result, map.AddressToOffset(0x000000, 0x7fff));
// These resolve in region 0.
Test_Expect(0x005000, ref result, map.AddressToOffset(0x000000, 0xd000));
Test_Expect(0x005000, ref result, map.AddressToOffset(0x003000, 0xd000));
// These fail because $c000-cfff only exists in region 0, and maps to
// offsets +004000-004fff, but region 1 (its child) spans the same range
// of offsets with different addresses.
Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0xc000));
Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0xcfff));
// These resolve in region 5.
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.
// $7fff doesn't exist in second pyramid, so we have to go back to first to find it.
Test_Expect(0x002000, ref result, map.AddressToOffset(0x008000, 0x7fff));
// Address $a000 exists in region 4, at offset +009000, but that's overlapped
// by region 5 (its child) with a different address.
Test_Expect(-1, ref result, map.AddressToOffset(0x008000, 0xa000));
// inside
@ -1703,28 +1798,38 @@ namespace CommonUtil {
return result;
}
// Test some region overlap edge cases.
private static bool Test_OddOverlap() {
const int mapLen = 0x1000;
AddressMap map = new AddressMap(mapLen);
bool result = true;
// Top region spans full map.
// Top region spans full map. +000000-000fff $1000-1fff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000000, mapLen, 0x1000));
// Parent region covers next two.
// Parent region covers next two. +000000-0003ff $1000-13ff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000000, 0x0400, 0x1000));
// Floating region.
// Floating region. +000100-0001ff* $2000-20ff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000100, FLOATING_LEN, 0x2000));
// Fixed region follows.
// Fixed region follows. +000200-0002ff $3000-30ff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000200, 0x0100, 0x3000));
//string mapStr = map.FormatAddressMap(); // DEBUG - format the map and
//Debug.WriteLine(mapStr); // DEBUG - print it to the console
Test_Expect(0x00017f, ref result, map.AddressToOffset(0x000000, 0x207f));
Test_Expect(0x00027f, ref result, map.AddressToOffset(0x000000, 0x307f));
Test_Expect(0x000180, ref result, map.AddressToOffset(0x000000, 0x2080));
// Add a region that starts in the middle of the floating region (becoming
// a sibling), and ends after the fixed region (becoming its parent).
// +000180-00037f $4000-41ff
Test_Expect(AddResult.Okay, ref result, map.AddEntry(0x000180, 0x0200, 0x4000));
// Remove it.
Test_Expect(0x00017f, ref result, map.AddressToOffset(0x000000, 0x207f));
Test_Expect(0x00027f, ref result, map.AddressToOffset(0x000000, 0x307f));
Test_Expect(-1, ref result, map.AddressToOffset(0x000000, 0x2080));
// Remove the region we just added. The float region should flex back out.
Test_Expect(true, ref result, map.RemoveEntry(0x000180, 0x0200));
Test_Expect(0x000180, ref result, map.AddressToOffset(0x000000, 0x2080));
// Add a region that starts in the middle of the floating region and ends after
// the parent. Since this crosses the parent's end boundary and doesn't share
@ -1736,6 +1841,151 @@ namespace CommonUtil {
return result;
}
// Test interaction between isolated regions.
private static bool Test_Isolation() {
const int mapLen = 0x8000;
bool result = true;
const int off0 = 0x001000; // region 0: +001000-003fff $1000-$3fff
const int len0 = 0x3000;
const int adr0 = 0x1000;
const int off1 = 0x002000; // region 1: +002000-002fff $2000-$2fff
const int len1 = 0x1000;
const int adr1 = 0x2000;
const int off2 = 0x004000; // region 2: +004000-006fff $4000-$6fff
const int len2 = 0x3000;
const int adr2 = 0x4000;
const int off3 = 0x005000; // region 3: +005000-005fff $8000-$8fff
const int len3 = 0x1000;
const int adr3 = 0x8000;
// Map: all open
AddressMap map = new AddressMap(mapLen);
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off0, len0, adr0, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off1, len1, adr1, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off2, len2, adr2, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off3, len3, adr3, string.Empty, false, false, false));
Test_Expect(-1, ref result, map.AddressToOffset(0x001000, 0x5005)); // hole
Test_Expect(0x002005, ref result, map.AddressToOffset(0x001000, 0x2005)); // 0 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x001000, 0x4005)); // 0 -> 2
Test_Expect(0x005005, ref result, map.AddressToOffset(0x001000, 0x8005)); // 0 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x002000, 0x1005)); // 1 -> 0
Test_Expect(0x004005, ref result, map.AddressToOffset(0x002000, 0x4005)); // 1 -> 2
Test_Expect(0x005005, ref result, map.AddressToOffset(0x002000, 0x8005)); // 1 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x004000, 0x1005)); // 2 -> 0
Test_Expect(0x002005, ref result, map.AddressToOffset(0x004000, 0x2005)); // 2 -> 1
Test_Expect(0x005005, ref result, map.AddressToOffset(0x004000, 0x8005)); // 2 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x005000, 0x1005)); // 3 -> 0
Test_Expect(0x002005, ref result, map.AddressToOffset(0x005000, 0x2005)); // 3 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x005000, 0x4005)); // 3 -> 2
// Map: inner regions 1 and 3 disallow inward
map = new AddressMap(mapLen);
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off0, len0, adr0, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off1, len1, adr1, string.Empty, true, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off2, len2, adr2, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off3, len3, adr3, string.Empty, true, false, false));
Test_Expect(-1, ref result, map.AddressToOffset(0x001000, 0x2005)); // 0 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x001000, 0x4005)); // 0 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x001000, 0x8005)); // 0 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x002000, 0x1005)); // 1 -> 0
Test_Expect(0x004005, ref result, map.AddressToOffset(0x002000, 0x4005)); // 1 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x8005)); // 1 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x004000, 0x1005)); // 2 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x004000, 0x2005)); // 2 -> 1
Test_Expect(-1, ref result, map.AddressToOffset(0x004000, 0x8005)); // 2 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x005000, 0x1005)); // 3 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x2005)); // 3 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x005000, 0x4005)); // 3 -> 2
// Map: inner regions 1 and 3 disallow outward
map = new AddressMap(mapLen);
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off0, len0, adr0, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off1, len1, adr1, string.Empty, false, true, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off2, len2, adr2, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off3, len3, adr3, string.Empty, false, true, false));
Test_Expect(0x002005, ref result, map.AddressToOffset(0x001000, 0x2005)); // 0 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x001000, 0x4005)); // 0 -> 2
Test_Expect(0x005005, ref result, map.AddressToOffset(0x001000, 0x8005)); // 0 -> 3
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x1005)); // 1 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x4005)); // 1 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x8005)); // 1 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x004000, 0x1005)); // 2 -> 0
Test_Expect(0x002005, ref result, map.AddressToOffset(0x004000, 0x2005)); // 2 -> 1
Test_Expect(0x005005, ref result, map.AddressToOffset(0x004000, 0x8005)); // 2 -> 3
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x1005)); // 3 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x2005)); // 3 -> 1
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x4005)); // 3 -> 2
// Map: region 0 disallows inward and outward
map = new AddressMap(mapLen);
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off0, len0, adr0, string.Empty, true, true, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off1, len1, adr1, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off2, len2, adr2, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off3, len3, adr3, string.Empty, false, false, false));
Test_Expect(0x001005, ref result, map.AddressToOffset(0x001000, 0x1005)); // 0 -> 0
Test_Expect(0x002005, ref result, map.AddressToOffset(0x001000, 0x2005)); // 0 -> 1
Test_Expect(-1, ref result, map.AddressToOffset(0x001000, 0x4005)); // 0 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x001000, 0x8005)); // 0 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x002000, 0x1005)); // 1 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x4005)); // 1 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x8005)); // 1 -> 3
Test_Expect(-1, ref result, map.AddressToOffset(0x004000, 0x1005)); // 2 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x004000, 0x2005)); // 2 -> 1
Test_Expect(0x005005, ref result, map.AddressToOffset(0x004000, 0x8005)); // 2 -> 3
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x1005)); // 3 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x2005)); // 3 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x005000, 0x4005)); // 3 -> 2
// Map: region 3 disallows inward and outward
map = new AddressMap(mapLen);
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off0, len0, adr0, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off1, len1, adr1, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off2, len2, adr2, string.Empty, false, false, false));
Test_Expect(AddResult.Okay, ref result,
map.AddEntry(off3, len3, adr3, string.Empty, true, true, false));
Test_Expect(0x005005, ref result, map.AddressToOffset(0x005000, 0x8005)); // 3 -> 3
Test_Expect(0x002005, ref result, map.AddressToOffset(0x001000, 0x2005)); // 0 -> 1
Test_Expect(0x004005, ref result, map.AddressToOffset(0x001000, 0x4005)); // 0 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x001000, 0x8005)); // 0 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x002000, 0x1005)); // 1 -> 0
Test_Expect(0x004005, ref result, map.AddressToOffset(0x002000, 0x4005)); // 1 -> 2
Test_Expect(-1, ref result, map.AddressToOffset(0x002000, 0x8005)); // 1 -> 3
Test_Expect(0x001005, ref result, map.AddressToOffset(0x004000, 0x1005)); // 2 -> 0
Test_Expect(0x002005, ref result, map.AddressToOffset(0x004000, 0x2005)); // 2 -> 1
Test_Expect(-1, ref result, map.AddressToOffset(0x004000, 0x8005)); // 2 -> 3
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x1005)); // 3 -> 0
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x2005)); // 3 -> 1
Test_Expect(-1, ref result, map.AddressToOffset(0x005000, 0x4005)); // 3 -> 2
return result;
}
public static bool Test() {
bool ok = true;
ok &= Test_Primitives();
@ -1746,6 +1996,11 @@ namespace CommonUtil {
ok &= Test_Cross();
ok &= Test_Pyramids();
ok &= Test_OddOverlap();
ok &= Test_Isolation();
// Do this to get a visualization:
//string mapStr = map.FormatAddressMap(); // DEBUG - format the map and
//Debug.WriteLine(mapStr); // DEBUG - print it to the console
Debug.WriteLine("AddressMap: test complete (ok=" + ok + ")");
return ok;

View File

@ -42,10 +42,10 @@ namespace CommonUtil {
/// </summary>
/// <remarks>
/// Usage:
/// AppDomain.CurrentDomain.UnhandledException +=
/// new UnhandledExceptionEventHandler(CommonUtil.Misc.CrashReporter);
/// <code>AppDomain.CurrentDomain.UnhandledException +=
/// new UnhandledExceptionEventHandler(CommonUtil.Misc.CrashReporter);</code>
///
/// Thanks: https://stackoverflow.com/a/21308327/294248
/// Thanks: <see href="https://stackoverflow.com/a/21308327/294248"/>.
/// </remarks>
public static void CrashReporter(object sender, UnhandledExceptionEventArgs e) {
const string CRASH_PATH = @"CrashLog.txt";
@ -80,7 +80,7 @@ namespace CommonUtil {
/// faster than setting array elements individually.
/// </summary>
/// <remarks>
/// From https://stackoverflow.com/a/18659408/294248
/// From <see href="https://stackoverflow.com/a/18659408/294248"/>.
///
/// Invokes Array.Copy() on overlapping elements. Other approaches involve using
/// Buffer.BlockCopy or unsafe code. Apparently .NET Core has an Array.Fill(), but

View File

@ -323,7 +323,8 @@ namespace PluginCommon {
/// Will be null for direct-color images. Do not modify.
/// </summary>
/// <remarks>
/// It's possible, but weird, for the array to have a length of zero.
/// It's possible, but weird, for the array to have a length of zero. For best results
/// with GIF images, only one palette entry should be transparent.
/// </remarks>
int[] GetPalette();

View File

@ -64,6 +64,12 @@ namespace PluginCommon {
return mPalette[pix];
}
/// <summary>
/// Gets the color index for a single pixel.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
/// <returns>Color index.</returns>
public byte GetPixelIndex(int x, int y) {
return mData[x + y * Width];
}
@ -180,7 +186,7 @@ namespace PluginCommon {
/// <remarks>
/// Might want a way to specify that the background shouldn't be drawn at all.
/// </remarks>
/// <param name="vb">Bitma to draw on.</param>
/// <param name="vb">Bitmap to draw on.</param>
/// <param name="ch">Character to draw.</param>
/// <param name="xc">X coord of upper-left pixel.</param>
/// <param name="yc">Y coord of upper-left pixel.</param>

View File

@ -143,9 +143,8 @@ The framework requires Win7 SP1, Win8.1, Win10 updated through at least the
Anniversary Update (1607), or Win11. (One user who had trouble with the
4.7.2 installer was able to get the 4.6.2 installer to work.)
SourceGen does not currently run on Linux or Mac OS. My understanding is
that WPF-based .NET apps don't work under Mono or WINE, so SourceGen can only
be run on a full Windows system emulator.
SourceGen does not run natively on Linux or Mac OS. It is reported
to work with recent versions (v9+) of the [Wine emulation layer](https://winehq.org/).
(SourceGen versions 1.0 and 1.1 used the WinForms API, which has been
implemented for [Mono](https://www.mono-project.com/), but after

View File

@ -25,6 +25,6 @@ namespace SourceGen {
/// SourceGen version number.
/// </summary>
public static readonly CommonUtil.Version ProgramVersion =
new CommonUtil.Version(1, 8, 5, CommonUtil.Version.PreRelType.Dev, 1);
new CommonUtil.Version(1, 9, 0, CommonUtil.Version.PreRelType.Dev, 1);
}
}

View File

@ -124,9 +124,13 @@ namespace SourceGen {
// Source generation settings.
public const string SRCGEN_DEFAULT_ASM = "srcgen-default-asm";
public const string SRCGEN_ADD_IDENT_COMMENT = "srcgen-add-ident-comment";
public const string SRCGEN_LONG_LABEL_NEW_LINE = "srcgen-long-label-new-line";
public const string SRCGEN_LABEL_NEW_LINE = "srcgen-label-new-line";
public const string SRCGEN_SHOW_CYCLE_COUNTS = "srcgen-show-cycle-counts";
// Label file generation settings.
public const string LABGEN_FORMAT = "labgen-format";
public const string LABGEN_INCLUDE_AUTO = "labgen-include-auto";
// Assembler settings prefix
public const string ASM_CONFIG_PREFIX = "asm-config-";
@ -187,6 +191,7 @@ namespace SourceGen {
/// </summary>
/// <returns></returns>
public AppSettings GetCopy() {
// TODO: make this a copy constructor?
AppSettings copy = new AppSettings();
//copy.mSettings.EnsureCapacity(mSettings.Count);
foreach (KeyValuePair<string, string> kvp in mSettings) {
@ -202,7 +207,7 @@ namespace SourceGen {
/// discarding the object itself, which is useful in case something has cached a
/// reference to the singleton.
/// </summary>
/// <param name="newSettings"></param>
/// <param name="newSettings">Object with new settings.</param>
public void ReplaceSettings(AppSettings newSettings) {
// Clone the new list, and stuff it into the old object. This way the
// objects aren't sharing lists.
@ -213,8 +218,7 @@ namespace SourceGen {
/// <summary>
/// Merges settings from another settings object into this one.
/// </summary>
/// <param name="settings"></param>
/// <param name="newSettings"></param>
/// <param name="newSettings">Object with new settings.</param>
public void MergeSettings(AppSettings newSettings) {
foreach (KeyValuePair<string, string> kvp in newSettings.mSettings) {
mSettings[kvp.Key] = kvp.Value;
@ -287,21 +291,20 @@ namespace SourceGen {
/// <summary>
/// Retrieves an enumerated value setting.
/// </summary>
/// <typeparam name="T">Enumerated type.</typeparam>
/// <param name="name">Setting name.</param>
/// <param name="enumType">Enum type that the value is part of.</param>
/// <param name="defaultValue">Setting default value.</param>
/// <returns>The value found, or the default value if no setting with the specified
/// name exists, or the stored value is not a member of the specified enumerated
/// type.</returns>
public int GetEnum(string name, Type enumType, int defaultValue) {
/// name exists, or the stored value is not a member of the enumeration.</returns>
public T GetEnum<T>(string name, T defaultValue) {
if (!mSettings.TryGetValue(name, out string valueStr)) {
return defaultValue;
}
try {
object o = Enum.Parse(enumType, valueStr);
return (int)o;
object o = Enum.Parse(typeof(T), valueStr);
return (T)o;
} catch (ArgumentException ae) {
Debug.WriteLine("Failed to parse " + valueStr + " (enum " + enumType + "): " +
Debug.WriteLine("Failed to parse '" + valueStr + "' (enum " + typeof(T) + "): " +
ae.Message);
return defaultValue;
}
@ -310,11 +313,22 @@ namespace SourceGen {
/// <summary>
/// Sets an enumerated setting.
/// </summary>
/// <remarks>
/// The value is output to the settings file as a string, rather than an integer, allowing
/// the correct handling even if the enumerated values are renumbered.
/// </remarks>
/// <typeparam name="T">Enumerated type.</typeparam>
/// <param name="name">Setting name.</param>
/// <param name="enumType">Enum type.</param>
/// <param name="value">Setting value (integer enum index).</param>
public void SetEnum(string name, Type enumType, int value) {
string newVal = Enum.GetName(enumType, value);
public void SetEnum<T>(string name, T value) {
if (value == null) {
throw new NotImplementedException("Can't handle a null-valued enum type");
}
string newVal = Enum.GetName(typeof(T), value);
if (newVal == null) {
Debug.WriteLine("Unable to get enum name type=" + typeof(T) + " value=" + value);
return;
}
if (!mSettings.TryGetValue(name, out string oldValue) || oldValue != newVal) {
mSettings[name] = newVal;
Dirty = true;

View File

@ -62,9 +62,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
/// <summary>
/// If set, long labels get their own line.
/// Influences whether labels are put on their own line.
/// </summary>
private bool mLongLabelNewLine;
private GenCommon.LabelPlacement mLabelNewLine;
/// <summary>
/// Output column widths.
@ -198,7 +198,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Acme);
@ -663,11 +664,13 @@ namespace SourceGen.AsmGen {
// IGenerator
public void OutputLine(string label, string opcode, string operand, string comment) {
// Break the line if the label is long and it's not a .EQ directive.
if (!string.IsNullOrEmpty(label) &&
if (!string.IsNullOrEmpty(label) && !string.IsNullOrEmpty(opcode) &&
!string.Equals(opcode, sDataOpNames.EquDirective,
StringComparison.InvariantCultureIgnoreCase)) {
if (mLongLabelNewLine && label.Length >= mColumnWidths[0]) {
if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
(mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
label.Length >= mColumnWidths[0])) {
mOutStream.WriteLine(label);
label = string.Empty;
}

View File

@ -57,9 +57,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
/// <summary>
/// If set, long labels get their own line.
/// Influences whether labels are put on their own line.
/// </summary>
private bool mLongLabelNewLine;
private GenCommon.LabelPlacement mLabelNewLine;
/// <summary>
/// Output column widths.
@ -188,7 +188,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Cc65);
@ -659,7 +660,10 @@ namespace SourceGen.AsmGen {
StringComparison.InvariantCultureIgnoreCase)) {
label += ':';
if (mLongLabelNewLine && label.Length >= mColumnWidths[0]) {
if (!string.IsNullOrEmpty(opcode) &&
(mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
(mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
label.Length >= mColumnWidths[0]))) {
mOutStream.WriteLine(label);
label = string.Empty;
}

View File

@ -57,9 +57,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
/// <summary>
/// If set, long labels get their own line.
/// Influences whether labels are put on their own line.
/// </summary>
private bool mLongLabelNewLine;
private GenCommon.LabelPlacement mLabelNewLine;
/// <summary>
/// Output column widths.
@ -174,7 +174,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Merlin32);
@ -606,11 +607,15 @@ namespace SourceGen.AsmGen {
// IGenerator
public void OutputLine(string label, string opcode, string operand, string comment) {
// Split long label, but not on EQU directives (confuses the assembler).
if (mLongLabelNewLine && label.Length >= mColumnWidths[0] &&
if (!string.IsNullOrEmpty(label) && !string.IsNullOrEmpty(opcode) &&
!string.Equals(opcode, sDataOpNames.EquDirective,
StringComparison.InvariantCultureIgnoreCase)) {
mOutStream.WriteLine(label);
label = string.Empty;
if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
(mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
label.Length >= mColumnWidths[0])) {
mOutStream.WriteLine(label);
label = string.Empty;
}
}
mLineBuilder.Clear();

View File

@ -73,9 +73,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
/// <summary>
/// If set, long labels get their own line.
/// Influences whether labels are put on their own line.
/// </summary>
private bool mLongLabelNewLine;
private GenCommon.LabelPlacement mLabelNewLine;
/// <summary>
/// Output column widths.
@ -201,7 +201,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Tass64);
@ -771,13 +772,15 @@ namespace SourceGen.AsmGen {
// IGenerator
public void OutputLine(string label, string opcode, string operand, string comment) {
// Break the line if the label is long and it's not a .EQ/.VAR directive.
if (!string.IsNullOrEmpty(label) &&
if (!string.IsNullOrEmpty(label) && !string.IsNullOrEmpty(opcode) &&
!string.Equals(opcode, sDataOpNames.EquDirective,
StringComparison.InvariantCultureIgnoreCase) &&
!string.Equals(opcode, sDataOpNames.VarDirective,
StringComparison.InvariantCultureIgnoreCase)) {
if (mLongLabelNewLine && label.Length >= mColumnWidths[0]) {
if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
(mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
label.Length >= mColumnWidths[0])) {
mOutStream.WriteLine(label);
label = string.Empty;
}

View File

@ -23,11 +23,19 @@ using Asm65;
using CommonUtil;
namespace SourceGen.AsmGen {
/// <summary>
/// Code common to all assembly source generators.
/// </summary>
public class GenCommon {
public enum LabelPlacement {
Unknown = 0,
PreferSameLine,
SplitIfTooLong,
PreferSeparateLine,
}
/// <summary>
/// Generates assembly source.
///
/// This code is common to all generators.
/// </summary>
/// <param name="gen">Reference to generator object (presumably the caller).</param>
/// <param name="sw">Text output sink.</param>

View File

@ -75,7 +75,7 @@ limitations under the License.
<DockPanel Grid.Column="3" Grid.Row="2">
<TextBlock DockPanel.Dock="Left" Margin="0,1,0,0">Work directory:</TextBlock>
<TextBox DockPanel.Dock="Right" Name="workDirectoryTextBox" Margin="8,0,0,0"
Text="C:\this\that\theother"/>
IsReadOnly="True" Text="C:\this\that\theother"/>
</DockPanel>
</Grid>

View File

@ -1171,7 +1171,7 @@ namespace SourceGen {
" (" + mAnalyzerTags[i] + ")");
return false;
}
if (mAnattribs[offset].IsInstruction) {
if (mAnattribs[i].IsInstruction) {
LogW(offset, "SIDF rej: not for use with instructions");
return false;
}

View File

@ -1438,17 +1438,19 @@ namespace SourceGen {
attr.OperandAddress >= 0 && attr.OperandOffset < 0) {
// This is an instruction that hasn't been explicitly formatted. It
// has an operand address, but not an offset, meaning it's a reference
// to an address outside the scope of the file. See if it has a
// platform symbol definition.
// to an address outside the scope of the file -or- a reference to an address
// region that we're not supposed to interact with (DisallowInbound on it
// or DisallowOutbound on us). See if it has a platform symbol definition,
// or perhaps an address region pre-label.
//
// It might seem unwise to examine the full symbol table, because it has
// non-project non-platform symbols in it. However, any matching user
// labels would have been applied already. Also, we want to ensure that
// conflicting user labels take precedence, e.g. creating a user label "COUT"
// will prevent a platform symbol with the same name from being visible.
// Using the full symbol table is potentially a tad less efficient than
// looking for a match exclusively in project/platform symbols, but it's
// the correct thing to do.
// labels would have been applied already (unless blocked by address region
// isolation). Also, we want to ensure that conflicting user labels take
// precedence, e.g. creating a user label "COUT" will prevent a platform
// symbol with the same name from being visible. Using the full symbol
// table is potentially a tad less efficient than looking for a match
// exclusively in project/platform symbols, but it's the correct thing to do.
OpDef op = CpuDef.GetOpDef(FileData[offset]);
accType = op.MemEffect;
address = attr.OperandAddress;
@ -1493,10 +1495,24 @@ namespace SourceGen {
if (sym == null && checkNearby && (address & 0xffff) < 0xffff &&
address > 0x0000ff) {
sym = SymbolTable.FindNonVariableByAddress(address + 1, accType);
if (sym != null && sym.SymbolSource != Symbol.Source.Project &&
sym.SymbolSource != Symbol.Source.Platform) {
Debug.WriteLine("Applying non-platform in GeneratePlatform: " + sym);
// should be okay to do this
}
if (sym != null && sym.SymbolSource != Symbol.Source.Project &&
sym.SymbolSource != Symbol.Source.Platform &&
sym.SymbolSource != Symbol.Source.AddrPreLabel) {
// If we matched to something other than a project/platform symbol or
// pre-label (which are expected to be outside the file area), make sure
// we're not doing an invalid cross-region reference.
if (AddrMap.AddressToOffset(offset, sym.Value) >= 0) {
Debug.WriteLine("GeneratePlatform applying non-platform at +" +
offset.ToString("x6") + ": " + sym);
} else {
Debug.WriteLine("GeneratePlatform not applying at +" +
offset.ToString("x6") + ": " + sym);
// Do a secondary scan, looking only at project/platform/pre-labels.
sym = SymbolTable.FindProjPlatPreByAddress(address, accType);
if (sym != null) {
Debug.WriteLine(" ...found matching proj/plat: " + sym);
}
}
}
@ -1534,7 +1550,7 @@ namespace SourceGen {
//
// We want to tag both. So if "LDA $1000" becomes "LDA label-2", we want to
// add a numeric reference to the code at $1000, and a symbolic reference to the
// labe at $1002, that point back to the LDA instruction. These are presented
// label at $1002, that point back to the LDA instruction. These are presented
// slightly differently to the user. For a symbolic reference with no adjustment,
// we don't add the (redundant) numeric reference.
//
@ -1632,6 +1648,12 @@ namespace SourceGen {
mAnattribs[operandOffset].Address;
}
// TODO: to handle pre-labels correctly, we need to associate an
// XrefSet with an address region, and add the reference there. We
// currently attach it to the offset of the first byte in the region,
// which means you don't see anything in the references window when
// the pre-label line is selected.
AddXref(symOffset, new XrefSet.Xref(offset, true, xrefType, accType,
accessFlags, adj));
if (adj == 0) {

View File

@ -550,10 +550,8 @@ namespace SourceGen {
// but we're only doing this on the template file, which should be small.
tmplStr = tmplStr.Replace("$ProjectName$", mProject.DataFileName);
tmplStr = tmplStr.Replace("$AppVersion$", App.ProgramVersion.ToString());
string expModeStr = ((Formatter.FormatConfig.ExpressionMode)
AppSettings.Global.GetEnum(AppSettings.FMT_EXPRESSION_MODE,
typeof(Formatter.FormatConfig.ExpressionMode),
(int)Formatter.FormatConfig.ExpressionMode.Unknown)).ToString();
string expModeStr = AppSettings.Global.GetEnum(AppSettings.FMT_EXPRESSION_MODE,
Formatter.FormatConfig.ExpressionMode.Unknown).ToString();
tmplStr = tmplStr.Replace("$ExpressionStyle$", expModeStr);
string dateStr = DateTime.Now.ToString("yyyy/MM/dd");
string timeStr = DateTime.Now.ToString("HH:mm:ss zzz");

View File

@ -0,0 +1,90 @@
/*
* Copyright 2019 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace SourceGen {
/// <summary>
/// Label file generator.
/// </summary>
public class LabelFileGenerator {
public enum LabelFmt {
Unknown = 0,
VICE,
}
private DisasmProject mProject;
private LabelFmt mFormat;
private bool mIncludeAutoLabels;
public LabelFileGenerator(DisasmProject project, LabelFmt format, bool includeAutoLabels) {
mProject = project;
mFormat = format;
mIncludeAutoLabels = includeAutoLabels;
}
public void Generate(StreamWriter outStream) {
List<Symbol> symList = new List<Symbol>();
foreach (Symbol sym in mProject.SymbolTable) {
bool include;
switch (sym.SymbolSource) {
case Symbol.Source.User:
case Symbol.Source.AddrPreLabel:
include = true;
break;
case Symbol.Source.Auto:
include = mIncludeAutoLabels;
break;
case Symbol.Source.Project:
case Symbol.Source.Platform:
case Symbol.Source.Variable:
default:
include = false;
break;
}
if (include) {
symList.Add(sym);
}
}
// Sort alphabetically. Not necessary, but it could make a "diff" easier to read.
symList.Sort((a, b) => Symbol.Compare(Symbol.SymbolSortField.Name, true, a, b));
Debug.Assert(mFormat == LabelFmt.VICE);
// VICE format is "add_label <address> <label>", but may be abbreviated "al".
// We could also use ACME format ("labelname = $1234 ; Maybe a comment").
foreach (Symbol sym in symList) {
// VICE only keeps one copy of each label, so local labels need to include the
// uniquifier. The UNIQUE_TAG_CHAR may not be accepted, so replace it with '_'.
string label = sym.Label;
label = label.Replace(Symbol.UNIQUE_TAG_CHAR, '_');
if (sym.IsNonUnique) {
// Add the cc65 prefix convention for local labels.
label = '@' + label;
}
// The cc65 docs (https://www.cc65.org/doc/debugging-4.html) say all labels
// must be prefaced with '.'. VICE rejects labels that start with a letter.
label = '.' + label;
outStream.WriteLine("al " + sym.Value.ToString("x6") + " " + label);
}
}
}
}

View File

@ -1122,9 +1122,19 @@ namespace SourceGen {
comment += " (auto-generated)";
}
#else
string comment = string.Empty;
string cstr = string.Empty;
if (change.IsSynthetic) {
comment = mFormatter.FormatEolComment("(auto-generated)");
cstr += " (auto-generated)";
}
if (region.DisallowInward) {
cstr += " [!in]";
}
if (region.DisallowOutward) {
cstr += " [!out]";
}
string comment = string.Empty;
if (cstr.Length > 0) {
comment = mFormatter.FormatEolComment(cstr.Substring(1));
}
#endif
newLine.Parts = FormattedParts.CreateFullDirective(string.Empty,

View File

@ -256,7 +256,7 @@ namespace SourceGen {
// Load the settings from the file. If this fails we have no way to tell the user,
// so just keep going.
LoadAppSettings();
SetAppWindowLocation();
SetAppWindowLocation(); // <-- this causes WindowLoaded to fire
}
/// <summary>
@ -345,7 +345,8 @@ namespace SourceGen {
settings.SetString(AppSettings.FMT_OPERAND_PREFIX_LONG, "f:");
settings.SetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, true);
settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, true);
settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
AsmGen.GenCommon.LabelPlacement.SplitIfTooLong);
#if DEBUG
settings.SetBool(AppSettings.DEBUG_MENU_ENABLED, true);
@ -453,20 +454,6 @@ namespace SourceGen {
}
}
/// <summary>
/// Replaces the contents of the global settings object with the new settings,
/// then applies them to the project.
/// </summary>
/// <param name="settings">New settings.</param>
public void SetAppSettings(AppSettings settings) {
AppSettings.Global.ReplaceSettings(settings);
ApplyAppSettings();
// We get called whenever Apply or OK is hit in the settings editor, so it's
// a pretty good time to save the settings out.
SaveAppSettings();
}
/// <summary>
/// Sets the app window's location and size. This should be called before the window has
/// finished initialization.
@ -1476,10 +1463,8 @@ namespace SourceGen {
return;
}
ClipLineFormat format = (ClipLineFormat)AppSettings.Global.GetEnum(
AppSettings.CLIP_LINE_FORMAT,
typeof(ClipLineFormat),
(int)ClipLineFormat.AssemblerSource);
ClipLineFormat format = AppSettings.Global.GetEnum(AppSettings.CLIP_LINE_FORMAT,
ClipLineFormat.AssemblerSource);
int[] rightWidths = new int[] { 16, 6, 16, 80 };
@ -1519,21 +1504,30 @@ namespace SourceGen {
}
/// <summary>
/// Opens the application settings dialog. All changes to settings are made directly
/// to the AppSettings.Global object.
/// Handles Edit &gt; App Settings.
/// </summary>
public void EditAppSettings() {
ShowAppSettings(mMainWin, WpfGui.EditAppSettings.Tab.Unknown,
AsmGen.AssemblerInfo.Id.Unknown);
}
/// <summary>
/// Opens the application settings dialog. All changes to settings are made directly
/// to the AppSettings.Global object.
/// </summary>
public void ShowAppSettings(Window owner, EditAppSettings.Tab initialTab,
AsmGen.AssemblerInfo.Id initialAsmId) {
EditAppSettings dlg = new EditAppSettings(owner, mMainWin, this,
initialTab, initialAsmId);
EditAppSettings dlg = new EditAppSettings(owner, mMainWin, initialTab, initialAsmId);
dlg.SettingsApplied += SetAppSettings; // called when "Apply" is clicked
dlg.ShowDialog();
}
// The settings code calls SetAppSettings() directly whenever "Apply" is hit.
/// <summary>
/// Applies settings to the project, and saves them to the settings files.
/// </summary>
private void SetAppSettings() {
ApplyAppSettings();
SaveAppSettings();
}
public void HandleCodeListDoubleClick(int row, int col) {
@ -1930,8 +1924,7 @@ namespace SourceGen {
}
// Create a prototype entry with the various values.
newEntry = new AddressMap.AddressMapEntry(firstOffset,
selectedLen, addr, string.Empty, false);
newEntry = new AddressMap.AddressMapEntry(firstOffset, selectedLen, addr);
Debug.WriteLine("New entry prototype: " + newEntry);
}
@ -2562,6 +2555,47 @@ namespace SourceGen {
}
}
public void GenerateLabels() {
GenerateLabels dlg = new GenerateLabels(mMainWin);
if (dlg.ShowDialog() == false) {
return;
}
string ext;
string filter;
switch (dlg.Format) {
case LabelFileGenerator.LabelFmt.VICE:
ext = ".lbl";
filter = "VICE labels (*.lbl)|*.lbl";
break;
default:
Debug.Assert(false, "bad format");
return;
}
SaveFileDialog fileDlg = new SaveFileDialog() {
Filter = filter,
FilterIndex = 1,
ValidateNames = true,
AddExtension = true, // doesn't add extension if non-ext file exists
FileName = "labels" + ext
};
if (fileDlg.ShowDialog() != true) {
return;
}
string pathName = Path.GetFullPath(fileDlg.FileName);
try {
using (StreamWriter writer = new StreamWriter(pathName, false)) {
LabelFileGenerator gen = new LabelFileGenerator(mProject,
dlg.Format, dlg.IncludeAutoLabels);
gen.Generate(writer);
}
} catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message, "Failed", MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
public void Find() {
FindBox dlg = new FindBox(mMainWin, mFindString);
if (dlg.ShowDialog() == true) {
@ -3913,7 +3947,8 @@ namespace SourceGen {
return;
}
int lineIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
LineListGen.Line.Type type = CodeLineList[lineIndex].LineType;
LineListGen.Line line = CodeLineList[lineIndex];
LineListGen.Line.Type type = line.LineType;
if (type != LineListGen.Line.Type.Code &&
type != LineListGen.Line.Type.Data &&
type != LineListGen.Line.Type.EquDirective &&
@ -3926,10 +3961,10 @@ namespace SourceGen {
// Find the appropriate xref set.
if (type == LineListGen.Line.Type.LocalVariableTable) {
DefSymbol defSym = CodeLineList.GetLocalVariableFromLine(CodeLineList[lineIndex]);
DefSymbol defSym = CodeLineList.GetLocalVariableFromLine(line);
xrefs = (defSym == null) ? null : defSym.Xrefs;
} else {
int offset = CodeLineList[lineIndex].FileOffset;
int offset = line.FileOffset;
if (offset < 0) {
// EQU in header
int index = LineListGen.DefSymIndexFromOffset(offset);

View File

@ -52,7 +52,7 @@ namespace SourceGen {
// ignore stuff that's in one side but not the other. However, if we're opening a
// newer file in an older program, it's worth letting the user know that some stuff
// may get lost as soon as they save the file.
public const int CONTENT_VERSION = 5;
public const int CONTENT_VERSION = 6;
// Max JSON file length.
internal const int MAX_JSON_LENGTH = 64 * 1024 * 1024;
@ -245,6 +245,8 @@ namespace SourceGen {
public int Addr { get; set; }
public int Length { get; set; }
public string PreLabel { get; set; }
public bool DisallowInward { get; set; }
public bool DisallowOutward { get; set; }
public bool IsRelative { get; set; }
public SerAddressMapEntry() {
@ -257,6 +259,8 @@ namespace SourceGen {
Addr = ent.Address;
Length = ent.Length;
PreLabel = ent.PreLabel;
DisallowInward = ent.DisallowInward;
DisallowOutward = ent.DisallowOutward;
IsRelative = ent.IsRelative;
}
}
@ -689,7 +693,8 @@ namespace SourceGen {
proj.AddrMap.Clear();
foreach (SerAddressMapEntry addr in spf.AddressMap) {
AddressMap.AddResult addResult = proj.AddrMap.AddEntry(addr.Offset,
addr.Length, addr.Addr, addr.PreLabel, addr.IsRelative);
addr.Length, addr.Addr, addr.PreLabel,
addr.DisallowInward, addr.DisallowOutward, addr.IsRelative);
if (addResult != CommonUtil.AddressMap.AddResult.Okay) {
string msg = "off=+" + addr.Offset.ToString("x6") + " len=" +
(addr.Length == CommonUtil.AddressMap.FLOATING_LEN ?

View File

@ -87,6 +87,12 @@ namespace SourceGen {
sb.Append(change.Region.PreLabel);
sb.Append("'");
}
if (change.Region.DisallowInward) {
sb.Append(" [!in]");
}
if (change.Region.DisallowOutward) {
sb.Append(" [!out]");
}
sb.Append(CRLF);

View File

@ -0,0 +1,203 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Commodore 1541 / OC-118 Disk Drive Memory Map (v1.3, Jan 18, 1995)
; https://ist.uwaterloo.ca/~schepers/MJK/ascii/1541map.txt
;
; - Commodore 1541 drive memory map
; https://sta.c64.org/cbm1541mem.html
;
; - DOS 2.6 ROM LISTINGS (v1.0, Feb 11, 2000)
; http://www.ffd2.com/fridge/docs/1541dis.html
;
; - CBM DOS ROM disassembly and memory variables for Commodore 1541 drive
; https://g3sl.github.io/c1541rom.html
*SYNOPSIS 1541 RAM locations used by the 1541 ROM
cmdCodeBuf0 @ $0000 ;Command code for buffer 0
cmdCodeBuf1 @ $0001 ;Command code for buffer 1
cmdCodeBuf2 @ $0002 ;Command code for buffer 2
cmdCodeBuf3 @ $0003 ;Command code for buffer 3
cmdCodeBuf4 @ $0004 ;Command code for buffer 4
trkBuf0 @ $0006 ;Track buffer 0
secBuf0 @ $0007 ;Sector buffer 0
trkBuf1 @ $0008 ;Track buffer 1
secBuf1 @ $0009 ;Sector buffer 1
trkBuf2 @ $000a ;Track buffer 2
secBuf2 @ $000b ;Sector buffer 2
trkBuf3 @ $000c ;Track buffer 3
secBuf3 @ $000d ;Sector buffer 3
trkBuf4 @ $000e ;Track buffer 4
secBuf4 @ $000f ;Sector buffer 4
d0DiskID @ $0012 ;Disk ID, drive 0
d1DiskID @ $0014 ;Disk ID, drive 1
hbID @ $0016 ;Header block: ID
hbTrk @ $0018 ;Header block: Track
hbSec @ $0019 ;Header block: Sector
hbParity @ $001a ;Header block: Parity
diskChgD0 @ $001c ;Flag for disk change, drive 0 01
diskChgD1 @ $001d ;Flag for disk change, drive 1 01
writeProtD0 @ $001e ;Flag for write protect sense, drive 0 01
writeProtD1 @ $001f ;Flag for write protect sense, drive 1
d0Status @ $0020 ;Drive 0 status (disk and step motor)
d1Status @ $0021 ;Drive 1 status (disk and step motor)
d0CurTrk @ $0022 ;Current track for drive 0
driveType @ $0023 ;Flag for 1541 (0), 1540 (not 0)
gcrWorkArea @ $0024 ;Scratch pad of GCR conversion
ptrTmpMem @ $002e 2 ;Pointer for temporary storage
bufPtrCtrl @ $0030 2 ;Buffer pointer for disk controller
ptrCurTrk @ $0032 2 ;Pointer: active track
ptrCurSec @ $0033 2 ;Pointer: active sector
ptrLastConvByte @ $0034 2 ;Pointer to last converted byte
convByteCnt @ $0036 ;Byte counter for GCR/BIN conversion
byteStartBlk @ $0038 ;Constant 7, ID mark for start of data block
byteStartBlkHdr @ $0039 ;Constant 8, ID mark for start of block header
dataBufParity @ $003a ;Parity for data buffer
motorFlag @ $003d ;Motor flag
curDrive @ $003e ;Active drive (FF, if not active)
ctrlBufNum @ $003f ;Buffer number for disk controller
gcrConvByteCnt @ $0040 ;Byte counter for GCR conversion
workCnt @ $0041 ;Number of next work in queue (0 - 5)
destTrk @ $0042 ;Destination track (to move R/W head to)
secPerTrk @ $0043 ;Number of sectors per track for formatting
tmpArea @ $0044 ;Temp. work area; Scratch pad
tmpArea2 @ $0045 ;Work code temp. storage
byteBlkID @ $0047 ;Data block ID char, default 07.
headMoveCnt @ $0048 ;Counter for head movement
headStepCnt @ $004a ;Step counter for head transport
lastReadSec @ $004c ;Last read sector
nextSec @ $004d ;Next sector
gcrConvBufPtr @ $004e 2 ;Pointer to buffer for GCR->BIN conversion
gcrFormatFlag @ $0050 ;Flag for GCR format (0=BIN, 1=GCR)
curFormatTrk @ $0051 ;Current track number for formatting FF
gcrConvBytesBuf @ $0052 4 ;Storage for 4 BIN bytes for GCR coding
gcrConvStore @ $0056 5 ;Storage for 5 GCR bytes
headAccSteps @ $005e ;Number of steps for head motor accel/decl
headAccFactor @ $005f ;accelerating/decl. factor 04
headMoveVec @ $0062 2 ;Pointer to routine for head movement $fa05
headStepsMin @ $0064 ;Minimum number of steps C8
nmiVec @ $0065 2 ;Pointer to start of NMI routine ($eb2e)
nmiInProc @ $0067 ;Flag: NMI in process
diskInitInProc @ $0068 ;Flag for disk initialisation
secDivStepSize @ $0069 ;Step size for sector division $0a
numReadAttempts @ $006a ;Number of read attempts 5
ptrStartJumpTbl @ $006b 2 ;Pointer: Start of Jump table for U commands $ffea
ptrStartBitmap @ $006d 2 ;Pointer: Start of bitmap $0400
ptrMBcmds @ $006f 2 ;Pointer to address for M & B commands
tmpArea3 @ $0071 4 ;Temp work area
indPtrVar @ $0075 2 ;Indirect pointer variable ($0100)
listenAddr @ $0077 ;Listener address (Device number + $20)
talkAddr @ $0078 ;Talker address (Device number + $40)
curListenFlag @ $0079 ;Flag: Active listener
curTalkFlag @ $007a ;Flag: Active talker
atnRecevFlag @ $007c ;Flag for ATN from serial bus receiving
atnActiveFlag @ $007d ;Flag for ATN on serial bus active
lastPrg @ $007e ;Last handled program
driveNum @ $007f ;Drive number (on 1541 always 00)
curTrk @ $0080 ;Current Track number
curSec @ $0081 ;Current Sector number
chnlNum @ $0082 ;Channel number (Logical index)
scndAddr @ $0083 ;Secondary address
scndAddrOrig @ $0084 ;Original Secondary address $6f
curDataByte @ $0085 ;Current Data byte $3f
tmpArea4 @ $0086 9 ;Temp Results area
curBufPtr @ $0094 2 ;Current dir buffer pointer
ptrNxtByteBuf0 @ $0099 2 ;Pointer: Next byte in buffer 0 $0300
ptrNxtByteBuf1 @ $009b 2 ;Pointer: Next byte in buffer 1 $0400
ptrNxtByteBuf2 @ $009d 2 ;Pointer: Next byte in buffer 2 $0500
ptrNxtByteBuf3 @ $009f 2 ;Pointer: Next byte in buffer 3 $0600
ptrNxtByteBuf4 @ $00a1 2 ;Pointer: Next byte in buffer 4 $0700
ptrNxtByteCmdBf @ $00a3 2 ;Pointer: Next byte in command buffer $0200
prtNxtByteErrBf @ $00a5 2 ;Pointer: Next byte in error message buffer $02d6
tblBufChnls @ $00a7 ;Table: buffer channel assignments
tblLoBufRecNum @ $00b5 6 ;Table: lo bytes of record numbers for each buffer
tblHiBufRecNum @ $00bb 6 ;Table: hi bytes of record numbers for each buffer
relWritePtr @ $00c1 ;Write pointer for REL file
relRecLen @ $00c7 ;Table: Record length for REL file
tblSideSecs @ $00cd 6 ;Table: Side sectors
relInRecPtr @ $00d4 ;Pointer in record for REL file
sideSecNum @ $00d5 ;Side sector number
blkPrtSideSec @ $00d6 ;Pointer to data block in side sector
relToRecPtr2 @ $00d7 ;Pointer to record in REL file
dirSectors @ $00d8 ;Directory sectors
indexDir @ $00dd ;Index: Directory
defaultDrive @ $00e2 ;Default disk drive 00
chnlStatus @ $00f2 ;Channel status
flatEOI @ $00f8 ;Flag for EOI
currWorkBufNum @ $00f9 ;Current work (Buffer number)
lruTable @ $00fa 5 ;Least recently used table
d0ReadyFlag @ $00ff ;Flag: FF = drive 0 not ready (No disk), 00 = ready
d1ReadyFlag @ $0100 ;Flag: FF = drive 1 not ready (No disk), 00 = ready
d0FormatMarker @ $0101 ;DOS version from t18 for drive 0
d1FormatMarker @ $0102 ;DOS version from t18 for drive 1
cmdStrBuf @ $0200 42 ;Buffer for command string
cmdCode @ $022a ;Command code
chnl1Index @ $022b ;Logical index, channel 0
chnl2Index @ $022c ;Logical index, channel 1
chnl3Index @ $022d ;Logical index, channel 2
chnlsLastRWbyte @ $022e 6 ;Last read/written byte for each channel
chnlsLastChar @ $0244 6 ;Pointer: Last char on channel
curFileType @ $024a ;Type of active file
strLen @ $024b ;String length
tmpChnlNum @ $024c ;Temp. channel number (secondary address)
curWork @ $024d ;Current work with drive number
workAreaForSec @ $024e ;Work area to find the best sector
bufAlloc @ $024f ;Buffer allocated
d0BamChangFlag @ $0251 ;Flag: BAM changed, drive 0
d1BamChangFlag @ $0252 ;Flag: BAM changed, drive 1
dirEntryFndFlag @ $0253 ;Flag for directory entry found
dirOutputFlag @ $0254 ;Flag for directory output
cmdWaitFlag @ $0255 ;Flag: Waiting for command
lastUsedBuf @ $0257 ;Last used buffer
recordLen @ $0258 ;Record length
sideSecTrk @ $0259 ;Track of side sector
sideSecSec @ $025a ;Sector of side sector
lastWorkBufs @ $025b 5 ;Last work (buffers)
dirSecBufs @ $0260 5 ;Directory sector (buffers)
fileDirIdxBufs @ $0266 5 ;File's index in directory (buffers)
ledFlashCnt @ $026c ;Counter for LED flash
ledFlashMask @ $026d ;Error LED mask for flashing
driveForLastPrg @ $026e ;Drive for last program
secForLastPrg @ $026f ;sector for last program
writeLindx @ $0270 ;Write LINDX
readLindx @ $0271 ;Read LINDX
inputLineLen @ $0274 ;Length of input line
charToProcess @ $0275 ;Char to interpret
endOfCmdBufFN @ $0276 ;Index: End of filename in command buffer
numOfFNs @ $0278 ;Number of filenames
tblPtrFNs @ $027a 6 ;Pointer table: filenames
fileTrk @ $0280 ;Track of a file
fileSec @ $0285 ;Sector of a file
patternFlag @ $028a ;Flag: wild cards
fileStrmImage @ $028b ;File stream image
numDriveSrches @ $028c ;Number of drives to look for
driveSearchFlag @ $028d ;Flag: Looking for drive
driveWthLastErr @ $028e ;drive with last write/open error, used as default drive
foundInDirFlag @ $028f ;Flag: Found in directory
dirSec @ $0290 ;Directory sector
sec1stAvailFile @ $0291 ;Sector for first available file
idx1stAvailFile @ $0292 ;Index (in directory) for first available file
zeroIfLastBlk @ $0293 ;=0 if last block
curBufIndex @ $0294 ;Current buffer-index
filesCnt @ $0295 ;Counter: Files
typeFlag @ $0296 ;Flag: Name matching wild cards
fileMode @ $0297 ;Active file mode (R or W)
jobReturnFlag @ $0298 ;Flag: job return
recoveryPtr @ $0299 2 ;Pointer for recovery
totalTrkOffset @ $029a ;Total tracks offset
lastBamUpdtPtr @ $029b 2 ;Pointer: BAM last update
bamImgTrackNum @ $029d 2 ;Track # of BAM image (drive 0/1)
bamImg @ $02a1 16 ;BAM image
dirOutputBuf @ $02b1 36 ;Buffer for directory output
errMsgBuf @ $02d5 36 ;Buffer for error message
noWriteBamFlag @ $02f9 ;Flag: Don't write BAM
numFreeBlksLo @ $02fa 2 ;Number of free blocks, lo for drives 0 and 1
numFreeBlksHi @ $02fc 2 ;Number of free blocks, hi for drives 0 and 1
stepperPhase @ $02fe 2 ;Current phase of head stepper motor
buffer0 @ $0300 256 ;Buffer 0
buffer1 @ $0400 256 ;Buffer 1
buffer2 @ $0500 256 ;Buffer 2
buffer3 @ $0600 256 ;Buffer 3
buffer4 @ $0700 256 ;Buffer 4

View File

@ -0,0 +1,309 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Commodore 1541 / OC-118 Disk Drive Memory Map (v1.3, Jan 18, 1995)
; https://ist.uwaterloo.ca/~schepers/MJK/ascii/1541map.txt
;
; - Commodore 1541 drive memory map
; https://sta.c64.org/cbm1541mem.html
;
; - DOS 2.6 ROM LISTINGS (v1.0, Feb 11, 2000)
; http://www.ffd2.com/fridge/docs/1541dis.html
;
; - CBM DOS ROM disassembly and memory variables for Commodore 1541 drive
; https://g3sl.github.io/c1541rom.html
*SYNOPSIS 1541 ROM and memory-mapped I/O labels
via1PortB @ $1800 ;VIA1: port B serial bus
via1PortA @ $1801 ;VIA1: port A. Read to ack interrupt from ATN IN going high
via1PortBddr @ $1802 ;VIA1: port B data direction reg
via1PortAddr @ $1803 ;VIA1: port A data direction reg
via1Timer @ $1805 ;VIA1: Timer
via2PortB @ $1c00 ;VIA2: PB, control port B
via2PortA @ $1c01 ;VIA2: PA, port A (data to and from read/write head)
via2PortBddr @ $1c02 ;VIA2: CB, data direction port B
via2PortAddr @ $1c03 ;VIA2: A, data direction port A
timerLo @ $1c04 ;Timer low byte
timerHi @ $1c05 ;Timer high byte, write to start timer
timerStartValLo @ $1c06 ;Timer starting value low byte
timerStartValHi @ $1c07 ;Timer starting value high byte
timerCtrl @ $1c0b ;Timer control register
auxCtrl @ $1c0c ;Auxiliary control register
interruptStatus @ $1c0d ;Interrupt status register
interruptCtrl @ $1c0e ;Interrupt control register
ledOnCurrDrive @ $c100 ;Turn LED on for current drive
ledOn @ $c118 ;Turn LED on
clrErrors @ $c123 ;Clear error flags
prepLedFlash @ $c12c ;Prepare for LED flash after error
interpretCmd @ $c146 ;Interpret command from computer
prepError @ $c194 ;Prepare error msg after executing command
clrInputBuf @ $c1bd ;Erase input buffer
outErrorMsg @ $c1c8 ;Output error msg (track and sector 0)
chkInputLine @ $c1d1 ;Check input line
srchInputBuf @ $c268 ;Search character in input buffer
chkLineLen @ $c2b3 ;Check line length
clrInputFlags @ $c2dc ;Clear flags for command input
prsrvDriveNum @ $c312 ;Preserve drive number
searchDriveNum @ $c33c ;Search for drive number
getDriveNum @ $c368 ;Get drive number
reserveDriveNum @ $c38f ;Reverse drive number
chkFileType @ $c398 ;Check given file type
chkDriveNum @ $c3bd ;Check given drive number
verifyDriveNum @ $c3ca ;Verify drive number
searchDir @ $c44f ;Search for file in directory
testInitDrive @ $c63d ;Test and initalise drive
fnInDirBuf @ $c66e ;Name of file in directory buffer
putFnInWorkBuf @ $c688 ;Copy filename to work buffer
searchEndOfName @ $c6a6 ;Search for end of name in command
clrDirOutputBuf @ $c7ac ;Clear Directory Output Buffer
hdrWithDiskName @ $c7b7 ;Create header with disk name
printBlocksFree @ $c806 ;Print 'blocks free.'
deleteCmd @ $c823 ;Perform S - Scratch command
deleteFile @ $c87d ;Erase file
deleteEntry @ $c8b6 ;Erase dir entry
formatCmd @ $c8c6 ;Format disk
copyCmd @ $c8f0 ;Perform C - Copy command
renameCmd @ $ca88 ;Perform R - Rename command
presentCmd @ $cacc ;Check if file present
memoryCmd @ $caf8 ;Perform M - Memory command
memReadCmd @ $cb20 ;M-R memory read
memWriteCmd @ $cb50 ;M-W memory write
userCmd @ $cb5c ;Perform U - User command
openDirAccChnl @ $cb84 ;Open direct access channel, number
blockCmd @ $cc1b ;Perform B - Block/Buffer command
parseBlkParams @ $cc6f ;Get parameters from block commands
blockFreeCmd @ $ccf5 ;B-F block free
blockAllocCmd @ $cd03 ;B-A block allocate
readBlockToBuf @ $cd36 ;Read block to buffer
getBufByte @ $cd3c ;Get byte from buffer
readBlock @ $cd42 ;Read block from disk
blkReadCmd @ $cd56 ;B-R block read
blkReadInPlace @ $cd5f ;U1, Block read without changing buffer pointer
blkWriteCmd @ $cd73 ;B-W block write
blkWriteInPlace @ $cd97 ;U2, Block write without changing buffer pointer
blkExecCmd @ $cda3 ;B-E block execute
blkPtrCmd @ $cdbd ;B-P block pointer
openChnl @ $cdd2 ;Open channel
chkBufNum @ $cdf2 ;Check buffer number and open channel
setRelFilePtr @ $ce0e ;Set pointer for REL file
div254 @ $ce6e ;Divide by 254
div120 @ $ce71 ;Divide by 120
eraseWrkMem @ $ced9 ;Erase work storage
chgBuf @ $cf8c ;Change buffer
writeInBuf @ $cf9b ;Write data in buffer
writeByteInBuf @ $cff1 ;Write data byte in buffer
initCmd @ $d005 ;Perform I - Initalise command
readBam @ $d00e ;Read BAM from disk
loadBam @ $d042 ;Load BAM
calcFree @ $d075 ;Calculate blocks free
readBlock @ $d0c3 ;Read block
writeBlock @ $d0c7 ;Write block
openReadChnl @ $d0eb ;Open channel for reading
openWriteChnl @ $d107 ;Open channel for writing
checkForRel @ $d125 ;Check for file type REL
getBufChnlNums @ $d12f ;Get buffer and channel numbers
getByteFromBuf @ $d137 ;Get a byte from buffer
getByteNextBlk @ $d156 ;Get byte and read next block
writeToBufBlk @ $d19d ;Write byte in buffer and block
incBufPtrs @ $d1c6 ;Increment buffer pointer
getDriveNum @ $d1d3 ;Get drive number
findWChnlBuf @ $d1df ;Find write channel and buffer
findRChnlBuf @ $d1e2 ;Find read channel and buffer
closeChnl @ $d227 ;Close channel
freeBuf @ $d25a ;Free buffer
findBuf @ $d28e ;Find buffer
closeAllChnls @ $d307 ;Close all channels
closeAllDChnls @ $d313 ;Close all channels of other drives
findChnlAlloc @ $d37f ;Find channel and allocate
getByteOutput @ $d39b ;Get byte for output
readNextBlk @ $d44d ;Read next block
readBlk @ $d460 ;Read block
writeBlk @ $d464 ;Write block
allocBufandRead @ $d475 ;Allocate buffer and read block
allocBlk @ $d486 ;Allocate new block
writeDirBlk @ $d48d ;Write dir block
setBufPtr @ $d4c8 ;Set buffer pointer
closeIntChnl @ $d4da ;Close internal channel
setBufPtr2 @ $d4e8 ;Set buffer pointer
getByteFromBuf2 @ $d4f6 ;Get byte from buffer
chkTSnums @ $d506 ;Check track and sector numbers
getTSForJob @ $d552 ;Get track and sector numbers for current job
chkValidTSNums @ $d55f ;Check for vaild track and sector numbers
errorDosMismtch @ $d572 ;DOS mismatch error
readBlk2 @ $d586 ;Read block
writeBlk2 @ $d58a ;Write block
verifyExe @ $d599 ;Verify execution
verifyExeNoWait @ $d5a6 ;Verify execution (without wait)
attempts @ $d5c6 ;Additional attempts for read errors
moveHeadHalfTrk @ $d676 ;Move head by half a track
moveHeadOneTrk @ $d693 ;Move head one track in or out
multiAttemptCmd @ $d6a6 ;Attempt command execution multiple times
parmsToCtrl @ $d6d0 ;Transmit param to disk controller
enterFileInDir @ $d6e4 ;Enter file in dir
open @ $d7b4 ;OPEN command, secondary addr 15
checkAstr @ $d7c7 ;Check '*' Last file
checkDolr @ $d7f3 ;Check '$' Directory
checkHash @ $d815 ;Check '#' Channel
openOverwrite @ $d8f5 ;Open a file with overwriting (@)
openRead @ $d9a0 ;Open file for reading
openWrite @ $d9e3 ;Open file for writing
chkTypetrl @ $da09 ;Check file type and control mode
prepAppend @ $da2a ;Preparation for append
openDir @ $da55 ;Open directory
closeRoutine @ $dac0 ;Close routine
closeFile @ $db02 ;Close file
writeLastBlk @ $db62 ;Write last block
dirEntry @ $dba5 ;Directory entry
readBlkAllocBuf @ $dc46 ;Read block, allocate buffer
resetPtr @ $dcb6 ;Reset pointer
makeNewBlk @ $dcda ;Construct a new block
writeSideSecBlk @ $dd8d ;Write byte in side-sector block
verifyWriteCmd @ $ddab ;Verify command code for writing
writeRelBlk @ $ddf1 ;Write a block of a REL file
writeForNextTrk @ $ddfd ;Write bytes for following track
getTSnums @ $de0c ;Get following track and sector numbers
folTrkLastBlk @ $de19 ;Following track for last block
zeroBufPtr @ $de2b ;buffer pointer to zero
getTSnums2 @ $de3b ;Get track and sector
getTSfromBuf @ $de95 ;Get following track and sector from buffer
copyBuf @ $dea5 ;Copy buffer contents
eraseBuf @ $dec1 ;Erase buffer Y
getSideSecNum @ $ded2 ;Get side-sector number
setBufPtrToSS @ $dedc ;Set buffer pointer to side-sector
getSSandBufPtr @ $def8 ;Get side sector and buffer pointer
readSS @ $df1b ;Read side-sector
writeSS @ $df21 ;Write side-sector
setBufInSS @ $df45 ;Set buffer pointer in side-sector
blocksInRelFile @ $df4c ;Calculate number of blocks in a REL file
verifySSinBuf @ $df66 ;Verify side-sector in buffer
getBufNum @ $df93 ;Get buffer number
nextRecInRel @ $dfd0 ;Get next record in REL file
writeBlkGetNext @ $e03c ;Write block and read next block
writeByteInRec @ $e07c ;Write a byte in a record
writeByteInRel @ $e0ab ;Write byte in REL file
zeroFillRec @ $e0f3 ;Fill record with 0s
writeBufNumTbl @ $e105 ;Write buffer number in table
getByteFromRel @ $e120 ;Get byte from REL file
getLastSS @ $e1cb ;Get last side-sector
positionCmd @ $e207 ;Perform P - Position command
blksToRecords @ $e2e2 ;Divide data blocks into records
prtToNextRec @ $e304 ;Set pointer to next record
expandSS @ $e31c ;Expand side-sector
writeSSallocNxt @ $e44e ;Write side-sector and allocate new
prepErrNumMsg @ $e60a ;Prepare error number and message
errorMsgToBuf @ $e645 ;Print error message into error buffer
talk3 @ $e680 ;TALK
listen @ $e688 ;LISTEN
binToPetscii @ $e69b ;Convert BIN to petscii (error message buffer)
bcdToPetscii @ $e6ab ;Convert BCD to petscii (error message buffer)
writeOK @ $e6bc ;Write OK in buffer
trk0ErrorToBuf @ $e6c1 ;Print error on track 00,00 to error buffer
curTrkErrToBuf @ $e6c7 ;Print error on current track to error buffer
errMsgToBuf @ $e706 ;Write error message string to buffer
tokenIntoBuf @ $e754 ;Get character and in buffer
getErrMsgChar @ $e767 ;Get a char of the error message
incPtr @ $e775 ;Increment pointer
usrExecCmd @ $e7a3 ;Perform & - USR file execute command
genChecksum @ $e84b ;Generate checksum
serialIrq @ $e853 ;IRQ routine for serial bus
serialService @ $e85b ;Service the serial bus
serialSend @ $e909 ;Send data
serialDataOutLo @ $e99c ;DATA OUT lo
serialDataOutHi @ $e9a5 ;DATA OUT hi
serialClkOutHi @ $e9ae ;CLOCK OUT hi
serialClkOutLo @ $e9b7 ;CLOCK OUT lo
readIEEE @ $e9c0 ;Read IEEE port
getByteFromBus @ $e9c9 ;Get data byte from bus
getByteWithEOI @ $e9f2 ;Accept byte with EOI
acceptData @ $ea2e ;Accept data from serial bus
testATN @ $ea59 ;Test for ATN
ledFlash @ $ea6e ;Flash LED for hardware defects, self-test
reset @ $eaa0 ;Power-up RESET routine
wait @ $ebff ;Wait loop
loadDir @ $ec9e ;Load dir
transmitDirLine @ $ed59 ;Transmit dir line
getByteFromBuf3 @ $ed67 ;Get byte from buffer
validateCmd @ $ed84 ;Perform V - Validate command
bamAlloc @ $ede5 ;Allocate file blocks in BAM
formatCmd2 @ $ee0d ;Perform N - New (Format) command
createBAM @ $eeb7 ;Create BAM
writeBAM @ $eef4 ;Write BAM if needed
setBAMptr @ $ef3a ;Set buffer pointer for BAM
getDirBlksFree @ $ef4d ;Get number of free blocks for dir
markBlkFree @ $ef5c ;Mark block as free
markBAMchanges @ $ef88 ;Set flag for BAM changed
markBlkAlloc @ $ef90 ;Mark block as allocated
delBAMsecBit @ $efcf ;Erase bit for sector in BAM entry
updateBAM @ $eff1 ;Write BAM after change
delBAMbuf @ $f005 ;Erase BAM buffer
clearBAM @ $f0d1 ;Crear BAM
getBAMbufNum @ $f10f ;Get buffer number for BAM
bamBufNum @ $f119 ;Buffer number for BAM
findFreeBlkAloc @ $f11e ;Find and allocate free block
findFreeSecAloc @ $f1a9 ;Find free sector and allocate
findFreeSectors @ $f1fa ;Find free sectors in current track
verFreeBAMblks @ $f220 ;Verify number of free blocks in BAM
numSecsPerTrk @ $f24b ;Establish number of sectors per track
initCtrl @ $f259 ;Initialise disk controller
irqCtrl @ $f2b0 ;IRQ routine for disk controller
headTransport @ $f2f9 ;Head transport
execInBuf @ $f36e ;Execute program in buffer
bump @ $f37c ;Bump, find track 1 (head at stop)
initPtrInBuf @ $f393 ;Initialise pointer in buffer
readBlkHdr @ $f3b1 ;Read block header, verify ID
prsrvBlkHdr @ $f410 ;Preserve block header
okInQueue @ $f418 ;Work Return value $01 (OK) into queue
error0bInQueue @ $f41b ;Work Return value $0b (READ ERROR) into queue
error09InQueue @ $f41e ;Work Return value $09 (READ ERROR) into queue
optimizeJob @ $f423 ;Job optimisation
readSec @ $f4d1 ;Read sector
findBlkStart @ $f50a ;Find start of data block
readBlkHdr2 @ $f510 ;Read block header
waitSync @ $f556 ;Wait for SYNC
writeBlk3 @ $f575 ;Write data block to disk
calcBufParity @ $f5e9 ;Calculate parity for data buffer
gcrToBin @ $f5f2 ;Convert buffer of GCR data into binary
findSec @ $f6ca ;Command code for find sector
bytesToGcrBytes @ $f6d0 ;Convert 4 binary bytes to 5 GCR bytes
gcrTable @ $f77f 16 ;GCR (5-bit) nybble table
gcrBytesToBytes @ $f7e6 ;Convert 5 GCR bytes to 4 binary bytes
tblGCRToBinHi @ $f8a0 64 ;Conversion table GCR to binary - high nybble
tblGCRToBinLo @ $f8c0 64 ;Conversion table GCR to binary - low nybble
decod69GcrBytes @ $f8e0 ;Decode 69 GCR bytes
blkHdrToGcr @ $f934 ;Convert block header to GCR code
errEntry @ $f969 ;Error entry disk controller
motorOn @ $f97e ;Turn drive motor on
motorOff @ $f98f ;Turn drive motor off
jobLoop @ $f99c ;Job loop disk controller
moveHeadNextTrk @ $fa05 ;Move head to next track
calNumSteps @ $fa1c ;Calculate number of head steps
nudgeStepper @ $fa3b ;Move stepper motor short distance
loadHead @ $fa4e ;Load head
prepFastHeadMov @ $fa7b ;Prepare fast head movement
fastHeadMov @ $fa97 ;Fast head movement
prepSlowHeadMov @ $faa5 ;Prepare slow head movement
formatRoutine @ $fac7 ;Formatting
writeSyncs @ $fda3 ;Write SYNC 10240 times, erase track
writeByteFill @ $fdc3 ;Read/write ($621/$622) times
formatErrRetry @ $fdd3 ;Attempt counter for formatting
cpyOvflwDataBuf @ $fdf5 ;Copy data from overflow buffer
switchToRead @ $fe00 ;Switch to reading
write55Fill @ $fe0e ;Write $55 10240 times
buf0HdrToGcr @ $fe30 ;Convert header in buffer 0 to GCR code
irdMainSystem @ $fe67 ;Interrupt routine
jmpToVNMI @ $fee7 ;From UI command $eb22, to reset
diagPatch @ $feea ;Patch for diagnostic routine from $ea7a
serialBusDelay @ $fef3 ;Delay loop for serial bus in 1541 mode, from $e97d
serialOutPatch @ $fefb ;Patch for data output to serial bus, from $e980
switch1540_1541 @ $ff01 2 ;U9 vector, switch 1540/1541
resetPatch @ $ff10 ;Patch for reset routine, from $eaa4
listenPatch @ $ff20 ;Patch for listen to serial bus, from $e9dc
vecFormat @ $ffe6 2 ;vector for format
vecOff @ $ffe8 2 ;vector for $f98f
vecUblkkrd @ $ffea 2 ;vector for $cd5f
vecUblkwt @ $ffec 2 ;vector for $cd97
vecNMI @ $fffa 2 ;vector to $ff01
vecInit @ $fffc 2 ;vector to $eaa0
vecIrq @ $fffe 2 ;vector to $fe67

View File

@ -0,0 +1,88 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Project 64, 64MAP10.TXT, June 1996, etext #41
; http://unusedino.de/ec64/technical/project64/memory_maps.html
;
; - "Mapping the Commodore 64", by Sheldon Leemon
; Compute! Publications Inc. (1984), ISBN 0-942386-23-X
; https://archive.org/details/Compute_s_Mapping_the_Commodore_64
*SYNOPSIS RAM locations used by BASIC
ADRAY1 @ $0003 2 ;Vector: Convert FAC to Integer in (A/Y) ($b1aa)
ADRAY2 @ $0005 2 ;Vector: Convert int in (A/Y) to float in (FAC) ($b391)
CHARAC @ $0007 ;Search Character/Temporary Integer during INT
ENDCHR @ $0008 ;Flag: Scan for Quote at end of String
INTEGR @ $0007 ;Temporary Integer during OR/AND
TRMPOS @ $0009 ;Screen Column for last TAB
VERCK @ $000a ;Flag: 0 = Load, 1 = Verify
COUNT @ $000b ;Input Buffer Pointer/Number of Subscripts
DIMFLG @ $000c ;Flag: Default Array dimension
VALTYP @ $000d ;Data type Flag: $00 = Numeric, $FF = String
INTFLG @ $000e ;Data type Flag: $00 = Floating point, $80 = Integer
GARBFL @ $000f ;Flag: DATA scan/List Quote/Garbage collection
SUBFLG @ $0010 ;Flag: Subscript reference/User Function call
INPFLG @ $0011 ;Input Flag: $00 = INPUT, $40 = GET, $98 = READ
TANSGN @ $0012 ;Flag: TAN sign/Comparative result
CHANNL @ $0013 ;File number of current Input Device
LINNUM @ $0014 2 ;Temporary: Integer value
TEMPPT @ $0016 ;Pointer: Temporary String Stack
LASTPT @ $0017 2 ;Last temporary String Address
TEMPST @ $0019 9 ;Stack for temporary Strings
INDEX1 @ $0022 2 ;First Utility Pointer
INDEX2 @ $0024 2 ;Second Utility Pointer
RESHO @ $0026 5 ;Floating point product of Multiply and Divide
TXTTAB @ $002b 2 ;Pointer: Start of BASIC Text Area ($0801)
VARTAB @ $002d 2 ;Pointer: Start of BASIC Variables
ARYTAB @ $002f 2 ;Pointer: Start of BASIC Arrays
STREND @ $0031 2 ;Pointer: End of BASIC Arrays + 1
FRETOP @ $0033 2 ;Pointer: Bottom of String space
FRESPC @ $0035 2 ;Utility String Pointer
MEMSIZ @ $0037 2 ;Pointer: Highest Address available to BASIC ($a000)
CURLIN @ $0039 2 ;Current BASIC Line number
OLDLIN @ $003b 2 ;Previous BASIC Line number
OLDTXT @ $003d 2 ;Pointer: BASIC Statement for CONT
DATLIN @ $003f 2 ;Current DATA Line number
DATPTR @ $0041 2 ;Pointer: Used by READ - current DATA Item Address
INPPTR @ $0043 2 ;Pointer: Temporary storage of Pointer during INPUT Routine
VARNAM @ $0045 2 ;Name of Variable being sought in Variable Table
VARPNT @ $0047 2 ;Pointer: to value of (VARNAM) if Int, to descriptor if Str
FORPNT @ $0049 2 ;Pointer: Index Variable for FOR/NEXT loop
VARTXT @ $004b 2 ;Temporary storage for TXTPTR during READ, INPUT and GET
OPMASK @ $004d ;Mask used during FRMEVL
TEMPF3 @ $004e 2 ;Temporary storage for FLPT value
FOUR6 @ $0053 ;Length of String Variable during Garbage collection
JMPER @ $0054 3 ;jmp used in Function Evaluation
TEMPF1 @ $0057 10 ;Temporary storage for FLPT value
TEMPF2 @ $005c ;Temporary storage for FLPT value
FACEXP @ $0061 ;FAC Exponent
FACHO @ $0062 4 ;FAC Mantissa
FACSGN @ $0066 ;FAC Sign
SGNFLG @ $0067 ;Pointer: Series Evaluation Constant
BITS @ $0068 ;Bit Overflow Area during normalisation Routine
ARGEXP @ $0069 ;AFAC Exponent
ARGHO @ $006a 4 ;AFAC Mantissa
ARGSGN @ $006e ;AFAC Sign
ARISGN @ $006f ;Sign of result of Arithmetic Evaluation
FACOV @ $0070 ;FAC low-order rounding
FBUFPT @ $0071 2 ;Pointer: Used during CRUNCH/ASCII conversion
CHRGET @ $0073 ;Subroutine: Get next Byte of BASIC Text
CHRGOT @ $0079 ;Entry to Get same Byte again
TXTPTR @ $007a 2 ;Pointer: Current Byte of BASIC Text
RNDX @ $008b 5 ;Floating RND Function Seed Value
BSTACK @ $013f ;BASIC Stack Area
BUF @ $0200 ;BASIC Input Buffer (Input Line from Screen)
IERROR @ $0300 2 ;Vector: BASIC Error ($e38b)
IMAIN @ $0302 2 ;Vector: BASIC Input Line ($a483)
ICRNCH @ $0304 2 ;Vector: BASIC Tokenise ($a57c)
IQPLOP @ $0306 2 ;Vector: BASIC LIST ($a71a)
IGONE @ $0308 2 ;Vector: BASIC Character ($a7e4)
IEVAL @ $030a 2 ;Vector: BASIC Token ($ae86)
SAREG @ $030c ;Storage for 6510 Accumulator during SYS
SXREG @ $030d ;Storage for 6510 X-Register during SYS
SYREG @ $030e ;Storage for 6510 Y-Register during SYS
SPREG @ $030f ;Storage for 6510 Status Register during SYS
USRPOK @ $0310 ;USR Function JMP Instruction ($4c)
USRADD @ $0311 ;USR Address ($LB,$MB)

View File

@ -0,0 +1,183 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Project 64, 64MAP10.TXT, June 1996, etext #41
; http://unusedino.de/ec64/technical/project64/memory_maps.html
;
; - PageTable's C64 BASIC & KERNAL ROM Disassembly
; https://www.pagetable.com/c64ref/c64disasm/
;
; - "Mapping the Commodore 64", by Sheldon Leemon
; Compute! Publications Inc. (1984), ISBN 0-942386-23-X
; https://archive.org/details/Compute_s_Mapping_the_Commodore_64
*SYNOPSIS BASIC ROM ($a000-$bfff) labels (functions and vectors)
coldStartVec @ $a000 2 ;Cold Start Vector
warmStartVec @ $a002 2 ;Warm Start Vector
fndfor @ $a38a ;Find FOR/GOSUB Entry on Stack
bltu @ $a3b8 ;Open Space in Memory
getstk @ $a3fb ;Check Stack Depth
reason @ $a408 ;Check Memory Overlap
omerr @ $a435 ;Output ?OUT OF MEMORY Error
error @ $a437 ;Error Routine
errfin @ $a469 ;Break Entry
ready @ $a474 ;Restart BASIC
main @ $a480 ;Input & Identify BASIC Line
main1 @ $a49c ;Get Line Number & Tokenise Text
inslin @ $a4a2 ;Insert BASIC Text
linkprg @ $a533 ;Rechain Lines
inlin @ $a560 ;Input Line Into Buffer
crunch @ $a579 ;Tokenise Input Buffer
fndlin @ $a613 ;Search for Line Number
scrtch @ $a642 ;Perform new
clear @ $a65e ;Perform clr
stxpt @ $a68e ;Reset TXTPTR
list @ $a69c ;Perform list
qplop @ $a717 ;Handle LIST Character
for @ $a742 ;Perform for
newstt @ $a7ae ;BASIC Warm Start
ckeol @ $a7c4 ;Check End of Program
gone @ $a7e1 ;Prepare to execute statement
gone3 @ $a7ed ;Perform BASIC Keyword
restor3 @ $a81d ;Perform restore
stop @ $a82c ;Perform stop, end, break
cont @ $a857 ;Perform cont
run @ $a871 ;Perform run
gosub @ $a883 ;Perform gosub
goto @ $a8a0 ;Perform goto
return @ $a8d2 ;Perform return
data @ $a8f8 ;Perform data
datan @ $a906 ;Search for Next Statement / Line
if @ $a928 ;Perform if
rem @ $a93b ;Perform rem
ongoto @ $a94b ;Perform on
linget @ $a96b ;Fetch linnum From BASIC
let @ $a9a5 ;Perform let
putint @ $a9c4 ;Assign Integer
ptflpt @ $a9d6 ;Assign Floating Point
putstr @ $a9d9 ;Assign String
puttim @ $a9e3 ;Assign TI$
getspt @ $aa2c ;Add Digit to FAC#1
printn @ $aa80 ;Perform print#
cmd @ $aa86 ;Perform cmd
strdon @ $aa9a ;Print String From Memory
print @ $aaa0 ;Perform print
varop @ $aab8 ;Output Variable
crdo @ $aad7 ;Output CR/LF
comprt @ $aae8 ;Handle comma, TAB(, SPC(
strout @ $ab1e ;Output String
outspc @ $ab3b ;Output Format Character
doagin @ $ab4d ;Handle Bad Data
get @ $ab7b ;Perform get
inputn @ $aba5 ;Perform input#
input @ $abbf ;Perform input
bufful @ $abea ;Read Input Buffer
qinlin @ $abf9 ;Do Input Prompt
read @ $ac06 ;Perform read
rdget @ $ac35 ;General Purpose Read Routine
next @ $ad1e ;Perform next
donext @ $ad61 ;Check Valid Loop
frmnum @ $ad8a ;Confirm Result
frmevl @ $ad9e ;Evaluate Expression in Text
eval @ $ae83 ;Evaluate Single Term
qdot @ $aead ;Continue Expression
parchk @ $aef1 ;Expression in Brackets
chkcls @ $aef7 ;Confirm Character
synerr @ $af08 ;Output ?SYNTAX Error
domin @ $af0d ;Set up NOT Function
rsvvar @ $af14 ;Identify Reserved Variable
isvar @ $af28 ;Search for Variable
tisasc @ $af48 ;Convert TI to ASCII String
isfun @ $afa7 ;Identify Function Type
strfun @ $afb1 ;Evaluate String Function
numfun @ $afd1 ;Evaluate Numeric Function
orop @ $afe6 ;Perform or, and
dorel @ $b016 ;Perform <, =, >
numrel @ $b01b ;Numeric Comparison
strrel @ $b02e ;String Comparison
dim @ $b07e ;Perform dim
ptrget @ $b08b ;Identify Variable
ordvar @ $b0e7 ;Locate Ordinary Variable
notfns @ $b11d ;Create New Variable
notevl @ $b128 ;Create Variable
aryget @ $b194 ;Allocate Array Pointer Space
facinx @ $b1aa ;FAC#1 to Integer in (AC/YR)
intidx @ $b1b2 ;Evaluate Text for Integer
ayint @ $b1bf ;FAC#1 to Positive Integer
isary @ $b1d1 ;Get Array Parameters
fndary @ $b218 ;Find Array
bserr @ $b245 ;?BAD SUBSCRIPT/?ILLEGAL QUANTITY
notfdd @ $b261 ;Create Array
inlpn2 @ $b30e ;Locate Element in Array
umult @ $b34c ;Number of Bytes in Subscript
fre @ $b37d ;Perform fre
givayf @ $b391 ;Convert Integer in (AC/YR) to Flpt
pos @ $b39e ;Perform pos
errdir @ $b3a6 ;Confirm Program Mode
getfnm @ $b3e1 ;Check Syntax of FN
fndoer @ $b3f4 ;Perform fn
strd @ $b465 ;Perform str$
strlit @ $b487 ;Set Up String
putnw1 @ $b4d5 ;Save String Descriptor
getspa @ $b4f4 ;Allocate Space for String
garbag @ $b526 ;Garbage Collection
dvars @ $b5bd ;Search for Next String
grbpas @ $b606 ;Collect a String
cat @ $b63d ;Concatenate Two Strings
movins @ $b67a ;Store String in High RAM
frestr @ $b6a3 ;Perform String Housekeeping
frefac @ $b6db ;Clean Descriptor Stack
chrd @ $b6ec ;Perform chr$
leftd @ $b700 ;Perform left$
rightd @ $b72c ;Perform right$
midd @ $b737 ;Perform mid$
pream @ $b761 ;Pull sTring Parameters
len @ $b77c ;Perform len
len1 @ $b782 ;Exit String Mode
asc @ $b78b ;Perform asc
gtbytc @ $b79b ;Evaluate Text to 1 Byte in XR
val @ $b7ad ;Perform val
strval @ $b7b5 ;Convert ASCII String to Flpt
getnum @ $b7eb ;Get parameters for POKE/WAIT
getadr @ $b7f7 ;Convert FAC#1 to Integer in LINNUM
peek @ $b80d ;Perform peek
poke @ $b824 ;Perform poke
wait @ $b82d ;Perform wait
faddh @ $b849 ;Add 0.5 to FAC#1
fsub @ $b850 ;Perform Subtraction
fadd5 @ $b862 ;Normalise Addition
fadd @ $b867 ;Perform Addition
negfac @ $b947 ;2's Complement FAC#1
overr @ $b97e ;Output ?OVERFLOW Error
mulshf @ $b983 ;Multiply by Zero Byte
log @ $b9ea ;Perform log
fmult @ $ba28 ;Perform Multiply
mulply @ $ba59 ;Multiply by a Byte
conupk @ $ba8c ;Load FAC#2 From Memory
muldiv @ $bab7 ;Test Both Accumulators
mldvex @ $bad4 ;Overflow / Underflow
mul10 @ $bae2 ;Multiply FAC#1 by 10
div10 @ $bafe ;Divide FAC#1 by 10
fdiv @ $bb07 ;Divide FAC#2 by Flpt at (AC/YR)
fdivt @ $bb0f ;Divide FAC#2 by FAC#1
movfm @ $bba2 ;Load FAC#1 From Memory
mov2f @ $bbc7 ;Store FAC#1 in Memory
movfa @ $bbfc ;Copy FAC#2 into FAC#1
movaf @ $bc0c ;Copy FAC#1 into FAC#2
round @ $bc1b ;Round FAC#1
sign @ $bc2b ;Check Sign of FAC#1
sgn @ $bc39 ;Perform sgn
abs @ $bc58 ;Perform abs
fcomp @ $bc5b ;Compare FAC#1 With Memory
qint @ $bc9b ;Convert FAC#1 to Integer
int @ $bccc ;Perform int
fin @ $bcf3 ;Convert ASCII String to a Number in FAC#1
inprt @ $bdc2 ;Output 'IN' and Line Number
fout @ $bddd ;Convert FAC#1 to ASCII String
foutim @ $be68 ;Convert TI to String
sqr @ $bf71 ;Perform sqr
fpwrt @ $bf7b ;Perform power ($)
negop @ $bfb4 ;Negate FAC#1
exp @ $bfed ;Perform exp (continued in KERNAL)

View File

@ -0,0 +1,124 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Project 64, 64MAP10.TXT, June 1996, etext #41
; http://unusedino.de/ec64/technical/project64/memory_maps.html
;
; - "Mapping the Commodore 64", by Sheldon Leemon
; Compute! Publications Inc. (1984), ISBN 0-942386-23-X
; https://archive.org/details/Compute_s_Mapping_the_Commodore_64
*SYNOPSIS Commodore 64 memory-mapped I/O addresses (and color ram)
D6510 @ $0000 ;6510 I/O Data Direction Register
R6510 @ $0001 ;ROM/IO Banking and Cassette I/O
SPOX @ $D000 ;Sprite 0 X Pos
SPOY @ $D001 ;Sprite 0 Y Pos
SP1X @ $D002 ;Sprite 1 X Pos
SP1Y @ $D003 ;Sprite 1 Y Pos
SP2X @ $D004 ;Sprite 2 X Pos
SP2Y @ $D005 ;Sprite 2 Y Pos
SP3X @ $D006 ;Sprite 3 X Pos
SP3Y @ $D007 ;Sprite 3 Y Pos
SP4X @ $D008 ;Sprite 4 X Pos
SP4Y @ $D009 ;Sprite 4 Y Pos
SP5X @ $D00A ;Sprite 5 X Pos
SP5Y @ $D00B ;Sprite 5 Y Pos
SP6X @ $D00C ;Sprite 6 X Pos
SP6Y @ $D00D ;Sprite 6 Y Pos
SP7X @ $D00E ;Sprite 7 X Pos
SP7Y @ $D00F ;Sprite 7 Y Pos
MSIGX @ $D010 ;Sprites 0-7 X Pos 9th bit
SCROLY @ $D011 ;VIC Control Register
RASTER @ $D012 ;Read Raster / Write Raster Value for Compare
LPENX @ $D013 ;Light Pen/Gun Latch X Pos (divided by 2)
LPENY @ $D014 ;Light Pen/Gun Latch Y Pos
SPENA @ $D015 ;Sprites 0-7 display Enable (1 = enable)
SCROLX @ $D016 ;VIC Control Register
YXPAND @ $D017 ;Sprites 0-7 Expand 2x Vertical
VMCSB @ $D018 ;VIC Memory Control Register
VICIRQ @ $D019 ;VIC Interrupt Flag Register
IRQMSK @ $D01A ;IRQ Mask Register (1 = Interrupt Enable)
SPBGPR @ $D01B ;Sprite to Background Display Priority
SPMC @ $D01C ;Sprites 0-7 Multi-Color Mode Select
XXPAND @ $D01D ;Sprites 0-7 Expand 2x Horizontal
SPSPCL @ $D01E ;Sprite to Sprite Collision Detect
SPBGCL @ $D01F ;Sprite to Background Collision Detect
EXTCOL @ $D020 ;Border Color
BGCOL0 @ $D021 ;Background Color 0 (screen color)
BGCOL1 @ $D022 ;Background Color 1
BGCOL2 @ $D023 ;Background Color 2
BGCOL3 @ $D024 ;Background Color 3
SPMC0 @ $D025 ;Sprite Multi-Color Register 0
SPMC1 @ $D026 ;Sprite Multi-Color Register 1
SP0CL @ $D027 ;Sprite 0 Color
SP1CL @ $D028 ;Sprite 1 Color
SP2CL @ $D029 ;Sprite 2 Color
SP3CL @ $D02A ;Sprite 3 Color
SP4CL @ $D02B ;Sprite 4 Color
SP5CL @ $D02C ;Sprite 5 Color
SP6CL @ $D02D ;Sprite 6 Color
SP7CL @ $D02E ;Sprite 7 Color
FRELO1 > $D400 ;Voice 1 Frequency - Low-Byte
FREHI1 > $D401 ;Voice 1 Frequency - High-Byte
PWLO1 > $D402 ;Voice 1 Pulse Waveform Width - Low-Byte
PWHI1 > $D403 ;Voice 1 Pulse Waveform Width - High-Nybble
VCREG1 > $D404 ;Voice 1 Control Register
ATDCY1 > $D405 ;Voice 1 Attack / Decay
SUREL1 > $D406 ;Voice 1 Sustain / Release
FRELO2 > $D407 ;Voice 2 Frequency - Low-Byte
FREHI2 > $D408 ;Voice 2 Frequency - High-Byte
PWLO2 > $D409 ;Voice 2 Pulse Waveform Width - Low-Byte
PWHI2 > $D40A ;Voice 2 Pulse Waveform Width - High-Nybble
VCREG2 > $D40B ;Voice 2 Control Register
ATDCY2 > $D40C ;Voice 2 Attack / Decay
SUREL2 > $D40D ;Voice 2 Sustain / Release
FRELO3 > $D40E ;Voice 3 Frequency - Low-Byte
FREHI3 > $D40F ;Voice 3 Frequency - High-Byte
PWLO3 > $D410 ;Voice 3 Pulse Waveform Width - Low-Byte
PWHI3 > $D411 ;Voice 3 Pulse Waveform Width - High-Nybble
VCREG3 > $D412 ;Voice 3 Control Register
ATDCY3 > $D413 ;Voice 3 Attack/Decay
SUREL3 > $D414 ;Voice 3 Sustain / Release
CUTLO > $D415 ;Filter Cutoff Frequency Low-Nybble
CUTHI > $D416 ;Filter Cutoff Frequency High-Byte
RESON > $D417 ;Filter Resonance / Voice Input
SIGVOL > $D418 ;Select Filter Mode and Volume
POTX > $D419 ;Analog/Digital Converter Game Paddle 1
POTY > $D41A ;Analog/Digital Converter Game Paddle 2
RANDOM < $D41B ;Voice 3 Oscillator output
ENV3 < $D41C ;Voice 3 Envelope output
colorRam @ $D800 1024 ;Color RAM nybbles ($d800-$dbff)
CIAPRA @ $DC00 ;CIA1 Data Port A (Keyboard, Joystick, Paddles, Light-Pen)
CIAPRB @ $DC01 ;CIA1 Data Port B (Keyboard, Joysticks, Paddles)
CIDDRA @ $DC02 ;CIA1 Data Direction Register - Port A
CIDDRB @ $DC03 ;CIA1 Data Direction Register - Port B
TIMALO @ $DC04 ;CIA1 Timer A Low-Byte
TIMAHI @ $DC05 ;CIA1 Timer A High-Byte
TIMBLO @ $DC06 ;CIA1 Timer B Low-Byte
TIMBHI @ $DC07 ;CIA1 Timer B High-Byte
TODTEN @ $DC08 ;CIA1 Time-of-Day Clock 1/10 Seconds
TODSEC @ $DC09 ;CIA1 Time-of-Day Clock Seconds
TODMIN @ $DC0A ;CIA1 Time-of-Day Clock Minutes
TODHRS @ $DC0B ;CIA1 Time-of-Day Clock Hours + AM/PM Flag (Bit 7)
CIASDR @ $DC0C ;CIA1 Synchronous Serial I/O Data Buffer
CIAICR @ $DC0D ;CIA1 CIA Interrupt Control Register
CIACRA @ $DC0E ;CIA1 CIA Control Register A
CIACRB @ $DC0F ;CIA1 CIA Control Register B
CI2PRA @ $DD00 ;CIA2 Data Port A (Serial Bus RS-232, VIC Memory Control)
CI2PRB @ $DD01 ;CIA2 Data Port B (User Port, RS-232)
C2DDRA @ $DD02 ;CIA2 Data Direction Register - Port A
C2DDRB @ $DD03 ;CIA2 Data Direction Register - Port B
TI2ALO @ $DD04 ;CIA2 Timer A Low-Byte
TI2AHI @ $DD05 ;CIA2 Timer A High-Byte
TI2BLO @ $DD06 ;CIA2 Timer B Low-Byte
TI2BHI @ $DD07 ;CIA2 Timer B High-Byte
TO2TEN @ $DD08 ;CIA2 Time-of-Day Clock 1/10 Seconds
TO2SEC @ $DD09 ;CIA2 Time-of-Day Clock Seconds
TO2MIN @ $DD0A ;CIA2 Time-of-Day Clock Minutes
TO2HRS @ $DD0B ;CIA2 Time-of-Day Clock Hours + AM/PM Flag (Bit 7)
CI2SDR @ $DD0C ;CIA2 Synchronous Serial I/O Data Buffer
CI2ICR @ $DD0D ;CIA2 CIA Interrupt Control Register
CI2CRA @ $DD0E ;CIA2 CIA Control Register A
CI2CRB @ $DD0F ;CIA2 CIA Control Register B

View File

@ -0,0 +1,139 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Project 64, 64MAP10.TXT, June 1996, etext #41
; http://unusedino.de/ec64/technical/project64/memory_maps.html
;
; - "Mapping the Commodore 64", by Sheldon Leemon
; Compute! Publications Inc. (1984), ISBN 0-942386-23-X
; https://archive.org/details/Compute_s_Mapping_the_Commodore_64
*SYNOPSIS RAM locations used by the KERNAL
STATUS @ $0090 ;Kernal I/O Status Word ST
STKEY @ $0091 ;Flag: $7f = STOP key
SVXT @ $0092 ;Timing Constant for Tape
VERCKK @ $0093 ;Flag: 0 = Load, 1 = Verify
C3PO @ $0094 ;Flag: Serial Bus - Output Character buffered
BSOUR @ $0095 ;Buffered Character for Serial Bus
SYNO @ $0096 ;Cassette Sync. number
TEMPX @ $0097 ;Temporary storage of X Register during CHRIN
TEMPY @ $0097 ;Temporary storage of Y Register during RS232 fetch
LDTND @ $0098 ;Number of Open Files/Index to File Table
DFLTN @ $0099 ;Default Input Device (0)
DFLTO @ $009a ;Default Output Device (3)
PRTY @ $009b ;Parity of Byte Output to Tape
DPSW @ $009c ;Flag: Byte received from Tape
MSGFLG @ $009d ;Set error message mode
FNMIDX @ $009e ;Index to Cassette File name/Header ID for Tape write
PTR1 @ $009e ;Tape Error log pass 1
PTR2 @ $009f ;Tape Error log pass 2
TIME @ $00a0 ;Real-time jiffy Clock, Update Routine: UDTIMK ($f69b)
TSFCNT @ $00a3 ;Bit Counter Tape Read or Write/Serial Bus
TBTCNT @ $00a4 ;Pulse Counter Tape Read or Write/Serial Bus shift Counter
CNTDN @ $00a5 ;Tape Synchronising count down
BUFPNT @ $00a6 2 ;Pointer: Tape I/O buffer
INBIT @ $00a7 ;RS232 temporary for received Bit/Tape
BITC1 @ $00a8 ;RS232 Input Bit count/Tape temporary
RINONE @ $00a9 ;RS232 Flag: Start Bit check/Tape temporary
RIDATA @ $00aa ;RS232 Input Byte Buffer/Tape temporary
RIPRTY @ $00ab ;RS232 Input parity/Tape temporary
SAL @ $00ac 2 ;Pointer: Tape Buffer/Screen scrolling
EAL @ $00ae ;Tape End Address/End of Program
CMPO @ $00b0 ;Tape timing Constants
TAPE1 @ $00b2 2 ;Pointer: Start Address of Tape Buffer ($033c)
BITTS @ $00b4 ;RS232 Write bit count/Tape Read timing Flag
NXTBIT @ $00b5 ;RS232 Next Bit to send/Tape Read - End of Tape
RODATA @ $00b6 ;RS232 Output Byte Buffer/Tape Read Error Flag
FNLEN @ $00b7 ;Number of Characters in Filename
LA @ $00b8 ;Current File - Logical File number
SA @ $00b9 ;Current File - Secondary Address
FA @ $00ba ;Current File - First Address (Device number)
FNADR @ $00bb 2 ;Pointer: Current File name Address
ROPRTY @ $00bd ;RS232 Output Parity/Tape Byte to be Input or Output
FSBLK @ $00be ;Tape Input/Output Block count
MYCH @ $00bf ;Serial Word Buffer
CAS1 @ $00c0 ;Tape Motor Switch
STAL @ $00c1 ;Start Address for LOAD and Cassette Write
MEMUSS @ $00c3 2 ;Pointer: Type 3 Tape LOAD and general use
LSTX @ $00c5 ;Matrix value of last Key pressed; No Key = $40
NDX @ $00c6 ;Number of Characters in Keyboard Buffer queue
RVS @ $00c7 ;Flag: Reverse On/Off; On = $01, Off = $00
INDX @ $00c8 2 ;Pointer: End of Line for Input
LXSP @ $00c9 ;Cursor X/Y (Line/Column) position at start of Input
SFDX @ $00cb ;Flag: Print shifted Characters
BLNSW @ $00cc ;Flag: Cursor blink; $00 = Enabled, $01 = Disabled
BLNCT @ $00cd ;Timer: Count down for Cursor blink toggle
GDBLN @ $00ce ;Character under Cursor while Cursor Inverted
BLNON @ $00cf ;Flag: Cursor Status; $00 = Off, $01 = On
CRSW @ $00d0 ;Flag: Input from Screen = $03, or Keyboard = $00
PNT @ $00d1 2 ;Pointer: Current Screen Line Address
PNTR @ $00d3 ;Cursor Column on current Line, including Wrap-round Line, if any
QTSW @ $00d4 ;Flag: Editor in Quote Mode; $00 = Not
LNMX @ $00d5 ;Current logical Line length: 39 or 79
TBLX @ $00d6 ;Current Screen Line number of Cursor
SCHAR @ $00d7 ;Screen value of current Input Character/Last Character Output
INSRT @ $00d8 ;Count of number of inserts outstanding
LDTB1 @ $00d9 ;Screen Line link Table/Editor temporaries
USER @ $00f3 2 ;Pointer: Current Colour RAM Location
KEYTAB @ $00f5 2 ;Vector: Current Keyboard decoding Table ($eb81)
RIBUF @ $00f7 2 ;RS232 Input Buffer Pointer
ROBUF @ $00f9 2 ;RS232 Output Buffer Pointer
FREKZP @ $00fb ;Free Zero Page space for User Programs
BASZPT @ $00ff ;BASIC temporary Data Area
ASCWRK @ $00ff ;Assembly Area for Floating point to ASCII conversion
LAT @ $0259 10 ;Kernal Table: Active logical File numbers
FAT @ $0263 10 ;Kernal Table: Active File First Addresses
SAT @ $026d 10 ;Kernal Table: Active File Secondary Addresses
KEYD @ $0277 10 ;Keyboard Buffer Queue (FIFO)
MEMSTR @ $0281 2 ;Pointer: Bottom of Memory for Operating System ($0800)
MEMSIZ2 @ $0283 2 ;Pointer: Top of Memory for Operating System ($a000)
TIMOUT @ $0285 ;Serial IEEE Bus timeout defeat Flag
COLOR @ $0286 ;Current Character Colour code
GDCOL @ $0287 ;Background Colour under Cursor
HIBASE @ $0288 ;High Byte of Screen Memory Address ($04)
XMAX @ $0289 ;Maximum number of Bytes in Keyboard Buffer ($0a)
RPTFLG @ $028a ;Flag: Repeat keys setting
KOUNT @ $028b ;Repeat Key: Speed Counter ($04)
DELAY @ $028c ;Repeat Key: First repeat delay Counter ($10)
SHFLAG @ $028d ;flags for shift, CBM, CTRL
LSTSHF @ $028e ;Last Shift Key used for debouncing
KEYLOG @ $028f 2 ;Vector: Routine to determine Keyboard table to use
MODE @ $0291 ;Flag: Upper/Lower Case change
AUTODN @ $0292 ;Flag: Auto scroll down: $00 = Disabled ($00)
M51CTR @ $0293 ;RS232 Pseudo 6551 control Register Image
M51CDR @ $0294 ;RS232 Pseudo 6551 command Register Image
M51AJB @ $0295 ;RS232 Non-standard Bits/Second
RSSTAT @ $0297 ;RS232 Pseudo 6551 Status Register Image
BITNUM @ $0298 ;RS232 Number of Bits left to send
BAUDOF @ $0299 ;RS232 Baud Rate; Full Bit time microseconds
RIDBE @ $029b ;RS232 Index to End of Input Buffer
RIDBS @ $029c 2 ;RS232 Pointer: High Byte of Address of Input Buffer
RODBS @ $029d 2 ;RS232 Pointer: High Byte of Address of Output Buffer
RODBE @ $029e ;RS232 Index to End of Output Buffer
IRQTMP @ $029f 2 ;Temporary store for IRQ Vector during Tape operations
ENABL @ $02a1 ;RS232 Enables
TODSNS @ $02a2 ;TOD sense during Tape I/O
TRDTMP @ $02a3 ;Temporary storage during Tape READ
TD1IRQ @ $02a4 ;Temporary D1IRQ Indicator during Tape READ
TLNIDX @ $02a5 ;Temporary for Line Index
TVSFLG @ $02a6 ;Flag: TV Standard: $00 = NTSC, $01 = PAL
CINV @ $0314 2 ;Vector: Hardware IRQ Interrupt ($ea31)
CNBINV @ $0316 2 ;Vector: BRK Instruction Interrupt ($fe66)
NMINV @ $0318 2 ;Vector: Hardware NMI Interrupt ($fe47)
IOPEN2 @ $031a 2 ;Vector: Kernal OPEN Routine ($f34a)
ICLOSE2 @ $031c 2 ;Vector: Kernal CLOSE Routine ($f291)
ICHKIN2 @ $031e 2 ;Vector: Kernal CHKIN Routine ($f20e)
ICKOUT2 @ $0320 2 ;Vector: Kernal CHKOUT Routine ($f250)
ICLRCH2 @ $0322 2 ;Vector: Kernal CLRCHN Routine ($f333)
IBASIN2 @ $0324 2 ;Vector: Kernal CHRIN Routine ($f157)
IBSOUT2 @ $0326 2 ;Vector: Kernal CHROUT Routine ($f1ca)
ISTOP2 @ $0328 2 ;Vector: Kernal STOP Routine ($f6ed)
IGETIN2 @ $032a 2 ;Vector: Kernal GETIN Routine ($f13e)
ICLALL2 @ $032c 2 ;Vector: Kernal CLALL Routine ($f32f)
USRCMD2 @ $032e 2 ;User Defined Vector ($fe66)
ILOAD2 @ $0330 2 ;Vector: Kernal LOAD Routine ($f4a5)
ISAVE2 @ $0332 2 ;Vector: Kernal SAVE Routine ($f5ed)
TBUFFR @ $033c 192 ;start of Tape I/O Buffer
VICSCN @ $0400 1024 ;start of Default Screen Video Matrix

View File

@ -0,0 +1,251 @@
; See the LICENSE file for distribution terms (Apache 2.0).
;
; Parts adapted from multiple sources:
;
; - Project 64, 64MAP10.TXT, June 1996, etext #41
; http://unusedino.de/ec64/technical/project64/memory_maps.html
;
; - PageTable's C64 BASIC & KERNAL ROM Disassembly
; https://www.pagetable.com/c64ref/c64disasm/
;
; - "Mapping the Commodore 64", by Sheldon Leemon
; Compute! Publications Inc. (1984), ISBN 0-942386-23-X
; https://archive.org/details/Compute_s_Mapping_the_Commodore_64
*SYNOPSIS KERNAL ROM ($e000-$ffff) labels (functions and some of the vectors)
; Note: BASIC too big to fit into $a000-$bfff, so some additional BASIC support
; spills over into the start of the KERNAL ROM.
expCont @ $e000 ;EXP continued From BASIC ROM
polyx @ $e043 ;Series Evaluation
rmulc @ $e08d ;Constants for RND
rnd @ $e097 ;Perform rnd
bioerr @ $e0f9 ;Handle I/O Error in BASIC
bchout @ $e10c ;Output Character
bchin @ $e112 ;Input Character
bckout @ $e118 ;Set Up For Output
bckin @ $e11e ;Set Up For Input
bgetin @ $e124 ;Get One Character
sys @ $e12a ;Perform sys
savet @ $e156 ;Perform save
verfyt @ $e165 ;Perform verify / load
opent @ $e1be ;Perform open
closet @ $e1c7 ;Perform close
slpara @ $e1d4 ;Get Parameters For LOAD/SAVE
combyt @ $e200 ;Get Next One Byte Parameter
deflt @ $e206 ;Check Default Parameters
cmmerr @ $e20e ;Check For Comma
ocpara @ $e219 ;Get Parameters For OPEN/CLOSE
cos @ $e264 ;Perform cos
sin @ $e26b ;Perform sin
tan @ $e2b4 ;Perform tan
atn @ $e30e ;Perform atn
bassft @ $e37b ;BASIC Warm Start RUNSTOP-RESTORE
init @ $e394 ;BASIC Cold Start
initat @ $e3a2 ;CHRGET For Zero-page
initcz @ $e3bf ;Initialize BASIC RAM
initms @ $e422 ;Output Power-Up Message
bvtrs @ $e447 12 ;Table of BASIC Vectors (for $300)
initv @ $e453 ;Initialize Vectors
words @ $e45f ;Power-Up Message
chkoutCallPatch @ $e4ad ;Patch for BASIC Call to CHKOUT
rstCharColor @ $e4da ;Reset Character Colour
pauseTapeFind @ $e4e0 ;Pause After Finding Tape File
rs232Timing @ $e4ec 20 ;RS-232 Timing Table
iobase2 @ $e500 ;Get I/O Address
screen2 @ $e505 ;Get Screen Size
plot2 @ $e50a ;Put / Get Row And Column
cint1 @ $e518 ;Initialize I/O
clrScrn @ $e544 ;Clear Screen
homeCur @ $e566 ;Home Cursor
setScrnPtrs @ $e56c ;Set Screen Pointers
ioDefaultsAlt @ $e59a ;Set I/O Defaults (Unused Entry)
ioDefaults @ $e5a0 ;Set I/O Defaults
lp2 @ $e5b4 ;Get Character From Keyboard Buffer
keyInput @ $e5ca ;Input From Keyboard
keyScrnInput @ $e632 ;Input From Screen or Keyboard
quotesTest @ $e684 ;Quotes Test
scrnPrntInit @ $e691 ;Set Up Screen Print
advanceCur @ $e6b6 ;Advance Cursor
retreatCur @ $e6ed ;Retreat Cursor
backPrevLine @ $e701 ;Back on to Previous Line
outputToScrn @ $e716 ;Output to Screen
unshiftChars @ $e72a ;unshifted characters
shiftedChars @ $e7d4 ;shifted characters
nextLine @ $e87c ;Go to Next Line
outputCR @ $e891 ;Output <CR>
chkLineDec @ $e8a1 ;Check Line Decrement
chkLineInc @ $e8b3 ;Check Line Increment
setColorCode @ $e8cb ;Set Colour Code
colorCodeTbl @ $e8da 16 ;Colour Code Table
scrnScroll @ $e8ea ;Scroll Screen
openSpace @ $e965 ;Open A Space On The Screen
moveLine @ $e9c8 ;Move A Screen Line
syncColorXfer @ $e9e0 ;Syncronise Colour Transfer
setSOL @ $e9f0 ;Set Start of Line
clearLine @ $e9ff ;Clear Screen Line
printToScrn @ $ea13 ;Print To Screen
syncColPntr @ $ea24 ;Syncronise Colour Pointer
defaultIrqEntry @ $ea31 ;Main IRQ Entry Point
scnkey2 @ $ea87 ;Scan Keyboard
processKey @ $eadd ;Process Key Image
graphTextCntrl @ $ec44 ;Graphics/Text Control
shiftRunEq @ $ece7 ;Shift-Run Equivalent
loScrnLineAddr @ $ecf0 ;Low Byte Screen Line Addresses
talk2 @ $ed09 ;Send TALK Command on Serial Bus
listn2 @ $ed0c ;Send LISTEN Command on Serial Bus
serialSend @ $ed40 ;Send Data On Serial Bus
flagErrors @ $edad ;Flag Errors
flagDevNotPres @ $edad ;Status #80 - device not present
flagWriteTout @ $edb0 ;Status #03 - write timeout
secnd2 @ $edb9 ;Send LISTEN Secondary Address
clrAtn @ $edbe ;Clear ATN
tksa2 @ $edc7 ;Send TALK Secondary Address
waitForClock @ $edcc ;Wait For Clock
ciout2 @ $eddd ;Send Serial Deferred
untalk2 @ $edef ;Send UNTALK / UNLISTEN
unlsn2 @ $edfe ;Unlisten
acptr2 @ $ee13 ;Receive From Serial Bus
serialClkOn @ $ee85 ;Serial Clock On
serialClkOff @ $ee8e ;Serial Clock Off
serialOutput1 @ $ee97 ;Serial Output 1
serialOutput0 @ $eea0 ;Serial Output 0
serialGet @ $eea9 ;Get Serial Data And Clock In
delay1ms @ $eeb3 ;Delay 1 ms
rs232Send @ $eebb ;RS-232 Send
rs232SendByte @ $ef06 ;Send New RS-232 Byte
noDataSetRdy @ $ef2e ;No DSR / No CTS Error
disableTimer @ $ef39 ;Disable Timer
bitCount @ $ef4a ;Compute Bit Count
rs232Recv @ $ef59 ;RS-232 Receive
rs232RecvInit @ $ef7e ;Set Up To Receive
rs232ProcByte @ $ef90 ;Process RS-232 Byte
rs232Submit @ $efe1 ;Submit to RS-232
noDsrError @ $f00d ;No DSR (Data Set Ready) Error
rs232SendToBuf @ $f017 ;Send to RS-232 Buffer
rs232Input @ $f04d ;Input From RS-232
rs232Get @ $f086 ;Get From RS-232
serialBusIdle @ $f0a4 ;Serial Bus Idle
prtMsgIfDirect @ $f12b ;Print Message if Direct
prtMsg @ $f12f ;Print Message
getin3 @ $f13e ;Get a byte
chrin3 @ $f157 ;Input a byte
getFromIO @ $f199 ;Get From Tape / Serial / RS-232
chrout3 @ $f1ca ;Output One Character
chkin3 @ $f20e ;Set Input Device
chkout3 @ $f250 ;Set Output Device
close3 @ $f291 ;Close File
findFile @ $f30f ;Find File
setFileParms @ $f31f ;Set File values
clall3 @ $f32f ;Abort All Files
clrchn3 @ $f333 ;Restore Default I/O
open3 @ $f34a ;Open File
setSecondary @ $f3d5 ;Send Secondary Address
rs232Open @ $f409 ;Open RS-232
load2 @ $f49e ;Load RAM
serialLoadFile @ $f4b8 ;Load File From Serial Bus
tapeLoadFile @ $f533 ;Load File From Tape
printSearching @ $f5af ;Print SEARCHING
printFilename @ $f5c1 ;Print Filename
printLoading @ $f5d2 ;Print LOADING / VERIFYING
save @ $f5dd ;Save RAM
serialSave @ $f5fa ;Save to Serial Bus
tapeSave @ $f659 ;Save to Tape
printSaving @ $f68f ;Print SAVING
udtim2 @ $f69b ;Bump Clock
rdtim2 @ $f6dd ;Get Time
settim2 @ $f6e4 ;Set Time
stop @ $f6ed ;Check STOP Key
findTapeHdr @ $f72c ;Find Any Tape Header
writeTapeHdr @ $f76a ;Write Tape Header
getBufAddr @ $f7d0 ;Get Buffer Address
headerStartEnd @ $f7d7 ;Set Buffer Stat / End Pointers
findSpecTapeHdr @ $f7ea ;Find Specific Tape Header
bumpTapePtr @ $f80d ;Bump Tape Pointer
printPressPlay @ $f817 ;Print PRESS PLAY ON TAPE
chkTapeStatus @ $f82e ;Check Tape Status
printPressRecrd @ $f838 ;Print PRESS RECORD...
initTapeRead @ $f841 ;Initiate Tape Read
initTapeWrite @ $f864 ;Initiate Tape Write
tapeOperEntry @ $f875 ;Common Tape Code
chkTapeStop @ $f8d0 ;Check Tape Stop
setReadTiming @ $f8e2 ;Set Read Timing
readTapeBits @ $f92c ;Read Tape Bits
storeTapeChars @ $fa60 ;Store Tape Characters
rstTapePtr @ $fb8e ;Reset Tape Pointer
newCharSetup @ $fb97 ;New Character Setup
sendTapeTone @ $fba6 ;Send Tone to Tape
writeTapeData @ $fbc8 ;Write Data to Tape
tapeIrqEntry @ $fbcd ;IRQ Entry Point
writeTapeLeader @ $fc57 ;Write Tape Leader
restoreIrq @ $fc93 ;Restore Normal IRQ
setIrqVec @ $fcb8 ;Set IRQ Vector
stopTapeMotor @ $fcca ;Kill Tape Motor
chkRwPtr @ $fcd1 ;Check Read / Write Pointer
bumpRwPtr @ $fcdb ;Bump Read / Write Pointer
resetEntry @ $fce2 ;Power-Up RESET Entry
cartridgeCheck @ $fd02 ;Check For 8-ROM
restor2 @ $fd15 ;Restore Kernal Vectors (at $0314)
vector2 @ $fd1a ;Change Vectors For User
ramtas2 @ $fd50 ;Initialise System Constants
ioinit2 @ $fda3 ;Initialise I/O
enableTimer @ $fddd ;Enable Timer
setnam2 @ $fdf9 ;Set Filename
setlfs2 @ $fe00 ;Set Logical File Parameters
readst2 @ $fe07 ;Get I/O Status Word
setmsg2 @ $fe18 ;Control OS Messages
settmo2 @ $fe21 ;Set IEEE Timeout
memtop2 @ $fe25 ;Read / Set Top of Memory
membot2 @ $fe34 ;Read / Set Bottom of Memory
nmiHandler @ $fe43 ;NMI Transfer Entry
basicWarmStart @ $fe66 ;Warm Start Basic BRK
exitInterrupt @ $febc ;Exit Interrupt
rs232NmiIn @ $fed6 ;NMI RS-232 In
rs232NmiOut @ $ff07 ;NMI RS-232 Out
irqEntryAlt @ $ff43 ;Fake IRQ Entry
irqEntry @ $ff48 ;IRQ Entry
cint2 @ $ff5b ;Initialize screen editor
kernalVer @ $ff80 ;Kernal Version Number 03
cint @ $ff81 ;Init Editor & Video Chips ($ff5b)
ioinit @ $ff84 ;Init I/O Devices Ports & Timers ($fda3)
ramtas @ $ff87 ;Init Ram & Buffers ($fd50)
restor @ $ff8a ;Restore Vectors ($fd15)
vector @ $ff8d ;Change Vectors For User ($fd1a)
setmsg @ $ff90 ;Control OS Messages ($fe18)
secnd @ $ff93 ;Send SA After Listen ($edb9)
tksa @ $ff96 ;Send SA After Talk ($edc7)
memtop @ $ff99 ;Set/Read System RAM Top ($fe25)
membot @ $ff9c ;Set/Read System RAM Bottom ($fe34)
scnkey @ $ff9f ;Scan Keyboard ($ea87)
settmo @ $ffa2 ;Set Timeout In IEEE ($fe21)
acptr @ $ffa5 ;Handshake Serial Byte In ($ee13)
ciout @ $ffa8 ;Handshake Serial Byte Out ($eddd)
untalk @ $ffab ;Command Serial Bus UNTALK ($edef)
unlsn @ $ffae ;Command Serial Bus UNLISTEN ($edfe)
listn @ $ffb1 ;Command Serial Bus LISTEN ($ed0c)
talk @ $ffb4 ;Command Serial Bus TALK ($ed09)
readst @ $ffb7 ;Read I/O Status Word ($fe07)
setlfs @ $ffba ;Set Logical File Parameters ($fe00)
setnam @ $ffbd ;Set Filename ($fdf9)
iopen @ $ffc0 ;Open Vector $f34a ($031a->$f34a)
iclose @ $ffc3 ;Close Vector $f291 ($031c->$f291)
ichkin @ $ffc6 ;Set Input $f20e ($031e->$f20e)
ichkout @ $ffc9 ;Set Output $f250 ($0320->$f250)
iclrch @ $ffcc ;Restore I/O Vector $f333 ($0322->$f333)
ichrin @ $ffcf ;Input Vector chrin $f157 ($0324->$f157)
ichrout @ $ffd2 ;Output Vector chrout $f1ca ($0326->$f1ca)
load @ $ffd5 ;Load RAM From Device ($f49e)
save2 @ $ffd8 ;Save RAM To Device ($f5dd)
settim @ $ffdb ;Set Real-Time Clock ($f6e4)
rdtim @ $ffde ;Read Real-Time Clock ($f6dd)
istop3 @ $ffe1 ;Test-Stop Vector $f6ed ($0328->$f6ed)
igetin @ $ffe4 ;Get From Keyboad $f13e ($032a->$f13e)
iclall @ $ffe7 ;Close All Channels And Files $f32f ($032c->$f32f)
udtim @ $ffea ;Increment Real-Time Clock ($f69b)
screen @ $ffed ;Return Screen Organization ($e505)
plot @ $fff0 ;Read / Set Cursor X/Y Position ($e50a)
iobase @ $fff3 ;Return I/O Base Address ($e500)
nmiVector @ $fffa 2 ;Non-Maskable Interrupt Hardware Vector ($fe43)
resetVector @ $fffc 2 ;System Rest (RES) Hardware Vector ($fce2)
irqVector @ $fffe 2 ;Maskable Interrupt Request and Break Hardware Vectors ($ff48)

View File

@ -434,7 +434,7 @@ namespace RuntimeData.Commodore {
private const byte TRANSPARENT = 16;
#if SHOW_BORDER
private const byte BORDER_COLOR = 0;
private const byte BORDER_COLOR = 17;
#else
private const byte BORDER_COLOR = TRANSPARENT;
#endif
@ -459,6 +459,9 @@ namespace RuntimeData.Commodore {
vb.SetColor(14, 0xff, 0x6c, 0x5e, 0xb5); // 14=light blue
vb.SetColor(15, 0xff, 0x95, 0x95, 0x95); // 15=light grey
vb.SetColor(16, 0, 0, 0, 0); // 16=transparent
#if SHOW_BORDER
vb.SetColor(17, 0xff, 0x00, 0xd6, 0xff); // 17=grid border
#endif
}
}
}

Binary file not shown.

View File

@ -0,0 +1,175 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":5,
"FileDataLength":25,
"FileDataCrc32":646072439,
"ProjectProps":{
"CpuName":"6502",
"IncludeUndocumentedInstr":false,
"TwoByteBrk":false,
"EntryFlags":32702671,
"AutoLabelStyle":"Simple",
"AnalysisParams":{
"AnalyzeUncategorizedData":true,
"DefaultTextScanMode":"LowHighAscii",
"MinCharsForString":4,
"SeekNearbyTargets":true,
"UseRelocData":false,
"SmartPlpHandling":false,
"SmartPlbHandling":true},
"PlatformSymbolFileIdentifiers":[],
"ExtensionScriptFileIdentifiers":[],
"ProjectSyms":{
"__ENABLE_ALL_LABEL_NEWLINE":{
"DataDescriptor":{
"Length":1,
"Format":"NumericLE",
"SubFormat":"Decimal",
"SymbolRef":null},
"Comment":"",
"HasWidth":false,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"__ENABLE_ALL_LABEL_NEWLINE",
"Value":1,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"},
"shortnm":{
"DataDescriptor":{
"Length":1,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"short label",
"HasWidth":false,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"shortnm",
"Value":16384,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"},
"SomewhatLongName":{
"DataDescriptor":{
"Length":1,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"somewhat longer label",
"HasWidth":false,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"SomewhatLongName",
"Value":16385,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"}}},
"AddressMap":[{
"Offset":0,
"Addr":4096,
"Length":25,
"PreLabel":"",
"IsRelative":false}],
"TypeHints":[{
"Low":0,
"High":0,
"Hint":"Code"}],
"StatusFlagOverrides":{
},
"Comments":{
},
"LongComments":{
},
"Notes":{
},
"UserLabels":{
"9":{
"Label":"data",
"Value":4105,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"20":{
"Label":"shortb",
"Value":4116,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"10":{
"Label":"BranchTargetLongName",
"Value":4106,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"24":{
"Label":"done",
"Value":4120,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"}},
"OperandFormats":{
},
"LvTables":{
"10":{
"Variables":[{
"DataDescriptor":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"local var with short name",
"HasWidth":true,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"ptr",
"Value":0,
"Source":"Variable",
"Type":"ExternalAddr",
"LabelAnno":"None"},
{
"DataDescriptor":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"local var with longer name",
"HasWidth":true,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"PointerWithLongName",
"Value":2,
"Source":"Variable",
"Type":"ExternalAddr",
"LabelAnno":"None"}],
"ClearPrevious":false}},
"Visualizations":[],
"VisualizationAnimations":[],
"VisualizationSets":{
},
"RelocList":{
},
"DbrValues":{
}}

Binary file not shown.

View File

@ -0,0 +1,419 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":6,
"FileDataLength":1537,
"FileDataCrc32":-1543685807,
"ProjectProps":{
"CpuName":"6502",
"IncludeUndocumentedInstr":false,
"TwoByteBrk":false,
"EntryFlags":32702671,
"AutoLabelStyle":"Simple",
"AnalysisParams":{
"AnalyzeUncategorizedData":true,
"DefaultTextScanMode":"LowHighAscii",
"MinCharsForString":4,
"SeekNearbyTargets":true,
"UseRelocData":false,
"SmartPlpHandling":false,
"SmartPlbHandling":true},
"PlatformSymbolFileIdentifiers":[],
"ExtensionScriptFileIdentifiers":[],
"ProjectSyms":{
"IN_1":{
"DataDescriptor":{
"Length":256,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"",
"HasWidth":true,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"IN_1",
"Value":36864,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"},
"IN_2":{
"DataDescriptor":{
"Length":256,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"",
"HasWidth":true,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"IN_2",
"Value":40960,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"},
"IN_3":{
"DataDescriptor":{
"Length":256,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"",
"HasWidth":true,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"IN_3",
"Value":45056,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"},
"IN_4":{
"DataDescriptor":{
"Length":256,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"",
"HasWidth":true,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"IN_4",
"Value":49152,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"},
"THREE_K":{
"DataDescriptor":{
"Length":1,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"Comment":"project symbol test",
"HasWidth":false,
"Direction":"ReadWrite",
"MultiMask":null,
"Label":"THREE_K",
"Value":12288,
"Source":"Project",
"Type":"ExternalAddr",
"LabelAnno":"None"}}},
"AddressMap":[{
"Offset":0,
"Addr":2048,
"Length":256,
"PreLabel":"",
"DisallowInward":false,
"DisallowOutward":false,
"IsRelative":false},
{
"Offset":45,
"Addr":2093,
"Length":12,
"PreLabel":"",
"DisallowInward":false,
"DisallowOutward":true,
"IsRelative":true},
{
"Offset":256,
"Addr":4096,
"Length":256,
"PreLabel":"",
"DisallowInward":true,
"DisallowOutward":true,
"IsRelative":false},
{
"Offset":512,
"Addr":4096,
"Length":256,
"PreLabel":"",
"DisallowInward":false,
"DisallowOutward":false,
"IsRelative":false},
{
"Offset":537,
"Addr":36864,
"Length":18,
"PreLabel":"inner1_pre",
"DisallowInward":false,
"DisallowOutward":false,
"IsRelative":false},
{
"Offset":768,
"Addr":8192,
"Length":256,
"PreLabel":"",
"DisallowInward":false,
"DisallowOutward":true,
"IsRelative":false},
{
"Offset":793,
"Addr":40960,
"Length":18,
"PreLabel":"inner2_pre",
"DisallowInward":false,
"DisallowOutward":false,
"IsRelative":false},
{
"Offset":1024,
"Addr":12288,
"Length":256,
"PreLabel":"",
"DisallowInward":true,
"DisallowOutward":false,
"IsRelative":false},
{
"Offset":1049,
"Addr":45056,
"Length":18,
"PreLabel":"inner3_pre",
"DisallowInward":false,
"DisallowOutward":false,
"IsRelative":false},
{
"Offset":1280,
"Addr":16384,
"Length":256,
"PreLabel":"",
"DisallowInward":true,
"DisallowOutward":true,
"IsRelative":false},
{
"Offset":1305,
"Addr":49152,
"Length":18,
"PreLabel":"inner4_pre",
"DisallowInward":false,
"DisallowOutward":false,
"IsRelative":false}],
"TypeHints":[{
"Low":0,
"High":0,
"Hint":"Code"},
{
"Low":256,
"High":256,
"Hint":"Code"},
{
"Low":512,
"High":512,
"Hint":"Code"},
{
"Low":1024,
"High":1024,
"Hint":"Code"},
{
"Low":1280,
"High":1280,
"Hint":"Code"}],
"StatusFlagOverrides":{
},
"Comments":{
"9":"operand label set manually"},
"LongComments":{
},
"Notes":{
},
"UserLabels":{
"256":{
"Label":"region1x",
"Value":4096,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"36":{
"Label":"altbnk1",
"Value":2084,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"45":{
"Label":"altbnk2",
"Value":2093,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"57":{
"Label":"done",
"Value":2105,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"512":{
"Label":"region1",
"Value":4096,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"537":{
"Label":"inner1",
"Value":36864,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"555":{
"Label":"finish1",
"Value":4139,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"768":{
"Label":"region2",
"Value":8192,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"793":{
"Label":"inner2",
"Value":40960,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"811":{
"Label":"finish2",
"Value":8235,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1024":{
"Label":"region3",
"Value":12288,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1049":{
"Label":"inner3",
"Value":45056,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1067":{
"Label":"finish3",
"Value":12331,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1280":{
"Label":"region4",
"Value":16384,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1305":{
"Label":"inner4",
"Value":49152,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1323":{
"Label":"finish4",
"Value":16427,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1287":{
"Label":"copy",
"Value":16391,
"Source":"User",
"Type":"NonUniqueLocalAddr",
"LabelAnno":"None"},
"1031":{
"Label":"copy",
"Value":12295,
"Source":"User",
"Type":"NonUniqueLocalAddr",
"LabelAnno":"None"},
"775":{
"Label":"copy",
"Value":8199,
"Source":"User",
"Type":"NonUniqueLocalAddr",
"LabelAnno":"None"},
"519":{
"Label":"copy",
"Value":4103,
"Source":"User",
"Type":"NonUniqueLocalAddr",
"LabelAnno":"None"},
"24":{
"Label":"self",
"Value":2072,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1319":{
"Label":"_checkit",
"Value":49166,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"}},
"OperandFormats":{
"9":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"region4",
"Part":"Low"}}},
"LvTables":{
},
"Visualizations":[],
"VisualizationAnimations":[],
"VisualizationSets":{
},
"RelocList":{
},
"DbrValues":{
}}

View File

@ -0,0 +1,28 @@
.cpu "6502"
shortnm = $4000 ;short label
SomewhatLongName = $4001 ;somewhat longer label
* = $1000
lda shortnm
ldx SomewhatLongName
clc
bcc BranchTargetLongName
data
.byte $cc
ptr .var $00 ;local var with short name
PointerWithLongName .var $02 ;local var with longer name
BranchTargetLongName
sta ptr
stx PointerWithLongName
ldy data
lsr a
bcc shortb
shortb
nop
jmp done
done
rts

View File

@ -0,0 +1,29 @@
!cpu 6502
shortnm = $4000 ;short label
SomewhatLongName = $4001 ;somewhat longer label
* = $1000
lda shortnm
ldx SomewhatLongName
clc
bcc BranchTargetLongName
data
!byte $cc
!zone Z00000a
.ptr = $00 ;local var with short name
.PointerWithLongName = $02 ;local var with longer name
BranchTargetLongName
sta .ptr
stx .PointerWithLongName
ldy data
lsr
bcc shortb
shortb
nop
jmp done
done
rts

View File

@ -0,0 +1,28 @@
.setcpu "6502"
shortnm = $4000 ;short label
SomewhatLongName = $4001 ;somewhat longer label
.org $1000
lda shortnm
ldx SomewhatLongName
clc
bcc BranchTargetLongName
data:
.byte $cc
ptr .set $00 ;local var with short name
PointerWithLongName .set $02 ;local var with longer name
BranchTargetLongName:
sta ptr
stx PointerWithLongName
ldy data
lsr A
bcc shortb
shortb:
nop
jmp done
done:
rts

View File

@ -0,0 +1,9 @@
# 6502bench SourceGen generated linker script for 20280-label-placement
MEMORY {
MAIN: file=%O, start=%S, size=65536;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
}
FEATURES {}
SYMBOLS {}

View File

@ -0,0 +1,27 @@
shortnm equ $4000 ;short label
SomewhatLongName equ $4001 ;somewhat longer label
org $1000
lda shortnm
ldx SomewhatLongName
clc
bcc BranchTargetLongName
data
dfb $cc
]ptr equ $00 ;local var with short name
]PointerWithLongName equ $02 ;local var with longer name
BranchTargetLongName
sta ]ptr
stx ]PointerWithLongName
ldy data
lsr A
bcc shortb
shortb
nop
jmp done
done
rts

View File

@ -0,0 +1,255 @@
.cpu "6502"
THREE_K = $3000 ;project symbol test
IN_1 = $9000
IN_2 = $a000
IN_3 = $b000
IN_4 = $c000
* = $0800
jsr region1
jsr region2
jsr THREE_K
jsr region4 ;operand label set manually
lda L9005
lda LA008
lda IN_3+11
lda IN_4+14
self .byte $ad,$ea
L081A nop
jsr altbnk1
jsr altbnk2
jmp done
altbnk1 bit $ffc0
lda self+1
bne L081A
rts
.logical *+$0000
altbnk2 bit $ffc0
lda $0819
bne $081a
ldx $081b
rts
.here
done nop
rts
.fill 197,$00
.logical $1000
region1x lda region1x
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
rts
.fill 202,$00
.here
.logical $1000
region1 lda region1
pha
ldy #$11
nop
_copy lda inner1_pre,y
sta inner1,y
dey
bpl _copy
bit $101d
jsr inner1
jmp finish1
inner1_pre
.logical $9000
inner1 ldx inner1
ldy #$aa
L9005 ldy finish1
ldy finish2
ldy $302b
ldy $402b
rts
.here
finish1 ldy finish1
ldx region1
ldx region2
ldx THREE_K
ldx $4000
lda inner1
lda inner2
lda IN_3
lda IN_4
pla
rts
.fill 184,$00
.here
.logical $2000
region2 lda region2
pha
ldy #$11
nop
_copy lda inner2_pre,y
sta inner2,y
dey
bpl _copy
bit $201d
jsr inner2
jmp finish2
inner2_pre
.logical $a000
inner2 ldx inner2
ldy #$aa
ldy $102b
LA008 ldy finish2
ldy $302b
ldy $402b
rts
.here
finish2 ldy finish2
ldx $1000
ldx region2
ldx THREE_K
ldx $4000
lda IN_1
lda inner2
lda IN_3
lda IN_4
pla
rts
.fill 184,$00
.here
.logical $3000
region3 lda region3
pha
ldy #$11
nop
_copy lda inner3_pre,y
sta inner3,y
dey
bpl _copy
bit $301d
jsr inner3
jmp finish3
inner3_pre
.logical $b000
inner3 ldx inner3
ldy #$aa
ldy finish1
ldy finish2
ldy finish3
ldy $402b
rts
.here
finish3 ldy finish3
ldx region1
ldx region2
ldx region3
ldx $4000
lda inner1
lda inner2
lda inner3
lda IN_4
pla
rts
.fill 184,$00
.here
.logical $4000
region4 lda region4
pha
ldy #$11
nop
_copy lda inner4_pre,y
sta inner4,y
dey
bpl _copy
bit $401d
jsr inner4
jmp finish4
inner4_pre
.logical $c000
inner4 ldx inner4
ldy #$aa
ldy $102b
ldy $202b
ldy $302b
X_checkit ldy finish4
rts
.here
finish4 ldy finish4
ldx $1000
ldx $2000
ldx THREE_K
ldx region4
lda IN_1
lda IN_2
lda IN_3
lda inner4
pla
rts
.fill 184,$00
.here
.logical $0000
.byte $ff
.here

View File

@ -0,0 +1,255 @@
!cpu 6502
THREE_K = $3000 ;project symbol test
IN_1 = $9000
IN_2 = $a000
IN_3 = $b000
IN_4 = $c000
* = $0800
jsr region1
jsr region2
jsr THREE_K
jsr region4 ;operand label set manually
lda L9005
lda LA008
lda IN_3+11
lda IN_4+14
self !byte $ad,$ea
L081A nop
jsr altbnk1
jsr altbnk2
jmp done
altbnk1 bit $ffc0
lda self+1
bne L081A
rts
!pseudopc *+$0000 {
altbnk2 bit $ffc0
lda $0819
bne $081a
ldx $081b
rts
}
done nop
rts
!fill 197,$00
!pseudopc $1000 {
region1x lda region1x
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
rts
!fill 202,$00
}
!pseudopc $1000 {
region1 lda region1
pha
ldy #$11
nop
@copy lda inner1_pre,y
sta inner1,y
dey
bpl @copy
bit $101d
jsr inner1
jmp finish1
inner1_pre
!pseudopc $9000 {
inner1 ldx inner1
ldy #$aa
L9005 ldy finish1
ldy finish2
ldy $302b
ldy $402b
rts
}
finish1 ldy finish1
ldx region1
ldx region2
ldx THREE_K
ldx $4000
lda inner1
lda inner2
lda IN_3
lda IN_4
pla
rts
!fill 184,$00
}
!pseudopc $2000 {
region2 lda region2
pha
ldy #$11
nop
@copy lda inner2_pre,y
sta inner2,y
dey
bpl @copy
bit $201d
jsr inner2
jmp finish2
inner2_pre
!pseudopc $a000 {
inner2 ldx inner2
ldy #$aa
ldy $102b
LA008 ldy finish2
ldy $302b
ldy $402b
rts
}
finish2 ldy finish2
ldx $1000
ldx region2
ldx THREE_K
ldx $4000
lda IN_1
lda inner2
lda IN_3
lda IN_4
pla
rts
!fill 184,$00
}
!pseudopc $3000 {
region3 lda region3
pha
ldy #$11
nop
@copy lda inner3_pre,y
sta inner3,y
dey
bpl @copy
bit $301d
jsr inner3
jmp finish3
inner3_pre
!pseudopc $b000 {
inner3 ldx inner3
ldy #$aa
ldy finish1
ldy finish2
ldy finish3
ldy $402b
rts
}
finish3 ldy finish3
ldx region1
ldx region2
ldx region3
ldx $4000
lda inner1
lda inner2
lda inner3
lda IN_4
pla
rts
!fill 184,$00
}
!pseudopc $4000 {
region4 lda region4
pha
ldy #$11
nop
@copy lda inner4_pre,y
sta inner4,y
dey
bpl @copy
bit $401d
jsr inner4
jmp finish4
inner4_pre
!pseudopc $c000 {
inner4 ldx inner4
ldy #$aa
ldy $102b
ldy $202b
ldy $302b
_checkit ldy finish4
rts
}
finish4 ldy finish4
ldx $1000
ldx $2000
ldx THREE_K
ldx region4
lda IN_1
lda IN_2
lda IN_3
lda inner4
pla
rts
!fill 184,$00
}
!pseudopc $0000 {
!byte $ff
}

View File

@ -0,0 +1,249 @@
.setcpu "6502"
THREE_K = $3000 ;project symbol test
IN_1 = $9000
IN_2 = $a000
IN_3 = $b000
IN_4 = $c000
.org $0800
jsr region1
jsr region2
jsr THREE_K
jsr region4 ;operand label set manually
lda L9005
lda LA008
lda IN_3+11
lda IN_4+14
self: .byte $ad,$ea
L081A: nop
jsr altbnk1
jsr altbnk2
jmp done
altbnk1: bit $ffc0
lda self+1
bne L081A
rts
.org *+$0000
altbnk2: bit $ffc0
lda $0819
bne $081a
ldx $081b
rts
.org $0839
done: nop
rts
.res 197,$00
.org $1000
region1x: lda region1x
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
rts
.res 202,$00
.org $1000
region1: lda region1
pha
ldy #$11
nop
@copy: lda inner1_pre,y
sta inner1,y
dey
bpl @copy
bit $101d
jsr inner1
jmp finish1
inner1_pre:
.org $9000
inner1: ldx inner1
ldy #$aa
L9005: ldy finish1
ldy finish2
ldy $302b
ldy $402b
rts
.org $102b
finish1: ldy finish1
ldx region1
ldx region2
ldx THREE_K
ldx $4000
lda inner1
lda inner2
lda IN_3
lda IN_4
pla
rts
.res 184,$00
.org $2000
region2: lda region2
pha
ldy #$11
nop
@copy: lda inner2_pre,y
sta inner2,y
dey
bpl @copy
bit $201d
jsr inner2
jmp finish2
inner2_pre:
.org $a000
inner2: ldx inner2
ldy #$aa
ldy $102b
LA008: ldy finish2
ldy $302b
ldy $402b
rts
.org $202b
finish2: ldy finish2
ldx $1000
ldx region2
ldx THREE_K
ldx $4000
lda IN_1
lda inner2
lda IN_3
lda IN_4
pla
rts
.res 184,$00
.org $3000
region3: lda region3
pha
ldy #$11
nop
@copy: lda inner3_pre,y
sta inner3,y
dey
bpl @copy
bit $301d
jsr inner3
jmp finish3
inner3_pre:
.org $b000
inner3: ldx inner3
ldy #$aa
ldy finish1
ldy finish2
ldy finish3
ldy $402b
rts
.org $302b
finish3: ldy finish3
ldx region1
ldx region2
ldx region3
ldx $4000
lda inner1
lda inner2
lda inner3
lda IN_4
pla
rts
.res 184,$00
.org $4000
region4: lda region4
pha
ldy #$11
nop
@copy: lda inner4_pre,y
sta inner4,y
dey
bpl @copy
bit $401d
jsr inner4
jmp finish4
inner4_pre:
.org $c000
inner4: ldx inner4
ldy #$aa
ldy $102b
ldy $202b
ldy $302b
_checkit: ldy finish4
rts
.org $402b
finish4: ldy finish4
ldx $1000
ldx $2000
ldx THREE_K
ldx region4
lda IN_1
lda IN_2
lda IN_3
lda inner4
pla
rts
.res 184,$00
.org $0000
.byte $ff

View File

@ -0,0 +1,9 @@
# 6502bench SourceGen generated linker script for 20290-region-isolation
MEMORY {
MAIN: file=%O, start=%S, size=65536;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
}
FEATURES {}
SYMBOLS {}

View File

@ -0,0 +1,248 @@
THREE_K equ $3000 ;project symbol test
IN_1 equ $9000
IN_2 equ $a000
IN_3 equ $b000
IN_4 equ $c000
org $0800
jsr region1
jsr region2
jsr THREE_K
jsr region4 ;operand label set manually
lda L9005
lda LA008
lda IN_3+11
lda IN_4+14
self dfb $ad,$ea
L081A nop
jsr altbnk1
jsr altbnk2
jmp done
altbnk1 bit $ffc0
lda self+1
bne L081A
rts
org *+$0000
altbnk2 bit $ffc0
lda $0819
bne $081a
ldx $081b
rts
org $0839
done nop
rts
ds 197
org $1000
region1x lda region1x
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
rts
ds 202
org $1000
region1 lda region1
pha
ldy #$11
nop
:copy lda inner1_pre,y
sta inner1,y
dey
bpl :copy
bit $101d
jsr inner1
jmp finish1
inner1_pre
org $9000
inner1 ldx inner1
ldy #$aa
L9005 ldy finish1
ldy finish2
ldy $302b
ldy $402b
rts
org $102b
finish1 ldy finish1
ldx region1
ldx region2
ldx THREE_K
ldx $4000
lda inner1
lda inner2
lda IN_3
lda IN_4
pla
rts
ds 184
org $2000
region2 lda region2
pha
ldy #$11
nop
:copy lda inner2_pre,y
sta inner2,y
dey
bpl :copy
bit $201d
jsr inner2
jmp finish2
inner2_pre
org $a000
inner2 ldx inner2
ldy #$aa
ldy $102b
LA008 ldy finish2
ldy $302b
ldy $402b
rts
org $202b
finish2 ldy finish2
ldx $1000
ldx region2
ldx THREE_K
ldx $4000
lda IN_1
lda inner2
lda IN_3
lda IN_4
pla
rts
ds 184
org $3000
region3 lda region3
pha
ldy #$11
nop
:copy lda inner3_pre,y
sta inner3,y
dey
bpl :copy
bit $301d
jsr inner3
jmp finish3
inner3_pre
org $b000
inner3 ldx inner3
ldy #$aa
ldy finish1
ldy finish2
ldy finish3
ldy $402b
rts
org $302b
finish3 ldy finish3
ldx region1
ldx region2
ldx region3
ldx $4000
lda inner1
lda inner2
lda inner3
lda IN_4
pla
rts
ds 184
org $4000
region4 lda region4
pha
ldy #$11
nop
:copy lda inner4_pre,y
sta inner4,y
dey
bpl :copy
bit $401d
jsr inner4
jmp finish4
inner4_pre
org $c000
inner4 ldx inner4
ldy #$aa
ldy $102b
ldy $202b
ldy $302b
_checkit ldy finish4
rts
org $402b
finish4 ldy finish4
ldx $1000
ldx $2000
ldx THREE_K
ldx region4
lda IN_1
lda IN_2
lda IN_3
lda inner4
pla
rts
ds 184
org $0000
dfb $ff

View File

@ -34,17 +34,19 @@ be opened as the project file.
### Overriding Settings ###
All tests are run with a fixed set of app settings, so that the tests look
the same regardless of how the assemblers are configured. For example,
upper-case conversion is disabled, and cycle counts are not shown.
the same regardless of how the assemblers are configured in the app settings
file. For example, upper-case conversion is disabled, and cycle counts are
not shown.
Sometimes a test will want to exercise one of these settings, so we need
a way to tell the test harness to override the default. We do this by
creating project symbols.
creating project symbols:
| Name | Value | Description
| ---------------------- | ----- | -------------------------------------------|
| __ENABLE_LABEL_NEWLINE | any | Puts long labels on their own line |
| __ENABLE_CYCLE_COUNTS | any | Adds cycle count to end-of-line comments |
| Name | Value | Description
| -------------------------- | ----- | -----------------------------------------|
| __ENABLE_LABEL_NEWLINE | any | Puts long labels on their own line |
| __ENABLE_ALL_LABEL_NEWLINE | any | Puts all labels on their own line |
| __ENABLE_CYCLE_COUNTS | any | Adds cycle count to end-of-line comments |
### Execution ###
@ -74,7 +76,7 @@ the "retain output" box in the test harness, the directory and its contents
will remain. This allows you to examine the outputs when investigating
failures.
As a safety measure, the directory will NOT be removed if it contains files
As a safety measure, a directory will NOT be removed if it contains files
that the test harness doesn't recognize.
### Updating Tests ###
@ -88,6 +90,7 @@ If you want to add or update a test, follow these steps:
into the Expected directory, replacing any existing copies.
4. Run the test harness. This should now report success, and will
remove the tmpNNNNN directory.
5. Run "git diff" to verify that the changes match your expectations.
Be sure to have the version of the cross-assembler identified at the top
of this document configured.
@ -115,4 +118,3 @@ for a full explanation.
Some test projects and data files for exercising the visualization generators.
Not part of a formal test; load the projects and eyeball the results.

View File

@ -0,0 +1,32 @@
; Copyright 2024 faddenSoft. All Rights Reserved.
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; The symbol __ENABLE_ALL_LABEL_NEWLINE must be defined in the project
; symbols, so that labels are placed on their own lines whenever possible.
;
; Assembler: Merlin 32
org $1000
shortnm equ $4000
SomewhatLongName equ $4001
lda shortnm
ldx SomewhatLongName
clc
bcc BranchTargetLongName
data dfb $cc
]ptr equ $00
]PointerWithLongName equ $02
BranchTargetLongName
sta ]ptr
stx ]PointerWithLongName
ldy data
lsr A
bcc shortb
shortb nop
jmp done
done rts

View File

@ -0,0 +1,259 @@
; Copyright 2024 faddenSoft. All Rights Reserved.
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; Assembler: 64tass
; % tass64 --ascii --case-sensitive --nostart 20290-region-isolation.S
;
; This is pretending to be a multi-bank ROM, with 256 bytes per bank.
.cpu "6502"
;
; Initial region. This should end before region1, rather than span
; all sub-regions, so that we're exercising top-level regions for
; regions 1-4.
;
* = $0800
BANK = $ffc0
; EDIT: create project symbol THREE_K for $3000
jsr region1
jsr region2
jsr region3
jsr region4
; EDIT: create project symbols for $8000/9000/a000/b000, len=256
; These should resolve to the user labels (for 1/2) or the project
; symbols (for 3/4). We use an offset from the base address to ensure
; that the range is being taken into account.
lda inner1a
lda inner2a
lda inner3a
lda inner4a
; Local reference, can use "do not follow" to avoid mid-instruction branch.
self lda $eaea
call jsr altbnk1
jsr altbnk2
jmp done
; These pretend to be code that switches the ROM bank, so the code
; after the BIT instruction is actually in a different ROM, and the
; BNE goes to something else.
; EDIT: mark individual BNE as "do not follow"
altbnk1 bit BANK ;e.g. trigger a ROM bank switch
lda self+1
bne self+2
rts
; EDIT: put this in a separate region, mark "disallow outbound"
altbnk2 bit BANK
lda self+1
bne self+2
ldx call ;EDIT: set symbol explicitly, should work
rts
done nop
rts
.align 256
;
; region 1x: fully closed
;
; This overlaps with region 1. By closing it we should prevent any
; of the external references from resolving here.
;
.logical $1000
region1x lda region1x
.fill 50,$ea
rts
.align 256
.endlogical
;
; region 1: fully open
;
.logical $1000 ;*
region1 lda region1 ;*
pha
ldy #inner1_end-inner1-1 ;*
nop
_copy lda inner1_pre,y ;*
sta inner1,y ;*
dey
bpl _copy
bit inner1_pre+4 ;* should be an unresolved hole
jsr inner1 ;*
jmp finish1 ;*
; relocated inner chunk
inner1_pre ;*
.logical region1+$8000 ;*
inner1 ldx inner1 ;*
ldy #$aa
inner1a ldy finish1
ldy finish2
ldy finish3
ldy finish4
rts
inner1_end ;*
.endlogical
finish1 ldy finish1 ;*
ldx region1
ldx region2
ldx region3
ldx region4
lda inner1
lda inner2
lda inner3
lda inner4
pla
rts
.align 256 ;pad chunk to 256 bytes
.endlogical
;
; region 2: disallow outbound
;
.logical $2000
region2 lda region2
pha
ldy #inner2_end-inner2-1 ;*
nop
_copy lda inner2_pre,y ;*
sta inner2,y ;*
dey
bpl _copy
bit inner2_pre+4 ;* should be an unresolved hole
jsr inner2 ;*
jmp finish2 ;*
; relocated inner chunk
inner2_pre ;*
.logical region2+$8000 ;*
inner2 ldx inner2 ;*
ldy #$aa
ldy finish1
inner2a ldy finish2
ldy finish3
ldy finish4
rts
inner2_end ;*
.endlogical
finish2 ldy finish2 ;*
ldx region1
ldx region2
ldx region3
ldx region4
lda inner1
lda inner2
lda inner3
lda inner4
pla
rts
.align 256 ;pad chunk to 256 bytes
.endlogical
;
; region 3: disallow inbound
;
.logical $3000
region3 lda region3
pha
ldy #inner3_end-inner3-1 ;*
nop
_copy lda inner3_pre,y ;*
sta inner3,y ;*
dey
bpl _copy
bit inner3_pre+4 ;* should be an unresolved hole
jsr inner3 ;*
jmp finish3 ;*
; relocated inner chunk
inner3_pre ;*
.logical region3+$8000 ;*
inner3 ldx inner3 ;*
ldy #$aa
ldy finish1
ldy finish2
inner3a ldy finish3
ldy finish4
rts
inner3_end ;*
.endlogical
finish3 ldy finish3 ;*
ldx region1
ldx region2
ldx region3
ldx region4
lda inner1
lda inner2
lda inner3
lda inner4
pla
rts
.align 256 ;pad chunk to 256 bytes
.endlogical
;
; region 4: disallow both
;
.logical $4000
region4 lda region4
pha
ldy #inner4_end-inner4-1 ;*
nop
_copy lda inner4_pre,y ;*
sta inner4,y ;*
dey
bpl _copy
bit inner4_pre+4 ;* should be an unresolved hole
jsr inner4 ;*
jmp finish4 ;*
; relocated inner chunk
inner4_pre ;*
.logical region4+$8000 ;*
inner4 ldx inner4 ;*
ldy #$aa
ldy finish1
ldy finish2
ldy finish3
inner4a ldy finish4
rts
inner4_end ;*
.endlogical
finish4 ldy finish4 ;*
ldx region1
ldx region2
ldx region3
ldx region4
lda inner1
lda inner2
lda inner3
lda inner4
pla
rts
.align 256 ;pad chunk to 256 bytes
.endlogical
; Not sure how to force asm to output alignment padding at end of file.
; Leave this marked as non-addressable.
.byte $ff

View File

@ -24,6 +24,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -33,6 +34,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Res\SourceGenIcon.ico</ApplicationIcon>
@ -79,6 +81,7 @@
<Compile Include="DailyTips.cs" />
<Compile Include="Exporter.cs" />
<Compile Include="FormattedOperandCache.cs" />
<Compile Include="LabelFileGenerator.cs" />
<Compile Include="LocalVariableLookup.cs" />
<Compile Include="MessageList.cs" />
<Compile Include="Sgec.cs" />
@ -188,6 +191,9 @@
<Compile Include="WpfGui\FormatAddressTable.xaml.cs">
<DependentUpon>FormatAddressTable.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\GenerateLabels.xaml.cs">
<DependentUpon>GenerateLabels.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\GotoBox.xaml.cs">
<DependentUpon>GotoBox.xaml</DependentUpon>
</Compile>
@ -413,6 +419,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\GenerateLabels.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\GotoBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -491,9 +501,6 @@
<ItemGroup>
<Resource Include="Res\SourceGenIcon.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Res\AboutImage.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Res\RedX.png" />
</ItemGroup>

View File

@ -23,8 +23,8 @@ namespace SourceGen {
/// </summary>
public class Symbol {
public const char UNCERTAIN_CHAR = '?';
public const char UNIQUE_TAG_CHAR = '\u00a7'; // SECTION SIGN
private const char NO_ANNO_CHAR = '\ufffd'; // REPLACEMENT CHARACTER '<27>'
private const char UNIQUE_TAG_CHAR = '\u00a7'; // SECTION SIGN
private const int NON_UNIQUE_LEN = 7; // NON_UNIQUE_CHAR + 6 hex digits
/// <summary>
@ -84,6 +84,7 @@ namespace SourceGen {
/// <remarks>
/// Non-unique labels have extra stuff at the end to make them unique. That is
/// included here, so that the Label field is still viable as a unique identifier.
/// Use <see cref="LabelWithoutTag"/> to get just the label.
/// </remarks>
public string Label { get; private set; }

View File

@ -523,6 +523,7 @@ namespace SourceGen {
/// variables.
/// </summary>
/// <param name="addr">Address to find.</param>
/// <param name="effect">Memory effect type to match against.</param>
/// <returns>First matching symbol found, or null if nothing matched.</returns>
public Symbol FindNonVariableByAddress(int addr, OpDef.MemoryEffect effect) {
bool tryRead, tryWrite;
@ -540,6 +541,7 @@ namespace SourceGen {
return null;
}
// The mSymbolsBy{Read,Write}Address tables don't include local vars or constants.
Symbol sym = null;
if (tryRead) {
mSymbolsByReadAddress.TryGetValue(addr, out sym);
@ -549,11 +551,10 @@ namespace SourceGen {
}
if (sym == null) {
// Nothing matched, check the match groups.
// Nothing matched, check the mask groups.
foreach (KeyValuePair<DefSymbol.MultiAddressMask, MaskGroup> kvp in mMaskGroups) {
DefSymbol.MultiAddressMask multiMask = kvp.Key;
if ((addr & multiMask.CompareMask) == multiMask.CompareValue) {
MaskGroup group = kvp.Value;
DefSymbol defSym = kvp.Value.Find(addr, tryRead, tryWrite);
if (defSym != null) {
sym = defSym;
@ -565,6 +566,53 @@ namespace SourceGen {
return sym;
}
/// <summary>
/// Searches the table for project/platform symbols with matching address values. Ignores
/// constants and variables.
/// </summary>
/// <param name="addr">Address to find.</param>
/// <param name="effect">Memory effect type to match against.</param>
/// <returns>First matching symbol found, or null if nothing matched.</returns>
public Symbol FindProjPlatPreByAddress(int addr, OpDef.MemoryEffect effect) {
bool tryRead, tryWrite;
if (effect == OpDef.MemoryEffect.Read) {
tryRead = true;
tryWrite = false;
} else if (effect == OpDef.MemoryEffect.Write) {
tryRead = false;
tryWrite = true;
} else if (effect == OpDef.MemoryEffect.ReadModifyWrite ||
effect == OpDef.MemoryEffect.None) {
tryRead = tryWrite = true;
} else {
Debug.Assert(false);
return null;
}
// We don't have a pair of tables for this, so just do a linear walk through
// the symbol table. This is inefficient, but the current use case is very rare.
foreach (KeyValuePair<string,Symbol> kvp in mSymbols) {
if (!(kvp.Value is DefSymbol)) {
continue;
}
DefSymbol defSym = (DefSymbol)kvp.Value;
if (defSym.SymbolSource != Symbol.Source.Project &&
defSym.SymbolSource != Symbol.Source.Platform &&
defSym.SymbolSource != Symbol.Source.AddrPreLabel) {
continue;
}
if (addr >= defSym.Value && addr < defSym.Value + defSym.DataDescriptor.Length) {
if ((tryRead && (defSym.Direction & DefSymbol.DirectionFlags.Read) != 0) ||
(tryWrite && (defSym.Direction & DefSymbol.DirectionFlags.Write) != 0))
{
return defSym;
}
}
}
// Do we need to check the mask groups?
return null;
}
public override string ToString() {
return "SymbolTable: " + mSymbols.Count + " by label, " +
mSymbolsByReadAddress.Count + " by addr(r), " +

View File

@ -430,7 +430,8 @@ namespace SourceGen.Tests {
// Don't break lines with long labels. That way we can redefine "long"
// without breaking our tests. (This is purely cosmetic.)
settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.PreferSameLine);
// This could be on or off. Off seems less distracting.
settings.SetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
@ -455,17 +456,23 @@ namespace SourceGen.Tests {
}
/// <summary>
/// Applies app setting overrides that were specified in the project settings.
/// Applies app setting overrides that were specified in the project properties.
/// </summary>
private void ApplyProjectSettings(AppSettings settings, DisasmProject project) {
// We could probably make this a more general mechanism, but that would strain
// things a bit, since we need to know the settings name, bool/int/string, and
// desired value. Easier to just have a set of named features.
const string ENABLE_LABEL_NEWLINE = "__ENABLE_LABEL_NEWLINE";
const string ENABLE_ALL_LABEL_NEWLINE = "__ENABLE_ALL_LABEL_NEWLINE";
const string ENABLE_CYCLE_COUNTS = "__ENABLE_CYCLE_COUNTS";
if (project.ProjectProps.ProjectSyms.ContainsKey(ENABLE_LABEL_NEWLINE)) {
settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, true);
settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.SplitIfTooLong);
}
if (project.ProjectProps.ProjectSyms.ContainsKey(ENABLE_ALL_LABEL_NEWLINE)) {
settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
GenCommon.LabelPlacement.PreferSeparateLine);
}
if (project.ProjectProps.ProjectSyms.ContainsKey(ENABLE_CYCLE_COUNTS)) {
settings.SetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, true);

View File

@ -610,7 +610,7 @@ namespace SourceGen.Tools.Omf {
// Generate an ORG directive.
//int origAddr = proj.AddrMap.OffsetToAddress(bufOffset);
AddressMap.AddressMapEntry addrEnt = new AddressMap.AddressMapEntry(bufOffset,
AddressMap.FLOATING_LEN, addr, string.Empty, false);
AddressMap.FLOATING_LEN, addr);
UndoableChange uc = UndoableChange.CreateAddressChange(null, addrEnt);
cs.Add(uc);

View File

@ -165,7 +165,7 @@ namespace SourceGen.Tools.Omf {
}
first = false;
Debug.Assert(seg.FileLength > 0);
Debug.Assert(seg != null && seg.FileLength > 0);
SegmentList.Add(seg);
offset += seg.FileLength;

View File

@ -35,8 +35,8 @@ limitations under the License.
<system:String x:Key="str_OmfFileLibraryStr">a Library file</system:String>
<system:String x:Key="str_OmfFileIndeterminateStr">a file of indeterminate type</system:String>
<system:String x:Key="str_OmfFileSummaryFmt">This is {0}, with {1} segment</system:String>
<system:String x:Key="str_OmfFileSummaryPlFmt">This is {0}, with {1} segments</system:String>
<system:String x:Key="str_OmfFileSummaryFmt">This is {0}, with {1} segment (double-click to examine):</system:String>
<system:String x:Key="str_OmfFileSummaryPlFmt">This is {0}, with {1} segments (double-click to examine):</system:String>
<system:String x:Key="str_OmfFileNot">This is not an Apple II OMF file</system:String>
<system:String x:Key="str_OmfLoaderFail">Unable to prepare data file for project.</system:String>

View File

@ -32,7 +32,6 @@ namespace SourceGen.Tools {
/// demand and retain the results indefinitely.
/// </remarks>
public class VirtualHexDump : IList, INotifyCollectionChanged, INotifyPropertyChanged {
/// <summary>
/// <summary>
/// Data to display. We currently require that the entire file fit in memory,
/// which is reasonable because we impose a 2^24 (16MB) limit.

View File

@ -75,8 +75,7 @@ namespace SourceGen.Tools.WpfGui {
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart mode setting.
ChartMode mode = (ChartMode)AppSettings.Global.GetEnum(
AppSettings.A2SC_MODE, typeof(ChartMode), (int)ChartMode.HiRes1_L);
ChartMode mode = AppSettings.Global.GetEnum(AppSettings.A2SC_MODE, ChartMode.HiRes1_L);
int index = 0;
for (int i = 0; i < ChartModeItems.Length; i++) {
if (ChartModeItems[i].Mode == mode) {
@ -107,7 +106,7 @@ namespace SourceGen.Tools.WpfGui {
return;
}
AppSettings.Global.SetEnum(AppSettings.A2SC_MODE, typeof(ChartMode), (int)item.Mode);
AppSettings.Global.SetEnum(AppSettings.A2SC_MODE, item.Mode);
string text;
switch (item.Mode) {

View File

@ -55,8 +55,7 @@ namespace SourceGen.Tools.WpfGui {
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart mode setting.
ChartMode mode = (ChartMode)AppSettings.Global.GetEnum(
AppSettings.ASCCH_MODE, typeof(ChartMode), (int)ChartMode.Standard);
ChartMode mode = AppSettings.Global.GetEnum(AppSettings.ASCCH_MODE, ChartMode.Standard);
int index = 0;
for (int i = 0; i < ChartModeItems.Length; i++) {
if (ChartModeItems[i].Mode == mode) {
@ -87,7 +86,7 @@ namespace SourceGen.Tools.WpfGui {
return;
}
AppSettings.Global.SetEnum(AppSettings.ASCCH_MODE, typeof(ChartMode), (int)item.Mode);
AppSettings.Global.SetEnum(AppSettings.ASCCH_MODE, item.Mode);
//
// Draw box contents.

View File

@ -42,7 +42,7 @@ limitations under the License.
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- DataGrid gives us Ctrl+A select-all and Ctrl+C text-copy built in. -->
<!-- DataGrid gives us Ctrl+A (select-all) and Ctrl+C (text-copy) built in. -->
<DataGrid Name="hexDumpData" Grid.Row="0"
IsReadOnly="True"
ItemsSource="{Binding HexDumpLines}"
@ -58,6 +58,8 @@ limitations under the License.
ScrollViewer.CanContentScroll="True"
VerticalScrollBarVisibility="Visible">
<DataGrid.Columns>
<!-- Unqualified {Binding} creates a Binding object with default values.
This is how we reference the strings we get from the virtualized IList. -->
<DataGridTextColumn Header="Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F Text"
Width="491" Binding="{Binding}"/>
</DataGrid.Columns>

View File

@ -111,8 +111,8 @@ namespace SourceGen.Tools.WpfGui {
AsciiOnlyDump = AppSettings.Global.GetBool(AppSettings.HEXD_ASCII_ONLY, false);
// Restore conv mode setting.
CharConvMode mode = (CharConvMode)AppSettings.Global.GetEnum(
AppSettings.HEXD_CHAR_CONV, typeof(CharConvMode), (int)CharConvMode.Ascii);
CharConvMode mode =
AppSettings.Global.GetEnum(AppSettings.HEXD_CHAR_CONV, CharConvMode.Ascii);
int index = 0;
for (int i = 0; i < CharConvItems.Length; i++) {
if (CharConvItems[i].Mode == mode) {
@ -156,8 +156,7 @@ namespace SourceGen.Tools.WpfGui {
// Keep app settings up to date.
AppSettings.Global.SetBool(AppSettings.HEXD_ASCII_ONLY, mAsciiOnlyDump);
AppSettings.Global.SetEnum(AppSettings.HEXD_CHAR_CONV, typeof(CharConvMode),
(int)item.Mode);
AppSettings.Global.SetEnum(AppSettings.HEXD_CHAR_CONV, item.Mode);
mFormatter = new Formatter(config);
HexDumpLines.Reformat(mFormatter);

View File

@ -112,8 +112,8 @@ namespace SourceGen.Tools.WpfGui {
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart settings.
CpuDef.CpuType type = (CpuDef.CpuType)AppSettings.Global.GetEnum(
AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType), (int)CpuDef.CpuType.Cpu6502);
CpuDef.CpuType type =
AppSettings.Global.GetEnum(AppSettings.INSTCH_MODE, CpuDef.CpuType.Cpu6502);
ShowUndocumented = AppSettings.Global.GetBool(AppSettings.INSTCH_SHOW_UNDOC, true);
int index = 0;
@ -146,8 +146,7 @@ namespace SourceGen.Tools.WpfGui {
}
// Push current choice to settings.
AppSettings.Global.SetEnum(AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType),
(int)item.Type);
AppSettings.Global.SetEnum(AppSettings.INSTCH_MODE, item.Type);
AppSettings.Global.SetBool(AppSettings.INSTCH_SHOW_UNDOC, mShowUndocumented);
// Populate the items source.

View File

@ -49,12 +49,13 @@ limitations under the License.
BorderThickness="0" HorizontalAlignment="Left"
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
Click="WebSiteButton_Click"/>
<TextBlock Text="Copyright 2022 faddenSoft" Margin="0,0,0,0"/>
<TextBlock Text="Copyright 2024 faddenSoft" Margin="0,0,0,0"/>
<TextBlock Text="Created by Andy McFadden"/>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,8,0,0">
<TextBlock Text="{Binding OsPlatform, FallbackValue=OS: blah blah blah}"/>
<TextBlock Text="{Binding RuntimeInfo, FallbackValue=RunTime: blah blah}"/>
<TextBlock Text="Assertions and extended validation are enabled"
Visibility="{Binding DebugMessageVisibility}"/>
<TextBlock Text="Legal stuff:" Margin="0,8,0,0"/>

View File

@ -15,6 +15,7 @@
*/
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
namespace SourceGen.WpfGui {
@ -40,6 +41,17 @@ namespace SourceGen.WpfGui {
}
}
/// <summary>
/// Runtime information, for display.
/// </summary>
public string RuntimeInfo {
get {
return "Runtime: " + RuntimeInformation.FrameworkDescription + ", " +
"OS-arch " + RuntimeInformation.OSArchitecture + ", proc-arch " +
RuntimeInformation.ProcessArchitecture;
}
}
/// <summary>
/// Determines whether a message about assertions is visible.
/// </summary>

View File

@ -187,6 +187,10 @@ limitations under the License.
<StackPanel>
<CheckBox Content="Use relative addressing"
IsChecked="{Binding UseRelativeAddressing}"/>
<CheckBox Content="Disallow inbound address resolution" Margin="0,8,0,0"
IsChecked="{Binding DisallowInwardRes}"/>
<CheckBox Content="Disallow outbound address resolution" Margin="0,4,0,0"
IsChecked="{Binding DisallowOutwardRes}"/>
<StackPanel Orientation="Horizontal" Margin="0,16,0,0">
<TextBlock Text="Pre-label:"/>

View File

@ -162,6 +162,18 @@ namespace SourceGen.WpfGui {
}
private bool mUseRelativeAddressing;
public bool DisallowInwardRes {
get { return mDisallowInwardRes; }
set { mDisallowInwardRes = value; OnPropertyChanged(); UpdateControls(); }
}
private bool mDisallowInwardRes;
public bool DisallowOutwardRes {
get { return mDisallowOutwardRes; }
set { mDisallowOutwardRes = value; OnPropertyChanged(); UpdateControls(); }
}
private bool mDisallowOutwardRes;
/// <summary>
/// Pre-label input TextBox.
/// </summary>
@ -309,6 +321,8 @@ namespace SourceGen.WpfGui {
AddressText = Asm65.Address.AddressToString(curRegion.Address, false);
}
PreLabelText = curRegion.PreLabel;
DisallowInwardRes = curRegion.DisallowInward;
DisallowOutwardRes = curRegion.DisallowOutward;
UseRelativeAddressing = curRegion.IsRelative;
OperationStr = (string)FindResource("str_HdrEdit");
@ -323,6 +337,7 @@ namespace SourceGen.WpfGui {
// to fixed.
mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset,
curRegion.Length, curRegion.Address, curRegion.PreLabel,
curRegion.DisallowInward, curRegion.DisallowOutward,
curRegion.IsRelative);
option1Summ = (string)FindResource("str_OptEditAsIsSummary");
option1Msg = (string)FindResource("str_OptEditAsIs");
@ -332,6 +347,7 @@ namespace SourceGen.WpfGui {
option2Msg = (string)FindResource("str_OptEditAndFix");
mResultEntry2 = new AddressMap.AddressMapEntry(curRegion.Offset,
curRegion.ActualLength, curRegion.Address, curRegion.PreLabel,
curRegion.DisallowInward, curRegion.DisallowOutward,
curRegion.IsRelative);
} else {
option2Summ = string.Empty;
@ -347,10 +363,10 @@ namespace SourceGen.WpfGui {
// first action is disabled.
mResultEntry1 = new AddressMap.AddressMapEntry(curRegion.Offset,
selectionLen, curRegion.Address, curRegion.PreLabel,
curRegion.IsRelative);
curRegion.DisallowInward, curRegion.DisallowOutward, curRegion.IsRelative);
mResultEntry2 = new AddressMap.AddressMapEntry(curRegion.Offset,
curRegion.Length, curRegion.Address, curRegion.PreLabel,
curRegion.IsRelative);
curRegion.DisallowInward, curRegion.DisallowOutward, curRegion.IsRelative);
option1Summ = (string)FindResource("str_OptResizeSummary");
string fmt = (string)FindResource("str_OptResize");
@ -396,6 +412,8 @@ namespace SourceGen.WpfGui {
AddressText = Asm65.Address.AddressToString(newEntry.Address, false);
}
PreLabelText = string.Empty;
DisallowInwardRes = false;
DisallowOutwardRes = false;
UseRelativeAddressing = false;
OperationStr = (string)FindResource("str_HdrCreate");
@ -417,7 +435,8 @@ namespace SourceGen.WpfGui {
// a fixed region with the same start offset, but can't create a float there.
if (ares1 == AddressMap.AddResult.Okay) {
mResultEntry1 = new AddressMap.AddressMapEntry(newEntry.Offset,
newRegion1.ActualLength, newEntry.Address, string.Empty, false);
newRegion1.ActualLength, newEntry.Address,
string.Empty, false, false, false);
option1Summ = (string)FindResource("str_CreateFixedSummary");
string fmt = (string)FindResource("str_CreateFixed");
@ -439,7 +458,8 @@ namespace SourceGen.WpfGui {
}
if (ares2 == AddressMap.AddResult.Okay) {
mResultEntry2 = new AddressMap.AddressMapEntry(newEntry.Offset,
AddressMap.FLOATING_LEN, newEntry.Address, string.Empty, false);
AddressMap.FLOATING_LEN, newEntry.Address,
string.Empty, false, false, false);
option2Summ = (string)FindResource("str_CreateFloatingSummary");
string fmt = (string)FindResource("str_CreateFloating");
@ -615,7 +635,8 @@ namespace SourceGen.WpfGui {
// Combine base entry with pre-label string and relative addressing checkbox.
ResultEntry = new AddressMap.AddressMapEntry(baseEntry.Offset,
baseEntry.Length, addr, PreLabelText, UseRelativeAddressing);
baseEntry.Length, addr, PreLabelText,
DisallowInwardRes, DisallowOutwardRes, UseRelativeAddressing);
Debug.WriteLine("Dialog result: " + ResultEntry);
DialogResult = true;
}

View File

@ -820,10 +820,20 @@ limitations under the License.
<TextBlock Text="General code generation:" Margin="4,16,0,0"/>
<CheckBox Content="Show cycle counts in comments" Margin="4,8,0,0"
IsChecked="{Binding ShowCycleCountsAsm}"/>
<CheckBox Content="Put long labels on separate line" Margin="4,8,0,0"
IsChecked="{Binding LongLabelNewLine}"/>
<CheckBox Content="Identify assembler in output" Margin="4,8,0,0"
<CheckBox Content="Identify assembler in output" Margin="4,6,0,0"
IsChecked="{Binding AddIdentComment}"/>
<StackPanel Orientation="Vertical" Margin="10,6,0,0">
<TextBlock Text="Put labels on their own line..."/>
<RadioButton GroupName="labelLineGroup" Margin="0,4,0,0"
Content="Only when required"
IsChecked="{Binding LabelPlacement_PreferSameLine}"/>
<RadioButton GroupName="labelLineGroup" Margin="0,4,0,0"
Content="When the label is wider than the field"
IsChecked="{Binding LabelPlacement_SplitIfTooLong}"/>
<RadioButton GroupName="labelLineGroup" Margin="0,4,0,0"
Content="Whenever possible"
IsChecked="{Binding LabelPlacement_PreferSeparateLine}"/>
</StackPanel>
</StackPanel>
</TabItem>

View File

@ -22,6 +22,7 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Win32;
using Asm65;
@ -30,24 +31,26 @@ using CommonUtil;
using AssemblerInfo = SourceGen.AsmGen.AssemblerInfo;
using AssemblerConfig = SourceGen.AsmGen.AssemblerConfig;
using ExpressionMode = Asm65.Formatter.FormatConfig.ExpressionMode;
using System.Windows.Input;
using LabelPlacement = SourceGen.AsmGen.GenCommon.LabelPlacement;
namespace SourceGen.WpfGui {
/// <summary>
/// Application settings dialog.
/// </summary>
public partial class EditAppSettings : Window, INotifyPropertyChanged {
/// <summary>
/// Event that the controller can subscribe to if it wants to be notified when the
/// "Apply" or "OK" button is hit.
/// </summary>
public event SettingsAppliedHandler SettingsApplied;
public delegate void SettingsAppliedHandler();
/// <summary>
/// Reference to main window. Needed for examination of the code list font and
/// column widths.
/// </summary>
private MainWindow mMainWin;
/// <summary>
/// Reference to main controller. Needed to push settings out when Apply/OK is clicked.
/// </summary>
private MainController mMainCtrl;
/// <summary>
/// Copy of settings that we make changes to. On "Apply" or "OK", this is pushed
/// into the global settings object, and applied to the ProjectView.
@ -102,14 +105,13 @@ namespace SourceGen.WpfGui {
}
public EditAppSettings(Window owner, MainWindow mainWin, MainController mainCtrl,
Tab initialTab, AssemblerInfo.Id initialAsmId) {
public EditAppSettings(Window owner, MainWindow mainWin, Tab initialTab,
AssemblerInfo.Id initialAsmId) {
InitializeComponent();
Owner = owner;
DataContext = this;
mMainWin = mainWin;
mMainCtrl = mainCtrl;
mInitialTab = initialTab;
mInitialAsmId = initialAsmId;
@ -203,7 +205,8 @@ namespace SourceGen.WpfGui {
// QueryVersions() can sometimes be slow under Win10 (mid 2019), possibly
// because of the built-in malware detection, so pop up a wait cursor.
Mouse.OverrideCursor = Cursors.Wait;
mMainCtrl.SetAppSettings(mSettings);
AppSettings.Global.ReplaceSettings(mSettings);
OnSettingsApplied();
AsmGen.AssemblerVersionCache.QueryVersions();
} finally {
Mouse.OverrideCursor = null;
@ -212,6 +215,16 @@ namespace SourceGen.WpfGui {
IsDirty = false;
}
/// <summary>
/// Raises the "settings applied" event.
/// </summary>
private void OnSettingsApplied() {
SettingsAppliedHandler handler = SettingsApplied;
if (handler != null) {
handler();
}
}
#region Code View
@ -268,8 +281,8 @@ namespace SourceGen.WpfGui {
UpperOperandXY = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_XY, false);
Debug.Assert(clipboardFormatComboBox.Items.Count == sClipboardFormatItems.Length);
int clipIndex = mSettings.GetEnum(AppSettings.CLIP_LINE_FORMAT,
typeof(MainController.ClipLineFormat), 0);
int clipIndex = (int)mSettings.GetEnum(AppSettings.CLIP_LINE_FORMAT,
MainController.ClipLineFormat.AssemblerSource);
if (clipIndex >= 0 && clipIndex < sClipboardFormatItems.Length) {
// require Value == clipIndex because we're lazy and don't want to search
Debug.Assert((int)sClipboardFormatItems[clipIndex].Value == clipIndex);
@ -402,8 +415,7 @@ namespace SourceGen.WpfGui {
private void ClipboardFormatComboBox_SelectionChanged(object sender,
SelectionChangedEventArgs e) {
ClipboardFormatItem item = (ClipboardFormatItem)clipboardFormatComboBox.SelectedItem;
mSettings.SetEnum(AppSettings.CLIP_LINE_FORMAT, typeof(MainController.ClipLineFormat),
(int)item.Value);
mSettings.SetEnum(AppSettings.CLIP_LINE_FORMAT, item.Value);
IsDirty = true;
}
@ -745,14 +757,6 @@ namespace SourceGen.WpfGui {
IsDirty = true;
}
}
public bool LongLabelNewLine {
get { return mSettings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); }
set {
mSettings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, value);
OnPropertyChanged();
IsDirty = true;
}
}
public bool AddIdentComment {
get { return mSettings.GetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, false); }
set {
@ -762,6 +766,58 @@ namespace SourceGen.WpfGui {
}
}
// label placement radio buttons
public bool LabelPlacement_PreferSameLine {
get {
LabelPlacement place = mSettings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
LabelPlacement.SplitIfTooLong);
return place == LabelPlacement.PreferSameLine;
}
set {
if (value) {
mSettings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
LabelPlacement.PreferSameLine);
LabelPlacementChanged();
IsDirty = true;
}
}
}
public bool LabelPlacement_SplitIfTooLong {
get {
LabelPlacement place = mSettings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
LabelPlacement.SplitIfTooLong);
return place == LabelPlacement.SplitIfTooLong;
}
set {
if (value) {
mSettings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
LabelPlacement.SplitIfTooLong);
LabelPlacementChanged();
IsDirty = true;
}
}
}
public bool LabelPlacement_PreferSeparateLine {
get {
LabelPlacement place = mSettings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
LabelPlacement.SplitIfTooLong);
return place == LabelPlacement.PreferSeparateLine;
}
set {
if (value) {
mSettings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
LabelPlacement.PreferSeparateLine);
LabelPlacementChanged();
IsDirty = true;
}
}
}
private void LabelPlacementChanged() {
OnPropertyChanged(nameof(LabelPlacement_PreferSameLine));
OnPropertyChanged(nameof(LabelPlacement_SplitIfTooLong));
OnPropertyChanged(nameof(LabelPlacement_PreferSeparateLine));
}
private void Loaded_AsmConfig() {
asmConfigComboBox.SelectedItem = AssemblerInfo.GetAssemblerInfo(mInitialAsmId);
if (asmConfigComboBox.SelectedIndex < 0) {

View File

@ -293,8 +293,7 @@ namespace SourceGen.WpfGui {
AnalyzeStringRanges(item.Mode);
UpdateControls();
AppSettings.Global.SetEnum(AppSettings.OPED_DEFAULT_STRING_ENCODING,
typeof(TextScanMode), (int)item.Mode);
AppSettings.Global.SetEnum(AppSettings.OPED_DEFAULT_STRING_ENCODING, item.Mode);
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
@ -780,9 +779,8 @@ namespace SourceGen.WpfGui {
// Get the previous mode selected in the combo box. If the format descriptor
// doesn't specify a string, we'll use this.
TextScanMode textMode = (TextScanMode)AppSettings.Global.GetEnum(
AppSettings.OPED_DEFAULT_STRING_ENCODING, typeof(TextScanMode),
(int)TextScanMode.LowHighAscii);
TextScanMode textMode = AppSettings.Global.GetEnum(
AppSettings.OPED_DEFAULT_STRING_ENCODING, TextScanMode.LowHighAscii);
if (dfd == null) {
radioDefaultFormat.IsChecked = true;

View File

@ -20,9 +20,9 @@ using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using CommonUtil;
using Microsoft.Win32;
namespace SourceGen.WpfGui {
/// <summary>
@ -235,8 +235,8 @@ namespace SourceGen.WpfGui {
AsmCommentColWidth = colWidths[3];
}
TextMode mode = (TextMode)AppSettings.Global.GetEnum(AppSettings.EXPORT_TEXT_MODE,
typeof(TextMode), (int)TextMode.PlainText);
TextMode mode = AppSettings.Global.GetEnum(AppSettings.EXPORT_TEXT_MODE,
TextMode.PlainText);
if (mode == TextMode.PlainText) {
TextModePlain = true;
} else {
@ -273,7 +273,7 @@ namespace SourceGen.WpfGui {
} else {
mode = TextMode.Csv;
}
AppSettings.Global.SetEnum(AppSettings.EXPORT_TEXT_MODE, typeof(TextMode), (int)mode);
AppSettings.Global.SetEnum(AppSettings.EXPORT_TEXT_MODE, mode);
}
/// <summary>

View File

@ -56,15 +56,20 @@ limitations under the License.
</ListBox>
<TextBlock Text="Font size:" Margin="0,8,0,0"/>
<ComboBox Name="sizeComboBox" IsReadOnly="True" Margin="0,4,0,0" Width="75"
HorizontalAlignment="Left">
<!-- these are parsed directly, so only use numeric values -->
<ComboBoxItem>8</ComboBoxItem>
<ComboBoxItem>10</ComboBoxItem>
<ComboBoxItem>12</ComboBoxItem>
<ComboBoxItem>16</ComboBoxItem>
<ComboBoxItem>20</ComboBoxItem>
</ComboBox>
<StackPanel Orientation="Horizontal">
<ComboBox Name="sizeComboBox" Margin="0,4,0,0" Width="75"
HorizontalAlignment="Left" IsEditable="True">
<!-- these are parsed directly, so only use numeric values -->
<ComboBoxItem>8</ComboBoxItem>
<ComboBoxItem>10</ComboBoxItem>
<ComboBoxItem>12</ComboBoxItem>
<ComboBoxItem>14</ComboBoxItem>
<ComboBoxItem>16</ComboBoxItem>
<ComboBoxItem>20</ComboBoxItem>
</ComboBox>
<TextBlock Name="sizeErrMsg" Margin="8,6,0,0" Text="Must be an integer from 3 to 64."
Foreground="Red" Visibility="Hidden"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,8,0,0">
<Button Name="okButton" Content="OK" IsDefault="True"

View File

@ -44,7 +44,7 @@ namespace SourceGen.WpfGui {
GenerateMonoFontList(initialFamily);
int selIndex = 0;
int selIndex = -1;
string sizeStr = initialSize.ToString();
for (int i = 0; i < sizeComboBox.Items.Count; i++) {
ComboBoxItem item = (ComboBoxItem)sizeComboBox.Items[i];
@ -53,6 +53,10 @@ namespace SourceGen.WpfGui {
break;
}
}
if (selIndex < 0) {
// Size is not one of the standard combo box items.
sizeComboBox.Text = initialSize.ToString();
}
sizeComboBox.SelectedIndex = selIndex;
}
@ -114,7 +118,21 @@ namespace SourceGen.WpfGui {
private void OkButton_Click(object sender, RoutedEventArgs e) {
ComboBoxItem item = (ComboBoxItem)sizeComboBox.SelectedItem;
SelectedSize = int.Parse((string)item.Content);
if (item != null) {
SelectedSize = int.Parse((string)item.Content);
} else {
// Catch bad font sizes when "OK" is hit. Not as nice as disabling the OK
// button on bad input, but much simpler.
try {
SelectedSize = int.Parse(sizeComboBox.Text);
} catch (FormatException) {
SelectedSize = -1; // trigger next test
}
if (SelectedSize < 3 || SelectedSize > 64) {
sizeErrMsg.Visibility = Visibility.Visible;
return;
}
}
DialogResult = true;
}
}

View File

@ -0,0 +1,52 @@
<!--
Copyright 2024 faddenSoft
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<Window x:Class="SourceGen.WpfGui.GenerateLabels"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:SourceGen.WpfGui"
mc:Ignorable="d"
Title="Generate Label File"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner">
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="Output Format" Padding="2,4">
<StackPanel>
<RadioButton Content="VICE label commands"
ToolTip="Load in VICE monitor with 'll' command."
IsChecked="{Binding Format_VICE}"/>
</StackPanel>
</GroupBox>
<CheckBox Grid.Row="1" Margin="0,4,0,0" Content="Include auto-generated labels"
IsChecked="{Binding IncludeAutoLabels}"/>
<StackPanel Grid.Row="2" Orientation="Horizontal"
HorizontalAlignment="Right" Margin="0,8,0,0">
<Button Content="Generate" IsDefault="True" Width="70" Click="OkButton_Click"/>
<Button Content="Cancel" IsCancel="True" Width="70" Margin="4,0,0,0"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,71 @@
/*
* Copyright 2019 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
namespace SourceGen.WpfGui {
/// <summary>
/// Select parameters for label file generation.
/// </summary>
public partial class GenerateLabels : Window, INotifyPropertyChanged {
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool IncludeAutoLabels {
get { return mIncludeAutoLabels; }
set { mIncludeAutoLabels = value; OnPropertyChanged(); }
}
private bool mIncludeAutoLabels;
public LabelFileGenerator.LabelFmt Format { get; private set; }
public bool Format_VICE {
get { return Format == LabelFileGenerator.LabelFmt.VICE;}
set { Format = LabelFileGenerator.LabelFmt.VICE; UpdateFormats(); }
}
private void UpdateFormats() {
OnPropertyChanged(nameof(Format_VICE));
}
public GenerateLabels(Window owner) {
InitializeComponent();
Owner = owner;
DataContext = this;
Format = AppSettings.Global.GetEnum(AppSettings.LABGEN_FORMAT,
LabelFileGenerator.LabelFmt.VICE);
UpdateFormats();
mIncludeAutoLabels = AppSettings.Global.GetBool(AppSettings.LABGEN_INCLUDE_AUTO, false);
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
// Save settings.
AppSettings.Global.SetEnum(AppSettings.LABGEN_FORMAT, Format);
AppSettings.Global.SetBool(AppSettings.LABGEN_INCLUDE_AUTO, mIncludeAutoLabels);
DialogResult = true;
}
}
}

View File

@ -57,7 +57,7 @@ limitations under the License.
</Style>
<RoutedUICommand x:Key="AboutCmd" Text="About..."/>
<RoutedUICommand x:Key="AssembleCmd" Text="Assemble...">
<RoutedUICommand x:Key="AssembleCmd" Text="Generate Assembly...">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+Shift+A</KeyGesture>
</RoutedUICommand.InputGestures>
@ -136,6 +136,7 @@ limitations under the License.
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="FormatAddressTableCmd" Text="Format Address Table..."/>
<RoutedUICommand x:Key="GenerateLabelsCmd" Text="Generate Label File..."/>
<RoutedUICommand x:Key="GotoCmd" Text="Go To...">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+G</KeyGesture>
@ -284,6 +285,8 @@ limitations under the License.
CanExecute="CanFormatAsWord" Executed="FormatAsWordCmd_Executed"/>
<CommandBinding Command="{StaticResource FormatAddressTableCmd}"
CanExecute="CanFormatAddressTable" Executed="FormatAddressTableCmd_Executed"/>
<CommandBinding Command="{StaticResource GenerateLabelsCmd}"
CanExecute="IsProjectOpen" Executed="GenerateLabelsCmd_Executed"/>
<CommandBinding Command="{StaticResource GotoCmd}"
CanExecute="IsProjectOpen" Executed="GotoCmd_Executed"/>
<CommandBinding Command="{StaticResource GotoLastChangeCmd}"
@ -392,8 +395,8 @@ limitations under the License.
</MenuItem>
<Separator/>
<MenuItem Command="{StaticResource AssembleCmd}"/>
<!--<MenuItem Command="Print"/>-->
<MenuItem Command="{StaticResource ExportCmd}"/>
<MenuItem Command="{StaticResource GenerateLabelsCmd}"/>
<Separator/>
<MenuItem Command="{StaticResource ReloadExternalFilesCmd}"/>
<Separator/>

View File

@ -1332,6 +1332,10 @@ namespace SourceGen.WpfGui {
mMainCtrl.FormatAddressTable();
}
private void GenerateLabelsCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.GenerateLabels();
}
private void GotoCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.Goto();
}

View File

@ -106,7 +106,7 @@ namespace SourceGen {
public override string ToString() {
return "Xref off=+" + Offset.ToString("x6") + " sym=" + IsByName +
" type=" + Type + " accType= " + AccType + " flags=" + Flags +
" type=" + Type + " accType=" + AccType + " flags=" + Flags +
" adj=" + Adjustment;
}
}

View File

@ -322,7 +322,9 @@ once, so there's no reason to treat them as separate projects. Currently,
the best way to deal with this is to concatenate the files into a single
file, and operate on that.</p>
<h2 id="overlap">Overlapping Address Spaces</h2>
<p>Some programs use memory overlays, where multiple parts of the
code run in the same address in RAM. Others use bank switching to access
parts of the program that reside in separate physical RAM or ROM,
@ -383,6 +385,16 @@ it is referring to.</p>
If we hit the top of the tree without finding a match, we conclude
that the reference is to an external address.</p>
<p>The tree search can be pruned with the
"disallow inbound address resolution" and
"disallow outbound address resolution" flags, which can be set in
the address region edit dialog
(<a href="intro-details.html#region-isolation">more info here</a>).
When inbound resolution is disabled,
parents and siblings will not search into a region. When outbound
resolution is disabled, the search will not ascend to the region's parent.
Note that neither option prevents descent into a region's children.</p>
<h2 id="reloc-data">OMF Relocation Dictionaries</h2>

View File

@ -19,7 +19,7 @@ the target assembler, will recreate the original data file exactly.
Every assembler is different, so support must be added to SourceGen
for each.</p>
<p>The generation / assembly dialog can be opened with
<samp>File &gt; Assemble</samp>.</p>
<samp>File &gt; Generate Assembly</samp>.</p>
<p>If you want to show code to others, perhaps by adding a page to
your web site, you can "export" the formatted code as text or HTML.
This is explained in more detail <a href="#export-source">below</a>.
@ -385,7 +385,7 @@ clipboard and pasting them into a text file, except that you have greater
control over which columns are included. The HTML version is augmented
with links and (optionally) images.</p>
<p>Use File &gt; Export to open the export dialog. You have several
<p>Use <samp>File &gt; Export</samp> to open the export dialog. You have several
options:</p>
<ul>
<li><b>Include only selected lines</b>. This allows you to choose between
@ -425,6 +425,13 @@ will be written to the same directory.</p>
<p>All output uses UTF-8 encoding. Filenames of HTML files will have '#'
replaced with '_' to make linking easier.</p>
<h2 id="generate-labels">Generating Label Files</h2>
<p>Some debuggers allow the import of labels associated with addresses.
To generate such a file, use <samp>File &gt; Generate Label File</samp>.</p>
<p>Select the desired output format (currently only VICE label commands
are supported), and whether or not to include auto-generated labels.</p>
</div>
<div id="footer">

View File

@ -30,9 +30,12 @@ would resolve to address $123456.
If you want to set the region to be non-addressable, enter
"<code>NA</code>".</p>
<p>You can also enter a <a href="intro-details.html#pre-labels">pre-label</a>
or specify that the operand should be formatted as a
<a href="intro-details.html#relative-addr">relative address</a>.
<p>You can also enter a <a href="intro-details.html#pre-labels">pre-label</a>,
specify that the operand should be formatted as a
<a href="intro-details.html#relative-addr">relative address</a>,
or
<a href="intro-details.html#region-isolation">disallow address resolution</a>
across region boundaries.</p>
<p>To delete a region, click the "Delete Region" button.</p>

View File

@ -140,6 +140,7 @@ using the <samp>Help &gt; Help</samp> menu item or by hitting
</ul></li>
</ul></li>
<li><a href="codegen.html#export-source">Exporting Source Code</a>
<li><a href="codegen.html#generate-labels">Generating Label Files</a>
</ul></li>
<li><a href="settings.html">Properties &amp; Settings</a>

View File

@ -653,8 +653,40 @@ within the file. The process is straightforward if the address only
appears once, but when overlays cause multiple parts of the file to have
the same address, the operand target may be in different places depending
on where the call is being made from.
The algorithm for resolving addresses is described
in the <a href="advanced.html#overlap">advanced topics</a> section.</p>
The algorithm for resolving addresses is described in the
<a href="advanced.html#overlap">advanced topics</a> section.</p>
<h3 id="region-isolation">Isolation</h3>
<p>Code in regions that have been relocated will usually be able to
access code and data in other regions. However, sometimes code is
destined to be executed in an independent address space, such as a
disk drive controller, or is part of a bank-switched ROM that puts
multiple regions at the same address. In such cases, you wouldn't
want the address operand of, say, a <code>JSR</code> to resolve to
a symbol in a different region.</p>
<p>The address resolution behavior for a given region can be modified
with the "disallow inbound address resolution" and
"disallow outbound address resolution" checkboxes. The former
prevents other regions from searching for matches in the current
region, and the latter prevents the current region from searching
other regions. (The algorithm is described in the
<a href="advanced.html#overlap">advanced topics</a> section.)</p>
<p>In some rare cases it may be useful to allow resolution to work
in one direction. For example, suppose ROM bank #1 has a table of
<code>JMP</code> instructions for bank #2 that it will copy out to
RAM. The table should be placed into its own address region, with
outbound resolution disabled, because we don't want it to try to
jump to locations in our bank #1 code. It's useful to leave inbound
resolution enabled so that we can reference the table from the code
that copies it to RAM.</p>
<p>Note this only affects automatic operand resolution. You can set
operand symbols manually to any location, regardless of the isolation
flags.</p>
<h3 id="non-addr">Non-Addressable Areas</h3>

View File

@ -209,12 +209,6 @@ counts are inserted into end-of-line comments. This works the same as
the option in the <samp>Code View</samp> tab, but applies to generated
source code rather than the on-screen display.</p>
<p>If <samp>put long labels on separate line</samp> is checked, labels
that are longer than the label column are placed on their own line. This
looks a bit nicer because otherwise the opcode gets pushed out of alignment.
(Some assemblers get bent out of shape if you split an equate
directive, so those might stay on one line.)</p>
<p>If you enable <samp>identify assembler in output</samp>, a comment will be
added to the top of the generated assembly output that identifies the
target assembler and version. It also shows the command-line options
@ -223,6 +217,22 @@ file is sent to other people, since it may not otherwise be obvious from
the source file what the intended target assembler is, or what options
are required to process the file correctly.</p>
<p>Labels can generally be placed either on the same line as a code or data
operand, or on the line before it. Placing them on the same line makes
the output a bit more compact, but if the label is longer than the label
column is wide, the subsequent fields can be pushed out of alignment.
The placement is configurable. Labels can be output on their own line:</p>
<ol>
<li>Only when required - labels will not be placed on a separate line
unless the assembler requires them to be.</li>
<li>When the label is wider than the field - labels will only be
placed on a separate line when they don't fit in the label column.</li>
<li>Whenever possible - labels are always placed on a separate line
when they are allowed to be. Most assemblers require that the label
be on the same line as assignment pseudo-ops,
e.g. "<code>FOO = $1000</code>".</li>
</ol>
<h2 id="project-properties">Project Properties</h2>

View File

@ -183,7 +183,7 @@ CopyData lda #&lt;addrs ;get pointer into
</div>
</div> <!-- grid-container -->
</div> <!-- main -->
<div id="prevnext">
<a href="using-sourcegen.html" class="btn-next">Next &raquo;</a>

View File

@ -91,7 +91,8 @@
</div>
<div class="grid-item-text">
<p>You can generate assembly source code from the disassembled data.
Select <samp>File &gt; Assemble</samp> (or hit <kbd class="key">Ctrl+Shift+A</kbd>)
Select <samp>File &gt; Generate Assembly</samp>
(or hit <kbd class="key">Ctrl+Shift+A</kbd>)
to open the source generation and assembly dialog.</p>
</div>
</div>