summaryrefslogtreecommitdiffstats
path: root/src/devices/pic/prog
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 18:42:24 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 18:42:24 +0000
commitf508189682b6fba62e08feeb1596f682bad5fff9 (patch)
tree28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/devices/pic/prog
downloadpiklab-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.am5
-rw-r--r--src/devices/pic/prog/pic_debug.cpp118
-rw-r--r--src/devices/pic/prog/pic_debug.h65
-rw-r--r--src/devices/pic/prog/pic_prog.cpp751
-rw-r--r--src/devices/pic/prog/pic_prog.h110
-rw-r--r--src/devices/pic/prog/pic_prog_specific.cpp121
-rw-r--r--src/devices/pic/prog/pic_prog_specific.h86
-rw-r--r--src/devices/pic/prog/prog.pro6
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