mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Attempts to introduce more rigour to variable-length instruction handling.
This commit is contained in:
parent
db4ca746e3
commit
d27ba90c07
@ -69,7 +69,7 @@
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
|
@ -925,6 +925,40 @@ class CPU::MC68000::ProcessorStorageTests {
|
||||
XCTAssertEqual(_machine->get_cycle_count(), 8);
|
||||
}
|
||||
|
||||
- (void)performBSETD1Ind:(uint32_t)d1 {
|
||||
_machine->set_program({
|
||||
0x03d0 // BSET D1, (A0)
|
||||
});
|
||||
auto state = _machine->get_processor_state();
|
||||
state.address[0] = 0x3000;
|
||||
state.data[1] = d1;
|
||||
*_machine->ram_at(0x3000) = 0x7800;
|
||||
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssertEqual(state.data[1], d1);
|
||||
XCTAssertEqual(state.address[0], 0x3000);
|
||||
XCTAssertEqual(_machine->get_cycle_count(), 12);
|
||||
}
|
||||
|
||||
- (void)testBSET_D1Ind_50 {
|
||||
[self performBSETD1Ind:50];
|
||||
|
||||
const auto state = _machine->get_processor_state();
|
||||
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero);
|
||||
XCTAssertEqual(*_machine->ram_at(0x3000), 0x7c00);
|
||||
}
|
||||
|
||||
- (void)testBSET_D1Ind_3 {
|
||||
[self performBSETD1Ind:3];
|
||||
|
||||
const auto state = _machine->get_processor_state();
|
||||
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
||||
XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800);
|
||||
}
|
||||
|
||||
// MARK: DBcc
|
||||
|
||||
- (void)performDBccTestOpcode:(uint16_t)opcode status:(uint16_t)status d2Outcome:(uint32_t)d2Output {
|
||||
|
@ -49,6 +49,12 @@
|
||||
#define s_extend16(x) int32_t(int16_t(x))
|
||||
#define s_extend8(x) int32_t(int8_t(x))
|
||||
|
||||
// Sets the length of the next microcycle; if this is a debug build, also confirms
|
||||
// that the microcycle being adjusted is the one that it's permissible to adjust.
|
||||
#define set_next_microcycle_length(x) \
|
||||
assert(resizeable_microcycle_ == &bus_program->microcycle); \
|
||||
bus_program->microcycle.length = x
|
||||
|
||||
template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::run_for(HalfCycles duration) {
|
||||
const HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
||||
|
||||
@ -623,13 +629,13 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
active_program_->destination->full &= ~(1 << (active_program_->source->full & 31));
|
||||
|
||||
// Clearing in the top word requires an extra four cycles.
|
||||
active_step_->microcycle.length = HalfCycles(8 + ((active_program_->source->full & 31) / 16) * 4);
|
||||
set_next_microcycle_length(HalfCycles(8 + ((active_program_->source->full & 31) / 16) * 4));
|
||||
break;
|
||||
|
||||
case Operation::BCHGl:
|
||||
zero_result_ = active_program_->destination->full & (1 << (active_program_->source->full & 31));
|
||||
active_program_->destination->full ^= 1 << (active_program_->source->full & 31);
|
||||
active_step_->microcycle.length = HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4));
|
||||
set_next_microcycle_length(HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4)));
|
||||
break;
|
||||
|
||||
case Operation::BCHGb:
|
||||
@ -640,7 +646,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
case Operation::BSETl:
|
||||
zero_result_ = active_program_->destination->full & (1 << (active_program_->source->full & 31));
|
||||
active_program_->destination->full |= 1 << (active_program_->source->full & 31);
|
||||
bus_program->microcycle.length = HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4));
|
||||
set_next_microcycle_length(HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4)));
|
||||
break;
|
||||
|
||||
case Operation::BSETb:
|
||||
@ -908,7 +914,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
}
|
||||
|
||||
// Time taken = 38 cycles + 2 cycles per 1 in the source.
|
||||
active_step_->microcycle.length = HalfCycles(4 * number_of_ones + 38*2);
|
||||
set_next_microcycle_length(HalfCycles(4 * number_of_ones + 38*2));
|
||||
} break;
|
||||
|
||||
case Operation::MULS: {
|
||||
@ -929,7 +935,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
}
|
||||
|
||||
// Time taken = 38 cycles + 2 cycles per 1 in the source.
|
||||
active_step_->microcycle.length = HalfCycles(4 * number_of_pairs + 38*2);
|
||||
set_next_microcycle_length(HalfCycles(4 * number_of_pairs + 38*2));
|
||||
} break;
|
||||
|
||||
/*
|
||||
@ -942,7 +948,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
bus_program = active_micro_op_->bus_program; \
|
||||
\
|
||||
populate_trap_steps(5, get_status()); \
|
||||
bus_program->microcycle.length = HalfCycles(8); \
|
||||
set_next_microcycle_length(HalfCycles(8)); \
|
||||
\
|
||||
program_counter_.full -= 2;
|
||||
|
||||
@ -964,7 +970,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
if(quotient >= 65536) {
|
||||
overflow_flag_ = 1;
|
||||
// TODO: is what should happen to the other flags known?
|
||||
active_step_->microcycle.length = HalfCycles(3*2*2);
|
||||
set_next_microcycle_length(HalfCycles(3*2*2));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1002,7 +1008,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
}
|
||||
}
|
||||
}
|
||||
active_step_->microcycle.length = HalfCycles(cycles_expended * 2);
|
||||
set_next_microcycle_length(HalfCycles(cycles_expended * 2));
|
||||
} break;
|
||||
|
||||
case Operation::DIVS: {
|
||||
@ -1027,7 +1033,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
// Check for overflow. If it exists, work here is already done.
|
||||
if(quotient > 32767 || quotient < -32768) {
|
||||
overflow_flag_ = 1;
|
||||
active_step_->microcycle.length = HalfCycles(3*2*2);
|
||||
set_next_microcycle_length(HalfCycles(3*2*2));
|
||||
|
||||
// These are officially undefined for results that overflow, so the below is a guess.
|
||||
zero_result_ = decltype(zero_result_)(divisor & 0xffff);
|
||||
@ -1064,7 +1070,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
} else if(dividend < 0) {
|
||||
cycles_expended += 4;
|
||||
}
|
||||
active_step_->microcycle.length = HalfCycles(cycles_expended * 2);
|
||||
set_next_microcycle_length(HalfCycles(cycles_expended * 2));
|
||||
} break;
|
||||
|
||||
#undef announce_divide_by_zero
|
||||
@ -1254,7 +1260,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
// Select the trap steps as next; the initial microcycle should be 4 cycles long.
|
||||
bus_program = trap_steps_;
|
||||
populate_trap_steps((decoded_instruction_.full & 15) + 32, get_status());
|
||||
bus_program->microcycle.length = HalfCycles(8);
|
||||
set_next_microcycle_length(HalfCycles(8));
|
||||
|
||||
// The program counter to push is actually one slot ago.
|
||||
program_counter_.full -= 2;
|
||||
@ -1265,7 +1271,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
// Select the trap steps as next; the initial microcycle should be 4 cycles long.
|
||||
bus_program = trap_steps_;
|
||||
populate_trap_steps(7, get_status());
|
||||
bus_program->microcycle.length = HalfCycles(0);
|
||||
set_next_microcycle_length(HalfCycles(0));
|
||||
program_counter_.full -= 4;
|
||||
}
|
||||
} break;
|
||||
@ -1282,9 +1288,9 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
bus_program = trap_steps_;
|
||||
populate_trap_steps(6, get_status());
|
||||
if(is_under) {
|
||||
bus_program->microcycle.length = HalfCycles(16);
|
||||
set_next_microcycle_length(HalfCycles(16));
|
||||
} else {
|
||||
bus_program->microcycle.length = HalfCycles(8);
|
||||
set_next_microcycle_length(HalfCycles(8));
|
||||
}
|
||||
|
||||
// The program counter to push is two slots ago as whatever was the correct prefetch
|
||||
@ -1538,7 +1544,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
#define decode_shift_count() \
|
||||
int shift_count = (decoded_instruction_.full & 32) ? data_[(decoded_instruction_.full >> 9) & 7].full&63 : ( ((decoded_instruction_.full >> 9)&7) ? ((decoded_instruction_.full >> 9)&7) : 8) ; \
|
||||
bus_program->microcycle.length = HalfCycles(4 * shift_count);
|
||||
set_next_microcycle_length(HalfCycles(4 * shift_count));
|
||||
|
||||
#define set_flags_b(t) set_flags(active_program_->destination->halves.low.halves.low, 0x80, t)
|
||||
#define set_flags_w(t) set_flags(active_program_->destination->halves.low.full, 0x8000, t)
|
||||
@ -2139,3 +2145,4 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
#undef u_extend8
|
||||
#undef s_extend16
|
||||
#undef s_extend8
|
||||
#undef set_next_microcycle_length
|
||||
|
@ -3045,6 +3045,19 @@ struct ProcessorStorageConstructor {
|
||||
storage_.interrupt_micro_ops_ = &storage_.all_micro_ops_[interrupt_pointer];
|
||||
link_operations(storage_.interrupt_micro_ops_, &arbitrary_base);
|
||||
|
||||
// If this is a debug build, not where the resizeable microcycle is
|
||||
// (and double check that there's only the one).
|
||||
#ifndef NDEBUG
|
||||
for(size_t c = 0; c < storage_.all_bus_steps_.size() - 1; ++c) {
|
||||
if(!storage_.all_bus_steps_[c+1].is_terminal()) continue;
|
||||
|
||||
if(storage_.all_bus_steps_[c].microcycle.length == HalfCycles(0)) {
|
||||
assert(!storage_.resizeable_microcycle_);
|
||||
storage_.resizeable_microcycle_ = &storage_.all_bus_steps_[c].microcycle;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::cout << storage_.all_bus_steps_.size() << " total steps" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -411,6 +411,11 @@ class ProcessorStorage {
|
||||
RegisterPair16 throwaway_value_;
|
||||
uint32_t movem_final_address_;
|
||||
|
||||
// Sanity checking for the debug build.
|
||||
#ifndef NDEBUG
|
||||
const Microcycle *resizeable_microcycle_ = nullptr;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Evaluates the conditional described by @c code and returns @c true or @c false to
|
||||
indicate the result of that evaluation.
|
||||
|
Loading…
x
Reference in New Issue
Block a user