You can not 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/base/hex_buffer.cpp

291 lines
11 KiB

/***************************************************************************
* 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 <tqtextstream.h>
#include "devices/base/generic_device.h"
//-----------------------------------------------------------------------------
const char * const HexBuffer::FORMATS[Nb_Formats] = {
"inhx8m", /*"inhx8s", */"inhx16", "inhx32"
};
void HexBuffer::savePartial(TQTextStream &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(TQTextStream &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(TQTextStream &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 ;
}
TQString HexBuffer::ErrorData::message() const
{
switch (type) {
case UnrecognizedFormat: return i18n("Unrecognized format (line %1).").tqarg(line);
case UnexpectedEOF: return i18n("Unexpected end-of-file.");
case UnexpectedEOL: return i18n("Unexpected end-of-line (line %1).").tqarg(line);
case WrongCRC: return i18n("CRC mismatch (line %1).").tqarg(line);
}
Q_ASSERT(false);
return TQString();
}
bool HexBuffer::load(TQTextStream &stream, TQStringList &errors)
{
Format format;
TQValueList<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;
}
TQValueList<HexBuffer::ErrorData> HexBuffer::load(TQTextStream &stream, Format &format)
{
clear();
format = Nb_Formats;
TQValueList<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(TQTextStream &stream, Format &format, TQValueList<ErrorData> &errors)
{
uint addrH = 0; // upper 16 bits of 32 bits address (inhx32 format)
uint line = 1;
for (; !stream.atEnd(); line++) { // read each line
TQString 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;
}