mirror of
https://github.com/fadden/6502bench.git
synced 2024-08-17 22:29:08 +00:00
My original goal was to add a sign-extended decimal format, but that turned out to be awkward. It works for data items and instructions with immediate operands (e.g. "LDA #-1"), but is either wrong or useless for address operands, since most assemblers treat integers as 32-bit values. (LDA -1 is not LDA $FFFF, it's LDA $FFFFFFFF, which is not useful unless your asm is doing an implicit mod.) There's also a bit of variability in how assemblers treat negative values, so I'm shelving the idea for now. I'm keeping the updated tests, which are now split into 6502 / 65816 parts. Also, updated the formatter to output all decimal values as unsigned. Most assemblers were fine with negative values, but 64tass .dword insists on positive. Rather than make the opcode conditional on the value's range, we now just always output unsigned decimal, which all current assemblers accept.
110 lines
4.3 KiB
C#
110 lines
4.3 KiB
C#
/*
|
|
* 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;
|
|
|
|
namespace CommonUtil {
|
|
public class BitTwiddle {
|
|
/// <summary>
|
|
/// Returns the argument, rounded up to the next highest power of 2. If the argument
|
|
/// is an exact power of two, it is returned unmodified.
|
|
/// </summary>
|
|
public static int RoundUpPowerOf2(int val) {
|
|
val--; // handle exact power of 2 case; works correctly for val=0
|
|
return NextHighestPowerOf2(val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the first power of 2 value that is higher than val. If the argument is
|
|
/// an exact power of two, the next power of 2 is returned.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Classic bit-twiddling approach. I can't find a "count leading zeroes" function
|
|
/// in C# that turns into a CPU instruction; if we had that, we could just use 1<<N.
|
|
/// </remarks>
|
|
public static int NextHighestPowerOf2(int val) {
|
|
val |= val >> 1; // "smear" bits across integer
|
|
val |= val >> 2;
|
|
val |= val >> 4;
|
|
val |= val >> 8;
|
|
val |= val >> 16;
|
|
return val + 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an integer in which the only bit set is the least-significant set bit in
|
|
/// the argument.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If you pass in 10110100, this will return 00000100.
|
|
///
|
|
/// Two's complement negation inverts and adds one, so 01100 --> 10011+1 --> 10100. The
|
|
/// only set bit they have in common is the one we want.
|
|
/// </remarks>
|
|
public static int IsolateLeastSignificantOne(int val) {
|
|
return val & -val;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the number of bits that are set in the argument.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If you pass in 10110100, this will return 4.
|
|
///
|
|
/// This comes from http://aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count) .
|
|
/// </remarks>
|
|
public static int CountOneBits(int val) {
|
|
// 32-bit recursive reduction using SWAR...
|
|
// but first step is mapping 2-bit values
|
|
// into sum of 2 1-bit values in sneaky way
|
|
val -= ((val >> 1) & 0x55555555);
|
|
val = (((val >> 2) & 0x33333333) + (val & 0x33333333));
|
|
val = (((val >> 4) + val) & 0x0f0f0f0f);
|
|
val += (val >> 8);
|
|
val += (val >> 16);
|
|
return (val & 0x0000003f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the number of trailing zero bits in the argument.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If you pass in 10110100, this will return 2.
|
|
///
|
|
/// Also from http://aggregate.org/MAGIC/ .
|
|
/// </remarks>
|
|
public static int CountTrailingZeroes(int val) {
|
|
// Lazy: reduce to least-significant 1 bit, subtract one to clear that bit and set
|
|
// all the bits to the right of it, then just count the 1s.
|
|
return CountOneBits(IsolateLeastSignificantOne(val) - 1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sign-extends an integer value.
|
|
/// </summary>
|
|
/// <param name="val">Value to extend.</param>
|
|
/// <param name="byteLen">Number of significant bytes (1-4).</param>
|
|
/// <returns>Sign-extended value, or original value if byteLen is invalid.</returns>
|
|
public static int SignExtend(int val, int byteLen) {
|
|
if (byteLen < 1 || byteLen >= 4) {
|
|
// invalid, or nothing to do
|
|
return val;
|
|
}
|
|
int shiftCount = (4 - byteLen) * 8;
|
|
return (val << shiftCount) >> shiftCount;
|
|
}
|
|
}
|
|
}
|