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:
|
||||
BusHandler &bus_handler_;
|
||||
void setup_operation();
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define _8000Mk2Implementation_h
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
namespace CPU {
|
||||
namespace MC68000Mk2 {
|
||||
@ -145,6 +146,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
prefetch_.high = prefetch_.low; \
|
||||
ReadProgramWord(prefetch_.low)
|
||||
|
||||
using Mode = InstructionSet::M68k::AddressingMode;
|
||||
|
||||
// Otherwise continue for all time, until back in debt.
|
||||
// Formatting is slightly obtuse here to make this look more like a coroutine.
|
||||
while(true) { switch(state_) {
|
||||
@ -181,21 +184,38 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
case State::Decode:
|
||||
opcode_ = prefetch_.high.w;
|
||||
instruction_ = decoder_.decode(opcode_);
|
||||
instruction_address_ = program_counter_.l - 4;
|
||||
|
||||
// TODO: it might be better to switch on instruction_.operation
|
||||
// and establish both the instruction pattern and the operand
|
||||
// flags here?
|
||||
operand_flags_ = InstructionSet::M68k::operand_flags<InstructionSet::M68k::Model::M68000>(instruction_.operation);
|
||||
// TODO: check for privilege and unrecognised instructions.
|
||||
|
||||
operand_ = 0;
|
||||
// Obtain operand flags and pick a perform pattern.
|
||||
setup_operation();
|
||||
|
||||
next_operand_ = 0;
|
||||
[[fallthrough]];
|
||||
|
||||
// Check the operand flags to determine whether the operand at index
|
||||
// operand_ needs to be fetched, and do so.
|
||||
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]];
|
||||
default:
|
||||
printf("Unhandled or unterminated state: %d\n", state_);
|
||||
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>
|
||||
CPU::MC68000Mk2::State Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::get_state() {
|
||||
return CPU::MC68000Mk2::State();
|
||||
|
@ -16,34 +16,76 @@ namespace CPU {
|
||||
namespace MC68000Mk2 {
|
||||
|
||||
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 {
|
||||
Reset = -1,
|
||||
Decode = -2,
|
||||
WaitForDTACK = -3,
|
||||
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;
|
||||
|
||||
/// Counts time left on the clock before the current batch of processing
|
||||
/// is complete; may be less than zero.
|
||||
HalfCycles time_remaining_;
|
||||
int post_dtack_state_ = 0;
|
||||
|
||||
/// Current supervisor state, for direct provision to the bus handler.
|
||||
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::Preinstruction instruction_;
|
||||
uint16_t opcode_;
|
||||
uint8_t operand_flags_;
|
||||
uint32_t instruction_address_;
|
||||
|
||||
// Register state.
|
||||
InstructionSet::M68k::Status status_;
|
||||
SlicedInt32 program_counter_;
|
||||
SlicedInt32 registers_[16]; // D0–D7 followed by A0–A7.
|
||||
SlicedInt32 stack_pointers_[2];
|
||||
|
||||
/// Current state of the DTACK input.
|
||||
bool dtack_ = false;
|
||||
/// Current state of the VPA input.
|
||||
bool vpa_ = false;
|
||||
/// Current state of the BERR input.
|
||||
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_;
|
||||
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