1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-29 00:29:28 +00:00

Merge branch '68000Mk2' into InMacintosh

This commit is contained in:
Thomas Harte 2022-06-02 12:30:54 -04:00
commit a292483344
5 changed files with 65 additions and 39 deletions

View File

@ -828,14 +828,14 @@ template <
set_neg_zero(v, m); \ set_neg_zero(v, m); \
status.overflow_flag = (Status::FlagT(value) ^ status.zero_result) & Status::FlagT(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; \ 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 set_flags_w(t) set_flags(src.w, 0x8000, t)
#define asl(destination, size) {\ #define asl(destination, size) {\
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
const auto value = destination; \ const auto value = destination; \
\ \
if(!shift_count) { \ if(!shift_count) { \
@ -865,7 +865,7 @@ template <
case Operation::ASLl: asl(dest.l, 32); break; case Operation::ASLl: asl(dest.l, 32); break;
#define asr(destination, size) {\ #define asr(destination, size) {\
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
const auto value = destination; \ const auto value = destination; \
\ \
if(!shift_count) { \ if(!shift_count) { \
@ -909,7 +909,7 @@ template <
status.carry_flag = value & (t); status.carry_flag = value & (t);
#define lsl(destination, size) {\ #define lsl(destination, size) {\
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
const auto value = destination; \ const auto value = destination; \
\ \
if(!shift_count) { \ if(!shift_count) { \
@ -933,7 +933,7 @@ template <
case Operation::LSLl: lsl(dest.l, 32); break; case Operation::LSLl: lsl(dest.l, 32); break;
#define lsr(destination, size) {\ #define lsr(destination, size) {\
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
const auto value = destination; \ const auto value = destination; \
\ \
if(!shift_count) { \ if(!shift_count) { \
@ -957,7 +957,7 @@ template <
case Operation::LSRl: lsr(dest.l, 32); break; case Operation::LSRl: lsr(dest.l, 32); break;
#define rol(destination, size) { \ #define rol(destination, size) { \
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
const auto value = destination; \ const auto value = destination; \
\ \
if(!shift_count) { \ if(!shift_count) { \
@ -985,7 +985,7 @@ template <
case Operation::ROLl: rol(dest.l, 32); break; case Operation::ROLl: rol(dest.l, 32); break;
#define ror(destination, size) { \ #define ror(destination, size) { \
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
const auto value = destination; \ const auto value = destination; \
\ \
if(!shift_count) { \ if(!shift_count) { \
@ -1013,7 +1013,7 @@ template <
case Operation::RORl: ror(dest.l, 32); break; case Operation::RORl: ror(dest.l, 32); break;
#define roxl(destination, size) { \ #define roxl(destination, size) { \
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
\ \
shift_count %= (size + 1); \ shift_count %= (size + 1); \
uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \ 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; case Operation::ROXLl: roxl(dest.l, 32); break;
#define roxr(destination, size) { \ #define roxr(destination, size) { \
decode_shift_count(); \ decode_shift_count(decltype(destination)); \
\ \
shift_count %= (size + 1); \ shift_count %= (size + 1); \
uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \ uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \

View File

@ -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. /// 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) {} 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. /// Indicates an in-register shift or roll occurred, providing the number of bits shifted by
void did_shift([[maybe_unused]] int bit_count) {} /// 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. /// 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. /// If @c did_overflow is @c true then the divide ended in overflow.

View File

@ -870,7 +870,16 @@
XCTAssertEqual(state.registers.data[1], 0x1fffffff); XCTAssertEqual(state.registers.data[1], 0x1fffffff);
XCTAssertEqual(state.registers.supervisor_stack_pointer, initial_sp - 6); XCTAssertEqual(state.registers.supervisor_stack_pointer, initial_sp - 6);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend); 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. // Check stack contents; should be PC.l, PC.h and status register.
// Assumed: the program counter on the stack is that of the // Assumed: the program counter on the stack is that of the
@ -908,7 +917,11 @@
const auto state = self.machine->get_processor_state(); const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x4768f231); 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()); XCTAssertEqual(14, self.machine->get_cycle_count());
} }
@ -917,7 +930,10 @@
const auto state = self.machine->get_processor_state(); const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x4768f231); 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()); XCTAssertEqual(14, self.machine->get_cycle_count());
} }

View File

@ -592,6 +592,11 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Signal the bus handler if requested. // Signal the bus handler if requested.
if constexpr (signal_will_perform) { 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_); bus_handler_.will_perform(instruction_address_.l, opcode_);
} }
@ -772,9 +777,6 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
Duplicate(SUBAw, ADDAw) StdCASE(ADDAw, perform_state_ = Perform_np_nn) Duplicate(SUBAw, ADDAw) StdCASE(ADDAw, perform_state_ = Perform_np_nn)
Duplicate(SUBAl, ADDAl) StdCASE(ADDAl, { Duplicate(SUBAl, ADDAl) StdCASE(ADDAl, {
if(instruction_.mode(1) == Mode::AddressRegisterDirect) {
perform_state_ = Perform_np_nn;
} else {
switch(instruction_.mode(0)) { switch(instruction_.mode(0)) {
default: default:
perform_state_ = Perform_np_n; perform_state_ = Perform_np_n;
@ -785,7 +787,6 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
perform_state_ = Perform_np_nn; perform_state_ = Perform_np_nn;
break; break;
} }
}
}) })
Duplicate(SUBXb, ADDXb) StdCASE(ADDXb, { Duplicate(SUBXb, ADDXb) StdCASE(ADDXb, {
@ -2546,7 +2547,7 @@ template <bool did_overflow> void ProcessorBase::did_divu(uint32_t dividend, uin
} }
if(did_overflow) { 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; 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 // since this is a classic divide algorithm, but would rather that
// errors produce incorrect timing only, not incorrect timing plus // errors produce incorrect timing only, not incorrect timing plus
// incorrect results. // 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; divisor <<= 16;
for(int c = 0; c < 15; ++c) { for(int c = 0; c < 15; ++c) {
if(dividend & 0x80000000) { if(dividend & 0x8000'0000) {
dividend = (dividend << 1) - divisor; dividend = (dividend << 1) - divisor;
dynamic_instruction_length_ += 2; // The fixed nn iteration cost.
} else { } else {
dividend <<= 1; 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: // and test the sign of the result, but this is easier to follow:
if (dividend >= divisor) { if (dividend >= divisor) {
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 { } 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, // back from there) — all costs accrue. So the fixed nn loop plus another n,
// plus another one. // 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) { template <typename IntT> void ProcessorBase::did_mulu(IntT multiplier) {
// Count number of bits set. // Count number of bits set.
convert_to_bit_count_16(multiplier); convert_to_bit_count_16(multiplier);
dynamic_instruction_length_ = multiplier; dynamic_instruction_length_ = 17 + multiplier;
} }
template <typename IntT> void ProcessorBase::did_muls(IntT 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. // Treat the bit to the right of b0 as 0.
int number_of_pairs = (multiplier ^ (multiplier << 1)) & 0xffff; int number_of_pairs = (multiplier ^ (multiplier << 1)) & 0xffff;
convert_to_bit_count_16(number_of_pairs); 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 #undef convert_to_bit_count_16
void ProcessorBase::did_shift(int bits_shifted) { template <typename IntT> void ProcessorBase::did_shift(int bits_shifted) {
dynamic_instruction_length_ = 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) { template <bool use_current_instruction_pc> void ProcessorBase::raise_exception(int vector) {

View File

@ -148,7 +148,7 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
template <typename IntT> void did_muls(IntT); template <typename IntT> void did_muls(IntT);
inline void did_chk(bool, bool); inline void did_chk(bool, bool);
inline void did_scc(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_divu(uint32_t, uint32_t);
template <bool did_overflow> void did_divs(int32_t, int32_t); template <bool did_overflow> void did_divs(int32_t, int32_t);
inline void did_bit_op(int); inline void did_bit_op(int);