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.
piklab/src/progs/icd2/base/icd2_debug.cpp

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;
}