1
0
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:
Thomas Harte 2022-05-17 14:08:50 -04:00
parent d0b6451f02
commit 1a27eea46c
3 changed files with 89 additions and 7 deletions

View File

@ -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();
}; };
} }

View File

@ -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();

View File

@ -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]; // D0D7 followed by A0A7. SlicedInt32 registers_[16]; // D0D7 followed by A0A7.
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;
}; };
} }