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:
parent
4a803e2d43
commit
fbd647080d
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 Developer’s 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user