You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/devices/pic/pic/pic_memory.cpp

561 lines
22 KiB
C++

/***************************************************************************
* 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_memory.h"
#include <tqfile.h>
#include "common/common/misc.h"
Pic::Memory::Memory(const Data &data)
: Device::Memory(data)
{
FOR_EACH(MemoryRangeType, i) _ranges[i].resize(device().nbWords(i));
fill(BitValue());
}
void Pic::Memory::fill(MemoryRangeType type, BitValue value)
{
for (uint i=0; i<_ranges[type].count(); i++) {
if ( type==MemoryRangeType::Config && !value.isInitialized() ) _ranges[type][i] = device().config()._words[i].bvalue;
else _ranges[type][i] = value;
}
}
bool Pic::Memory::isClear(MemoryRangeType type) const
{
for (uint i=0; i<_ranges[type].count(); i++) {
if ( type==MemoryRangeType::Config ) {
if ( _ranges[type][i]!=device().config()._words[i].bvalue ) return false;
} else if ( _ranges[type][i].isInitialized() ) return false;
}
return true;
}
void Pic::Memory::fill(BitValue value)
{
FOR_EACH(MemoryRangeType, k) fill(k, value);
}
void Pic::Memory::copyFrom(MemoryRangeType type, const Memory &memory)
{
Q_ASSERT( memory.device().name()==device().name() );
for (uint i=0; i<_ranges[type].count(); i++) _ranges[type][i] = memory._ranges[type][i];
}
void Pic::Memory::copyFrom(const Device::Memory &memory)
{
Q_ASSERT( memory.device().name()==device().name() );
FOR_EACH(MemoryRangeType, i) copyFrom(i, static_cast<const Memory &>(memory));
}
Device::Array Pic::Memory::arrayForWriting(MemoryRangeType type) const
{
Device::Array data = _ranges[type];
for (uint i=0; i<data.count(); i++)
data[i] = data[i].maskWith(type==MemoryRangeType::Config ? device().config()._words[i].wmask : device().mask(type));
return data;
}
BitValue Pic::Memory::word(MemoryRangeType type, uint offset) const
{
CRASH_ASSERT( offset<_ranges[type].size() );
return _ranges[type][offset];
}
BitValue Pic::Memory::normalizeWord(MemoryRangeType type, uint offset, BitValue value) const
{
if ( type==MemoryRangeType::Config) {
const Config::Word &cword = device().config()._words[offset];
return value.maskWith(cword.usedMask());
}
if ( type==MemoryRangeType::UserId ) return value.maskWith(device().userIdRecommendedMask());
return value.maskWith(device().mask(type));
}
BitValue Pic::Memory::normalizedWord(MemoryRangeType type, uint offset) const
{
return normalizeWord(type, offset, word(type, offset));
}
void Pic::Memory::setWord(MemoryRangeType type, uint offset, BitValue value)
{
if ( offset>=_ranges[type].size() ) qDebug("Memory::setWord: type=%s offset=%s size=%s value=%s", type.key(), toHexLabelAbs(offset).latin1(), toHexLabelAbs(_ranges[type].size()).latin1(), toHexLabelAbs(value).latin1());
CRASH_ASSERT( offset<_ranges[type].size() );
_ranges[type][offset] = value;
}
void Pic::Memory::setArray(MemoryRangeType type, const Device::Array &data)
{
CRASH_ASSERT( _ranges[type].size()==data.size() );
_ranges[type] = data;
}
TQString Pic::Memory::findValue(const TQString &maskName) const
{
if ( maskName.isEmpty() ) return TQString();
uint i;
const Config::Mask *mask = device().config().findMask(maskName, &i);
if ( mask==0 ) return TQString();
BitValue v = word(MemoryRangeType::Config, i).maskWith(mask->value);
for (uint k=0; k<uint(mask->values.count()); k++)
if ( v.isInside(mask->values[k].value) ) return mask->values[k].name;
Q_ASSERT(false);
return TQString();
}
AddressRange Pic::Memory::bootRange() const
{
const Protection &protection = device().config().protection();
// with boot size
TQString value = findValue(protection.bootSizeMaskName());
if ( !value.isEmpty() ) {
uint size = value.toUInt();
if ( size==0 ) return AddressRange();
Address start = device().range(MemoryRangeType::Code).start;
if ( device().architecture()==Architecture::P30F ) start = 0x100;
return AddressRange(start, 2 * size - 1); // instruction words
}
// only CPB
TQString maskName = protection.bootMaskName(Protection::ProgramProtected);
const Config::Mask *mask = device().config().findMask(maskName);
for (uint k=0; k<uint(mask->values.count()); k++) {
AddressRangeVector rv = protection.extractRanges(mask->values[k].name, MemoryRangeType::Code);
if ( !rv.isEmpty() ) return rv[0];
}
Q_ASSERT(false);
return AddressRange();
}
AddressRange Pic::Memory::blockRange(uint i) const
{
const Protection &protection = device().config().protection();
Q_ASSERT( i<protection.nbBlocks() );
if ( protection.family()==Protection::CodeGuard && i==1 ) { // general segment
AddressRange previous = blockRange(0);
if ( previous.isEmpty() ) previous = bootRange();
Address start = (previous.isEmpty() ? device().range(MemoryRangeType::Code).start : previous.end + 1);
return AddressRange(start, device().range(MemoryRangeType::Code).end);
}
TQString maskName = protection.blockSizeMaskName(i);
if ( protection.family()==Protection::CodeGuard ) { // secure segment
TQString value = findValue(maskName);
Q_ASSERT( !value.isEmpty() );
uint size = value.toUInt();
if ( size==0 ) return AddressRange();
AddressRange previous = bootRange();
Address start = (previous.isEmpty() ? device().range(MemoryRangeType::Code).start : previous.end + 1);
return AddressRange(start, 2 * size - 1);
}
AddressRange previous = (i==0 ? bootRange() : blockRange(i-1));
const Config::Mask *mask = device().config().findMask(maskName);
for (uint k=0; k<uint(mask->values.count()); k++) {
AddressRangeVector rv = protection.extractRanges(mask->values[k].name, MemoryRangeType::Code);
if ( !rv.isEmpty() ) return AddressRange(previous.end + 1, rv[0].end);
}
Q_ASSERT(false);
return AddressRange();
}
AddressRange Pic::Memory::bootProtectedRange(Protection::Type ptype) const
{
const Protection &protection = device().config().protection();
TQString maskName = protection.bootMaskName(ptype);
TQString value = findValue(maskName);
if ( value.isEmpty() ) return AddressRange();
if ( protection.family()!=Protection::CodeGuard ) {
if ( protection.extractRanges(value, MemoryRangeType::Code).isEmpty() ) return AddressRange();
} else {
if ( value!=protection.securityValueName(ptype) ) return AddressRange();
}
return bootRange();
}
AddressRange Pic::Memory::blockProtectedRange(Protection::Type ptype, uint i) const
{
const Protection &protection = device().config().protection();
TQString maskName = protection.blockMaskName(ptype, i);
TQString value = findValue(maskName);
if ( value.isEmpty() ) return AddressRange();
if ( protection.family()!=Protection::CodeGuard ) {
if ( protection.extractRanges(value, MemoryRangeType::Code).isEmpty() ) return AddressRange();
} else {
if ( value!=protection.securityValueName(ptype) ) return AddressRange();
}
return blockRange(i);
}
AddressRangeVector Pic::Memory::protectedRanges(Protection::Type ptype, MemoryRangeType type) const
{
const Protection &protection = device().config().protection();
AddressRangeVector rv;
if ( type==MemoryRangeType::Code ) {
if ( protection.hasBootBlock() ) rv.append(bootProtectedRange(ptype));
if ( protection.nbBlocks()!=0 ) {
for (uint i=0; i<protection.nbBlocks(); i++) rv.append(blockProtectedRange(ptype, i));
return rv;
}
}
if ( protection.family()!=Protection::CodeGuard ) {
TQString maskName = protection.maskName(ptype, type);
TQString value = findValue(maskName);
//qDebug("%s %s", maskName.latin1(), value.latin1());
if ( !value.isEmpty() ) {
AddressRangeVector tmp = protection.extractRanges(value, type);
Q_ASSERT( tmp.count()==1 );
rv.append(tmp[0]);
}
}
return rv;
}
void Pic::Memory::setBootProtection(bool on, Protection::Type ptype)
{
TQString maskName = device().config().protection().bootMaskName(ptype);
setProtection(on, maskName, ptype);
}
void Pic::Memory::setBlockProtection(bool on, Protection::Type ptype, uint block)
{
TQString maskName = device().config().protection().blockMaskName(ptype, block);
setProtection(on, maskName, ptype);
}
void Pic::Memory::setProtection(bool on, Protection::Type ptype, MemoryRangeType type)
{
const Protection &protection = device().config().protection();
if ( type==MemoryRangeType::Code ) {
if ( protection.hasBootBlock() ) setBootProtection(on, ptype);
if ( protection.nbBlocks()!=0 ) {
for (uint i=0; i<protection.nbBlocks(); i++) setBlockProtection(on, ptype, i);
return;
}
}
setProtection(on, protection.maskName(ptype, type), ptype);
}
void Pic::Memory::setConfigValue(const TQString &maskName, const TQString &valueName)
{
uint i;
const Config::Mask *mask = device().config().findMask(maskName, &i);
Q_ASSERT(mask);
BitValue v = word(MemoryRangeType::Config, i);
v = v.clearMaskBits(mask->value);
for (int k=mask->values.count()-1; k>=0; k--) { // important to get the highest value in case of identical values
if ( mask->values[k].name!=valueName ) continue;
setWord(MemoryRangeType::Config, i, v | mask->values[k].value);
return;
}
Q_ASSERT(false);
}
void Pic::Memory::setProtection(bool on, const TQString &maskName, Protection::Type ptype)
{
const Config::Mask *mask = device().config().findMask(maskName, 0);
if( mask==0 ) return;
const Protection &protection = device().config().protection();
TQString valueName;
if ( ptype==Protection::StandardSecurity || ptype==Protection::HighSecurity )
valueName = protection.securityValueName(ptype);
else {
for (int k=mask->values.count()-1; k>=0; k--) {
if ( (on && protection.isAllProtectedValueName(mask->values[k].name))
|| (!on && protection.isNoneProtectedValueName(mask->values[k].name)) ) valueName = mask->values[k].name;
}
}
setConfigValue(maskName, valueName);
}
bool Pic::Memory::hasFlagOn(const TQString &maskName, bool valueIfNotPresent) const
{
const Config::Mask *mask = device().config().findMask(maskName, 0);
if ( mask==0 ) return valueIfNotPresent;
Q_ASSERT(mask);
Q_ASSERT( mask->values.count()==2 );
return ( findValue(maskName)=="On" );
}
void Pic::Memory::setFlagOn(const TQString &maskName, bool on)
{
const Config::Mask *mask = device().config().findMask(maskName, 0);
Q_UNUSED(mask);
Q_ASSERT(mask);
Q_ASSERT( mask->values.count()==2 );
setConfigValue(maskName, on ? "On" : "Off");
}
void Pic::Memory::checksumCheckFill()
{
clear();
switch (device().architecture().type()) {
case Architecture::P10X:
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).start.toUInt(), 0x723);
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).end.toUInt(), 0x723);
break;
case Architecture::P16X:
if ( device().name()=="16F72" || device().name()=="16F73" || device().name()=="16F74" || device().name()=="16F76" || device().name()=="16F77"
|| device().name()=="16CR73" || device().name()=="16CR74" || device().name()=="16CR76" || device().name()=="16CR77" ) {
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).start.toUInt(), 0x05E6);
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).end.toUInt(), 0x05E6);
} else {
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).start.toUInt(), 0x25E6);
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).end.toUInt(), 0x25E6);
}
break;
case Architecture::P17C:
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).start.toUInt(), 0xC0DE);
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).end.toUInt(), 0xC0DE);
break;
case Architecture::P18C:
case Architecture::P18F:
case Architecture::P18J:
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).start.toUInt()/2, 0xAAFF);
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).end.toUInt()/2, 0xFFAA);
break;
case Architecture::P24F:
case Architecture::P24H:
case Architecture::P30F:
case Architecture::P33F:
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).start.toUInt(), 0xAAAAAA);
setWord(MemoryRangeType::Code, device().range(MemoryRangeType::Code).end.toUInt(), 0xAAAAAA);
break;
case Architecture::Nb_Types: Q_ASSERT(false); break;
}
}
BitValue Pic::Memory::checksum() const
{
// code
BitValue mask = device().mask(MemoryRangeType::Code);
AddressRangeVector rv = protectedRanges(Protection::ProgramProtected, MemoryRangeType::Code);
bool isProtected = !rv.isEmpty();
uint inc = device().addressIncrement(MemoryRangeType::Code);
//uint nbChars = device().nbCharsWord(MemoryRangeType::Code);
//qDebug("protected: %i nb: %s (%s)", isProtected, toHexLabelAbs(inc*device().nbWords(MemoryRangeType::Code)).latin1(), toHexLabel(mask, nbChars).latin1());
//for (uint i=0; i<rv.count(); i++)
// qDebug("protected: %s:%s", toHex(rv[i].start, nbChars).latin1(), toHex(rv[i].end, nbChars).latin1());
if ( isProtected && (device().architecture()==Pic::Architecture::P18J || device().architecture()==Pic::Architecture::P24F) )
return 0x0000;
Checksum::Algorithm algorithm = Checksum::Algorithm::Normal;
BitValue cs = 0x0000;
const Protection &protection = device().config().protection();
if ( protection.family()==Protection::BasicProtection ) {
TQString maskName = protection.maskName(Protection::ProgramProtected, MemoryRangeType::Code);
TQString valueName = findValue(maskName);
const TQMap<TQString, Checksum::Data> &checksums = device().checksums();
if ( checksums.contains(valueName) ) { // #### REMOVE ME !!
algorithm = checksums[valueName].algorithm;
cs = checksums[valueName].constant;
}
}
//qDebug("constant: %s", toHexLabelAbs(cs).data());
//qDebug("algo: %s", Checksum::ALGORITHM_DATA[algorithm].name);
for (uint i=0; i<device().nbWords(MemoryRangeType::Code); i++) {
if ( algorithm==Checksum::Algorithm::Normal && rv.contains(inc*i) ) continue;
BitValue v = word(MemoryRangeType::Code, i).maskWith(mask);
//if ( i==0 || i==device().nbWords(MemoryRangeType::Code)-1 ) qDebug("%s %s", toHexLabel(i, 4).latin1(), toHexLabel(v, 4).latin1());
switch (device().architecture().type()) {
case Architecture::P10X:
case Architecture::P16X:
case Architecture::P17C:
if ( rv.contains(i) ) {
switch (algorithm.type()) {
case Checksum::Algorithm::Normal: cs += v; break;
case Checksum::Algorithm::XOR4: cs += v.XORn(4); break;
case Checksum::Algorithm::XNOR7: cs += v.XNORn(7); break;
case Checksum::Algorithm::XNOR8: cs += v.XNORn(8) + (v.XNORn(8) << 8); break;
case Checksum::Algorithm::Nb_Types: Q_ASSERT(false); break;
}
} else cs += v;
break;
case Architecture::P18C:
case Architecture::P18F: // #### not true for all 18F ??
case Architecture::P18J:
cs += v.byte(0) + v.byte(1);
break;
case Architecture::P24F:
case Architecture::P24H:
case Architecture::P30F:
case Architecture::P33F:
cs += v.byte(0) + v.byte(1) + v.byte(2);
break;
case Architecture::Nb_Types: Q_ASSERT(false); break;
}
}
//qDebug("after code: %s", toHexLabelAbs(cs).latin1());
// config
const Config &config = device().config();
for (uint i=0; i<uint(config._words.count()); i++) {
const Config::Word &cword = config._words[i];
BitValue v = word(MemoryRangeType::Config, i).maskWith(cword.cmask);
//uint nbChars = device().nbCharsWord(MemoryRangeType::Config);
// qDebug("%i: %s %s", i, toHex(word(MemoryRangeType::Config, i), nbChars).latin1(), toHex(cword.cmask, nbChars).latin1());
if ( ( device().name()=="16C61" || device().name()=="16C71" ) && isProtected ) cs += v | 0x0060;
else if ( device().is16bitFamily() ) cs += v.byte(0) + v.byte(1);
else cs += v;
}
//qDebug("after config: %s", toHexLabelAbs(cs).latin1());
// user ids
if ( isProtected && device().isPresent(MemoryRangeType::UserId) && !device().is16bitFamily() && algorithm==Checksum::Algorithm::Normal ) {
BitValue id = 0x0;
uint nb = device().nbWords(MemoryRangeType::UserId);
for (uint i=0; i<nb; i++) {
BitValue v = word(MemoryRangeType::UserId, nb-i-1).maskWith(0xF);
if ( device().is18Family() ) id += v;
else {
// qDebug("id %i (%i): %s %s", i, nbb, toHex(v, 4).latin1(), toHex(v << (nbb*i), 9).latin1());
id += v << (4*i);
}
}
//qDebug("id %s", toHexLabelAbs(id).latin1());
cs += id;
}
//qDebug("checksum: %s %s", toHexLabelAbs(cs).latin1(), toHex(cs & 0xFFFF, 4).latin1());
return cs.maskWith(0xFFFF);
}
BitValue Pic::Memory::unprotectedChecksum() const
{
const Protection &protection = device().config().protection();
Memory tmp(*this);
if ( protection.hasBootBlock() ) tmp.setBootProtection(false, Protection::ProgramProtected);
if ( protection.nbBlocks()!=0 ) {
for (uint i=0; i<protection.nbBlocks(); i++)
tmp.setBlockProtection(false, Protection::ProgramProtected, i);
} else tmp.setProtection(false, Protection::ProgramProtected, MemoryRangeType::Code);
tmp.setProtection(false, Protection::ProgramProtected, MemoryRangeType::Eeprom);
tmp.setProtection(false, Protection::ProgramProtected, MemoryRangeType::Config);
tmp.setProtection(false, Protection::ProgramProtected, MemoryRangeType::Cal);
return tmp.checksum();
}
void Pic::Memory::setUserIdToUnprotectedChecksum()
{
BitValue cs = unprotectedChecksum();
uint nb = device().nbWords(MemoryRangeType::UserId);
for (uint i=0; i<nb; i++) setWord(MemoryRangeType::UserId, nb-i-1, cs.nybble(i));
}
//-----------------------------------------------------------------------------
void Pic::Memory::savePartial(TQTextStream &stream, HexBuffer::Format format) const
{
// save memory ranges in the same order as MPLAB (for easy checking)
const MemoryRangeType saveOrder[] = { MemoryRangeType::Code, MemoryRangeType::Eeprom, MemoryRangeType::Config, MemoryRangeType::UserId, MemoryRangeType::Cal, MemoryRangeType::Nb_Types };
HexBuffer hb;
for (uint i=0; saveOrder[i]!=MemoryRangeType::Nb_Types; i++) {
hb.clear();
toHexBuffer(saveOrder[i], hb);
hb.savePartial(stream, format);
}
}
//-----------------------------------------------------------------------------
void Pic::Memory::toHexBuffer(MemoryRangeType type, HexBuffer &hb) const
{
if ( !device().isWritable(type) ) return;
uint nbBytes = device().architecture().data().nbBytesWord;
bool packed = device().architecture().data().packed;
uint offset = device().range(type).hexFileOffset;
if ( offset==0 ) offset = device().range(type).start.toUInt();
BitValue mask = device().mask(type);
uint wNbBytes = nbBytes;
if ( packed && type!=Pic::MemoryRangeType::Code ) {
offset /= 2;
wNbBytes /= 2;
}
uint byte = 0;
uint wOffset = 0;
uint wByte = 0;
//qDebug("%s wnb=%i snb=%i div=%i", MEMORY_RANGE_TYPE_DATA[type].label, wNbBytes, sNbBytes, div);
for (uint k=0; k<wNbBytes*device().nbWords(type); k++) {
// set byte
BitValue s = _ranges[type][wOffset].maskWith(mask);
//if ( k<4 ) qDebug("s=%s so=%s sb=%i wo=%i wb=%i", toHex(s, 8).data(), toHex(sOffset, 8).data(), sByte, wOffset, wByte);
s = s.byte(wByte);
if ( (byte%2)==0 ) hb.insert(offset, s);
else hb.insert(offset, hb[offset] | (s << ((byte%2)*8)));
// increment offsets
byte++;
if ( (byte%nbBytes)==0 ) {
byte = 0;
offset++;
} else if ( byte==2 ) offset++;
wByte++;
if ( (wByte%wNbBytes)==0 ) {
wByte = 0;
wOffset++;
}
}
}
HexBuffer Pic::Memory::toHexBuffer() const
{
HexBuffer hb;
FOR_EACH(MemoryRangeType, i) toHexBuffer(i, hb);
return hb;
}
void Pic::Memory::fromHexBuffer(MemoryRangeType type, const HexBuffer &hb, WarningTypes &result,
TQStringList &warnings, TQMap<uint, bool> &inRange)
{
if ( !device().isWritable(type) ) return;
uint nbBytes = device().architecture().data().nbBytesWord;
bool packed = device().architecture().data().packed;
uint offset = device().range(type).hexFileOffset;
if ( offset==0 ) offset = device().range(type).start.toUInt();
BitValue mask = device().mask(type);
uint wNbBytes = nbBytes;
if ( packed && type!=Pic::MemoryRangeType::Code ) {
offset /= 2;
wNbBytes /= 2;
}
uint byte = 0;
uint wOffset = 0;
uint wByte = 0;
//qDebug("%s wnb=%i snb=%i", MEMORY_RANGE_TYPE_DATA[type].label, wNbBytes, nbBytes);
for (uint k=0; k<wNbBytes*device().nbWords(type); k++) {
// set byte
BitValue s = hb[offset];
//if ( k<4 ) qDebug("s=%s so=%s sb=%i wo=%i wb=%i", toHex(s, 8).data(), toHex(offset, 8).data(), byte, wOffset, wByte);
if ( !s.isInitialized() ) {
if ( type==MemoryRangeType::Config ) _ranges[type][wOffset] = mask;
else _ranges[type][wOffset] = BitValue();
} else {
inRange[offset] = true;
s = s.byte(byte%2);
if ( wByte==0 ) _ranges[type][wOffset] = s;
else _ranges[type][wOffset] |= (s << (wByte*8));
}
// increment offsets
byte++;
if ( (byte%nbBytes)==0 ) {
byte = 0;
offset++;
} else if ( byte==2 ) offset++;
wByte++;
if ( (wByte%wNbBytes)==0 ) {
if ( _ranges[type][wOffset].isInitialized() ) {
if ( !(result & ValueTooLarge) && _ranges[type][wOffset].maskWith(mask)!=_ranges[type][wOffset] ) {
result |= ValueTooLarge;
warnings += i18n("At least one word (at offset %1) is larger (%2) than the corresponding mask (%3).")
.arg(toHexLabel(offset, 8)).arg(toHexLabel(_ranges[type][wOffset], 8)).arg(toHexLabel(mask, 8));
}
_ranges[type][wOffset] = _ranges[type][wOffset].maskWith(mask);
}
wByte = 0;
wOffset++;
}
}
}
void Pic::Memory::fromHexBuffer(const HexBuffer &hb, WarningTypes &result,
TQStringList &warnings, TQMap<uint, bool> &inRange)
{
FOR_EACH(MemoryRangeType, i) fromHexBuffer(i, hb, result, warnings, inRange);
}