diff --git a/Processors/65816/Implementation/65816Base.cpp b/Processors/65816/Implementation/65816Base.cpp index ab1e699ca..736ed2268 100644 --- a/Processors/65816/Implementation/65816Base.cpp +++ b/Processors/65816/Implementation/65816Base.cpp @@ -14,7 +14,7 @@ uint16_t ProcessorBase::get_value_of_register(Register r) const { switch (r) { case Register::ProgramCounter: return pc_; case Register::LastOperationAddress: return last_operation_pc_; - case Register::StackPointer: return s_; + case Register::StackPointer: return s_.full; // case Register::Flags: return get_flags(); case Register::A: return a_.full; case Register::X: return x_.full; @@ -26,11 +26,11 @@ uint16_t ProcessorBase::get_value_of_register(Register r) const { void ProcessorBase::set_value_of_register(Register r, uint16_t value) { switch (r) { case Register::ProgramCounter: pc_ = value; break; - case Register::StackPointer: s_ = value; break; + case Register::StackPointer: s_.full = value; break; // case Register::Flags: set_flags(uint8_t(value)); break; - case Register::A: a_ = value; break; - case Register::X: x_ = value; break; - case Register::Y: y_ = value; break; + case Register::A: a_.full = value; break; + case Register::X: x_.full = value; break; + case Register::Y: y_.full = value; break; default: break; } } diff --git a/Processors/65816/Implementation/65816Implementation.hpp b/Processors/65816/Implementation/65816Implementation.hpp index 0a8602254..b85ac3779 100644 --- a/Processors/65816/Implementation/65816Implementation.hpp +++ b/Processors/65816/Implementation/65816Implementation.hpp @@ -24,32 +24,38 @@ template void Processor::run_for(const Cycles // Scheduling. // - case OperationMoveToNextProgram: + 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]; + const auto offset = instructions[pending_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offsets[0]; + next_op_ = µ_ops_[offset]; instruction_buffer_.clear(); data_buffer_.clear(); last_operation_pc_ = pc_; - continue; + } continue; - case OperationDecode: + 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]; + active_instruction_ = &instructions[instruction_offset_ + instruction_buffer_.value]; + + const auto size_flag = mx_flags_[active_instruction_->size_field]; + next_op_ = µ_ops_[active_instruction_->program_offsets[size_flag]]; instruction_buffer_.clear(); - continue; + } continue; // // PC fetches. // case CycleFetchIncrementPC: + case CycleFetchOpcode: bus_address = pc_ | program_bank_; bus_value = instruction_buffer_.next(); - bus_operation = MOS6502Esque::Read; // TODO: indicate ReadOpcode when appropriate. + bus_operation = (operation == CycleFetchOpcode) ? MOS6502Esque::ReadOpcode : MOS6502Esque::Read; + // TODO: split this action when I'm happy that my route to bus accesses is settled, to avoid repeating the conditional + // embedded into the `switch`. ++pc_; break; @@ -78,14 +84,40 @@ template void Processor::run_for(const Cycles case OperationPerform: switch(active_instruction_->operation) { + + // + // Flag manipulation. + // + case CLD: - // TODO. + decimal_flag_ = 0; + break; + + // + // Loads, stores and transfers + // + +#define LD(dest, src, masks) dest.full = (dest.full & masks[0]) | (src & masks[1]) + + case LDA: + LD(a_, data_buffer_.value, m_masks_); break; case LDX: - // TODO. + LD(x_, data_buffer_.value, x_masks_); break; + case LDY: + LD(y_, data_buffer_.value, x_masks_); + break; + + case TXS: + // TODO: does this transfer in full when in 8-bit index mode? + LD(s_, x_.full, x_masks_); + break; + +#undef LD + default: assert(false); } diff --git a/Processors/65816/Implementation/65816Storage.cpp b/Processors/65816/Implementation/65816Storage.cpp index f6f10deda..c57ca6ee1 100644 --- a/Processors/65816/Implementation/65816Storage.cpp +++ b/Processors/65816/Implementation/65816Storage.cpp @@ -97,11 +97,11 @@ struct CPU::WDC65816::ProcessorStorageConstructor { } // Fill in the proper table entries and increment the opcode pointer. - storage_.instructions[opcode].program_offset = uint16_t(micro_op_location_8); + storage_.instructions[opcode].program_offsets[0] = uint16_t(micro_op_location_16); + storage_.instructions[opcode].program_offsets[1] = uint16_t(micro_op_location_8); storage_.instructions[opcode].operation = operation; - storage_.instructions[opcode + 256].program_offset = uint16_t(micro_op_location_16); - storage_.instructions[opcode + 256].operation = operation; + // TODO: fill in size_field. ++opcode; } @@ -109,14 +109,15 @@ struct CPU::WDC65816::ProcessorStorageConstructor { void set_exception_generator(Generator generator) { const auto key = std::make_pair(AccessType::Read, generator); const auto map_entry = installed_patterns.find(key); - storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offset = uint16_t(map_entry->second.first); + storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[0] = + storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[1] = uint16_t(map_entry->second.first); storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = BRK; } void install_fetch_decode_execute() { - storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offset = uint16_t(storage_.micro_ops_.size()); - storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].operation = NOP; - storage_.micro_ops_.push_back(CycleFetchIncrementPC); + storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offsets[0] = + storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offsets[1] = uint16_t(storage_.micro_ops_.size()); + storage_.micro_ops_.push_back(CycleFetchOpcode); storage_.micro_ops_.push_back(OperationDecode); } diff --git a/Processors/65816/Implementation/65816Storage.hpp b/Processors/65816/Implementation/65816Storage.hpp index 79cda40b7..680f42d18 100644 --- a/Processors/65816/Implementation/65816Storage.hpp +++ b/Processors/65816/Implementation/65816Storage.hpp @@ -11,6 +11,8 @@ enum MicroOp: uint8_t { CycleFetchIncrementPC, /// Fetches a byte from the program counter without incrementing it, and throws it away. CycleFetchPC, + /// The same as CycleFetchIncrementPC but indicates valid program address rather than valid data address. + CycleFetchOpcode, /// Fetches a byte from the data address to the data buffer. CycleFetchData, @@ -171,30 +173,42 @@ struct ProcessorStorage { // Frustratingly, there is not quite enough space in 16 bits to store both // the program offset and the operation as currently defined. struct Instruction { - uint16_t program_offset; - Operation operation; + /// Pointers into micro_ops_ for: [0] = 16-bit operation; [1] = 8-bit operation. + uint16_t program_offsets[2] = {0xffff, 0xffff}; + /// The operation to perform upon an OperationPerform. + Operation operation = NOP; + /// An index into the mx field indicating which of M or X affects whether this is an 8-bit or 16-bit field. + /// So the program to perform is that at @c program_offsets[mx_flags[size_field]] + uint8_t size_field = 0; }; - Instruction instructions[514]; // Arranged as: - // 256 entries: emulation-mode instructions; - // 256 entries: 16-bit instructions; - // the entry for 'exceptions' (i.e. reset, irq, nmi); and - // the entry for fetch-decode-execute. + Instruction instructions[256 + 2]; // Arranged as: + // 256 entries: instructions; + // the entry for 'exceptions' (i.e. reset, irq, nmi); and + // the entry for fetch-decode-execute. enum class OperationSlot { - Exception = 512, + Exception = 256, FetchDecodeExecute }; // Registers. RegisterPair16 a_; RegisterPair16 x_, y_; - uint16_t pc_, s_; + RegisterPair16 s_; + uint16_t pc_; // A helper for testing. uint16_t last_operation_pc_; Instruction *active_instruction_; Cycles cycles_left_to_run_; + // Flags aplenty. + uint8_t carry_flag_, negative_result_, zero_result_, decimal_flag_, overflow_flag_, inverse_interrupt_flag_ = 0; + uint8_t mx_flags_[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`. + uint16_t m_masks_[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask. + uint16_t x_masks_[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask. + int instruction_offset_ = 0; + // I.e. the offset for direct addressing (outside of emulation mode). uint16_t direct_ = 0;