1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-09 06:29:33 +00:00

Completes performance of NBCD D0.

This commit is contained in:
Thomas Harte 2022-05-17 16:10:20 -04:00
parent eed2672db5
commit 4a40581deb
4 changed files with 98 additions and 61 deletions

View File

@ -181,7 +181,7 @@ struct Test68000 {
// This is the test class for 68000 execution. // This is the test class for 68000 execution.
struct Test68000: public CPU::MC68000Mk2::BusHandler { struct Test68000: public CPU::MC68000Mk2::BusHandler {
std::array<uint8_t, 16*1024*1024> ram; std::array<uint8_t, 16*1024*1024> ram;
CPU::MC68000Mk2::Processor<Test68000> processor; CPU::MC68000Mk2::Processor<Test68000, true, false, true> processor;
std::function<void(void)> comparitor; std::function<void(void)> comparitor;
Test68000() : processor(*this) {} Test68000() : processor(*this) {}

View File

@ -13,8 +13,6 @@
#include "../../Numeric/RegisterSizes.hpp" #include "../../Numeric/RegisterSizes.hpp"
#include "../../InstructionSets/M68k/RegisterSet.hpp" #include "../../InstructionSets/M68k/RegisterSet.hpp"
#include "Implementation/68000Mk2Storage.hpp"
namespace CPU { namespace CPU {
namespace MC68000Mk2 { namespace MC68000Mk2 {
@ -361,6 +359,14 @@ struct State {
InstructionSet::M68k::RegisterSet registers; InstructionSet::M68k::RegisterSet registers;
}; };
}
}
#include "Implementation/68000Mk2Storage.hpp"
namespace CPU {
namespace MC68000Mk2 {
/*! /*!
Provides an emulation of the 68000 with accurate bus logic via the @c BusHandler, subject to the following template parameters: Provides an emulation of the 68000 with accurate bus logic via the @c BusHandler, subject to the following template parameters:

View File

@ -60,31 +60,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// (* an extension supported by at least GCC, Clang and MSVC) // (* an extension supported by at least GCC, Clang and MSVC)
// Some microcycles that will be modified as required and used in the loop below;
// the semantics of a switch statement make in-place declarations awkward.
Microcycle idle{0};
// Read a data word.
Microcycle read_word_data_announce {
Microcycle::Read | Microcycle::NewAddress | Microcycle::IsData
};
Microcycle read_word_data {
Microcycle::Read | Microcycle::SameAddress | Microcycle::SelectWord | Microcycle::IsData
};
// Read a program word. All accesses via the program counter are word sized.
Microcycle read_program_announce {
Microcycle::Read | Microcycle::NewAddress | Microcycle::IsProgram
};
Microcycle read_program {
Microcycle::Read | Microcycle::SameAddress | Microcycle::SelectWord | Microcycle::IsProgram
};
// Holding spot when awaiting DTACK/etc.
Microcycle awaiting_dtack;
// Spare containers: // Spare containers:
uint32_t address = 0; // For an address, where it isn't provideable by reference.
HalfCycles delay; // To receive any additional time added on by calls to perform_bus_operation. HalfCycles delay; // To receive any additional time added on by calls to perform_bus_operation.
// Helper macros for common bus transactions: // Helper macros for common bus transactions:
@ -125,7 +101,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Performs the memory access implied by the announce, perform pair, // Performs the memory access implied by the announce, perform pair,
// honouring DTACK, BERR and VPA as necessary. // honouring DTACK, BERR and VPA as necessary.
#define AccessPair(addr, val, announce, perform) \ #define AccessPair(addr, val, announce, perform) \
perform.address = announce.address = &addr; \ announce.address = perform.address = &addr; \
perform.value = &val; \ perform.value = &val; \
if constexpr (!dtack_is_implicit) { \ if constexpr (!dtack_is_implicit) { \
announce.length = HalfCycles(4); \ announce.length = HalfCycles(4); \
@ -135,10 +111,11 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
CompleteAccess(perform); CompleteAccess(perform);
// Reads the data (i.e. non-program) word from addr into val. // Reads the data (i.e. non-program) word from addr into val.
#define ReadDataWord(addr, val) AccessPair(addr, val, read_word_data_announce, read_word_data) #define ReadDataWord(addr, val) \
AccessPair(addr, val, read_word_data_announce, read_word_data)
// Reads the program (i.e. non-data) word from addr into val. // Reads the program (i.e. non-data) word from addr into val.
#define ReadProgramWord(val) \ #define ReadProgramWord(val) \
AccessPair(program_counter_.l, val, read_program_announce, read_program); \ AccessPair(program_counter_.l, val, read_program_announce, read_program); \
program_counter_.l += 2; program_counter_.l += 2;
@ -175,10 +152,17 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
status_.trace_flag = 0; status_.trace_flag = 0;
did_update_status(); did_update_status();
address = 0; ReadDataWord(address, registers_[15].high); // nF temporary_address_ = 0;
address += 2; ReadDataWord(address, registers_[15].low); // nf ReadDataWord(temporary_address_, registers_[15].high); // nF
address += 2; ReadDataWord(address, program_counter_.high); // nV
address += 2; ReadDataWord(address, program_counter_.low); // nv temporary_address_ += 2;
ReadDataWord(temporary_address_, registers_[15].low); // nf
temporary_address_ += 2;
ReadDataWord(temporary_address_, program_counter_.high); // nV
temporary_address_ += 2;
ReadDataWord(temporary_address_, program_counter_.low); // nv
Prefetch(); // np Prefetch(); // np
IdleBus(1); // n IdleBus(1); // n
@ -196,14 +180,14 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// TODO: check for privilege and unrecognised instructions. // TODO: check for privilege and unrecognised instructions.
// Obtain operand flags and pick a perform pattern.
setup_operation();
// Signal the bus handler if requested. // Signal the bus handler if requested.
if constexpr (signal_will_perform) { if constexpr (signal_will_perform) {
bus_handler_.will_perform(instruction_address_, opcode_); bus_handler_.will_perform(instruction_address_, opcode_);
} }
// Obtain operand flags and pick a perform pattern.
setup_operation();
// Ensure the first parameter is next fetched. // Ensure the first parameter is next fetched.
next_operand_ = 0; next_operand_ = 0;
[[fallthrough]]; [[fallthrough]];
@ -235,16 +219,33 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
} }
break; break;
// Store operand is a lot simpler: only one operand is ever stored, and its address
// is already known. So this can either skip straight back to ::Decode if the target
// is a register, otherwise a single write operation can occur.
case State::StoreOperand:
if(instruction_.mode(next_operand_) <= Mode::AddressRegisterDirect) {
registers_[instruction_.lreg(next_operand_)] = operand_[next_operand_];
state_ = State::Decode;
continue;
}
// TODO: make a decision on how I'm going to deal with byte/word/longword.
assert(false);
break;
// //
// Various forms of perform. // Various forms of perform.
// //
#define MoveToWritePhase() \
next_operand_ = operand_flags_ >> 3; \
MoveToState(operand_flags_ & 0x0c ? State::StoreOperand : State::Decode)
case State::Perform_np: case State::Perform_np:
InstructionSet::M68k::perform<InstructionSet::M68k::Model::M68000>( InstructionSet::M68k::perform<InstructionSet::M68k::Model::M68000>(
instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this)); instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this));
Prefetch(); // np Prefetch(); // np
next_operand_ = 0; MoveToWritePhase();
MoveToState(operand_flags_ & 0x0c ? State::StoreOperand : State::Decode);
break; break;
case State::Perform_np_n: case State::Perform_np_n:
@ -253,10 +254,10 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
Prefetch(); // np Prefetch(); // np
IdleBus(1); // n IdleBus(1); // n
next_operand_ = 0; MoveToWritePhase();
MoveToState(operand_flags_ & 0x0c ? State::StoreOperand : State::Decode);
break; break;
#undef MoveToWritePhase
default: default:
printf("Unhandled state: %d\n", state_); printf("Unhandled state: %d\n", state_);

View File

@ -90,37 +90,67 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
/// or store. /// or store.
int next_operand_ = 0; int next_operand_ = 0;
/// Storage for a temporary address, which can't be a local because it'll
/// be used to populate microcycles, which may persist beyond an entry
/// and exit of run_for (especially between an address announcement, and
/// a data select).
uint32_t temporary_address_ = 0;
// Flow controller... all TODO. // Flow controller... all TODO.
using Preinstruction = InstructionSet::M68k::Preinstruction; using Preinstruction = InstructionSet::M68k::Preinstruction;
template <typename IntT> void did_mulu(IntT) {} template <typename IntT> void did_mulu(IntT) {}
template <typename IntT> void did_muls(IntT) {} template <typename IntT> void did_muls(IntT) {}
void did_chk([[maybe_unused]] bool was_under, [[maybe_unused]] bool was_over) {} void did_chk(bool, bool) {}
void did_shift([[maybe_unused]] int bit_count) {} void did_shift(int) {}
template <bool did_overflow> void did_divu([[maybe_unused]] uint32_t dividend, [[maybe_unused]] uint32_t divisor) {} template <bool did_overflow> void did_divu(uint32_t, uint32_t) {}
template <bool did_overflow> void did_divs([[maybe_unused]] int32_t dividend, [[maybe_unused]] int32_t divisor) {} template <bool did_overflow> void did_divs(int32_t, int32_t) {}
void did_bit_op([[maybe_unused]] int bit_position) {} void did_bit_op(int) {}
inline void did_update_status(); inline void did_update_status();
template <typename IntT> void complete_bcc(bool matched_condition, IntT offset) {} template <typename IntT> void complete_bcc(bool, IntT) {}
void complete_dbcc(bool matched_condition, bool overflowed, int16_t offset) {} void complete_dbcc(bool, bool, int16_t) {}
void bsr(uint32_t offset) {} void bsr(uint32_t) {}
void jsr(uint32_t address) {} void jsr(uint32_t) {}
void jmp(uint32_t address) {} void jmp(uint32_t) {}
void rtr() {} void rtr() {}
void rte() {} void rte() {}
void rts() {} void rts() {}
void stop() {} void stop() {}
void reset() {} void reset() {}
void link(Preinstruction instruction, uint32_t offset) {} void link(Preinstruction, uint32_t) {}
void unlink(uint32_t &address) {} void unlink(uint32_t &) {}
void pea(uint32_t address) {} void pea(uint32_t) {}
void move_to_usp(uint32_t address) {} void move_to_usp(uint32_t) {}
void move_from_usp(uint32_t &address) {} void move_from_usp(uint32_t &) {}
void tas(Preinstruction instruction, uint32_t address) {} void tas(Preinstruction, uint32_t) {}
template <typename IntT> void movep(Preinstruction instruction, uint32_t source, uint32_t dest) {} template <typename IntT> void movep(Preinstruction, uint32_t, uint32_t) {}
template <typename IntT> void movem_toM(Preinstruction instruction, uint32_t mask, uint32_t address) {} template <typename IntT> void movem_toM(Preinstruction, uint32_t, uint32_t) {}
template <typename IntT> void movem_toR(Preinstruction instruction, uint32_t mask, uint32_t address) {} template <typename IntT> void movem_toR(Preinstruction, uint32_t, uint32_t) {}
template <bool use_current_instruction_pc = true> void raise_exception([[maybe_unused]] int vector) {} template <bool use_current_instruction_pc = true> void raise_exception(int) {}
// Some microcycles that will be modified as required and used in the main loop;
// the semantics of a switch statement make in-place declarations awkward and
// some of these may persist across multiple calls to run_for.
Microcycle idle{0};
// Read a data word.
Microcycle read_word_data_announce {
Microcycle::Read | Microcycle::NewAddress | Microcycle::IsData
};
Microcycle read_word_data {
Microcycle::Read | Microcycle::SameAddress | Microcycle::SelectWord | Microcycle::IsData
};
// Read a program word. All accesses via the program counter are word sized.
Microcycle read_program_announce {
Microcycle::Read | Microcycle::NewAddress | Microcycle::IsProgram
};
Microcycle read_program {
Microcycle::Read | Microcycle::SameAddress | Microcycle::SelectWord | Microcycle::IsProgram
};
// Holding spot when awaiting DTACK/etc.
Microcycle awaiting_dtack;
}; };
} }