mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 16:31:31 +00:00
Takes a shot at the synchronous bus.
This commit is contained in:
parent
857f74b320
commit
291e91375f
@ -27,8 +27,8 @@ namespace MC68000 {
|
|||||||
|
|
||||||
Concretely, a standard read cycle breaks down into at least two microcycles:
|
Concretely, a standard read cycle breaks down into at least two microcycles:
|
||||||
|
|
||||||
1) a 5 half-cycle length microcycle in which the address strobe is signalled; and
|
1) a 4 half-cycle length microcycle in which the address strobe is signalled; and
|
||||||
2) a 3 half-cycle length microcycle in which at least one of the data strobes is
|
2) a 4 half-cycle length microcycle in which at least one of the data strobes is
|
||||||
signalled, and the data bus is sampled.
|
signalled, and the data bus is sampled.
|
||||||
|
|
||||||
That is, assuming DTack were signalled when microcycle (1) ended. If not then additional
|
That is, assuming DTack were signalled when microcycle (1) ended. If not then additional
|
||||||
@ -47,36 +47,44 @@ namespace MC68000 {
|
|||||||
struct Microcycle {
|
struct Microcycle {
|
||||||
/// A NewAddress cycle is one in which the address strobe is initially low but becomes high;
|
/// A NewAddress cycle is one in which the address strobe is initially low but becomes high;
|
||||||
/// this correlates to states 0 to 5 of a standard read/write cycle.
|
/// this correlates to states 0 to 5 of a standard read/write cycle.
|
||||||
static const int NewAddress = 1 << 0;
|
static const int NewAddress = 1 << 0;
|
||||||
|
|
||||||
/// A SameAddress cycle is one in which the address strobe is continuously asserted, but neither
|
/// A SameAddress cycle is one in which the address strobe is continuously asserted, but neither
|
||||||
/// of the data strobes are.
|
/// of the data strobes are.
|
||||||
static const int SameAddress = 1 << 1;
|
static const int SameAddress = 1 << 1;
|
||||||
|
|
||||||
/// A Reset cycle is one in which the RESET output is asserted.
|
/// A Reset cycle is one in which the RESET output is asserted.
|
||||||
static const int Reset = 1 << 2;
|
static const int Reset = 1 << 2;
|
||||||
|
|
||||||
/// Indicates that the address and both data select strobes are active.
|
/// Indicates that the address and both data select strobes are active.
|
||||||
static const int SelectWord = 1 << 3;
|
static const int SelectWord = 1 << 3;
|
||||||
|
|
||||||
/// Indicates that the address strobe and exactly one of the data strobes are active; you can determine
|
/// Indicates that the address strobe and exactly one of the data strobes are active; you can determine
|
||||||
/// which by inspecting the low bit of the provided address. The RW line indicates a read.
|
/// which by inspecting the low bit of the provided address. The RW line indicates a read.
|
||||||
static const int SelectByte = 1 << 4;
|
static const int SelectByte = 1 << 4;
|
||||||
|
|
||||||
/// If set, indicates a read. Otherwise, a write.
|
/// If set, indicates a read. Otherwise, a write.
|
||||||
static const int Read = 1 << 5;
|
static const int Read = 1 << 5;
|
||||||
|
|
||||||
/// Contains the value of line FC0 if it is not implicit via InterruptAcknowledge.
|
/// Contains the value of line FC0 if it is not implicit via InterruptAcknowledge.
|
||||||
static const int IsData = 1 << 6;
|
static const int IsData = 1 << 6;
|
||||||
|
|
||||||
/// Contains the value of line FC1 if it is not implicit via InterruptAcknowledge.
|
/// Contains the value of line FC1 if it is not implicit via InterruptAcknowledge.
|
||||||
static const int IsProgram = 1 << 7;
|
static const int IsProgram = 1 << 7;
|
||||||
|
|
||||||
/// The interrupt acknowledge cycle is that during which the 68000 seeks to obtain the vector for
|
/// The interrupt acknowledge cycle is that during which the 68000 seeks to obtain the vector for
|
||||||
/// an interrupt it plans to observe. Noted on a real 68000 by all FCs being set to 1.
|
/// an interrupt it plans to observe. Noted on a real 68000 by all FCs being set to 1.
|
||||||
static const int InterruptAcknowledge = 1 << 8;
|
static const int InterruptAcknowledge = 1 << 8;
|
||||||
|
|
||||||
|
/// Represents the state of the 68000's valid memory address line — indicating whether this microcycle
|
||||||
|
/// is synchronised with the E clock to satisfy a valid peripheral address request.
|
||||||
|
static const int IsPeripheral = 1 << 9;
|
||||||
|
|
||||||
|
/// Contains a valid combination of the various static const int flags, describing the operation
|
||||||
|
/// performed by this Microcycle.
|
||||||
int operation = 0;
|
int operation = 0;
|
||||||
|
|
||||||
|
/// Describes the duration of this Microcycle.
|
||||||
HalfCycles length = HalfCycles(4);
|
HalfCycles length = HalfCycles(4);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -84,11 +92,29 @@ struct Microcycle {
|
|||||||
if reading indirectly via an address register, this will indicate the full
|
if reading indirectly via an address register, this will indicate the full
|
||||||
value of the address register.
|
value of the address register.
|
||||||
|
|
||||||
The receiver should ignore bits 0 and 24+.
|
The receiver should ignore bits 0 and 24+. Use word_address() automatically
|
||||||
|
to obtain the only the 68000's real address lines, giving a 23-bit address
|
||||||
|
at word resolution.
|
||||||
*/
|
*/
|
||||||
const uint32_t *address = nullptr;
|
const uint32_t *address = nullptr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
If this is a write cycle, dereference value to get the value loaded onto
|
||||||
|
the data bus.
|
||||||
|
|
||||||
|
If this is a read cycle, write the value on the data bus to it.
|
||||||
|
|
||||||
|
Otherwise, this value is undefined.
|
||||||
|
|
||||||
|
Byte values are provided via @c value.halves.low. @c value.halves.high is undefined.
|
||||||
|
This is true regardless of whether the upper or lower byte of a word is being
|
||||||
|
accessed.
|
||||||
|
|
||||||
|
Word values occupy the entirety of @c value.full.
|
||||||
|
*/
|
||||||
RegisterPair16 *value = nullptr;
|
RegisterPair16 *value = nullptr;
|
||||||
|
|
||||||
|
/// @returns @c true if two Microcycles are equal; @c false otherwise.
|
||||||
bool operator ==(const Microcycle &rhs) const {
|
bool operator ==(const Microcycle &rhs) const {
|
||||||
if(value != rhs.value) return false;
|
if(value != rhs.value) return false;
|
||||||
if(address != rhs.address) return false;
|
if(address != rhs.address) return false;
|
||||||
@ -101,7 +127,7 @@ struct Microcycle {
|
|||||||
|
|
||||||
/*! @returns true if any data select line is active; @c false otherwise. */
|
/*! @returns true if any data select line is active; @c false otherwise. */
|
||||||
inline bool data_select_active() const {
|
inline bool data_select_active() const {
|
||||||
return bool(operation & (SelectWord | SelectByte));
|
return bool(operation & (SelectWord | SelectByte | InterruptAcknowledge));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -97,10 +97,28 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address);
|
populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the microcycle.
|
// Perform the microcycle if it is of non-zero length. If this is an operation that
|
||||||
cycles_run_for +=
|
// would normally strobe one of the data selects and VPA is active, it will also need
|
||||||
active_step_->microcycle.length +
|
// stretching.
|
||||||
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
if(active_step_->microcycle.length != HalfCycles(0)) {
|
||||||
|
if(is_peripheral_address_ && active_step_->microcycle.data_select_active()) {
|
||||||
|
auto cycle_copy = active_step_->microcycle;
|
||||||
|
cycle_copy.operation |= Microcycle::IsPeripheral;
|
||||||
|
|
||||||
|
// Extend length by: (i) distance to next E low, plus (ii) difference between
|
||||||
|
// current length and a whole E cycle.
|
||||||
|
cycle_copy.length = HalfCycles(20); // i.e. one E cycle in length.
|
||||||
|
cycle_copy.length += (e_clock_phase_ + cycles_run_for) % 10;
|
||||||
|
|
||||||
|
cycles_run_for +=
|
||||||
|
cycle_copy.length +
|
||||||
|
bus_handler_.perform_bus_operation(cycle_copy, is_supervisor_);
|
||||||
|
} else {
|
||||||
|
cycles_run_for +=
|
||||||
|
active_step_->microcycle.length +
|
||||||
|
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PERFORM THE BUS STEP'S ACTION.
|
PERFORM THE BUS STEP'S ACTION.
|
||||||
|
@ -3340,10 +3340,10 @@ struct ProcessorStorageConstructor {
|
|||||||
op(Action::None, seq(""));
|
op(Action::None, seq(""));
|
||||||
|
|
||||||
// Perform a single write and then a cycle that will obtain an interrupt vector, or else dictate an autovector or a spurious interrupt.
|
// Perform a single write and then a cycle that will obtain an interrupt vector, or else dictate an autovector or a spurious interrupt.
|
||||||
op(Action::PrepareINT, seq("nw int", { &storage_.precomputed_addresses_[0] }));
|
op(Action::PrepareINT, seq("n nn nw int", { &storage_.precomputed_addresses_[0] }));
|
||||||
|
|
||||||
// The reset of the standard trap steps occur here; PrepareINT will set them up according to the vector received.
|
// The reset of the standard trap steps occur here; PrepareINT will set them up according to the vector received.
|
||||||
op(Action::PrepareINTVector, seq("nw nW nV nv np np", { &storage_.precomputed_addresses_[1], &storage_.precomputed_addresses_[2] }));
|
op(Action::PrepareINTVector, seq("nn n nw nW nV nv np np", { &storage_.precomputed_addresses_[1], &storage_.precomputed_addresses_[2] }));
|
||||||
|
|
||||||
// Terminate the sequence.
|
// Terminate the sequence.
|
||||||
op();
|
op();
|
||||||
|
Loading…
Reference in New Issue
Block a user