diff options
Diffstat (limited to 'src/devices/base/hex_buffer.cpp')
-rw-r--r-- | src/devices/base/hex_buffer.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/src/devices/base/hex_buffer.cpp b/src/devices/base/hex_buffer.cpp new file mode 100644 index 0000000..a63554d --- /dev/null +++ b/src/devices/base/hex_buffer.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * (C) 2003 by Alain Gibaud * + * * + * 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 "hex_buffer.h" + +#include <qtextstream.h> + +#include "devices/base/generic_device.h" + +//----------------------------------------------------------------------------- +const char * const HexBuffer::FORMATS[Nb_Formats] = { + "inhx8m", /*"inhx8s", */"inhx16", "inhx32" +}; + +void HexBuffer::savePartial(QTextStream &stream, Format format) const +{ + BitValue oldseg; + const_iterator block = begin(); + int len; + while ( fetchNextBlock(block, end(), &len) ) { + // block found, write it + BitValue seg = block.key() >> 15 ; // 2 * seg address + if ( format==IHX32 && seg!=oldseg ) { + char buf[50]; + BitValue check = 0x02 + 0x04 + seg.byte(1) + seg.byte(0); + sprintf(buf, ":02000004%04X%02X\n", seg.toUInt(), check.twoComplement().byte(0)); + stream << buf; + oldseg = seg; + } + writeHexBlock(stream, len, block, format); + } +} + +void HexBuffer::saveEnd(QTextStream &stream) const +{ + stream << ":00000001FF\n"; +} + +/* Write one line of Intel-hex file + * Original code source from Timo Rossi, + * modified by Alain Gibaud to support large blocks write + */ +void HexBuffer::writeHexBlock(QTextStream &stream, int reclen, // length (in words) + const_iterator& data, // pointer to 1st data word (incremented by function) + Format format) +{ + while ( reclen>HEXBLKSIZE ) { + writeHexBlock(stream, HEXBLKSIZE, data, format); + reclen -= HEXBLKSIZE; + } + if ( reclen<=0 ) return; /* Oops, block has just a HEXBLKSIZE * n size */ + + char buf[20]; + BitValue check = 0x0; + + // line start + uint loc = data.key(); + switch (format) { + case IHX8M: + case IHX32: + loc *= 2; + sprintf(buf, ":%02X%04X00", 2*reclen, loc & 0xFFFF); + check += ((loc) & 0xff) + (((loc) >> 8) & 0xff) + 2*reclen; + break; + case IHX16: + sprintf(buf, ":%02X%04X00", reclen, loc & 0xFFFF); + check += (loc & 0xff) + ((loc >> 8) & 0xff) + reclen; + break; + case Nb_Formats: Q_ASSERT(false); break; + } + stream << buf; + + // data + for (; reclen > 0; ++data, --reclen) { + BitValue word = data.data(); + switch (format) { + case IHX8M: + case IHX32: + sprintf(buf, "%02X%02X", word.byte(0), word.byte(1)); + break; + case IHX16: + sprintf(buf, "%02X%02X", word.byte(1), word.byte(0)); + break; + case Nb_Formats: Q_ASSERT(false); break; + } + stream << buf; + check += word.byte(0) + word.byte(1); + } + + // checksum, assumes 2-complement + sprintf(buf, "%02X\n", check.twoComplement().byte(0)); + stream << buf; +} + +/* ------------------------------------------------------------------------- + This routine detects the next block to output + A block is a set of consecutive addresse words not + containing 0xFFFFFFFF + @return true if a block has been detected + 'it' is updated to point to the first address of the block + '*len' contains the size of the block +*/ +bool HexBuffer::fetchNextBlock(const_iterator& it, const const_iterator &end, int *len) +{ + uint startadr, curadr; + // for( i = *start ; (i < MAXPICSIZE) && (Mem[i] == INVALID) ; ++i) ; + // skip non-used words + + // Search block start + while ( it!=end && !it.data().isInitialized() ) ++it; + + // if(i >= MAXPICSIZE ) return false ; + if ( it==end ) return false; + + //for( *start = i ; (i < MAXPICSIZE) && (Mem[i] != INVALID) ; ++i) ; + //*len = i - *start ; + // search block end - a block may not cross a segment boundary + const_iterator itt(it) ; + for (curadr = startadr = itt.key(), ++itt; itt!=end; ++itt) { + if ( itt.key()!=curadr+1 ) break; // non contiguous addresses + if ( !itt.data().isInitialized() ) break; // unused word found + if ( ((itt.key()) & 0xFFFF0000U)!=(curadr & 0xFFFF0000U) ) break; // cross segment boundary + curadr = itt.key(); + } + *len = curadr - startadr + 1 ; + + return *len != 0 ; +} + +QString HexBuffer::ErrorData::message() const +{ + switch (type) { + case UnrecognizedFormat: return i18n("Unrecognized format (line %1).").arg(line); + case UnexpectedEOF: return i18n("Unexpected end-of-file."); + case UnexpectedEOL: return i18n("Unexpected end-of-line (line %1).").arg(line); + case WrongCRC: return i18n("CRC mismatch (line %1).").arg(line); + } + Q_ASSERT(false); + return QString::null; +} + +bool HexBuffer::load(QTextStream &stream, QStringList &errors) +{ + Format format; + QValueList<ErrorData> list = load(stream, format); + if ( list.isEmpty() ) return true; + errors.clear(); + for (uint i=0; i<uint(list.count()); i++) errors += list[i].message(); + return false; +} + +QValueList<HexBuffer::ErrorData> HexBuffer::load(QTextStream &stream, Format &format) +{ + clear(); + format = Nb_Formats; + QValueList<HexBuffer::ErrorData> errors; + load(stream, format, errors); + if ( format==Nb_Formats ) format = IHX8M; // default + return errors; +} + +/* ------------------------------------------------------------------------- + Read a Intel HEX file of either INHX16 or INHX8M format type, detecting + the format automagicly by the wordcount and length of the line + Tested in 8 and 16 bits modes + ------------------------------------------------------------------------ */ +void HexBuffer::load(QTextStream &stream, Format &format, QValueList<ErrorData> &errors) +{ + uint addrH = 0; // upper 16 bits of 32 bits address (inhx32 format) + uint line = 1; + + for (; !stream.atEnd(); line++) { // read each line + QString s = stream.readLine(); + if ( !s.startsWith(":") ) continue; // skip invalid intel hex line + s = s.stripWhiteSpace(); // clean-up white spaces at end-of-line + if ( s==":" ) continue; // skip empty line + + const char *p = s.latin1(); + p += 1; // skip ':' + uint bytecount = (s.length()-11) / 2; // number of data bytes of this record + + // get the byte count, the address and the type for this line. + uint count, addr, type; + if ( sscanf(p, "%02X%04X%02X", &count , &addr, &type)!=3 ) { + errors += ErrorData(line, UnrecognizedFormat); + return; + } + p += 8; + uint cksum = count + (addr >> 8) + (addr & 0xFF) + type; + + if( type==0x01 ) { // EOF field :00 0000 01 FF + uint data; + if ( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); + else if ( ((cksum+data) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); + return; + } + + if ( type==0x04 ) { // linear extended record (for 0x21xxxx, :02 0000 04 0021 D9) + if( sscanf(p, "%04X", &addrH)!=1 ) { + errors += ErrorData(line, UnrecognizedFormat); // bad address record + return; + } + p += 4; + cksum += (addrH & 0xFF); + cksum += (addrH >> 8); + if ( format==Nb_Formats || format==IHX8M ) format = IHX32; + else if ( format!=IHX32 ) { + errors += ErrorData(line, UnrecognizedFormat); // inconsistent format + return; + } + uint data; + if ( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); + else if ( ((cksum+data) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); + //qDebug("new address high: %s", toHex(addrH<<16, 8).data()); + continue; // goto next record + } + + /* Figure out if its INHX16 or INHX8M + if count is a 16 bits words count => INHX16 + if count is a byte count => INHX8M or INHX32 */ + if ( bytecount==count ) { + if ( format==Nb_Formats ) format = IHX8M; + else if ( format!=IHX8M && format!=IHX32 ) { + errors += ErrorData(line, UnrecognizedFormat); // inconsistent format + return; + } + /* Processing a INHX8M line */ + /* Modified to be able to read fuses from hexfile created by C18 toolchain */ + /* changed by Tobias Schoene 9 April 2005, */ + /* modified by A.G, because low and hi bytes was swapped in Tobias's code , 8 may 2005 + */ + uint addrbase = ((addrH << 16) | addr); + //qDebug("line %i: address %s", line, toHex(addrbase, 8).data()); + for (uint x = 0; x<count; x++) { + uint data; + if ( sscanf(p, "%02X", &data)!=1 ) { + errors += ErrorData(line, UnexpectedEOL); + break; + } + p += 2; + // A.G: I suspect possible initialization problem + // if block begins at odd address + // because |= works on an uninitalized word + // however, I don't know if such a situation can occurs + uint a = addrbase+x >> 1; + BitValue value = (*this)[a]; + if ( addrbase+x & 1 ) insert(a, value.maskWith(0x00FF) | data << 8); // Odd addr => Hi byte + else insert(a, value.maskWith(0xFF00) | data); // Low byte + //if ( x==0 ) qDebug("fb@%s: %s", toHex(addrbase+x >> 1, 8).data(), toHex(fb[addrbase+x >> 1], 8).data()); + cksum += data; + } + } else if ( bytecount==count*2 ) { + if ( format==Nb_Formats ) format = IHX16; + else if ( format!=IHX16 ) { + errors += ErrorData(line, UnrecognizedFormat); // inconsistent format + return; + } + /* Processing a INHX16 line */ + for(uint x=0; x<count; x++) { + uint datal, datah; + if( sscanf(p, "%02X%02X", &datah, &datal)!=2 ) { + errors += ErrorData(line, UnexpectedEOL); + break; + } + p += 4; + //qDebug("%s: %s", toHexLabel(addr+x, 4).latin1(), toHexLabel(datal | (datah << 8), 4).latin1()); + insert(addr+x, datal | (datah << 8)); + cksum += datah; + cksum += datal; + } + } else { + errors += ErrorData(line, UnrecognizedFormat); // Brrrr !! Strange format. + return; + } + + /* Process the checksum */ + uint data; + if( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); + else if( ((data + cksum) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); + } + + errors += ErrorData(line, UnexpectedEOF); + return; +} |