1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-18 14:40:33 +00:00

Start factoring out useful ALU stuff.

This commit is contained in:
Thomas Harte 2023-10-11 11:06:20 -04:00
parent 4a803e2d43
commit fbd647080d
3 changed files with 107 additions and 102 deletions
InstructionSets/x86/Implementation
Numeric
OSBindings/Mac/Clock SignalTests

@ -149,47 +149,6 @@ IntT *resolve(
namespace Primitive {
//
// BEGIN TEMPORARY COPY AND PASTE SECTION.
//
// The following are largely excised from the M68k PerformImplementation.hpp; if there proves to be no
// reason further to specialise them, there'll be a factoring out. In some cases I've tightened the documentation.
//
/// @returns An int of type @c IntT with only the most-significant bit set.
template <typename IntT> constexpr IntT top_bit() {
static_assert(!std::numeric_limits<IntT>::is_signed);
constexpr IntT max = std::numeric_limits<IntT>::max();
return max - (max >> 1);
}
/// @returns The number of bits in @c IntT.
template <typename IntT> constexpr int bit_size() {
return sizeof(IntT) * 8;
}
/// @returns An int with the top bit indicating whether overflow occurred during the calculation of
/// • @c lhs + @c rhs (if @c is_add is true); or
/// • @c lhs - @c rhs (if @c is_add is false)
/// and the result was @c result. All other bits will be clear.
template <bool is_add, typename IntT>
IntT overflow(IntT lhs, IntT rhs, IntT result) {
const IntT output_changed = result ^ lhs;
const IntT input_differed = lhs ^ rhs;
if constexpr (is_add) {
return top_bit<IntT>() & output_changed & ~input_differed;
} else {
return top_bit<IntT>() & output_changed & input_differed;
}
}
// NOTE TO FUTURE SELF: the original 68k `overflow` treats lhs and rhs the other way
// around, affecting subtractive overflow. Be careful.
//
// END COPY AND PASTE SECTION.
//
//
// Comments below on intended functioning of each operation come from the 1997 edition of the
// Intel Architecture Software Developers Manual; that year all such definitions still fitted within a
@ -410,11 +369,11 @@ void add(IntT &destination, IntT source, Status &status) {
*/
const IntT result = destination + source + (with_carry ? status.carry_bit<IntT>() : 0);
status.carry = Numeric::carried_out<true, bit_size<IntT>() - 1>(destination, source, result);
status.carry = Numeric::carried_out<true, Numeric::bit_size<IntT>() - 1>(destination, source, result);
status.auxiliary_carry = Numeric::carried_in<4>(destination, source, result);
status.sign = result & top_bit<IntT>();
status.sign = result & Numeric::top_bit<IntT>();
status.zero = status.parity = result;
status.overflow = overflow<true, IntT>(destination, source, result);
status.overflow = Numeric::overflow<true, IntT>(destination, source, result);
destination = result;
}
@ -429,11 +388,11 @@ void sub(IntT &destination, IntT source, Status &status) {
*/
const IntT result = destination - source - (with_borrow ? status.carry_bit<IntT>() : 0);
status.carry = Numeric::carried_out<false, bit_size<IntT>() - 1>(destination, source, result);
status.carry = Numeric::carried_out<false, Numeric::bit_size<IntT>() - 1>(destination, source, result);
status.auxiliary_carry = Numeric::carried_in<4>(destination, source, result);
status.sign = result & top_bit<IntT>();
status.sign = result & Numeric::top_bit<IntT>();
status.zero = status.parity = result;
status.overflow = overflow<false, IntT>(destination, source, result);
status.overflow = Numeric::overflow<false, IntT>(destination, source, result);
if constexpr (write_back) {
destination = result;
@ -460,7 +419,7 @@ void test(IntT &destination, IntT source, Status &status) {
*/
const IntT result = destination & source;
status.sign = result & top_bit<IntT>();
status.sign = result & Numeric::top_bit<IntT>();
status.zero = result;
status.carry = status.overflow = 0;
status.parity = result;
@ -529,7 +488,7 @@ void imul(IntT &destination_high, IntT &destination_low, IntT source, Status &st
destination_high = (sIntT(destination_low) * sIntT(source)) >> (8 * sizeof(IntT));
destination_low = IntT(sIntT(destination_low) * sIntT(source));
const auto sign_extension = (destination_low & top_bit<IntT>()) ? IntT(~0) : 0;
const auto sign_extension = (destination_low & Numeric::top_bit<IntT>()) ? IntT(~0) : 0;
status.overflow = status.carry = destination_high != sign_extension;
}
@ -657,8 +616,8 @@ void inc(IntT &destination, Status &status) {
*/
++destination;
status.overflow = destination == top_bit<IntT>();
status.sign = destination & top_bit<IntT>();
status.overflow = destination == Numeric::top_bit<IntT>();
status.sign = destination & Numeric::top_bit<IntT>();
status.zero = status.parity = destination;
status.auxiliary_carry = ((destination - 1) ^ destination) & 0x10;
}
@ -691,11 +650,11 @@ void dec(IntT &destination, Status &status) {
The CF flag is not affected.
The OF, SF, ZF, AF, and PF flags are set according to the result.
*/
status.overflow = destination == top_bit<IntT>();
status.overflow = destination == Numeric::top_bit<IntT>();
--destination;
status.sign = destination & top_bit<IntT>();
status.sign = destination & Numeric::top_bit<IntT>();
status.zero = status.parity = destination;
status.auxiliary_carry = ((destination + 1) ^ destination) & 0x10;
}
@ -713,7 +672,7 @@ void and_(IntT &destination, IntT source, Status &status) {
status.overflow = 0;
status.carry = 0;
status.sign = destination & top_bit<IntT>();
status.sign = destination & Numeric::top_bit<IntT>();
status.zero = status.parity = destination;
}
@ -730,7 +689,7 @@ void or_(IntT &destination, IntT source, Status &status) {
status.overflow = 0;
status.carry = 0;
status.sign = destination & top_bit<IntT>();
status.sign = destination & Numeric::top_bit<IntT>();
status.zero = status.parity = destination;
}
@ -747,7 +706,7 @@ void xor_(IntT &destination, IntT source, Status &status) {
status.overflow = 0;
status.carry = 0;
status.sign = destination & top_bit<IntT>();
status.sign = destination & Numeric::top_bit<IntT>();
status.zero = status.parity = destination;
}
@ -769,8 +728,8 @@ void neg(IntT &destination, Status &status) {
destination = -destination;
status.carry = destination;
status.overflow = destination == top_bit<IntT>();
status.sign = destination & top_bit<IntT>();
status.overflow = destination == Numeric::top_bit<IntT>();
status.sign = destination & Numeric::top_bit<IntT>();
status.zero = status.parity = destination;
}
@ -841,7 +800,7 @@ void cbw(IntT &ax) {
template <typename IntT>
void cwd(IntT &dx, IntT ax) {
dx = ax & top_bit<IntT>() ? IntT(~0) : IntT(0);
dx = ax & Numeric::top_bit<IntT>() ? IntT(~0) : IntT(0);
}
inline void clc(Status &status) { status.carry = 0; }

@ -16,9 +16,17 @@ namespace Numeric {
/// • borrow after calculating @c lhs - @c rhs if @c is_add is false;
/// producing @c result.
template <bool is_add, int bit, typename IntT> bool carried_out(IntT lhs, IntT rhs, IntT result) {
// Additive:
//
// 0 and 0 => didn't.
// 0 and 1 or 1 and 0 => did if 0.
// 1 and 1 => did.
//
// Subtractive:
//
// 1 and 0 => didn't
// 1 and 1 or 0 and 0 => did if 1.
// 0 and 1 => did.
if constexpr (!is_add) {
rhs = ~rhs;
}
@ -40,6 +48,47 @@ template <int bit, typename IntT> bool carried_in(IntT lhs, IntT rhs, IntT resul
return IntT(1 << bit) & (lhs ^ rhs ^ result);
}
//
// BEGIN TEMPORARY COPY AND PASTE SECTION.
//
// The following are largely excised from the M68k PerformImplementation.hpp; if there proves to be no
// reason further to specialise them, there'll be a factoring out. In some cases I've tightened the documentation.
//
/// @returns An int of type @c IntT with only the most-significant bit set.
template <typename IntT> constexpr IntT top_bit() {
static_assert(!std::numeric_limits<IntT>::is_signed);
constexpr IntT max = std::numeric_limits<IntT>::max();
return max - (max >> 1);
}
/// @returns The number of bits in @c IntT.
template <typename IntT> constexpr int bit_size() {
return sizeof(IntT) * 8;
}
/// @returns An int with the top bit indicating whether overflow occurred during the calculation of
/// • @c lhs + @c rhs (if @c is_add is true); or
/// • @c lhs - @c rhs (if @c is_add is false)
/// and the result was @c result. All other bits will be clear.
template <bool is_add, typename IntT>
IntT overflow(IntT lhs, IntT rhs, IntT result) {
const IntT output_changed = result ^ lhs;
const IntT input_differed = lhs ^ rhs;
if constexpr (is_add) {
return top_bit<IntT>() & output_changed & ~input_differed;
} else {
return top_bit<IntT>() & output_changed & input_differed;
}
}
// NOTE TO FUTURE SELF: the original 68k `overflow` treats lhs and rhs the other way
// around, affecting subtractive overflow. Be careful.
//
// END COPY AND PASTE SECTION.
//
}
#endif /* Carry_hpp */

@ -282,7 +282,7 @@ struct FailedExecution {
- (NSArray<NSString *> *)testFiles {
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
NSSet *allowList = [NSSet setWithArray:@[
/* @"37.json.gz", // AAA
@"37.json.gz", // AAA
@"3F.json.gz", // AAS
@"D4.json.gz", // AAM
@"D5.json.gz", // AAD
@ -297,7 +297,7 @@ struct FailedExecution {
@"DC.json.gz", @"DD.json.gz", @"DE.json.gz", @"DE.json.gz",
// Untested: HLT, WAIT
*/
// ADC
@"10.json.gz", @"11.json.gz", @"12.json.gz", @"13.json.gz", @"14.json.gz", @"15.json.gz",
@"80.2.json.gz", @"81.2.json.gz", @"83.2.json.gz",
@ -313,7 +313,7 @@ struct FailedExecution {
// SUB
@"28.json.gz", @"29.json.gz", @"2A.json.gz", @"2B.json.gz", @"2C.json.gz", @"2D.json.gz",
@"80.5.json.gz", @"81.5.json.gz", @"83.5.json.gz",
/*
// MUL
@"F6.4.json.gz", @"F7.4.json.gz",
@ -324,41 +324,41 @@ struct FailedExecution {
@"F6.6.json.gz", @"F7.6.json.gz",
// IDIV
@"F6.7.json.gz", @"F7.7.json.gz",*/
@"F6.7.json.gz", @"F7.7.json.gz",
// INC
// @"40.json.gz", @"41.json.gz", @"42.json.gz", @"43.json.gz",
// @"44.json.gz", @"45.json.gz", @"46.json.gz", @"47.json.gz",
// @"FE.0.json.gz",
// @"FF.0.json.gz",
@"40.json.gz", @"41.json.gz", @"42.json.gz", @"43.json.gz",
@"44.json.gz", @"45.json.gz", @"46.json.gz", @"47.json.gz",
@"FE.0.json.gz",
@"FF.0.json.gz",
// DEC
// @"48.json.gz", @"49.json.gz", @"4A.json.gz", @"4B.json.gz",
// @"4C.json.gz", @"4D.json.gz", @"4E.json.gz", @"4F.json.gz",
// @"FE.1.json.gz",
// @"FF.1.json.gz",
@"48.json.gz", @"49.json.gz", @"4A.json.gz", @"4B.json.gz",
@"4C.json.gz", @"4D.json.gz", @"4E.json.gz", @"4F.json.gz",
@"FE.1.json.gz",
@"FF.1.json.gz",
// TODO: IN, OUT
// @"70.json.gz", // JO
// @"71.json.gz", // JNO
// @"72.json.gz", // JB
// @"73.json.gz", // JNB
// @"74.json.gz", // JZ
// @"75.json.gz", // JNZ
// @"76.json.gz", // JBE
// @"77.json.gz", // JNBE
// @"78.json.gz", // JS
// @"79.json.gz", // JNS
// @"7A.json.gz", // JP
// @"7B.json.gz", // JNP
// @"7C.json.gz", // JL
// @"7D.json.gz", // JNL
// @"7E.json.gz", // JLE
// @"7F.json.gz", // JNLE
@"70.json.gz", // JO
@"71.json.gz", // JNO
@"72.json.gz", // JB
@"73.json.gz", // JNB
@"74.json.gz", // JZ
@"75.json.gz", // JNZ
@"76.json.gz", // JBE
@"77.json.gz", // JNBE
@"78.json.gz", // JS
@"79.json.gz", // JNS
@"7A.json.gz", // JP
@"7B.json.gz", // JNP
@"7C.json.gz", // JL
@"7D.json.gz", // JNL
@"7E.json.gz", // JLE
@"7F.json.gz", // JNLE
// CALL
/* @"E8.json.gz", @"FF.2.json.gz",
@"E8.json.gz", @"FF.2.json.gz",
@"9A.json.gz", @"FF.3.json.gz",
// TODO: IRET
@ -388,15 +388,13 @@ struct FailedExecution {
// XOR
@"30.json.gz", @"31.json.gz", @"32.json.gz", @"33.json.gz", @"34.json.gz", @"35.json.gz",
@"80.6.json.gz", @"81.6.json.gz", @"83.6.json.gz",
*/
// // NEG
// @"F6.3.json.gz", @"F7.3.json.gz",
//
// // NOT
// @"F6.2.json.gz", @"F7.2.json.gz",
// NEG
@"F6.3.json.gz", @"F7.3.json.gz",
// NOT
@"F6.2.json.gz", @"F7.2.json.gz",
/*
// NOP
@"90.json.gz",
@ -410,7 +408,6 @@ struct FailedExecution {
@"FD.json.gz", // STD
@"FB.json.gz", // STI
@"F5.json.gz", // CMC
*/
// CMP
@"38.json.gz", @"39.json.gz", @"3A.json.gz",
@ -418,14 +415,14 @@ struct FailedExecution {
@"80.7.json.gz", @"81.7.json.gz", @"83.7.json.gz",
// TEST
// @"84.json.gz", @"85.json.gz",
// @"A8.json.gz", @"A9.json.gz",
// @"F6.0.json.gz", @"F7.0.json.gz",
@"84.json.gz", @"85.json.gz",
@"A8.json.gz", @"A9.json.gz",
@"F6.0.json.gz", @"F7.0.json.gz",
// XCHG
// @"86.json.gz", @"87.json.gz",
// @"91.json.gz", @"92.json.gz", @"93.json.gz", @"94.json.gz",
// @"95.json.gz", @"96.json.gz", @"97.json.gz",
@"86.json.gz", @"87.json.gz",
@"91.json.gz", @"92.json.gz", @"93.json.gz", @"94.json.gz",
@"95.json.gz", @"96.json.gz", @"97.json.gz",
// TODO: XLAT
// TODO: SALC, SETMO, SETMOC