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:
parent
9fa35dd559
commit
baef1ccd57
@ -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.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user