1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Made the constructor protected, to emphasise that this class isn't for instantiation. Also added extra comments aplenty.

This commit is contained in:
Thomas Harte 2016-01-21 08:39:34 -05:00
parent 9fa35dd559
commit baef1ccd57

View File

@ -14,6 +14,9 @@
namespace CPU6502 { namespace CPU6502 {
/*
The list of registers that can be accessed via @c set_value_of_register and @c set_value_of_register.
*/
enum Register { enum Register {
LastOperationAddress, LastOperationAddress,
ProgramCounter, ProgramCounter,
@ -25,6 +28,9 @@ enum Register {
S S
}; };
/*
Flags as defined on the 6502; can be used to decode the result of @c get_flags or to form a value for @c set_flags.
*/
enum Flag { enum Flag {
Sign = 0x80, Sign = 0x80,
Overflow = 0x40, Overflow = 0x40,
@ -36,6 +42,13 @@ enum Flag {
Carry = 0x01 Carry = 0x01
}; };
/*!
Subclasses will be given the task of performing bus operations, allowing them to provide whatever interface they like
between a 6502 and the rest of the system. @c BusOperation lists the types of bus operation that may be requested.
@c None is reserved for internal use. It will never be requested from a subclass. It is safe always to use the
isReadOperation macro to make a binary choice between reading and writing.
*/
enum BusOperation { enum BusOperation {
Read, ReadOpcode, Write, Ready, None Read, ReadOpcode, Write, Ready, None
}; };
@ -51,8 +64,8 @@ enum BusOperation {
extern const uint8_t JamOpcode; extern const uint8_t JamOpcode;
/*! /*!
@abstact An abstract base class for emulation of a 6502 processor. @abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism.
@discussion Subclasses should implement @c perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) in @discussion Subclasses should implement @c perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) in
order to provde the bus on which the 6502 operates. Additional functionality can be provided by the host machine by providing order to provde the bus on which the 6502 operates. Additional functionality can be provided by the host machine by providing
a jam handler and inserting jam opcodes where appropriate; that will cause call outs when the program counter reaches those a jam handler and inserting jam opcodes where appropriate; that will cause call outs when the program counter reaches those
@ -68,6 +81,11 @@ template <class T> class Processor {
private: private:
/*
This emulation funcitons 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 { enum MicroOp {
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH, CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand, CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
@ -111,33 +129,69 @@ template <class T> class Processor {
} bytes; } bytes;
}; };
/*
Storage for the 6502 registers; F is stored as individual flags.
*/
RegisterPair _pc, _lastOperationPC; RegisterPair _pc, _lastOperationPC;
uint8_t _a, _x, _y, _s; uint8_t _a, _x, _y, _s;
uint8_t _carryFlag, _negativeResult, _zeroResult, _decimalFlag, _overflowFlag, _interruptFlag; uint8_t _carryFlag, _negativeResult, _zeroResult, _decimalFlag, _overflowFlag, _interruptFlag;
/*
Temporary state for the micro programs.
*/
uint8_t _operation, _operand; uint8_t _operation, _operand;
RegisterPair _address, _nextAddress; RegisterPair _address, _nextAddress;
/*
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 MicroOp *_scheduledPrograms[4]; const MicroOp *_scheduledPrograms[4];
unsigned int _scheduleProgramsWritePointer, _scheduleProgramsReadPointer, _scheduleProgramProgramCounter; unsigned int _scheduleProgramsWritePointer, _scheduleProgramsReadPointer, _scheduleProgramProgramCounter;
/*
Temporary storage allowing a common dispatch point for calling perform_bus_operation;
possibly deferring is no longer of value.
*/
BusOperation _nextBusOperation; BusOperation _nextBusOperation;
uint16_t _busAddress; uint16_t _busAddress;
uint8_t *_busValue; uint8_t *_busValue;
uint64_t _externalBus; /*!
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.
*/
void schedule_program(const MicroOp *program) void schedule_program(const MicroOp *program)
{ {
_scheduledPrograms[_scheduleProgramsWritePointer] = program; _scheduledPrograms[_scheduleProgramsWritePointer] = program;
_scheduleProgramsWritePointer = (_scheduleProgramsWritePointer+1)&3; _scheduleProgramsWritePointer = (_scheduleProgramsWritePointer+1)&3;
} }
/*!
Gets the flags register.
@see set_flags
@returns The current value of the flags register.
*/
uint8_t get_flags() uint8_t get_flags()
{ {
return _carryFlag | _overflowFlag | _interruptFlag | (_negativeResult & 0x80) | (_zeroResult ? 0 : Flag::Zero) | Flag::Always | _decimalFlag; return _carryFlag | _overflowFlag | _interruptFlag | (_negativeResult & 0x80) | (_zeroResult ? 0 : Flag::Zero) | Flag::Always | _decimalFlag;
} }
/*!
Sets the flags register.
@see set_flags
@param flags The new value of the flags register.
*/
void set_flags(uint8_t flags) void set_flags(uint8_t flags)
{ {
_carryFlag = flags & Flag::Carry; _carryFlag = flags & Flag::Carry;
@ -148,6 +202,11 @@ template <class T> class Processor {
_decimalFlag = flags & Flag::Decimal; _decimalFlag = flags & Flag::Decimal;
} }
/*!
Schedules the program corresponding to the specified operation.
@param operation The operation code for which to schedule a program.
*/
void decode_operation(uint8_t operation) void decode_operation(uint8_t operation)
{ {
#define Program(...) {__VA_ARGS__, OperationMoveToNextProgram} #define Program(...) {__VA_ARGS__, OperationMoveToNextProgram}
@ -397,6 +456,11 @@ template <class T> class Processor {
bool _nmi_line_is_enabled; bool _nmi_line_is_enabled;
bool _ready_is_active; bool _ready_is_active;
/*!
Gets the program representing an RST response.
@returns The program representing an RST response.
*/
const MicroOp *get_reset_program() { const MicroOp *get_reset_program() {
static const MicroOp reset[] = { static const MicroOp reset[] = {
CycleFetchOperand, CycleFetchOperand,
@ -411,6 +475,11 @@ template <class T> class Processor {
return reset; return reset;
} }
/*!
Gets the program representing an IRQ response.
@returns The program representing an IRQ response.
*/
const MicroOp *get_irq_program() { const MicroOp *get_irq_program() {
static const MicroOp reset[] = { static const MicroOp reset[] = {
CyclePushPCH, CyclePushPCH,
@ -424,7 +493,7 @@ template <class T> class Processor {
return reset; return reset;
} }
public: protected:
Processor() : Processor() :
_scheduleProgramsReadPointer(0), _scheduleProgramsReadPointer(0),
_scheduleProgramsWritePointer(0), _scheduleProgramsWritePointer(0),
@ -451,6 +520,7 @@ template <class T> class Processor {
schedule_program(get_reset_program()); schedule_program(get_reset_program());
} }
public:
/*! /*!
Runs the 6502 for a supplied number of cycles. Runs the 6502 for a supplied number of cycles.