mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-21 21:33:54 +00:00
Merge pull request #1388 from TomHarte/6502BBSBBR
Correct 65c02 BBS/BBR bus activity.
This commit is contained in:
commit
94058d498c
@ -708,12 +708,23 @@ void Processor<personality, T, uses_ready_line>::run_for(const Cycles cycles) {
|
||||
continue;
|
||||
|
||||
case CycleFetchFromHalfUpdatedPC: {
|
||||
uint16_t halfUpdatedPc = uint16_t(((pc_.halves.low + int8_t(operand_)) & 0xff) | (pc_.halves.high << 8));
|
||||
throwaway_read(halfUpdatedPc);
|
||||
uint16_t half_updated_pc = uint16_t(((pc_.halves.low + int8_t(operand_)) & 0xff) | (pc_.halves.high << 8));
|
||||
throwaway_read(half_updated_pc);
|
||||
} break;
|
||||
|
||||
case CycleFetchFromNextAddress:
|
||||
throwaway_read(next_address_.full);
|
||||
break;
|
||||
|
||||
case OperationAddSignedOperandToPC16:
|
||||
next_address_ = pc_.full;
|
||||
pc_.full = uint16_t(pc_.full + int8_t(operand_));
|
||||
|
||||
// Skip a step if 8-bit arithmetic would have been sufficient;
|
||||
// in practise this operation is used only by BBS/BBR.
|
||||
if(pc_.halves.high == next_address_.halves.high) {
|
||||
++scheduled_program_counter_;
|
||||
}
|
||||
continue;
|
||||
|
||||
case OperationBBRBBS: {
|
||||
@ -725,7 +736,7 @@ void Processor<personality, T, uses_ready_line>::run_for(const Cycles cycles) {
|
||||
} else {
|
||||
scheduled_program_counter_ = operations_[size_t(OperationsSlot::DoNotBBRBBS)];
|
||||
}
|
||||
} break;
|
||||
} continue;
|
||||
|
||||
// MARK: - Transfers
|
||||
|
||||
|
@ -269,18 +269,35 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
|
||||
/* 0x105: Do BBR or BBS. */
|
||||
Program(
|
||||
CycleFetchOperand, // Fetch offset.
|
||||
CycleFetchOperand, // Fetch offset, and increment PC.
|
||||
OperationIncrementPC,
|
||||
CycleFetchFromHalfUpdatedPC,
|
||||
OperationAddSignedOperandToPC16
|
||||
|
||||
OperationAddSignedOperandToPC16, // Calculate target PC, leaving old PC in next_address_
|
||||
// and possibly skipping the next instruction.
|
||||
|
||||
CycleFetchFromNextAddress,
|
||||
CycleFetchFromNextAddress
|
||||
),
|
||||
// Six or seven cycles total are:
|
||||
// (1) operation;
|
||||
// (2) zero page address as operand;
|
||||
// (3) zero page address;
|
||||
// (4) duplicate of (3);
|
||||
// (5) further operand;
|
||||
// (6) read from next PC;
|
||||
// (7) repeat read from next PC if 16-bit arithmetic was required.
|
||||
|
||||
/* 0x106: Complete BBR or BBS without branching. */
|
||||
Program(
|
||||
CycleFetchOperand,
|
||||
OperationIncrementPC,
|
||||
CycleFetchFromHalfUpdatedPC
|
||||
CycleFetchOperand, // Fetch offset.
|
||||
OperationIncrementPC
|
||||
)
|
||||
// Five cycles total are:
|
||||
// (1) operation;
|
||||
// (2) zero page address as operand;
|
||||
// (3) zero page address;
|
||||
// (4) duplicate of (3);
|
||||
// (5) further operand, which goes unused.
|
||||
};
|
||||
|
||||
static_assert(sizeof(operations_6502) == sizeof(operations_));
|
||||
@ -408,15 +425,25 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
// 0xc7, 0xcb, 0xcf, 0xd7, 0xdb, 0xdf,
|
||||
// 0xe7, 0xef, 0xf7, 0xff
|
||||
if(has_bbrbbsrmbsmb(personality)) {
|
||||
// Add BBS and BBR. These take five cycles. My guessed breakdown is:
|
||||
// Add BBS and BBR. These take five, six or seven cycles. First five:
|
||||
// 1. read opcode
|
||||
// 2. read operand
|
||||
// 2. read first operand (i.e. zero-page address)
|
||||
// 3. read zero page
|
||||
// 4. read second operand
|
||||
// 5. read from PC without top byte fixed yet
|
||||
// ... with the caveat that (3) and (4) could be the other way around.
|
||||
// 4. reread zero page (presumably as a stall, to make a decision on the above)
|
||||
// 5. read second operand (i.e. branch offset)
|
||||
//
|
||||
// ... and then, if the branch is taken:
|
||||
//
|
||||
// 6. read from where next instruction would have been
|
||||
// 7. reread, if a further stall is necessary to cover up for a 16-bit address change.
|
||||
for(int location = 0x0f; location <= 0xff; location += 0x10) {
|
||||
Install(location, Program(OperationLoadAddressZeroPage, CycleFetchOperandFromAddress, OperationBBRBBS));
|
||||
Install(location, Program(
|
||||
OperationLoadAddressZeroPage,
|
||||
CycleFetchOperandFromAddress, // (cycle 3)
|
||||
CycleFetchOperandFromAddress, // (cycle 4)
|
||||
OperationBBRBBS // Branches to either OperationsSlot::DoBBRBBS, or to
|
||||
// OperationSlot::DoNotBBRBBS, depending on data read.
|
||||
));
|
||||
}
|
||||
|
||||
// Add RMB and SMB.
|
||||
|
@ -186,7 +186,9 @@ class ProcessorStorage {
|
||||
|
||||
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. 65C02 specific: if the top two bytes are the same, proceeds directly to fetch-decode-execute, ignoring any pending interrupts.
|
||||
OperationAddSignedOperandToPC16, // adds (signed)operand into the PC
|
||||
OperationAddSignedOperandToPC16, // adds (signed)operand into the PC, leaving old PC in next_address_ and skipping a program step if there was no carry from low to high byte
|
||||
|
||||
CycleFetchFromNextAddress, // performs a throwaway fetch from next_address_
|
||||
|
||||
OperationSetFlagsFromOperand, // sets all flags based on operand_
|
||||
OperationSetOperandFromFlagsWithBRKSet, // sets operand_ to the value of all flags, with the break flag set
|
||||
|
Loading…
Reference in New Issue
Block a user