1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Wraps all registers into a struct, so that I can implement abort.

Makes some preparations for ready too.
This commit is contained in:
Thomas Harte 2020-10-15 18:42:38 -04:00
parent 3c6adc1ff4
commit c0a1c34012
6 changed files with 321 additions and 294 deletions

View File

@ -36,8 +36,8 @@ template <Type processor_type, typename BusHandler, bool uses_ready_line> class
}; };
template <typename BusHandler, bool uses_ready_line> class Processor<Type::TWDC65816, BusHandler, uses_ready_line>: template <typename BusHandler, bool uses_ready_line> class Processor<Type::TWDC65816, BusHandler, uses_ready_line>:
public CPU::WDC65816::Processor<BusHandler> { public CPU::WDC65816::Processor<BusHandler, uses_ready_line> {
using CPU::WDC65816::Processor<BusHandler>::Processor; using CPU::WDC65816::Processor<BusHandler, uses_ready_line>::Processor;
}; };
} }

View File

@ -34,17 +34,34 @@ class ProcessorBase: protected ProcessorStorage {
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); inline void set_reset_line(bool);
inline void set_abort_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;
uint16_t get_value_of_register(Register r) const; uint16_t get_value_of_register(Register r) const;
}; };
template <typename BusHandler> class Processor: public ProcessorBase { template <typename BusHandler, bool uses_ready_line> class Processor: public ProcessorBase {
public: public:
/*!
Constructs an instance of the 6502 that will use @c bus_handler for all bus communications.
*/
Processor(BusHandler &bus_handler) : bus_handler_(bus_handler) {} Processor(BusHandler &bus_handler) : bus_handler_(bus_handler) {}
/*!
Runs the 6502 for a supplied number of cycles.
@param cycles The number of cycles to run the 6502 for.
*/
void run_for(const Cycles cycles); void run_for(const Cycles cycles);
/*!
Sets the current level of the RDY line.
@param active @c true if the line is logically active; @c false otherwise.
*/
void set_ready_line(bool active);
private: private:
BusHandler &bus_handler_; BusHandler &bus_handler_;
}; };

View File

@ -12,33 +12,33 @@ 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_; case Register::ProgramCounter: return registers_.pc;
case Register::LastOperationAddress: return last_operation_pc_; case Register::LastOperationAddress: return last_operation_pc_;
case Register::StackPointer: return s_.full; case Register::StackPointer: return registers_.s.full;
case Register::Flags: return get_flags(); case Register::Flags: return get_flags();
case Register::A: return a_.full; case Register::A: return registers_.a.full;
case Register::X: return x_.full; case Register::X: return registers_.x.full;
case Register::Y: return y_.full; case Register::Y: return registers_.y.full;
case Register::EmulationFlag: return emulation_flag_; case Register::EmulationFlag: return registers_.emulation_flag;
case Register::DataBank: return data_bank_ >> 16; case Register::DataBank: return registers_.data_bank >> 16;
case Register::ProgramBank: return program_bank_ >> 16; case Register::ProgramBank: return registers_.program_bank >> 16;
case Register::Direct: return direct_; case Register::Direct: return registers_.direct;
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_ = value; break; case Register::ProgramCounter: registers_.pc = value; break;
case Register::StackPointer: s_.full = value; break; case Register::StackPointer: registers_.s.full = value; break;
case Register::Flags: set_flags(uint8_t(value)); break; case Register::Flags: set_flags(uint8_t(value)); break;
case Register::A: a_.full = value; break; case Register::A: registers_.a.full = value; break;
case Register::X: x_.full = value; break; case Register::X: registers_.x.full = value; break;
case Register::Y: y_.full = value; break; case Register::Y: registers_.y.full = value; break;
case Register::EmulationFlag: set_emulation_mode(value); break; case Register::EmulationFlag: set_emulation_mode(value); break;
case Register::DataBank: data_bank_ = uint32_t(value) << 16; break; case Register::DataBank: registers_.data_bank = uint32_t(value) << 16; break;
case Register::ProgramBank: program_bank_ = uint32_t(value) << 16; break; case Register::ProgramBank: registers_.program_bank = uint32_t(value) << 16; break;
case Register::Direct: direct_ = value; break; case Register::Direct: registers_.direct = value; break;
default: break; default: break;
} }
} }

View File

