From dfda2adf0de71f1e96bd8c8a43328da11da86e74 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 15 Oct 2020 20:46:18 -0400 Subject: [PATCH] Attempts implementations of both ready and abort. Which I think concludes the inputs? --- Processors/65816/65816.hpp | 1 + .../Implementation/65816Implementation.hpp | 1541 +++++++++-------- 2 files changed, 789 insertions(+), 753 deletions(-) diff --git a/Processors/65816/65816.hpp b/Processors/65816/65816.hpp index f98d9deb5..c5f2daf53 100644 --- a/Processors/65816/65816.hpp +++ b/Processors/65816/65816.hpp @@ -35,6 +35,7 @@ class ProcessorBase: protected ProcessorStorage { inline void set_nmi_line(bool); inline void set_reset_line(bool); inline void set_abort_line(bool); + inline bool get_is_resetting() const; void set_value_of_register(Register r, uint16_t value); inline bool is_jammed() const; diff --git a/Processors/65816/Implementation/65816Implementation.hpp b/Processors/65816/Implementation/65816Implementation.hpp index 1080bbe2b..23359bb25 100644 --- a/Processors/65816/Implementation/65816Implementation.hpp +++ b/Processors/65816/Implementation/65816Implementation.hpp @@ -25,395 +25,410 @@ template void Processor Cycles(0)) { - const MicroOp operation = *next_op_; - ++next_op_; + // Wait for ready to be inactive before proceeding. + while(uses_ready_line && ready_line_ && number_of_cycles > Cycles(0)) { + number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, bus_address_, &bus_throwaway_); + } + + // Process for as much time is left and/or until ready is signalled. + while((!uses_ready_line || !ready_line_) && number_of_cycles > Cycles(0)) { + const MicroOp operation = *next_op_; + ++next_op_; #ifndef NDEBUG - // As a sanity check. - bus_value_ = nullptr; + // As a sanity check. + bus_value_ = nullptr; #endif - switch(operation) { + switch(operation) { - // - // Scheduling. - // + // + // Scheduling. + // - case OperationMoveToNextProgram: { - // The exception program will determine the appropriate way to respond - // based on the pending exception if one exists; otherwise just do a - // standard fetch-decode-execute. - const auto offset = instructions[selected_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offsets[0]; - next_op_ = µ_ops_[offset]; - instruction_buffer_.clear(); - data_buffer_.clear(); - last_operation_pc_ = registers_.pc; - } continue; + case OperationMoveToNextProgram: { + // The exception program will determine the appropriate way to respond + // based on the pending exception if one exists; otherwise just do a + // standard fetch-decode-execute. + const auto offset = instructions[selected_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offsets[0]; + next_op_ = µ_ops_[offset]; + instruction_buffer_.clear(); + data_buffer_.clear(); + last_operation_pc_ = registers_.pc; + } continue; - case OperationDecode: { - active_instruction_ = &instructions[instruction_buffer_.value]; + case OperationDecode: { + active_instruction_ = &instructions[instruction_buffer_.value]; - const auto size_flag = registers_.mx_flags[active_instruction_->size_field]; - next_op_ = µ_ops_[active_instruction_->program_offsets[size_flag]]; - instruction_buffer_.clear(); - } continue; + const auto size_flag = registers_.mx_flags[active_instruction_->size_field]; + next_op_ = µ_ops_[active_instruction_->program_offsets[size_flag]]; + instruction_buffer_.clear(); + } continue; - // - // PC fetches. - // + // + // PC fetches. + // - case CycleFetchIncrementPC: - read(registers_.pc | registers_.program_bank, instruction_buffer_.next_input()); - ++registers_.pc; - break; + case CycleFetchIncrementPC: + read(registers_.pc | registers_.program_bank, instruction_buffer_.next_input()); + ++registers_.pc; + break; - case CycleFetchOpcode: - perform_bus(registers_.pc | registers_.program_bank, instruction_buffer_.next_input(), MOS6502Esque::ReadOpcode); - ++registers_.pc; - break; + case CycleFetchOpcode: + perform_bus(registers_.pc | registers_.program_bank, instruction_buffer_.next_input(), MOS6502Esque::ReadOpcode); + ++registers_.pc; + break; - case CycleFetchPC: - read(registers_.pc | registers_.program_bank, instruction_buffer_.next_input()); - break; + case CycleFetchPC: + read(registers_.pc | registers_.program_bank, instruction_buffer_.next_input()); + break; - case CycleFetchPCThrowaway: - read(registers_.pc | registers_.program_bank, &bus_throwaway_); - break; + case CycleFetchPCThrowaway: + read(registers_.pc | registers_.program_bank, &bus_throwaway_); + break; - // - // Data fetches and stores. - // + // + // Data fetches and stores. + // #define increment_data_address() data_address_ = (data_address_ & ~data_address_increment_mask_) + ((data_address_ + 1) & data_address_increment_mask_) #define decrement_data_address() data_address_ = (data_address_ & ~data_address_increment_mask_) + ((data_address_ - 1) & data_address_increment_mask_) - case CycleFetchData: - read(data_address_, data_buffer_.next_input()); - break; + case CycleFetchData: + read(data_address_, data_buffer_.next_input()); + break; - case CycleFetchDataThrowaway: - read(data_address_, &bus_throwaway_); - break; + case CycleFetchDataThrowaway: + read(data_address_, &bus_throwaway_); + break; - case CycleFetchIncorrectDataAddress: - read(incorrect_data_address_, &bus_throwaway_); - break; + case CycleFetchIncorrectDataAddress: + read(incorrect_data_address_, &bus_throwaway_); + break; - case CycleFetchIncrementData: - read(data_address_, data_buffer_.next_input()); - increment_data_address(); - break; + case CycleFetchIncrementData: + read(data_address_, data_buffer_.next_input()); + increment_data_address(); + break; - case CycleStoreData: - write(data_address_, data_buffer_.next_output()); - break; + case CycleStoreData: + write(data_address_, data_buffer_.next_output()); + break; - case CycleStoreDataThrowaway: - write(data_address_, data_buffer_.preview_output()); - break; + case CycleStoreDataThrowaway: + write(data_address_, data_buffer_.preview_output()); + break; - case CycleStoreIncrementData: - write(data_address_, data_buffer_.next_output()); - increment_data_address(); - break; + case CycleStoreIncrementData: + write(data_address_, data_buffer_.next_output()); + increment_data_address(); + break; - case CycleStoreDecrementData: - write(data_address_, data_buffer_.next_output_descending()); - decrement_data_address(); - break; + case CycleStoreDecrementData: + write(data_address_, data_buffer_.next_output_descending()); + decrement_data_address(); + break; - case CycleFetchBlockX: - read(((instruction_buffer_.value & 0xff00) << 8) | x(), data_buffer_.any_byte()); - break; + case CycleFetchBlockX: + read(((instruction_buffer_.value & 0xff00) << 8) | x(), data_buffer_.any_byte()); + break; - case CycleFetchBlockY: - read(((instruction_buffer_.value & 0xff00) << 8) | y(), &bus_throwaway_); - break; + case CycleFetchBlockY: + read(((instruction_buffer_.value & 0xff00) << 8) | y(), &bus_throwaway_); + break; - case CycleStoreBlockY: - write(((instruction_buffer_.value & 0xff00) << 8) | x(), data_buffer_.any_byte()); - break; + case CycleStoreBlockY: + write(((instruction_buffer_.value & 0xff00) << 8) | x(), data_buffer_.any_byte()); + break; #undef increment_data_address #undef decrement_data_address - // - // Stack accesses. - // + // + // Stack accesses. + // #define stack_access(value, operation) \ bus_address_ = stack_address(); \ bus_value_ = value; \ bus_operation_ = operation; - case CyclePush: - stack_access(data_buffer_.next_output_descending(), MOS6502Esque::Write); - --registers_.s.full; - break; + case CyclePush: + stack_access(data_buffer_.next_output_descending(), MOS6502Esque::Write); + --registers_.s.full; + break; - case CyclePullIfNotEmulation: - if(registers_.emulation_flag) { - continue; - } - [[fallthrough]]; + case CyclePullIfNotEmulation: + if(registers_.emulation_flag) { + continue; + } + [[fallthrough]]; - case CyclePull: - ++registers_.s.full; - stack_access(data_buffer_.next_input(), MOS6502Esque::Read); - break; + case CyclePull: + ++registers_.s.full; + stack_access(data_buffer_.next_input(), MOS6502Esque::Read); + break; - case CycleAccessStack: - stack_access(&bus_throwaway_, MOS6502Esque::Read); - break; + case CycleAccessStack: + stack_access(&bus_throwaway_, MOS6502Esque::Read); + break; #undef stack_access - // - // STP and WAI. - // - - case CycleRepeatingNone: - if(pending_exceptions_ & required_exceptions_) { - continue; - } else { - --next_op_; - perform_bus(0xffffff, nullptr, MOS6502Esque::None); - } - break; - - // - // Data movement. - // - - case OperationCopyPCToData: - data_buffer_.size = 2; - data_buffer_.value = registers_.pc; - continue; - - case OperationCopyInstructionToData: - data_buffer_ = instruction_buffer_; - continue; - - case OperationCopyDataToInstruction: - instruction_buffer_ = data_buffer_; - data_buffer_.clear(); - continue; - - case OperationCopyAToData: - data_buffer_.value = registers_.a.full & registers_.m_masks[1]; - data_buffer_.size = 2 - m_flag(); - continue; - - case OperationCopyDataToA: - registers_.a.full = (registers_.a.full & registers_.m_masks[0]) + (data_buffer_.value & registers_.m_masks[1]); - continue; - - case OperationCopyPBRToData: - data_buffer_.size = 1; - data_buffer_.value = registers_.program_bank >> 16; - continue; - - case OperationCopyDataToPC: - registers_.pc = uint16_t(data_buffer_.value); - continue; - - // - // Address construction. - // - - case OperationConstructAbsolute: - data_address_ = instruction_buffer_.value + registers_.data_bank; - data_address_increment_mask_ = 0xff'ff'ff; - continue; - - case OperationConstructAbsolute16: - data_address_ = instruction_buffer_.value; - data_address_increment_mask_ = 0x00'ff'ff; - continue; - - case OperationConstructAbsoluteLong: - data_address_ = instruction_buffer_.value; - data_address_increment_mask_ = 0xff'ff'ff; - continue; - - // Used for JMP and JSR (absolute, x). - case OperationConstructAbsoluteIndexedIndirect: - data_address_ = registers_.program_bank + ((instruction_buffer_.value + x()) & 0xffff); - data_address_increment_mask_ = 0x00'ff'ff; - continue; - - case OperationConstructAbsoluteLongX: - data_address_ = instruction_buffer_.value + x(); - data_address_increment_mask_ = 0xff'ff'ff; - continue; - - case OperationConstructAbsoluteXRead: - case OperationConstructAbsoluteX: - data_address_ = instruction_buffer_.value + x() + registers_.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(operation == OperationConstructAbsoluteXRead && data_address_ == incorrect_data_address_) { - ++next_op_; - } - data_address_increment_mask_ = 0xff'ff'ff; - continue; - - case OperationConstructAbsoluteYRead: - case OperationConstructAbsoluteY: - data_address_ = instruction_buffer_.value + y() + registers_.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(operation == OperationConstructAbsoluteYRead && data_address_ == incorrect_data_address_) { - ++next_op_; - } - data_address_increment_mask_ = 0xff'ff'ff; - continue; - - case OperationConstructDirect: - data_address_ = (registers_.direct + instruction_buffer_.value) & 0xffff; - data_address_increment_mask_ = 0x00'ff'ff; - if(!(registers_.direct&0xff)) { - // If the low byte is 0 and this is emulation mode, incrementing - // is restricted to the low byte. - data_address_increment_mask_ = registers_.e_masks[1]; - ++next_op_; - } - continue; - - case OperationConstructDirectLong: - data_address_ = (registers_.direct + instruction_buffer_.value) & 0xffff; - data_address_increment_mask_ = 0x00'ff'ff; - if(!(registers_.direct&0xff)) { - ++next_op_; - } - continue; - - case OperationConstructDirectIndirect: - data_address_ = registers_.data_bank + data_buffer_.value; - data_address_increment_mask_ = 0xff'ff'ff; - data_buffer_.clear(); - continue; - - case OperationConstructDirectIndexedIndirect: - data_address_ = registers_.data_bank + ( - ((registers_.direct + x() + instruction_buffer_.value) & registers_.e_masks[1]) + - (registers_.direct & registers_.e_masks[0]) - ) & 0xffff; - data_address_increment_mask_ = 0x00'ff'ff; - - if(!(registers_.direct&0xff)) { - ++next_op_; - } - continue; - - case OperationConstructDirectIndirectIndexedLong: - data_address_ = y() + data_buffer_.value; - data_address_increment_mask_ = 0xff'ff'ff; - data_buffer_.clear(); - continue; - - case OperationConstructDirectIndirectLong: - data_address_ = data_buffer_.value; - data_address_increment_mask_ = 0xff'ff'ff; - data_buffer_.clear(); - continue; - - // TODO: confirm incorrect_data_address_ below. - - case OperationConstructDirectX: - data_address_ = ( - (registers_.direct & registers_.e_masks[0]) + - ((instruction_buffer_.value + registers_.direct + x()) & registers_.e_masks[1]) - ) & 0xffff; - data_address_increment_mask_ = 0x00'ff'ff; - - incorrect_data_address_ = (registers_.direct & 0xff00) + (data_address_ & 0x00ff); - if(!(registers_.direct&0xff)) { - ++next_op_; - } - continue; - - case OperationConstructDirectY: - data_address_ = ( - (registers_.direct & registers_.e_masks[0]) + - ((instruction_buffer_.value + registers_.direct + y()) & registers_.e_masks[1]) - ) & 0xffff; - data_address_increment_mask_ = 0x00'ff'ff; - - incorrect_data_address_ = (registers_.direct & 0xff00) + (data_address_ & 0x00ff); - if(!(registers_.direct&0xff)) { - ++next_op_; - } - continue; - - case OperationConstructStackRelative: - data_address_ = (registers_.s.full + instruction_buffer_.value) & 0xffff; - data_address_increment_mask_ = 0x00'ff'ff; - continue; - - case OperationConstructStackRelativeIndexedIndirect: - data_address_ = registers_.data_bank + data_buffer_.value + y(); - data_address_increment_mask_ = 0xff'ff'ff; - data_buffer_.clear(); - continue; - - case OperationConstructPER: - data_buffer_.value = instruction_buffer_.value + registers_.pc; - data_buffer_.size = 2; - continue; - - case OperationPrepareException: { - // Put the proper exception vector into the data address, put the flags and PC - // into the data buffer (possibly also PBR), and skip an instruction if in - // emulation mode. // - // I've assumed here that interrupts, BRKs and COPs can be usurped similarly - // to a 6502 but may not have the exact details correct. E.g. if IRQ has - // become inactive since the decision was made to start an interrupt, should - // that turn into a BRK? + // STP and WAI. + // - bool is_brk = false; - - if(pending_exceptions_ & (Reset | PowerOn)) { - pending_exceptions_ &= ~(Reset | PowerOn); - data_address_ = 0xfffc; - set_reset_state(); - } else if(pending_exceptions_ & NMI) { - pending_exceptions_ &= ~NMI; - data_address_ = 0xfffa; - } else if(pending_exceptions_ & IRQ & registers_.flags.inverse_interrupt) { - pending_exceptions_ &= ~IRQ; - data_address_ = 0xfffe; - } else { - is_brk = active_instruction_ == instructions; // Given that BRK has opcode 00. - if(is_brk) { - data_address_ = registers_.emulation_flag ? 0xfffe : 0xfff6; + case CycleRepeatingNone: + if(pending_exceptions_ & required_exceptions_) { + continue; } else { - // Implicitly: COP. - data_address_ = 0xfff4; + --next_op_; + perform_bus(0xffffff, nullptr, MOS6502Esque::None); } - } + break; - data_buffer_.value = (registers_.pc << 8) | get_flags(); - if(registers_.emulation_flag) { - if(is_brk) data_buffer_.value |= Flag::Break; - data_buffer_.size = 3; - ++next_op_; - } else { - data_buffer_.value |= registers_.program_bank << 24; - data_buffer_.size = 4; - registers_.program_bank = 0; - } + // + // Data movement. + // - registers_.flags.inverse_interrupt = 0; - } continue; + case OperationCopyPCToData: + data_buffer_.size = 2; + data_buffer_.value = registers_.pc; + continue; - // - // Performance. - // + case OperationCopyInstructionToData: + data_buffer_ = instruction_buffer_; + continue; + + case OperationCopyDataToInstruction: + instruction_buffer_ = data_buffer_; + data_buffer_.clear(); + continue; + + case OperationCopyAToData: + data_buffer_.value = registers_.a.full & registers_.m_masks[1]; + data_buffer_.size = 2 - m_flag(); + continue; + + case OperationCopyDataToA: + registers_.a.full = (registers_.a.full & registers_.m_masks[0]) + (data_buffer_.value & registers_.m_masks[1]); + continue; + + case OperationCopyPBRToData: + data_buffer_.size = 1; + data_buffer_.value = registers_.program_bank >> 16; + continue; + + case OperationCopyDataToPC: + registers_.pc = uint16_t(data_buffer_.value); + continue; + + // + // Address construction. + // + + case OperationConstructAbsolute: + data_address_ = instruction_buffer_.value + registers_.data_bank; + data_address_increment_mask_ = 0xff'ff'ff; + continue; + + case OperationConstructAbsolute16: + data_address_ = instruction_buffer_.value; + data_address_increment_mask_ = 0x00'ff'ff; + continue; + + case OperationConstructAbsoluteLong: + data_address_ = instruction_buffer_.value; + data_address_increment_mask_ = 0xff'ff'ff; + continue; + + // Used for JMP and JSR (absolute, x). + case OperationConstructAbsoluteIndexedIndirect: + data_address_ = registers_.program_bank + ((instruction_buffer_.value + x()) & 0xffff); + data_address_increment_mask_ = 0x00'ff'ff; + continue; + + case OperationConstructAbsoluteLongX: + data_address_ = instruction_buffer_.value + x(); + data_address_increment_mask_ = 0xff'ff'ff; + continue; + + case OperationConstructAbsoluteXRead: + case OperationConstructAbsoluteX: + data_address_ = instruction_buffer_.value + x() + registers_.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(operation == OperationConstructAbsoluteXRead && data_address_ == incorrect_data_address_) { + ++next_op_; + } + data_address_increment_mask_ = 0xff'ff'ff; + continue; + + case OperationConstructAbsoluteYRead: + case OperationConstructAbsoluteY: + data_address_ = instruction_buffer_.value + y() + registers_.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(operation == OperationConstructAbsoluteYRead && data_address_ == incorrect_data_address_) { + ++next_op_; + } + data_address_increment_mask_ = 0xff'ff'ff; + continue; + + case OperationConstructDirect: + data_address_ = (registers_.direct + instruction_buffer_.value) & 0xffff; + data_address_increment_mask_ = 0x00'ff'ff; + if(!(registers_.direct&0xff)) { + // If the low byte is 0 and this is emulation mode, incrementing + // is restricted to the low byte. + data_address_increment_mask_ = registers_.e_masks[1]; + ++next_op_; + } + continue; + + case OperationConstructDirectLong: + data_address_ = (registers_.direct + instruction_buffer_.value) & 0xffff; + data_address_increment_mask_ = 0x00'ff'ff; + if(!(registers_.direct&0xff)) { + ++next_op_; + } + continue; + + case OperationConstructDirectIndirect: + data_address_ = registers_.data_bank + data_buffer_.value; + data_address_increment_mask_ = 0xff'ff'ff; + data_buffer_.clear(); + continue; + + case OperationConstructDirectIndexedIndirect: + data_address_ = registers_.data_bank + ( + ((registers_.direct + x() + instruction_buffer_.value) & registers_.e_masks[1]) + + (registers_.direct & registers_.e_masks[0]) + ) & 0xffff; + data_address_increment_mask_ = 0x00'ff'ff; + + if(!(registers_.direct&0xff)) { + ++next_op_; + } + continue; + + case OperationConstructDirectIndirectIndexedLong: + data_address_ = y() + data_buffer_.value; + data_address_increment_mask_ = 0xff'ff'ff; + data_buffer_.clear(); + continue; + + case OperationConstructDirectIndirectLong: + data_address_ = data_buffer_.value; + data_address_increment_mask_ = 0xff'ff'ff; + data_buffer_.clear(); + continue; + + // TODO: confirm incorrect_data_address_ below. + + case OperationConstructDirectX: + data_address_ = ( + (registers_.direct & registers_.e_masks[0]) + + ((instruction_buffer_.value + registers_.direct + x()) & registers_.e_masks[1]) + ) & 0xffff; + data_address_increment_mask_ = 0x00'ff'ff; + + incorrect_data_address_ = (registers_.direct & 0xff00) + (data_address_ & 0x00ff); + if(!(registers_.direct&0xff)) { + ++next_op_; + } + continue; + + case OperationConstructDirectY: + data_address_ = ( + (registers_.direct & registers_.e_masks[0]) + + ((instruction_buffer_.value + registers_.direct + y()) & registers_.e_masks[1]) + ) & 0xffff; + data_address_increment_mask_ = 0x00'ff'ff; + + incorrect_data_address_ = (registers_.direct & 0xff00) + (data_address_ & 0x00ff); + if(!(registers_.direct&0xff)) { + ++next_op_; + } + continue; + + case OperationConstructStackRelative: + data_address_ = (registers_.s.full + instruction_buffer_.value) & 0xffff; + data_address_increment_mask_ = 0x00'ff'ff; + continue; + + case OperationConstructStackRelativeIndexedIndirect: + data_address_ = registers_.data_bank + data_buffer_.value + y(); + data_address_increment_mask_ = 0xff'ff'ff; + data_buffer_.clear(); + continue; + + case OperationConstructPER: + data_buffer_.value = instruction_buffer_.value + registers_.pc; + data_buffer_.size = 2; + continue; + + case OperationPrepareException: { + // Put the proper exception vector into the data address, put the flags and PC + // into the data buffer (possibly also PBR), and skip an instruction if in + // emulation mode. + // + // I've assumed here that interrupts, BRKs and COPs can be usurped similarly + // to a 6502 but may not have the exact details correct. E.g. if IRQ has + // become inactive since the decision was made to start an interrupt, should + // that turn into a BRK? + // + // Also: priority here is a guess. + + bool is_brk = false; + + if(pending_exceptions_ & (Reset | PowerOn)) { + pending_exceptions_ &= ~(Reset | PowerOn); + data_address_ = 0xfffc; + set_reset_state(); + } else if(pending_exceptions_ & NMI) { + pending_exceptions_ &= ~NMI; + data_address_ = registers_.emulation_flag ? 0xfffa : 0xffea; + } else if(pending_exceptions_ & IRQ & registers_.flags.inverse_interrupt) { + pending_exceptions_ &= ~IRQ; + data_address_ = registers_.emulation_flag ? 0xfffe : 0xffee; + } else if(pending_exceptions_ & Abort) { + // Special case: restore registers from start of instruction. + registers_ = abort_registers_copy_; + + pending_exceptions_ &= ~Abort; + data_address_ = registers_.emulation_flag ? 0xfff8 : 0xffe8;; + } else { + is_brk = active_instruction_ == instructions; // Given that BRK has opcode 00. + if(is_brk) { + data_address_ = registers_.emulation_flag ? 0xfffe : 0xffe6; + } else { + // Implicitly: COP. + data_address_ = registers_.emulation_flag ? 0xfff4 : 0xffe8; + } + } + + data_buffer_.value = (registers_.pc << 8) | get_flags(); + if(registers_.emulation_flag) { + if(is_brk) data_buffer_.value |= Flag::Break; + data_buffer_.size = 3; + ++next_op_; + } else { + data_buffer_.value |= registers_.program_bank << 24; + data_buffer_.size = 4; + registers_.program_bank = 0; + } + + registers_.flags.inverse_interrupt = 0; + } continue; + + // + // Performance. + // #define LD(dest, src, masks) dest.full = (dest.full & masks[0]) | (src & masks[1]) #define m_top() (instruction_buffer_.value >> registers_.m_shift) & 0xff @@ -421,326 +436,326 @@ template void Processor> registers_.x_shift) & 0xff #define a_top() (registers_.a.full >> registers_.m_shift) & 0xff - case OperationPerform: - switch(active_instruction_->operation) { - - // - // Loads, stores and transfers (and NOP, and XBA). - // - - case LDA: - LD(registers_.a, data_buffer_.value, registers_.m_masks); - registers_.flags.set_nz(registers_.a.full, registers_.m_shift); - break; - - case LDX: - LD(registers_.x, data_buffer_.value, registers_.x_masks); - registers_.flags.set_nz(registers_.x.full, registers_.x_shift); - break; - - case LDY: - LD(registers_.y, data_buffer_.value, registers_.x_masks); - registers_.flags.set_nz(registers_.y.full, registers_.x_shift); - break; - - case PLB: - registers_.data_bank = (data_buffer_.value & 0xff) << 16; - registers_.flags.set_nz(instruction_buffer_.value); - break; - - case PLD: - registers_.direct = data_buffer_.value; - registers_.flags.set_nz(instruction_buffer_.value); - break; - - case PLP: - set_flags(data_buffer_.value); - break; - - case STA: - data_buffer_.value = registers_.a.full & registers_.m_masks[1]; - data_buffer_.size = 2 - m_flag(); - break; - - case STZ: - data_buffer_.value = 0; - data_buffer_.size = 2 - m_flag(); - break; - - case STX: - data_buffer_.value = registers_.x.full & registers_.x_masks[1]; - data_buffer_.size = 2 - x_flag(); - break; - - case STY: - data_buffer_.value = registers_.y.full & registers_.x_masks[1]; - data_buffer_.size = 2 - m_flag(); - break; - - case PHB: - data_buffer_.value = registers_.data_bank >> 16; - data_buffer_.size = 1; - break; - - case PHK: - data_buffer_.value = registers_.program_bank >> 16; - data_buffer_.size = 1; - break; - - case PHD: - data_buffer_.value = registers_.direct; - data_buffer_.size = 2; - break; - - case PHP: - data_buffer_.value = get_flags(); - data_buffer_.size = 1; - - if(registers_.emulation_flag) { - // On the 6502, the break flag is set during a PHP. - data_buffer_.value |= Flag::Break; - } - break; - - case NOP: break; - - // The below attempt to obey the 8/16-bit mixed transfer rules - // as documented in https://softpixel.com/~cwright/sianse/docs/65816NFO.HTM - // (and make reasonable guesses as to the N flag). - - case TXS: - registers_.s = registers_.x.full & registers_.x_masks[1]; - break; - - case TSX: - LD(registers_.x, registers_.s.full, registers_.x_masks); - registers_.flags.set_nz(registers_.x.full, registers_.x_shift); - break; - - case TXY: - LD(registers_.y, registers_.x.full, registers_.x_masks); - registers_.flags.set_nz(registers_.y.full, registers_.x_shift); - break; - - case TYX: - LD(registers_.x, registers_.y.full, registers_.x_masks); - registers_.flags.set_nz(registers_.x.full, registers_.x_shift); - break; - - case TAX: - LD(registers_.x, registers_.a.full, registers_.x_masks); - registers_.flags.set_nz(registers_.x.full, registers_.x_shift); - break; - - case TAY: - LD(registers_.y, registers_.a.full, registers_.x_masks); - registers_.flags.set_nz(registers_.y.full, registers_.x_shift); - break; - - case TXA: - LD(registers_.a, registers_.x.full, registers_.m_masks); - registers_.flags.set_nz(registers_.a.full, registers_.m_shift); - break; - - case TYA: - LD(registers_.a, registers_.y.full, registers_.m_masks); - registers_.flags.set_nz(registers_.a.full, registers_.m_shift); - break; - - case TCD: - registers_.direct = registers_.a.full; - registers_.flags.set_nz(registers_.a.full, 8); - break; - - case TDC: - registers_.a.full = registers_.direct; - registers_.flags.set_nz(registers_.a.full, 8); - break; - - case TCS: - registers_.s.full = registers_.a.full; - // No need to worry about byte masking here; for the stack it's handled as the emulation runs. - break; - - case TSC: - registers_.a.full = stack_address(); - registers_.flags.set_nz(registers_.a.full, 8); - break; - - case XBA: { - const uint8_t a_low = registers_.a.halves.low; - registers_.a.halves.low = registers_.a.halves.high; - registers_.a.halves.high = a_low; - registers_.flags.set_nz(registers_.a.halves.low); - } break; - - // - // Jumps and returns. - // - - case JML: - registers_.program_bank = instruction_buffer_.value & 0xff0000; - [[fallthrough]]; - - case JMP: - registers_.pc = uint16_t(instruction_buffer_.value); - break; - - case JMPind: - registers_.pc = data_buffer_.value; - break; - - case RTS: - registers_.pc = data_buffer_.value + 1; - break; - - case JSL: - registers_.program_bank = instruction_buffer_.value & 0xff0000; - [[fallthrough]]; - - case JSR: - data_buffer_.value = registers_.pc; - data_buffer_.size = 2; - - registers_.pc = instruction_buffer_.value; - break; - - case RTI: - registers_.pc = uint16_t(data_buffer_.value >> 8); - set_flags(uint8_t(data_buffer_.value)); - - if(!registers_.emulation_flag) { - registers_.program_bank = (data_buffer_.value & 0xff000000) >> 8; - } - break; - - // - // Block moves. - // - - case MVP: - registers_.data_bank = (instruction_buffer_.value & 0xff) << 16; - --registers_.x.full; - --registers_.y.full; - --registers_.a.full; - if(registers_.a.full) registers_.pc -= 3; - break; - - case MVN: - registers_.data_bank = (instruction_buffer_.value & 0xff) << 16; - ++registers_.x.full; - ++registers_.y.full; - --registers_.a.full; - if(registers_.a.full) registers_.pc -= 3; - break; - - // - // Flag manipulation. - // - - case CLC: registers_.flags.carry = 0; break; - case CLI: registers_.flags.inverse_interrupt = Flag::Interrupt; break; - case CLV: registers_.flags.overflow = 0; break; - case CLD: registers_.flags.decimal = 0; break; - - case SEC: registers_.flags.carry = Flag::Carry; break; - case SEI: registers_.flags.inverse_interrupt = 0; break; - case SED: registers_.flags.decimal = Flag::Decimal; break; - - case REP: - set_flags(get_flags() &~ instruction_buffer_.value); - break; - - case SEP: - set_flags(get_flags() | instruction_buffer_.value); - break; - - case XCE: { - const bool old_emulation_flag = registers_.emulation_flag; - set_emulation_mode(registers_.flags.carry); - registers_.flags.carry = old_emulation_flag; - } break; - - // - // Increments and decrements. - // - - case INC: - ++data_buffer_.value; - registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); - break;; - - case DEC: - --data_buffer_.value; - registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); - break; - - case INX: { - const uint16_t x_inc = registers_.x.full + 1; - LD(registers_.x, x_inc, registers_.x_masks); - registers_.flags.set_nz(registers_.x.full, registers_.x_shift); - } break; - - case DEX: { - const uint16_t x_dec = registers_.x.full - 1; - LD(registers_.x, x_dec, registers_.x_masks); - registers_.flags.set_nz(registers_.x.full, registers_.x_shift); - } break; - - case INY: { - const uint16_t y_inc = registers_.y.full + 1; - LD(registers_.y, y_inc, registers_.x_masks); - registers_.flags.set_nz(registers_.y.full, registers_.x_shift); - } break; - - case DEY: { - const uint16_t y_dec = registers_.y.full - 1; - LD(registers_.y, y_dec, registers_.x_masks); - registers_.flags.set_nz(registers_.y.full, registers_.x_shift); - } break; - - // - // Bitwise operations. - // - - case AND: - registers_.a.full &= data_buffer_.value | registers_.m_masks[0]; - registers_.flags.set_nz(registers_.a.full, registers_.m_shift); - break; - - case EOR: - registers_.a.full ^= data_buffer_.value; - registers_.flags.set_nz(registers_.a.full, registers_.m_shift); - break; - - case ORA: - registers_.a.full |= data_buffer_.value; - registers_.flags.set_nz(registers_.a.full, registers_.m_shift); - break; - - case BIT: - registers_.flags.set_n(data_buffer_.value, registers_.m_shift); - registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); - registers_.flags.overflow = data_buffer_.value & Flag::Overflow; - break; - - case BITimm: - registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); - break; - - case TRB: - registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); - data_buffer_.value &= ~registers_.a.full; - break; - - case TSB: - registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); - data_buffer_.value |= registers_.a.full; - break; - - // - // Branches. - // + case OperationPerform: + switch(active_instruction_->operation) { + + // + // Loads, stores and transfers (and NOP, and XBA). + // + + case LDA: + LD(registers_.a, data_buffer_.value, registers_.m_masks); + registers_.flags.set_nz(registers_.a.full, registers_.m_shift); + break; + + case LDX: + LD(registers_.x, data_buffer_.value, registers_.x_masks); + registers_.flags.set_nz(registers_.x.full, registers_.x_shift); + break; + + case LDY: + LD(registers_.y, data_buffer_.value, registers_.x_masks); + registers_.flags.set_nz(registers_.y.full, registers_.x_shift); + break; + + case PLB: + registers_.data_bank = (data_buffer_.value & 0xff) << 16; + registers_.flags.set_nz(instruction_buffer_.value); + break; + + case PLD: + registers_.direct = data_buffer_.value; + registers_.flags.set_nz(instruction_buffer_.value); + break; + + case PLP: + set_flags(data_buffer_.value); + break; + + case STA: + data_buffer_.value = registers_.a.full & registers_.m_masks[1]; + data_buffer_.size = 2 - m_flag(); + break; + + case STZ: + data_buffer_.value = 0; + data_buffer_.size = 2 - m_flag(); + break; + + case STX: + data_buffer_.value = registers_.x.full & registers_.x_masks[1]; + data_buffer_.size = 2 - x_flag(); + break; + + case STY: + data_buffer_.value = registers_.y.full & registers_.x_masks[1]; + data_buffer_.size = 2 - m_flag(); + break; + + case PHB: + data_buffer_.value = registers_.data_bank >> 16; + data_buffer_.size = 1; + break; + + case PHK: + data_buffer_.value = registers_.program_bank >> 16; + data_buffer_.size = 1; + break; + + case PHD: + data_buffer_.value = registers_.direct; + data_buffer_.size = 2; + break; + + case PHP: + data_buffer_.value = get_flags(); + data_buffer_.size = 1; + + if(registers_.emulation_flag) { + // On the 6502, the break flag is set during a PHP. + data_buffer_.value |= Flag::Break; + } + break; + + case NOP: break; + + // The below attempt to obey the 8/16-bit mixed transfer rules + // as documented in https://softpixel.com/~cwright/sianse/docs/65816NFO.HTM + // (and make reasonable guesses as to the N flag). + + case TXS: + registers_.s = registers_.x.full & registers_.x_masks[1]; + break; + + case TSX: + LD(registers_.x, registers_.s.full, registers_.x_masks); + registers_.flags.set_nz(registers_.x.full, registers_.x_shift); + break; + + case TXY: + LD(registers_.y, registers_.x.full, registers_.x_masks); + registers_.flags.set_nz(registers_.y.full, registers_.x_shift); + break; + + case TYX: + LD(registers_.x, registers_.y.full, registers_.x_masks); + registers_.flags.set_nz(registers_.x.full, registers_.x_shift); + break; + + case TAX: + LD(registers_.x, registers_.a.full, registers_.x_masks); + registers_.flags.set_nz(registers_.x.full, registers_.x_shift); + break; + + case TAY: + LD(registers_.y, registers_.a.full, registers_.x_masks); + registers_.flags.set_nz(registers_.y.full, registers_.x_shift); + break; + + case TXA: + LD(registers_.a, registers_.x.full, registers_.m_masks); + registers_.flags.set_nz(registers_.a.full, registers_.m_shift); + break; + + case TYA: + LD(registers_.a, registers_.y.full, registers_.m_masks); + registers_.flags.set_nz(registers_.a.full, registers_.m_shift); + break; + + case TCD: + registers_.direct = registers_.a.full; + registers_.flags.set_nz(registers_.a.full, 8); + break; + + case TDC: + registers_.a.full = registers_.direct; + registers_.flags.set_nz(registers_.a.full, 8); + break; + + case TCS: + registers_.s.full = registers_.a.full; + // No need to worry about byte masking here; for the stack it's handled as the emulation runs. + break; + + case TSC: + registers_.a.full = stack_address(); + registers_.flags.set_nz(registers_.a.full, 8); + break; + + case XBA: { + const uint8_t a_low = registers_.a.halves.low; + registers_.a.halves.low = registers_.a.halves.high; + registers_.a.halves.high = a_low; + registers_.flags.set_nz(registers_.a.halves.low); + } break; + + // + // Jumps and returns. + // + + case JML: + registers_.program_bank = instruction_buffer_.value & 0xff0000; + [[fallthrough]]; + + case JMP: + registers_.pc = uint16_t(instruction_buffer_.value); + break; + + case JMPind: + registers_.pc = data_buffer_.value; + break; + + case RTS: + registers_.pc = data_buffer_.value + 1; + break; + + case JSL: + registers_.program_bank = instruction_buffer_.value & 0xff0000; + [[fallthrough]]; + + case JSR: + data_buffer_.value = registers_.pc; + data_buffer_.size = 2; + + registers_.pc = instruction_buffer_.value; + break; + + case RTI: + registers_.pc = uint16_t(data_buffer_.value >> 8); + set_flags(uint8_t(data_buffer_.value)); + + if(!registers_.emulation_flag) { + registers_.program_bank = (data_buffer_.value & 0xff000000) >> 8; + } + break; + + // + // Block moves. + // + + case MVP: + registers_.data_bank = (instruction_buffer_.value & 0xff) << 16; + --registers_.x.full; + --registers_.y.full; + --registers_.a.full; + if(registers_.a.full) registers_.pc -= 3; + break; + + case MVN: + registers_.data_bank = (instruction_buffer_.value & 0xff) << 16; + ++registers_.x.full; + ++registers_.y.full; + --registers_.a.full; + if(registers_.a.full) registers_.pc -= 3; + break; + + // + // Flag manipulation. + // + + case CLC: registers_.flags.carry = 0; break; + case CLI: registers_.flags.inverse_interrupt = Flag::Interrupt; break; + case CLV: registers_.flags.overflow = 0; break; + case CLD: registers_.flags.decimal = 0; break; + + case SEC: registers_.flags.carry = Flag::Carry; break; + case SEI: registers_.flags.inverse_interrupt = 0; break; + case SED: registers_.flags.decimal = Flag::Decimal; break; + + case REP: + set_flags(get_flags() &~ instruction_buffer_.value); + break; + + case SEP: + set_flags(get_flags() | instruction_buffer_.value); + break; + + case XCE: { + const bool old_emulation_flag = registers_.emulation_flag; + set_emulation_mode(registers_.flags.carry); + registers_.flags.carry = old_emulation_flag; + } break; + + // + // Increments and decrements. + // + + case INC: + ++data_buffer_.value; + registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); + break;; + + case DEC: + --data_buffer_.value; + registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); + break; + + case INX: { + const uint16_t x_inc = registers_.x.full + 1; + LD(registers_.x, x_inc, registers_.x_masks); + registers_.flags.set_nz(registers_.x.full, registers_.x_shift); + } break; + + case DEX: { + const uint16_t x_dec = registers_.x.full - 1; + LD(registers_.x, x_dec, registers_.x_masks); + registers_.flags.set_nz(registers_.x.full, registers_.x_shift); + } break; + + case INY: { + const uint16_t y_inc = registers_.y.full + 1; + LD(registers_.y, y_inc, registers_.x_masks); + registers_.flags.set_nz(registers_.y.full, registers_.x_shift); + } break; + + case DEY: { + const uint16_t y_dec = registers_.y.full - 1; + LD(registers_.y, y_dec, registers_.x_masks); + registers_.flags.set_nz(registers_.y.full, registers_.x_shift); + } break; + + // + // Bitwise operations. + // + + case AND: + registers_.a.full &= data_buffer_.value | registers_.m_masks[0]; + registers_.flags.set_nz(registers_.a.full, registers_.m_shift); + break; + + case EOR: + registers_.a.full ^= data_buffer_.value; + registers_.flags.set_nz(registers_.a.full, registers_.m_shift); + break; + + case ORA: + registers_.a.full |= data_buffer_.value; + registers_.flags.set_nz(registers_.a.full, registers_.m_shift); + break; + + case BIT: + registers_.flags.set_n(data_buffer_.value, registers_.m_shift); + registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); + registers_.flags.overflow = data_buffer_.value & Flag::Overflow; + break; + + case BITimm: + registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); + break; + + case TRB: + registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); + data_buffer_.value &= ~registers_.a.full; + break; + + case TSB: + registers_.flags.set_z(data_buffer_.value & registers_.a.full, registers_.m_shift); + data_buffer_.value |= registers_.a.full; + break; + + // + // Branches. + // #define BRA(condition) \ if(!(condition)) { \ @@ -754,54 +769,54 @@ template void Processor> (7 + registers_.m_shift); - data_buffer_.value <<= 1; - registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); - break; + case ASL: + registers_.flags.carry = data_buffer_.value >> (7 + registers_.m_shift); + data_buffer_.value <<= 1; + registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); + break; - case LSR: - registers_.flags.carry = data_buffer_.value & 1; - data_buffer_.value >>= 1; - registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); - break; + case LSR: + registers_.flags.carry = data_buffer_.value & 1; + data_buffer_.value >>= 1; + registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); + break; - case ROL: - data_buffer_.value = (data_buffer_.value << 1) | registers_.flags.carry; - registers_.flags.carry = data_buffer_.value >> (8 + registers_.m_shift); - registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); - break; + case ROL: + data_buffer_.value = (data_buffer_.value << 1) | registers_.flags.carry; + registers_.flags.carry = data_buffer_.value >> (8 + registers_.m_shift); + registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); + break; - case ROR: { - const uint8_t next_carry = data_buffer_.value & 1; - data_buffer_.value = (data_buffer_.value >> 1) | (registers_.flags.carry << (7 + registers_.m_shift)); - registers_.flags.carry = next_carry; - registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); - } break; + case ROR: { + const uint8_t next_carry = data_buffer_.value & 1; + data_buffer_.value = (data_buffer_.value >> 1) | (registers_.flags.carry << (7 + registers_.m_shift)); + registers_.flags.carry = next_carry; + registers_.flags.set_nz(data_buffer_.value, registers_.m_shift); + } break; - // - // Arithmetic. - // + // + // Arithmetic. + // #define cp(v, shift, masks) {\ const uint32_t temp32 = (v.full & masks[1]) - (data_buffer_.value & masks[1]); \ @@ -809,19 +824,19 @@ template void Processor> (8 + shift))&1; \ } - case CMP: cp(registers_.a, registers_.m_shift, registers_.m_masks); break; - case CPX: cp(registers_.x, registers_.x_shift, registers_.x_masks); break; - case CPY: cp(registers_.y, registers_.x_shift, registers_.x_masks); break; + case CMP: cp(registers_.a, registers_.m_shift, registers_.m_masks); break; + case CPX: cp(registers_.x, registers_.x_shift, registers_.x_masks); break; + case CPY: cp(registers_.y, registers_.x_shift, registers_.x_masks); break; #undef cp - case SBC: - if(registers_.flags.decimal) { - // I've yet to manage to find a rational way to map this to an ADC, - // hence the yucky repetition of code here. - const uint16_t a = registers_.a.full & registers_.m_masks[1]; - unsigned int result = 0; - unsigned int borrow = registers_.flags.carry ^ 1; + case SBC: + if(registers_.flags.decimal) { + // I've yet to manage to find a rational way to map this to an ADC, + // hence the yucky repetition of code here. + const uint16_t a = registers_.a.full & registers_.m_masks[1]; + unsigned int result = 0; + unsigned int borrow = registers_.flags.carry ^ 1; #define nibble(mask, adjustment, carry) \ result += (a & mask) - (data_buffer_.value & mask) - borrow; \ @@ -829,66 +844,66 @@ template void Processor mask) ? carry : 0; \ result &= (carry - 1); - nibble(0x000f, 0x0006, 0x00010); - nibble(0x00f0, 0x0060, 0x00100); - nibble(0x0f00, 0x0600, 0x01000); - nibble(0xf000, 0x6000, 0x10000); + nibble(0x000f, 0x0006, 0x00010); + nibble(0x00f0, 0x0060, 0x00100); + nibble(0x0f00, 0x0600, 0x01000); + nibble(0xf000, 0x6000, 0x10000); #undef nibble - registers_.flags.overflow = ~(( (result ^ registers_.a.full) & (result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40; - registers_.flags.set_nz(result, registers_.m_shift); - registers_.flags.carry = ((borrow >> 16)&1)^1; - LD(registers_.a, result, registers_.m_masks); + registers_.flags.overflow = ~(( (result ^ registers_.a.full) & (result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40; + registers_.flags.set_nz(result, registers_.m_shift); + registers_.flags.carry = ((borrow >> 16)&1)^1; + LD(registers_.a, result, registers_.m_masks); - break; - } + break; + } - data_buffer_.value = ~data_buffer_.value & registers_.m_masks[1]; - [[fallthrough]]; + data_buffer_.value = ~data_buffer_.value & registers_.m_masks[1]; + [[fallthrough]]; - case ADC: { - int result; - const uint16_t a = registers_.a.full & registers_.m_masks[1]; + case ADC: { + int result; + const uint16_t a = registers_.a.full & registers_.m_masks[1]; - if(registers_.flags.decimal) { - result = registers_.flags.carry; + if(registers_.flags.decimal) { + result = registers_.flags.carry; #define nibble(mask, limit, adjustment, carry) \ result += (a & mask) + (data_buffer_.value & mask); \ if(result >= limit) result = ((result + (adjustment)) & (carry - 1)) + carry; - nibble(0x000f, 0x000a, 0x0006, 0x00010); - nibble(0x00f0, 0x00a0, 0x0060, 0x00100); - nibble(0x0f00, 0x0a00, 0x0600, 0x01000); - nibble(0xf000, 0xa000, 0x6000, 0x10000); + nibble(0x000f, 0x000a, 0x0006, 0x00010); + nibble(0x00f0, 0x00a0, 0x0060, 0x00100); + nibble(0x0f00, 0x0a00, 0x0600, 0x01000); + nibble(0xf000, 0xa000, 0x6000, 0x10000); #undef nibble - } else { - result = a + data_buffer_.value + registers_.flags.carry; - } + } else { + result = a + data_buffer_.value + registers_.flags.carry; + } - registers_.flags.overflow = (( (result ^ registers_.a.full) & (result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40; - registers_.flags.set_nz(result, registers_.m_shift); - registers_.flags.carry = (result >> (8 + registers_.m_shift))&1; - LD(registers_.a, result, registers_.m_masks); - } break; + registers_.flags.overflow = (( (result ^ registers_.a.full) & (result ^ data_buffer_.value) ) >> (1 + registers_.m_shift))&0x40; + registers_.flags.set_nz(result, registers_.m_shift); + registers_.flags.carry = (result >> (8 + registers_.m_shift))&1; + LD(registers_.a, result, registers_.m_masks); + } break; - // - // STP and WAI - // + // + // STP and WAI + // - case STP: - required_exceptions_ = Reset; - break; + case STP: + required_exceptions_ = Reset; + break; - case WAI: - required_exceptions_ = Reset | IRQ | NMI; - break; - } - continue; - } + case WAI: + required_exceptions_ = Reset | IRQ | NMI; + break; + } + continue; + } #undef LD #undef m_top @@ -896,12 +911,11 @@ template void Processor void Processor::set_ready_line(bool active) { + assert(uses_ready_line); + ready_line_ = active; +} + // The 65816 can't jam. bool ProcessorBase::is_jammed() const { return false; } + +bool ProcessorBase::get_is_resetting() const { + return pending_exceptions_ & (Reset | PowerOn); +}