RISC-V/V203F6P6/programmer/software/intelhex.cpp
2025-02-03 19:18:47 +01:00

249 lines
6.8 KiB
C++

#include <stdio.h>
#include "string.h"
#include "endien.h"
#include "intelhex.h"
static uint8_t hexval (const char c) {
if ('0' <= c && c <= '9')
return (uint8_t) c - '0';
else if ('a' <= c && c <= 'f')
return (uint8_t) c - 'a' + 10;
else return 0;
}
static unsigned to_hex_str (char * str, const uint8_t * data, const unsigned len) {
unsigned result = 0;
const char * hexstr = "0123456789ABCDEF";
for (unsigned n=0; n<len; n++) {
const uint8_t c = data [n];
str [result++] = hexstr [c >> 4];
str [result++] = hexstr [c & 0xF];
}
return result;
}
static uint8_t chk_sum (const uint8_t * data, const unsigned len) {
uint8_t sum = 0;
for (unsigned n=0; n<len; n++) sum += data [n];
return sum;
}
union IhxHeader {
struct {
uint8_t reclen;
ui16be load;
RowTypes rectyp;
}__attribute__((packed));
uint8_t bytes [4];
};
union UlbaAddr {
ui16be addr;
uint8_t bytes [2];
};
union EipAddr {
ui32be addr;
uint8_t bytes [4];
};
IntelHex::IntelHex() noexcept : address(0), offset(0), lenght(0), total_lenght(0), ackofs(0) {
}
RowTypes IntelHex::parseRecord (const char * data, const unsigned int len) {
//printf ("parseRecord: %d %s\r\n", len, data);
if (data[0] != (uint8_t) ':') return badRecord;
uint8_t tmp [(len >> 1) + 1];
uint8_t val = 0;
unsigned k = 0;
for (unsigned n=1; n<len; n++) {
const uint8_t c = data [n];
if (c == '\r') break;
if (c == '\n') break;
val *= 0x10;
val += hexval (c | 0x20);
if ((n & 1) == 0) {
tmp [k++] = val;
val = 0;
}
}
k -= 1;
uint8_t chk = 0;
for (unsigned n=0; n<k; n++) chk += tmp [n];
chk = 0 - chk;
// kontrolní součet
if (chk != tmp[k]) return badRecord;
// chybná délka
if (k < sizeof (IhxHeader)) return badRecord;
IhxHeader hdr;
memcpy (hdr.bytes, tmp, sizeof(IhxHeader));
// chybná délka
if (k != (hdr.reclen + sizeof(IhxHeader))) return badRecord;
//printf ("%d: %d=%d, %d, %02X=%02X\n", len, k, hdr.reclen+4, hdr.rectyp, chk, tmp[k]);
UlbaAddr a1; EipAddr a2;
RowTypes t = hdr.rectyp;
lenght = hdr.reclen;
const uint8_t * start = tmp + sizeof(IhxHeader);
uint32_t tmpadr;
// uint16_t old_ofs = offset;
switch (t) {
case dataRecord:
memcpy (chunk, start, lenght);
offset = hdr.load.get();
// if (old_ofs != offset) printf ("Posun 0x%04X-0x%04X\n", old_ofs, offset);
total_lenght = offset + lenght;
break;
case elaRecord:
total_lenght = 0;
memcpy (a1.bytes, start, lenght);
address = (uint32_t) a1.addr.get() << 16;
offset = hdr.load.get();
break;
case slaRecord:
memcpy (a2.bytes, start, lenght);
address = a2.addr.get();
offset = hdr.load.get();
break;
case ackRecord:
case nakRecord:
ackofs = hdr.load.get();
break;
case eofRecord:
case reqRecord:
case ersRecord:
offset = hdr.load.get();
break;
// Tyhle 2 rekordy nějak fungují, ale je to divné. Bohužel třeba objcopy
// je na nízkých adresách z nějakého důvodu používá. Možná je v tom chyba.
case esaRecord:
total_lenght = 0;
memcpy (a1.bytes, start, lenght);
address = (uint32_t) a1.addr.get() << 4;
offset = hdr.load.get();
break;
case ssaRecord:
memcpy (a2.bytes, start, lenght);
tmpadr = a2.addr.get();
address = (tmpadr >> 12); // CS:IP ? čerti vědí, jak je to myšleno
offset = hdr.load.get();
break;
default:
break;
}
return t;
}
bool IntelHex::CompareAckOffsset() {
//printf ("ofs: %04X=%04X\n", ackofs, offset);
if (ackofs == offset) return true;
return false;
}
void IntelHex::getAddress (uint32_t & adr) {
adr = address;
}
void IntelHex::getLenght (uint32_t & len) {
len = total_lenght;
}
void IntelHex::getOffset (uint32_t & ofs) {
ofs = offset;
}
void IntelHex::WriteData (uint8_t * data) {
memcpy (data + offset, chunk, lenght);
offset += lenght;
}
uint8_t * IntelHex::getDataRow (uint32_t & ofs, uint32_t & len) {
ofs = offset;
len = lenght;
return chunk;
}
void IntelHex::AddOffset (uint32_t len) {
offset += len;
}
uint32_t IntelHex::ElaRecord (char * string, const uint32_t adr) {
offset = 0;
uint32_t result = 0;
string [result++] = ':';
UlbaAddr lba;
IhxHeader hdr;
hdr.load.set(0);
hdr.reclen = sizeof (lba);
hdr.rectyp = elaRecord;
lba.addr.set (adr >> 16);
uint8_t chk = 0;
chk += chk_sum (hdr.bytes, sizeof(IhxHeader));
chk += chk_sum (lba.bytes, sizeof(UlbaAddr ));
chk = 0 - chk;
result += to_hex_str (string + result, hdr.bytes, sizeof(IhxHeader));
result += to_hex_str (string + result, lba.bytes, sizeof(UlbaAddr ));
result += to_hex_str (string + result, & chk, 1);
string [result++] = '\r';
string [result++] = '\n';
string [result] = '\0';
return result;
}
uint32_t IntelHex::SlaRecord (char* string, const uint32_t adr) {
offset = 0;
uint32_t result = 0;
string [result++] = ':';
EipAddr lba;
IhxHeader hdr;
hdr.load.set(0);
hdr.reclen = sizeof (lba);
hdr.rectyp = slaRecord;
lba.addr.set (adr);
uint8_t chk = 0;
chk += chk_sum (hdr.bytes, sizeof(IhxHeader));
chk += chk_sum (lba.bytes, sizeof(EipAddr ));
chk = 0 - chk;
result += to_hex_str (string + result, hdr.bytes, sizeof(IhxHeader));
result += to_hex_str (string + result, lba.bytes, sizeof(EipAddr ));
result += to_hex_str (string + result, & chk, 1);
string [result++] = '\r';
string [result++] = '\n';
string [result] = '\0';
return result;
}
uint32_t IntelHex::DataRecord (char * string, const uint8_t * data, const uint32_t len) {
uint32_t result = 0;
string [result++] = ':';
IhxHeader hdr;
hdr.load.set (offset);
hdr.reclen = len;
hdr.rectyp = dataRecord;
uint8_t chk = 0;
chk += chk_sum (hdr.bytes, sizeof(IhxHeader));
chk += chk_sum (data, len);
chk = 0 - chk;
result += to_hex_str (string + result, hdr.bytes, sizeof(IhxHeader));
if (len) result += to_hex_str (string + result, data, len);
result += to_hex_str (string + result, & chk, 1);
string [result++] = '\r';
string [result++] = '\n';
string [result] = '\0';
return result;
}
uint32_t IntelHex::EofRecord (char * string) {
offset = 0;
const char * eof = ":00000001FF\r\n";
const uint32_t result = strlen (eof);
memcpy (string, eof, result);
string [result] = '\0';
return result;
}
uint32_t IntelHex::BTxRecord (char * string, RowTypes t) {
uint32_t result = 0;
string [result++] = ':';
IhxHeader hdr;
hdr.load.set (offset);
hdr.reclen = 0;
hdr.rectyp = t;
uint8_t chk = 0;
chk += chk_sum (hdr.bytes, sizeof(IhxHeader));
chk = 0 - chk;
result += to_hex_str (string + result, hdr.bytes, sizeof(IhxHeader));
result += to_hex_str (string + result, & chk, 1);
string [result++] = '\r';
string [result++] = '\n';
string [result] = '\0';
//offset += len;
return result;
}