diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
commit | f508189682b6fba62e08feeb1596f682bad5fff9 (patch) | |
tree | 28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/devices/pic/prog | |
download | piklab-f508189682b6fba62e08feeb1596f682bad5fff9.tar.gz piklab-f508189682b6fba62e08feeb1596f682bad5fff9.zip |
Added KDE3 version of PikLab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/piklab@1095639 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/devices/pic/prog')
-rw-r--r-- | src/devices/pic/prog/Makefile.am | 5 | ||||
-rw-r--r-- | src/devices/pic/prog/pic_debug.cpp | 118 | ||||
-rw-r--r-- | src/devices/pic/prog/pic_debug.h | 65 | ||||
-rw-r--r-- | src/devices/pic/prog/pic_prog.cpp | 751 | ||||
-rw-r--r-- | src/devices/pic/prog/pic_prog.h | 110 | ||||
-rw-r--r-- | src/devices/pic/prog/pic_prog_specific.cpp | 121 | ||||
-rw-r--r-- | src/devices/pic/prog/pic_prog_specific.h | 86 | ||||
-rw-r--r-- | src/devices/pic/prog/prog.pro | 6 |
8 files changed, 1262 insertions, 0 deletions
diff --git a/src/devices/pic/prog/Makefile.am b/src/devices/pic/prog/Makefile.am new file mode 100644 index 0000000..055d2cd --- /dev/null +++ b/src/devices/pic/prog/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libpicprog.la +libpicprog_la_SOURCES = pic_prog.cpp pic_prog_specific.cpp pic_debug.cpp diff --git a/src/devices/pic/prog/pic_debug.cpp b/src/devices/pic/prog/pic_debug.cpp new file mode 100644 index 0000000..443bb10 --- /dev/null +++ b/src/devices/pic/prog/pic_debug.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2006 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 "pic_debug.h" + +#include "common/common/misc.h" +#include "devices/pic/base/pic_register.h" +#include "progs/manager/debug_manager.h" + +//---------------------------------------------------------------------------- +Register::TypeData Debugger::PicBase::registerTypeData(const QString &name) const +{ + const Pic::RegistersData &rdata = device()->registersData(); + Q_ASSERT(rdata.sfrs.contains(name)); + return Register::TypeData(rdata.sfrs[name].address, rdata.nbChars()); +} + +bool Debugger::PicBase::updatePortStatus(uint index, QMap<uint, Device::PortBitData> &bits) +{ + const Pic::RegistersData &rdata = device()->registersData(); + BitValue tris; + if ( rdata.hasTris(index) ) { + tris = Register::list().value(registerTypeData(rdata.trisName(index))); + Q_ASSERT( tris.isInitialized() ); + } + BitValue port = Register::list().value(registerTypeData(rdata.portName(index))); + Q_ASSERT( port.isInitialized() ); + BitValue latch; + if ( rdata.hasLatch(index) ) { + latch = Register::list().value(registerTypeData(rdata.latchName(index))); + Q_ASSERT( latch.isInitialized() ); + } + for (uint i=0; i<Device::MAX_NB_PORT_BITS; i++) { + if ( !rdata.hasPortBit(index, i) ) continue; + bits[i].state = Device::Unknown; + bits[i].drivenState = Device::IoUnknown; + bits[i].drivingState = Device::IoUnknown; + if ( tris.isInitialized() ) { + bits[i].driving = !tris.bit(i); + if (bits[i].driving) { + bits[i].drivenState = Device::IoUnknown; + bits[i].drivingState = (port.bit(i) ? Device::IoHigh : Device::IoLow); + } else { + bits[i].drivenState = (port.bit(i) ? Device::IoHigh : Device::IoLow); + if ( latch.isInitialized() ) bits[i].drivingState = (latch.bit(i) ? Device::IoHigh : Device::IoLow); + else bits[i].drivingState = Device::IoUnknown; + } + } + } + return true; +} + +//---------------------------------------------------------------------------- +Debugger::PicBase &Debugger::PicSpecific::base() +{ + return static_cast<PicBase &>(_base); +} +const Debugger::PicBase &Debugger::PicSpecific::base() const +{ + return static_cast<PicBase &>(_base); +} + +bool Debugger::PicSpecific::updateStatus() +{ + if ( !Debugger::manager->readRegister(base().pcTypeData()) ) return false; + if ( !Debugger::manager->readRegister(base().registerTypeData("STATUS")) ) return false; + if ( !Debugger::manager->readRegister(wregTypeData()) ) return false; + return true; +} + +//---------------------------------------------------------------------------- +Register::TypeData Debugger::P16FSpecific::wregTypeData() const +{ + return Register::TypeData("WREG", device().registersData().nbChars()); +} + +QString Debugger::P16FSpecific::statusString() const +{ + const Pic::RegistersData &rdata = device().registersData(); + BitValue status = Register::list().value(base().registerTypeData("STATUS")); + uint bank = (status.bit(5) ? 1 : 0) + (status.bit(6) ? 2 : 0); + BitValue wreg = Register::list().value(wregTypeData()); + return QString("W:%1 %2 %3 %4 PC:%5 Bank:%6") + .arg(toHexLabel(wreg, rdata.nbChars())).arg(status.bit(2) ? "Z" : "z") + .arg(status.bit(1) ? "DC" : "dc").arg(status.bit(0) ? "C" : "c") + .arg(toHexLabel(_base.pc(), device().nbCharsAddress())).arg(bank); +} + +//---------------------------------------------------------------------------- +bool Debugger::P18FSpecific::updateStatus() +{ + if ( !PicSpecific::updateStatus() ) return false; + if ( !Debugger::manager->readRegister(base().registerTypeData("BSR")) ) return false; + return true; +} + +Register::TypeData Debugger::P18FSpecific::wregTypeData() const +{ + return base().registerTypeData("WREG"); +} + +QString Debugger::P18FSpecific::statusString() const +{ + const Pic::RegistersData &rdata = device().registersData(); + BitValue status = Register::list().value(base().registerTypeData("STATUS")); + BitValue bsr = Register::list().value(base().registerTypeData("BSR")); + BitValue wreg = Register::list().value(wregTypeData()); + return QString("W:%1 %2 %3 %4 %5 %6 PC:%7 Bank:%8") + .arg(toHexLabel(wreg, rdata.nbChars())).arg(status.bit(4) ? "N" : "n") + .arg(status.bit(3) ? "OV" : "ov").arg(status.bit(2) ? "Z" : "z") + .arg(status.bit(1) ? "DC" : "dc").arg(status.bit(0) ? "C" : "c") + .arg(toHexLabel(base().pc(), device().nbCharsAddress())).arg(toLabel(bsr)); +} diff --git a/src/devices/pic/prog/pic_debug.h b/src/devices/pic/prog/pic_debug.h new file mode 100644 index 0000000..dfb8af6 --- /dev/null +++ b/src/devices/pic/prog/pic_debug.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2006 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. * + ***************************************************************************/ +#ifndef PIC_DEBUG_H +#define PIC_DEBUG_H + +#include "progs/base/generic_debug.h" +#include "pic_prog.h" +#include "devices/base/register.h" + +namespace Debugger +{ +class PicBase; + +//---------------------------------------------------------------------------- +class PicSpecific : public DeviceSpecific +{ +public: + PicSpecific(Debugger::Base &base) : DeviceSpecific(base) {} + const Pic::Data &device() const { return static_cast<const Pic::Data &>(*_base.device()); } + PicBase &base(); + const PicBase &base() const; + virtual bool updateStatus(); + virtual Register::TypeData wregTypeData() const = 0; +}; + +//---------------------------------------------------------------------------- +class P16FSpecific : public PicSpecific +{ +public: + P16FSpecific(Debugger::Base &base) : PicSpecific(base) {} + virtual QString statusString() const; + virtual Register::TypeData wregTypeData() const; +}; + +//---------------------------------------------------------------------------- +class P18FSpecific : public PicSpecific +{ +public: + P18FSpecific(Debugger::Base &base) : PicSpecific(base) {} + virtual QString statusString() const; + virtual bool updateStatus(); + virtual Register::TypeData wregTypeData() const; +}; + +//---------------------------------------------------------------------------- +class PicBase : public Debugger::Base +{ +public: + PicBase(Programmer::PicBase &base) : Debugger::Base(base) {} + PicSpecific *deviceSpecific() { return static_cast<PicSpecific *>(_deviceSpecific); } + const PicSpecific *deviceSpecific() const { return static_cast<const PicSpecific *>(_deviceSpecific); } + const Pic::Data *device() const { return static_cast<const Pic::Data *>(Debugger::Base::device()); } + Register::TypeData registerTypeData(const QString &name) const; + virtual bool updatePortStatus(uint index, QMap<uint, Device::PortBitData> &bits); +}; + +} // namespace + +#endif diff --git a/src/devices/pic/prog/pic_prog.cpp b/src/devices/pic/prog/pic_prog.cpp new file mode 100644 index 0000000..bc7dcd1 --- /dev/null +++ b/src/devices/pic/prog/pic_prog.cpp @@ -0,0 +1,751 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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 "pic_prog.h" + +#include "common/global/global.h" +#include "devices/list/device_list.h" +#include "progs/base/prog_config.h" +#include "progs/base/prog_group.h" +#include "pic_debug.h" + +//----------------------------------------------------------------------------- +bool Programmer::PicGroup::canReadVoltages() const +{ + for (uint i=0; i<Pic::Nb_VoltageTypes; i++) + if ( canReadVoltage(Pic::VoltageType(i)) ) return true; + return false; +} + +Debugger::DeviceSpecific *Programmer::PicGroup::createDebuggerDeviceSpecific(::Debugger::Base &base) const +{ + const Pic::Data *data = static_cast<const Pic::Data *>(base.device()); + if ( data==0 ) return 0; + switch (data->architecture().type()) { + case Pic::Architecture::P10X: + case Pic::Architecture::P16X: return new ::Debugger::P16FSpecific(base); + case Pic::Architecture::P18C: + case Pic::Architecture::P18F: + case Pic::Architecture::P18J: return new ::Debugger::P18FSpecific(base); + case Pic::Architecture::P24F: + case Pic::Architecture::P24H: + case Pic::Architecture::P30F: + case Pic::Architecture::P33F: + case Pic::Architecture::P17C: + case Pic::Architecture::Nb_Types: break; + } + Q_ASSERT(false); + return 0; +} + +//----------------------------------------------------------------------------- +Programmer::PicBase::PicBase(const Group &group, const Pic::Data *data, const char *name) + : Base(group, data, name), _deviceMemory(0), _hasProtectedCode(false), _hasProtectedEeprom(false) +{ + if (data) _deviceMemory = new Pic::Memory(*data); +} + +Programmer::PicBase::~PicBase() +{ + delete _deviceMemory; +} + +void Programmer::PicBase::clear() +{ + ::Programmer::Base::clear(); + for (uint i=0; i<Pic::Nb_VoltageTypes; i++) { + _voltages[i].error = false; + _voltages[i].value = UNKNOWN_VOLTAGE; + } +} + +uint Programmer::PicBase::nbSteps(Task task, const Device::MemoryRange *range) const +{ + const Pic::MemoryRange *prange = static_cast<const Pic::MemoryRange *>(range); + switch (task.type()) { + case Task::Erase: return 1; + case Task::Read: + case Task::Verify: + case Task::BlankCheck: { + uint nb = 0; + FOR_EACH(Pic::MemoryRangeType, type) { + if ( type!=Pic::MemoryRangeType::Code && type!=Pic::MemoryRangeType::Eeprom ) continue; + if ( !device()->isReadable(type) || !specific()->canReadRange(type) ) continue; + if ( !prange->all() && prange->_type!=type ) continue; + nb += device()->nbWords(type); + } + return QMAX(nb, uint(1)); + } + case Task::Write: { + uint nb = 0; + FOR_EACH(Pic::MemoryRangeType, type) { + if ( type!=Pic::MemoryRangeType::Code && type!=Pic::MemoryRangeType::Eeprom ) continue; + if ( !device()->isWritable(type) || !specific()->canWriteRange(type) ) continue; + if ( !prange->all() && prange->_type!=type ) continue; + nb += device()->nbWords(type); + if ( readConfigEntry(Config::VerifyAfterProgram).toBool() ) nb += device()->nbWords(type); + } + return QMAX(nb, uint(1)); + } + case Task::Nb_Types: break; + } + Q_ASSERT(false); + return 0; +} + +bool Programmer::PicBase::readVoltages() +{ + if ( !hardware()->readVoltages(_voltages) ) return false; + bool ok = true; + for (uint i=0; i<Pic::Nb_VoltageTypes; i++) { + if ( !group().canReadVoltage(Pic::VoltageType(i)) ) continue; + if ( _voltages[i].error==true ) { + ok = false; + log(Log::LineType::Error, i18n(" %1 = %2 V: error in voltage level.").arg(i18n(Pic::VOLTAGE_TYPE_LABELS[i])).arg(_voltages[i].value)); + } else if ( _voltages[i].value!=UNKNOWN_VOLTAGE ) + log(Log::DebugLevel::Normal, QString(" %1 = %2 V").arg(i18n(Pic::VOLTAGE_TYPE_LABELS[i])).arg(_voltages[i].value)); + } + return ok; +} + +bool Programmer::PicBase::internalSetupHardware() +{ + if ( !Base::internalSetupHardware() ) return false; + if ( group().properties() & ::Programmer::CanReleaseReset ) { + log(Log::DebugLevel::Normal, " Hold reset"); + if ( !hardware()->setTargetReset(Pic::ResetHeld) ) return false; + } + Pic::TargetMode mode; + if ( !getTargetMode(mode) ) return false; + if ( mode!=Pic::TargetInProgramming ) { + log(Log::LineType::Error, i18n("Device not in programming")); + return false; + } + return true; +} + +bool Programmer::PicBase::initProgramming(Task) +{ +/* + if ( vpp()!=UNKNOWN_VOLTAGE ) { + const Pic::VoltageData &tvpp = device()->voltage(Pic::Vpp); + if ( vpp()<tvpp.min ) + log(Log::LineType::Warning, i18n("Vpp (%1 V) is lower than the minimum required voltage (%2 V).") + .arg(vpp()).arg(tvpp.min)); + if ( vpp()>tvpp.max ) { + QString s = i18n("Vpp (%1 V) is higher than the maximum voltage (%2 V). You may damage the device.") + .arg(vpp()).arg(tvpp.max); + log(Log::LineType::Warning, s); + if ( !askContinue(s) ) { + logUserAbort(); + return false; + } + } + } + if ( vdd()!=UNKNOWN_VOLTAGE ) { + Q_ASSERT( type!=Pic::Vpp ); + const Pic::VoltageData &tvdd = device()->voltage(type); + if ( vdd()<tvdd.min ) { + if ( type==Pic::VddBulkErase && device()->voltage(Pic::VddWrite).min!=tvdd.min ) + log(Log::LineType::Warning, i18n("Vdd (%1 V) is too low for high-voltage programming\n(piklab only supports high-voltage programming at the moment).\nMinimum required is %2 V.") + .arg(vdd()).arg(tvdd.min)); + else if ( type==Pic::VddRead && device()->voltage(Pic::VddWrite).min!=tvdd.min ) + log(Log::LineType::Warning, i18n("Vdd (%1 V) is too low for reading\nMinimum required is %2 V.") + .arg(vdd()).arg(tvdd.min)); + else log(Log::LineType::Warning, i18n("Vdd (%1 V) is too low for programming\nMinimum required is %2 V.") + .arg(vdd()).arg(tvdd.min)); + } else if ( vdd()>tvdd.max ) { + QString s = i18n("Vdd (%1 V) is higher than the maximum voltage (%2 V). You may damage the device.") + .arg(vdd()).arg(tvdd.max); + log(Log::LineType::Warning, s); + if ( !askContinue(s) ) { + logUserAbort(); + return false; + } + } + } +*/ + if ( specific()->canReadRange(Pic::MemoryRangeType::Config) ) { + // read config + Device::Array data; + if ( !specific()->read(Pic::MemoryRangeType::Config, data, 0) ) return false; + _deviceMemory->setArray(Pic::MemoryRangeType::Config, data); + _hasProtectedCode = _deviceMemory->isProtected(Pic::Protection::ProgramProtected, Pic::MemoryRangeType::Code); + _hasProtectedEeprom = _deviceMemory->isProtected(Pic::Protection::ProgramProtected, Pic::MemoryRangeType::Eeprom); + log(Log::DebugLevel::Normal, QString(" protected: code=%1 data=%2") + .arg(_hasProtectedCode ? "true" : "false").arg(_hasProtectedEeprom ? "true" : "false")); + // read calibration + if ( !readCalibration() ) return false; + } + + return initProgramming(); +} + +bool Programmer::PicBase::preserveCode() +{ + if ( _hasProtectedCode && !askContinue(i18n("All or part of code memory is protected so it cannot be preserved. Continue anyway?")) ) + return false; + return readRange(Pic::MemoryRangeType::Code, _deviceMemory, 0); +} + +bool Programmer::PicBase::preserveEeprom() +{ + if ( _hasProtectedEeprom && !askContinue(i18n("All or part of data EEPROM is protected so it cannot be preserved. Continue anyway?")) ) + return false; + return readRange(Pic::MemoryRangeType::Eeprom, _deviceMemory, 0); +} + +bool Programmer::PicBase::internalRun() +{ + _state = ::Programmer::Running; + return hardware()->setTargetReset(Pic::ResetReleased); +} + +bool Programmer::PicBase::internalStop() +{ + _state = ::Programmer::Stopped; + return hardware()->setTargetReset(Pic::ResetHeld); +} + +bool Programmer::PicBase::getTargetMode(Pic::TargetMode &mode) +{ + return hardware()->getTargetMode(mode); +} + +bool Programmer::PicBase::initProgramming() +{ + _state = ::Programmer::Stopped; + return hardware()->setTargetReset(Pic::ResetHeld); +} + +//----------------------------------------------------------------------------- +BitValue Programmer::PicBase::readDeviceId() +{ + Device::Array data; + if ( !specific()->read(Pic::MemoryRangeType::DeviceId, data, 0) ) return 0; + Q_ASSERT( data.count()!=0 ); + BitValue id = 0x0; + switch (device()->architecture().type()) { + case Pic::Architecture::P10X: + case Pic::Architecture::P16X: + case Pic::Architecture::P17C: id = data[0]; break; + case Pic::Architecture::P18C: + case Pic::Architecture::P18F: + case Pic::Architecture::P18J: id = data[0] | (data[1] << 8); break; + case Pic::Architecture::P24F: + case Pic::Architecture::P24H: + case Pic::Architecture::P30F: + case Pic::Architecture::P33F: id = data[1] | (data[0] << 16); break; + case Pic::Architecture::Nb_Types: Q_ASSERT(false); break; + } + return id; +} + +bool Programmer::PicBase::verifyDeviceId() +{ + if ( !specific()->canReadRange(Pic::MemoryRangeType::DeviceId ) ) return true; + if ( !device()->isReadable(Pic::MemoryRangeType::DeviceId) ) { + log(Log::LineType::Information, i18n("Device not autodetectable: continuing with the specified device name \"%1\"...").arg(device()->name())); + return true; + } + BitValue rawId = readDeviceId(); + if ( hasError() ) return false; + uint nbChars = device()->nbWords(Pic::MemoryRangeType::DeviceId) * device()->nbCharsWord(Pic::MemoryRangeType::DeviceId); + if ( rawId==0x0 || rawId==device()->mask(Pic::MemoryRangeType::DeviceId) ) { + log(Log::LineType::Error, i18n("Missing or incorrect device (Read id is %1).").arg(toHexLabel(rawId, nbChars))); + return false; + } + QMap<QString, Device::IdData> ids; + QValueVector<QString> names = group().supportedDevices(); + for (uint k=0; k<uint(names.count()); k++) { + const Pic::Data *data = static_cast<const Pic::Data *>(group().deviceData(names[k]).data); + if ( data->architecture()!=device()->architecture() ) continue; + Device::IdData idata; + if ( data->matchId(rawId, idata) ) ids[names[k]] = idata; + } + QString message; + if ( ids.count()!=0 ) { + log(Log::LineType::Information, i18n("Read id: %1").arg(device()->idNames(ids).join("; "))); + if ( ids.contains(device()->name()) ) return true; + message = i18n("Read id does not match the specified device name \"%1\".").arg(device()->name()); + } else { + log(Log::LineType::Warning, i18n(" Unknown or incorrect device (Read id is %1).").arg(toHexLabel(rawId, nbChars))); + message = i18n("Unknown device."); + } + if ( !askContinue(message) ) { + logUserAbort(); + return false; + } + log(Log::LineType::Information, i18n("Continue with the specified device name: \"%1\"...").arg(device()->name())); + return true; +} + +//----------------------------------------------------------------------------- +QString Programmer::PicBase::prettyCalibration(const Device::Array &data) const +{ + QString s; + for (uint i=0; i<data.count(); i++) { + if ( i!=0 ) s += ", "; + s += toHexLabel(data[i], device()->nbCharsWord(Pic::MemoryRangeType::Cal)); + } + return s; +} + +bool Programmer::PicBase::readCalibration() +{ + if ( device()->isReadable(Pic::MemoryRangeType::Cal) ) { + if ( !specific()->canReadRange(Pic::MemoryRangeType::Cal) ) { + log(Log::LineType::Warning, i18n("Osccal cannot be read by the selected programmer")); + return true; + } + Device::Array data; + if ( !specific()->read(Pic::MemoryRangeType::Cal, data, 0) ) return false; + _deviceMemory->setArray(Pic::MemoryRangeType::Cal, data); + log(Log::DebugLevel::Normal, QString(" Read osccal: %1").arg(prettyCalibration(data))); + QString message; + if ( !device()->checkCalibration(data, &message) ) log(Log::LineType::Warning, " " + message); + if ( device()->isReadable(Pic::MemoryRangeType::CalBackup) ) { + if ( !specific()->canReadRange(Pic::MemoryRangeType::CalBackup) ) { + log(Log::LineType::Warning, i18n("Osccal backup cannot be read by the selected programmer")); + return true; + } + if ( !specific()->read(Pic::MemoryRangeType::CalBackup, data, 0) ) return false; + _deviceMemory->setArray(Pic::MemoryRangeType::CalBackup, data); + log(Log::DebugLevel::Normal, QString(" Read osccal backup: %1").arg(prettyCalibration(data))); + if ( !device()->checkCalibration(data, &message) ) log(Log::LineType::Warning, " " + message); + } + } + return true; +} + +bool Programmer::PicBase::restoreCalibration() +{ + if ( !specific()->canReadRange(Pic::MemoryRangeType::Cal) || !specific()->canWriteRange(Pic::MemoryRangeType::Cal) ) return true; + if ( !device()->isWritable(Pic::MemoryRangeType::Cal) ) return true; + Device::Array data = _deviceMemory->arrayForWriting(Pic::MemoryRangeType::Cal); + Device::Array bdata = _deviceMemory->arrayForWriting(Pic::MemoryRangeType::CalBackup); + if ( device()->isReadable(Pic::MemoryRangeType::CalBackup) && specific()->canReadRange(Pic::MemoryRangeType::CalBackup) ) { + if ( !device()->checkCalibration(data) && device()->checkCalibration(bdata) ) { + log(Log::LineType::Information, i18n(" Replace invalid osccal with backup value.")); + data = bdata; + } + } + Device::Array cdata; + if ( !specific()->read(Pic::MemoryRangeType::Cal, cdata, 0) ) return false; + if ( cdata==data ) { + log(Log::LineType::Information, i18n(" Osccal is unchanged.")); + return true; + } + if ( !programRange(Pic::MemoryRangeType::Cal, data) ) return false; + if ( !specific()->read(Pic::MemoryRangeType::Cal, cdata, 0) ) return false; + if ( cdata==data ) log(Log::LineType::Information, i18n(" Osccal has been preserved.")); + + if ( !device()->isWritable(Pic::MemoryRangeType::CalBackup) || !device()->checkCalibration(bdata) ) return true; + if ( !specific()->read(Pic::MemoryRangeType::CalBackup, cdata, 0) ) return false; + if ( cdata.count()==0 ) { + log(Log::LineType::Warning, i18n("Osccal backup cannot be read by selected programmer")); + return true; + } + if ( cdata==bdata ) { + log(Log::LineType::Information, i18n(" Osccal backup is unchanged.")); + return true; + } + if ( !programRange(Pic::MemoryRangeType::CalBackup, bdata) ) return false; + if ( !specific()->read(Pic::MemoryRangeType::CalBackup, cdata, 0) ) return false; + if ( cdata==bdata ) log(Log::LineType::Information, i18n(" Osccal backup has been preserved.")); + return true; +} + +bool Programmer::PicBase::restoreBandGapBits() +{ + if ( !specific()->canReadRange(Pic::MemoryRangeType::Config) ) return true; + bool hasProtectedBits = false; + for (uint i=0; i<device()->nbWords(Pic::MemoryRangeType::Config); i++) + if ( device()->config()._words[i].pmask!=0 ) hasProtectedBits = true; + if ( !hasProtectedBits ) return true; + Device::Array cdata; + if ( !specific()->read(Pic::MemoryRangeType::Config, cdata, 0) ) return false; + Device::Array data = _deviceMemory->arrayForWriting(Pic::MemoryRangeType::Config); + for (uint i=0; i<cdata.count(); i++) { + BitValue pmask = device()->config()._words[i].pmask; + if ( pmask==0 ) continue; + cdata[i] = cdata[i].clearMaskBits(pmask); + cdata[i] |= data[i].maskWith(pmask); + } + if ( !specific()->canWriteRange(Pic::MemoryRangeType::Config) ) { + log(Log::LineType::Warning, i18n("Could not restore band gap bits because programmer does not support writing config bits.")); + return true; + } + log(Log::DebugLevel::Normal, QString(" Write config with band gap bits: %2").arg(toHexLabel(cdata[0], device()->nbCharsWord(Pic::MemoryRangeType::Config)))); + if ( !programRange(Pic::MemoryRangeType::Config, cdata) ) return false; + if ( !specific()->read(Pic::MemoryRangeType::Config, data, 0) ) return false; + if ( data==cdata ) log(Log::LineType::Information, i18n(" Band gap bits have been preserved.")); + return true; +} + +bool Programmer::PicBase::eraseAll() +{ + if ( !specific()->canEraseAll() ) { + log(Log::LineType::SoftError, i18n("The selected programmer does not support erasing the whole device.")); + return false; + } + if ( !specific()->erase(_hasProtectedCode || _hasProtectedEeprom) ) return false; + if ( !restoreCalibration() ) return false; + return true; +} + +bool Programmer::PicBase::checkErase() +{ + if ( device()->memoryTechnology()==Device::MemoryTechnology::Rom || device()->memoryTechnology()==Device::MemoryTechnology::Romless + || device()->memoryTechnology()==Device::MemoryTechnology::Eprom ) { + log(Log::LineType::SoftError, i18n("Cannot erase ROM or EPROM device.")); + return false; + } + return true; +} + +bool Programmer::PicBase::internalErase(const Device::MemoryRange &range) +{ + if ( !initProgramming(Task::Erase) ) return false; + bool ok = true; + if ( range.all() ) ok = eraseAll(); + else ok = eraseRange(static_cast<const Pic::MemoryRange &>(range)._type); + if ( !restoreBandGapBits() ) return false; + return ok; +} + +bool Programmer::PicBase::eraseSingle(Pic::MemoryRangeType type) +{ + return erase(Pic::MemoryRange(type)); +} + +bool Programmer::PicBase::eraseRange(Pic::MemoryRangeType type) +{ + bool ok = internalEraseRange(type); + if ( !restoreCalibration() ) return false; + if ( ok && readConfigEntry(Config::BlankCheckAfterErase).toBool() ) { + Pic::Memory memory(*device()); + VerifyData vdata(BlankCheckVerify, memory); + return readRange(type, 0, &vdata); + } + return ok; +} + +bool Programmer::PicBase::internalEraseRange(Pic::MemoryRangeType type) +{ + if ( !specific()->canEraseRange(type) && !specific()->canEraseAll() ) { + log(Log::LineType::SoftError, i18n("The selected programmer does not support erasing neither the specified range nor the whole device.")); + return false; + } + if ( type==Pic::MemoryRangeType::Code && _hasProtectedCode ) { + log(Log::LineType::SoftError, i18n("Cannot erase protected code memory. Consider erasing the whole chip.")); + return false; + } + if ( type==Pic::MemoryRangeType::Eeprom && _hasProtectedEeprom ) { + log(Log::LineType::SoftError, i18n("Cannot erase protected data EEPROM. Consider erasing the whole chip.")); + return false; + } + if ( specific()->canEraseRange(type) ) return specific()->eraseRange(type); + bool softErase = true; + if ( type!=Pic::MemoryRangeType::Code && (!specific()->canReadRange(Pic::MemoryRangeType::Code) + || !specific()->canWriteRange(Pic::MemoryRangeType::Code)) ) softErase = false; + if ( type!=Pic::MemoryRangeType::Eeprom && (!specific()->canReadRange(Pic::MemoryRangeType::Eeprom) + || !specific()->canWriteRange(Pic::MemoryRangeType::Eeprom)) ) softErase = false; + if ( type!=Pic::MemoryRangeType::Config && (!specific()->canReadRange(Pic::MemoryRangeType::Config) + || !specific()->canWriteRange(Pic::MemoryRangeType::Config)) ) softErase = false; + if ( type!=Pic::MemoryRangeType::UserId && (!specific()->canReadRange(Pic::MemoryRangeType::UserId) + || !specific()->canWriteRange(Pic::MemoryRangeType::UserId)) ) softErase = false; + if ( !softErase ) { + log(Log::LineType::SoftError, i18n("Cannot erase specified range because of programmer limitations.")); + return false; + } + if ( !askContinue(i18n("%1: Erasing this range only is not supported with this programmer. This will erase the whole chip and restore the other memory ranges.").arg(type.label())) ) { + logUserAbort(); + return false; + } + if ( type!=Pic::MemoryRangeType::Code && !preserveCode() ) return false; + if ( type!=Pic::MemoryRangeType::Eeprom && !preserveEeprom() ) return false; + if ( type!=Pic::MemoryRangeType::UserId && !readRange(Pic::MemoryRangeType::UserId, _deviceMemory, 0) ) return false; + specific()->erase(_hasProtectedCode || _hasProtectedEeprom); + if ( type!=Pic::MemoryRangeType::Code && !programAndVerifyRange(Pic::MemoryRangeType::Code, *_deviceMemory) ) return false; + if ( type!=Pic::MemoryRangeType::Eeprom && !programAndVerifyRange(Pic::MemoryRangeType::Eeprom, *_deviceMemory) ) return false; + if ( type!=Pic::MemoryRangeType::UserId && !programAndVerifyRange(Pic::MemoryRangeType::UserId, *_deviceMemory) ) return false; + if ( !programAndVerifyRange(Pic::MemoryRangeType::Config, *_deviceMemory) ) return false; + return true; +} + +//----------------------------------------------------------------------------- +bool Programmer::PicBase::readSingle(Pic::MemoryRangeType type, Pic::Memory &memory) +{ + if ( !specific()->canReadRange(type) ) { + log(Log::LineType::SoftError, i18n("The selected programmer cannot read the specified memory range.")); + return false; + } + Pic::Memory tmp(*device()); + if ( !read(tmp, Pic::MemoryRange(type)) ) return false; + memory.copyFrom(type, tmp); + if ( type==Pic::MemoryRangeType::Cal ) memory.copyFrom(Pic::MemoryRangeType::CalBackup, tmp); + return true; +} + +bool Programmer::PicBase::readRange(Pic::MemoryRangeType type, Pic::Memory *memory, const VerifyData *vd) +{ + if ( !device()->isReadable(type) ) return true; + if ( !specific()->canReadRange(type) ) { + log(Log::LineType::Information, i18n("The selected programmer cannot read %1: operation skipped.").arg(type.label())); + return true; + } + VerifyData *vdata = (vd ? new VerifyData(vd->actions, vd->memory) : 0); + if (vdata) { + log(Log::LineType::Information, i18n(" Verify memory: %1").arg(type.label())); + if ( !(vdata->actions & IgnoreProtectedVerify) ) { + vdata->protectedRanges = static_cast<const Pic::Memory &>(vdata->memory).protectedRanges(Pic::Protection::ProgramProtected, type); + if ( !vdata->protectedRanges.isEmpty() ) log(Log::LineType::Warning, i18n(" Part of device memory is protected (in %1) and cannot be verified.") + .arg(type.label())); + } else vdata->protectedRanges.clear(); + } else { + log(Log::LineType::Information, i18n(" Read memory: %1").arg(type.label())); + CRASH_ASSERT(memory); + } + Device::Array data; + bool ok = specific()->read(type, data, vdata); + delete vdata; + if (!ok) return false; + if (memory) memory->setArray(type, data); + return true; +} + +bool Programmer::PicBase::checkRead() +{ + if ( device()->memoryTechnology()==Device::MemoryTechnology::Romless ) { + log(Log::LineType::SoftError, i18n("Cannot read ROMless device.")); + return false; + } + return true; +} + +bool Programmer::PicBase::internalRead(Device::Memory *memory, const Device::MemoryRange &range, const VerifyData *vdata) +{ + if ( !initProgramming(Task::Read) ) return false; + Pic::Memory *pmemory = static_cast<Pic::Memory *>(memory); + if ( !range.all() ) { + Pic::MemoryRangeType type = static_cast<const Pic::MemoryRange &>(range)._type; + if ( type==Pic::MemoryRangeType::Cal ) { + if ( !readRange(Pic::MemoryRangeType::Cal, pmemory, vdata) ) return false; + return readRange(Pic::MemoryRangeType::CalBackup, pmemory, vdata); + } + return readRange(type, pmemory, vdata); + } + if ( !readRange(Pic::MemoryRangeType::Config, pmemory, vdata) ) return false; + if ( !readRange(Pic::MemoryRangeType::UserId, pmemory, vdata) ) return false; + if ( vdata==0 ) if ( !readRange(Pic::MemoryRangeType::Cal, pmemory, 0) ) return false; + if ( vdata==0 ) if ( !readRange(Pic::MemoryRangeType::CalBackup, pmemory, 0) ) return false; + if ( !readRange(Pic::MemoryRangeType::Code, pmemory, vdata) ) return false; + if ( !readRange(Pic::MemoryRangeType::Eeprom, pmemory, vdata) ) return false; + return true; +} + +//----------------------------------------------------------------------------- +bool Programmer::PicBase::programSingle(Pic::MemoryRangeType type, const Pic::Memory &memory) +{ + if ( !specific()->canWriteRange(type) ) { + log(Log::LineType::SoftError, i18n("The selected programmer cannot read the specified memory range.")); + return false; + } + return program(memory, Pic::MemoryRange(type)); +} + +bool Programmer::PicBase::programRange(Pic::MemoryRangeType mtype, const Device::Array &data) +{ + log(Log::LineType::Information, i18n(" Write memory: %1").arg(mtype.label())); + bool only = ( readConfigEntry(Config::OnlyProgramNonMask).toBool() + && (mtype==Pic::MemoryRangeType::Code || mtype==Pic::MemoryRangeType::Eeprom) ); + return specific()->write(mtype, data, !only); +} + +bool Programmer::PicBase::programAndVerifyRange(Pic::MemoryRangeType type, const Pic::Memory &memory) +{ + if ( !device()->isWritable(type) || !specific()->canWriteRange(type) ) return true; + Device::Array data = memory.arrayForWriting(type); + if ( !programRange(type, data) ) return false; + if ( !readConfigEntry(Config::VerifyAfterProgram).toBool() ) return true; + if ( !specific()->canReadRange(type) ) return true; + VerifyActions actions = IgnoreProtectedVerify; + if ( type==Pic::MemoryRangeType::Code && readConfigEntry(Config::OnlyVerifyProgrammed).toBool() ) actions |= OnlyProgrammedVerify; + VerifyData vdata(actions, memory); + return readRange(type, 0, &vdata); +} + +bool Programmer::PicBase::programAll(const Pic::Memory &memory) +{ + if ( !programAndVerifyRange(Pic::MemoryRangeType::Code, memory) ) return false; + if ( readConfigEntry(Config::ProgramEeprom).toBool() ) { + const Pic::Memory &tmp = (readConfigEntry(Config::PreserveEeprom).toBool() ? *_deviceMemory : memory); + if ( !programAndVerifyRange(Pic::MemoryRangeType::Eeprom, tmp) ) return false; + } + if ( !programAndVerifyRange(Pic::MemoryRangeType::UserId, memory) ) return false; + if ( memory.isProtected(Pic::Protection::WriteProtected, Pic::MemoryRangeType::Config) ) { + log(Log::DebugLevel::Normal, " Config write protection is on: first program without it and then with it"); + Pic::Memory tmp(memory.device()); + tmp.copyFrom(Pic::MemoryRangeType::Config, memory); + tmp.setProtection(false, Pic::Protection::WriteProtected, Pic::MemoryRangeType::Config); + if ( !programAndVerifyRange(Pic::MemoryRangeType::Config, tmp) ) return false; + } + if ( !programAndVerifyRange(Pic::MemoryRangeType::Config, memory) ) return false; + return true; +} + +bool Programmer::PicBase::checkProgram(const Device::Memory &memory) +{ + if ( device()->memoryTechnology()==Device::MemoryTechnology::Rom || device()->memoryTechnology()==Device::MemoryTechnology::Romless ) { + log(Log::LineType::SoftError, i18n("Cannot write ROM or ROMless device.")); + return false; + } + if ( !group().isDebugger() && static_cast<const Pic::Memory &>(memory).hasDebugOn() ) { + if ( !askContinue(i18n("DEBUG configuration bit is on. Are you sure you want to continue programming the chip?")) ) { + logUserAbort(); + return false; + } + } + return true; +} + +bool Programmer::PicBase::internalProgram(const Device::Memory &memory, const Device::MemoryRange &range) +{ + if ( !initProgramming(Task::Erase) ) return false; + const Pic::Memory &pmemory = static_cast<const Pic::Memory &>(memory); + + // blank check if OTP device + bool eprom = ( device()->memoryTechnology()==Device::MemoryTechnology::Eprom ); + if (eprom) { + log(Log::LineType::Information, i18n(" EPROM device: blank checking first...")); + Pic::Memory memory(*device()); + VerifyData vdata(BlankCheckVerify, memory); + if ( !internalRead(0, range, &vdata) ) return false; + log(Log::LineType::Information, i18n(" Blank check successful")); + // check if protecting device + bool protectedCode = pmemory.isProtected(Pic::Protection::ProgramProtected, Pic::MemoryRangeType::Code); + bool protectedEeprom = pmemory.isProtected(Pic::Protection::ProgramProtected, Pic::MemoryRangeType::Eeprom); + if ( protectedCode || protectedEeprom ) { + log(Log::LineType::SoftError, i18n("Protecting code memory or data EEPROM on OTP devices is disabled as a security...")); + return false; + } + } + + // programming + bool ok = true; + if ( !range.all() ) { + Pic::MemoryRangeType type = static_cast<const Pic::MemoryRange &>(range)._type; + if ( (type==Pic::MemoryRangeType::Code && _hasProtectedCode) || (type==Pic::MemoryRangeType::Eeprom && _hasProtectedEeprom) ) { + log(Log::LineType::SoftError, i18n("This memory range is programming protected.")); + return false; + } + if ( specific()->canEraseRange(type) ) { + if ( !specific()->emulatedErase() && !eraseRange(type) ) return false; + } else log(Log::LineType::Warning, i18n("The range cannot be erased first by the selected programmer so programming may fail...")); + ok = programRange(type, pmemory.arrayForWriting(type)); + VerifyData vdata(NormalVerify, pmemory); + if (ok) ok = readRange(type, 0, &vdata); + } else { + if ( !eprom ) { + if ( specific()->canEraseAll() ) { + if ( !specific()->emulatedErase() ) { + log(Log::LineType::Information, i18n(" Erasing device")); + ok = ( !readConfigEntry(Config::PreserveEeprom).toBool() || preserveEeprom() ); + if (ok) ok = eraseAll(); + } + } else log(Log::LineType::Warning, i18n("The device cannot be erased first by the selected programmer so programming may fail...")); + } + if (ok) ok = programAll(pmemory); + } + if ( !restoreBandGapBits() ) return false; + return ok; +} + +//----------------------------------------------------------------------------- +bool Programmer::PicBase::checkProgramCalibration(const Device::Array &data) +{ + QString message, s = prettyCalibration(data); + if ( !device()->checkCalibration(data, &message) ) { + sorry(i18n("The calibration word %1 is not valid.").arg(s), message); + return false; + } + return askContinue(i18n("Do you want to overwrite the device calibration with %1?").arg(s)); +} + +bool Programmer::PicBase::tryProgramCalibration(const Device::Array &data, bool &success) +{ + log(Log::LineType::Information, i18n(" Write memory: %1").arg(Pic::MemoryRangeType(Pic::MemoryRangeType::Cal).label())); + success = true; + if ( !specific()->write(Pic::MemoryRangeType::Cal, data, true) ) return false; + Device::Array read; + if ( !specific()->read(Pic::MemoryRangeType::Cal, read, 0) ) return false; + for (uint i=0; i<data.count(); i++) + if ( data[i]!=read[i] ) success = false; + if ( !success ) return true; + if ( device()->isWritable(Pic::MemoryRangeType::CalBackup) ) { + if ( !specific()->read(Pic::MemoryRangeType::CalBackup, read, 0) ) return false; + if ( device()->checkCalibration(read) ) return true; // do not overwrite correct backup value + log(Log::LineType::Information, i18n(" Write memory: %1").arg(Pic::MemoryRangeType(Pic::MemoryRangeType::CalBackup).label())); + if ( !specific()->write(Pic::MemoryRangeType::CalBackup, data, true) ) return false; + if ( !specific()->read(Pic::MemoryRangeType::CalBackup, read, 0) ) return false; + for (uint i=0; i<data.count(); i++) + if ( data[i]!=read[i] ) success = false; + } + return true; +} + +bool Programmer::PicBase::internalProgramCalibration(const Device::Array &data) +{ + if ( !initProgramming(Task::Write) ) return false; + // try without erase + bool success; + if ( !tryProgramCalibration(data, success) ) return false; + if (success) return true; + if ( !askContinue(i18n("Programming calibration data needs a chip erase. Continue anyway?")) ) { + logUserAbort(); + return false; + } + log(Log::LineType::Information, i18n(" Erasing device")); + bool ok = specific()->erase(_hasProtectedCode || _hasProtectedEeprom); + if ( !restoreBandGapBits() ) return false; + if ( !ok ) return false; + // retry + if ( !tryProgramCalibration(data, success) ) return false; + return success; +} + +bool Programmer::PicBase::programCalibration(const Device::Array &data) +{ + _progressMonitor.clear(); + bool ok = doProgramCalibration(data); + endProgramming(); + return ok; +} + +bool Programmer::PicBase::doProgramCalibration(const Device::Array &data) +{ + if ( !checkProgramCalibration(data) ) return false; + if ( !doConnectDevice() ) return false; + log(Log::LineType::Information, i18n("Programming calibration...")); + emit actionMessage(i18n("Programming calibration...")); + if ( !internalProgramCalibration(data) ) return false; + log(Log::LineType::Information, i18n("Programming calibration successful")); + return true; +} + +//----------------------------------------------------------------------------- +bool Programmer::PicBase::verifySingle(Pic::MemoryRangeType type, const Pic::Memory &memory) +{ + return verify(memory, Pic::MemoryRange(type)); +} + +bool Programmer::PicBase::blankCheckSingle(Pic::MemoryRangeType type) +{ + return blankCheck(Pic::MemoryRange(type)); +} diff --git a/src/devices/pic/prog/pic_prog.h b/src/devices/pic/prog/pic_prog.h new file mode 100644 index 0000000..0fb37f7 --- /dev/null +++ b/src/devices/pic/prog/pic_prog.h @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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. * + ***************************************************************************/ +#ifndef PIC_PROG_H +#define PIC_PROG_H + +#include "pic_prog_specific.h" +#include "progs/base/prog_group.h" +#include "devices/base/device_group.h" + +namespace Pic +{ + +class MemoryRange : public Device::MemoryRange { +public: + MemoryRange(MemoryRangeType type) : _type(type) {} + virtual bool all() const { return _type==MemoryRangeType::Nb_Types; } + MemoryRangeType _type; +}; + +} //namespace + +namespace Programmer +{ +//----------------------------------------------------------------------------- +class PicGroup : public Group +{ +public: + virtual bool canReadVoltage(Pic::VoltageType) const { return false; } + virtual bool canReadVoltages() const; + virtual ::Debugger::DeviceSpecific *createDebuggerDeviceSpecific(::Debugger::Base &base) const; +}; + +//----------------------------------------------------------------------------- +class PicBase : public Base +{ +public: + PicBase(const Group &group, const Pic::Data *data, const char *name); + virtual ~PicBase(); + PicDeviceSpecific *specific() { return static_cast<PicDeviceSpecific *>(_specific); } + const PicDeviceSpecific *specific() const { return static_cast<PicDeviceSpecific *>(_specific); } + const Pic::Data *device() const { return static_cast<const Pic::Data *>(_device); } + const Pic::Memory &deviceMemory() const { return *_deviceMemory; } + const PicGroup &group() const { return static_cast<const PicGroup &>(_group); } + double voltage(Pic::VoltageType type) const { return _voltages[type].value; } + virtual bool readVoltages(); + bool getTargetMode(Pic::TargetMode &mode); + + bool eraseSingle(Pic::MemoryRangeType type); + bool readSingle(Pic::MemoryRangeType type, Pic::Memory &memory); + bool programSingle(Pic::MemoryRangeType type, const Pic::Memory &memory); + bool verifySingle(Pic::MemoryRangeType type, const Pic::Memory &memory); + bool blankCheckSingle(Pic::MemoryRangeType type); + bool readCalibration(); + bool programCalibration(const Device::Array &data); + +protected: + PicHardware *hardware() { return static_cast<PicHardware *>(_hardware); } + virtual bool internalSetupHardware(); + virtual double vdd() const { return _voltages[Pic::TargetVdd].value; } + virtual double vpp() const { return _voltages[Pic::TargetVpp].value; } + virtual bool verifyDeviceId(); + virtual uint nbSteps(Task task, const Device::MemoryRange *range) const; + bool initProgramming(Task task); + virtual bool initProgramming(); + virtual bool internalRun(); + virtual bool internalStop(); + virtual void clear(); + + virtual bool checkErase(); + virtual bool internalErase(const Device::MemoryRange &range); + + virtual bool checkRead(); + virtual bool internalRead(Device::Memory *memory, const Device::MemoryRange &range, const VerifyData *data); + bool readRange(Pic::MemoryRangeType type, Pic::Memory *memory, const VerifyData *data); + + virtual bool checkProgram(const Device::Memory &memory); + virtual bool internalProgram(const Device::Memory &memory, const Device::MemoryRange &range); + virtual bool programAll(const Pic::Memory &memory); + bool programAndVerifyRange(Pic::MemoryRangeType type, const Pic::Memory &memory); + bool programRange(Pic::MemoryRangeType type, const Device::Array &array); + +private: + Pic::Memory *_deviceMemory; + bool _hasProtectedCode, _hasProtectedEeprom; + PicHardware::VoltagesData _voltages; + + BitValue readDeviceId(); + bool eraseAll(); + bool eraseRange(Pic::MemoryRangeType type); + bool restoreCalibration(); + bool restoreBandGapBits(); + bool doProgramCalibration(const Device::Array &data); + bool checkProgramCalibration(const Device::Array &data); + bool internalProgramCalibration(const Device::Array &data); + QString prettyCalibration(const Device::Array &data) const; + bool tryProgramCalibration(const Device::Array &data, bool &success); + bool preserveCode(); + bool preserveEeprom(); + bool internalEraseRange(Pic::MemoryRangeType type); +}; + +} // namespace + +#endif diff --git a/src/devices/pic/prog/pic_prog_specific.cpp b/src/devices/pic/prog/pic_prog_specific.cpp new file mode 100644 index 0000000..bfcd2fa --- /dev/null +++ b/src/devices/pic/prog/pic_prog_specific.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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 "pic_prog_specific.h" + +#include "common/global/global.h" + +//----------------------------------------------------------------------------- +const char * const Pic::VOLTAGE_TYPE_LABELS[Nb_VoltageTypes] = { + I18N_NOOP("Programmer Vpp"), I18N_NOOP("Target Vdd"), I18N_NOOP("Target Vpp") +}; + +const char * const Pic::TARGET_MODE_LABELS[Nb_TargetModes] = { + I18N_NOOP("Stopped"), I18N_NOOP("Running"), I18N_NOOP("In Programming") +}; + +const char * const Pic::RESET_MODE_LABELS[Nb_ResetModes] = { + I18N_NOOP("Reset Held"), I18N_NOOP("Reset Released") +}; + +//----------------------------------------------------------------------------- +uint Programmer::PicDeviceSpecific::findNonMaskStart(Pic::MemoryRangeType type, const Device::Array &data) const +{ + uint start = 0; + for (; start<data.count(); start++) + if ( data[start]!=device().mask(type) ) break; + const_cast<PicDeviceSpecific *>(this)->log(Log::DebugLevel::Normal, QString("start before align: %1").arg(start)); + uint align = device().nbWordsWriteAlignment(type); + start -= start % align; + const_cast<PicDeviceSpecific *>(this)->log(Log::DebugLevel::Normal, QString("start after align: %1 (align=%2)").arg(start).arg(align)); + return start; +} + +uint Programmer::PicDeviceSpecific::findNonMaskEnd(Pic::MemoryRangeType type, const Device::Array &data) const +{ + uint end = data.count()-1; + for (; end>0; end--) + if ( data[end]!=device().mask(type) ) break; + const_cast<PicDeviceSpecific *>(this)->log(Log::DebugLevel::Normal, QString("end before align: %1").arg(end)); + uint align = device().nbWordsWriteAlignment(type); + if ( (end+1) % align ) end += align - (end+1) % align; + const_cast<PicDeviceSpecific *>(this)->log(Log::DebugLevel::Normal, QString("end after align: %1 (align=%2)").arg(end).arg(align)); + Q_ASSERT(end<data.count()); + return end; +} + +bool Programmer::PicDeviceSpecific::read(Pic::MemoryRangeType type, Device::Array &data, const VerifyData *vdata) +{ + setPowerOn(); + bool ok = doRead(type, data, vdata); + setPowerOff(); + return ok; +} + +bool Programmer::PicDeviceSpecific::write(Pic::MemoryRangeType mtype, const Device::Array &data, bool force) +{ + setPowerOn(); + bool ok = doWrite(mtype, data, force); + setPowerOff(); + return ok; +} + +bool Programmer::PicDeviceSpecific::erase(bool isProtected) +{ + setPowerOn(); + bool ok = doErase(isProtected); + setPowerOff(); + return ok; +} + +bool Programmer::PicDeviceSpecific::eraseRange(Pic::MemoryRangeType type) +{ + setPowerOn(); + bool ok = doEraseRange(type); + setPowerOff(); + return ok; +} + +bool Programmer::PicDeviceSpecific::doEmulatedEraseRange(Pic::MemoryRangeType type) +{ + Pic::Memory memory(device()); + if ( !doWrite(type, memory.arrayForWriting(type), true) ) return false; + if ( !canReadRange(type) ) return true; + VerifyData vdata(BlankCheckVerify, memory); + Device::Array data; + return doRead(type, data, &vdata); +} + +//----------------------------------------------------------------------------- +bool Programmer::PicHardware::compareWords(Pic::MemoryRangeType type, uint index, BitValue v, BitValue d, Programmer::VerifyActions actions) +{ + if ( v==d ) return true; + uint inc = device().addressIncrement(type); + Address address = device().range(type).start + inc * index; + if ( actions & ::Programmer::BlankCheckVerify ) + log(Log::LineType::SoftError, i18n("Device memory is not blank (in %1 at address %2: reading %3 and expecting %4).") + .arg(type.label()).arg(toHexLabel(address, device().nbCharsAddress())) + .arg(toHexLabel(d, device().nbCharsWord(type))).arg(toHexLabel(v, device().nbCharsWord(type)))); + else log(Log::LineType::SoftError, i18n("Device memory does not match hex file (in %1 at address %2: reading %3 and expecting %4).") + .arg(type.label()).arg(toHexLabel(address, device().nbCharsAddress())) + .arg(toHexLabel(d, device().nbCharsWord(type))).arg(toHexLabel(v, device().nbCharsWord(type)))); + return false; +} + +bool Programmer::PicHardware::verifyWord(uint i, BitValue word, Pic::MemoryRangeType type, const VerifyData &vdata) +{ + if ( !(vdata.actions & ::Programmer::IgnoreProtectedVerify) && vdata.protectedRanges.contains(i) ) return true; // protected + BitValue v = static_cast<const Pic::Memory &>(vdata.memory).normalizedWord(type, i); + BitValue d = static_cast<const Pic::Memory &>(vdata.memory).normalizeWord(type, i, word); + if ( type==Pic::MemoryRangeType::Config ) { + BitValue pmask = device().config()._words[i].pmask; + v = v.clearMaskBits(pmask); + d = d.clearMaskBits(pmask); + } + return compareWords(type, i, v, d, vdata.actions); +} diff --git a/src/devices/pic/prog/pic_prog_specific.h b/src/devices/pic/prog/pic_prog_specific.h new file mode 100644 index 0000000..fef8a61 --- /dev/null +++ b/src/devices/pic/prog/pic_prog_specific.h @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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. * + ***************************************************************************/ +#ifndef PIC_PROG_SPECIFIC_H +#define PIC_PROG_SPECIFIC_H + +#include "progs/base/prog_specific.h" +#include "progs/base/generic_prog.h" +#include "devices/pic/pic/pic_memory.h" + +//---------------------------------------------------------------------------- +namespace Pic +{ + enum ResetMode { ResetHeld = 0, ResetReleased, Nb_ResetModes}; + extern const char * const RESET_MODE_LABELS[Nb_ResetModes]; + + enum VoltageType { ProgrammerVpp = 0, TargetVdd, TargetVpp, Nb_VoltageTypes }; + extern const char * const VOLTAGE_TYPE_LABELS[Nb_VoltageTypes]; + + enum TargetMode { TargetStopped = 0, TargetRunning, TargetInProgramming, Nb_TargetModes}; + extern const char * const TARGET_MODE_LABELS[Nb_TargetModes]; + + enum WriteMode { WriteOnlyMode = 0, EraseWriteMode, Nb_WriteModes }; +} // namespace + +namespace Programmer +{ +//----------------------------------------------------------------------------- +class PicDeviceSpecific : public DeviceSpecific +{ +public: + PicDeviceSpecific(::Programmer::Base &base) : DeviceSpecific(base) {} + const Pic::Data &device() const { return static_cast<const Pic::Data &>(*_base.device()); } + virtual bool canEraseAll() const = 0; + virtual bool canEraseRange(Pic::MemoryRangeType type) const = 0; + virtual bool emulatedErase() const { return false; } + virtual bool canReadRange(Pic::MemoryRangeType type) const = 0; + virtual bool canWriteRange(Pic::MemoryRangeType type) const = 0; + bool eraseRange(Pic::MemoryRangeType type); + bool erase(bool isProtected); + bool read(Pic::MemoryRangeType type, Device::Array &data, const VerifyData *vdata); + bool write(Pic::MemoryRangeType type, const Device::Array &data, bool force); + uint findNonMaskStart(Pic::MemoryRangeType type, const Device::Array &data) const; + uint findNonMaskEnd(Pic::MemoryRangeType type, const Device::Array &data) const; + +protected: + virtual bool doErase(bool isProtected) = 0; + virtual bool doEraseRange(Pic::MemoryRangeType type) = 0; + bool doEmulatedEraseRange(Pic::MemoryRangeType type); + virtual bool doRead(Pic::MemoryRangeType type, Device::Array &data, const VerifyData *vdata) = 0; + virtual bool doWrite(Pic::MemoryRangeType type, const Device::Array &data, bool force) = 0; +}; + +//----------------------------------------------------------------------------- +class PicHardware : public Hardware +{ +public: + class VoltageData { + public: + VoltageData() : value(UNKNOWN_VOLTAGE) {} + double value; + bool error; + }; + class VoltagesData : public QValueVector<VoltageData> { + public: + VoltagesData() : QValueVector<VoltageData>(Pic::Nb_VoltageTypes) {} + }; + +public: + PicHardware(::Programmer::Base &base, Port::Base *port, const QString &name) : Hardware(base, port, name) {} + const Pic::Data &device() const { return static_cast<const Pic::Data &>(*_base.device()); } + virtual bool readVoltages(VoltagesData &) { return true; } + virtual bool getTargetMode(Pic::TargetMode &mode) { mode = Pic::TargetInProgramming; return true; } + virtual bool setTargetReset(Pic::ResetMode) { return true; } + bool compareWords(Pic::MemoryRangeType type, uint index, BitValue v, BitValue d, VerifyActions actions); + bool verifyWord(uint index, BitValue word, Pic::MemoryRangeType type, const VerifyData &vdata); +}; + +} // namespace + +#endif diff --git a/src/devices/pic/prog/prog.pro b/src/devices/pic/prog/prog.pro new file mode 100644 index 0000000..c0caf87 --- /dev/null +++ b/src/devices/pic/prog/prog.pro @@ -0,0 +1,6 @@ +STOPDIR = ../../../.. +include($${STOPDIR}/lib.pro) + +TARGET = picprog +HEADERS += pic_prog.h pic_debug.h pic_prog_specific.h +SOURCES += pic_prog.cpp pic_debug.cpp pic_prog_specific.cpp |