@ -6,27 +6,22 @@
// Copyright © 2020 Thomas Harte. All rights reserved. // Copyright © 2020 Thomas Harte. All rights reserved.
// //
template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles cycles) { template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler, uses_ready_line>::run_for(const Cycles 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;
#define perform_bus(address, value, operation) \ #define perform_bus(address, value, operation) \
bus_address = address; \ bus_address_ = address; \
bus_value = value; \ bus_value_ = value; \
bus_operation = operation bus_operation_ = operation
#define read(address, value) perform_bus(address, value, MOS6502Esque::Read) #define read(address, value) perform_bus(address, value, MOS6502Esque::Read)
#define write(address, value) perform_bus(address, value, MOS6502Esque::Write) #define write(address, value) perform_bus(address, value, MOS6502Esque::Write)
#define m_flag() mx_flags_[0] #define m_flag() registers_.mx_flags[0]
#define x_flag() mx_flags_[1] #define x_flag() registers_.mx_flags[1]
#define x() (x_.full & x_masks_[1]) #define x() (registers_.x.full & registers_.x_masks[1])
#define y() (y_.full & x_masks_[1]) #define y() (registers_.y.full & registers_.x_masks[1])
#define stack_address() ((s_.full & e_masks_[1]) | (0x0100 & e_masks_[0])) #define stack_address() ((registers_.s.full & registers_.e_masks[1]) | (0x0100 & registers_.e_masks[0]))
Cycles number_of_cycles = cycles + cycles_left_to_run_; Cycles number_of_cycles = cycles + cycles_left_to_run_;
while(number_of_cycles > Cycles(0)) { while(number_of_cycles > Cycles(0)) {
@ -35,7 +30,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
#ifndef NDEBUG #ifndef NDEBUG
// As a sanity check. // As a sanity check.
bus_value = nullptr; bus_value_ = nullptr;
#endif #endif
switch(operation) { switch(operation) {
@ -52,13 +47,13 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
next_op_ = &micro_ops_[offset]; next_op_ = &micro_ops_[offset];
instruction_buffer_.clear(); instruction_buffer_.clear();
data_buffer_.clear(); data_buffer_.clear();
last_operation_pc_ = pc_; last_operation_pc_ = registers_.pc;
} continue; } continue;
case OperationDecode: { case OperationDecode: {
active_instruction_ = &instructions[instruction_buffer_.value]; active_instruction_ = &instructions[instruction_buffer_.value];
const auto size_flag = mx_flags_[active_instruction_->size_field]; const auto size_flag = registers_.mx_flags[active_instruction_->size_field];
next_op_ = &micro_ops_[active_instruction_->program_offsets[size_flag]]; next_op_ = &micro_ops_[active_instruction_->program_offsets[size_flag]];
instruction_buffer_.clear(); instruction_buffer_.clear();
} continue; } continue;
@ -68,21 +63,21 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case CycleFetchIncrementPC: case CycleFetchIncrementPC:
read(pc_ | program_bank_, instruction_buffer_.next_input()); read(registers_.pc | registers_.program_bank, instruction_buffer_.next_input());
++pc_; ++registers_.pc;
break; break;
case CycleFetchOpcode: case CycleFetchOpcode:
perform_bus(pc_ | program_bank_, instruction_buffer_.next_input(), MOS6502Esque::ReadOpcode); perform_bus(registers_.pc | registers_.program_bank, instruction_buffer_.next_input(), MOS6502Esque::ReadOpcode);
++pc_; ++registers_.pc;
break; break;
case CycleFetchPC: case CycleFetchPC:
read(pc_ | program_bank_, instruction_buffer_.next_input()); read(registers_.pc | registers_.program_bank, instruction_buffer_.next_input());
break; break;
case CycleFetchPCThrowaway: case CycleFetchPCThrowaway:
read(pc_ | program_bank_, &throwaway); read(registers_.pc | registers_.program_bank, &bus_throwaway_);
break; break;
// //
@ -98,11 +93,11 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
break; break;
case CycleFetchDataThrowaway: case CycleFetchDataThrowaway:
read(data_address_, &throwaway); read(data_address_, &bus_throwaway_);
break; break;
case CycleFetchIncorrectDataAddress: case CycleFetchIncorrectDataAddress:
read(incorrect_data_address_, &throwaway); read(incorrect_data_address_, &bus_throwaway_);
break; break;
case CycleFetchIncrementData: case CycleFetchIncrementData:
@ -133,7 +128,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
break; break;
case CycleFetchBlockY: case CycleFetchBlockY:
read(((instruction_buffer_.value & 0xff00) << 8) | y(), &throwaway); read(((instruction_buffer_.value & 0xff00) << 8) | y(), &bus_throwaway_);
break; break;
case CycleStoreBlockY: case CycleStoreBlockY:
@ -148,28 +143,28 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
#define stack_access(value, operation) \ #define stack_access(value, operation) \
bus_address = stack_address(); \ bus_address_ = stack_address(); \
bus_value = value; \ bus_value_ = value; \
bus_operation = operation; bus_operation_ = operation;
case CyclePush: case CyclePush:
stack_access(data_buffer_.next_output_descending(), MOS6502Esque::Write); stack_access(data_buffer_.next_output_descending(), MOS6502Esque::Write);
--s_.full; --registers_.s.full;
break; break;
case CyclePullIfNotEmulation: case CyclePullIfNotEmulation:
if(emulation_flag_) { if(registers_.emulation_flag) {
continue; continue;
} }
[[fallthrough]]; [[fallthrough]];
case CyclePull: case CyclePull:
++s_.full; ++registers_.s.full;
stack_access(data_buffer_.next_input(), MOS6502Esque::Read); stack_access(data_buffer_.next_input(), MOS6502Esque::Read);
break; break;
case CycleAccessStack: case CycleAccessStack:
stack_access(&throwaway, MOS6502Esque::Read); stack_access(&bus_throwaway_, MOS6502Esque::Read);
break; break;
#undef stack_access #undef stack_access
@ -193,7 +188,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
case OperationCopyPCToData: case OperationCopyPCToData:
data_buffer_.size = 2; data_buffer_.size = 2;
data_buffer_.value = pc_; data_buffer_.value = registers_.pc;
continue; continue;
case OperationCopyInstructionToData: case OperationCopyInstructionToData:
@ -206,21 +201,21 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
continue; continue;
case OperationCopyAToData: case OperationCopyAToData:
data_buffer_.value = a_.full & m_masks_[1]; data_buffer_.value = registers_.a.full & registers_.m_masks[1];
data_buffer_.size = 2 - m_flag(); data_buffer_.size = 2 - m_flag();
continue; continue;
case OperationCopyDataToA: case OperationCopyDataToA:
a_.full = (a_.full & m_masks_[0]) + (data_buffer_.value & m_masks_[1]); registers_.a.full = (registers_.a.full & registers_.m_masks[0]) + (data_buffer_.value & registers_.m_masks[1]);
continue; continue;
case OperationCopyPBRToData: case OperationCopyPBRToData:
data_buffer_.size = 1; data_buffer_.size = 1;
data_buffer_.value = program_bank_ >> 16; data_buffer_.value = registers_.program_bank >> 16;
continue; continue;
case OperationCopyDataToPC: case OperationCopyDataToPC:
pc_ = uint16_t(data_buffer_.value); registers_.pc = uint16_t(data_buffer_.value);
continue; continue;
// //
@ -228,7 +223,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case OperationConstructAbsolute: case OperationConstructAbsolute:
data_address_ = instruction_buffer_.value + data_bank_; data_address_ = instruction_buffer_.value + registers_.data_bank;
data_address_increment_mask_ = 0xff'ff'ff; data_address_increment_mask_ = 0xff'ff'ff;
continue; continue;
@ -244,7 +239,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// Used for JMP and JSR (absolute, x). // Used for JMP and JSR (absolute, x).
case OperationConstructAbsoluteIndexedIndirect: case OperationConstructAbsoluteIndexedIndirect:
data_address_ = program_bank_ + ((instruction_buffer_.value + x()) & 0xffff); data_address_ = registers_.program_bank + ((instruction_buffer_.value + x()) & 0xffff);
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
continue; continue;
@ -255,8 +250,8 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
case OperationConstructAbsoluteXRead: case OperationConstructAbsoluteXRead:
case OperationConstructAbsoluteX: case OperationConstructAbsoluteX:
data_address_ = instruction_buffer_.value + x() + data_bank_; data_address_ = instruction_buffer_.value + x() + registers_.data_bank;
incorrect_data_address_ = (data_address_ & 0xff) | (instruction_buffer_.value & 0xff00) + data_bank_; incorrect_data_address_ = (data_address_ & 0xff) | (instruction_buffer_.value & 0xff00) + registers_.data_bank;
// If the incorrect address isn't actually incorrect, skip its usage. // If the incorrect address isn't actually incorrect, skip its usage.
if(operation == OperationConstructAbsoluteXRead && data_address_ == incorrect_data_address_) { if(operation == OperationConstructAbsoluteXRead && data_address_ == incorrect_data_address_) {
@ -267,8 +262,8 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
case OperationConstructAbsoluteYRead: case OperationConstructAbsoluteYRead:
case OperationConstructAbsoluteY: case OperationConstructAbsoluteY:
data_address_ = instruction_buffer_.value + y() + data_bank_; data_address_ = instruction_buffer_.value + y() + registers_.data_bank;
incorrect_data_address_ = (data_address_ & 0xff) + (instruction_buffer_.value & 0xff00) + data_bank_; incorrect_data_address_ = (data_address_ & 0xff) + (instruction_buffer_.value & 0xff00) + registers_.data_bank;
// If the incorrect address isn't actually incorrect, skip its usage. // If the incorrect address isn't actually incorrect, skip its usage.
if(operation == OperationConstructAbsoluteYRead && data_address_ == incorrect_data_address_) { if(operation == OperationConstructAbsoluteYRead && data_address_ == incorrect_data_address_) {
@ -278,38 +273,38 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
continue; continue;
case OperationConstructDirect: case OperationConstructDirect:
data_address_ = (direct_ + instruction_buffer_.value) & 0xffff; data_address_ = (registers_.direct + instruction_buffer_.value) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
if(!(direct_&0xff)) { if(!(registers_.direct&0xff)) {
// If the low byte is 0 and this is emulation mode, incrementing // If the low byte is 0 and this is emulation mode, incrementing
// is restricted to the low byte. // is restricted to the low byte.
data_address_increment_mask_ = e_masks_[1]; data_address_increment_mask_ = registers_.e_masks[1];
++next_op_; ++next_op_;
} }
continue; continue;
case OperationConstructDirectLong: case OperationConstructDirectLong:
data_address_ = (direct_ + instruction_buffer_.value) & 0xffff; data_address_ = (registers_.direct + instruction_buffer_.value) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
if(!(direct_&0xff)) { if(!(registers_.direct&0xff)) {
++next_op_; ++next_op_;
} }
continue; continue;
case OperationConstructDirectIndirect: case OperationConstructDirectIndirect:
data_address_ = data_bank_ + data_buffer_.value; data_address_ = registers_.data_bank + data_buffer_.value;
data_address_increment_mask_ = 0xff'ff'ff; data_address_increment_mask_ = 0xff'ff'ff;
data_buffer_.clear(); data_buffer_.clear();
continue; continue;
case OperationConstructDirectIndexedIndirect: case OperationConstructDirectIndexedIndirect:
data_address_ = data_bank_ + ( data_address_ = registers_.data_bank + (
((direct_ + x() + instruction_buffer_.value) & e_masks_[1]) + ((registers_.direct + x() + instruction_buffer_.value) & registers_.e_masks[1]) +
(direct_ & e_masks_[0]) (registers_.direct & registers_.e_masks[0])
) & 0xffff; ) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
if(!(direct_&0xff)) { if(!(registers_.direct&0xff)) {
++next_op_; ++next_op_;
} }
continue; continue;
@ -330,43 +325,43 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
case OperationConstructDirectX: case OperationConstructDirectX:
data_address_ = ( data_address_ = (
(direct_ & e_masks_[0]) + (registers_.direct & registers_.e_masks[0]) +
((instruction_buffer_.value + direct_ + x()) & e_masks_[1]) ((instruction_buffer_.value + registers_.direct + x()) & registers_.e_masks[1])
) & 0xffff; ) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
incorrect_data_address_ = (direct_ & 0xff00) + (data_address_ & 0x00ff); incorrect_data_address_ = (registers_.direct & 0xff00) + (data_address_ & 0x00ff);
if(!(direct_&0xff)) { if(!(registers_.direct&0xff)) {
++next_op_; ++next_op_;
} }
continue; continue;
case OperationConstructDirectY: case OperationConstructDirectY:
data_address_ = ( data_address_ = (
(direct_ & e_masks_[0]) + (registers_.direct & registers_.e_masks[0]) +
((instruction_buffer_.value + direct_ + y()) & e_masks_[1]) ((instruction_buffer_.value + registers_.direct + y()) & registers_.e_masks[1])
) & 0xffff; ) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
incorrect_data_address_ = (direct_ & 0xff00) + (data_address_ & 0x00ff); incorrect_data_address_ = (registers_.direct & 0xff00) + (data_address_ & 0x00ff);
if(!(direct_&0xff)) { if(!(registers_.direct&0xff)) {
++next_op_; ++next_op_;
} }
continue; continue;
case OperationConstructStackRelative: case OperationConstructStackRelative:
data_address_ = (s_.full + instruction_buffer_.value) & 0xffff; data_address_ = (registers_.s.full + instruction_buffer_.value) & 0xffff;
data_address_increment_mask_ = 0x00'ff'ff; data_address_increment_mask_ = 0x00'ff'ff;
continue; continue;
case OperationConstructStackRelativeIndexedIndirect: case OperationConstructStackRelativeIndexedIndirect:
data_address_ = data_bank_ + data_buffer_.value + y(); data_address_ = registers_.data_bank + data_buffer_.value + y();
data_address_increment_mask_ = 0xff'ff'ff; data_address_increment_mask_ = 0xff'ff'ff;
data_buffer_.clear(); data_buffer_.clear();
continue; continue;
case OperationConstructPER: case OperationConstructPER:
data_buffer_.value = instruction_buffer_.value + pc_; data_buffer_.value = instruction_buffer_.value + registers_.pc;
data_buffer_.size = 2; data_buffer_.size = 2;
continue; continue;
@ -389,31 +384,31 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
} else if(pending_exceptions_ & NMI) { } else if(pending_exceptions_ & NMI) {
pending_exceptions_ &= ~NMI; pending_exceptions_ &= ~NMI;
data_address_ = 0xfffa; data_address_ = 0xfffa;
} else if(pending_exceptions_ & IRQ & flags_.inverse_interrupt) { } else if(pending_exceptions_ & IRQ & registers_.flags.inverse_interrupt) {
pending_exceptions_ &= ~IRQ; pending_exceptions_ &= ~IRQ;
data_address_ = 0xfffe; data_address_ = 0xfffe;
} else { } else {
is_brk = active_instruction_ == instructions; // Given that BRK has opcode 00. is_brk = active_instruction_ == instructions; // Given that BRK has opcode 00.
if(is_brk) { if(is_brk) {
data_address_ = emulation_flag_ ? 0xfffe : 0xfff6; data_address_ = registers_.emulation_flag ? 0xfffe : 0xfff6;
} else { } else {
// Implicitly: COP. // Implicitly: COP.
data_address_ = 0xfff4; data_address_ = 0xfff4;
} }
} }
data_buffer_.value = (pc_ << 8) | get_flags(); data_buffer_.value = (registers_.pc << 8) | get_flags();
if(emulation_flag_) { if(registers_.emulation_flag) {
if(is_brk) data_buffer_.value |= Flag::Break; if(is_brk) data_buffer_.value |= Flag::Break;
data_buffer_.size = 3; data_buffer_.size = 3;
++next_op_; ++next_op_;
} else { } else {
data_buffer_.value |= program_bank_ << 24; data_buffer_.value |= registers_.program_bank << 24;
data_buffer_.size = 4; data_buffer_.size = 4;
program_bank_ = 0; registers_.program_bank = 0;
} }
flags_.inverse_interrupt = 0; registers_.flags.inverse_interrupt = 0;
} continue; } continue;
// //
@ -421,10 +416,10 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
#define LD(dest, src, masks) dest.full = (dest.full & masks[0]) | (src & masks[1]) #define LD(dest, src, masks) dest.full = (dest.full & masks[0]) | (src & masks[1])
#define m_top() (instruction_buffer_.value >> m_shift_) & 0xff #define m_top() (instruction_buffer_.value >> registers_.m_shift) & 0xff
#define x_top() (x_.full >> x_shift_) & 0xff #define x_top() (registers_.x.full >> registers_.x_shift) & 0xff
#define y_top() (y_.full >> x_shift_) & 0xff #define y_top() (registers_.y.full >> registers_.x_shift) & 0xff
#define a_top() (a_.full >> m_shift_) & 0xff #define a_top() (registers_.a.full >> registers_.m_shift) & 0xff
case OperationPerform: case OperationPerform:
switch(active_instruction_->operation) { switch(active_instruction_->operation) {
@ -434,28 +429,28 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case LDA: case LDA:
LD(a_, data_buffer_.value, m_masks_); LD(registers_.a, data_buffer_.value, registers_.m_masks);
flags_.set_nz(a_.full, m_shift_); registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break; break;
case LDX: case LDX:
LD(x_, data_buffer_.value, x_masks_); LD(registers_.x, data_buffer_.value, registers_.x_masks);
flags_.set_nz(x_.full, x_shift_); registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break; break;
case LDY: case LDY:
LD(y_, data_buffer_.value, x_masks_); LD(registers_.y, data_buffer_.value, registers_.x_masks);
flags_.set_nz(y_.full, x_shift_); registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
break; break;
case PLB: case PLB:
data_bank_ = (data_buffer_.value & 0xff) << 16; registers_.data_bank = (data_buffer_.value & 0xff) << 16;
flags_.set_nz(instruction_buffer_.value); registers_.flags.set_nz(instruction_buffer_.value);
break; break;
case PLD: case PLD:
direct_ = data_buffer_.value; registers_.direct = data_buffer_.value;
flags_.set_nz(instruction_buffer_.value); registers_.flags.set_nz(instruction_buffer_.value);
break; break;
case PLP: case PLP:
@ -463,7 +458,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
break; break;
case STA: case STA:
data_buffer_.value = a_.full & m_masks_[1]; data_buffer_.value = registers_.a.full & registers_.m_masks[1];
data_buffer_.size = 2 - m_flag(); data_buffer_.size = 2 - m_flag();
break; break;
@ -473,27 +468,27 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
break; break;
case STX: case STX:
data_buffer_.value = x_.full & x_masks_[1]; data_buffer_.value = registers_.x.full & registers_.x_masks[1];
data_buffer_.size = 2 - x_flag(); data_buffer_.size = 2 - x_flag();
break; break;
case STY: case STY:
data_buffer_.value = y_.full & x_masks_[1]; data_buffer_.value = registers_.y.full & registers_.x_masks[1];
data_buffer_.size = 2 - m_flag(); data_buffer_.size = 2 - m_flag();
break; break;
case PHB: case PHB:
data_buffer_.value = data_bank_ >> 16; data_buffer_.value = registers_.data_bank >> 16;
data_buffer_.size = 1; data_buffer_.size = 1;
break; break;
case PHK: case PHK:
data_buffer_.value = program_bank_ >> 16; data_buffer_.value = registers_.program_bank >> 16;
data_buffer_.size = 1; data_buffer_.size = 1;
break; break;
case PHD: case PHD:
data_buffer_.value = direct_; data_buffer_.value = registers_.direct;
data_buffer_.size = 2; data_buffer_.size = 2;
break; break;
@ -501,7 +496,7 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
data_buffer_.value = get_flags(); data_buffer_.value = get_flags();
data_buffer_.size = 1; data_buffer_.size = 1;
if(emulation_flag_) { if(registers_.emulation_flag) {
// On the 6502, the break flag is set during a PHP. // On the 6502, the break flag is set during a PHP.
data_buffer_.value |= Flag::Break; data_buffer_.value |= Flag::Break;
} }
@ -514,69 +509,69 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// (and make reasonable guesses as to the N flag). // (and make reasonable guesses as to the N flag).
case TXS: case TXS:
s_ = x_.full & x_masks_[1]; registers_.s = registers_.x.full & registers_.x_masks[1];
break; break;
case TSX: case TSX:
LD(x_, s_.full, x_masks_); LD(registers_.x, registers_.s.full, registers_.x_masks);
flags_.set_nz(x_.full, x_shift_); registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break; break;
case TXY: case TXY:
LD(y_, x_.full, x_masks_); LD(registers_.y, registers_.x.full, registers_.x_masks);
flags_.set_nz(y_.full, x_shift_); registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
break; break;
case TYX: case TYX:
LD(x_, y_.full, x_masks_); LD(registers_.x, registers_.y.full, registers_.x_masks);
flags_.set_nz(x_.full, x_shift_); registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break; break;
case TAX: case TAX:
LD(x_, a_.full, x_masks_); LD(registers_.x, registers_.a.full, registers_.x_masks);
flags_.set_nz(x_.full, x_shift_); registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
break; break;
case TAY: case TAY:
LD(y_, a_.full, x_masks_); LD(registers_.y, registers_.a.full, registers_.x_masks);
flags_.set_nz(y_.full, x_shift_); registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
break; break;
case TXA: case TXA:
LD(a_, x_.full, m_masks_); LD(registers_.a, registers_.x.full, registers_.m_masks);
flags_.set_nz(a_.full, m_shift_); registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break; break;
case TYA: case TYA:
LD(a_, y_.full, m_masks_); LD(registers_.a, registers_.y.full, registers_.m_masks);
flags_.set_nz(a_.full, m_shift_); registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break; break;
case TCD: case TCD:
direct_ = a_.full; registers_.direct = registers_.a.full;
flags_.set_nz(a_.full, 8); registers_.flags.set_nz(registers_.a.full, 8);
break; break;
case TDC: case TDC:
a_.full = direct_; registers_.a.full = registers_.direct;
flags_.set_nz(a_.full, 8); registers_.flags.set_nz(registers_.a.full, 8);
break; break;
case TCS: case TCS:
s_.full = a_.full; registers_.s.full = registers_.a.full;
// No need to worry about byte masking here; for the stack it's handled as the emulation runs. // No need to worry about byte masking here; for the stack it's handled as the emulation runs.
break; break;
case TSC: case TSC:
a_.full = stack_address(); registers_.a.full = stack_address();
flags_.set_nz(a_.full, 8); registers_.flags.set_nz(registers_.a.full, 8);
break; break;
case XBA: { case XBA: {
const uint8_t a_low = a_.halves.low; const uint8_t a_low = registers_.a.halves.low;
a_.halves.low = a_.halves.high; registers_.a.halves.low = registers_.a.halves.high;
a_.halves.high = a_low; registers_.a.halves.high = a_low;
flags_.set_nz(a_.halves.low); registers_.flags.set_nz(registers_.a.halves.low);
} break; } break;
// //
@ -584,38 +579,38 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case JML: case JML:
program_bank_ = instruction_buffer_.value & 0xff0000; registers_.program_bank = instruction_buffer_.value & 0xff0000;
[[fallthrough]]; [[fallthrough]];
case JMP: case JMP:
pc_ = uint16_t(instruction_buffer_.value); registers_.pc = uint16_t(instruction_buffer_.value);
break; break;
case JMPind: case JMPind:
pc_ = data_buffer_.value; registers_.pc = data_buffer_.value;
break; break;
case RTS: case RTS:
pc_ = data_buffer_.value + 1; registers_.pc = data_buffer_.value + 1;
break; break;
case JSL: case JSL:
program_bank_ = instruction_buffer_.value & 0xff0000; registers_.program_bank = instruction_buffer_.value & 0xff0000;
[[fallthrough]]; [[fallthrough]];
case JSR: case JSR:
data_buffer_.value = pc_; data_buffer_.value = registers_.pc;
data_buffer_.size = 2; data_buffer_.size = 2;
pc_ = instruction_buffer_.value; registers_.pc = instruction_buffer_.value;
break; break;
case RTI: case RTI:
pc_ = uint16_t(data_buffer_.value >> 8); registers_.pc = uint16_t(data_buffer_.value >> 8);
set_flags(uint8_t(data_buffer_.value)); set_flags(uint8_t(data_buffer_.value));
if(!emulation_flag_) { if(!registers_.emulation_flag) {
program_bank_ = (data_buffer_.value & 0xff000000) >> 8; registers_.program_bank = (data_buffer_.value & 0xff000000) >> 8;
} }
break; break;
@ -624,33 +619,33 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case MVP: case MVP:
data_bank_ = (instruction_buffer_.value & 0xff) << 16; registers_.data_bank = (instruction_buffer_.value & 0xff) << 16;
--x_.full; --registers_.x.full;
--y_.full; --registers_.y.full;
--a_.full; --registers_.a.full;
if(a_.full) pc_ -= 3; if(registers_.a.full) registers_.pc -= 3;
break; break;
case MVN: case MVN:
data_bank_ = (instruction_buffer_.value & 0xff) << 16; registers_.data_bank = (instruction_buffer_.value & 0xff) << 16;
++x_.full; ++registers_.x.full;
++y_.full; ++registers_.y.full;
--a_.full; --registers_.a.full;
if(a_.full) pc_ -= 3; if(registers_.a.full) registers_.pc -= 3;
break; break;
// //
// Flag manipulation. // Flag manipulation.
// //
case CLC: flags_.carry = 0; break; case CLC: registers_.flags.carry = 0; break;
case CLI: flags_.inverse_interrupt = Flag::Interrupt; break; case CLI: registers_.flags.inverse_interrupt = Flag::Interrupt; break;
case CLV: flags_.overflow = 0; break; case CLV: registers_.flags.overflow = 0; break;
case CLD: flags_.decimal = 0; break; case CLD: registers_.flags.decimal = 0; break;
case SEC: flags_.carry = Flag::Carry; break; case SEC: registers_.flags.carry = Flag::Carry; break;
case SEI: flags_.inverse_interrupt = 0; break; case SEI: registers_.flags.inverse_interrupt = 0; break;
case SED: flags_.decimal = Flag::Decimal; break; case SED: registers_.flags.decimal = Flag::Decimal; break;
case REP: case REP:
set_flags(get_flags() &~ instruction_buffer_.value); set_flags(get_flags() &~ instruction_buffer_.value);
@ -661,9 +656,9 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
break; break;
case XCE: { case XCE: {
const bool old_emulation_flag = emulation_flag_; const bool old_emulation_flag = registers_.emulation_flag;
set_emulation_mode(flags_.carry); set_emulation_mode(registers_.flags.carry);
flags_.carry = old_emulation_flag; registers_.flags.carry = old_emulation_flag;
} break; } break;
// //
@ -672,36 +667,36 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
case INC: case INC:
++data_buffer_.value; ++data_buffer_.value;
flags_.set_nz(data_buffer_.value, m_shift_); registers_.flags.set_nz(data_buffer_.value, registers_.m_shift);
break;; break;;
case DEC: case DEC:
--data_buffer_.value; --data_buffer_.value;
flags_.set_nz(data_buffer_.value, m_shift_); registers_.flags.set_nz(data_buffer_.value, registers_.m_shift);
break; break;
case INX: { case INX: {
const uint16_t x_inc = x_.full + 1; const uint16_t x_inc = registers_.x.full + 1;
LD(x_, x_inc, x_masks_); LD(registers_.x, x_inc, registers_.x_masks);
flags_.set_nz(x_.full, x_shift_); registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
} break; } break;
case DEX: { case DEX: {
const uint16_t x_dec = x_.full - 1; const uint16_t x_dec = registers_.x.full - 1;
LD(x_, x_dec, x_masks_); LD(registers_.x, x_dec, registers_.x_masks);
flags_.set_nz(x_.full, x_shift_); registers_.flags.set_nz(registers_.x.full, registers_.x_shift);
} break; } break;
case INY: { case INY: {
const uint16_t y_inc = y_.full + 1; const uint16_t y_inc = registers_.y.full + 1;
LD(y_, y_inc, x_masks_); LD(registers_.y, y_inc, registers_.x_masks);
flags_.set_nz(y_.full, x_shift_); registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
} break; } break;
case DEY: { case DEY: {
const uint16_t y_dec = y_.full - 1; const uint16_t y_dec = registers_.y.full - 1;
LD(y_, y_dec, x_masks_); LD(registers_.y, y_dec, registers_.x_masks);
flags_.set_nz(y_.full, x_shift_); registers_.flags.set_nz(registers_.y.full, registers_.x_shift);
} break; } break;
// //
@ -709,38 +704,38 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case AND: case AND:
a_.full &= data_buffer_.value | m_masks_[0]; registers_.a.full &= data_buffer_.value | registers_.m_masks[0];
flags_.set_nz(a_.full, m_shift_); registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break; break;
case EOR: case EOR:
a_.full ^= data_buffer_.value; registers_.a.full ^= data_buffer_.value;
flags_.set_nz(a_.full, m_shift_); registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break; break;
case ORA: case ORA:
a_.full |= data_buffer_.value; registers_.a.full |= data_buffer_.value;
flags_.set_nz(a_.full, m_shift_); registers_.flags.set_nz(registers_.a.full, registers_.m_shift);
break; break;
case BIT: case BIT:
flags_.set_n(data_buffer_.value, m_shift_); registers_.flags.set_n(data_buffer_.value, registers_.m_shift);
flags_.set_z(data_buffer_.value & a_.full, m_shift_); registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift);
flags_.overflow = data_buffer_.value & Flag::Overflow; registers_.flags.overflow = data_buffer_.value & Flag::Overflow;
break; break;
case BITimm: case BITimm:
flags_.set_z(data_buffer_.value & a_.full, m_shift_); registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift);
break; break;
case TRB: case TRB:
flags_.set_z(data_buffer_.value & a_.full, m_shift_); registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift);
data_buffer_.value &= ~a_.full; data_buffer_.value &= ~registers_.a.full;
break; break;
case TSB: case TSB:
flags_.set_z(data_buffer_.value & a_.full, m_shift_); registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift);
data_buffer_.value |= a_.full; data_buffer_.value |= registers_.a.full;
break; break;
// //
@ -752,27 +747,27 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
next_op_ += 3; \ next_op_ += 3; \
} else { \ } else { \
data_buffer_.size = 2; \ data_buffer_.size = 2; \
data_buffer_.value = pc_ + int8_t(instruction_buffer_.value); \ data_buffer_.value = registers_.pc + int8_t(instruction_buffer_.value); \
\ \
if((pc_ & 0xff00) == (instruction_buffer_.value & 0xff00)) { \ if((registers_.pc & 0xff00) == (instruction_buffer_.value & 0xff00)) { \
++next_op_; \ ++next_op_; \
} \ } \
} }
case BPL: BRA(!(flags_.negative_result&0x80)); break; case BPL: BRA(!(registers_.flags.negative_result&0x80)); break;
case BMI: BRA(flags_.negative_result&0x80); break; case BMI: BRA(registers_.flags.negative_result&0x80); break;
case BVC: BRA(!flags_.overflow); break; case BVC: BRA(!registers_.flags.overflow); break;
case BVS: BRA(flags_.overflow); break; case BVS: BRA(registers_.flags.overflow); break;
case BCC: BRA(!flags_.carry); break; case BCC: BRA(!registers_.flags.carry); break;
case BCS: BRA(flags_.carry); break; case BCS: BRA(registers_.flags.carry); break;
case BNE: BRA(flags_.zero_result); break; case BNE: BRA(registers_.flags.zero_result); break;
case BEQ: BRA(!flags_.zero_result); break; case BEQ: BRA(!registers_.flags.zero_result); break;
case BRA: BRA(true); break; case BRA: BRA(true); break;
#undef BRA #undef BRA
case BRL: case BRL:
pc_ += int16_t(instruction_buffer_.value); registers_.pc += int16_t(instruction_buffer_.value);
break; break;
// //
@ -780,28 +775,28 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
// //
case ASL: case ASL:
flags_.carry = data_buffer_.value >> (7 + m_shift_); registers_.flags.carry = data_buffer_.value >> (7 + registers_.m_shift);
data_buffer_.value <<= 1; data_buffer_.value <<= 1;
flags_.set_nz(data_buffer_.value, m_shift_); registers_.flags.set_nz(data_buffer_.value, registers_.m_shift);
break; break;
case LSR: case LSR:
flags_.carry = data_buffer_.value & 1; registers_.flags.carry = data_buffer_.value & 1;
data_buffer_.value >>= 1; data_buffer_.value >>= 1;
flags_.set_nz(data_buffer_.value, m_shift_); registers_.flags.set_nz(data_buffer_.value, registers_.m_shift);
break; break;
case ROL: case ROL:
data_buffer_.value = (data_buffer_.value << 1) | flags_.carry; data_buffer_.value = (data_buffer_.value << 1) | registers_.flags.carry;
flags_.carry = data_buffer_.value >> (8 + m_shift_); registers_.flags.carry = data_buffer_.value >> (8 + registers_.m_shift);
flags_.set_nz(data_buffer_.value, m_shift_); registers_.flags.set_nz(data_buffer_.value, registers_.m_shift);
break; break;
case ROR: { case ROR: {
const uint8_t next_carry = data_buffer_.value & 1; const uint8_t next_carry = data_buffer_.value & 1;
data_buffer_.value = (data_buffer_.value >> 1) | (flags_.carry << (7 + m_shift_)); data_buffer_.value = (data_buffer_.value >> 1) | (registers_.flags.carry << (7 + registers_.m_shift));
flags_.carry = next_carry; registers_.flags.carry = next_carry;
flags_.set_nz(data_buffer_.value, m_shift_); registers_.flags.set_nz(data_buffer_.value, registers_.m_shift);
} break; } break;
// //
@ -810,23 +805,23 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
#define cp(v, shift, masks) {\ #define cp(v, shift, masks) {\
const uint32_t temp32 = (v.full & masks[1]) - (data_buffer_.value & masks[1]); \ const uint32_t temp32 = (v.full & masks[1]) - (data_buffer_.value & masks[1]); \
flags_.set_nz(uint16_t(temp32), shift); \ registers_.flags.set_nz(uint16_t(temp32), shift); \
flags_.carry = ((~temp32) >> (8 + shift))&1; \ registers_.flags.carry = ((~temp32) >> (8 + shift))&1; \
} }
case CMP: cp(a_, m_shift_, m_masks_); break; case CMP: cp(registers_.a, registers_.m_shift, registers_.m_masks); break;
case CPX: cp(x_, x_shift_, x_masks_); break; case CPX: cp(registers_.x, registers_.x_shift, registers_.x_masks); break;
case CPY: cp(y_, x_shift_, x_masks_); break; case CPY: cp(registers_.y, registers_.x_shift, registers_.x_masks); break;
#undef cp #undef cp
case SBC: case SBC:
if(flags_.decimal) { if(registers_.flags.decimal) {
// I've yet to manage to find a rational way to map this to an ADC, // I've yet to manage to find a rational way to map this to an ADC,
// hence the yucky repetition of code here. // hence the yucky repetition of code here.
const uint16_t a = a_.full & m_masks_[1]; const uint16_t a = registers_.a.full & registers_.m_masks[1];
unsigned int result = 0; unsigned int result = 0;
unsigned int borrow = flags_.carry ^ 1; unsigned int borrow = registers_.flags.carry ^ 1;
#define nibble(mask, adjustment, carry) \ #define nibble(mask, adjustment, carry) \
result += (a & mask) - (data_buffer_.value & mask) - borrow; \ result += (a & mask) - (data_buffer_.value & mask) - borrow; \
@ -841,23 +836,23 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
#undef nibble #undef nibble
flags_.overflow = ~(( (result ^ a_.full) & (result ^ data_buffer_.value) ) >> (1 + m_shift_))&0x40; registers_.flags.overflow = ~(( (result ^ registers_.a.full) & (result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40;
flags_.set_nz(result, m_shift_); registers_.flags.set_nz(result, registers_.m_shift);
flags_.carry = ((borrow >> 16)&1)^1; registers_.flags.carry = ((borrow >> 16)&1)^1;
LD(a_, result, m_masks_); LD(registers_.a, result, registers_.m_masks);
break; break;
} }
data_buffer_.value = ~data_buffer_.value & m_masks_[1]; data_buffer_.value = ~data_buffer_.value & registers_.m_masks[1];
[[fallthrough]]; [[fallthrough]];
case ADC: { case ADC: {
int result; int result;
const uint16_t a = a_.full & m_masks_[1]; const uint16_t a = registers_.a.full & registers_.m_masks[1];
if(flags_.decimal) { if(registers_.flags.decimal) {
result = flags_.carry; result = registers_.flags.carry;
#define nibble(mask, limit, adjustment, carry) \ #define nibble(mask, limit, adjustment, carry) \
result += (a & mask) + (data_buffer_.value & mask); \ result += (a & mask) + (data_buffer_.value & mask); \
@ -871,13 +866,13 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
#undef nibble #undef nibble
} else { } else {
result = a + data_buffer_.value + flags_.carry; result = a + data_buffer_.value + registers_.flags.carry;
} }
flags_.overflow = (( (result ^ a_.full) & (result ^ data_buffer_.value) ) >> (1 + m_shift_))&0x40; registers_.flags.overflow = (( (result ^ registers_.a.full) & (result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40;
flags_.set_nz(result, m_shift_); registers_.flags.set_nz(result, registers_.m_shift);
flags_.carry = (result >> (8 + m_shift_))&1; registers_.flags.carry = (result >> (8 + registers_.m_shift))&1;
LD(a_, result, m_masks_); LD(registers_.a, result, registers_.m_masks);
} break; } break;
// //
@ -901,12 +896,12 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
#undef y_top #undef y_top
#undef a_top #undef a_top
// TODO: the ready line.
// Store a selection as to the exceptions, if any, that would be honoured after this cycle if the // Store a selection as to the exceptions, if any, that would be honoured after this cycle if the
// next thing is a MoveToNextProgram. // next thing is a MoveToNextProgram.
selected_exceptions_ = pending_exceptions_ & (flags_.inverse_interrupt | PowerOn | Reset | NMI); selected_exceptions_ = pending_exceptions_ & (registers_.flags.inverse_interrupt | PowerOn | Reset | NMI);
number_of_cycles -= bus_handler_.perform_bus_operation(bus_operation, bus_address, bus_value); number_of_cycles -= bus_handler_.perform_bus_operation(bus_operation_, bus_address_, bus_value_);
// TODO: RDY line.
} }
#undef read #undef read

View File

@ -1028,63 +1028,63 @@ ProcessorStorage::ProcessorStorage() {
} }
void ProcessorStorage::set_reset_state() { void ProcessorStorage::set_reset_state() {
data_bank_ = 0; registers_.data_bank = 0;
program_bank_ = 0; registers_.program_bank = 0;
direct_ = 0; registers_.direct = 0;
flags_.decimal = 0; registers_.flags.decimal = 0;
flags_.inverse_interrupt = 0; registers_.flags.inverse_interrupt = 0;
set_emulation_mode(true); set_emulation_mode(true);
} }
void ProcessorStorage::set_emulation_mode(bool enabled) { void ProcessorStorage::set_emulation_mode(bool enabled) {
if(emulation_flag_ == enabled) { if(registers_.emulation_flag == enabled) {
return; return;
} }
emulation_flag_ = enabled; registers_.emulation_flag = enabled;
if(enabled) { if(enabled) {
set_m_x_flags(true, true); set_m_x_flags(true, true);
x_.halves.high = y_.halves.high = 0; registers_.x.halves.high = registers_.y.halves.high = 0;
e_masks_[0] = 0xff00; registers_.e_masks[0] = 0xff00;
e_masks_[1] = 0x00ff; registers_.e_masks[1] = 0x00ff;
} else { } else {
e_masks_[0] = 0x0000; registers_.e_masks[0] = 0x0000;
e_masks_[1] = 0xffff; registers_.e_masks[1] = 0xffff;
s_.halves.high = 1; // To pretend it was 1 all along; this implementation actually ignores registers_.s.halves.high = 1; // To pretend it was 1 all along; this implementation actually ignores
// the top byte while in emulation mode. // the top byte while in emulation mode.
} }
} }
void ProcessorStorage::set_m_x_flags(bool m, bool x) { void ProcessorStorage::set_m_x_flags(bool m, bool x) {
// true/1 => 8bit for both flags. // true/1 => 8bit for both flags.
mx_flags_[0] = m; registers_.mx_flags[0] = m;
mx_flags_[1] = x; registers_.mx_flags[1] = x;
m_masks_[0] = m ? 0xff00 : 0x0000; registers_.m_masks[0] = m ? 0xff00 : 0x0000;
m_masks_[1] = m ? 0x00ff : 0xffff; registers_.m_masks[1] = m ? 0x00ff : 0xffff;
m_shift_ = m ? 0 : 8; registers_.m_shift = m ? 0 : 8;
x_masks_[0] = x ? 0xff00 : 0x0000; registers_.x_masks[0] = x ? 0xff00 : 0x0000;
x_masks_[1] = x ? 0x00ff : 0xffff; registers_.x_masks[1] = x ? 0x00ff : 0xffff;
x_shift_ = x ? 0 : 8; registers_.x_shift = x ? 0 : 8;
} }
uint8_t ProcessorStorage::get_flags() const { uint8_t ProcessorStorage::get_flags() const {
uint8_t result = flags_.get(); uint8_t result = registers_.flags.get();
if(!emulation_flag_) { if(!registers_.emulation_flag) {
result &= ~(Flag::MemorySize | Flag::IndexSize); result &= ~(Flag::MemorySize | Flag::IndexSize);
result |= mx_flags_[0] * Flag::MemorySize; result |= registers_.mx_flags[0] * Flag::MemorySize;
result |= mx_flags_[1] * Flag::IndexSize; result |= registers_.mx_flags[1] * Flag::IndexSize;
} }
return result; return result;
} }
void ProcessorStorage::set_flags(uint8_t value) { void ProcessorStorage::set_flags(uint8_t value) {
flags_.set(value); registers_.flags.set(value);
if(!emulation_flag_) { if(!registers_.emulation_flag) {
set_m_x_flags(value & Flag::MemorySize, value & Flag::IndexSize); set_m_x_flags(value & Flag::MemorySize, value & Flag::IndexSize);
} }
} }

View File

@ -241,49 +241,64 @@ struct ProcessorStorage {
FetchDecodeExecute FetchDecodeExecute
}; };
// Registers.
RegisterPair16 a_;
RegisterPair16 x_, y_;
RegisterPair16 s_;
uint16_t pc_;
// A helper for testing. // A helper for testing.
uint16_t last_operation_pc_; uint16_t last_operation_pc_;
Instruction *active_instruction_; Instruction *active_instruction_;
Cycles cycles_left_to_run_; Cycles cycles_left_to_run_;
// Flags aplenty. // All registers are boxed up into a struct so that they can be stored and restored in support of abort.
MOS6502Esque::LazyFlags flags_; struct Registers {
uint8_t mx_flags_[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`; `1` => 8-bit. // Registers.
uint16_t m_masks_[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask. RegisterPair16 a;
uint16_t x_masks_[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask. RegisterPair16 x, y;
uint16_t e_masks_[2] = {0xff00, 0x00ff}; RegisterPair16 s;
int m_shift_ = 0; uint16_t pc;
int x_shift_ = 0;
bool emulation_flag_ = true;
// I.e. the offset for direct addressing (outside of emulation mode). // Flags aplenty.
uint16_t direct_ = 0; MOS6502Esque::LazyFlags flags;
uint8_t mx_flags[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`; `1` => 8-bit.
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.
uint16_t e_masks[2] = {0xff00, 0x00ff};
int m_shift = 0;
int x_shift = 0;
bool emulation_flag = true;
// Banking registers are all stored with the relevant byte // I.e. the offset for direct addressing (outside of emulation mode).
// shifted up bits 1623. uint16_t direct = 0;
uint32_t data_bank_ = 0; // i.e. DBR.
uint32_t program_bank_ = 0; // i.e. PBR.
// Banking registers are all stored with the relevant byte
// shifted up bits 1623.
uint32_t data_bank = 0; // i.e. DBR.
uint32_t program_bank = 0; // i.e. PBR.
} registers_, abort_registers_copy_;
// The next bus transaction.
uint32_t bus_address_ = 0;
uint8_t *bus_value_ = nullptr;
static inline uint8_t bus_throwaway_ = 0;
BusOperation bus_operation_ = BusOperation::None;
// A bitfield for various exceptions.
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 = Flag::Interrupt; // This makes masking a lot easier later on; this is 1 << 2. static constexpr int IRQ = Flag::Interrupt; // This makes masking a lot easier later on; this is 1 << 2.
static constexpr int NMI = 1 << 3; static constexpr int NMI = 1 << 3;
static constexpr int Abort = 1 << 4;
int pending_exceptions_ = PowerOn; // By default. int pending_exceptions_ = PowerOn; // By default.
int selected_exceptions_ = 0; int selected_exceptions_ = 0;
bool ready_line_ = false;
// Just to be safe. // Just to be safe.
static_assert(PowerOn != IRQ); static_assert(PowerOn != IRQ);
static_assert(Reset != IRQ); static_assert(Reset != IRQ);
static_assert(NMI != IRQ); static_assert(NMI != IRQ);
static_assert(Abort != IRQ);
/// Sets the required exception flags necessary to exit a STP or WAI. /// Sets the required exception flags necessary to exit a STP or WAI.
int required_exceptions_ = 0; int required_exceptions_ = 0;
BusOperation stp_wai_bus_operation_ = BusOperation::None;
/// 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.