200 lines
9.0 KiB
C++
200 lines
9.0 KiB
C++
/*
|
|
* This file is part of the 65816 Emulator Library.
|
|
* Copyright (c) 2018 Francesco Rigoni.
|
|
*
|
|
* https://github.com/FrancescoRigoni/Lib65816
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Cpu65816Debugger.hpp"
|
|
#include "Cpu65816.hpp"
|
|
|
|
#define LOG_TAG "Cpu65816Debugger"
|
|
|
|
Cpu65816Debugger::Cpu65816Debugger(Cpu65816 &cpu) : mCpu(cpu) {
|
|
cpu.setRESPin(false);
|
|
|
|
Log::dbg(LOG_TAG).str("Cpu is ready to run").show();
|
|
Log::dbg(LOG_TAG).str("Emulation mode RST vector at").sp().hex(mCpu.mEmulationInterrupts->reset, 4).show();
|
|
Log::dbg(LOG_TAG).str("Native mode BRK vector at").sp().hex(mCpu.mNativeInterrupts->brk, 4).show();
|
|
Log::dbg(LOG_TAG).str("Native mode VSYNC vector at").sp().hex(mCpu.mNativeInterrupts->nonMaskableInterrupt, 4).show();
|
|
}
|
|
|
|
void Cpu65816Debugger::step() {
|
|
if (mBreakpointHit) return;
|
|
|
|
mOnBeforeStepHandler();
|
|
const uint8_t instruction = mCpu.mSystemBus.readByte(mCpu.mProgramAddress);
|
|
OpCode opCode = mCpu.OP_CODE_TABLE[instruction];
|
|
logOpCode(opCode);
|
|
|
|
mCpu.executeNextInstruction();
|
|
|
|
mOnAfterStepHandler();
|
|
|
|
if (mCpu.mProgramAddress.getBank() == mBreakPointAddress.getBank() &&
|
|
mCpu.mProgramAddress.getOffset() == mBreakPointAddress.getOffset()) {
|
|
mBreakpointHit = true;
|
|
Log::dbg(LOG_TAG).str("BREAKPOINT").sp()
|
|
.hex(mBreakPointAddress.getBank(), 2).hex(mBreakPointAddress.getOffset(), 4).show();
|
|
mOnBreakPointHandler();
|
|
}
|
|
}
|
|
|
|
void Cpu65816Debugger::doBeforeStep(const std::function<void ()> handler) {
|
|
mOnBeforeStepHandler = handler;
|
|
}
|
|
|
|
void Cpu65816Debugger::doAfterStep(const std::function<void ()> handler) {
|
|
mOnAfterStepHandler = handler;
|
|
}
|
|
|
|
void Cpu65816Debugger::onBreakPoint(const std::function<void ()> handler) {
|
|
mOnBreakPointHandler = handler;
|
|
}
|
|
|
|
void Cpu65816Debugger::setBreakPoint(const Address &address) {
|
|
mBreakPointAddress = address;
|
|
}
|
|
|
|
void Cpu65816Debugger::logStatusRegister() const {
|
|
Log::trc(LOG_TAG).str("P (Status): ").hex(mCpu.mCpuStatus.getRegisterValue(), 2).show();
|
|
}
|
|
|
|
void Cpu65816Debugger::dumpCpu() const {
|
|
Log::trc(LOG_TAG).str("====== CPU status start ======").show();
|
|
Log::trc(LOG_TAG).str("A: ").hex(mCpu.mA, 4).sp().str("X: ").hex(mCpu.mX, 4).sp().str("Y: ").hex(mCpu.mY, 4).show();
|
|
Log::trc(LOG_TAG).str("PB: ").hex(mCpu.mProgramAddress.getBank(), 2).sp().str("PC: ").hex(mCpu.mProgramAddress.getOffset(), 4).show();
|
|
Log::trc(LOG_TAG).str("DB: ").hex(mCpu.mDB, 2).sp().str("D: ").hex(mCpu.mD, 4).show();
|
|
Log::trc(LOG_TAG).str("S (Stack pointer): ").hex(mCpu.mStack.getStackPointer(), 4).show();
|
|
logStatusRegister();
|
|
Log::trc(LOG_TAG).str("====== CPU status end ======").show();
|
|
}
|
|
|
|
void Cpu65816Debugger::logOpCode(OpCode &opCode) const {
|
|
Address onePlusOpCodeAddress = mCpu.mProgramAddress.newWithOffset(1);
|
|
|
|
Log &log = Log::trc(LOG_TAG);
|
|
log.hex(mCpu.mProgramAddress.getBank(), 2).str(":").hex(mCpu.mProgramAddress.getOffset(), 4);
|
|
log.str(" | ").hex(opCode.getCode(), 2).sp().str(opCode.getName()).sp();
|
|
|
|
switch(opCode.getAddressingMode()) {
|
|
case AddressingMode::Interrupt:
|
|
case AddressingMode::Accumulator:
|
|
case AddressingMode::Implied:
|
|
break;
|
|
case AddressingMode::Immediate:
|
|
// This refers to accumulator size to estimate the kind of value to print.
|
|
// Instructions using index registers might print the wrong value.
|
|
if (mCpu.accumulatorIs8BitWide()) {
|
|
log.str("#").hex(mCpu.mSystemBus.readByte(mCpu.getAddressOfOpCodeData(opCode)), 2);
|
|
} else {
|
|
log.str("#").hex(mCpu.mSystemBus.readTwoBytes(mCpu.getAddressOfOpCodeData(opCode)), 4);
|
|
}
|
|
break;
|
|
case AddressingMode::Absolute:
|
|
log.hex(mCpu.getAddressOfOpCodeData(opCode).getOffset(), 4).sp();
|
|
log.str(" [Absolute]");
|
|
break;
|
|
case AddressingMode::AbsoluteLong:
|
|
{
|
|
Address opCodeDataAddress = mCpu.getAddressOfOpCodeData(opCode);
|
|
log.hex(opCodeDataAddress.getBank(), 2).str(":").hex(opCodeDataAddress.getOffset(), 4).sp();
|
|
log.str(" [Absolute Long]");
|
|
}
|
|
break;
|
|
case AddressingMode::AbsoluteIndirect:
|
|
break;
|
|
case AddressingMode::AbsoluteIndirectLong:
|
|
break;
|
|
case AddressingMode::AbsoluteIndexedIndirectWithX:
|
|
break;
|
|
case AddressingMode::AbsoluteIndexedWithX:
|
|
log.hex(mCpu.mSystemBus.readTwoBytes(onePlusOpCodeAddress), 4).str(", X").sp();
|
|
log.str(" [Absolute Indexed, X]");
|
|
break;
|
|
case AddressingMode::AbsoluteLongIndexedWithX:
|
|
{
|
|
Address opCodeDataAddress = mCpu.getAddressOfOpCodeData(opCode);
|
|
Address effectiveAddress = mCpu.mSystemBus.readAddressAt(opCodeDataAddress);
|
|
log.hex(effectiveAddress.getBank(), 2).str(":").hex(effectiveAddress.getOffset(), 4).str(", X").sp();
|
|
log.str(" [Absolute Long Indexed, X]");
|
|
}
|
|
break;
|
|
case AddressingMode::AbsoluteIndexedWithY:
|
|
log.hex(mCpu.mSystemBus.readTwoBytes(mCpu.getAddressOfOpCodeData(opCode)), 4).str(", Y").sp();
|
|
log.str(" [Absolute Indexed, Y]");
|
|
break;
|
|
case AddressingMode::DirectPage:
|
|
log.hex(mCpu.mSystemBus.readByte(onePlusOpCodeAddress), 2).sp();
|
|
log.str(" [Direct Page]");
|
|
break;
|
|
case AddressingMode::DirectPageIndexedWithX:
|
|
log.hex(mCpu.mSystemBus.readByte(onePlusOpCodeAddress), 2).str(", X").sp();
|
|
log.str(" [Direct Page Indexed, X]");
|
|
break;
|
|
case AddressingMode::DirectPageIndexedWithY:
|
|
log.hex(mCpu.mSystemBus.readByte(onePlusOpCodeAddress), 2).str(", Y").sp();
|
|
log.str(" [Direct Page Indexed, Y]");
|
|
break;
|
|
case AddressingMode::DirectPageIndirect:
|
|
log.str("(").hex(mCpu.mSystemBus.readByte(onePlusOpCodeAddress), 2).str(")").sp();
|
|
log.str(" [Direct Page Indirect]");
|
|
break;
|
|
case AddressingMode::DirectPageIndirectLong:
|
|
log.str("[").hex(mCpu.mSystemBus.readByte(mCpu.getAddressOfOpCodeData(opCode)), 2).str("]").sp();
|
|
log.str(" [Direct Page Indirect Long]");
|
|
break;
|
|
case AddressingMode::DirectPageIndexedIndirectWithX:
|
|
log.str("(").hex(mCpu.mSystemBus.readByte(Address(mCpu.mProgramAddress.getBank(),mCpu.mProgramAddress.getOffset()+1)), 2).str(", X)").sp();
|
|
log.str(" [Direct Page Indexed Indirect, X]");
|
|
break;
|
|
case AddressingMode::DirectPageIndirectIndexedWithY:
|
|
log.str("(").hex(mCpu.mSystemBus.readByte(Address(mCpu.mProgramAddress.getBank(),mCpu.mProgramAddress.getOffset()+1)), 2).str("), Y").sp();
|
|
log.str(" [Direct Page Indirect Indexed, Y]");
|
|
break;
|
|
case AddressingMode::DirectPageIndirectLongIndexedWithY:
|
|
log.str("[").hex(mCpu.mSystemBus.readByte(mCpu.getAddressOfOpCodeData(opCode)), 2).str("], Y").sp();
|
|
log.str(" [Direct Page Indirect Indexed, Y]");
|
|
break;
|
|
case AddressingMode::StackImplied:
|
|
log.str(" [Stack Implied]");
|
|
break;
|
|
case AddressingMode::StackRelative:
|
|
log.hex(mCpu.mSystemBus.readByte(mCpu.getAddressOfOpCodeData(opCode)), 2).str(", S").sp();
|
|
log.str(" [Stack Relative]");
|
|
break;
|
|
case AddressingMode::StackAbsolute:
|
|
break;
|
|
case AddressingMode::StackDirectPageIndirect:
|
|
break;
|
|
case AddressingMode::StackProgramCounterRelativeLong:
|
|
break;
|
|
case AddressingMode::StackRelativeIndirectIndexedWithY:
|
|
log.str("(").hex(mCpu.mSystemBus.readByte(Address::sumOffsetToAddressWrapAround(mCpu.mProgramAddress, 1)), 2);
|
|
log.str(", S), Y").sp();
|
|
log.str(" [Absolute Indexed, X]");
|
|
break;
|
|
case AddressingMode::ProgramCounterRelative:
|
|
log.hex(mCpu.mSystemBus.readByte(mCpu.getAddressOfOpCodeData(opCode)), 2).sp();
|
|
log.str(" [Program Counter Relative]");
|
|
break;
|
|
case AddressingMode::ProgramCounterRelativeLong:
|
|
break;
|
|
case AddressingMode::BlockMove:
|
|
break;
|
|
}
|
|
|
|
log.show();
|
|
} |