mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Documents all 6502 micro-operations.
Also makes sure 1-cycle NOPs really, definitely are one cycle only on a 65C02 and eliminates OperationCopyOperandFromA as a redundant copy of OperationSTA.
This commit is contained in:
parent
ddf45a0010
commit
901e0d65b9
@ -104,6 +104,9 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
operation_ == 0xdb
|
||||
) {
|
||||
read_mem(operand_, pc_.full);
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -173,11 +176,11 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case OperationSetFlagsFromX: zero_result_ = negative_result_ = x_; continue;
|
||||
case OperationSetFlagsFromY: zero_result_ = negative_result_ = y_; continue;
|
||||
|
||||
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
|
||||
case CycleReadPCLFromAddress: read_mem(pc_.bytes.low, address_.full); break;
|
||||
case CycleReadPCHFromAddressLowInc: address_.bytes.low++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressFixed: if(!address_.bytes.low) address_.bytes.high++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressInc: address_.full++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
|
||||
case CycleReadPCLFromAddress: read_mem(pc_.bytes.low, address_.full); break;
|
||||
case CycleReadPCHFromAddressLowInc: address_.bytes.low++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressFixed: if(!address_.bytes.low) address_.bytes.high++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressInc: address_.full++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
|
||||
case CycleReadAndIncrementPC: {
|
||||
uint16_t oldPC = pc_.full;
|
||||
@ -204,6 +207,7 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case OperationLDX: x_ = negative_result_ = zero_result_ = operand_; continue;
|
||||
case OperationLDY: y_ = negative_result_ = zero_result_ = operand_; continue;
|
||||
case OperationLAX: a_ = x_ = negative_result_ = zero_result_ = operand_; continue;
|
||||
case OperationCopyOperandToA: a_ = operand_; continue;
|
||||
|
||||
case OperationSTA: operand_ = a_; continue;
|
||||
case OperationSTX: operand_ = x_; continue;
|
||||
@ -516,8 +520,6 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case OperationIncrementPC: pc_.full++; continue;
|
||||
case CycleFetchOperandFromAddress: read_mem(operand_, address_.full); break;
|
||||
case CycleWriteOperandToAddress: write_mem(operand_, address_.full); break;
|
||||
case OperationCopyOperandFromA: operand_ = a_; continue;
|
||||
case OperationCopyOperandToA: a_ = operand_; continue;
|
||||
|
||||
// MARK: - Branching
|
||||
|
||||
|
@ -61,7 +61,7 @@ using namespace CPU::MOS6502;
|
||||
#define IndirectIndexedReadModifyWrite(...) Program(IndirectIndexed, ReadModifyWrite(__VA_ARGS__))
|
||||
|
||||
#define Immediate(op) Program(OperationIncrementPC, op)
|
||||
#define Implied(op) Program(OperationCopyOperandFromA, op, OperationCopyOperandToA)
|
||||
#define Implied(op) Program(OperationSTA, op, OperationCopyOperandToA)
|
||||
|
||||
#define ZeroNop() Program(Zero, CycleFetchOperandFromAddress)
|
||||
#define ZeroXNop() Program(ZeroX, CycleFetchOperandFromAddress)
|
||||
|
@ -23,62 +23,173 @@ class ProcessorStorage {
|
||||
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,
|
||||
CyclePushX, CyclePushY, OperationSetIRQFlags, OperationSetNMIRSTFlags,
|
||||
CycleFetchOperation, // fetches (PC) to operation_, storing PC to last_operation_pc_ before incrementing it
|
||||
CycleFetchOperand, // 6502: fetches from (PC) to operand_; 65C02: as 6502 unless operation_ indicates a one-cycle NOP, in which case this is a no0op
|
||||
OperationDecodeOperation, // schedules the microprogram associated with operation_
|
||||
OperationMoveToNextProgram, // either schedules the next fetch-decode-execute or an interrupt response if a request has been pending for at least one cycle
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
CycleIncPCPushPCH, // increments the PC and pushes PC.h to the stack
|
||||
CyclePushPCL, // pushes PC.l to the stack
|
||||
CyclePushPCH, // pushes PC.h to the stack
|
||||
CyclePushA, // pushes A to the stack
|
||||
CyclePushX, // pushes X to the stack
|
||||
CyclePushY, // pushes Y to the stack
|
||||
CyclePushOperand, // pushes operand_ to the stack
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CyclePullX, CyclePullY,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL,
|
||||
OperationSetIRQFlags, // 6502: sets I; 65C02: sets I and resets D
|
||||
OperationSetNMIRSTFlags, // 6502: no-op. 65C02: resets D
|
||||
|
||||
CycleReadPCLFromAddress, CycleReadPCHFromAddressLowInc, CycleReadPCHFromAddressFixed, CycleReadPCHFromAddressInc,
|
||||
OperationBRKPickVector, // 65C02: sets next_address_ to the BRK vector location; 6502: as 65C02 if no NMI is pending; otherwise sets next_address_ to the NMI address and resets the internal NMI-pending flag
|
||||
OperationNMIPickVector, // sets next_address_ to the NMI vector
|
||||
OperationRSTPickVector, // sets next_address_ to the RST vector
|
||||
CycleReadVectorLow, // reads PC.l from next_address_
|
||||
CycleReadVectorHigh, // reads PC.h from (next_address_+1)
|
||||
|
||||
CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead,
|
||||
OperationMoveToNextProgram, OperationIncrementPC,
|
||||
CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA,
|
||||
CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand,
|
||||
CycleFetchAddressLowFromOperand,
|
||||
OperationIncrementOperand, OperationORA, OperationAND, OperationEOR,
|
||||
OperationINS, OperationADC, OperationSBC, OperationLDA,
|
||||
OperationLDX, OperationLDY, OperationLAX, OperationSTA,
|
||||
OperationSTX, OperationSTY, OperationSTZ,
|
||||
OperationSAX, OperationSHA,
|
||||
OperationSHX, OperationSHY, OperationSHS, OperationCMP,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationBITNoNV,
|
||||
OperationASL, OperationRMB, OperationSMB,
|
||||
OperationASO, OperationROL, OperationRLA, OperationLSR,
|
||||
OperationLSE, OperationASR, OperationROR, OperationRRA,
|
||||
OperationCLC, OperationCLI, OperationCLV, OperationCLD,
|
||||
OperationSEC, OperationSEI, OperationSED,
|
||||
OperationTRB, OperationTSB,
|
||||
CycleReadFromS, // performs a read from the stack pointer, throwing the result away
|
||||
CycleReadFromPC, // performs a read from the program counter, throwing the result away
|
||||
|
||||
OperationINC, OperationDEC, OperationINX, OperationDEX,
|
||||
OperationINY, OperationDEY, OperationINA, OperationDEA,
|
||||
CyclePullPCL, // pulls PC.l from the stack
|
||||
CyclePullPCH, // pulls PC.h from the stack
|
||||
CyclePullA, // pulls A from the stack
|
||||
CyclePullX, // pulls X from the stack
|
||||
CyclePullY, // pulls Y from the stack
|
||||
CyclePullOperand, // pulls operand_ from the stack
|
||||
|
||||
OperationBPL, OperationBMI, OperationBVC, OperationBVS,
|
||||
OperationBCC, OperationBCS, OperationBNE, OperationBEQ,
|
||||
OperationBRA, OperationBBRBBS,
|
||||
CycleNoWritePush, // decrements S as though it were a push, but reads from the new stack address instead of writing
|
||||
CycleReadAndIncrementPC, // reads from the PC, throwing away the result, and increments the PC
|
||||
CycleIncrementPCAndReadStack, // increments the PC and reads from the stack pointer, throwing away the result
|
||||
CycleIncrementPCReadPCHLoadPCL, // increments the PC, schedules a read of PC.h from the post-incremented PC, then copies operand_ to PC.l
|
||||
CycleReadPCHLoadPCL, // schedules a read of PC.h from the post-incremented PC, then copies operand_ to PC.l
|
||||
CycleReadAddressHLoadAddressL, // increments the PC; copies operand_ to address_.l; reads address_.h from the new PC
|
||||
|
||||
OperationTXA, OperationTYA, OperationTXS, OperationTAY,
|
||||
OperationTAX, OperationTSX,
|
||||
CycleReadPCLFromAddress, // reads PC.l from address_
|
||||
CycleReadPCHFromAddressLowInc, // increments address_.l and reads PC.h from address_
|
||||
CycleReadPCHFromAddressFixed, // if address_.l is 0, increments address_.h; and reads PC.h from address_
|
||||
CycleReadPCHFromAddressInc, // increments address_ and reads PC.h from it
|
||||
|
||||
OperationARR, OperationSBX, OperationLXA, OperationANE,
|
||||
OperationANC, OperationLAS,
|
||||
CycleLoadAddressAbsolute, // copies operand_ to address_.l, increments the PC, reads address_.h from PC, increments the PC again
|
||||
OperationLoadAddressZeroPage, // copies operand_ to address_ and increments the PC
|
||||
CycleLoadAddessZeroX, // copies (operand_+x)&0xff to address_, increments the PC, and reads from operand_, throwing away the result
|
||||
CycleLoadAddessZeroY, // copies (operand_+y)&0xff to address_, increments the PC, and reads from operand_, throwing away the result
|
||||
|
||||
CycleFetchFromHalfUpdatedPC, CycleAddSignedOperandToPC, OperationAddSignedOperandToPC16,
|
||||
CycleAddXToAddressLow, // calculates address_ + x and stores it to next_address_; copies next_address_.l back to address_.l; if address_ now does not equal next_address_, schedules a throwaway read from address_
|
||||
CycleAddYToAddressLow, // calculates address_ + y and stores it to next_address_; copies next_address_.l back to address_.l; if address_ now does not equal next_address_, schedules a throwaway read from address_
|
||||
CycleAddXToAddressLowRead, // calculates address_ + x and stores it to next_address; copies next_address.l back to address_.l; schedules a throwaway read from address_
|
||||
CycleAddYToAddressLowRead, // calculates address_ + y and stores it to next_address; copies next_address.l back to address_.l; schedules a throwaway read from address_
|
||||
OperationCorrectAddressHigh, // copies next_address_ to address_
|
||||
|
||||
OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA, OperationSetFlagsFromX, OperationSetFlagsFromY,
|
||||
CycleScheduleJam
|
||||
OperationIncrementPC, // increments the PC
|
||||
CycleFetchOperandFromAddress, // fetches operand_ from address_
|
||||
CycleWriteOperandToAddress, // writes operand_ to address_
|
||||
|
||||
CycleIncrementPCFetchAddressLowFromOperand, // increments the PC and loads address_.l from (operand_)
|
||||
CycleAddXToOperandFetchAddressLow, // adds x [in]to operand_, producing an 8-bit result, and reads address_.l from (operand_)
|
||||
CycleIncrementOperandFetchAddressHigh, // increments operand_, producing an 8-bit result, and reads address_.h from (operand_)
|
||||
OperationDecrementOperand, // decrements operand_
|
||||
OperationIncrementOperand, // increments operand_
|
||||
CycleFetchAddressLowFromOperand, // reads address_.l from (operand_)
|
||||
|
||||
OperationORA, // ORs operand_ into a, setting the negative and zero flags
|
||||
OperationAND, // ANDs operand_ into a, setting the negative and zero flags
|
||||
OperationEOR, // EORs operand_ into a, setting the negative and zero flags
|
||||
|
||||
OperationINS, // increments operand_, then performs an SBC of operand_ from a
|
||||
OperationADC, // performs an ADC of operand_ into a_; if this is a 65C02 and decimal mode is set, performs an extra read to operand_ from address_
|
||||
OperationSBC, // performs an SBC of operand_ from a_; if this is a 65C02 and decimal mode is set, performs an extra read to operand_ from address_
|
||||
|
||||
OperationCMP, // CMPs a and operand_, setting negative, zero and carry flags
|
||||
OperationCPX, // CMPs x and operand_, setting negative, zero and carry flags
|
||||
OperationCPY, // CMPs y and operand_, setting negative, zero and carry flags
|
||||
OperationBIT, // sets the zero, negative and overflow flags as per a BIT of operand_ against a
|
||||
OperationBITNoNV, // sets the zero flag as per a BIT of operand_ against a
|
||||
|
||||
OperationLDA, // loads a with operand_, setting the negative and zero flags
|
||||
OperationLDX, // loads x with operand_, setting the negative and zero flags
|
||||
OperationLDY, // loads y with operand_, setting the negative and zero flags
|
||||
OperationLAX, // loads a and x with operand_, setting the negative and zero flags
|
||||
OperationCopyOperandToA, // sets a_ = operand_, not setting any flags
|
||||
|
||||
OperationSTA, // loads operand_ with a
|
||||
OperationSTX, // loads operand_ with x
|
||||
OperationSTY, // loads operand_ with y
|
||||
OperationSTZ, // loads operand_ with 0
|
||||
OperationSAX, // loads operand_ with a & x
|
||||
OperationSHA, // loads operand_ with a & x & (address.h+1)
|
||||
OperationSHX, // loads operand_ with x & (address.h+1)
|
||||
OperationSHY, // loads operand_ with y & (address.h+1)
|
||||
OperationSHS, // loads s with a & x, then loads operand_ with s & (address.h+1)
|
||||
|
||||
OperationASL, // shifts operand_ left, moving the top bit into carry and setting the negative and zero flags
|
||||
OperationASO, // performs an ASL of operand and ORs it into a
|
||||
OperationROL, // performs a ROL of operand_
|
||||
OperationRLA, // performs a ROL of operand_ and ANDs it into a
|
||||
OperationLSR, // shifts operand_ right, setting carry, negative and zero flags
|
||||
OperationLSE, // performs an LSR and EORs the result into a
|
||||
OperationASR, // ANDs operand_ into a, then performs an LSR
|
||||
OperationROR, // performs a ROR of operand_, setting carry, negative and zero flags
|
||||
OperationRRA, // performs a ROR of operand_ but sets only the carry flag
|
||||
|
||||
OperationCLC, // resets the carry flag
|
||||
OperationCLI, // resets I
|
||||
OperationCLV, // resets the overflow flag
|
||||
OperationCLD, // resets the decimal flag
|
||||
OperationSEC, // sets the carry flag
|
||||
OperationSEI, // sets I
|
||||
OperationSED, // sets the decimal flag
|
||||
|
||||
OperationRMB, // resets the bit in operand_ implied by operatiopn_
|
||||
OperationSMB, // sets the bit in operand_ implied by operatiopn_
|
||||
OperationTRB, // sets zero according to operand_ & a, then resets any bits in operand_ that are set in a
|
||||
OperationTSB, // sets zero according to operand_ & a, then sets any bits in operand_ that are set in a
|
||||
|
||||
OperationINC, // increments operand_, setting the negative and zero flags
|
||||
OperationDEC, // decrements operand_, setting the negative and zero flags
|
||||
OperationINX, // increments x, setting the negative and zero flags
|
||||
OperationDEX, // decrements x, setting the negative and zero flags
|
||||
OperationINY, // increments y, setting the negative and zero flags
|
||||
OperationDEY, // decrements y, setting the negative and zero flags
|
||||
OperationINA, // increments a, setting the negative and zero flags
|
||||
OperationDEA, // decrements a, setting the negative and zero flags
|
||||
|
||||
OperationBPL, // schedules the branch program if the negative flag is clear
|
||||
OperationBMI, // schedules the branch program if the negative flag is set
|
||||
OperationBVC, // schedules the branch program if the overflow flag is clear
|
||||
OperationBVS, // schedules the branch program if the overflow flag is set
|
||||
OperationBCC, // schedules the branch program if the carry flag is clear
|
||||
OperationBCS, // schedules the branch program if the carry flag is set
|
||||
OperationBNE, // schedules the branch program if the zero flag is clear
|
||||
OperationBEQ, // schedules the branch program if the zero flag is set
|
||||
OperationBRA, // schedules the branch program
|
||||
|
||||
OperationBBRBBS, // inspecting the operation_, if the appropriate bit of operand_ is set or clear schedules a program to read and act upon the second operand; otherwise schedule a program to read and discard it
|
||||
|
||||
OperationTXA, // copies x to a, setting the zero and negative flags
|
||||
OperationTYA, // copies y to a, setting the zero and negative flags
|
||||
OperationTXS, // copies x to s
|
||||
OperationTAY, // copies a to y, setting the zero and negative flags
|
||||
OperationTAX, // copies a to x, setting the zero and negative flags
|
||||
OperationTSX, // copies s to x, setting the zero and negative flags
|
||||
|
||||
/* The following are amongst the 6502's undocumented (/unintended) operations */
|
||||
OperationARR, // performs a mixture of ANDing operand_ into a, and shifting the result right
|
||||
OperationSBX, // performs a mixture of an SBC of x&a and operand_, mutating x
|
||||
OperationLXA, // loads a and x with (a | 0xee) & operand, setting the negative and zero flags
|
||||
OperationANE, // loads a_ with (a | 0xee) & operand & x, setting the negative and zero flags
|
||||
OperationANC, // ANDs operand_ into a, setting the negative and zero flags, and loading carry as if the result were shifted right
|
||||
OperationLAS, // loads a, x and s with s & operand, setting the negative and zero flags
|
||||
|
||||
CycleFetchFromHalfUpdatedPC, // performs a throwaway read from (PC + (signed)operand).l combined with PC.h
|
||||
CycleAddSignedOperandToPC, // sets next_address to PC + (signed)operand. If the high byte of next_address differs from the PC, schedules a throwaway read from the half-updated PC
|
||||
OperationAddSignedOperandToPC16, // adds (signed)operand into the PC
|
||||
|
||||
OperationSetFlagsFromOperand, // sets all flags based on operand_
|
||||
OperationSetOperandFromFlagsWithBRKSet, // sets operand_ to the value of all flags, with the break flag set
|
||||
OperationSetOperandFromFlags, // sets operand_ to the value of all flags
|
||||
|
||||
OperationSetFlagsFromA, // sets the zero and negative flags based on the value of a
|
||||
OperationSetFlagsFromX, // sets the zero and negative flags based on the value of x
|
||||
OperationSetFlagsFromY, // sets the zero and negative flags based on the value of y
|
||||
CycleScheduleJam // schedules the program for operation F2
|
||||
};
|
||||
|
||||
using InstructionList = MicroOp[10];
|
||||
|
Loading…
x
Reference in New Issue
Block a user