// // Carry.hpp // Clock Signal // // Created by Thomas Harte on 30/08/2023. // Copyright © 2023 Thomas Harte. All rights reserved. // #ifndef Carry_hpp #define Carry_hpp #include namespace Numeric { /// @returns @c true if from @c bit there was: /// • carry after calculating @c lhs + @c rhs if @c is_add is true; or /// • borrow after calculating @c lhs - @c rhs if @c is_add is false; /// producing @c result. template 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; } const bool carry = IntT(1 << bit) & (lhs | rhs) & ((lhs & rhs) | ~result); if constexpr (!is_add) { return !carry; } else { return carry; } } /// @returns @c true if there was carry into @c bit when computing either: /// • @c lhs + @c rhs; or /// • @c lhs - @c rhs; /// producing @c result. template bool carried_in(IntT lhs, IntT rhs, IntT result) { // 0 and 0 or 1 and 1 => did if 1. // 0 and 1 or 1 and 0 => did if 0. 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 constexpr IntT top_bit() { static_assert(!std::numeric_limits::is_signed); constexpr IntT max = std::numeric_limits::max(); return max - (max >> 1); } /// @returns The number of bits in @c IntT. template 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 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() & output_changed & ~input_differed; } else { return top_bit() & 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 */