From 3ceef2005b78ac98a00ad7689998de89111f6f75 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 3 Jun 2017 19:17:34 -0400 Subject: [PATCH 1/2] Pulled the Z80 from the MicroOpScheduler inheritance tree as it barely uses the thing, and that allows me to make the MicroOp structure private. --- Processors/Z80/Z80.hpp | 182 +++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 90 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 78c72af59..5721d9ddc 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -14,7 +14,6 @@ #include #include -#include "../MicroOpScheduler.hpp" #include "../RegisterSizes.hpp" namespace CPU { @@ -79,92 +78,6 @@ struct MachineCycle { uint8_t *value; }; -struct MicroOp { - enum Type { - BusOperation, - DecodeOperation, - DecodeOperationNoRChange, - MoveToNextProgram, - - Increment8, - Increment16, - Decrement8, - Decrement16, - Move8, - Move16, - - IncrementPC, - - AssembleAF, - DisassembleAF, - - And, - Or, - Xor, - - TestNZ, - TestZ, - TestNC, - TestC, - TestPO, - TestPE, - TestP, - TestM, - - ADD16, ADC16, SBC16, - CP8, SUB8, SBC8, ADD8, ADC8, - NEG, - - ExDEHL, ExAFAFDash, EXX, - - EI, DI, IM, - - LDI, LDIR, LDD, LDDR, - CPI, CPIR, CPD, CPDR, - INI, INIR, IND, INDR, - OUTI, OUTD, OUT_R, - - RLA, RLCA, RRA, RRCA, - RLC, RRC, RL, RR, - SLA, SRA, SLL, SRL, - RLD, RRD, - - SetInstructionPage, - CalculateIndexAddress, - - BeginNMI, - BeginIRQ, - BeginIRQMode0, - RETN, - JumpTo66, - HALT, - - DJNZ, - DAA, - CPL, - SCF, - CCF, - - RES, - BIT, - SET, - - CalculateRSTDestination, - - SetAFlags, - SetInFlags, - SetZero, - - IndexedPlaceHolder, - - Reset - }; - Type type; - void *source; - void *destination; - MachineCycle machine_cycle; -}; - /*! @abstact An abstract base class for emulation of a Z80 processor via the curiously recurring template pattern/f-bounded polymorphism. @@ -172,7 +85,7 @@ struct MicroOp { order to provide the bus on which the Z80 operates and @c flush(), which is called upon completion of a continuous run of cycles to allow a subclass to bring any on-demand activities up to date. */ -template class Processor: public MicroOpScheduler { +template class Processor { private: uint8_t a_, i_, r_; RegisterPair bc_, de_, hl_; @@ -207,6 +120,94 @@ template class Processor: public MicroOpScheduler { RegisterPair temp16_; uint8_t temp8_; + struct MicroOp { + enum Type { + BusOperation, + DecodeOperation, + DecodeOperationNoRChange, + MoveToNextProgram, + + Increment8, + Increment16, + Decrement8, + Decrement16, + Move8, + Move16, + + IncrementPC, + + AssembleAF, + DisassembleAF, + + And, + Or, + Xor, + + TestNZ, + TestZ, + TestNC, + TestC, + TestPO, + TestPE, + TestP, + TestM, + + ADD16, ADC16, SBC16, + CP8, SUB8, SBC8, ADD8, ADC8, + NEG, + + ExDEHL, ExAFAFDash, EXX, + + EI, DI, IM, + + LDI, LDIR, LDD, LDDR, + CPI, CPIR, CPD, CPDR, + INI, INIR, IND, INDR, + OUTI, OUTD, OUT_R, + + RLA, RLCA, RRA, RRCA, + RLC, RRC, RL, RR, + SLA, SRA, SLL, SRL, + RLD, RRD, + + SetInstructionPage, + CalculateIndexAddress, + + BeginNMI, + BeginIRQ, + BeginIRQMode0, + RETN, + JumpTo66, + HALT, + + DJNZ, + DAA, + CPL, + SCF, + CCF, + + RES, + BIT, + SET, + + CalculateRSTDestination, + + SetAFlags, + SetInFlags, + SetZero, + + IndexedPlaceHolder, + + Reset + }; + Type type; + void *source; + void *destination; + MachineCycle machine_cycle; + }; + const MicroOp *scheduled_program_counter_; + + struct InstructionPage { std::vector instructions; std::vector all_operations; @@ -665,14 +666,15 @@ template class Processor: public MicroOpScheduler { } public: - Processor() : MicroOpScheduler(), + Processor() : halt_mask_(0xff), number_of_cycles_(0), request_status_(Interrupt::PowerOn), last_request_status_(Interrupt::PowerOn), irq_line_(false), bus_request_line_(false), - pc_increment_(1) { + pc_increment_(1), + scheduled_program_counter_(nullptr) { set_flags(0xff); assemble_base_page(base_page_, hl_, false, cb_page_); From b304c3a4b9b153bcaf3fca50ad36e51709a95a54 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 3 Jun 2017 20:30:07 -0400 Subject: [PATCH 2/2] Eliminated the 6502's reliance on the micro-op scheduler. --- .../Clock Signal.xcodeproj/project.pbxproj | 2 - Processors/6502/6502.hpp | 120 +++++++++--------- Processors/6502/6502AllRAM.cpp | 2 + Processors/MicroOpScheduler.hpp | 56 -------- 4 files changed, 61 insertions(+), 119 deletions(-) delete mode 100644 Processors/MicroOpScheduler.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 8d2395e20..2b38f5ab1 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -559,7 +559,6 @@ 4B6C73BC1D387AE500AFCFCA /* DiskController.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = ""; }; 4B77069B1EC904570053B588 /* Z80.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80.cpp; path = Z80/Z80.cpp; sourceTree = ""; }; 4B77069C1EC904570053B588 /* Z80.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80.hpp; path = Z80/Z80.hpp; sourceTree = ""; }; - 4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MicroOpScheduler.hpp; sourceTree = ""; }; 4B7913CA1DFCD80E00175A82 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Electron/Video.cpp; sourceTree = ""; }; 4B7913CB1DFCD80E00175A82 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Electron/Video.hpp; sourceTree = ""; }; 4B79E4411E3AF38600141F11 /* cassette.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cassette.png; sourceTree = ""; }; @@ -1838,7 +1837,6 @@ children = ( 4B1414561B58879D00E04248 /* 6502 */, 4B77069E1EC9045B0053B588 /* Z80 */, - 4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */, 4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */, 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */, 4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */, diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index 80a288fd1..9250405e4 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -12,7 +12,6 @@ #include #include -#include "../MicroOpScheduler.hpp" #include "../RegisterSizes.hpp" namespace CPU { @@ -67,51 +66,6 @@ enum BusOperation { */ extern const uint8_t JamOpcode; -/* - This emulation functions by decomposing instructions into micro programs, consisting of the micro operations - as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle - to perform whereas those called OperationX occur for free (so, in effect, their cost is loaded onto the next cycle). -*/ -enum MicroOp { - CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH, - CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand, - OperationSetI, - - OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector, - CycleReadVectorLow, CycleReadVectorHigh, - - CycleReadFromS, CycleReadFromPC, - CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA, - CycleNoWritePush, - CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL, - CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute, - OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow, - CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead, - OperationMoveToNextProgram, OperationIncrementPC, - CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA, - CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand, - OperationIncrementOperand, OperationORA, OperationAND, OperationEOR, - OperationINS, OperationADC, OperationSBC, OperationLDA, - OperationLDX, OperationLDY, OperationLAX, OperationSTA, - OperationSTX, OperationSTY, OperationSAX, OperationSHA, - OperationSHX, OperationSHY, OperationSHS, OperationCMP, - OperationCPX, OperationCPY, OperationBIT, OperationASL, - OperationASO, OperationROL, OperationRLA, OperationLSR, - OperationLSE, OperationASR, OperationROR, OperationRRA, - OperationCLC, OperationCLI, OperationCLV, OperationCLD, - OperationSEC, OperationSEI, OperationSED, OperationINC, - OperationDEC, OperationINX, OperationDEX, OperationINY, - OperationDEY, OperationBPL, OperationBMI, OperationBVC, - OperationBVS, OperationBCC, OperationBCS, OperationBNE, - OperationBEQ, OperationTXA, OperationTYA, OperationTXS, - OperationTAY, OperationTAX, OperationTSX, OperationARR, - OperationSBX, OperationLXA, OperationANE, OperationANC, - OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet, - OperationSetOperandFromFlags, - OperationSetFlagsFromA, - CycleScheduleJam -}; - /*! @abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism. @@ -123,7 +77,7 @@ enum MicroOp { that will cause call outs when the program counter reaches those addresses. @c return_from_subroutine can be used to exit from a jammed state. */ -template class Processor: public MicroOpScheduler { +template class Processor { public: class JamHandler { @@ -133,7 +87,53 @@ template class Processor: public MicroOpScheduler { private: -#define JAM {CycleFetchOperand, CycleScheduleJam, OperationMoveToNextProgram} + /* + This emulation functions by decomposing instructions into micro programs, consisting of the micro operations + as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle + to perform whereas those called OperationX occur for free (so, in effect, their cost is loaded onto the next cycle). + */ + enum MicroOp { + CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH, + CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand, + OperationSetI, + + OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector, + CycleReadVectorLow, CycleReadVectorHigh, + + CycleReadFromS, CycleReadFromPC, + CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA, + CycleNoWritePush, + CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL, + CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute, + OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow, + CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead, + OperationMoveToNextProgram, OperationIncrementPC, + CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA, + CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand, + OperationIncrementOperand, OperationORA, OperationAND, OperationEOR, + OperationINS, OperationADC, OperationSBC, OperationLDA, + OperationLDX, OperationLDY, OperationLAX, OperationSTA, + OperationSTX, OperationSTY, OperationSAX, OperationSHA, + OperationSHX, OperationSHY, OperationSHS, OperationCMP, + OperationCPX, OperationCPY, OperationBIT, OperationASL, + OperationASO, OperationROL, OperationRLA, OperationLSR, + OperationLSE, OperationASR, OperationROR, OperationRRA, + OperationCLC, OperationCLI, OperationCLV, OperationCLD, + OperationSEC, OperationSEI, OperationSED, OperationINC, + OperationDEC, OperationINX, OperationDEX, OperationINY, + OperationDEY, OperationBPL, OperationBMI, OperationBVC, + OperationBVS, OperationBCC, OperationBCS, OperationBNE, + OperationBEQ, OperationTXA, OperationTYA, OperationTXS, + OperationTAY, OperationTAX, OperationTSX, OperationARR, + OperationSBX, OperationLXA, OperationANE, OperationANC, + OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet, + OperationSetOperandFromFlags, + OperationSetFlagsFromA, + CycleScheduleJam + }; + const MicroOp *scheduled_program_counter_; + +#define JAM {CycleFetchOperand, CycleScheduleJam} /* Storage for the 6502 registers; F is stored as individual flags. @@ -422,7 +422,7 @@ template class Processor: public MicroOpScheduler { #undef Immediate #undef Implied - schedule_program(operations[operation]); + scheduled_program_counter_ = operations[operation]; } bool is_jammed_; @@ -522,7 +522,8 @@ template class Processor: public MicroOpScheduler { interrupt_requests_(InterruptRequestFlags::PowerOn), irq_line_(0), nmi_line_is_enabled_(false), - set_overflow_line_is_enabled_(false) { + set_overflow_line_is_enabled_(false), + scheduled_program_counter_(nullptr) { // only the interrupt flag is defined upon reset but get_flags isn't going to // mask the other flags so we need to do that, at least carry_flag_ &= Flag::Carry; @@ -550,8 +551,7 @@ template class Processor: public MicroOpScheduler { static const MicroOp fetch_decode_execute[] = { CycleFetchOperation, CycleFetchOperand, - OperationDecodeOperation, - OperationMoveToNextProgram + OperationDecodeOperation }; // These plus program below act to give the compiler permission to update these values @@ -564,19 +564,18 @@ template class Processor: public MicroOpScheduler { #define checkSchedule(op) \ if(!scheduled_program_counter_) {\ - schedule_programs_read_pointer_ = schedule_programs_write_pointer_ = 0; \ if(interrupt_requests_) {\ if(interrupt_requests_ & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn)) {\ interrupt_requests_ &= ~InterruptRequestFlags::PowerOn;\ - schedule_program(get_reset_program());\ + scheduled_program_counter_ = get_reset_program();\ } else if(interrupt_requests_ & InterruptRequestFlags::NMI) {\ interrupt_requests_ &= ~InterruptRequestFlags::NMI;\ - schedule_program(get_nmi_program());\ + scheduled_program_counter_ = get_nmi_program();\ } else if(interrupt_requests_ & InterruptRequestFlags::IRQ) {\ - schedule_program(get_irq_program());\ + scheduled_program_counter_ = get_irq_program();\ } \ } else {\ - schedule_program(fetch_decode_execute);\ + scheduled_program_counter_ = fetch_decode_execute;\ }\ op;\ } @@ -644,7 +643,7 @@ template class Processor: public MicroOpScheduler { continue; case OperationMoveToNextProgram: - move_to_next_program(); + scheduled_program_counter_ = nullptr; checkSchedule(); continue; @@ -704,7 +703,7 @@ template class Processor: public MicroOpScheduler { case CycleScheduleJam: { is_jammed_ = true; static const MicroOp jam[] = JAM; - schedule_program(jam); + scheduled_program_counter_ = jam; if(jam_handler_) { jam_handler_->processor_did_jam(this, pc_.full - 1); @@ -1003,7 +1002,7 @@ template class Processor: public MicroOpScheduler { #pragma mark - Branching -#define BRA(condition) pc_.full++; if(condition) schedule_program(doBranch) +#define BRA(condition) pc_.full++; if(condition) scheduled_program_counter_ = doBranch case OperationBPL: BRA(!(negative_result_&0x80)); continue; case OperationBMI: BRA(negative_result_&0x80); continue; @@ -1145,7 +1144,6 @@ template class Processor: public MicroOpScheduler { pc_.full++; if(is_jammed_) { - scheduled_programs_[0] = scheduled_programs_[1] = scheduled_programs_[2] = scheduled_programs_[3] = nullptr; scheduled_program_counter_ = nullptr; } } diff --git a/Processors/6502/6502AllRAM.cpp b/Processors/6502/6502AllRAM.cpp index 66d386b8a..7c822616f 100644 --- a/Processors/6502/6502AllRAM.cpp +++ b/Processors/6502/6502AllRAM.cpp @@ -19,6 +19,8 @@ AllRAMProcessor::AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) { int AllRAMProcessor::perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { timestamp_++; +// if(operation == MOS6502::BusOperation::ReadOpcode) printf("%04x\n", address); + if(isReadOperation(operation)) { *value = memory_[address]; } else { diff --git a/Processors/MicroOpScheduler.hpp b/Processors/MicroOpScheduler.hpp deleted file mode 100644 index 846fce754..000000000 --- a/Processors/MicroOpScheduler.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// -// MicroOpScheduler.hpp -// Clock Signal -// -// Created by Thomas Harte on 14/05/2017. -// Copyright © 2017 Thomas Harte. All rights reserved. -// - -#ifndef MicroOpScheduler_hpp -#define MicroOpScheduler_hpp - -namespace CPU { - -template class MicroOpScheduler { - public: - MicroOpScheduler() : - scheduled_programs_{nullptr, nullptr, nullptr, nullptr}, - schedule_programs_write_pointer_(0), - schedule_programs_read_pointer_(0), - scheduled_program_counter_(nullptr) {} - - protected: - /* - Up to four programs can be scheduled; each will be carried out in turn. This - storage maintains pointers to the scheduled list of programs. - - Programs should be terminated by an OperationMoveToNextProgram, causing this - queue to take that step. - */ - const T *scheduled_programs_[4]; - const T *scheduled_program_counter_; - unsigned int schedule_programs_write_pointer_, schedule_programs_read_pointer_; - - /*! - Schedules a new program, adding it to the end of the queue. Programs should be - terminated with a OperationMoveToNextProgram. No attempt to copy the program - is made; a non-owning reference is kept. - - @param program The program to schedule. - */ - inline void schedule_program(const T *program) { - scheduled_programs_[schedule_programs_write_pointer_] = program; - if(schedule_programs_write_pointer_ == schedule_programs_read_pointer_) scheduled_program_counter_ = program; - schedule_programs_write_pointer_ = (schedule_programs_write_pointer_+1)&3; - } - - inline void move_to_next_program() { - scheduled_programs_[schedule_programs_read_pointer_] = nullptr; - schedule_programs_read_pointer_ = (schedule_programs_read_pointer_+1)&3; - scheduled_program_counter_ = scheduled_programs_[schedule_programs_read_pointer_]; - } -}; - -} - -#endif /* MicroOpScheduler_hpp */