diff options
Diffstat (limited to 'src/progs/icd2/base/icd2_debug.cpp')
-rw-r--r-- | src/progs/icd2/base/icd2_debug.cpp | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/progs/icd2/base/icd2_debug.cpp b/src/progs/icd2/base/icd2_debug.cpp new file mode 100644 index 0000000..62f6404 --- /dev/null +++ b/src/progs/icd2/base/icd2_debug.cpp @@ -0,0 +1,348 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "icd2_debug.h" + +#include "common/global/pfile.h" +#include "progs/base/prog_config.h" +#include "devices/pic/base/pic_register.h" +#include "devices/pic/pic/pic_group.h" +#include "icd2_data.h" +#include "icd2_debug_specific.h" + +//----------------------------------------------------------------------------- +Icd2::DebuggerSpecific *Icd2::Debugger::specific() { return static_cast<Icd2::DebuggerSpecific *>(_specific); } + +bool Icd2::Debugger::waitForTargetMode(Pic::TargetMode mode) +{ + Pic::TargetMode rmode; + for (uint i=0; i<20; i++) { + if ( !programmer().getTargetMode(rmode) ) return false; + if ( rmode==mode ) return true; + Port::msleep(200); + } + log(Log::LineType::Error, QString("Timeout waiting for mode: %1 (target is in mode: %2).") + .arg(i18n(Pic::TARGET_MODE_LABELS[mode])).arg(i18n(Pic::TARGET_MODE_LABELS[rmode]))); + return false; +} + +bool Icd2::Debugger::init(bool last) +{ + _initLast = last; + return ::Debugger::PicBase::init(); +} + +bool Icd2::Debugger::internalInit() +{ + return specific()->init(_initLast); +} + +bool Icd2::Debugger::updateState() +{ + Pic::TargetMode mode; + if ( !programmer().getTargetMode(mode) ) return false; + switch (mode) { + case Pic::TargetStopped: _programmer.setState(::Programmer::Halted); break; + case Pic::TargetRunning: _programmer.setState(::Programmer::Running); break; + case Pic::TargetInProgramming: _programmer.setState(::Programmer::Stopped); break; + case Pic::Nb_TargetModes: Q_ASSERT(false); break; + } + return true; +} + +bool Icd2::Debugger::setBreakpoints(const QValueList<Address> &addresses) +{ + if ( addresses.count()==0 ) return specific()->setBreakpoint(Address()); + for (uint i=0; i<uint(addresses.count()); i++) { + log(Log::DebugLevel::Normal, QString("Set breakpoint at %1").arg(toHexLabel(addresses[i], device()->nbCharsAddress()))); + if ( !specific()->setBreakpoint(addresses[i]) ) return false; + } + return true; +} + +bool Icd2::Debugger::internalRun() +{ + return hardware()->resumeRun(); +} + +bool Icd2::Debugger::hardHalt() +{ + log(Log::LineType::Warning, i18n("Failed to halt target: try a reset.")); + return reset(); +} + +bool Icd2::Debugger::softHalt(bool &success) +{ + if ( !hardware()->haltRun() ) return false; + success = waitForTargetMode(Pic::TargetStopped); + return true; +} + +bool Icd2::Debugger::internalReset() +{ + return specific()->reset(); +} + +bool Icd2::Debugger::internalStep() +{ + return hardware()->step(); +} + +bool Icd2::Debugger::readRegister(const Register::TypeData &data, BitValue &value) +{ + if ( data.type()==Register::Special ) { + if ( data.name()=="WREG" ) return hardware()->readRegister(specific()->addressWREG(), value, 1); + if ( data.name()=="PC" ) { value = hardware()->getProgramCounter().maskWith(specific()->maskPC()); return !hasError(); } + Q_ASSERT(false); + return true; + } + QString name = device()->registersData().sfrNames[data.address()]; + if ( name=="WREG" ) return hardware()->readRegister(specific()->addressWREG(), value, 1); + if ( name=="PCL" ) { value = hardware()->getProgramCounter().maskWith(specific()->maskPC()).byte(0); return !hasError(); } + if ( name=="PCLATH" ) { value = hardware()->getProgramCounter().maskWith(specific()->maskPC()).byte(1); return !hasError(); } + return hardware()->readRegister(specific()->addressRegister(data.address()), value, 1); +} + +bool Icd2::Debugger::writeRegister(const Register::TypeData &data, BitValue value) +{ + if ( data.type()==Register::Special ) { + if ( data.name()=="WREG" ) return hardware()->writeRegister(specific()->addressWREG(), value, 1); + Q_ASSERT(false); + return true; + } + QString name = device()->registersData().sfrNames[data.address()]; + if ( name=="WREG" ) return hardware()->writeRegister(specific()->addressWREG(), value, 1); + return hardware()->writeRegister(specific()->addressRegister(data.address()), value, 1); +} + +//----------------------------------------------------------------------------- +Icd2::DebugProgrammer::DebugProgrammer(const ::Programmer::Group &group, const Pic::Data *data) + : Icd2::ProgrammerBase(group, data, "icd2_programmer") +{} + +void Icd2::DebugProgrammer::clear() +{ + Icd2::ProgrammerBase::clear(); + _debugExecutiveVersion.clear(); +} + +bool Icd2::DebugProgrammer::internalSetupHardware() +{ + if ( _specific==0 ) return true; + const FamilyData &fdata = FAMILY_DATA[family(device()->name())]; + + // find debug executive file + PURL::Directory dir(::Programmer::GroupConfig::firmwareDirectory(group())); + if ( !dir.exists() ) { + log(Log::LineType::Error, i18n("Firmware directory not configured.")); + return false; + } + uint reservedBank = 0; + QString filename; + if ( device()->is18Family() ) { + Debugger *debug = static_cast<Debugger *>(debugger()); + reservedBank = static_cast<const P18FDebuggerSpecific *>(debug->specific())->reservedBank(); + filename = QString("de18F_BANK%1.hex").arg(QString(toString(NumberBase::Dec, reservedBank, 2))); + } else filename = QString("de%1.hex").arg(fdata.debugExec); + PURL::Url url = dir.findMatchingFilename(filename); + log(Log::DebugLevel::Normal, QString(" Debug executive file: %1").arg(url.pretty())); + if ( !url.exists() ) { + log(Log::LineType::Error, i18n("Could not find debug executive file \"%1\".").arg(url.pretty())); + return false; + } + // upload hex file + Log::StringView sview; + PURL::File file(url, sview); + if ( !file.openForRead() ) { + log(Log::LineType::Error, i18n("Could not open firmware file \"%1\".").arg(url.pretty())); + return false; + } + QStringList errors; + HexBuffer hbuffer; + if ( !hbuffer.load(file.stream(), errors) ) { + log(Log::LineType::Error, i18n("Could not read debug executive file \"%1\": %2.").arg(url.pretty()).arg(errors[0])); + return false; + } + uint nbWords = device()->nbWords(Pic::MemoryRangeType::Code); + uint offset = nbWords - 0x100; + if ( fdata.debugExecOffset!=0 && fdata.debugExecOffset!=offset ) + for (uint i=0; i<0x100; i++) hbuffer.insert(offset+i, hbuffer[fdata.debugExecOffset+i]); + Pic::Memory::WarningTypes warningTypes; + QStringList warnings; + QMap<uint, bool> inRange; + Pic::Memory memory(*device()); + memory.fromHexBuffer(Pic::MemoryRangeType::Code, hbuffer, warningTypes, warnings, inRange); + _deArray = memory.arrayForWriting(Pic::MemoryRangeType::Code); + if ( device()->is18Family() ) { + // that's a bit ugly but it cannot be guessed for 18F2455 family... + uint size; + switch (reservedBank) { + case 0: size = 0x0E0; break; + case 12: + case 14: size = 0x140; break; + default: size = 0x120; break; + } + _deStart = nbWords - size; + _deEnd = nbWords - 1; + for (uint i=0; i<size; i++) { + BitValue v = memory.word(Pic::MemoryRangeType::Code, i); + memory.setWord(Pic::MemoryRangeType::Code, i, BitValue()); + memory.setWord(Pic::MemoryRangeType::Code, _deStart+i, v); + } + _deArray = memory.arrayForWriting(Pic::MemoryRangeType::Code); + } else { + _deStart = specific()->findNonMaskStart(Pic::MemoryRangeType::Code, _deArray); + _deEnd = specific()->findNonMaskEnd(Pic::MemoryRangeType::Code, _deArray); + } + log(Log::DebugLevel::Extra, QString("debug executive: \"%1\" %2:%3").arg(url.pretty()).arg(toHexLabel(_deStart, 4)).arg(toHexLabel(_deEnd, 4))); + return Icd2::ProgrammerBase::internalSetupHardware(); +} + +Pic::Memory Icd2::DebugProgrammer::toDebugMemory(const Pic::Memory &mem, bool withDebugExecutive) +{ + Pic::Memory memory = mem; + memory.setDebugOn(true); + if ( memory.hasWatchdogTimerOn() ) { + log(Log::LineType::Warning, i18n("Disabling watchdog timer for debugging")); + memory.setWatchdogTimerOn(false); + } + if ( memory.isProtected(Pic::Protection::ProgramProtected, Pic::MemoryRangeType::Code) ) { + log(Log::LineType::Warning, i18n("Disabling code program protection for debugging")); + memory.setProtection(false, Pic::Protection::ProgramProtected, Pic::MemoryRangeType::Code); + } + if ( memory.isProtected(Pic::Protection::WriteProtected, Pic::MemoryRangeType::Code) ) { + log(Log::LineType::Warning, i18n("Disabling code write protection for debugging")); + memory.setProtection(false, Pic::Protection::WriteProtected, Pic::MemoryRangeType::Code); + } + if ( memory.isProtected(Pic::Protection::ReadProtected, Pic::MemoryRangeType::Code) ) { + log(Log::LineType::Warning, i18n("Disabling code read protection for debugging")); + memory.setProtection(false, Pic::Protection::ReadProtected, Pic::MemoryRangeType::Code); + } + uint address = _deStart * device()->addressIncrement(Pic::MemoryRangeType::Code); + Device::Array data = device()->gotoInstruction(address, false); + for (uint i=0; i<data.count(); i++) memory.setWord(Pic::MemoryRangeType::DebugVector, i, data[i]); + if ( device()->is18Family() ) + memory.setWord(Pic::MemoryRangeType::DebugVector, data.count(), 0xFF00); // ?? + if (withDebugExecutive) { + bool ok = true; + for (uint i=_deStart; i<=_deEnd; i++) { + if ( memory.word(Pic::MemoryRangeType::Code, i).isInitialized() ) ok = false; + memory.setWord(Pic::MemoryRangeType::Code, i, _deArray[i]); + } + if ( !ok ) log(Log::LineType::Warning, i18n("Memory area for debug executive was not empty. Overwrite it and continue anyway...")); + } + return memory; +} + +bool Icd2::DebugProgrammer::writeDebugExecutive() +{ + log(Log::LineType::Information, i18n(" Write debug executive")); + Device::Array data = _deArray.mid(_deStart, _deEnd - _deStart + 1); + if ( !hardware()->writeMemory(Pic::MemoryRangeType::Code, _deStart, data) ) return false; + log(Log::LineType::Information, i18n(" Verify debug executive")); + if ( !hardware()->readMemory(Pic::MemoryRangeType::Code, _deStart, data, 0) ) return false; + for (uint i=0; i<data.count(); i++) { + if ( _deArray[_deStart+i]==data[i] ) continue; + uint inc = device()->addressIncrement(Pic::MemoryRangeType::Code); + Address address = device()->range(Pic::MemoryRangeType::Code).start + inc * (_deStart + i); + log(Log::LineType::Error, i18n("Device memory doesn't match debug executive (at address %1: reading %2 and expecting %3).") + .arg(toHexLabel(address, device()->nbCharsAddress())) + .arg(toHexLabel(data[i], device()->nbCharsWord(Pic::MemoryRangeType::Code))) + .arg(toHexLabel(_deArray[_deStart+i], device()->nbCharsWord(Pic::MemoryRangeType::Code)))); + return false; + } + return true; +} + +bool Icd2::DebugProgrammer::doProgram(const Device::Memory &memory, const Device::MemoryRange &range) +{ + if ( !checkProgram(memory) ) return false; + if ( !doConnectDevice() ) return false; + _progressMonitor.startNextTask(); + // probably needed for all devices that don't have a "erase and write" mode + if ( range.all() && FAMILY_DATA[family(device()->name())].debugExec==QString("16F7X7") ) { + Pic::Memory dmemory(*device()); + dmemory.setWord(Pic::MemoryRangeType::Code, 0, 0x0028); + dmemory.setWord(Pic::MemoryRangeType::Code, 1, 0x0030); + log(Log::LineType::Information, i18n("Programming device for debugging test...")); + if ( !internalProgram(dmemory, range) ) return false; + if ( !static_cast<Debugger *>(_debugger)->init(false) ) return false; + log(Log::LineType::Information, i18n("Debugging test successful")); + } + log(Log::LineType::Information, i18n("Programming device memory...")); + if ( !internalProgram(memory, range) ) return false; + log(Log::LineType::Information, i18n("Programming successful")); + return static_cast<Debugger *>(_debugger)->init(true); +} + +bool Icd2::DebugProgrammer::programAll(const Pic::Memory &mem) +{ + Pic::Memory memory = toDebugMemory(mem, false); + if ( !programAndVerifyRange(Pic::MemoryRangeType::Code, memory) ) return false; + if ( !writeDebugExecutive() ) return false; + if ( !programAndVerifyRange(Pic::MemoryRangeType::DebugVector, memory) ) return false; + if ( !programAndVerifyRange(Pic::MemoryRangeType::Eeprom, memory) ) return false; + if ( !programAndVerifyRange(Pic::MemoryRangeType::UserId, memory) ) return false; + if ( device()->is18Family() ) { + if ( !hardware()->command("0C00", 0) ) return false; // #### ?? + QString com = "42" + toHex(0xFB5, 8) + toHex(1, 8); // write RSBUG (?) + if ( !hardware()->command(com, 0) ) return false; + if ( !hardware()->command("0C01", 0) ) return false; // #### ?? + } + if ( !programAndVerifyRange(Pic::MemoryRangeType::Config, memory) ) return false; + return true; +} + +bool Icd2::DebugProgrammer::internalRead(Device::Memory *mem, const Device::MemoryRange &range, const ::Programmer::VerifyData *vd) +{ + if ( vd==0 || (vd->actions & ::Programmer::BlankCheckVerify) ) return Icd2::ProgrammerBase::internalRead(mem, range, vd); + Pic::Memory memory = toDebugMemory(static_cast<const Pic::Memory &>(vd->memory), true); + ::Programmer::VerifyData vdata(vd->actions, memory); + if ( !Icd2::ProgrammerBase::internalRead(0, range, &vdata) ) return false; + if ( range.all() && !readRange(Pic::MemoryRangeType::DebugVector, 0, &vdata) ) return false; + return true; +} + +bool Icd2::DebugProgrammer::readDebugExecutiveVersion() +{ + if ( !hardware()->getDebugExecVersion(_debugExecutiveVersion) ) return false; + log(Log::LineType::Information, i18n(" Debug executive version: %1").arg(_debugExecutiveVersion.pretty())); + return true; +} + +//---------------------------------------------------------------------------- +void Icd2::DebuggerGroup::addDevice(const QString &name, const Device::Data *ddata, ::Group::Support) +{ + if ( FAMILY_DATA[family(name)].debugExec==0 ) return; + Group::addDevice(name, ddata, data(name).debugSupport); +} + +::Debugger::Specific *Icd2::DebuggerGroup::createDebuggerSpecific(::Debugger::Base &base) const +{ + const Pic::Data *data = static_cast< ::Debugger::PicBase &>(base).device(); + if ( data==0 ) return 0; + QString debugExec = FAMILY_DATA[family(data->name())].debugExec; + switch (data->architecture().type()) { + case Pic::Architecture::P16X: + if ( debugExec=="16F872" ) return new P16F872DebuggerSpecific(base); + if ( debugExec=="16F7X7" ) return new P16F7X7DebuggerSpecific(base); + return new P16F87XDebuggerSpecific(base); + case Pic::Architecture::P17C: + case Pic::Architecture::P18C: + case Pic::Architecture::P18F: + case Pic::Architecture::P18J: return new P18FDebuggerSpecific(base); + case Pic::Architecture::P10X: + case Pic::Architecture::P24F: + case Pic::Architecture::P24H: + case Pic::Architecture::P30F: + case Pic::Architecture::P33F: + case Pic::Architecture::Nb_Types: break; + } + Q_ASSERT(false); + return 0; +} |