You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
15 KiB
349 lines
15 KiB
/***************************************************************************
|
|
* 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, TQString("Timeout waiting for mode: %1 (target is in mode: %2).")
|
|
.tqarg(i18n(Pic::TARGET_MODE_LABELS[mode])).tqarg(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<Address> &addresses)
|
|
{
|
|
if ( addresses.count()==0 ) return specific()->setBreakpoint(Address());
|
|
for (uint i=0; i<uint(addresses.count()); i++) {
|
|
log(Log::DebugLevel::Normal, TQString("Set breakpoint at %1").tqarg(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;
|
|
}
|
|
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 *>(debugger());
|
|
reservedBank = static_cast<const P18FDebuggerSpecific *>(debug->specific())->reservedBank();
|
|
filename = TQString("de18F_BANK%1.hex").tqarg(TQString(toString(NumberBase::Dec, reservedBank, 2)));
|
|
} else filename = TQString("de%1.hex").tqarg(fdata.debugExec);
|
|
PURL::Url url = dir.findMatchingFilename(filename);
|
|
log(Log::DebugLevel::Normal, TQString(" Debug executive file: %1").tqarg(url.pretty()));
|
|
if ( !url.exists() ) {
|
|
log(Log::LineType::Error, i18n("Could not find debug executive file \"%1\".").tqarg(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\".").tqarg(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.").tqarg(url.pretty()).tqarg(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<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, TQString("debug executive: \"%1\" %2:%3").tqarg(url.pretty()).tqarg(toHexLabel(_deStart, 4)).tqarg(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).")
|
|
.tqarg(toHexLabel(address, device()->nbCharsAddress()))
|
|
.tqarg(toHexLabel(data[i], device()->nbCharsWord(Pic::MemoryRangeType::Code)))
|
|
.tqarg(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 *>(_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; // #### ??
|
|
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<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").tqarg(_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;
|
|
}
|