/*************************************************************************** * Copyright (C) 2005 Nicolas Hadacek * * * * 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); } TQString Pic::Data::fname(Device::Special special) const { TQString 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.tqreplace(2, 1, "LV"); break; case Device::Special::HighVoltage: // assume name is of form "NNXN..." s.tqreplace(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; TQMap::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.tqmaskWith(0x1F); break; case Architecture::P24F: nid = (rawId >> 16).tqmaskWith(0x3FFF); idata.revision = (rawId >> 6).tqmaskWith(0x7); idata.minorRevision = rawId.tqmaskWith(0x7); break; case Architecture::P30F: nid = (rawId >> 16).tqmaskWith(0xFFFF); idata.revision = (rawId >> 6).tqmaskWith(0x3F); idata.minorRevision = rawId.tqmaskWith(0x3F); idata.process = (rawId >> 12).tqmaskWith(0xF); break; case Architecture::P24H: case Architecture::P33F: nid = (rawId >> 16).tqmaskWith(0xFFFF); idata.revision = rawId.tqmaskWith(0xFFFF); // ?? break; case Architecture::Nb_Types: Q_ASSERT(false); break; } if ( nid==it.data() ) return true; } return false; } TQStringList Pic::Data::idNames(const TQMap &ids) const { TQStringList list; TQMap::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)").tqarg(it.key()).tqarg(toLabel(it.data().revision)); break; case Architecture::P24F: list += i18n("%1 (rev. %2.%3)").tqarg(it.key()).tqarg(toLabel(it.data().revision)).tqarg(toLabel(it.data().minorRevision)); break; case Architecture::P30F: list += i18n("%1 (proc. %2; rev. %3.%4)").tqarg(it.key()).tqarg(toLabel(it.data().process)).tqarg(toLabel(it.data().revision)).tqarg(toLabel(it.data().minorRevision)); break; case Architecture::P24H: case Architecture::P33F: list += i18n("%1 (rev. %2)").tqarg(it.key()).tqarg(toLabel(it.data().revision)); break; case Architecture::Nb_Types: Q_ASSERT(false); break; } } return list; } bool Pic::Data::checkCalibration(const Device::Array &data, TQString *message) const { Q_ASSERT( nbWords(MemoryRangeType::Cal)==data.count() ); for (uint i=0; i(*_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.tqcontains("CCP1CON"); case Feature::ADC: return registersData().sfrs.tqcontains("ADCON0"); case Feature::SSP: return registersData().sfrs.tqcontains("SSPCON"); case Feature::LVD: return registersData().sfrs.tqcontains("LVDCON"); case Feature::USB: return registersData().sfrs.tqcontains("UCON"); case Feature::USART: return ( registersData().sfrs.tqcontains("TXSTA") // 16F || registersData().sfrs.tqcontains("TXSTA1") // 18F || registersData().sfrs.tqcontains("U1MODE") ); // 30F case Feature::CAN: return registersData().sfrs.tqcontains("CANCON") && !registersData().sfrs.tqcontains("ECANCON"); case Feature::ECAN: return registersData().sfrs.tqcontains("ECANCON"); case Feature::Ethernet: return registersData().sfrs.tqcontains("ETHCON1"); case Feature::LCD: return registersData().sfrs.tqcontains("LCDCON"); case Feature::MotorControl: return registersData().sfrs.tqcontains("PWMCON0"); case Feature::MotionFeedback: return registersData().sfrs.tqcontains("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( address0x1FF && 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.tqmaskWith(0xE00)==0xA00 ); case Architecture::P16X: return ( instruction.tqmaskWith(0xF800)==0x2800 ); case Architecture::P17C: return ( instruction.tqmaskWith(0xE000)==0xC000 ); case Architecture::P18C: case Architecture::P18F: case Architecture::P18J: return ( instruction.tqmaskWith(0xFF00)==0xEF00 ); case Architecture::P24F: case Architecture::P24H: case Architecture::P30F: case Architecture::P33F: return ( instruction.tqmaskWith(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 TQMAX(_nbWordsCodeWrite, uint(16)); } //---------------------------------------------------------------------------- TQDataStream &operator <<(TQDataStream &s, const Pic::VoltageData &vd) { s << vd.min << vd.max << vd.nominal; return s; } TQDataStream &operator >>(TQDataStream &s, Pic::VoltageData &vd) { s >> vd.min >> vd.max >> vd.nominal; return s; } TQDataStream &operator <<(TQDataStream &s, const Pic::MemoryRangeData &mrd) { s << TQ_UINT8(mrd.properties) << mrd.start << mrd.end << mrd.hexFileOffset; return s; } TQDataStream &operator >>(TQDataStream &s, Pic::MemoryRangeData &mrd) { TQ_UINT8 properties; s >> properties >> mrd.start >> mrd.end >> mrd.hexFileOffset; mrd.properties = Pic::MemoryRangeProperties(properties); return s; } TQDataStream &operator <<(TQDataStream &s, const Pic::Checksum::Data &cd) { s << cd.constant << cd.bbsize << cd.algorithm << cd.protectedMaskNames; s << cd.blankChecksum << cd.checkChecksum; return s; } TQDataStream &operator >>(TQDataStream &s, Pic::Checksum::Data &cd) { s >> cd.constant >> cd.bbsize >> cd.algorithm >> cd.protectedMaskNames; s >> cd.blankChecksum >> cd.checkChecksum; return s; } TQDataStream &operator <<(TQDataStream &s, const Pic::CalibrationData &cd) { s << cd.opcode << cd.opcodeMask; return s; } TQDataStream &operator >>(TQDataStream &s, Pic::CalibrationData &cd) { s >> cd.opcode >> cd.opcodeMask; return s; } TQDataStream &Pic::operator <<(TQDataStream &s, const Pic::Data &data) { s << static_cast(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(*data._registersData); s << data._nbWordsCodeWrite << data._nbWordsCodeRowErase; s << data._selfWrite; return s; } TQDataStream &Pic::operator >>(TQDataStream &s, Pic::Data &data) { s >> static_cast(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(*data._registersData); s >> data._nbWordsCodeWrite >> data._nbWordsCodeRowErase; s >> data._selfWrite; return s; }