mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Resolve for work factored out.
This commit is contained in:
parent
29a921f764
commit
de230fb6be
@ -9,6 +9,7 @@
|
||||
#ifndef InstructionSets_M68k_PerformImplementation_h
|
||||
#define InstructionSets_M68k_PerformImplementation_h
|
||||
|
||||
#include "../../../Numeric/Carry.hpp"
|
||||
#include "../ExceptionVectors.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@ -25,28 +26,6 @@ inline int32_t s_extend16(uint16_t x) { return int32_t(int16_t(x)); }
|
||||
|
||||
namespace Primitive {
|
||||
|
||||
/// @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 An int with the top bit indicating whether overflow occurred when @c source and @c destination
|
||||
/// were either added (if @c is_add is true) or subtracted (if @c is_add is false) and the result was @c result.
|
||||
/// All other bits will be clear.
|
||||
template <bool is_add, typename IntT>
|
||||
static Status::FlagT overflow(IntT source, IntT destination, IntT result) {
|
||||
const IntT output_changed = result ^ destination;
|
||||
const IntT input_differed = source ^ destination;
|
||||
|
||||
if constexpr (is_add) {
|
||||
return top_bit<IntT>() & output_changed & ~input_differed;
|
||||
} else {
|
||||
return top_bit<IntT>() & output_changed & input_differed;
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs an add or subtract (as per @c is_add) between @c source and @c destination,
|
||||
/// updating @c status. @c is_extend indicates whether this is an extend operation (e.g. ADDX)
|
||||
/// or a plain one (e.g. ADD).
|
||||
@ -81,7 +60,7 @@ static void add_sub(IntT source, IntT &destination, Status &status) {
|
||||
status.zero_result = Status::FlagT(result);
|
||||
}
|
||||
status.set_negative(result);
|
||||
status.overflow_flag = overflow<is_add>(source, destination, result);
|
||||
status.overflow_flag = Numeric::overflow<is_add>(destination, source, result);
|
||||
destination = result;
|
||||
}
|
||||
|
||||
@ -143,7 +122,7 @@ void compare(IntT source, IntT destination, Status &status) {
|
||||
const IntT result = destination - source;
|
||||
status.carry_flag = result > destination;
|
||||
status.set_neg_zero(result);
|
||||
status.overflow_flag = Primitive::overflow<false>(source, destination, result);
|
||||
status.overflow_flag = Numeric::overflow<false>(destination, source, result);
|
||||
}
|
||||
|
||||
/// @returns the name of the bit to be used as a mask for BCLR, BCHG, BSET or BTST for
|
||||
@ -293,7 +272,7 @@ template <bool is_extend, typename IntT> void negative(IntT &source, Status &sta
|
||||
}
|
||||
status.extend_flag = status.carry_flag = result; // i.e. any value other than 0 will result in carry.
|
||||
status.set_negative(result);
|
||||
status.overflow_flag = Primitive::overflow<false>(source, IntT(0), result);
|
||||
status.overflow_flag = Numeric::overflow<false>(IntT(0), source, result);
|
||||
|
||||
source = result;
|
||||
}
|
||||
@ -311,11 +290,6 @@ template <typename IntT, typename FlowController> int shift_count(uint8_t source
|
||||
return count;
|
||||
}
|
||||
|
||||
/// @returns The number of bits in @c IntT.
|
||||
template <typename IntT> constexpr int bit_size() {
|
||||
return sizeof(IntT) * 8;
|
||||
}
|
||||
|
||||
/// Perform an arithmetic or logical shift, i.e. any of LSL, LSR, ASL or ASR.
|
||||
template <Operation operation, typename IntT, typename FlowController> void shift(uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) {
|
||||
static_assert(
|
||||
@ -325,7 +299,7 @@ template <Operation operation, typename IntT, typename FlowController> void shif
|
||||
operation == Operation::LSRb || operation == Operation::LSRw || operation == Operation::LSRl
|
||||
);
|
||||
|
||||
constexpr auto size = bit_size<IntT>();
|
||||
constexpr auto size = Numeric::bit_size<IntT>();
|
||||
const auto shift = shift_count<IntT>(uint8_t(source), flow_controller);
|
||||
|
||||
if(!shift) {
|
||||
@ -355,7 +329,7 @@ template <Operation operation, typename IntT, typename FlowController> void shif
|
||||
if(shift > size) {
|
||||
status.carry_flag = status.extend_flag = 0;
|
||||
} else {
|
||||
status.carry_flag = status.extend_flag = (destination << (shift - 1)) & top_bit<IntT>();
|
||||
status.carry_flag = status.extend_flag = (destination << (shift - 1)) & Numeric::top_bit<IntT>();
|
||||
}
|
||||
|
||||
if(type == Type::LSL) {
|
||||
@ -370,7 +344,7 @@ template <Operation operation, typename IntT, typename FlowController> void shif
|
||||
// For a shift of n places, overflow will be set if the top n+1 bits were not
|
||||
// all the same value.
|
||||
const auto affected_bits = IntT(
|
||||
~((top_bit<IntT>() >> shift) - 1)
|
||||
~((Numeric::top_bit<IntT>() >> shift) - 1)
|
||||
); // e.g. shift = 1 => ~((0x80 >> 1) - 1) = ~(0x40 - 1) = ~0x3f = 0xc0, i.e. if shift is
|
||||
// 1 then the top two bits are relevant to whether there was overflow. If they have the
|
||||
// same value, i.e. are both 0 or are both 1, then there wasn't. Otherwise there was.
|
||||
@ -396,7 +370,7 @@ template <Operation operation, typename IntT, typename FlowController> void shif
|
||||
|
||||
const IntT sign_word =
|
||||
type == Type::LSR ?
|
||||
0 : (destination & top_bit<IntT>() ? IntT(~0) : 0);
|
||||
0 : (destination & Numeric::top_bit<IntT>() ? IntT(~0) : 0);
|
||||
|
||||
if(shift >= size) {
|
||||
destination = sign_word;
|
||||
@ -417,7 +391,7 @@ template <Operation operation, typename IntT, typename FlowController> void rota
|
||||
operation == Operation::RORb || operation == Operation::RORw || operation == Operation::RORl
|
||||
);
|
||||
|
||||
constexpr auto size = bit_size<IntT>();
|
||||
constexpr auto size = Numeric::bit_size<IntT>();
|
||||
auto shift = shift_count<IntT>(uint8_t(source), flow_controller);
|
||||
|
||||
if(!shift) {
|
||||
@ -442,7 +416,7 @@ template <Operation operation, typename IntT, typename FlowController> void rota
|
||||
(destination << (size - shift))
|
||||
);
|
||||
}
|
||||
status.carry_flag = Status::FlagT(destination & top_bit<IntT>());
|
||||
status.carry_flag = Status::FlagT(destination & Numeric::top_bit<IntT>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -458,7 +432,7 @@ template <Operation operation, typename IntT, typename FlowController> void rox(
|
||||
operation == Operation::ROXRb || operation == Operation::ROXRw || operation == Operation::ROXRl
|
||||
);
|
||||
|
||||
constexpr auto size = bit_size<IntT>();
|
||||
constexpr auto size = Numeric::bit_size<IntT>();
|
||||
auto shift = shift_count<IntT>(uint8_t(source), flow_controller) % (size + 1);
|
||||
|
||||
if(!shift) {
|
||||
@ -469,9 +443,9 @@ template <Operation operation, typename IntT, typename FlowController> void rox(
|
||||
case Operation::ROXLb: case Operation::ROXLw: case Operation::ROXLl:
|
||||
status.carry_flag = Status::FlagT((destination >> (size - shift)) & 1);
|
||||
|
||||
if(shift == bit_size<IntT>()) {
|
||||
if(shift == Numeric::bit_size<IntT>()) {
|
||||
destination = IntT(
|
||||
(status.extend_flag ? top_bit<IntT>() : 0) |
|
||||
(status.extend_flag ? Numeric::top_bit<IntT>() : 0) |
|
||||
(destination >> 1)
|
||||
);
|
||||
} else if(shift == 1) {
|
||||
@ -491,7 +465,7 @@ template <Operation operation, typename IntT, typename FlowController> void rox(
|
||||
case Operation::ROXRb: case Operation::ROXRw: case Operation::ROXRl:
|
||||
status.carry_flag = Status::FlagT(destination & (1 << (shift - 1)));
|
||||
|
||||
if(shift == bit_size<IntT>()) {
|
||||
if(shift == Numeric::bit_size<IntT>()) {
|
||||
destination = IntT(
|
||||
(status.extend_flag ? 1 : 0) |
|
||||
(destination << 1)
|
||||
@ -499,12 +473,12 @@ template <Operation operation, typename IntT, typename FlowController> void rox(
|
||||
} else if(shift == 1) {
|
||||
destination = IntT(
|
||||
(destination >> 1) |
|
||||
(status.extend_flag ? top_bit<IntT>() : 0)
|
||||
(status.extend_flag ? Numeric::top_bit<IntT>() : 0)
|
||||
);
|
||||
} else {
|
||||
destination = IntT(
|
||||
(destination >> shift) |
|
||||
((status.extend_flag ? top_bit<IntT>() : 0) >> (shift - 1)) |
|
||||
((status.extend_flag ? Numeric::top_bit<IntT>() : 0) >> (shift - 1)) |
|
||||
(destination << (size + 1 - shift))
|
||||
);
|
||||
}
|
||||
@ -882,14 +856,14 @@ template <
|
||||
Shifts and rotates.
|
||||
*/
|
||||
case Operation::ASLm:
|
||||
status.extend_flag = status.carry_flag = src.w & Primitive::top_bit<uint16_t>();
|
||||
status.overflow_flag = (src.w ^ (src.w << 1)) & Primitive::top_bit<uint16_t>();
|
||||
status.extend_flag = status.carry_flag = src.w & Numeric::top_bit<uint16_t>();
|
||||
status.overflow_flag = (src.w ^ (src.w << 1)) & Numeric::top_bit<uint16_t>();
|
||||
src.w <<= 1;
|
||||
status.set_neg_zero(src.w);
|
||||
break;
|
||||
|
||||
case Operation::LSLm:
|
||||
status.extend_flag = status.carry_flag = src.w & Primitive::top_bit<uint16_t>();
|
||||
status.extend_flag = status.carry_flag = src.w & Numeric::top_bit<uint16_t>();
|
||||
status.overflow_flag = 0;
|
||||
src.w <<= 1;
|
||||
status.set_neg_zero(src.w);
|
||||
@ -898,7 +872,7 @@ template <
|
||||
case Operation::ASRm:
|
||||
status.extend_flag = status.carry_flag = src.w & 1;
|
||||
status.overflow_flag = 0;
|
||||
src.w = (src.w & Primitive::top_bit<uint16_t>()) | (src.w >> 1);
|
||||
src.w = (src.w & Numeric::top_bit<uint16_t>()) | (src.w >> 1);
|
||||
status.set_neg_zero(src.w);
|
||||
break;
|
||||
|
||||
@ -918,13 +892,13 @@ template <
|
||||
|
||||
case Operation::RORm:
|
||||
src.w = uint16_t((src.w >> 1) | (src.w << 15));
|
||||
status.carry_flag = src.w & Primitive::top_bit<uint16_t>();
|
||||
status.carry_flag = src.w & Numeric::top_bit<uint16_t>();
|
||||
status.overflow_flag = 0;
|
||||
status.set_neg_zero(src.w);
|
||||
break;
|
||||
|
||||
case Operation::ROXLm:
|
||||
status.carry_flag = src.w & Primitive::top_bit<uint16_t>();
|
||||
status.carry_flag = src.w & Numeric::top_bit<uint16_t>();
|
||||
src.w = uint16_t((src.w << 1) | (status.extend_flag ? 0x0001 : 0x0000));
|
||||
status.extend_flag = status.carry_flag;
|
||||
status.overflow_flag = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user