mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-07 23:29:06 +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:
parent
3c6adc1ff4
commit
c0a1c34012
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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_ = µ_ops_[offset];
|
next_op_ = µ_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_ = µ_ops_[active_instruction_->program_offsets[size_flag]];
|
next_op_ = µ_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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
// All registers are boxed up into a struct so that they can be stored and restored in support of abort.
|
||||||
|
struct Registers {
|
||||||
|
// Registers.
|
||||||
|
RegisterPair16 a;
|
||||||
|
RegisterPair16 x, y;
|
||||||
|
RegisterPair16 s;
|
||||||
|
uint16_t pc;
|
||||||
|
|
||||||
// Flags aplenty.
|
// Flags aplenty.
|
||||||
MOS6502Esque::LazyFlags flags_;
|
MOS6502Esque::LazyFlags flags;
|
||||||
uint8_t mx_flags_[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`; `1` => 8-bit.
|
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 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 x_masks[2] = {0xff00, 0x00ff}; // [0] = src mask; [1] = dst mask.
|
||||||
uint16_t e_masks_[2] = {0xff00, 0x00ff};
|
uint16_t e_masks[2] = {0xff00, 0x00ff};
|
||||||
int m_shift_ = 0;
|
int m_shift = 0;
|
||||||
int x_shift_ = 0;
|
int x_shift = 0;
|
||||||
bool emulation_flag_ = true;
|
bool emulation_flag = true;
|
||||||
|
|
||||||
// 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_ = 0;
|
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_ = 0; // i.e. DBR.
|
uint32_t data_bank = 0; // i.e. DBR.
|
||||||
uint32_t program_bank_ = 0; // i.e. PBR.
|
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user