1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 01:32:55 +00:00

Merge pull request #1388 from TomHarte/6502BBSBBR

Correct 65c02 BBS/BBR bus activity.
This commit is contained in:
Thomas Harte 2024-07-05 14:51:31 -04:00 committed by GitHub
commit 94058d498c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 16 deletions

View File

@ -708,12 +708,23 @@ void Processor<personality, T, uses_ready_line>::run_for(const Cycles cycles) {
continue; continue;
case CycleFetchFromHalfUpdatedPC: { case CycleFetchFromHalfUpdatedPC: {
uint16_t halfUpdatedPc = uint16_t(((pc_.halves.low + int8_t(operand_)) & 0xff) | (pc_.halves.high << 8)); uint16_t half_updated_pc = uint16_t(((pc_.halves.low + int8_t(operand_)) & 0xff) | (pc_.halves.high << 8));
throwaway_read(halfUpdatedPc); throwaway_read(half_updated_pc);
} break; } break;
case CycleFetchFromNextAddress:
throwaway_read(next_address_.full);
break;
case OperationAddSignedOperandToPC16: case OperationAddSignedOperandToPC16:
next_address_ = pc_.full;
pc_.full = uint16_t(pc_.full + int8_t(operand_)); 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; continue;
case OperationBBRBBS: { case OperationBBRBBS: {
@ -725,7 +736,7 @@ void Processor<personality, T, uses_ready_line>::run_for(const Cycles cycles) {
} else { } else {
scheduled_program_counter_ = operations_[size_t(OperationsSlot::DoNotBBRBBS)]; scheduled_program_counter_ = operations_[size_t(OperationsSlot::DoNotBBRBBS)];
} }
} break; } continue;
// MARK: - Transfers // MARK: - Transfers

View File

@ -269,18 +269,35 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
/* 0x105: Do BBR or BBS. */ /* 0x105: Do BBR or BBS. */
Program( Program(
CycleFetchOperand, // Fetch offset. CycleFetchOperand, // Fetch offset, and increment PC.
OperationIncrementPC, 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. */ /* 0x106: Complete BBR or BBS without branching. */
Program( Program(
CycleFetchOperand, CycleFetchOperand, // Fetch offset.
OperationIncrementPC, OperationIncrementPC
CycleFetchFromHalfUpdatedPC
) )
// 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_)); static_assert(sizeof(operations_6502) == sizeof(operations_));
@ -408,15 +425,25 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
// 0xc7, 0xcb, 0xcf, 0xd7, 0xdb, 0xdf, // 0xc7, 0xcb, 0xcf, 0xd7, 0xdb, 0xdf,
// 0xe7, 0xef, 0xf7, 0xff // 0xe7, 0xef, 0xf7, 0xff
if(has_bbrbbsrmbsmb(personality)) { 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 // 1. read opcode
// 2. read operand // 2. read first operand (i.e. zero-page address)
// 3. read zero page // 3. read zero page
// 4. read second operand // 4. reread zero page (presumably as a stall, to make a decision on the above)
// 5. read from PC without top byte fixed yet // 5. read second operand (i.e. branch offset)
// ... with the caveat that (3) and (4) could be the other way around. //
// ... 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) { 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. // Add RMB and SMB.

View File

@ -186,7 +186,9 @@ class ProcessorStorage {
CycleFetchFromHalfUpdatedPC, // performs a throwaway read from (PC + (signed)operand).l combined with PC.h 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. 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_ OperationSetFlagsFromOperand, // sets all flags based on operand_
OperationSetOperandFromFlagsWithBRKSet, // sets operand_ to the value of all flags, with the break flag set OperationSetOperandFromFlagsWithBRKSet, // sets operand_ to the value of all flags, with the break flag set