mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Establish general pattern for selecting a performance phase and obtaining operands.
This commit is contained in:
parent
d0b6451f02
commit
1a27eea46c
@ -372,6 +372,7 @@ template <class BusHandler, bool dtack_is_implicit = true, bool permit_overrun =
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
BusHandler &bus_handler_;
|
BusHandler &bus_handler_;
|
||||||
|
void setup_operation();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define _8000Mk2Implementation_h
|
#define _8000Mk2Implementation_h
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
namespace MC68000Mk2 {
|
namespace MC68000Mk2 {
|
||||||
@ -145,6 +146,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
prefetch_.high = prefetch_.low; \
|
prefetch_.high = prefetch_.low; \
|
||||||
ReadProgramWord(prefetch_.low)
|
ReadProgramWord(prefetch_.low)
|
||||||
|
|
||||||
|
using Mode = InstructionSet::M68k::AddressingMode;
|
||||||
|
|
||||||
// Otherwise continue for all time, until back in debt.
|
// Otherwise continue for all time, until back in debt.
|
||||||
// Formatting is slightly obtuse here to make this look more like a coroutine.
|
// Formatting is slightly obtuse here to make this look more like a coroutine.
|
||||||
while(true) { switch(state_) {
|
while(true) { switch(state_) {
|
||||||
@ -181,21 +184,38 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
case State::Decode:
|
case State::Decode:
|
||||||
opcode_ = prefetch_.high.w;
|
opcode_ = prefetch_.high.w;
|
||||||
instruction_ = decoder_.decode(opcode_);
|
instruction_ = decoder_.decode(opcode_);
|
||||||
|
instruction_address_ = program_counter_.l - 4;
|
||||||
|
|
||||||
// TODO: it might be better to switch on instruction_.operation
|
// TODO: check for privilege and unrecognised instructions.
|
||||||
// and establish both the instruction pattern and the operand
|
|
||||||
// flags here?
|
|
||||||
operand_flags_ = InstructionSet::M68k::operand_flags<InstructionSet::M68k::Model::M68000>(instruction_.operation);
|
|
||||||
|
|
||||||
operand_ = 0;
|
// Obtain operand flags and pick a perform pattern.
|
||||||
|
setup_operation();
|
||||||
|
|
||||||
|
next_operand_ = 0;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
// Check the operand flags to determine whether the operand at index
|
// Check the operand flags to determine whether the operand at index
|
||||||
// operand_ needs to be fetched, and do so.
|
// operand_ needs to be fetched, and do so.
|
||||||
case State::FetchOperand:
|
case State::FetchOperand:
|
||||||
|
switch(instruction_.mode(next_operand_)) {
|
||||||
|
case Mode::None:
|
||||||
|
state_ = perform_state_;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Mode::AddressRegisterDirect:
|
||||||
|
case Mode::DataRegisterDirect:
|
||||||
|
operand_[next_operand_] = registers_[instruction_.lreg(next_operand_)];
|
||||||
|
++next_operand_;
|
||||||
|
state_ = next_operand_ == 2 ? perform_state_ : state_;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
default:
|
default:
|
||||||
|
printf("Unhandled or unterminated state: %d\n", state_);
|
||||||
assert(false);
|
assert(false);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -214,6 +234,25 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
|
||||||
|
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::setup_operation() {
|
||||||
|
|
||||||
|
#define BIND(x, p) \
|
||||||
|
case InstructionSet::M68k::Operation::x: \
|
||||||
|
operand_flags_ = InstructionSet::M68k::operand_flags<InstructionSet::M68k::Model::M68000, InstructionSet::M68k::Operation::x>(); \
|
||||||
|
perform_state_ = State::p; \
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch(instruction_.operation) {
|
||||||
|
BIND(NBCD, Perform_np);
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BIND
|
||||||
|
}
|
||||||
|
|
||||||
template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
|
template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
|
||||||
CPU::MC68000Mk2::State Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::get_state() {
|
CPU::MC68000Mk2::State Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::get_state() {
|
||||||
return CPU::MC68000Mk2::State();
|
return CPU::MC68000Mk2::State();
|
||||||
|
@ -16,34 +16,76 @@ namespace CPU {
|
|||||||
namespace MC68000Mk2 {
|
namespace MC68000Mk2 {
|
||||||
|
|
||||||
struct ProcessorBase {
|
struct ProcessorBase {
|
||||||
|
/// States for the state machine which are named by
|
||||||
|
/// me for their purpose rather than automatically by file position.
|
||||||
|
/// These are negative to avoid ambiguity with the other group.
|
||||||
enum State: int {
|
enum State: int {
|
||||||
Reset = -1,
|
Reset = -1,
|
||||||
Decode = -2,
|
Decode = -2,
|
||||||
WaitForDTACK = -3,
|
WaitForDTACK = -3,
|
||||||
FetchOperand = -4,
|
FetchOperand = -4,
|
||||||
|
|
||||||
|
// Various different effective address calculations.
|
||||||
|
|
||||||
|
CalculateAnDn = -5,
|
||||||
|
|
||||||
|
// Various forms of perform; each of these will
|
||||||
|
// perform the current instruction, then do the
|
||||||
|
// indicated bus cycle.
|
||||||
|
|
||||||
|
Perform_np = -6,
|
||||||
};
|
};
|
||||||
int state_ = State::Reset;
|
int state_ = State::Reset;
|
||||||
|
|
||||||
|
/// Counts time left on the clock before the current batch of processing
|
||||||
|
/// is complete; may be less than zero.
|
||||||
HalfCycles time_remaining_;
|
HalfCycles time_remaining_;
|
||||||
int post_dtack_state_ = 0;
|
|
||||||
|
/// Current supervisor state, for direct provision to the bus handler.
|
||||||
int is_supervisor_ = 1;
|
int is_supervisor_ = 1;
|
||||||
|
|
||||||
|
// A decoder for instructions, plus all collected information about the
|
||||||
|
// current instruction.
|
||||||
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> decoder_;
|
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> decoder_;
|
||||||
InstructionSet::M68k::Preinstruction instruction_;
|
InstructionSet::M68k::Preinstruction instruction_;
|
||||||
uint16_t opcode_;
|
uint16_t opcode_;
|
||||||
uint8_t operand_flags_;
|
uint8_t operand_flags_;
|
||||||
|
uint32_t instruction_address_;
|
||||||
|
|
||||||
|
// Register state.
|
||||||
InstructionSet::M68k::Status status_;
|
InstructionSet::M68k::Status status_;
|
||||||
SlicedInt32 program_counter_;
|
SlicedInt32 program_counter_;
|
||||||
SlicedInt32 registers_[16]; // D0–D7 followed by A0–A7.
|
SlicedInt32 registers_[16]; // D0–D7 followed by A0–A7.
|
||||||
SlicedInt32 stack_pointers_[2];
|
SlicedInt32 stack_pointers_[2];
|
||||||
|
|
||||||
|
/// Current state of the DTACK input.
|
||||||
bool dtack_ = false;
|
bool dtack_ = false;
|
||||||
|
/// Current state of the VPA input.
|
||||||
bool vpa_ = false;
|
bool vpa_ = false;
|
||||||
|
/// Current state of the BERR input.
|
||||||
bool berr_ = false;
|
bool berr_ = false;
|
||||||
|
|
||||||
|
/// Contains the prefetch queue; the most-recently fetched thing is the
|
||||||
|
/// low portion of this word, and the thing fetched before that has
|
||||||
|
/// proceeded to the high portion.
|
||||||
SlicedInt32 prefetch_;
|
SlicedInt32 prefetch_;
|
||||||
int operand_ = 0;
|
|
||||||
|
// Temporary storage for the current instruction's operands
|
||||||
|
// and the corresponding effective addresses.
|
||||||
|
CPU::SlicedInt32 operand_[2];
|
||||||
|
uint32_t effective_address_[2];
|
||||||
|
|
||||||
|
/// If currently in the wait-for-DTACK state, this indicates where to go
|
||||||
|
/// upon receipt of DTACK or VPA. BERR will automatically segue
|
||||||
|
/// into the proper exception.
|
||||||
|
int post_dtack_state_ = 0;
|
||||||
|
|
||||||
|
/// The perform state for this operation.
|
||||||
|
int perform_state_ = 0;
|
||||||
|
|
||||||
|
/// When fetching or storing operands, this is the next one to fetch
|
||||||
|
/// or store.
|
||||||
|
int next_operand_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user