diff --git a/Processors/65816/65816.hpp b/Processors/65816/65816.hpp index 327855251..f47d9711b 100644 --- a/Processors/65816/65816.hpp +++ b/Processors/65816/65816.hpp @@ -29,6 +29,7 @@ class ProcessorBase: protected ProcessorStorage { inline void set_power_on(bool); inline void set_irq_line(bool); inline void set_nmi_line(bool); + inline void set_reset_line(bool); void set_value_of_register(Register r, uint16_t value); inline bool is_jammed() const; diff --git a/Processors/65816/Implementation/65816Base.cpp b/Processors/65816/Implementation/65816Base.cpp index f0165281d..ab1e699ca 100644 --- a/Processors/65816/Implementation/65816Base.cpp +++ b/Processors/65816/Implementation/65816Base.cpp @@ -12,25 +12,25 @@ using namespace CPU::WDC65816; uint16_t ProcessorBase::get_value_of_register(Register r) const { switch (r) { -// case Register::ProgramCounter: return pc_.full; -// case Register::LastOperationAddress: return last_operation_pc_.full; -// case Register::StackPointer: return s_; + case Register::ProgramCounter: return pc_; + case Register::LastOperationAddress: return last_operation_pc_; + case Register::StackPointer: return s_; // case Register::Flags: return get_flags(); -// case Register::A: return a_; -// case Register::X: return x_; -// case Register::Y: return y_; + case Register::A: return a_.full; + case Register::X: return x_.full; + case Register::Y: return y_.full; default: return 0; } } void ProcessorBase::set_value_of_register(Register r, uint16_t value) { switch (r) { -// case Register::ProgramCounter: pc_.full = value; break; -// case Register::StackPointer: s_ = uint8_t(value); break; + case Register::ProgramCounter: pc_ = value; break; + case Register::StackPointer: s_ = value; break; // case Register::Flags: set_flags(uint8_t(value)); break; -// case Register::A: a_ = uint8_t(value); break; -// case Register::X: x_ = uint8_t(value); break; -// case Register::Y: y_ = uint8_t(value); break; + case Register::A: a_ = value; break; + case Register::X: x_ = value; break; + case Register::Y: y_ = value; break; default: break; } } diff --git a/Processors/65816/Implementation/65816Implementation.hpp b/Processors/65816/Implementation/65816Implementation.hpp index ae6d8189a..0a8602254 100644 --- a/Processors/65816/Implementation/65816Implementation.hpp +++ b/Processors/65816/Implementation/65816Implementation.hpp @@ -7,28 +7,130 @@ // template void Processor::run_for(const Cycles cycles) { - auto int_cycles = cycles.as_integral(); - while(int_cycles--) { + // Temporary storage for the next bus cycle. + 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_; ++next_op_; switch(operation) { + + // + // Scheduling. + // + case OperationMoveToNextProgram: // The exception program will determine the appropriate way to respond // based on the pending exception if one exists; otherwise just do a // standard fetch-decode-execute. next_op_ = µ_ops_[instructions[pending_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offset]; - - // TODO: reset instruction buffer. + instruction_buffer_.clear(); + data_buffer_.clear(); + last_operation_pc_ = pc_; 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: 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) {} -void ProcessorBase::set_nmi_line(bool) {} +void ProcessorBase::set_irq_line(bool active) { + if(active) { + 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; } diff --git a/Processors/65816/Implementation/65816Storage.cpp b/Processors/65816/Implementation/65816Storage.cpp index 31e5642ad..889eea8bc 100644 --- a/Processors/65816/Implementation/65816Storage.cpp +++ b/Processors/65816/Implementation/65816Storage.cpp @@ -988,6 +988,10 @@ ProcessorStorage::ProcessorStorage() { constructor.set_exception_generator(&ProcessorStorageConstructor::stack_exception); constructor.install_fetch_decode_execute(); + // Find any OperationMoveToNextProgram. + next_op_ = micro_ops_.data(); + while(*next_op_ != OperationMoveToNextProgram) ++next_op_; + #ifndef NDEBUG assert(micro_ops_.size() < 65536); printf("Generated %zd micro-ops in total; covered %d opcodes\n", micro_ops_.size(), constructor.opcode); diff --git a/Processors/65816/Implementation/65816Storage.hpp b/Processors/65816/Implementation/65816Storage.hpp index 388a6493e..79cda40b7 100644 --- a/Processors/65816/Implementation/65816Storage.hpp +++ b/Processors/65816/Implementation/65816Storage.hpp @@ -185,34 +185,29 @@ struct ProcessorStorage { 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. RegisterPair16 a_; RegisterPair16 x_, y_; 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). - uint16_t direct_; + uint16_t direct_ = 0; // Banking registers are all stored with the relevant byte // shifted up bits 16–23. - uint32_t data_bank_; // i.e. DBR. - uint32_t program_bank_; // i.e. PBR. + uint32_t data_bank_ = 0; // i.e. DBR. + uint32_t program_bank_ = 0; // i.e. PBR. static constexpr int PowerOn = 1 << 0; static constexpr int Reset = 1 << 1; static constexpr int IRQ = 1 << 2; 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 /// to most significant.