1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +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:
Thomas Harte 2018-08-14 22:17:53 -04:00
parent ddf45a0010
commit 901e0d65b9
3 changed files with 167 additions and 54 deletions

View File

@ -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

View File

@ -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)

View File

@ -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];