mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Merge branch '68000Mk2' into InMacintosh
This commit is contained in:
commit
a292483344
@ -828,14 +828,14 @@ template <
|
||||
set_neg_zero(v, m); \
|
||||
status.overflow_flag = (Status::FlagT(value) ^ status.zero_result) & Status::FlagT(m);
|
||||
|
||||
#define decode_shift_count() \
|
||||
#define decode_shift_count(type) \
|
||||
int shift_count = src.l & 63; \
|
||||
flow_controller.did_shift(shift_count);
|
||||
flow_controller.template did_shift<type>(shift_count);
|
||||
|
||||
#define set_flags_w(t) set_flags(src.w, 0x8000, t)
|
||||
|
||||
#define asl(destination, size) {\
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
const auto value = destination; \
|
||||
\
|
||||
if(!shift_count) { \
|
||||
@ -865,7 +865,7 @@ template <
|
||||
case Operation::ASLl: asl(dest.l, 32); break;
|
||||
|
||||
#define asr(destination, size) {\
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
const auto value = destination; \
|
||||
\
|
||||
if(!shift_count) { \
|
||||
@ -909,7 +909,7 @@ template <
|
||||
status.carry_flag = value & (t);
|
||||
|
||||
#define lsl(destination, size) {\
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
const auto value = destination; \
|
||||
\
|
||||
if(!shift_count) { \
|
||||
@ -933,7 +933,7 @@ template <
|
||||
case Operation::LSLl: lsl(dest.l, 32); break;
|
||||
|
||||
#define lsr(destination, size) {\
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
const auto value = destination; \
|
||||
\
|
||||
if(!shift_count) { \
|
||||
@ -957,7 +957,7 @@ template <
|
||||
case Operation::LSRl: lsr(dest.l, 32); break;
|
||||
|
||||
#define rol(destination, size) { \
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
const auto value = destination; \
|
||||
\
|
||||
if(!shift_count) { \
|
||||
@ -985,7 +985,7 @@ template <
|
||||
case Operation::ROLl: rol(dest.l, 32); break;
|
||||
|
||||
#define ror(destination, size) { \
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
const auto value = destination; \
|
||||
\
|
||||
if(!shift_count) { \
|
||||
@ -1013,7 +1013,7 @@ template <
|
||||
case Operation::RORl: ror(dest.l, 32); break;
|
||||
|
||||
#define roxl(destination, size) { \
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
\
|
||||
shift_count %= (size + 1); \
|
||||
uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \
|
||||
@ -1037,7 +1037,7 @@ template <
|
||||
case Operation::ROXLl: roxl(dest.l, 32); break;
|
||||
|
||||
#define roxr(destination, size) { \
|
||||
decode_shift_count(); \
|
||||
decode_shift_count(decltype(destination)); \
|
||||
\
|
||||
shift_count %= (size + 1); \
|
||||
uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \
|
||||
|
@ -32,8 +32,11 @@ struct NullFlowController {
|
||||
/// Indicates that a @c CHK was performed, along with whether the result @c was_under zero or @c was_over the source operand.
|
||||
void did_chk([[maybe_unused]] bool was_under, [[maybe_unused]] bool was_over) {}
|
||||
|
||||
/// Indicates an in-register shift or roll occurred, providing the number of bits shifted by.
|
||||
void did_shift([[maybe_unused]] int bit_count) {}
|
||||
/// Indicates an in-register shift or roll occurred, providing the number of bits shifted by
|
||||
/// and the type shifted.
|
||||
///
|
||||
/// @c IntT may be uint8_t, uint16_t or uint32_t.
|
||||
template <typename IntT> void did_shift([[maybe_unused]] int bit_count) {}
|
||||
|
||||
/// Indicates that a @c DIVU was performed, providing the @c dividend and @c divisor.
|
||||
/// If @c did_overflow is @c true then the divide ended in overflow.
|
||||
|
@ -870,7 +870,16 @@
|
||||
XCTAssertEqual(state.registers.data[1], 0x1fffffff);
|
||||
XCTAssertEqual(state.registers.supervisor_stack_pointer, initial_sp - 6);
|
||||
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
|
||||
XCTAssertEqual(44, self.machine->get_cycle_count());
|
||||
|
||||
// Total expected bus pattern:
|
||||
//
|
||||
// np | nn nn | nw nw nw np np np n np = 42 cycles
|
||||
//
|
||||
// Noted: Yacht shows a total of three nps for a DIVS #;
|
||||
// I believe this is incorrect as it includes two in the
|
||||
// '1st op (ea)' stage, but an immediate word causes
|
||||
// only one elsewhere.
|
||||
XCTAssertEqual(42, self.machine->get_cycle_count());
|
||||
|
||||
// Check stack contents; should be PC.l, PC.h and status register.
|
||||
// Assumed: the program counter on the stack is that of the
|
||||
@ -908,7 +917,11 @@
|
||||
|
||||
const auto state = self.machine->get_processor_state();
|
||||
XCTAssertEqual(state.registers.data[1], 0x4768f231);
|
||||
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow);
|
||||
|
||||
// This test should produce overflow; so don't test N or Z flags.
|
||||
XCTAssertEqual(
|
||||
state.registers.status & (ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend),
|
||||
ConditionCode::Extend | ConditionCode::Overflow);
|
||||
XCTAssertEqual(14, self.machine->get_cycle_count());
|
||||
}
|
||||
|
||||
@ -917,7 +930,10 @@
|
||||
|
||||
const auto state = self.machine->get_processor_state();
|
||||
XCTAssertEqual(state.registers.data[1], 0x4768f231);
|
||||
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow);
|
||||
// This test should also produce overflow; so don't test N or Z flags.
|
||||
XCTAssertEqual(
|
||||
state.registers.status & (ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend),
|
||||
ConditionCode::Extend | ConditionCode::Overflow);
|
||||
XCTAssertEqual(14, self.machine->get_cycle_count());
|
||||
}
|
||||
|
||||
|
@ -592,6 +592,11 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
|
||||
// Signal the bus handler if requested.
|
||||
if constexpr (signal_will_perform) {
|
||||
// Set the state to Decode, so that if the callee pulls any shenanigans in order
|
||||
// to force an exit here, the interpreter can resume without skipping a beat.
|
||||
//
|
||||
// signal_will_perform is overtly a debugging/testing feature.
|
||||
state_ = Decode;
|
||||
bus_handler_.will_perform(instruction_address_.l, opcode_);
|
||||
}
|
||||
|
||||
@ -772,19 +777,15 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
|
||||
Duplicate(SUBAw, ADDAw) StdCASE(ADDAw, perform_state_ = Perform_np_nn)
|
||||
Duplicate(SUBAl, ADDAl) StdCASE(ADDAl, {
|
||||
if(instruction_.mode(1) == Mode::AddressRegisterDirect) {
|
||||
perform_state_ = Perform_np_nn;
|
||||
} else {
|
||||
switch(instruction_.mode(0)) {
|
||||
default:
|
||||
perform_state_ = Perform_np_n;
|
||||
break;
|
||||
case Mode::DataRegisterDirect:
|
||||
case Mode::AddressRegisterDirect:
|
||||
case Mode::ImmediateData:
|
||||
perform_state_ = Perform_np_nn;
|
||||
break;
|
||||
}
|
||||
switch(instruction_.mode(0)) {
|
||||
default:
|
||||
perform_state_ = Perform_np_n;
|
||||
break;
|
||||
case Mode::DataRegisterDirect:
|
||||
case Mode::AddressRegisterDirect:
|
||||
case Mode::ImmediateData:
|
||||
perform_state_ = Perform_np_nn;
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
@ -2546,7 +2547,7 @@ template <bool did_overflow> void ProcessorBase::did_divu(uint32_t dividend, uin
|
||||
}
|
||||
|
||||
if(did_overflow) {
|
||||
dynamic_instruction_length_ = 3; // Just a quick nn n, and then on to prefetch.
|
||||
dynamic_instruction_length_ = 3; // Covers the nn n to get into the loop.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2555,13 +2556,15 @@ template <bool did_overflow> void ProcessorBase::did_divu(uint32_t dividend, uin
|
||||
// since this is a classic divide algorithm, but would rather that
|
||||
// errors produce incorrect timing only, not incorrect timing plus
|
||||
// incorrect results.
|
||||
dynamic_instruction_length_ = 3; // Covers the nn n to get into the loop.
|
||||
dynamic_instruction_length_ =
|
||||
3 + // nn n to get into the loop;
|
||||
30 + // nn per iteration of the loop below;
|
||||
3; // n nn upon completion of the loop.
|
||||
|
||||
divisor <<= 16;
|
||||
for(int c = 0; c < 15; ++c) {
|
||||
if(dividend & 0x80000000) {
|
||||
if(dividend & 0x8000'0000) {
|
||||
dividend = (dividend << 1) - divisor;
|
||||
dynamic_instruction_length_ += 2; // The fixed nn iteration cost.
|
||||
} else {
|
||||
dividend <<= 1;
|
||||
|
||||
@ -2569,9 +2572,9 @@ template <bool did_overflow> void ProcessorBase::did_divu(uint32_t dividend, uin
|
||||
// and test the sign of the result, but this is easier to follow:
|
||||
if (dividend >= divisor) {
|
||||
dividend -= divisor;
|
||||
dynamic_instruction_length_ += 3; // i.e. the original nn plus one further n before going down the MSB=0 route.
|
||||
dynamic_instruction_length_ += 1; // i.e. the original nn plus one further n before going down the MSB=0 route.
|
||||
} else {
|
||||
dynamic_instruction_length_ += 4; // The costliest path (since in real life it's a subtraction and then a step
|
||||
dynamic_instruction_length_ += 2; // The costliest path (since in real life it's a subtraction and then a step
|
||||
// back from there) — all costs accrue. So the fixed nn loop plus another n,
|
||||
// plus another one.
|
||||
}
|
||||
@ -2635,7 +2638,7 @@ template <bool did_overflow> void ProcessorBase::did_divs(int32_t dividend, int3
|
||||
template <typename IntT> void ProcessorBase::did_mulu(IntT multiplier) {
|
||||
// Count number of bits set.
|
||||
convert_to_bit_count_16(multiplier);
|
||||
dynamic_instruction_length_ = multiplier;
|
||||
dynamic_instruction_length_ = 17 + multiplier;
|
||||
}
|
||||
|
||||
template <typename IntT> void ProcessorBase::did_muls(IntT multiplier) {
|
||||
@ -2644,13 +2647,17 @@ template <typename IntT> void ProcessorBase::did_muls(IntT multiplier) {
|
||||
// Treat the bit to the right of b0 as 0.
|
||||
int number_of_pairs = (multiplier ^ (multiplier << 1)) & 0xffff;
|
||||
convert_to_bit_count_16(number_of_pairs);
|
||||
dynamic_instruction_length_ = number_of_pairs;
|
||||
dynamic_instruction_length_ = 17 + number_of_pairs;
|
||||
}
|
||||
|
||||
#undef convert_to_bit_count_16
|
||||
|
||||
void ProcessorBase::did_shift(int bits_shifted) {
|
||||
dynamic_instruction_length_ = bits_shifted;
|
||||
template <typename IntT> void ProcessorBase::did_shift(int bits_shifted) {
|
||||
if constexpr (sizeof(IntT) == 4) {
|
||||
dynamic_instruction_length_ = bits_shifted + 2;
|
||||
} else {
|
||||
dynamic_instruction_length_ = bits_shifted + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool use_current_instruction_pc> void ProcessorBase::raise_exception(int vector) {
|
||||
|
@ -148,7 +148,7 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
|
||||
template <typename IntT> void did_muls(IntT);
|
||||
inline void did_chk(bool, bool);
|
||||
inline void did_scc(bool);
|
||||
inline void did_shift(int);
|
||||
template <typename IntT> void did_shift(int);
|
||||
template <bool did_overflow> void did_divu(uint32_t, uint32_t);
|
||||
template <bool did_overflow> void did_divs(int32_t, int32_t);
|
||||
inline void did_bit_op(int);
|
||||
|
Loading…
x
Reference in New Issue
Block a user