mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-18 01:30:56 +00:00
The actual work begins: starts implementing 65816 micro-ops.
This commit is contained in:
parent
ef1a514785
commit
78b3ec4b10
@ -29,6 +29,7 @@ class ProcessorBase: protected ProcessorStorage {
|
|||||||
inline void set_power_on(bool);
|
inline void set_power_on(bool);
|
||||||
inline void set_irq_line(bool);
|
inline void set_irq_line(bool);
|
||||||
inline void set_nmi_line(bool);
|
inline void set_nmi_line(bool);
|
||||||
|
inline void set_reset_line(bool);
|
||||||
void set_value_of_register(Register r, uint16_t value);
|
void set_value_of_register(Register r, uint16_t value);
|
||||||
|
|
||||||
inline bool is_jammed() const;
|
inline bool is_jammed() const;
|
||||||
|
@ -12,25 +12,25 @@ using namespace CPU::WDC65816;
|
|||||||
|
|
||||||
uint16_t ProcessorBase::get_value_of_register(Register r) const {
|
uint16_t ProcessorBase::get_value_of_register(Register r) const {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
// case Register::ProgramCounter: return pc_.full;
|
case Register::ProgramCounter: return pc_;
|
||||||
// case Register::LastOperationAddress: return last_operation_pc_.full;
|
case Register::LastOperationAddress: return last_operation_pc_;
|
||||||
// case Register::StackPointer: return s_;
|
case Register::StackPointer: return s_;
|
||||||
// case Register::Flags: return get_flags();
|
// case Register::Flags: return get_flags();
|
||||||
// case Register::A: return a_;
|
case Register::A: return a_.full;
|
||||||
// case Register::X: return x_;
|
case Register::X: return x_.full;
|
||||||
// case Register::Y: return y_;
|
case Register::Y: return y_.full;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessorBase::set_value_of_register(Register r, uint16_t value) {
|
void ProcessorBase::set_value_of_register(Register r, uint16_t value) {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
// case Register::ProgramCounter: pc_.full = value; break;
|
case Register::ProgramCounter: pc_ = value; break;
|
||||||
// case Register::StackPointer: s_ = uint8_t(value); break;
|
case Register::StackPointer: s_ = value; break;
|
||||||
// case Register::Flags: set_flags(uint8_t(value)); break;
|
// case Register::Flags: set_flags(uint8_t(value)); break;
|
||||||
// case Register::A: a_ = uint8_t(value); break;
|
case Register::A: a_ = value; break;
|
||||||
// case Register::X: x_ = uint8_t(value); break;
|
case Register::X: x_ = value; break;
|
||||||
// case Register::Y: y_ = uint8_t(value); break;
|
case Register::Y: y_ = value; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,28 +7,130 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles cycles) {
|
template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles cycles) {
|
||||||
auto int_cycles = cycles.as_integral();
|
// Temporary storage for the next bus cycle.
|
||||||
while(int_cycles--) {
|
uint32_t bus_address = 0;
|
||||||
|
uint8_t *bus_value = nullptr;
|
||||||
|
uint8_t throwaway = 0;
|
||||||
|
BusOperation bus_operation = BusOperation::None;
|
||||||
|
|
||||||
|
Cycles number_of_cycles = cycles + cycles_left_to_run_;
|
||||||
|
while(number_of_cycles > Cycles(0)) {
|
||||||
const MicroOp operation = *next_op_;
|
const MicroOp operation = *next_op_;
|
||||||
++next_op_;
|
++next_op_;
|
||||||
|
|
||||||
switch(operation) {
|
switch(operation) {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Scheduling.
|
||||||
|
//
|
||||||
|
|
||||||
case OperationMoveToNextProgram:
|
case OperationMoveToNextProgram:
|
||||||
// The exception program will determine the appropriate way to respond
|
// The exception program will determine the appropriate way to respond
|
||||||
// based on the pending exception if one exists; otherwise just do a
|
// based on the pending exception if one exists; otherwise just do a
|
||||||
// standard fetch-decode-execute.
|
// standard fetch-decode-execute.
|
||||||
next_op_ = µ_ops_[instructions[pending_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offset];
|
next_op_ = µ_ops_[instructions[pending_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offset];
|
||||||
|
instruction_buffer_.clear();
|
||||||
// TODO: reset instruction buffer.
|
data_buffer_.clear();
|
||||||
|
last_operation_pc_ = pc_;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case OperationDecode:
|
||||||
|
// A VERY TEMPORARY piece of logging.
|
||||||
|
printf("%02x\n", instruction_buffer_.value);
|
||||||
|
active_instruction_ = &instructions[instruction_buffer_.value];
|
||||||
|
next_op_ = µ_ops_[active_instruction_->program_offset];
|
||||||
|
instruction_buffer_.clear();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//
|
||||||
|
// PC fetches.
|
||||||
|
//
|
||||||
|
|
||||||
|
case CycleFetchIncrementPC:
|
||||||
|
bus_address = pc_ | program_bank_;
|
||||||
|
bus_value = instruction_buffer_.next();
|
||||||
|
bus_operation = MOS6502Esque::Read; // TODO: indicate ReadOpcode when appropriate.
|
||||||
|
++pc_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CycleFetchPC:
|
||||||
|
bus_address = pc_ | program_bank_;
|
||||||
|
bus_value = &throwaway;
|
||||||
|
bus_operation = MOS6502Esque::Read;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Data movement.
|
||||||
|
//
|
||||||
|
|
||||||
|
case OperationCopyPCToData:
|
||||||
|
data_buffer_.size = 2;
|
||||||
|
data_buffer_.value = pc_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OperationCopyInstructionToData:
|
||||||
|
data_buffer_ = instruction_buffer_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Performance.
|
||||||
|
//
|
||||||
|
|
||||||
|
case OperationPerform:
|
||||||
|
switch(active_instruction_->operation) {
|
||||||
|
case CLD:
|
||||||
|
// TODO.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LDX:
|
||||||
|
// TODO.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
number_of_cycles -= bus_handler_.perform_bus_operation(bus_operation, bus_address, bus_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
cycles_left_to_run_ = number_of_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBase::set_power_on(bool active) {
|
||||||
|
if(active) {
|
||||||
|
pending_exceptions_ |= PowerOn;
|
||||||
|
} else {
|
||||||
|
pending_exceptions_ &= ~PowerOn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessorBase::set_power_on(bool) {}
|
void ProcessorBase::set_irq_line(bool active) {
|
||||||
void ProcessorBase::set_irq_line(bool) {}
|
if(active) {
|
||||||
void ProcessorBase::set_nmi_line(bool) {}
|
pending_exceptions_ |= IRQ;
|
||||||
|
} else {
|
||||||
|
pending_exceptions_ &= ~IRQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBase::set_reset_line(bool active) {
|
||||||
|
if(active) {
|
||||||
|
pending_exceptions_ |= Reset;
|
||||||
|
} else {
|
||||||
|
pending_exceptions_ &= ~Reset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBase::set_nmi_line(bool active) {
|
||||||
|
// This is edge triggered.
|
||||||
|
if(active) {
|
||||||
|
pending_exceptions_ |= NMI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 65816 can't jam.
|
||||||
bool ProcessorBase::is_jammed() const { return false; }
|
bool ProcessorBase::is_jammed() const { return false; }
|
||||||
|
@ -988,6 +988,10 @@ ProcessorStorage::ProcessorStorage() {
|
|||||||
constructor.set_exception_generator(&ProcessorStorageConstructor::stack_exception);
|
constructor.set_exception_generator(&ProcessorStorageConstructor::stack_exception);
|
||||||
constructor.install_fetch_decode_execute();
|
constructor.install_fetch_decode_execute();
|
||||||
|
|
||||||
|
// Find any OperationMoveToNextProgram.
|
||||||
|
next_op_ = micro_ops_.data();
|
||||||
|
while(*next_op_ != OperationMoveToNextProgram) ++next_op_;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert(micro_ops_.size() < 65536);
|
assert(micro_ops_.size() < 65536);
|
||||||
printf("Generated %zd micro-ops in total; covered %d opcodes\n", micro_ops_.size(), constructor.opcode);
|
printf("Generated %zd micro-ops in total; covered %d opcodes\n", micro_ops_.size(), constructor.opcode);
|
||||||
|
@ -185,34 +185,29 @@ struct ProcessorStorage {
|
|||||||
FetchDecodeExecute
|
FetchDecodeExecute
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_power_on(bool power_on) {
|
|
||||||
if(power_on) {
|
|
||||||
// Set next_op_ to start the exception program.
|
|
||||||
next_op_ = µ_ops_[instructions[size_t(OperationSlot::Exception)].program_offset];
|
|
||||||
pending_exceptions_ = PowerOn;
|
|
||||||
} else {
|
|
||||||
pending_exceptions_ &= ~PowerOn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registers.
|
// Registers.
|
||||||
RegisterPair16 a_;
|
RegisterPair16 a_;
|
||||||
RegisterPair16 x_, y_;
|
RegisterPair16 x_, y_;
|
||||||
uint16_t pc_, s_;
|
uint16_t pc_, s_;
|
||||||
|
|
||||||
|
// A helper for testing.
|
||||||
|
uint16_t last_operation_pc_;
|
||||||
|
Instruction *active_instruction_;
|
||||||
|
Cycles cycles_left_to_run_;
|
||||||
|
|
||||||
// I.e. the offset for direct addressing (outside of emulation mode).
|
// I.e. the offset for direct addressing (outside of emulation mode).
|
||||||
uint16_t direct_;
|
uint16_t direct_ = 0;
|
||||||
|
|
||||||
// Banking registers are all stored with the relevant byte
|
// Banking registers are all stored with the relevant byte
|
||||||
// shifted up bits 16–23.
|
// shifted up bits 16–23.
|
||||||
uint32_t data_bank_; // i.e. DBR.
|
uint32_t data_bank_ = 0; // i.e. DBR.
|
||||||
uint32_t program_bank_; // i.e. PBR.
|
uint32_t program_bank_ = 0; // i.e. PBR.
|
||||||
|
|
||||||
static constexpr int PowerOn = 1 << 0;
|
static constexpr int PowerOn = 1 << 0;
|
||||||
static constexpr int Reset = 1 << 1;
|
static constexpr int Reset = 1 << 1;
|
||||||
static constexpr int IRQ = 1 << 2;
|
static constexpr int IRQ = 1 << 2;
|
||||||
static constexpr int NMI = 1 << 3;
|
static constexpr int NMI = 1 << 3;
|
||||||
int pending_exceptions_ = 0;
|
int pending_exceptions_ = PowerOn; // By default.
|
||||||
|
|
||||||
/// Defines a four-byte buffer which can be cleared or filled in single-byte increments from least significant byte
|
/// Defines a four-byte buffer which can be cleared or filled in single-byte increments from least significant byte
|
||||||
/// to most significant.
|
/// to most significant.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user