mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-30 01:50:10 +00:00
173 lines
5.6 KiB
C#
173 lines
5.6 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.Diagnostics;
|
|||
|
|
|||
|
namespace Asm65 {
|
|||
|
/// <summary>
|
|||
|
/// A value with 16 tri-state bits.
|
|||
|
/// </summary>
|
|||
|
public struct TriState16 {
|
|||
|
/// <summary>
|
|||
|
/// Two 16-bit values. The low 16 bits indicate that bit N is zero, the high
|
|||
|
/// 16 bits indicate that bit N is one. If neither or both are set, the value
|
|||
|
/// is undetermined and could be either.
|
|||
|
///
|
|||
|
/// While 0/0 and 1/1 both represent an indeterminate value, they're not equivalent.
|
|||
|
/// When two values are merged, a 0/0 bit has no effect on the result, while
|
|||
|
/// a 1/1 bit will force the merged bit to be indeterminate. We use UNSPECIFIED for
|
|||
|
/// 0/0 and INDETERMINATE for 1/1.
|
|||
|
///
|
|||
|
/// The default value for new instances is UNSPECIFIED for all bits.
|
|||
|
/// </summary>
|
|||
|
private ushort mZero, mOne;
|
|||
|
|
|||
|
public const int INDETERMINATE = -1;
|
|||
|
public const int UNSPECIFIED = -2;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Constructor; sets initial zero/one values.
|
|||
|
/// </summary>
|
|||
|
/// <param name="zeroes">16-bit value, with bits set for each known-zero.</param>
|
|||
|
/// <param name="ones">16-bit value, with bits set for each known-one.</param>
|
|||
|
public TriState16(ushort zeroes, ushort ones) {
|
|||
|
mZero = zeroes;
|
|||
|
mOne = ones;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Access the value as a single integer. Used for serialization.
|
|||
|
/// </summary>
|
|||
|
public int AsInt {
|
|||
|
get {
|
|||
|
return (int)mZero | ((int)mOne << 16);
|
|||
|
}
|
|||
|
set {
|
|||
|
mZero = (ushort) value;
|
|||
|
mOne = (ushort) (value >> 16);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Sets bit N to zero.
|
|||
|
/// </summary>
|
|||
|
public void SetZero(int bit) {
|
|||
|
Debug.Assert(bit >= 0 && bit < 16);
|
|||
|
|
|||
|
// clear 1-flag, set 0-flag
|
|||
|
//mValue = (mValue & ~(1U << (bit + 16))) | (1U << bit);
|
|||
|
mZero |= (ushort) (1U << bit);
|
|||
|
mOne &= (ushort) ~(1U << bit);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Sets bit N to one.
|
|||
|
/// </summary>
|
|||
|
public void SetOne(int bit) {
|
|||
|
Debug.Assert(bit >= 0 && bit < 16);
|
|||
|
|
|||
|
// clear 0-flag, set 1-flag
|
|||
|
//mValue = (mValue & ~(1U << bit)) | (1U << (bit + 16));
|
|||
|
mZero &= (ushort)~(1U << bit);
|
|||
|
mOne |= (ushort)(1U << bit);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Sets bit N to indeterminate.
|
|||
|
/// </summary>
|
|||
|
public void SetIndeterminate(int bit) {
|
|||
|
Debug.Assert(bit >= 0 && bit < 16);
|
|||
|
|
|||
|
// set both flags
|
|||
|
mZero |= (ushort)(1U << bit);
|
|||
|
mOne |= (ushort)(1U << bit);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Sets bit N to unspecified.
|
|||
|
/// </summary>
|
|||
|
public void SetUnspecified(int bit) {
|
|||
|
Debug.Assert(bit >= 0 && bit < 16);
|
|||
|
|
|||
|
// clear both flags
|
|||
|
mZero &= (ushort)~(1U << bit);
|
|||
|
mOne &= (ushort)~(1U << bit);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Merges bit states.
|
|||
|
/// </summary>
|
|||
|
/// <param name="other">Value to merge in.</param>
|
|||
|
public void Merge(TriState16 other) {
|
|||
|
//mValue |= other.mValue;
|
|||
|
mZero |= other.mZero;
|
|||
|
mOne |= other.mOne;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Applies a set of bits to an existing set, overriding any bits that aren't set
|
|||
|
/// to "unspecified" in the input.
|
|||
|
/// </summary>
|
|||
|
public void Apply(TriState16 overrides) {
|
|||
|
ushort mask = (ushort) ~(overrides.mZero | overrides.mOne);
|
|||
|
mZero = (ushort)((mZero & mask) | overrides.mZero);
|
|||
|
mOne = (ushort)((mOne & mask) | overrides.mOne);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns 0, 1, -1, or -2 depending on whether the specified bit is 0, 1,
|
|||
|
/// indeterminate, or unspecified.
|
|||
|
/// </summary>
|
|||
|
public int GetBit(int bit) {
|
|||
|
bool zero = ((mZero >> bit) & 0x01) != 0;
|
|||
|
bool one = ((mOne >> bit) & 0x01) != 0;
|
|||
|
if (zero ^ one) {
|
|||
|
// Only one of the bits is set.
|
|||
|
if (one) {
|
|||
|
return 1;
|
|||
|
} else {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Both or neither are set.
|
|||
|
if (zero) {
|
|||
|
return INDETERMINATE;
|
|||
|
} else {
|
|||
|
return UNSPECIFIED;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static bool operator ==(TriState16 a, TriState16 b) {
|
|||
|
return a.mZero == b.mZero && a.mOne == b.mOne;
|
|||
|
}
|
|||
|
public static bool operator !=(TriState16 a, TriState16 b) {
|
|||
|
return !(a == b);
|
|||
|
}
|
|||
|
public override bool Equals(object obj) {
|
|||
|
return obj is TriState16 && this == (TriState16)obj;
|
|||
|
}
|
|||
|
public override int GetHashCode() {
|
|||
|
return (mOne << 16) | mZero;
|
|||
|
}
|
|||
|
|
|||
|
public override string ToString() {
|
|||
|
return mZero.ToString("x4") + "-" + mOne.ToString("x4");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|