diff --git a/Processors/Z80/Implementation/Z80Storage.hpp b/Processors/Z80/Implementation/Z80Storage.hpp index 3269210ad..91577739d 100644 --- a/Processors/Z80/Implementation/Z80Storage.hpp +++ b/Processors/Z80/Implementation/Z80Storage.hpp @@ -127,8 +127,6 @@ class ProcessorStorage { InstructionPage() : r_step(1), is_indexed(false) {} }; - typedef MicroOp InstructionTable[256][30]; - ProcessorStorage(); void install_default_instruction_set(); @@ -223,6 +221,7 @@ class ProcessorStorage { carry_result_ = flags; } + typedef MicroOp InstructionTable[256][30]; virtual void assemble_page(InstructionPage &target, InstructionTable &table, bool add_offsets) = 0; virtual void copy_program(const MicroOp *source, std::vector &destination) = 0; diff --git a/Processors/Z80/State/State.cpp b/Processors/Z80/State/State.cpp index 081783ebf..10f81ae44 100644 --- a/Processors/Z80/State/State.cpp +++ b/Processors/Z80/State/State.cpp @@ -45,6 +45,55 @@ State::State(const ProcessorBase &src): State() { execution_state.operation = src.operation_; execution_state.flag_adjustment_history = src.flag_adjustment_history_; execution_state.pc_increment = src.pc_increment_; + execution_state.refresh_address = src.refresh_addr_.full; + execution_state.half_cycles_into_step = src.number_of_cycles_.as(); + + // Search for the current holder of the scheduled_program_counter_. +#define ContainedBy(x) (src.scheduled_program_counter_ >= &src.x[0]) && (src.scheduled_program_counter_ < &src.x[src.x.size()]) +#define Populate(x, y) \ + execution_state.phase = ExecutionState::Phase::x; \ + execution_state.steps_into_phase = int(src.scheduled_program_counter_ - &src.y[0]); + + if(ContainedBy(conditional_call_untaken_program_)) { + Populate(UntakenConditionalCall, conditional_call_untaken_program_); + } else if(ContainedBy(reset_program_)) { + Populate(Reset, reset_program_); + } else if(ContainedBy(irq_program_[0])) { + Populate(IRQMode0, irq_program_[0]); + } else if(ContainedBy(irq_program_[1])) { + Populate(IRQMode1, irq_program_[1]); + } else if(ContainedBy(irq_program_[2])) { + Populate(IRQMode2, irq_program_[2]); + } else if(ContainedBy(nmi_program_)) { + Populate(NMI, nmi_program_); + } else { + if(src.current_instruction_page_ == &src.base_page_) { + execution_state.instruction_page = 0; + } else if(src.current_instruction_page_ == &src.ed_page_) { + execution_state.instruction_page = 0xed; + } else if(src.current_instruction_page_ == &src.fd_page_) { + execution_state.instruction_page = 0xfd; + } else if(src.current_instruction_page_ == &src.dd_page_) { + execution_state.instruction_page = 0xdd; + } else if(src.current_instruction_page_ == &src.cb_page_) { + execution_state.instruction_page = 0xcb; + } else if(src.current_instruction_page_ == &src.fdcb_page_) { + execution_state.instruction_page = 0xfdcb; + } else if(src.current_instruction_page_ == &src.ddcb_page_) { + execution_state.instruction_page = 0xddcb; + } + + if(ContainedBy(current_instruction_page_->fetch_decode_execute)) { + Populate(FetchDecode, current_instruction_page_->fetch_decode_execute); + } else { + // There's no need to determine which opcode because that knowledge is already + // contained in the dedicated opcode field. + Populate(Operation, current_instruction_page_->instructions[src.operation_]); + } + } + +#undef Populate +#undef ContainedBy } void State::apply(ProcessorBase &target) { @@ -82,8 +131,30 @@ void State::apply(ProcessorBase &target) { target.operation_ = execution_state.operation; target.flag_adjustment_history_ = execution_state.flag_adjustment_history; target.pc_increment_ = execution_state.pc_increment; + target.refresh_addr_.full = execution_state.refresh_address; + target.number_of_cycles_ = HalfCycles(execution_state.half_cycles_into_step); - // TODO: scheduled_program_counter_ and number_of_cycles_. + switch(execution_state.instruction_page) { + default: target.current_instruction_page_ = &target.base_page_; break; + case 0xed: target.current_instruction_page_ = &target.ed_page_; break; + case 0xdd: target.current_instruction_page_ = &target.dd_page_; break; + case 0xcb: target.current_instruction_page_ = &target.cb_page_; break; + case 0xfd: target.current_instruction_page_ = &target.fd_page_; break; + case 0xfdcb: target.current_instruction_page_ = &target.fdcb_page_; break; + case 0xddcb: target.current_instruction_page_ = &target.ddcb_page_; break; + } + + switch(execution_state.phase) { + case ExecutionState::Phase::UntakenConditionalCall: target.scheduled_program_counter_ = &target.conditional_call_untaken_program_[0]; break; + case ExecutionState::Phase::Reset: target.scheduled_program_counter_ = &target.reset_program_[0]; break; + case ExecutionState::Phase::IRQMode0: target.scheduled_program_counter_ = &target.irq_program_[0][0]; break; + case ExecutionState::Phase::IRQMode1: target.scheduled_program_counter_ = &target.irq_program_[1][0]; break; + case ExecutionState::Phase::IRQMode2: target.scheduled_program_counter_ = &target.irq_program_[2][0]; break; + case ExecutionState::Phase::NMI: target.scheduled_program_counter_ = &target.nmi_program_[0]; break; + case ExecutionState::Phase::FetchDecode: target.scheduled_program_counter_ = &target.current_instruction_page_->fetch_decode_execute[0]; break; + case ExecutionState::Phase::Operation: target.scheduled_program_counter_ = target.current_instruction_page_->instructions[target.operation_]; break; + } + target.scheduled_program_counter_ += execution_state.steps_into_phase; } // Boilerplate follows here, to establish 'reflection'. @@ -127,6 +198,13 @@ State::ExecutionState::ExecutionState() { DeclareField(temp16); DeclareField(flag_adjustment_history); DeclareField(pc_increment); + DeclareField(refresh_address); + + AnnounceEnum(Phase); + DeclareField(phase); + DeclareField(half_cycles_into_step); + DeclareField(steps_into_phase); + DeclareField(instruction_page); } } diff --git a/Processors/Z80/State/State.hpp b/Processors/Z80/State/State.hpp index 4b2b5fc9f..05c210420 100644 --- a/Processors/Z80/State/State.hpp +++ b/Processors/Z80/State/State.hpp @@ -46,10 +46,10 @@ struct State: public Reflection::StructImpl { related to an access cycle. */ struct Inputs: public Reflection::StructImpl { - bool irq; - bool nmi; - bool bus_request; - bool wait; + bool irq = false; + bool nmi = false; + bool bus_request = false; + bool wait = false; Inputs(); } inputs; @@ -69,6 +69,17 @@ struct State: public Reflection::StructImpl { uint16_t temp16; unsigned int flag_adjustment_history; uint16_t pc_increment; + uint16_t refresh_address; + + ReflectableEnum(Phase, + UntakenConditionalCall, Reset, IRQMode0, IRQMode1, IRQMode2, + NMI, FetchDecode, Operation + ); + + Phase phase; + int half_cycles_into_step; + int steps_into_phase; + uint16_t instruction_page = 0; ExecutionState(); } execution_state;