/*************************************************************************** * Copyright (C) 2005-2007 Nicolas Hadacek * * * * 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(_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, TQString("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 TQValueList
&addresses) { if ( addresses.count()==0 ) return specific()->setBreakpoint(Address()); for (uint i=0; inbCharsAddress()))); 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; } TQString 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; } TQString 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; TQString filename; if ( device()->is18Family() ) { Debugger *debug = static_cast(debugger()); reservedBank = static_cast(debug->specific())->reservedBank(); filename = TQString("de18F_BANK%1.hex").arg(TQString(toString(NumberBase::Dec, reservedBank, 2))); } else filename = TQString("de%1.hex").arg(fdata.debugExec); PURL::Url url = dir.findMatchingFilename(filename); log(Log::DebugLevel::Normal, TQString(" 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; } TQStringList 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; TQStringList warnings; TQMap 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; ifindNonMaskStart(Pic::MemoryRangeType::Code, _deArray); _deEnd = specific()->findNonMaskEnd(Pic::MemoryRangeType::Code, _deArray); } log(Log::DebugLevel::Extra, TQString("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; iis18Family() ) 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; iaddressIncrement(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==TQString("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)->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)->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; // #### ?? TQString 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(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 TQString &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; TQString 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; }