mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 03:32:01 +00:00
Merge pull request #128 from TomHarte/Scheduling
Eliminates the micro-op scheduler
This commit is contained in:
commit
0b2a3f18bc
@ -559,7 +559,6 @@
|
|||||||
4B6C73BC1D387AE500AFCFCA /* DiskController.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = "<group>"; };
|
4B6C73BC1D387AE500AFCFCA /* DiskController.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = "<group>"; };
|
||||||
4B77069B1EC904570053B588 /* Z80.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80.cpp; path = Z80/Z80.cpp; sourceTree = "<group>"; };
|
4B77069B1EC904570053B588 /* Z80.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80.cpp; path = Z80/Z80.cpp; sourceTree = "<group>"; };
|
||||||
4B77069C1EC904570053B588 /* Z80.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80.hpp; path = Z80/Z80.hpp; sourceTree = "<group>"; };
|
4B77069C1EC904570053B588 /* Z80.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80.hpp; path = Z80/Z80.hpp; sourceTree = "<group>"; };
|
||||||
4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MicroOpScheduler.hpp; sourceTree = "<group>"; };
|
|
||||||
4B7913CA1DFCD80E00175A82 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Electron/Video.cpp; sourceTree = "<group>"; };
|
4B7913CA1DFCD80E00175A82 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Electron/Video.cpp; sourceTree = "<group>"; };
|
||||||
4B7913CB1DFCD80E00175A82 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Electron/Video.hpp; sourceTree = "<group>"; };
|
4B7913CB1DFCD80E00175A82 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Electron/Video.hpp; sourceTree = "<group>"; };
|
||||||
4B79E4411E3AF38600141F11 /* cassette.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cassette.png; sourceTree = "<group>"; };
|
4B79E4411E3AF38600141F11 /* cassette.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cassette.png; sourceTree = "<group>"; };
|
||||||
@ -1838,7 +1837,6 @@
|
|||||||
children = (
|
children = (
|
||||||
4B1414561B58879D00E04248 /* 6502 */,
|
4B1414561B58879D00E04248 /* 6502 */,
|
||||||
4B77069E1EC9045B0053B588 /* Z80 */,
|
4B77069E1EC9045B0053B588 /* Z80 */,
|
||||||
4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */,
|
|
||||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
|
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
|
||||||
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */,
|
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */,
|
||||||
4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */,
|
4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */,
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "../MicroOpScheduler.hpp"
|
|
||||||
#include "../RegisterSizes.hpp"
|
#include "../RegisterSizes.hpp"
|
||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
@ -67,51 +66,6 @@ enum BusOperation {
|
|||||||
*/
|
*/
|
||||||
extern const uint8_t JamOpcode;
|
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.
|
@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
|
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.
|
jammed state.
|
||||||
*/
|
*/
|
||||||
template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
template <class T> class Processor {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class JamHandler {
|
class JamHandler {
|
||||||
@ -133,7 +87,53 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
|
|
||||||
private:
|
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.
|
Storage for the 6502 registers; F is stored as individual flags.
|
||||||
@ -422,7 +422,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
#undef Immediate
|
#undef Immediate
|
||||||
#undef Implied
|
#undef Implied
|
||||||
|
|
||||||
schedule_program(operations[operation]);
|
scheduled_program_counter_ = operations[operation];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_jammed_;
|
bool is_jammed_;
|
||||||
@ -522,7 +522,8 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
interrupt_requests_(InterruptRequestFlags::PowerOn),
|
interrupt_requests_(InterruptRequestFlags::PowerOn),
|
||||||
irq_line_(0),
|
irq_line_(0),
|
||||||
nmi_line_is_enabled_(false),
|
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
|
// 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
|
// mask the other flags so we need to do that, at least
|
||||||
carry_flag_ &= Flag::Carry;
|
carry_flag_ &= Flag::Carry;
|
||||||
@ -550,8 +551,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
static const MicroOp fetch_decode_execute[] = {
|
static const MicroOp fetch_decode_execute[] = {
|
||||||
CycleFetchOperation,
|
CycleFetchOperation,
|
||||||
CycleFetchOperand,
|
CycleFetchOperand,
|
||||||
OperationDecodeOperation,
|
OperationDecodeOperation
|
||||||
OperationMoveToNextProgram
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// These plus program below act to give the compiler permission to update these values
|
// These plus program below act to give the compiler permission to update these values
|
||||||
@ -564,19 +564,18 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
|
|
||||||
#define checkSchedule(op) \
|
#define checkSchedule(op) \
|
||||||
if(!scheduled_program_counter_) {\
|
if(!scheduled_program_counter_) {\
|
||||||
schedule_programs_read_pointer_ = schedule_programs_write_pointer_ = 0; \
|
|
||||||
if(interrupt_requests_) {\
|
if(interrupt_requests_) {\
|
||||||
if(interrupt_requests_ & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn)) {\
|
if(interrupt_requests_ & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn)) {\
|
||||||
interrupt_requests_ &= ~InterruptRequestFlags::PowerOn;\
|
interrupt_requests_ &= ~InterruptRequestFlags::PowerOn;\
|
||||||
schedule_program(get_reset_program());\
|
scheduled_program_counter_ = get_reset_program();\
|
||||||
} else if(interrupt_requests_ & InterruptRequestFlags::NMI) {\
|
} else if(interrupt_requests_ & InterruptRequestFlags::NMI) {\
|
||||||
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) {\
|
} else if(interrupt_requests_ & InterruptRequestFlags::IRQ) {\
|
||||||
schedule_program(get_irq_program());\
|
scheduled_program_counter_ = get_irq_program();\
|
||||||
} \
|
} \
|
||||||
} else {\
|
} else {\
|
||||||
schedule_program(fetch_decode_execute);\
|
scheduled_program_counter_ = fetch_decode_execute;\
|
||||||
}\
|
}\
|
||||||
op;\
|
op;\
|
||||||
}
|
}
|
||||||
@ -644,7 +643,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case OperationMoveToNextProgram:
|
case OperationMoveToNextProgram:
|
||||||
move_to_next_program();
|
scheduled_program_counter_ = nullptr;
|
||||||
checkSchedule();
|
checkSchedule();
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -704,7 +703,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
case CycleScheduleJam: {
|
case CycleScheduleJam: {
|
||||||
is_jammed_ = true;
|
is_jammed_ = true;
|
||||||
static const MicroOp jam[] = JAM;
|
static const MicroOp jam[] = JAM;
|
||||||
schedule_program(jam);
|
scheduled_program_counter_ = jam;
|
||||||
|
|
||||||
if(jam_handler_) {
|
if(jam_handler_) {
|
||||||
jam_handler_->processor_did_jam(this, pc_.full - 1);
|
jam_handler_->processor_did_jam(this, pc_.full - 1);
|
||||||
@ -1003,7 +1002,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
|
|
||||||
#pragma mark - Branching
|
#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 OperationBPL: BRA(!(negative_result_&0x80)); continue;
|
||||||
case OperationBMI: BRA(negative_result_&0x80); continue;
|
case OperationBMI: BRA(negative_result_&0x80); continue;
|
||||||
@ -1145,7 +1144,6 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
pc_.full++;
|
pc_.full++;
|
||||||
|
|
||||||
if(is_jammed_) {
|
if(is_jammed_) {
|
||||||
scheduled_programs_[0] = scheduled_programs_[1] = scheduled_programs_[2] = scheduled_programs_[3] = nullptr;
|
|
||||||
scheduled_program_counter_ = nullptr;
|
scheduled_program_counter_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ AllRAMProcessor::AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) {
|
|||||||
int AllRAMProcessor::perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
int AllRAMProcessor::perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||||
timestamp_++;
|
timestamp_++;
|
||||||
|
|
||||||
|
// if(operation == MOS6502::BusOperation::ReadOpcode) printf("%04x\n", address);
|
||||||
|
|
||||||
if(isReadOperation(operation)) {
|
if(isReadOperation(operation)) {
|
||||||
*value = memory_[address];
|
*value = memory_[address];
|
||||||
} else {
|
} else {
|
||||||
|
@ -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 T> 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 */
|
|
@ -14,7 +14,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../MicroOpScheduler.hpp"
|
|
||||||
#include "../RegisterSizes.hpp"
|
#include "../RegisterSizes.hpp"
|
||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
@ -79,92 +78,6 @@ struct MachineCycle {
|
|||||||
uint8_t *value;
|
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.
|
@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
|
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.
|
of cycles to allow a subclass to bring any on-demand activities up to date.
|
||||||
*/
|
*/
|
||||||
template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
template <class T> class Processor {
|
||||||
private:
|
private:
|
||||||
uint8_t a_, i_, r_;
|
uint8_t a_, i_, r_;
|
||||||
RegisterPair bc_, de_, hl_;
|
RegisterPair bc_, de_, hl_;
|
||||||
@ -207,6 +120,94 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
RegisterPair temp16_;
|
RegisterPair temp16_;
|
||||||
uint8_t temp8_;
|
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 {
|
struct InstructionPage {
|
||||||
std::vector<MicroOp *> instructions;
|
std::vector<MicroOp *> instructions;
|
||||||
std::vector<MicroOp> all_operations;
|
std::vector<MicroOp> all_operations;
|
||||||
@ -665,14 +666,15 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Processor() : MicroOpScheduler(),
|
Processor() :
|
||||||
halt_mask_(0xff),
|
halt_mask_(0xff),
|
||||||
number_of_cycles_(0),
|
number_of_cycles_(0),
|
||||||
request_status_(Interrupt::PowerOn),
|
request_status_(Interrupt::PowerOn),
|
||||||
last_request_status_(Interrupt::PowerOn),
|
last_request_status_(Interrupt::PowerOn),
|
||||||
irq_line_(false),
|
irq_line_(false),
|
||||||
bus_request_line_(false),
|
bus_request_line_(false),
|
||||||
pc_increment_(1) {
|
pc_increment_(1),
|
||||||
|
scheduled_program_counter_(nullptr) {
|
||||||
set_flags(0xff);
|
set_flags(0xff);
|
||||||
|
|
||||||
assemble_base_page(base_page_, hl_, false, cb_page_);
|
assemble_base_page(base_page_, hl_, false, cb_page_);
|
||||||
|
Loading…
Reference in New Issue
Block a user