/* * 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 . */ #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 handler) { mOnBeforeStepHandler = handler; } void Cpu65816Debugger::doAfterStep(const std::function handler) { mOnAfterStepHandler = handler; } void Cpu65816Debugger::onBreakPoint(const std::function 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(mCpu.getAddressOfOpCodeData(opCode)), 2).str(", X)").sp(); log.str(" [Direct Page Indexed Indirect, X]"); break; case AddressingMode::DirectPageIndirectIndexedWithY: log.str("(").hex(mCpu.mSystemBus.readByte(mCpu.getAddressOfOpCodeData(opCode)), 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(); }