#include <windows.h>
#include <stdio.h>
#if defined(UNICODE) && !defined(_UNICODE)
# define _UNICODE
#endif
#include <tchar.h>
#define elemof(x) (sizeof(x)/sizeof(*(x)))
#define nobreak
#define T(x) TEXT(x)
typedef const TCHAR *PCTSTR;
// error codes
enum{
IHEX_LINE_NO_COLON=-47,
IHEX_LINE_TOO_SHORT,
IHEX_LINE_GARBAGE,
IHEX_WRONG_CHECKSUM,
SREC_LINE_NO_S,
SREC_LINE_TOO_SHORT,
SREC_LINE_GARBAGE,
SREC_WRONG_CHECKSUM,
TEXT_LINE_GARBAGE,
};
// when writing HEX or SREC files
#define MAX_WRITE_BYTES_PER_LINE 16 // 32 bytes per line can be read, but this program writes shorter lines
#define MAX_CHAR_PER_LINE 82 // longest IHEX oder SREC record text line expected, including "\r\n\0"
struct LINEFILE{
virtual int put(char*)=0;
virtual int get(const char*)=0;
virtual int putf(FILE*);
virtual int getf(FILE*);
};
#pragma pack(1)
struct IHEXRECORD:LINEFILE{
union{
BYTE all[37];
DWORD head; // Combined access to the first 4 bytes
struct{
BYTE len; // 0..20h, for the data part
WORD addr; // only for 16 bit address space, big endian!
BYTE rectype; // see below
BYTE data[32]; // variable length, therefore checksum is not really at <cs> position
BYTE cs; // checksum, all bytes added must result in 0
};
};
virtual int put(char*); // encode record to ASCII
virtual int get(const char*); // decode record from ASCII
};
#pragma pack()
// record types [Wikipedia]
// 00 = data, len = 1..32, addr = load address
// 01 = end of file, len = 0, addr = start address
// 02 = segment address (x86), len = 2, addr = 0, data = segment address, endianness?
// 03 = FAR start address (x86), len = 4, addr = 0, data = CShi CSlo IPhi IPlo
// 04 = linear high address, len = 2, addr = 0, data = high part of data load address
// 05 = start linear address, len = 4, addr = 0, data = address (big endian?)
struct SRECRECORD:LINEFILE{
union{
BYTE all[39];
DWORD head; // Combined access to the first 4 bytes
struct{
BYTE rectype; // see below, the 'S' is tought stripped to '0'
BYTE len; // byte count that follow, inclusive checksum
BYTE data[36]; // contains a 2/3/4 byte address, variable length
BYTE cs; // checksum, from <len> bytes added must result in 0
};
};
virtual int put(char*); // encode record to ASCII
virtual int get(const char*); // decode record from ASCII
};
// record types [Wikipedia]
// 0 = Block Header, len = 3..37, addr = 2 Bytes (meist 0000h), data = vendor specific
// 1 = Data with 2-byte address, MSB first
// 2 = Data with 3-byte address
// 3 = Data with 4-byte address
// 5 = Record count, len = 3, addr = 2 Bytes
// 7 = End of block with 4-byte start address, len = 5
// 8 = End of block with 3-byte start address, len = 4
// 9 = End of block with 2-byte start address, len = 3
struct TEXTRECORD:LINEFILE{
int len; // 0..32 = data, '@' = address (always DWORD)
union{
DWORD addr;
BYTE data[32];
};
virtual int put(char*); // encode record to ASCII
virtual int get(const char*); // decode record from ASCII
};
// Abstract base class, i.e. an interface.
// All classes should work on streams, i.e. do not use fseek()
// Negative return values indicate errors.
// Non-negative return values indicate read or written bytes.
struct FILEIO{
DWORD addr; // the address for the data to read/write
DWORD start; // start address (if given)
bool write; // =true when in write mode
bool havestart; // start address found, or should be written
virtual int Open(PCTSTR FileName,bool Write=false)=0;
virtual int Read(BYTE*buf, int siz, DWORD&adr)=0; // returns 0 on EOF; siz must be >0
virtual int Write(const BYTE*buf, int siz, DWORD adr)=0;
virtual int Close()=0;
};
// Derivated class for INTEL HEX files
class IHEXFILEIO:public FILEIO{
FILE*f; // stdio file handle (must be closed on error manually)
IHEXRECORD hr; // last interpreted record (to not seek backward)
DWORD segaddr; // address found in record type 2 (shiftet by 4), else 0
DWORD linaddr; // address found in record type 4 (shifted by 16), else 0
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr);
virtual int Close();
};
// Derivated class for MOTOROLA SREC files
class SRECFILEIO:public FILEIO{
FILE*f; // stdio file handle (must be closed on error manually)
SRECRECORD hr; // last interpreted record (to not seek backward)
BYTE addrlen; // can be preset but can rise with address length on write (2, 3 or 4 is valid)
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr);
virtual int Close();
};
// Derivated class for Texas Instrument's TEXT files
// (IMHO a useable file format but a stupid file extension)
class TEXTFILEIO:public FILEIO{
FILE*f; // stdio file handle
TEXTRECORD hr;
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr);
virtual int Close();
};
// Derivated class for ELF files (reading only)
class ELFFILEIO:public FILEIO{
struct ELFHDR {
union{
struct{
BYTE magic[4]; // "\x7FELF"
BYTE eclass; // 1 for 32-bit
BYTE data; // 1 for little endian, 2 for big endian
BYTE version; // (1)
BYTE pad[9]; // (0xFF, then 0x00)
};
DWORD dw[4];
}ident;
WORD type;
WORD machine;
enum{
T_EXEC = 2, // executable file
M_MSP430 =105,
};
DWORD version; // (1)
DWORD entry; // (00004400) start address
DWORD phoff; // (00000034) program header table
DWORD shoff; // (0000AF78) section header table
DWORD flags; // (00000036)
WORD ehsize; // (0034) this size
WORD phentsize; // (0020) header table entry size (32 byte)
WORD phnum; // (0002) header table entries (2)
WORD shentsize; // (0028) section header entry size (40 byte)
WORD shnum; // (000D) section header entries (13)
WORD shstrndx; // (000A) index of section name string table (10)
};
struct Proghdr32 {
DWORD type, // Headers with type != PT_LOAD (=1) are ignored
offset, // offset of data bits in ELF file
vaddr, // not needed (VMA)
paddr, // offset where to load into flash (LMA)
filesz, // size of section in file (0 for .bss)
memsz, // not needed
flags, // not needed
align; // not needed
};
BYTE*filemap; // mapped file content
int phti; // current program header table to process
int dataindex; // current data byte index
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr) {return -1;}
virtual int Close();
};
// Derivated class for binary dumps (with an address offset)
// Remember: DOS + CP/M .COM files had a fixed offset of 0x100
class BINFILEIO:public FILEIO{
FILE*f; // stdio file handle
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr);
virtual int Close();
};
// Derivated class for given bytes on command line
class NOFILEIO:public FILEIO{
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr);
virtual int Close();
};
// Derivated class for resource data (internal use for RAM bootloader)
class RESIO:public FILEIO{
HRSRC hRes; // loaded resource handle
union {
void*vp;
BYTE*bp;
DWORD*dp;
long*lp;
}pRes; // moving pointer to mapped resource data
long rest; // number of data bytes not yet read
virtual int Open(PCTSTR FileName,bool Write);
virtual int Read(BYTE*buf, int siz, DWORD&adr);
virtual int Write(const BYTE*buf, int siz, DWORD adr) {return -1;}
virtual int Close();
};
// Each resource data chunk consists of:
// 1 DWORD target address
// 1 DWORD data length, in bytes
// n BYTE data
// The final record has a zero data length, its address is the start address,
// if not (DWORD)-1
Detected encoding: ASCII (7 bit) | 2
|