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/base | |
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/base')
-rw-r--r-- | src/devices/pic/base/Makefile.am | 6 | ||||
-rw-r--r-- | src/devices/pic/base/base.pro | 6 | ||||
-rw-r--r-- | src/devices/pic/base/pic.cpp | 426 | ||||
-rw-r--r-- | src/devices/pic/base/pic.h | 179 | ||||
-rw-r--r-- | src/devices/pic/base/pic_config.cpp | 456 | ||||
-rw-r--r-- | src/devices/pic/base/pic_config.h | 107 | ||||
-rw-r--r-- | src/devices/pic/base/pic_protection.cpp | 361 | ||||
-rw-r--r-- | src/devices/pic/base/pic_protection.h | 60 | ||||
-rw-r--r-- | src/devices/pic/base/pic_register.cpp | 287 | ||||
-rw-r--r-- | src/devices/pic/base/pic_register.h | 115 |
10 files changed, 2003 insertions, 0 deletions
diff --git a/src/devices/pic/base/Makefile.am b/src/devices/pic/base/Makefile.am new file mode 100644 index 0000000..ebade1c --- /dev/null +++ b/src/devices/pic/base/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libpicbase.la +libpicbase_la_SOURCES = pic.cpp pic_config.cpp pic_protection.cpp \ + pic_register.cpp diff --git a/src/devices/pic/base/base.pro b/src/devices/pic/base/base.pro new file mode 100644 index 0000000..621d6d3 --- /dev/null +++ b/src/devices/pic/base/base.pro @@ -0,0 +1,6 @@ +STOPDIR = ../../../.. +include($${STOPDIR}/lib.pro) + +TARGET = picbase +HEADERS += pic_protection.h pic_config.h pic_register.h pic.h +SOURCES += pic_protection.cpp pic_config.cpp pic_register.cpp pic.cpp diff --git a/src/devices/pic/base/pic.cpp b/src/devices/pic/base/pic.cpp new file mode 100644 index 0000000..8f81540 --- /dev/null +++ b/src/devices/pic/base/pic.cpp @@ -0,0 +1,426 @@ +/*************************************************************************** + * Copyright (C) 2005 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.h" + +#include "common/global/global.h" +#include "common/common/misc.h" +#include "common/global/purl.h" +#include "pic_register.h" +#include "pic_config.h" + +//------------------------------------------------------------------------------ +const Pic::ProgVoltageType::Data Pic::ProgVoltageType::DATA[Nb_Types] = { + { "vpp", 0 }, + { "vdd_prog", 0 }, + { "vdd_prog_write", 0 } +}; + +const Pic::MemoryRangeType::Data Pic::MemoryRangeType::DATA[Nb_Types] = { + { "code", I18N_NOOP("Code memory"), Writable }, + { "calibration", I18N_NOOP("Calibration"), Writable }, + { "user_ids", I18N_NOOP("User IDs"), Writable }, + { "device_id", I18N_NOOP("Device ID"), ReadOnly }, + { "config", I18N_NOOP("Configuration Bits"), Writable }, + { "eeprom", I18N_NOOP("Data EEPROM"), Writable }, + { "debug_vector", I18N_NOOP("Debug Vector"), Writable }, + { "hardware_stack", I18N_NOOP("Hardware Stack"), ReadOnly }, + { "calibration_backup", I18N_NOOP("Calibration Backup"), Writable }, + { "program_executive", I18N_NOOP("Program Executive"), Writable } +}; + +const Pic::SelfWrite::Data Pic::SelfWrite::DATA[Nb_Types] = { + { "yes", 0 }, + { "no", 0 } +}; + +const Pic::DeviceType::Data Pic::DeviceType::DATA[Nb_Types] = { + { 0, I18N_NOOP("Normal") }, + { 0, I18N_NOOP("J") }, + { 0, I18N_NOOP("K") } +}; + +const Pic::Architecture::Data Pic::Architecture::DATA[Nb_Types] = { +// name family_label nbBytesPC nbBytesWord packed nbBitsRegister registerBankLength +// {Code, Cal, UserID, DevId, Conf, EEPROM, DebugVec, HardStack, CalBackup, Program Executive} randomAccess + { "10X", I18N_NOOP("Baseline Family"), 0, 2, false, 8, 0x020, { 12, 12, 12, 12, 12, 8, 12, 0, 12, 0 }, false, SelfWrite::No, DeviceType::Normal }, // 9, 10, 11 or 12-bit program counter + { "16X", I18N_NOOP("Midrange Family"), 13, 2, false, 8, 0x080, { 14, 14, 14, 14, 14, 8, 14, 0, 14, 0 }, false, SelfWrite::Nb_Types, DeviceType::Normal }, // max eeprom: 256 words + { "17C", I18N_NOOP("17C Family"), 16, 2, false, 8, 0x100, { 16, 0, 0, 0, 16, 8, 0, 0, 0, 0 }, true, SelfWrite::No, DeviceType::Normal }, + { "18C", I18N_NOOP("18C Family"), 21, 2, true, 8, 0x100, { 16, 8, 8, 8, 8, 8, 16, 0, 8, 0 }, true, SelfWrite::No, DeviceType::Normal }, + { "18F", I18N_NOOP("18F Family"), 21, 2, true, 8, 0x100, { 16, 8, 8, 8, 8, 8, 16, 0, 8, 0 }, true, SelfWrite::Nb_Types, DeviceType::Normal }, + { "18J", I18N_NOOP("18J Family"), 21, 2, true, 8, 0x100, { 16, 8, 8, 8, 8, 8, 16, 0, 8, 0 }, true, SelfWrite::Yes, DeviceType::J }, + { "24F", I18N_NOOP("24F Family"), 23, 4, false, 16, 0x800, { 24, 0, 0, 16, 24, 0, 24, 0, 0, 24 }, true, SelfWrite::Yes, DeviceType::J }, + { "24H", I18N_NOOP("24H Family"), 23, 4, false, 16, 0x800, { 24, 0, 8, 16, 8, 0, 24, 0, 0, 24 }, true, SelfWrite::Yes, DeviceType::J }, + { "30F", I18N_NOOP("30F Family"), 23, 4, false, 16, 0xA00, { 24, 0, 24, 16, 16, 16, 24, 0, 0, 24 }, true, SelfWrite::Yes, DeviceType::Normal }, // dsPIC: eeprom max = 2 kwords = 4 kbytes + { "33F", I18N_NOOP("33F Family"), 23, 4, false, 16, 0x800, { 24, 0, 8, 16, 8, 0, 24, 0, 0, 24 }, true, SelfWrite::Yes, DeviceType::J } +}; + +const Pic::Checksum::Algorithm::Data Pic::Checksum::Algorithm::DATA[Nb_Types] = { + { "", 0 }, + { "XOR4", 0 }, + { "XNOR7", 0 }, + { "XNOR8", 0 } +}; + +const Pic::Feature::Data Pic::Feature::DATA[Nb_Types] = { + { "ccp", I18N_NOOP("CCP") }, + { "adc", I18N_NOOP("ADC") }, + { "ssp", I18N_NOOP("SSP") }, + { "lvd", I18N_NOOP("Low Voltage Detect") }, + { "usb", I18N_NOOP("USB") }, + { "usart", I18N_NOOP("USART") }, + { "can", I18N_NOOP("CAN") }, + { "ecan", I18N_NOOP("ECAN") }, + { "ethernet", I18N_NOOP("Ethernet") }, + { "lcd", I18N_NOOP("LCD") }, + { "motor_control", I18N_NOOP("Motor Control") }, + { "motion_feedback", I18N_NOOP("Motion Feeback") }, + { "self_write", I18N_NOOP("Self-Write") } +}; + +//----------------------------------------------------------------------------- +Pic::Data::Data() + : Device::Data(new RegistersData(*this)) +{ + FOR_EACH(ProgVoltageType, type) { + _voltages[type].min = 0.0; + _voltages[type].max = 0.0; + _voltages[type].nominal = 0.0; + } + FOR_EACH(MemoryRangeType, type) { + _ranges[type].properties = NotPresent; + _ranges[type].start = 0; + _ranges[type].end = 0; + _ranges[type].hexFileOffset = 0; + } + _config = new Config(*this); + _calibration.opcode = 0; + _calibration.opcodeMask = 0; +} + +Pic::Data::~Data() +{ + delete _config; +} + +bool Pic::Data::isReadable(MemoryRangeType type) const +{ + return ( range(type).properties & Programmable ); +} + +bool Pic::Data::isWritable(MemoryRangeType type) const +{ + return ( (type.data().properties & Writable) && (range(type).properties & Programmable) ); +} + +uint Pic::Data::addressIncrement(MemoryRangeType type) const +{ + uint inc = _architecture.data().nbBytesWord; + if ( _architecture.data().packed + && ( type==MemoryRangeType::Code || type==MemoryRangeType::DebugVector ) ) return inc; + return inc / 2; +} + +uint Pic::Data::nbWords(MemoryRangeType type) const +{ + if ( !isPresent(type) ) return 0; + return nbAddresses(type) / addressIncrement(type); +} + +uint Pic::Data::nbAddresses(MemoryRangeType type) const +{ + if ( !isPresent(type) ) return 0; + return (range(type).end - range(type).start + 1); +} + +QString Pic::Data::fname(Device::Special special) const +{ + QString s = name(); + switch (special.type()) { + case Device::Special::Normal: break; + case Device::Special::LowPower: + // assume name is of form "NNX..." + s.insert(2, 'L'); + break; + case Device::Special::LowVoltage: + // assume name is of form "NNXN..." + s.replace(2, 1, "LV"); + break; + case Device::Special::HighVoltage: + // assume name is of form "NNXN..." + s.replace(2, 1, "HV"); + break; + case Device::Special::Nb_Types: Q_ASSERT(false); break; + } + return s; +} + +bool Pic::Data::matchId(BitValue rawId, Device::IdData &idata) const +{ + if ( !isPresent(MemoryRangeType::DeviceId) ) return false; + QMap<Device::Special, BitValue>::const_iterator it; + for (it=_ids.begin(); it!=_ids.end(); ++it) { + idata.special = it.key(); + BitValue nid = 0x0; + switch (architecture().type()) { + case Architecture::P10X: + case Architecture::P16X: + case Architecture::P17C: + case Architecture::P18C: + case Architecture::P18F: + case Architecture::P18J: + nid = rawId.clearMaskBits(0x1F); + idata.revision = rawId.maskWith(0x1F); + break; + case Architecture::P24F: + nid = (rawId >> 16).maskWith(0x3FFF); + idata.revision = (rawId >> 6).maskWith(0x7); + idata.minorRevision = rawId.maskWith(0x7); + break; + case Architecture::P30F: + nid = (rawId >> 16).maskWith(0xFFFF); + idata.revision = (rawId >> 6).maskWith(0x3F); + idata.minorRevision = rawId.maskWith(0x3F); + idata.process = (rawId >> 12).maskWith(0xF); + break; + case Architecture::P24H: + case Architecture::P33F: + nid = (rawId >> 16).maskWith(0xFFFF); + idata.revision = rawId.maskWith(0xFFFF); // ?? + break; + case Architecture::Nb_Types: Q_ASSERT(false); break; + } + if ( nid==it.data() ) return true; + } + return false; +} + +QStringList Pic::Data::idNames(const QMap<QString, Device::IdData> &ids) const +{ + QStringList list; + QMap<QString, Device::IdData>::const_iterator it; + for (it=ids.begin(); it!=ids.end(); ++it) { + switch (_architecture.type()) { + case Architecture::P10X: + case Architecture::P16X: + case Architecture::P17C: + case Architecture::P18C: + case Architecture::P18F: + case Architecture::P18J: + list += i18n("%1 (rev. %2)").arg(it.key()).arg(toLabel(it.data().revision)); + break; + case Architecture::P24F: + list += i18n("%1 (rev. %2.%3)").arg(it.key()).arg(toLabel(it.data().revision)).arg(toLabel(it.data().minorRevision)); + break; + case Architecture::P30F: + list += i18n("%1 (proc. %2; rev. %3.%4)").arg(it.key()).arg(toLabel(it.data().process)).arg(toLabel(it.data().revision)).arg(toLabel(it.data().minorRevision)); + break; + case Architecture::P24H: + case Architecture::P33F: + list += i18n("%1 (rev. %2)").arg(it.key()).arg(toLabel(it.data().revision)); + break; + case Architecture::Nb_Types: Q_ASSERT(false); break; + } + } + return list; +} + +bool Pic::Data::checkCalibration(const Device::Array &data, QString *message) const +{ + Q_ASSERT( nbWords(MemoryRangeType::Cal)==data.count() ); + for (uint i=0; i<data.count(); i++) { + QString address = toHexLabel(range(MemoryRangeType::Cal).start + i*addressIncrement(MemoryRangeType::Cal), nbCharsAddress()); + if ( data[i]==mask(MemoryRangeType::Cal) ) { + if (message) *message = i18n("Calibration word at address %1 is blank.").arg(address); + return false; + } + } + if ( data.count()==1 ) { + if ( data[0].maskWith(_calibration.opcodeMask)!=_calibration.opcode ) { + if (message) *message = i18n("Calibration word is not a compatible opcode (%2).") + .arg(toHexLabel(_calibration.opcode, nbCharsWord(MemoryRangeType::Code))); + return false; + } + } + return true; +} + +const Pic::RegistersData &Pic::Data::registersData() const +{ + return static_cast<const RegistersData &>(*_registersData); +} + +bool Pic::Data::hasFeature(Feature feature, bool *unknown) const +{ + bool ok = ( registersData().nbBanks!=0 ); + if (unknown) *unknown = !ok; + if (!ok) return false; + switch (feature.type()) { + case Feature::CCP: return registersData().sfrs.contains("CCP1CON"); + case Feature::ADC: return registersData().sfrs.contains("ADCON0"); + case Feature::SSP: return registersData().sfrs.contains("SSPCON"); + case Feature::LVD: return registersData().sfrs.contains("LVDCON"); + case Feature::USB: return registersData().sfrs.contains("UCON"); + case Feature::USART: + return ( registersData().sfrs.contains("TXSTA") // 16F + || registersData().sfrs.contains("TXSTA1") // 18F + || registersData().sfrs.contains("U1MODE") ); // 30F + case Feature::CAN: return registersData().sfrs.contains("CANCON") && !registersData().sfrs.contains("ECANCON"); + case Feature::ECAN: return registersData().sfrs.contains("ECANCON"); + case Feature::Ethernet: return registersData().sfrs.contains("ETHCON1"); + case Feature::LCD: return registersData().sfrs.contains("LCDCON"); + case Feature::MotorControl: return registersData().sfrs.contains("PWMCON0"); + case Feature::MotionFeedback: return registersData().sfrs.contains("CAP1CON"); + case Feature::SelfWrite: return _selfWrite==SelfWrite::Yes; + case Feature::Nb_Types: Q_ASSERT(false); break; + } + return false; +} + +Device::Array Pic::Data::gotoInstruction(Address address, bool withPageSelection) const +{ + Q_ASSERT( address<addressIncrement(MemoryRangeType::Code)*nbWords(MemoryRangeType::Code) ); + Device::Array a; + switch (_architecture.type()) { + case Architecture::P10X: + if ( nbWords(MemoryRangeType::Code)>0x1FF && withPageSelection) + a.append(0x4A3 | (address>0x1FF ? 0x100 : 0x000)); // bsf STATUS,PA0 or bcf STATUS,PA0 + a.append(0xA00 | (address.toUInt() & 0x1FF)); // goto + break; + case Architecture::P16X: + if ( nbWords(MemoryRangeType::Code)>0x7FF && withPageSelection ) { + if ( address<=0x7FF ) a.append(0x018A); // clrf PCLATH + else { + a.append(0x3000 | (address.toUInt() >> 8)); // movl high address + a.append(0x008A); // movwf PCLATH + } + } + a.append(0x2800 | (address.toUInt() & 0x7FF)); + break; + case Architecture::P17C: + a.append(0xC000 | (address.toUInt() & 0x1FFF)); + break; + case Architecture::P18C: + case Architecture::P18F: + case Architecture::P18J: + a.append(0xEF00 | ((address.toUInt()/2) & 0xFF)); + a.append(0xF000 | ((address.toUInt()/2) >> 8)); + break; + case Architecture::P24F: + case Architecture::P24H: + case Architecture::P30F: + case Architecture::P33F: + a.append(0x040000 | (address.toUInt() & 0x00FFFE)); + a.append(0X000000 | (address.toUInt() >> 16)); + break; + case Architecture::Nb_Types: Q_ASSERT(false); break; + } + return a; +} + +bool Pic::Data::isGotoInstruction(BitValue instruction) const +{ + switch (_architecture.type()) { + case Architecture::P10X: return ( instruction.maskWith(0xE00)==0xA00 ); + case Architecture::P16X: return ( instruction.maskWith(0xF800)==0x2800 ); + case Architecture::P17C: return ( instruction.maskWith(0xE000)==0xC000 ); + case Architecture::P18C: + case Architecture::P18F: + case Architecture::P18J: return ( instruction.maskWith(0xFF00)==0xEF00 ); + case Architecture::P24F: + case Architecture::P24H: + case Architecture::P30F: + case Architecture::P33F: return ( instruction.maskWith(0xFF0000)==0x040000 ); + case Architecture::Nb_Types: Q_ASSERT(false); break; + } + return false; +} + +uint Pic::Data::nbWordsWriteAlignment(MemoryRangeType type) const +{ + if ( type!=MemoryRangeType::Code ) return 1; + return QMAX(_nbWordsCodeWrite, uint(16)); +} + +//---------------------------------------------------------------------------- +QDataStream &operator <<(QDataStream &s, const Pic::VoltageData &vd) +{ + s << vd.min << vd.max << vd.nominal; + return s; +} +QDataStream &operator >>(QDataStream &s, Pic::VoltageData &vd) +{ + s >> vd.min >> vd.max >> vd.nominal; + return s; +} + +QDataStream &operator <<(QDataStream &s, const Pic::MemoryRangeData &mrd) +{ + s << Q_UINT8(mrd.properties) << mrd.start << mrd.end << mrd.hexFileOffset; + return s; +} +QDataStream &operator >>(QDataStream &s, Pic::MemoryRangeData &mrd) +{ + Q_UINT8 properties; + s >> properties >> mrd.start >> mrd.end >> mrd.hexFileOffset; + mrd.properties = Pic::MemoryRangeProperties(properties); + return s; +} + +QDataStream &operator <<(QDataStream &s, const Pic::Checksum::Data &cd) +{ + s << cd.constant << cd.bbsize << cd.algorithm << cd.protectedMaskNames; + s << cd.blankChecksum << cd.checkChecksum; + return s; +} +QDataStream &operator >>(QDataStream &s, Pic::Checksum::Data &cd) +{ + s >> cd.constant >> cd.bbsize >> cd.algorithm >> cd.protectedMaskNames; + s >> cd.blankChecksum >> cd.checkChecksum; + return s; +} + +QDataStream &operator <<(QDataStream &s, const Pic::CalibrationData &cd) +{ + s << cd.opcode << cd.opcodeMask; + return s; +} +QDataStream &operator >>(QDataStream &s, Pic::CalibrationData &cd) +{ + s >> cd.opcode >> cd.opcodeMask; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const Pic::Data &data) +{ + s << static_cast<const Device::Data &>(data); + s << data._architecture << data._ids << data._nbBitsPC; + s << data._voltages << data._ranges; + s << data._userIdRecommendedMask; + s << *data._config; + s << data._checksums; + s << data._calibration; + s << static_cast<const Pic::RegistersData &>(*data._registersData); + s << data._nbWordsCodeWrite << data._nbWordsCodeRowErase; + s << data._selfWrite; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, Pic::Data &data) +{ + s >> static_cast<Device::Data &>(data); + s >> data._architecture >> data._ids >> data._nbBitsPC; + s >> data._voltages >> data._ranges; + s >> data._userIdRecommendedMask; + s >> *data._config; + s >> data._checksums; + s >> data._calibration; + s >> static_cast<Pic::RegistersData &>(*data._registersData); + s >> data._nbWordsCodeWrite >> data._nbWordsCodeRowErase; + s >> data._selfWrite; + return s; +} diff --git a/src/devices/pic/base/pic.h b/src/devices/pic/base/pic.h new file mode 100644 index 0000000..7b0dfc4 --- /dev/null +++ b/src/devices/pic/base/pic.h @@ -0,0 +1,179 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PIC_H +#define PIC_H + +#include <qstringlist.h> +#include <qmap.h> + +#include "common/global/global.h" +#include "common/common/bitvalue.h" +#include "devices/base/generic_device.h" + +namespace Pic +{ +class XmlToData; +class Group; +class Config; +class RegistersData; + +//----------------------------------------------------------------------------- +struct VoltageData { + double min, max, nominal; +}; +inline bool operator ==(const Pic::VoltageData &v1, const Pic::VoltageData &v2) { return ( v1.min==v2.min && v1.max==v2.max && v1.nominal==v2.nominal ); } + +BEGIN_DECLARE_ENUM(ProgVoltageType) + Vpp = 0, VddBulkErase, VddWrite +END_DECLARE_ENUM_STD(ProgVoltageType) + +struct CalibrationData { + BitValue opcode, opcodeMask; +}; + +enum MemoryRangeTypeProperty { ReadOnly = 0, Writable = 1 }; +Q_DECLARE_FLAGS(MemoryRangeTypeProperties, MemoryRangeTypeProperty) +Q_DECLARE_OPERATORS_FOR_FLAGS(MemoryRangeTypeProperties) +struct MemoryRangeTypeData { + const char *key, *label; + MemoryRangeTypeProperties properties; +}; +BEGIN_DECLARE_ENUM(MemoryRangeType) + Code = 0, Cal, UserId, DeviceId, Config, Eeprom, DebugVector, HardwareStack, CalBackup, ProgramExecutive +END_DECLARE_ENUM(MemoryRangeType, MemoryRangeTypeData) + +BEGIN_DECLARE_ENUM(SelfWrite) + Yes, No +END_DECLARE_ENUM_STD(SelfWrite) + +BEGIN_DECLARE_ENUM(DeviceType) + Normal, J, K +END_DECLARE_ENUM_STD(DeviceType) + +struct ArchitectureData { + const char *key, *label; + uint nbBitsPC; // nb bits program counter + uint nbBytesWord; // nb bytes per word (hex file and icd2) + bool packed; // addressIncrement = (packed ? nbBytesWord : nbBytesWord/2) + uint nbBitsRegister; + uint registerBankLength; + uint nbBits[MemoryRangeType::Nb_Types]; // nb bits per word + bool hasAddressAccess; // memory can be accessed randomly + SelfWrite::Type selfWrite; + DeviceType::Type deviceType; +}; +BEGIN_DECLARE_ENUM(Architecture) + P10X = 0, P16X, P17C, P18C, P18F, P18J, P24F, P24H, P30F, P33F +END_DECLARE_ENUM(Architecture, ArchitectureData) + +enum MemoryRangeProperty { NotPresent = 0, Present = 1, Programmable = 2 }; +Q_DECLARE_FLAGS(MemoryRangeProperties, MemoryRangeProperty) +Q_DECLARE_OPERATORS_FOR_FLAGS(MemoryRangeProperties) +struct MemoryRangeData { + MemoryRangeProperties properties; + Address start, end; + uint hexFileOffset; +}; + +namespace Checksum +{ + BEGIN_DECLARE_ENUM(Algorithm) + Normal = 0, XOR4, XNOR7, XNOR8 + END_DECLARE_ENUM_STD(Algorithm) + class Data { + public: + BitValue constant; + Algorithm algorithm; + QStringList protectedMaskNames; + QString bbsize; + BitValue blankChecksum, checkChecksum; + }; +} // namespace + +BEGIN_DECLARE_ENUM(Feature) + CCP, ADC, SSP, LVD, USB, USART, CAN, ECAN, Ethernet, LCD, MotorControl, + MotionFeedback, SelfWrite +END_DECLARE_ENUM_STD(Feature) + +//----------------------------------------------------------------------------- +class Data : public Device::Data +{ +public: + Data(); + virtual ~Data(); + virtual QString fname(Device::Special special) const; + virtual QString listViewGroup() const { return _architecture.label(); } + bool isPresent(MemoryRangeType type) const { return (range(type).properties & Present); } + bool isReadable(MemoryRangeType type) const; + bool isWritable(MemoryRangeType type) const; + uint nbAddresses(MemoryRangeType type) const; + uint nbWords(MemoryRangeType type) const; + uint addressIncrement(MemoryRangeType type) const; + uint nbWordsWriteAlignment(MemoryRangeType type) const; + MemoryRangeData range(MemoryRangeType type) const { return _ranges[type]; } + virtual uint nbBitsAddress() const { return _nbBitsPC; } + uint nbBitsWord(MemoryRangeType type) const { return _architecture.data().nbBits[type.type()]; } + uint nbBytesWord(MemoryRangeType type) const { return nbBitsToNbBytes(nbBitsWord(type)); } + uint nbCharsWord(MemoryRangeType type) const { return nbBitsToNbChars(nbBitsWord(type)); } + BitValue mask(MemoryRangeType type) const { return uint(1 << nbBitsWord(type))-1; } + BitValue userIdRecommendedMask() const { return _userIdRecommendedMask; } + const Config &config() const { return *_config; } + Architecture architecture() const { return _architecture; } + bool is18Family() const { return ( _architecture==Architecture::P18C || _architecture==Architecture::P18F || _architecture==Architecture::P18J); } + bool is16bitFamily() const { return ( _architecture.data().nbBitsRegister==16 ); } + VoltageData voltage(ProgVoltageType type) const { return _voltages[type]; } + virtual bool canWriteCalibration() const { return isWritable(MemoryRangeType::Cal); } + bool checkCalibration(const Device::Array &data, QString *message = 0) const; + const QMap<Device::Special, BitValue> ids() const { return _ids; } + virtual bool matchId(BitValue rawId, Device::IdData &data) const; + QStringList idNames(const QMap<QString, Device::IdData> &ids) const; + const QMap<QString, Checksum::Data> checksums() const { return _checksums; } + const RegistersData ®istersData() const; + const CalibrationData &calibrationData() const { return _calibration; } + + bool hasFeature(Feature feature, bool *unknown = 0) const; + BitValue nopInstruction() const { return 0x0; } + Device::Array gotoInstruction(Address address, bool withPageSelection) const; + bool isGotoInstruction(BitValue instruction) const; + +private: + Architecture _architecture; + QMap<Device::Special, BitValue> _ids; + uint _nbBitsPC; + uint _nbWordsCodeWrite; // #### only for 18F/18J devices [0 for other devices] + uint _nbWordsCodeRowErase; // #### only for 18F/18J devices [0 for other devices or if not available] + QMap<ProgVoltageType, VoltageData> _voltages; + QMap<MemoryRangeType, MemoryRangeData> _ranges; + BitValue _userIdRecommendedMask; + Config *_config; + QMap<QString, Checksum::Data> _checksums; + CalibrationData _calibration; + SelfWrite _selfWrite; + + friend class XmlToData; + friend class Group; + friend QDataStream &operator <<(QDataStream &s, const Data &data); + friend QDataStream &operator >>(QDataStream &s, Data &data); +}; + +QDataStream &operator <<(QDataStream &s, const Data &data); +QDataStream &operator >>(QDataStream &s, Data &data); + +} // namespace + +QDataStream &operator <<(QDataStream &s, const Pic::VoltageData &vd); +QDataStream &operator >>(QDataStream &s, Pic::VoltageData &vd); +QDataStream &operator <<(QDataStream &s, const Pic::MemoryRangeData &mrd); +QDataStream &operator >>(QDataStream &s, Pic::MemoryRangeData &mrd); +QDataStream &operator <<(QDataStream &s, const Pic::Checksum::Data &cd); +QDataStream &operator >>(QDataStream &s, Pic::Checksum::Data &cd); +QDataStream &operator <<(QDataStream &s, const Pic::CalibrationData &cd); +QDataStream &operator >>(QDataStream &s, Pic::CalibrationData &cd); + +#endif diff --git a/src/devices/pic/base/pic_config.cpp b/src/devices/pic/base/pic_config.cpp new file mode 100644 index 0000000..6672794 --- /dev/null +++ b/src/devices/pic/base/pic_config.cpp @@ -0,0 +1,456 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "pic_config.h" + +#include <qregexp.h> + +const Pic::ConfigNameType::Data Pic::ConfigNameType::DATA[Nb_Types] = { + { "cname", 0 }, + { "ecname", 0 }, + { "sdcc_cname", 0 } +}; + +const Pic::Config::Data Pic::Config::DATA[] = { + { { "CP", I18N_NOOP("Code code-protection") }, MemoryRange, { { 0, 0 } } }, + { { "CPD", I18N_NOOP("Data code-protection") }, MemoryRange, { { 0, 0 } } }, + { { "CPC", I18N_NOOP("Calibration code-protection") }, MemoryRange, { { 0, 0 } } }, + { { "CPB", I18N_NOOP("Boot code-protection") }, MemoryRange, { { 0, 0 } } }, + + { { "WRT", I18N_NOOP("Code write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "WRTD", I18N_NOOP("Data write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "WRTB", I18N_NOOP("Boot write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "WRTC", I18N_NOOP("Configuration write-protection") }, MemoryRange, { { 0, 0 } } }, + + { { "EBTR", I18N_NOOP("Table read-protection") }, MemoryRange, { { 0, 0 } } }, + { { "EBTRB", I18N_NOOP("Boot table read-protection") }, MemoryRange, { { 0, 0 } } }, + + { { "WDT", I18N_NOOP("Watchdog timer") }, Toggle, { { 0, 0 } } }, + { { "MCLRE", I18N_NOOP("Master clear reset"), }, Fixed, { + { "External", I18N_NOOP("External"), }, + { "Internal", I18N_NOOP("Disabled (connected to Vdd)") }, { 0, 0 } } }, + { { "PWRTE", I18N_NOOP("Power-up timer") }, Toggle, { { 0, 0 } } }, + + { { "FOSC", I18N_NOOP("Oscillator") }, Fixed, { + { "EXTRC", I18N_NOOP("External RC oscillator") }, + { "EXTRC_CLKOUT", I18N_NOOP("External RC oscillator with CLKOUT") }, + { "EXTRC_IO", I18N_NOOP("External RC oscillator (no CLKOUT)") }, + { "INTRC", I18N_NOOP("Internal oscillator") }, + { "INTRC_CLKOUT", I18N_NOOP("Internal oscillator with CLKOUT") }, + { "INTRC_IO", I18N_NOOP("Internal oscillator (no CLKOUT)") }, + { "XT", I18N_NOOP("Crystal/resonator") }, + { "XTPLL", I18N_NOOP("Crystal/resonator, PLL enabled") }, + { "LP", I18N_NOOP("Low power crystal") }, + { "EC", I18N_NOOP("External clock") }, + { "EC_CLKOUT", I18N_NOOP("External clock with CLKOUT") }, + { "EC_IO", I18N_NOOP("External clock (no CLKOUT)") }, + { "ECPLL_CLKOUT", I18N_NOOP("External clock with CLKOUT, PLL enabled") }, + { "ECPLL_IO", I18N_NOOP("External clock (no CLKOUT), PLL enabled") }, + { "E4_CLKOUT", I18N_NOOP("External clock with 4x PLL and with CLKOUT") }, + { "E4_IO", I18N_NOOP("External clock with 4x PLL (no CLKOUT)") }, + { "E4S_IO", I18N_NOOP("External clock with software controlled 4x PLL (no CLKOUT)") }, + { "ER", I18N_NOOP("External resistor") }, + { "ER_CLKOUT", I18N_NOOP("External resistor with CLKOUT") }, + { "ER_IO", I18N_NOOP("External resistor (no CLKOUT)") }, + { "HS", I18N_NOOP("High speed crystal/resonator") }, + { "HSPLL", I18N_NOOP("High speed crystal/resonator, PLL enabled") }, + { "H4", I18N_NOOP("High speed crystal/resonator with 4x PLL") }, + { "H4S", I18N_NOOP("High speed crystal/resonator with software controlled 4x PLL") }, + { "INTXT", I18N_NOOP("Internal oscillator, XT used by USB") }, + { "INTHS", I18N_NOOP("Internal oscillator, HS used by USB") }, + { 0, 0 } } }, + + { { "BG", I18N_NOOP("Bandgap voltage calibration") }, Fixed, { + { "Lowest", I18N_NOOP("Lowest") }, + { "Mid/Low", I18N_NOOP("Mid/Low") }, + { "Mid/High", I18N_NOOP("Mid/High") }, + { "Highest", I18N_NOOP("Highest") }, { 0, 0 } } }, + { { "TRIM", I18N_NOOP("Internal Trim") }, Fixed, { + { "00", I18N_NOOP("00") }, { "01", I18N_NOOP("01") }, + { "10", I18N_NOOP("10") }, { "11", I18N_NOOP("11") }, { 0, 0 } } }, + { { "BODEN", I18N_NOOP("Brown-out detect") }, Toggle, { + { "On_run", I18N_NOOP("Enabled in run - Disabled in sleep") }, + { "Software", I18N_NOOP("SBODEN controls BOD function") }, { 0, 0 } } }, + { { "FCMEN", I18N_NOOP("Fail-safe clock monitor") }, Toggle, { { 0, 0 } } }, + { { "IESO", I18N_NOOP("Internal-external switchover") }, Toggle, { { 0, 0 } } }, + { { "WUREN", I18N_NOOP("Wake-up reset") }, Toggle, { { 0, 0 } } }, + { { "DEBUG", I18N_NOOP("In-circuit debugger") }, Toggle, { { 0, 0 } } }, + { { "MPEEN", I18N_NOOP("Memory parity error") }, Toggle, { { 0, 0 } } }, + { { "BORV", I18N_NOOP("Brown-out reset voltage") }, ValueDouble, { + { "0", I18N_NOOP("Undefined") }, { 0, 0 } } }, + { { "LVP", I18N_NOOP("Low voltage programming") }, Toggle, { { 0, 0 } } }, + { { "CCP2MX", I18N_NOOP("CCP2 multiplex") }, Pin, { { 0, 0 } } }, + { { "CCP1MX", I18N_NOOP("CCP1 multiplex") }, Pin, { { 0, 0 } } }, + { { "BORSEN", I18N_NOOP("Brown-out reset software") }, Toggle, { { 0, 0 } } }, + { { "WDTPS", I18N_NOOP("WDT post-scaler") }, Ratio, { + { "Disabled", I18N_NOOP("Disabled") }, { 0, 0 } } }, + { { "PM", I18N_NOOP("Processor mode") }, Fixed, { + { "Extended microcontroller", I18N_NOOP("Extended microcontroller") }, + { "Microcontroller", I18N_NOOP("Microcontroller") }, + { "Microprocessor", I18N_NOOP("Microprocessor") }, + { "Code-protected microcontroller", I18N_NOOP("Code protected microcontroller") }, + { "Microprocessor with boot", I18N_NOOP("Microprocessor with boot block") }, + { 0, 0 } } }, + + { { "OSCSEN", I18N_NOOP("Oscillator system clock switch") }, Toggle, { { 0, 0 } } }, + { { "STVREN", I18N_NOOP("Stack full/underflow reset") }, Toggle, { { 0, 0 } } }, + { { "BW", I18N_NOOP("External bus data width (in bits)") }, ValueUInt, { { 0, 0 } } }, + { { "PBADEN", I18N_NOOP("PORTB A/D") }, Fixed, { + { "digital", I18N_NOOP("Digital") }, + { "analog", I18N_NOOP("Analog") }, { 0, 0 } } }, + { { "WINEN", I18N_NOOP("Watchdog timer window") }, Toggle, { { 0, 0 } } }, + { { "HPOL", I18N_NOOP("Odd PWM output polarity") }, Fixed, { + { "high", I18N_NOOP("Active high") }, + { "low", I18N_NOOP("Active low") }, { 0, 0 } } }, + { { "LPOL", I18N_NOOP("Even PWM output polarity") }, Fixed, { + { "high", I18N_NOOP("Active high") }, + { "low", I18N_NOOP("Active low") }, { 0, 0 } } }, + { { "PWMPIN", I18N_NOOP("PWM output pin reset state") }, Toggle, { { 0, 0 } } }, + { { "T1OSCMX", I18N_NOOP("Timer1 oscillator mode") }, Fixed, { + { "Legacy", I18N_NOOP("Standard operation") }, + { "Low Power", I18N_NOOP("Low power in sleep mode") }, + { "RA6", I18N_NOOP("T1OSO/T1CKI on RA6") }, + { "RB2", I18N_NOOP("T1OSO/T1CKI on RB2") }, { 0, 0 } } }, + { { "EXCLKMX", I18N_NOOP("TMR0/T5CKI external clock mux") }, Pin, { { 0, 0 } } }, + { { "FLTAMX", I18N_NOOP("FLTA mux") }, Pin, { { 0, 0 } } }, + { { "PWM4MX", I18N_NOOP("PWM4 mux") }, Pin, { { 0, 0 } } }, + { { "SSPMX", I18N_NOOP("SSP I/O mux (SCK/SLC, SDA/SDI, SD0)") }, Pins, { { 0, 0 } } }, + { { "LPT1OSC", I18N_NOOP("Low-power timer1 oscillator") }, Toggle, { { 0, 0 } } }, + { { "XINST", I18N_NOOP("Extended instruction set") }, Toggle, { { 0, 0 } } }, + { { "BBSIZ", I18N_NOOP("Boot block size") }, ValueUInt, { { 0, 0 } } }, + { { "ICPORT", I18N_NOOP("Dedicated in-circuit port") }, Toggle, { { 0, 0 } } }, + { { "VREGEN", I18N_NOOP("USB voltage regulator") }, Toggle, { { 0, 0 } } }, + { { "WAIT", I18N_NOOP("External bus data wait") }, Toggle, { { 0, 0 } } }, + { { "ABW", I18N_NOOP("Address bus width (in bits)") }, ValueUInt, { { 0, 0 } } }, + { { "ECCPMX", I18N_NOOP("ECCP mux") }, Fixed, { + { "RE6-RE3", I18N_NOOP("PWM multiplexed onto RE6 and RE3") }, + { "RH7-RH4", I18N_NOOP("PWM multiplexed onto RH7 and RH4") }, + { "RE6-RE5", I18N_NOOP("PWM multiplexed onto RE6 and RE5") }, + { "RH7-RH6", I18N_NOOP("PWM multiplexed onto RH7 and RH6") }, { 0, 0 } } }, + + { { "FCKSM", I18N_NOOP("Clock switching mode") }, Fixed, { + { "Switching off, monitor off", I18N_NOOP("Switching off, monitor off") }, + { "Switching on, monitor off", I18N_NOOP("Switching on, monitor off") }, + { "Switching on, monitor on", I18N_NOOP("Switching on, monitor on") }, { 0, 0 } } }, + { { "FOS", I18N_NOOP("Oscillator source") }, Fixed, { + { "INTRC_F", I18N_NOOP("Internal fast RC") }, + { "INTRC_LP", I18N_NOOP("Internal low-power RC") }, + { "PRIM", I18N_NOOP("Primary") }, + { "TMR1", I18N_NOOP("Timer1") }, { 0, 0 } } }, + { { "FPR", I18N_NOOP("Primary oscillator mode") }, Fixed, { + { "XTL", I18N_NOOP("Low-power/low-frequency crystal") }, + { "HS", I18N_NOOP("High speed crystal") }, + { "XT", I18N_NOOP("XT Crystal") }, + { "XT4", I18N_NOOP("XT Crystal with 4x PLL") }, + { "XT8", I18N_NOOP("XT Crystal with 8x PLL") }, + { "XT16", I18N_NOOP("XT Crystal with 16x PLL") }, + { "EC_CLKOUT", I18N_NOOP("External clock with CLKOUT") }, + { "EC_IO", I18N_NOOP("External clock (no CLKOUT)") }, + { "EC4", I18N_NOOP("External clock with 4x PLL") }, + { "EC8", I18N_NOOP("External clock with 8x PLL") }, + { "EC16", I18N_NOOP("External clock with 16x PLL") }, + { "FRC8", I18N_NOOP("Internal fast RC oscillator with 8x PLL") }, + { "EXTRC_CLKOUT", I18N_NOOP("External RC oscillator with CLKOUT") }, + { "EXTRC_IO", I18N_NOOP("External RC oscillator (no CLKOUT)") }, { 0, 0 } } }, + { { "FOSFPR", I18N_NOOP("Oscillator mode") }, Fixed, { + { "XTL", I18N_NOOP("Low-power/low-frequency crystal") }, + { "HS", I18N_NOOP("High speed crystal") }, + { "XT", I18N_NOOP("XT Crystal") }, + { "XT4", I18N_NOOP("XT Crystal with 4x PLL") }, + { "XT8", I18N_NOOP("XT Crystal with 8x PLL") }, + { "XT16", I18N_NOOP("XT Crystal with 16x PLL") }, + { "HS2_4", I18N_NOOP("HS/2 Crystal with 4x PLL") }, + { "HS2_8", I18N_NOOP("HS/2 Crystal with 8x PLL") }, + { "HS2_16", I18N_NOOP("HS/2 Crystal with 16x PLL") }, + { "HS3_4", I18N_NOOP("HS/3 Crystal with 4x PLL") }, + { "HS3_8", I18N_NOOP("HS/3 Crystal with 8x PLL") }, + { "HS3_16", I18N_NOOP("HS/3 Crystal with 16x PLL") }, + { "EC_CLKOUT", I18N_NOOP("External clock with CLKOUT") }, + { "EC_IO", I18N_NOOP("External clock (no CLKOUT)") }, + { "EC4", I18N_NOOP("External clock with 4x PLL") }, + { "EC8", I18N_NOOP("External clock with 8x PLL") }, + { "EC16", I18N_NOOP("External clock with 16x PLL") }, + { "FRC4", I18N_NOOP("Internal fast RC oscillator with 4x PLL") }, + { "FRC8", I18N_NOOP("Internal fast RC oscillator with 8x PLL") }, + { "FRC16", I18N_NOOP("Internal fast RC oscillator with 16x PLL") }, + { "TMR1", I18N_NOOP("Low-power 32 kHz oscillator (TMR1 oscillator)") }, + { "INTRC_F", I18N_NOOP("Internal fast RC oscillator (no PLL)") }, + { "INTRC_LP", I18N_NOOP("Internal low-power RC oscillator") }, + { "EXTRC_CLKOUT", I18N_NOOP("External RC oscillator with CLKOUT") }, + { "EXTRC_IO", I18N_NOOP("External RC oscillator (no CLKOUT)") }, { 0, 0 } } }, + { { "FWPSA", I18N_NOOP("Watchdog timer prescaler A") }, Ratio, { { 0, 0 } } }, + { { "FWPSB", I18N_NOOP("Watchdog timer prescaler B") }, Ratio, { { 0, 0 } } }, + { { "FWDTEN", I18N_NOOP("Watchdog") }, Toggle, { + { "Software", I18N_NOOP("Software") }, { 0, 0 } } }, + { { "FPWRT", I18N_NOOP("Power-on reset timer value (ms)") }, ValueUInt, { + { "0", I18N_NOOP("Disabled") }, { 0, 0 } } }, + { { "GCP", I18N_NOOP("General code segment read-protection") }, MemoryRange, { { 0, 0 } } }, + { { "GWRP", I18N_NOOP("General code segment write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "COE", I18N_NOOP("Reset into clip on emulation mode") }, Toggle, { { 0, 0 } } }, + { { "ICS", I18N_NOOP("ICD communication channel") }, Pins, { { 0, 0 } } }, + + { { "USBDIV", I18N_NOOP("USB clock (PLL divided by)") }, ValueUInt, { + { "1", I18N_NOOP("not divided") }, { 0, 0 } } }, + { { "CPUDIV", I18N_NOOP("CPU system clock (divided by)") }, ValueUInt, { + { "1", I18N_NOOP("not divided") }, { 0, 0 } } }, + { { "PLLDIV", I18N_NOOP("PLL clock (divided by)") }, ValueUInt, { + { "1", I18N_NOOP("not divided") }, { 0, 0 } } }, + + { { "MCPU", I18N_NOOP("Master clear pull-up resistor") }, Toggle, { { 0, 0 } } }, + { { "IOSCFS", I18N_NOOP("Internal oscillator speed") }, Fixed, { + { "8MHZ", I18N_NOOP("8 MHz") }, + { "4MHZ", I18N_NOOP("4 MHz") }, { 0, 0 } } }, + + // 18J specific + { { "ETHLED", I18N_NOOP("Ethernet LED enable") }, Toggle, { { 0, 0 } } }, + { { "FOSC2", I18N_NOOP("Default system clock select") }, Fixed, { + { "FOSC1:FOSC0", I18N_NOOP("FOSC1:FOSC0") }, + { "INTRC", I18N_NOOP("INTRC") }, { 0, 0 } } }, + { { "EMB", I18N_NOOP("External memory bus") }, Fixed, { + { "Disabled", I18N_NOOP("Disabled") }, + { "12BIT", I18N_NOOP("12-bit external bus") }, + { "16BIT", I18N_NOOP("16-bit external bus") }, + { "20BIT", I18N_NOOP("20-bit external bus") }, { 0, 0 } } }, + { { "EASHFT", I18N_NOOP("External address bus shift") }, Toggle, { { 0, 0 } } }, + { { "MSSPSEL", I18N_NOOP("MSSP address select bit") }, Fixed, { + { "7BIT", I18N_NOOP("7-bit address mask mode") }, + { "5BIT", I18N_NOOP("5-bit address mask mode") }, { 0, 0 } } }, + { { "PMPMX", I18N_NOOP("PMP pin select bit") }, Fixed, { + { "Connected", I18N_NOOP("Connected to EMB") }, + { "NotConnected", I18N_NOOP("Not connected to EMB") }, { 0, 0 } } }, + + // 24X specific / 30F1010 / 30F202X + { { "WRTBS", I18N_NOOP("Boot segment write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "BSSIZ", I18N_NOOP("Boot segment size") }, ValueUInt, { { 0, 0 } } }, + { { "BSSEC", I18N_NOOP("Boot segment security") }, Fixed, { + { "High Security", I18N_NOOP("High Security") }, + { "Standard Security", I18N_NOOP("Standard Security") }, { 0, 0 } } }, + { { "EBSSIZ", I18N_NOOP("Boot segment EEPROM size") }, ValueUInt, { { 0, 0 } } }, + { { "RBSSIZ", I18N_NOOP("Boot segment RAM size") }, ValueUInt, { { 0, 0 } } }, + { { "WRTSS", I18N_NOOP("Secure segment write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "SSSIZ", I18N_NOOP("Secure segment size") }, ValueUInt, { { 0, 0 } } }, + { { "SSSEC", I18N_NOOP("Secure segment security") }, Fixed, { + { "High Security", I18N_NOOP("High Security") }, + { "Standard Security", I18N_NOOP("Standard Security") }, { 0, 0 } } }, + { { "ESSSIZ", I18N_NOOP("Secure segment EEPROM size") }, ValueUInt, { { 0, 0 } } }, + { { "RSSSIZ", I18N_NOOP("Secure segment RAM size") }, ValueUInt, { { 0, 0 } } }, + { { "WRTGS", I18N_NOOP("General segment write-protection") }, MemoryRange, { { 0, 0 } } }, + { { "GSSEC", I18N_NOOP("General segment security") }, Fixed, { + { "Off", I18N_NOOP("Off") }, + { "High Security", I18N_NOOP("High security") }, + { "Standard Security", I18N_NOOP("Standard security") }, { 0, 0 } } }, + { { "FNOSC", I18N_NOOP("Initial oscillator source") }, Fixed, { + { "EXTRC_F" , I18N_NOOP("Fast RC oscillator") }, + { "INTRC_F", I18N_NOOP("Internal fast RC oscillator") }, + { "INTRC_F_PLL", I18N_NOOP("Internal fast RC oscillator with PLL") }, + { "PRIM", I18N_NOOP("Primary oscillator") }, + { "PRIM_PLL", I18N_NOOP("Primary oscillator with PLL") }, + { "SECOND", I18N_NOOP("Secondary oscillator (LP)") }, + { "EXTRC_LP", I18N_NOOP("Low power RC oscillator") }, + { "INTRC_F_POST", I18N_NOOP("Internal fast RC oscillator with postscaler") }, { 0, 0 } } }, + { { "POSCMD", I18N_NOOP("Primary oscillator mode") }, Fixed, { + { "Off", I18N_NOOP("Off") }, + { "HS", I18N_NOOP("HS crystal oscillator") }, + { "XT", I18N_NOOP("XT crystal oscillator") }, + { "EC", I18N_NOOP("External clock") }, { 0, 0 } } }, + { { "TEMP", I18N_NOOP("Temperature protection") }, Toggle, { { 0, 0 } } }, + { { "OSCIOFNC", I18N_NOOP("OSC2 pin function") }, Fixed, { + { "IO", I18N_NOOP("Digital I/O") }, + { "Clock", I18N_NOOP("Clock output") }, { 0, 0 } } }, + { { "WINDIS", I18N_NOOP("Watchdog timer window") }, Toggle, { { 0, 0 } } }, + { { "WDTPRE", I18N_NOOP("Watchdog timer prescaler") }, Ratio, { { 0, 0 } } }, + { { "WDTPOST", I18N_NOOP("Watchdog timer postscaler") }, Ratio, { { 0, 0 } } }, + { { "JTAGEN", I18N_NOOP("JTAG port enabled") }, Toggle, { { 0, 0 } } }, + { { "IOL1WAY", I18N_NOOP("Peripheral pin select configuration") }, Fixed, { + { "One reconfiguration", I18N_NOOP("Allow only one reconfiguration") }, + { "Multiple reconfigurations", I18N_NOOP("Allow multiple reconfigurations") }, { 0, 0 } } }, + { { "ALTI2C", I18N_NOOP("Alternate I2C pins") }, Pin, { { 0, 0 } } }, + { { "I2C1SEL", I18N_NOOP("I2C pins selection") }, Fixed, { + { "Default", I18N_NOOP("Default") }, + { "Alternate", I18N_NOOP("Alternate") }, { 0, 0 } } }, + { { "FRANGE", I18N_NOOP("Frequency range selection for FRC oscillator") }, Fixed, { + { "High range", I18N_NOOP("High range (nominal FRC frequency is 14.1 MHz)") }, + { "Low range", I18N_NOOP("Low range (nominal FRC frequency is 9.7 MHz)") }, { 0, 0 } } }, + + { { 0, 0 }, Fixed, { { 0, 0 } } } +}; + +QMap<QString, Pic::Config::MapData> *Pic::Config::_masks = 0; +QMap<QString, Pic::Config::MapData> &Pic::Config::masks() +{ + if ( _masks==0 ) { + _masks = new QMap<QString, MapData>; + for (uint i=0; DATA[i].mask.name; i++) { + (*_masks)[DATA[i].mask.name] = MapData(i, -1); + if ( DATA[i].type==MemoryRange ) { + for (uint k=0; k<Protection::MAX_NB_BLOCKS; k++) + (*_masks)[QString("%1_%2").arg(DATA[i].mask.name).arg(k)] = MapData(i, k); + } + } + } + return *_masks; +} + +bool Pic::Config::hasMaskName(const QString &mask) +{ + return masks().contains(mask); +} + +QString Pic::Config::maskLabel(const QString &mask) +{ + const MapData &mp = masks()[mask]; + QString s = i18n(DATA[mp.index].mask.label); + if ( mp.block>=0 ) return i18n("%1 for block %2").arg(s).arg(mp.block); + return s; +} + +const Pic::Config::Mask *Pic::Config::findMask(const QString &mask, uint *wordIndex) const +{ + for (uint i=0; i<uint(_words.count()); i++) + for (uint k=0; k<uint(_words[i].masks.count()); k++) { + if ( _words[i].masks[k].name==mask ) { + if (wordIndex) *wordIndex = i; + return &_words[i].masks[k]; + } + } + return 0; +} + +const Pic::Config::Value *Pic::Config::findValue(const QString &mask, const QString &value) const +{ + const Mask *cmask = findMask(mask); + if ( cmask==0 ) return 0; + for (uint i=0; i<uint(cmask->values.count()); i++) + if ( cmask->values[i].name==value ) return &cmask->values[i]; + return 0; +} + +bool Pic::Config::checkValueName(const QString &mask, const QString &name) const +{ + const Data &data = DATA[masks()[mask].index]; + QString pinRegexp = "[A-Z]+\\d*(/[A-Z]+\\d*)?"; + switch (data.type) { + case Fixed: break; + case ValueDouble: { + bool ok; + (void)name.toDouble(&ok); + if (ok) return true; + break; + } + case ValueUInt: { + bool ok; + (void)name.toUInt(&ok); + if (ok) return true; + break; + } + case Ratio: { + QRegExp regexp("(\\d+):(\\d+)"); + if ( regexp.exactMatch(name) ) { + bool ok1, ok2; + (void)regexp.cap(1).toUInt(&ok1); + (void)regexp.cap(2).toUInt(&ok2); + if ( ok1 && ok2 ) return true; + } + break; + } + case MemoryRange: + return _protection.checkRange(mask, name); + case Toggle: + if ( name=="On" || name=="Off" ) return true; + break; + case Pin: { + QRegExp regexp(pinRegexp); + if ( regexp.exactMatch(name) ) return true; + break; + } + case Pins: { + QRegExp regexp(pinRegexp + "(, " + pinRegexp + ")+"); + if ( regexp.exactMatch(name) ) return true; + break; + } + } + for (uint i=0; data.values[i].name; i++) + if ( data.values[i].name==name ) return true; + return false; +} + +QString Pic::Config::valueLabel(const QString &mask, const QString &name) +{ + const Data &data = DATA[masks()[mask].index]; + switch (data.type) { + case Fixed: + case ValueDouble: + case ValueUInt: + case Pin: + case Pins: + case Ratio: break; + case MemoryRange: + if ( name=="All" ) return i18n("All"); + if ( name=="Off" ) return i18n("Disabled"); + break; + case Toggle: + if ( name=="On" ) return i18n("Enabled"); + if ( name=="Off" ) return i18n("Disabled"); + break; + } + for (uint i=0; data.values[i].name; i++) + if ( data.values[i].name==name ) return i18n(data.values[i].label); + return name; +} + +BitValue Pic::Config::Word::usedMask() const +{ + BitValue mask = 0x0; + for (uint i=0; i<uint(masks.count()); i++) mask |= masks[i].value; + return mask; +} + +//----------------------------------------------------------------------------- +QDataStream &Pic::operator <<(QDataStream &s, const Config::Value &value) +{ + s << value.name << value.configNames << value.value; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, Config::Value &value) +{ + s >> value.name >> value.configNames >> value.value; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const Config::Mask &mask) +{ + s << mask.name << mask.value << mask.values; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, Config::Mask &mask) +{ + s >> mask.name >> mask.value >> mask.values; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const Config::Word &word) +{ + s << word.name << word.ignoredCNames << word.wmask << word.pmask << word.cmask << word.bvalue << word.masks; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, Config::Word &word) +{ + s >> word.name >> word.ignoredCNames >> word.wmask >> word.pmask >> word.cmask >> word.bvalue >> word.masks; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const Config &config) +{ + s << config._words; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, Config &config) +{ + s >> config._words; + return s; +} diff --git a/src/devices/pic/base/pic_config.h b/src/devices/pic/base/pic_config.h new file mode 100644 index 0000000..185a19e --- /dev/null +++ b/src/devices/pic/base/pic_config.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PIC_CONFIG_H +#define PIC_CONFIG_H + +#include <qmap.h> +#include <qstringlist.h> + +#include "common/common/bitvalue.h" +#include "pic_protection.h" +#include "pic.h" + +namespace Pic +{ +class Data; + +BEGIN_DECLARE_ENUM(ConfigNameType) + Default = 0, Extra, SDCC +END_DECLARE_ENUM_STD(ConfigNameType) + +class Config +{ +public: + class Value { + public: + QString name; + QMap<ConfigNameType, QStringList> configNames; + BitValue value; + bool operator <(const Value &cv) const { return value<cv.value; } + bool isValid() const { return !name.isEmpty(); } + }; + + class Mask { + public: + QString name; + BitValue value; + QValueVector<Value> values; // ordered from lower to higher + bool operator <(const Mask &cm) const { return value<cm.value; } + }; + + class Word { + public: + QString name; + QStringList ignoredCNames; + BitValue wmask, pmask, cmask; // write, protected, and checksum bits masks + BitValue bvalue; // blank value + QValueVector<Mask> masks; // ordered from lower to higher + BitValue usedMask() const; + }; + +public: + Config(const Pic::Data &data) : _data(data), _protection(data, *this) {} + QValueVector<Word> _words; + const Protection &protection() const { return _protection; } + + const Value *findValue(const QString &mask, const QString &value) const; + const Mask *findMask(const QString &mask, uint *wordIndex = 0) const; + static bool hasMaskName(const QString &mask); + static QString maskLabel(const QString &mask); + bool checkValueName(const QString &mask, const QString &name) const; + static QString valueLabel(const QString &mask, const QString &name); + +private: + class MapData { + public: + MapData() {} + MapData(int i, int b) : index(i), block(b) {} + int index, block; + }; + static QMap<QString, MapData> &masks(); + static QMap<QString, MapData> *_masks; // mask name -> index in DATA + + struct NameData { + const char *name, *label; + }; + enum Type { Fixed, ValueDouble, ValueUInt, Ratio, MemoryRange, Toggle, Pin, Pins }; + class Data { + public: + const NameData mask; + Type type; + const NameData values[50]; + }; + static const Data DATA[]; + +private: + const Pic::Data &_data; + Protection _protection; +}; + +QDataStream &operator <<(QDataStream &s, const Config::Value &value); +QDataStream &operator >>(QDataStream &s, Config::Value &value); +QDataStream &operator <<(QDataStream &s, const Config::Mask &mask); +QDataStream &operator >>(QDataStream &s, Config::Mask &mask); +QDataStream &operator <<(QDataStream &s, const Config::Word &word); +QDataStream &operator >>(QDataStream &s, Config::Word &word); +QDataStream &operator <<(QDataStream &s, const Config &config); +QDataStream &operator >>(QDataStream &s, Config &config); + +} //namespace + +#endif diff --git a/src/devices/pic/base/pic_protection.cpp b/src/devices/pic/base/pic_protection.cpp new file mode 100644 index 0000000..da77881 --- /dev/null +++ b/src/devices/pic/base/pic_protection.cpp @@ -0,0 +1,361 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "pic_protection.h" + +#include "pic_config.h" + +#include <qregexp.h> + +bool Pic::Protection::isNoneProtectedValueName(const QString &name) const +{ + if ( name=="Off" ) return true; + if ( _data.architecture()==Architecture::P17C ) return !isAllProtectedValueName(name); + return false; +} + +bool Pic::Protection::isAllProtectedValueName(const QString &name) const +{ + if ( name=="All" ) return true; + if ( _data.architecture()==Architecture::P17C ) return ( name=="Code-protected microcontroller" ); + return false; +} + +Pic::Protection::Family Pic::Protection::family() const +{ + if ( _config.findMask("WRTBS") ) return CodeGuard; + QString mask = maskName(ProgramProtected, MemoryRangeType::Code); + if ( _config.findMask(QString("%1_%2").arg(mask).arg(0)) ) return BlockProtection; + if ( _config.findMask(mask) ) return BasicProtection; + return NoProtection; +} + +QString Pic::Protection::securityValueName(Type type) const +{ + if ( type==StandardSecurity ) return "Standard Security"; + if ( type==HighSecurity ) return "High Security"; + Q_ASSERT( type==Nb_Types ); + return "Off"; +} + +QString Pic::Protection::bootSizeMaskName() const +{ + return (family()==CodeGuard ? "BSSIZ" : "BBSIZ"); +} + +QString Pic::Protection::bootMaskName(Type type) const +{ + Q_ASSERT( type!=Nb_Types ); + if ( family()==CodeGuard ) { + if ( type==WriteProtected ) return "WRTBS"; + if ( type==StandardSecurity || type==HighSecurity ) return "BSSEC"; + } else { + if ( type==ProgramProtected ) return "CPB"; + if ( type==WriteProtected ) return "WRTB"; + if ( type==ReadProtected ) return "EBTRB"; + } + return QString::null; +} + +QString Pic::Protection::blockSizeMaskName(uint block) const +{ + if ( family()==CodeGuard ) { + Q_ASSERT( block==0 ); + return "SSSIZ"; + } + return blockMaskName(ProgramProtected, block); +} + +QString Pic::Protection::blockMaskName(Type type, uint block) const +{ + Q_ASSERT( type!=Nb_Types ); + if ( family()==CodeGuard ) { + if ( type==WriteProtected ) return (block==0 ? "WRTSS" : "WRTGS"); + if ( type==StandardSecurity || type==HighSecurity ) return (block==0 ? "SSSEC" : "GSSEC"); + return QString::null; + } + return QString("%1_%2").arg(maskName(type, MemoryRangeType::Code)).arg(block); +} + +QString Pic::Protection::maskName(Type type, MemoryRangeType mtype) const +{ + Q_ASSERT( type!=Nb_Types ); + switch (mtype.type()) { + case MemoryRangeType::Code: + if ( type==ProgramProtected ) { + if ( _data.architecture()==Architecture::P17C ) return "PM"; + if ( _data.architecture()==Architecture::P30F || _data.architecture()==Architecture::P24F ) return "GCP"; + return "CP"; + } + if ( type==WriteProtected ) { + if ( _data.architecture()==Architecture::P30F || _data.architecture()==Architecture::P24F ) return "GWRP"; + return "WRT"; + } + if ( type==ReadProtected ) return "EBTR"; + break; + case MemoryRangeType::Eeprom: + if ( type==ProgramProtected ) return "CPD"; + if ( type==WriteProtected ) return "WRTD"; + break; + case MemoryRangeType::Cal: + if ( type==ProgramProtected ) return "CPC"; + break; + case MemoryRangeType::Config: + if ( type==WriteProtected ) return "WRTC"; + if ( type==ReadProtected ) return "EBTRC"; + break; + case MemoryRangeType::Nb_Types: Q_ASSERT(false); break; + default: break; + } + return QString::null; +} + +bool Pic::Protection::extractRanges(const QString &name, QValueVector<Address> &starts, Address &end, bool &ok) +{ + ok = false; + QRegExp regexp("([A-F0-9]+)(/[A-F0-9]+)?(/[A-F0-9]+)?:([A-F0-9]+)"); + if ( !regexp.exactMatch(name) ) return false; + bool ok1; + end = fromHex(regexp.cap(regexp.numCaptures()), &ok1); + if ( !ok1 ) { + qDebug("Malformed end address"); + return true; + } + starts.clear(); + for (int i=1; i<regexp.numCaptures(); i++) { + if ( regexp.cap(i).isEmpty() ) break; + bool ok1; + QString s = (i==1 ? regexp.cap(i) : regexp.cap(i).mid(1)); + Address start = fromHex(s, &ok1); + if ( !ok1 ) { + qDebug("Malformed start address %s", s.latin1()); + return true; + } + if ( start>=end && (starts.count()==0 || starts[starts.count()-1]<start) ) { + qDebug("Start addresses should be ordered"); + return true; + } + starts.append(start); + } + ok = true; + return true; +} + +AddressRangeVector Pic::Protection::extractRanges(const QString &name, MemoryRangeType type) const +{ + if ( isNoneProtectedValueName(name) ) return AddressRange(); + if ( isAllProtectedValueName(name) ) { + const MemoryRangeData &rdata = _data.range(type); + return AddressRange(rdata.start, rdata.end); + } + bool ok1; + QValueVector<Address> starts; + Address end; + bool ok2 = extractRanges(name, starts, end, ok1); + Q_ASSERT(ok1); + Q_ASSERT(ok2); + Q_UNUSED(ok2); + AddressRangeVector rv; + for (uint i=0; i<uint(starts.count()); i++) rv.append(AddressRange(starts[i], end)); + return rv; +} + +bool Pic::Protection::checkRange(const QString &mask, const QString &name) const +{ + if ( family()!=CodeGuard ) { + bool ok; + (void)extractRange(mask, name, ok); + return ok; + } + + bool isBootBlock = false; + int block = 0; + Type ptype = Nb_Types; + for (uint i=0; i<3; i++) { + isBootBlock = ( i==0 ); + block = i - 1; + for (uint k=0; k<Nb_Types; k++) { + QString mname = (isBootBlock ? bootMaskName(Type(k)) : blockMaskName(Type(k), block)); + if ( mask!=mname ) continue; + ptype = Type(k); + break; + } + if ( ptype!=Nb_Types ) break; + } + if ( ptype==Nb_Types ) { + qDebug("Unknown protected memory range"); + return false; + } + // #### TODO + return true; +} + +Pic::Protection::ProtectedRange Pic::Protection::extractRange(const QString &mask, const QString &name, bool &ok) const +{ + Q_ASSERT( family()!=CodeGuard ); + //qDebug("extract range %s %s", mask.latin1(), name.latin1()); + ProtectedRange pr; + ok = false; + + QRegExp rexp("([A-Z]+)(?:_([0-9])|)"); + if ( !rexp.exactMatch(mask) ) { + qDebug("Malformed block range"); + return pr; + } + + bool isBootBlock = false; + MemoryRangeType rtype = MemoryRangeType::Nb_Types; + Type ptype = Nb_Types; + + for (MemoryRangeType type; type<=MemoryRangeType::Nb_Types; ++type) { // #### danger: <= + isBootBlock = ( type==MemoryRangeType::Nb_Types ); + for (uint k=0; k<Nb_Types; k++) { + QString mname = (isBootBlock ? bootMaskName(Type(k)) : maskName(Type(k), type)); + if ( rexp.cap(1)!=mname ) continue; + rtype = (isBootBlock ? MemoryRangeType(MemoryRangeType::Code) : type); + ptype = Type(k); + if ( !rexp.cap(2).isEmpty() ) { + if ( isBootBlock || (rtype!=MemoryRangeType::Code && rtype!=MemoryRangeType::Eeprom) ) { + qDebug("Multiple blocks only for code and eeprom"); + return pr; + } + } + break; + } + if ( rtype!=MemoryRangeType::Nb_Types ) break; + } + if ( rtype==MemoryRangeType::Nb_Types ) { + qDebug("Unknown protected memory range"); + return pr; + } + + if ( isNoneProtectedValueName(name) ) { + ok = true; + return pr; + } + + const Config::Mask *bmask = _config.findMask(bootMaskName(ptype)); + const Config::Mask *bsmask = _config.findMask(bootSizeMaskName()); + const MemoryRangeData &rdata = _data.range(rtype); + if ( isAllProtectedValueName(name) ) { + if ( rtype==MemoryRangeType::Code && !isBootBlock && bmask ) { + qDebug("Protected range should be explicit with boot block"); + return pr; + } + if (isBootBlock) { + if ( bsmask==0 ) { + qDebug("Protected range should be explicit when boot size not present"); + return pr; + } + Address start = _data.range(MemoryRangeType::Code).start; + pr.starts.append(start); + for (uint k=0; k<uint(bsmask->values.count()); k++) { + bool ok1; + uint size = bsmask->values[k].name.toUInt(&ok1); + if ( !ok1 ) { + qDebug("Could not recognize boot size value"); + return pr; + } + if ( size==0 ) { + qDebug("Boot size cannot be zero"); + return pr; + } + Address end = 2 * size - 1; // instruction words + if ( pr.ends.count()!=0 && end==pr.ends[pr.ends.count()-1] ) continue; + pr.ends.append(end); + qHeapSort(pr.ends); + } + } else { + pr.starts.append(rdata.start); + pr.ends.append(rdata.end); + } + ok = true; + return pr; + } + if ( isBootBlock && bsmask ) { + qDebug("Protected range should not be explicit when boot size is present"); + return pr; + } + + // extract start and end + Address end; + bool ok1; + if ( !extractRanges(name, pr.starts, end, ok1) ) { + qDebug("Could not recognized explicit range"); + return pr; + } + if ( !ok1 ) return pr; + if ( end>rdata.end ) { + qDebug("End is beyond memory range"); + return pr; + } + if ( (rtype!=MemoryRangeType::Code || isBootBlock) && (pr.starts.count()>1 || !rexp.cap(2).isEmpty() || bmask==0) ) { + qDebug("Only code with blocks and boot can have multiple protected ranges"); + return pr; + } + if ( isBootBlock && pr.starts[0]!=0 ) { + qDebug("Boot block start should be zero"); + return pr; + } + pr.ends.append(end); + + // check with boot block + if ( pr.starts.count()>1 ) { + if ( bmask==0 ) { + qDebug("No boot mask"); + return pr; + } + for (uint i=0; i<uint(bmask->values.count()); i++) { + if ( bmask->values[i].name=="Off" ) continue; + bool ok1; + ProtectedRange bpr = extractRange(bmask->name, bmask->values[i].name, ok1); + if ( !ok1 ) return pr; + if ( bpr.ends.count()!=pr.starts.count() ) { + qDebug("Boot number of ends (%i) should be the same as code number of starts (%i)", int(bpr.ends.count()), int(pr.starts.count())); + return pr; + } + for (uint k=0; k<uint(bpr.ends.count()); k++) { + if ( bpr.ends[k]+1!=pr.starts[k] ) { + qDebug("%i: End of boot block (%s) doesn't match start of code block (%s)", k, toHexLabelAbs(bpr.ends[k]).latin1(), toHexLabelAbs(pr.starts[k]).latin1()); + return pr; + } + } + } + } + + ok = true; + return pr; +} + +bool Pic::Protection::hasBootBlock() const +{ + return ( _config.findMask("CPB") || _config.findMask(bootSizeMaskName()) ); +} + +uint Pic::Protection::nbBlocks() const +{ + if ( family()==CodeGuard ) return 2; // codeguard : secure segment + general segment + for (uint i=0; i<MAX_NB_BLOCKS; i++) + if ( _config.findMask(QString("CP_%1").arg(i))==0 ) return i; + return MAX_NB_BLOCKS; +} + +QString Pic::Protection::bootLabel() const +{ + if ( family()==CodeGuard ) return i18n("Boot Segment"); + return i18n("Boot Block"); +} + +QString Pic::Protection::blockLabel(uint i) const +{ + if ( family()==CodeGuard ) { + if ( i==0 ) return i18n("Secure Segment"); + return i18n("General Segment"); + } + return i18n("Block #%1").arg(i); +} diff --git a/src/devices/pic/base/pic_protection.h b/src/devices/pic/base/pic_protection.h new file mode 100644 index 0000000..67ff667 --- /dev/null +++ b/src/devices/pic/base/pic_protection.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PIC_PROTECTION_H +#define PIC_PROTECTION_H + +#include "pic.h" + +namespace Pic +{ +class Data; + +//---------------------------------------------------------------------------- +class Protection +{ +public: + enum { MAX_NB_BLOCKS = 8 }; + enum Family { NoProtection = 0, BasicProtection, BlockProtection, CodeGuard, Nb_Families }; + enum Type { ProgramProtected = 0, WriteProtected, ReadProtected, + StandardSecurity, HighSecurity, Nb_Types }; + +public: + Protection(const Pic::Data &data, const Config &config) : _data(data), _config(config) {} + Family family() const; + QString securityValueName(Type type) const; + bool hasBootBlock() const; + QString bootSizeMaskName() const; + QString bootMaskName(Type ptype) const; + QString bootLabel() const; + uint nbBlocks() const; + QString blockSizeMaskName(uint i) const; + QString blockMaskName(Type ptype, uint i) const; + QString blockLabel(uint i) const; + AddressRangeVector extractRanges(const QString &name, MemoryRangeType type) const; + bool checkRange(const QString &mask, const QString &name) const; + QString maskName(Type type, MemoryRangeType mtype) const; + bool isAllProtectedValueName(const QString &valueName) const; + bool isNoneProtectedValueName(const QString &valueName) const; + +private: + const Pic::Data &_data; + const Config &_config; + + enum SegmentType { BootSegment = 0, SecureSegment, GeneralSegment, Nb_SegmentTypes }; + static bool extractRanges(const QString &name, QValueVector<Address> &starts, Address &end, bool &ok); + class ProtectedRange { + public: + QValueVector<Address> starts, ends; + }; + ProtectedRange extractRange(const QString &mask, const QString &name, bool &ok) const; +}; + +} //namespace + +#endif diff --git a/src/devices/pic/base/pic_register.cpp b/src/devices/pic/base/pic_register.cpp new file mode 100644 index 0000000..fcfe5ef --- /dev/null +++ b/src/devices/pic/base/pic_register.cpp @@ -0,0 +1,287 @@ +/*************************************************************************** + * 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_register.h" + +#include "pic.h" + +//----------------------------------------------------------------------------- +Pic::RegistersData::RegistersData(const Data &data) + : nbBanks(0), accessBankSplit(0), _data(data) +{} + +Address Pic::RegistersData::mirroredAddress(Address address) const +{ + Address mirror = address; + for (uint i=0; i<uint(mirrored.count()); i++) { + int delta = -1; + for (uint k=0; k<uint(mirrored[i].count()); k++) { + if ( address<mirrored[i][k].start + || address>=mirrored[i][k].start+mirrored[i][k].length ) continue; + delta = address - mirrored[i][k].start; + break; + } + if ( delta==-1 ) continue; + for (uint k=0; k<uint(mirrored[i].count()); k++) + mirror = QMIN(mirrored[i][k].start + delta, mirror); + break; + } + return mirror; +} + +Device::RegisterProperties Pic::RegistersData::properties(Address address) const +{ + switch ( type(address) ) { + case Mirrored: + case UnusedRegister: return Device::NotAccessible; + case Gpr: return (Device::Readable | Device::Writable); + case Sfr: { + Device::RegisterProperties properties = Device::NotAccessible; + RegisterBitProperties rbp = RegisterBitUnused; + QMap<QString, RegisterData>::const_iterator it; + for (it=sfrs.begin(); it!=sfrs.end(); ++it) { + if ( it.data().address!=address ) continue; + for (uint i=0; i<Device::MAX_NB_PORT_BITS; i++) rbp |= it.data().bits[i].properties; + if ( rbp & RegisterBitRead ) properties |= Device::Readable; + if ( rbp & RegisterBitWrite ) properties |= Device::Writable; + break; + } + return properties; + } + } + Q_ASSERT(false); + return Device::NotAccessible; +} + +Pic::RegisterType Pic::RegistersData::type(Address address) const +{ + for (uint i=0; i<uint(unused.count()); i++) + if ( address>=unused[i].start && address<unused[i].start+unused[i].length ) return UnusedRegister; + if ( !sfrNames[address].isEmpty() ) return Sfr; + Address mirror = mirroredAddress(address); + if ( !sfrNames[mirror].isEmpty() ) return Mirrored; + if ( address==mirror ) return Gpr; + return Mirrored; +} + +QString Pic::RegistersData::label(Address address) const +{ + switch ( type(address) ) { + case UnusedRegister: return "---"; + case Mirrored: return i18n("Mirror of %1").arg(toHexLabel(mirroredAddress(address), nbCharsAddress())); + case Gpr: return "<GPR>"; + case Sfr: return sfrNames[address]; + } + Q_ASSERT(false); + return QString::null; +} + +bool Pic::RegistersData::hasPort(uint index) const +{ + Q_ASSERT( index<Device::MAX_NB_PORTS ); + if ( sfrs.contains("GPIO") ) return ( index==0 ); + if ( !sfrs.contains(portName(index)) ) return false; + return true; +} + +int Pic::RegistersData::portIndex(Address address) const +{ + QString name = sfrNames[address]; + if ( name.isEmpty() ) return -1; + for (uint i=0; i<Device::MAX_NB_PORTS; i++) { + if ( !hasPort(i) ) continue; + if ( name==portName(i) || name==trisName(i) || name==latchName(i) ) return i; + } + return -1; +} + +bool Pic::RegistersData::hasPortBit(uint index, uint bit) const +{ + if ( !hasPort(index) ) return false; + const RegisterData &port = sfrs[portName(index)]; + return ( port.bits[bit].properties!=RegisterBitUnused ); +} + +QString Pic::RegistersData::portName(uint index) const +{ + if ( sfrs.contains("GPIO") ) { + if ( index!=0 ) return QString::null; + return "GPIO"; + } + return QString("PORT") + char('A' + index); +} + +QString Pic::RegistersData::trisName(uint index) const +{ + if ( sfrs.contains("GPIO") ) { + if ( index!=0 ) return QString::null; + return "TRISIO"; + } + if ( _data.architecture()==Architecture::P17C ) { + if ( index==0 ) return QString::null; + return QString("DDR") + char('A' + index); + } + return QString("TRIS") + char('A' + index); +} + +bool Pic::RegistersData::hasTris(uint index) const +{ + QString name = trisName(index); + if ( name.isEmpty() ) return false; + return sfrs.contains(name); +} + +QString Pic::RegistersData::latchName(uint index) const +{ + if ( _data.architecture()==Architecture::P10X || _data.architecture()==Architecture::P16X || _data.architecture()==Architecture::P17C ) + return QString::null; + return QString("LAT") + char('A' + index); +} + +bool Pic::RegistersData::hasLatch(uint index) const +{ + QString name = latchName(index); + if ( name.isEmpty() ) return false; + return sfrs.contains(name); +} + +QString Pic::RegistersData::portBitName(uint index, uint bit) const +{ + if ( sfrs.contains("GPIO") ) return QString("GP") + QString::number(bit); + return QString("R") + char('A' + index) + QString::number(bit); +} + +QValueList<Register::TypeData> Pic::RegistersData::relatedRegisters(const Register::TypeData &data) const +{ + QValueList<Register::TypeData> list; + if ( data.type()==Register::Regular ) { + int i = portIndex(data.address()); + if ( i==-1 ) list.append(data); + else { + list.append(Register::TypeData(sfrs[portName(i)].address, nbChars())); + if ( hasTris(i) ) list.append(Register::TypeData(sfrs[trisName(i)].address, nbChars())); + if ( hasLatch(i) ) list.append(Register::TypeData(sfrs[latchName(i)].address, nbChars())); + } + } else if ( data.type()==Register::Combined ) { + uint nb = nbBitsToNbBytes(4*data.nbChars()) / nbBytes(); + for (uint i=0; i<nb; i++) list.append(Register::TypeData(data.address() + i*nbBytes(), nbChars())); + } else list.append(data); + return list; +} + +bool Pic::RegistersData::isBankUsed(uint i) const +{ + Q_ASSERT( i<nbBanks ); + return !(unusedBankMask & (1 << i)); +} + +bool Pic::RegistersData::bankHasSfrs(uint i) const +{ + if ( i==0 ) return true; + if ( (_data.architecture()==Pic::Architecture::P18F || _data.architecture()==Pic::Architecture::P18J) && i==15 ) return true; + if ( !isBankUsed(i) ) return false; + QMap<Address, QString>::const_iterator it; + for (it=sfrNames.begin(); it!=sfrNames.end(); ++it) + if ( bankFromAddress(it.key())==i ) return true; + return false; +} + +bool Pic::RegistersData::hasSharedGprs(uint &firstIndex, bool &all) const +{ + bool ok = false; + all = true; + for (uint i=0; i<nbRegistersPerBank(); i++) { + Address address = addressFromIndex(i); + if ( type(address)!=Gpr ) continue; + uint k = 1; + for (; k<nbBanks; k++) { + RegisterType t = type(address + k*nbBytesPerBank()); + if ( t!=Mirrored ) break; + } + if ( k==nbBanks ) { + if ( !ok ) firstIndex = i; + ok = true; + } else all = false; + } + return ok; +} + +uint Pic::RegistersData::firstGprIndex() const +{ + for (uint i=0; i<nbRegistersPerBank(); i++) + if ( type(addressFromIndex(i))==Gpr ) return i; + Q_ASSERT(false); + return 0; +} + +//---------------------------------------------------------------------------- +QDataStream &Pic::operator <<(QDataStream &s, const RangeData &rd) +{ + s << rd.start << rd.length; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, RangeData &rd) +{ + s >> rd.start >> rd.length; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const RegisterBitData &rbd) +{ + s << Q_UINT8(rbd.properties) << Q_UINT8(rbd.por) << Q_UINT8(rbd.mclr); + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, RegisterBitData &rbd) +{ + Q_UINT8 properties, por, mclr; + s >> properties >> por >> mclr; + rbd.properties = RegisterBitProperties(properties); + rbd.por = RegisterBitState(por); + rbd.mclr = RegisterBitState(mclr); + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const RegisterData &rd) +{ + s << rd.address; + for (int i=0; i<Device::MAX_NB_PORT_BITS; i++) s << rd.bits[i]; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, RegisterData &rd) +{ + s >> rd.address; + for (int i=0; i<Device::MAX_NB_PORT_BITS; i++) s >> rd.bits[i]; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const CombinedData &rd) +{ + s << rd.address << rd.nbChars; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, CombinedData &rd) +{ + s >> rd.address >> rd.nbChars; + return s; +} + +QDataStream &Pic::operator <<(QDataStream &s, const RegistersData &rd) +{ + s << rd.nbBanks << rd.accessBankSplit << rd.unusedBankMask; + s << rd.sfrs << rd.mirrored << rd.unused << rd.combined; + return s; +} +QDataStream &Pic::operator >>(QDataStream &s, RegistersData &rd) +{ + s >> rd.nbBanks >> rd.accessBankSplit >> rd.unusedBankMask; + s >> rd.sfrs >> rd.mirrored >> rd.unused >> rd.combined; + rd.sfrNames.clear(); + QMap<QString, RegisterData>::const_iterator it; + for(it=rd.sfrs.begin(); it!=rd.sfrs.end(); ++it) rd.sfrNames[it.data().address] = it.key(); + return s; +} diff --git a/src/devices/pic/base/pic_register.h b/src/devices/pic/base/pic_register.h new file mode 100644 index 0000000..41da020 --- /dev/null +++ b/src/devices/pic/base/pic_register.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * 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_REGISTER_H +#define PIC_REGISTER_H + +#include <qmap.h> + +#include "devices/base/register.h" +#include "pic.h" + +namespace Pic +{ +class Data; +struct RangeData { + Address start; + uint length; +}; + +//----------------------------------------------------------------------------- +enum RegisterType { UnusedRegister, Sfr, Gpr, Mirrored}; +enum RegisterBitProperty { RegisterBitUnused = 0x0, + RegisterBitRead = 0x1, RegisterBitWrite = 0x2, + RegisterBitOnlySoftwareClear = 0x4, RegisterBitOnlySoftwareSet = 0x8, + MaxRegisterBitProperty = 0x15 +}; +Q_DECLARE_FLAGS(RegisterBitProperties, RegisterBitProperty) +Q_DECLARE_OPERATORS_FOR_FLAGS(RegisterBitProperties) +enum RegisterBitState { RegisterBitUnknown = 0, RegisterBitLow, RegisterBitHigh, + RegisterBitUnchanged, RegisterBitDepends, RegisterBitDependsConfig, Nb_RegisterBitStates +}; + +//----------------------------------------------------------------------------- +class RegisterBitData +{ +public: + RegisterBitData() : properties(RegisterBitUnused) {} + RegisterBitProperties properties; + RegisterBitState por, mclr; +}; +struct RegisterData +{ + Address address; + RegisterBitData bits[Device::MAX_NB_PORT_BITS]; +}; +struct CombinedData +{ + Address address; + uint nbChars; +}; + +class RegistersData : public Device::RegistersData +{ +public: + RegistersData(const Data &data); + virtual uint nbBits() const { return _data.architecture().data().nbBitsRegister; } + uint nbBytesPerBank() const { return _data.architecture().data().registerBankLength; } + uint nbRegistersPerBank() const { return nbBytesPerBank() / nbBytes(); } + uint nbCharsAddress() const { return ::nbChars(nbRegisters() - 1); } + virtual uint nbRegisters() const { return nbBanks * nbRegistersPerBank(); } + virtual uint addressFromIndex(uint i) const { return nbBytes() * i; } + virtual uint indexFromAddress(Address address) const { return address.toUInt() / nbBytes(); } + bool isBankUsed(uint i) const; + uint bankFromAddress(Address address) const { return indexFromAddress(address) / nbRegistersPerBank(); } + bool bankHasSfrs(uint i) const; // slow + bool hasSharedGprs(uint &firstIndex, bool &all) const; // i.e. mirrored in all banks (all is for first bank only) + uint firstGprIndex() const; // in first bank + + uint nbBanks, accessBankSplit, unusedBankMask; + QMap<QString, RegisterData> sfrs; + QMap<Address, QString> sfrNames; // address -> name + QValueVector<QValueVector<RangeData> > mirrored; + QValueVector<RangeData> unused; + QMap<QString, CombinedData> combined; + + virtual Device::RegisterProperties properties(Address address) const; + RegisterType type(Address address) const; + QString label(Address address) const; + virtual QValueList<Register::TypeData> relatedRegisters(const Register::TypeData &data) const; + + virtual bool hasPort(uint index) const; + virtual int portIndex(Address address) const; + virtual QString portName(uint index) const; + bool hasTris(uint index) const; + QString trisName(uint index) const; + bool hasLatch(uint index) const; + QString latchName(uint index) const; + virtual bool hasPortBit(uint index, uint bit) const; + virtual QString portBitName(uint index, uint bit) const; + +private: + const Data &_data; + Address mirroredAddress(Address address) const; +}; + +//----------------------------------------------------------------------------- +QDataStream &operator <<(QDataStream &s, const RangeData &rd); +QDataStream &operator >>(QDataStream &s, RangeData &rd); +QDataStream &operator <<(QDataStream &s, const RegisterBitData &rbd); +QDataStream &operator >>(QDataStream &s, RegisterBitData &rbd); +QDataStream &operator <<(QDataStream &s, const RegisterData &rd); +QDataStream &operator >>(QDataStream &s, RegisterData &rd); +QDataStream &operator <<(QDataStream &s, const CombinedData &rd); +QDataStream &operator >>(QDataStream &s, CombinedData &rd); +QDataStream &operator <<(QDataStream &s, const RegistersData &rd); +QDataStream &operator >>(QDataStream &s, RegistersData &rd); + +} // namespace + +#endif |