1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-29 10:50:28 +00:00
6502bench/CommonUtil/Container.cs
Andy McFadden 99cd0d3ac1 Improve handling of C64 PRG header
C64 PRG files are pretty common.  Their salient feature is that they
start with a 16-bit value that is used as the load address.  The
value is commonly generated by the assembler itself, rather than
explicitly added to the source file.

Not all assemblers know what a PRG file is, and some of them handle
it in ways that are difficult to guarantee in SourceGen.  ACME adds
the 16-bit header when the output file name ends in ".prg", cc65
uses a modified config file, 64tass uses a different command-line
option, and Merlin 32 has no idea what they are.

This change adds PRG file detection and handling to the 64tass code
generator.  Doing so required making a few changes to the gen/asm
interfaces, because we now need to have the generator pass additional
flags to the assembler, and sometimes we need code generation to
start somewhere other than offset zero.  Overall the changes were
pretty minor.

The 20042-address-changes test needed a 6502-only variant.  A new test
(20040-address-changes) has been added and given a PRG header.  As
part of this change the 65816 variant was changed to use addresses
in bank 2, which uncovered a code generation bug that this change
also fixes.

The 64tass --long-address flag doesn't appear to be necessary for
files <= 65536 bytes long, so we no longer emit it for those.

(issue #90)
2020-10-17 16:45:13 -07:00

113 lines
4.2 KiB
C#

/*
* Copyright 2018 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.Collections.ObjectModel;
using System.Linq;
namespace CommonUtil {
public class Container {
/// <summary>
/// Compares two lists of strings to see if their contents are equal. The lists
/// must contain the same strings, in the same order.
/// </summary>
/// <param name="l1">List #1.</param>
/// <param name="l2">List #2.</param>
/// <param name="comparer">String comparer (e.g. StringComparer.InvariantCulture). If
/// null, the default string comparer is used.</param>
/// <returns>True if the lists are equal.</returns>
public static bool StringListEquals(IList<string> l1, IList<string>l2,
StringComparer comparer) {
// Quick check for reference equality.
if (l1 == l2) {
return true;
}
return Enumerable.SequenceEqual<string>(l1, l2, comparer);
}
/// <summary>
/// Makes a deep copy of a string list.
/// </summary>
/// <param name="src">String list to copy.</param>
/// <returns>New string list.</returns>
public static List<string> CopyStringList(IList<string> src) {
List<string> dst = new List<string>(src.Count);
foreach (string str in src) {
dst.Add(str);
}
return dst;
}
/// <summary>
/// Compares two Dictionaries to see if their contents are equal. Key and value types
/// must have correctly-implemented equality checks. (I contend this works incorrectly
/// for float -- 5.0f is equal to the integer 5.)
/// </summary>
/// <remarks>
/// https://stackoverflow.com/q/3804367/294248
///
/// TODO: make this work right for float/int comparisons
/// </remarks>
/// <typeparam name="TKey">Dictionary key type.</typeparam>
/// <typeparam name="TValue">Dictionary value type.</typeparam>
/// <param name="dict1">Dictionary #1.</param>
/// <param name="dict2">Dictionary #2.</param>
/// <returns>True if equal, false if not.</returns>
public static bool CompareDicts<TKey, TValue>(
Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue> dict2) {
if (dict1 == dict2) {
return true;
}
if (dict1 == null || dict2 == null) {
return false;
}
if (dict1.Count != dict2.Count) {
return false;
}
#if false
var valueComparer = EqualityComparer<TValue>.Default;
foreach (var kvp in dict1) {
TValue value2;
if (!dict2.TryGetValue(kvp.Key, out value2)) return false;
if (!valueComparer.Equals(kvp.Value, value2)) return false;
}
return true;
#else
// Check to see if there are any elements in the first that are not in the second.
return !dict1.Except(dict2).Any();
#endif
}
public static bool CompareDicts<TKey, TValue>(
ReadOnlyDictionary<TKey, TValue> dict1, ReadOnlyDictionary<TKey, TValue> dict2) {
if (dict1 == dict2) {
return true;
}
if (dict1 == null || dict2 == null) {
return false;
}
if (dict1.Count != dict2.Count) {
return false;
}
// Check to see if there are any elements in the first that are not in the second.
return !dict1.Except(dict2).Any();
}
}
}