mirror of
https://github.com/TomHarte/CLK.git
synced 2024-10-04 17:56:29 +00:00
Adds support for HALT as an input, and puts some effort into how to calculate E.
This commit is contained in:
parent
f1879c5fbc
commit
92568c90c8
@ -253,6 +253,11 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform = false> cla
|
|||||||
bus_acknowledge_ = bus_acknowledge;
|
bus_acknowledge_ = bus_acknowledge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the halt line.
|
||||||
|
void set_halt(bool halt) {
|
||||||
|
halt_ = halt;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T &bus_handler_;
|
T &bus_handler_;
|
||||||
};
|
};
|
||||||
|
@ -43,8 +43,12 @@
|
|||||||
((active_step_->microcycle.operation & Microcycle::Read) ? 0x10 : 0)
|
((active_step_->microcycle.operation & Microcycle::Read) ? 0x10 : 0)
|
||||||
|
|
||||||
template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::run_for(HalfCycles duration) {
|
template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::run_for(HalfCycles duration) {
|
||||||
HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
const HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
||||||
while(remaining_duration > HalfCycles(0)) {
|
|
||||||
|
// This loop counts upwards rather than downwards because it simplifies calculation of
|
||||||
|
// E as and when required.
|
||||||
|
HalfCycles cycles_run_for;
|
||||||
|
while(cycles_run_for < remaining_duration) {
|
||||||
/*
|
/*
|
||||||
PERFORM THE CURRENT BUS STEP'S MICROCYCLE.
|
PERFORM THE CURRENT BUS STEP'S MICROCYCLE.
|
||||||
*/
|
*/
|
||||||
@ -56,12 +60,13 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
// If an interrupt (TODO: or reset) has finally arrived that will be serviced,
|
// If an interrupt (TODO: or reset) has finally arrived that will be serviced,
|
||||||
// exit the STOP.
|
// exit the STOP.
|
||||||
if(bus_interrupt_level_ > interrupt_level_) {
|
if(bus_interrupt_level_ > interrupt_level_) {
|
||||||
|
// TODO: schedule interrupt right here.
|
||||||
execution_state_ = ExecutionState::Executing;
|
execution_state_ = ExecutionState::Executing;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise continue being stopped.
|
// Otherwise continue being stopped.
|
||||||
remaining_duration -=
|
cycles_run_for +=
|
||||||
stop_cycle_.length +
|
stop_cycle_.length +
|
||||||
bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
|
bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
|
||||||
continue;
|
continue;
|
||||||
@ -74,13 +79,31 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, signal another cycle of wait.
|
// Otherwise, signal another cycle of wait.
|
||||||
remaining_duration -=
|
cycles_run_for +=
|
||||||
dtack_cycle_.length +
|
dtack_cycle_.length +
|
||||||
bus_handler_.perform_bus_operation(dtack_cycle_, is_supervisor_);
|
bus_handler_.perform_bus_operation(dtack_cycle_, is_supervisor_);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case ExecutionState::Halted:
|
||||||
|
if(!halt_) break;
|
||||||
|
|
||||||
|
cycles_run_for +=
|
||||||
|
stop_cycle_.length +
|
||||||
|
bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for entry into the halted state.
|
||||||
|
if(halt_ && active_step_[0].microcycle.operation & Microcycle::NewAddress) {
|
||||||
|
execution_state_ = ExecutionState::Halted;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(active_step_->microcycle.data_select_active()) {
|
if(active_step_->microcycle.data_select_active()) {
|
||||||
|
// TODO: if valid peripheral address is asserted, substitute a
|
||||||
|
// synhronous bus access.
|
||||||
|
|
||||||
|
// Check whether the processor needs to await DTack.
|
||||||
if(!dtack_is_implicit && !dtack_ && !bus_error_) {
|
if(!dtack_is_implicit && !dtack_ && !bus_error_) {
|
||||||
execution_state_ = ExecutionState::WaitingForDTack;
|
execution_state_ = ExecutionState::WaitingForDTack;
|
||||||
dtack_cycle_ = active_step_->microcycle;
|
dtack_cycle_ = active_step_->microcycle;
|
||||||
@ -89,7 +112,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for bus error here.
|
// Check for bus error.
|
||||||
if(bus_error_) {
|
if(bus_error_) {
|
||||||
active_program_ = nullptr;
|
active_program_ = nullptr;
|
||||||
active_micro_op_ = long_exception_micro_ops_;
|
active_micro_op_ = long_exception_micro_ops_;
|
||||||
@ -111,7 +134,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform the microcycle.
|
// Perform the microcycle.
|
||||||
remaining_duration -=
|
cycles_run_for +=
|
||||||
active_step_->microcycle.length +
|
active_step_->microcycle.length +
|
||||||
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
||||||
|
|
||||||
@ -1933,7 +1956,8 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
half_cycles_left_to_run_ = remaining_duration;
|
e_clock_phase_ = (e_clock_phase_ + cycles_run_for) % 10;
|
||||||
|
half_cycles_left_to_run_ = remaining_duration - cycles_run_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, bool dtack_is_implicit, bool signal_will_perform> ProcessorState Processor<T, dtack_is_implicit, signal_will_perform>::get_state() {
|
template <class T, bool dtack_is_implicit, bool signal_will_perform> ProcessorState Processor<T, dtack_is_implicit, signal_will_perform>::get_state() {
|
||||||
|
@ -24,9 +24,18 @@ class ProcessorStorage {
|
|||||||
RegisterPair32 prefetch_queue_; // Each word will go into the low part of the word, then proceed upward.
|
RegisterPair32 prefetch_queue_; // Each word will go into the low part of the word, then proceed upward.
|
||||||
|
|
||||||
enum class ExecutionState {
|
enum class ExecutionState {
|
||||||
|
/// The normal mode, this means the 68000 is expending processing effort.
|
||||||
Executing,
|
Executing,
|
||||||
|
|
||||||
|
/// The 68000 is in a holding loop, waiting for either DTack or to be notified of a bus error.
|
||||||
WaitingForDTack,
|
WaitingForDTack,
|
||||||
Stopped
|
|
||||||
|
/// Occurs after executing a STOP instruction; the processor will idle waiting for an interrupt or reset.
|
||||||
|
Stopped,
|
||||||
|
|
||||||
|
/// Occurs at the end of the current bus cycle after detection of the HALT input, continuing until
|
||||||
|
/// HALT is no longer signalled.
|
||||||
|
Halted
|
||||||
} execution_state_ = ExecutionState::Executing;
|
} execution_state_ = ExecutionState::Executing;
|
||||||
Microcycle dtack_cycle_;
|
Microcycle dtack_cycle_;
|
||||||
Microcycle stop_cycle_;
|
Microcycle stop_cycle_;
|
||||||
@ -48,6 +57,7 @@ class ProcessorStorage {
|
|||||||
bool bus_error_ = false;
|
bool bus_error_ = false;
|
||||||
bool bus_request_ = false;
|
bool bus_request_ = false;
|
||||||
bool bus_acknowledge_ = false;
|
bool bus_acknowledge_ = false;
|
||||||
|
bool halt_ = false;
|
||||||
|
|
||||||
// Generic sources and targets for memory operations;
|
// Generic sources and targets for memory operations;
|
||||||
// by convention: [0] = source, [1] = destination.
|
// by convention: [0] = source, [1] = destination.
|
||||||
@ -56,6 +66,7 @@ class ProcessorStorage {
|
|||||||
RegisterPair32 destination_bus_data_[1];
|
RegisterPair32 destination_bus_data_[1];
|
||||||
|
|
||||||
HalfCycles half_cycles_left_to_run_;
|
HalfCycles half_cycles_left_to_run_;
|
||||||
|
HalfCycles e_clock_phase_;
|
||||||
|
|
||||||
enum class Operation {
|
enum class Operation {
|
||||||
None,
|
None,
|
||||||
|
Loading…
Reference in New Issue
Block a user