From c3b0fa04a663fe233765b83d3be41a42aa08c25d Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Mon, 3 May 2021 08:21:10 +0100 Subject: Initial import for public release --- tools/hex2bin-2.0/src/binary.c | 196 +++++++++++++ tools/hex2bin-2.0/src/binary.h | 36 +++ tools/hex2bin-2.0/src/common.c | 527 ++++++++++++++++++++++++++++++++++ tools/hex2bin-2.0/src/common.h | 116 ++++++++ tools/hex2bin-2.0/src/hex2bin.1 | 294 +++++++++++++++++++ tools/hex2bin-2.0/src/hex2bin.c | 587 ++++++++++++++++++++++++++++++++++++++ tools/hex2bin-2.0/src/hex2bin.pod | 161 +++++++++++ tools/hex2bin-2.0/src/libcrc.c | 204 +++++++++++++ tools/hex2bin-2.0/src/libcrc.h | 44 +++ tools/hex2bin-2.0/src/mot2bin.c | 518 +++++++++++++++++++++++++++++++++ 10 files changed, 2683 insertions(+) create mode 100644 tools/hex2bin-2.0/src/binary.c create mode 100644 tools/hex2bin-2.0/src/binary.h create mode 100644 tools/hex2bin-2.0/src/common.c create mode 100644 tools/hex2bin-2.0/src/common.h create mode 100644 tools/hex2bin-2.0/src/hex2bin.1 create mode 100644 tools/hex2bin-2.0/src/hex2bin.c create mode 100644 tools/hex2bin-2.0/src/hex2bin.pod create mode 100644 tools/hex2bin-2.0/src/libcrc.c create mode 100644 tools/hex2bin-2.0/src/libcrc.h create mode 100644 tools/hex2bin-2.0/src/mot2bin.c (limited to 'tools/hex2bin-2.0/src') diff --git a/tools/hex2bin-2.0/src/binary.c b/tools/hex2bin-2.0/src/binary.c new file mode 100644 index 0000000..63ead0d --- /dev/null +++ b/tools/hex2bin-2.0/src/binary.c @@ -0,0 +1,196 @@ +/*---------------------------------------------------------------------------* + * binary.c * + * Copyright (C) 2014 Jacques Pelletier * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation, * + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + *---------------------------------------------------------------------------*/ + +#include + +#include "binary.h" + +const uint8_t Reflect8[256] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; + +uint16_t Reflect16(uint16_t Value16) +{ + return (((uint16_t) Reflect8[u16_lo(Value16)]) << 8) | ((uint16_t) Reflect8[u16_hi(Value16)]); +} + +uint32_t Reflect24(uint32_t Value24) +{ + return ( + (((uint32_t) Reflect8[u32_b0(Value24)]) << 16) | + (((uint32_t) Reflect8[u32_b1(Value24)]) << 8) | + ((uint32_t) Reflect8[u32_b2(Value24)]) + ); +} + +uint32_t Reflect32(uint32_t Value32) +{ + return ( + (((uint32_t) Reflect8[u32_b0(Value32)]) << 24) | + (((uint32_t) Reflect8[u32_b1(Value32)]) << 16) | + (((uint32_t) Reflect8[u32_b2(Value32)]) << 8) | + ((uint32_t) Reflect8[u32_b3(Value32)]) + ); +} + +uint64_t Reflect40(uint64_t Value40) +{ + return ( + (((uint64_t) Reflect8[u64_b0(Value40)]) << 32) | + (((uint64_t) Reflect8[u64_b1(Value40)]) << 24) | + (((uint64_t) Reflect8[u64_b2(Value40)]) << 16) | + (((uint64_t) Reflect8[u64_b3(Value40)]) << 8) | + ((uint64_t) Reflect8[u64_b4(Value40)]) + ); +} + +uint64_t Reflect64(uint64_t Value64) +{ + return ( + (((uint64_t) Reflect8[u64_b0(Value64)]) << 56) | + (((uint64_t) Reflect8[u64_b1(Value64)]) << 48) | + (((uint64_t) Reflect8[u64_b2(Value64)]) << 40) | + (((uint64_t) Reflect8[u64_b3(Value64)]) << 32) | + (((uint64_t) Reflect8[u64_b4(Value64)]) << 24) | + (((uint64_t) Reflect8[u64_b5(Value64)]) << 16) | + (((uint64_t) Reflect8[u64_b6(Value64)]) << 8) | + ((uint64_t) Reflect8[u64_b7(Value64)]) + ); +} + +uint8_t u16_hi(uint16_t value) +{ + return (uint8_t)((value & 0xFF00) >> 8); +} + +uint8_t u16_lo(uint16_t value) +{ + return (uint8_t)(value & 0x00FF); +} + +uint8_t u32_b3(uint32_t value) +{ + return (uint8_t)((value & 0xFF000000) >> 24); +} + +uint8_t u32_b2(uint32_t value) +{ + return (uint8_t)((value & 0x00FF0000) >> 16); +} + +uint8_t u32_b1(uint32_t value) +{ + return (uint8_t)((value & 0x0000FF00) >> 8); +} + +uint8_t u32_b0(uint32_t value) +{ + return (uint8_t)(value & 0x000000FF); +} + +uint8_t u64_b7(uint64_t value) +{ + return (uint8_t)((value & 0xFF00000000000000) >> 56); +} + +uint8_t u64_b6(uint64_t value) +{ + return (uint8_t)((value & 0x00FF000000000000) >> 48); +} + +uint8_t u64_b5(uint64_t value) +{ + return (uint8_t)((value & 0x0000FF0000000000) >> 40); +} + +uint8_t u64_b4(uint64_t value) +{ + return (uint8_t)((value & 0x000000FF00000000) >> 32); +} + +uint8_t u64_b3(uint64_t value) +{ + return (uint8_t)((value & 0x00000000FF000000) >> 24); +} + +uint8_t u64_b2(uint64_t value) +{ + return (uint8_t)((value & 0x0000000000FF0000) >> 16); +} + +uint8_t u64_b1(uint64_t value) +{ + return (uint8_t)((value & 0x000000000000FF00) >> 8); +} + +uint8_t u64_b0(uint64_t value) +{ + return (uint8_t)(value & 0x00000000000000FF); +} + +/* Checksum/CRC conversion to ASCII */ +uint8_t nibble2ascii(uint8_t value) +{ + uint8_t result = value & 0x0f; + + if (result > 9) return result + 0x41-0x0A; + else return result + 0x30; +} + +bool cs_isdecdigit(char c) +{ + return (c >= 0x30) && (c < 0x3A); +} + +unsigned char tohex(unsigned char c) +{ + if ((c >= '0') && (c < '9'+1)) + return (c - '0'); + if ((c >= 'A') && (c < 'F'+1)) + return (c - 'A' + 0x0A); + if ((c >= 'a') && (c < 'f'+1)) + return (c - 'a' + 0x0A); + + return 0; +} + +unsigned char todecimal(unsigned char c) +{ + if ((c >= '0') && (c < '9'+1)) + return (c - '0'); + + return 0; +} + + diff --git a/tools/hex2bin-2.0/src/binary.h b/tools/hex2bin-2.0/src/binary.h new file mode 100644 index 0000000..198589b --- /dev/null +++ b/tools/hex2bin-2.0/src/binary.h @@ -0,0 +1,36 @@ +#ifndef _BINARY_H_ +#define _BINARY_H_ + +typedef enum {false, true} bool; + +extern const unsigned char Reflect8[256]; + +uint16_t Reflect16(uint16_t Value16); +uint32_t Reflect24(uint32_t Value24); +uint32_t Reflect32(uint32_t Value32); +uint64_t Reflect40(uint64_t Value40); +uint64_t Reflect64(uint64_t Value64); + +uint8_t u16_hi(uint16_t value); +uint8_t u16_lo(uint16_t value); + +uint8_t u32_b3(uint32_t value); +uint8_t u32_b2(uint32_t value); +uint8_t u32_b1(uint32_t value); +uint8_t u32_b0(uint32_t value); + +uint8_t u64_b7(uint64_t value); +uint8_t u64_b6(uint64_t value); +uint8_t u64_b5(uint64_t value); +uint8_t u64_b4(uint64_t value); +uint8_t u64_b3(uint64_t value); +uint8_t u64_b2(uint64_t value); +uint8_t u64_b1(uint64_t value); +uint8_t u64_b0(uint64_t value); + +uint8_t nibble2ascii(uint8_t value); +bool cs_isdecdigit(char c); +unsigned char tohex(unsigned char c); +unsigned char todecimal(unsigned char c); + +#endif /* _BINARY_H_ */ diff --git a/tools/hex2bin-2.0/src/common.c b/tools/hex2bin-2.0/src/common.c new file mode 100644 index 0000000..f453dc4 --- /dev/null +++ b/tools/hex2bin-2.0/src/common.c @@ -0,0 +1,527 @@ +#include "common.h" + +filetype Filename; /* string for opening files */ +char Extension[MAX_EXTENSION_SIZE]; /* filename extension for output files */ + +FILE *Filin, /* input files */ + *Filout; /* output files */ + +#ifdef USE_FILE_BUFFERS +char *FilinBuf, /* text buffer for file input */ + *FiloutBuf; /* text buffer for file output */ +#endif + +int Pad_Byte = 0xFF; +bool Enable_Checksum_Error = false; +bool Status_Checksum_Error = false; +byte Checksum; +unsigned int Record_Nb; + +/* This will hold binary codes translated from hex file. */ +byte *Memory_Block; +unsigned int Lowest_Address, Highest_Address; +unsigned int Starting_Address; +unsigned int Max_Length = 0; +unsigned int Minimum_Block_Size = 0x1000; // 4096 byte +int Module; +bool Minimum_Block_Size_Setted = false; +bool Starting_Address_Setted = false; +bool Max_Length_Setted = false; +bool Swap_Wordwise = false; + +int Endian = 0; + +t_CRC Cks_Type = CHK8_SUM; +unsigned int Cks_Start = 0, Cks_End = 0, Cks_Addr = 0, Cks_Value = 0; +bool Cks_range_set = false; +bool Cks_Addr_set = false; +bool Force_Value = false; + +unsigned int Crc_Poly = 0x07, Crc_Init = 0, Crc_XorOut = 0; +bool Crc_RefIn = false; +bool Crc_RefOut = false; + +void usage(void) +{ + fprintf (stderr, + "\n" + "usage: %s [OPTIONS] filename\n" + "Options:\n" + " -c Enable record checksum verification\n" + " -C [Poly][Init][RefIn][RefOut][XorOut]\n CRC parameters" + " -e [ext] Output filename extension (without the dot)\n" + " -E [0|1] Endian for checksum/CRC, 0: little, 1: big\n" + " -f [address] Address of check result to write\n" + " -F [address] [value]\n Address and value to force\n" + " -k [0-4] Select check method (checksum or CRC) and size\n" + " -d display list of check methods/value size\n" + " -l [length] Maximal Length (Starting address + Length -1 is Max Address)\n" + " File will be filled with Pattern until Max Address is reached\n" + " -m [size] Minimum Block Size\n" + " File Size Dimension will be a multiple of Minimum block size\n" + " File will be filled with Pattern\n" + " Length must be a power of 2 in hexadecimal [see -l option]\n" + " Attention this option is STRONGER than Maximal Length \n" + " -p [value] Pad-byte value in hex (default: %x)\n" + " -r [start] [end]\n" + " Range to compute checksum over (default is min and max addresses)\n" + " -s [address] Starting address in hex (default: 0)\n" + " -w Swap wordwise (low <-> high)\n\n", + Pgm_Name,Pad_Byte); + exit(1); +} /* procedure USAGE */ + +void DisplayCheckMethods(void) +{ + fprintf (stderr, + "Check methods/value size:\n" + "0: Checksum 8-bit\n" + "1: Checksum 16-bit\n" + "2: CRC8\n" + "3: CRC16\n" + "4: CRC32\n"); + exit(1); +} + +#define LAST_CHECK_METHOD 4 + +void *NoFailMalloc (size_t size) +{ + void *result; + + if ((result = malloc (size)) == NULL) + { + fprintf (stderr,"Can't allocate memory.\n"); + exit(1); + } + return (result); +} + +/* Open the input file, with error checking */ +void NoFailOpenInputFile (char *Flnm) +{ + while ((Filin = fopen(Flnm,"r")) == NULL) + { + fprintf (stderr,"Input file %s cannot be opened. Enter new filename: ",Flnm); + if (fgets (Flnm,MAX_FILE_NAME_SIZE,stdin) == NULL) exit(1); /* modified error checking */ + + if (Flnm[strlen(Flnm) - 1] == '\n') Flnm[strlen(Flnm) - 1] = '\0'; + } + +#ifdef USE_FILE_BUFFERS + FilinBuf = (char *) NoFailMalloc (BUFFSZ); + setvbuf(Filin, FilinBuf, _IOFBF, BUFFSZ); +#endif +} /* procedure OPENFILIN */ + +/* Open the output file, with error checking */ +void NoFailOpenOutputFile (char *Flnm) +{ + while ((Filout = fopen(Flnm,"wb")) == NULL) + { + /* Failure to open the output file may be + simply due to an insufficiant permission setting. */ + fprintf(stderr,"Output file %s cannot be opened. Enter new file name: ", Flnm); + if (fgets(Flnm,MAX_FILE_NAME_SIZE,stdin) == NULL) exit(1); + + if (Flnm[strlen(Flnm) - 1] == '\n') Flnm[strlen(Flnm) - 1] = '\0'; + } + +#ifdef USE_FILE_BUFFERS + FiloutBuf = (char *) NoFailMalloc (BUFFSZ); + setvbuf(Filout, FiloutBuf, _IOFBF, BUFFSZ); +#endif + +} /* procedure OPENFILOUT */ + +void GetLine(char* str,FILE *in) +{ + char *result; + + result = fgets(str,MAX_LINE_SIZE,in); + if ((result == NULL) && !feof (in)) fprintf(stderr,"Error occurred while reading from file\n"); +} + +// 0 or 1 +int GetBin(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%u",&value); + + if (result == 1) return value & 1; + else + { + fprintf(stderr,"GetBin: some error occurred when parsing options.\n"); + exit (1); + } +} + +int GetDec(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%u",&value); + + if (result == 1) return value; + else + { + fprintf(stderr,"GetDec: some error occurred when parsing options.\n"); + exit (1); + } +} + +int GetHex(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%x",&value); + + if (result == 1) return value; + else + { + fprintf(stderr,"GetHex: some error occurred when parsing options.\n"); + exit (1); + } +} + +// Char t/T: true f/F: false +bool GetBoolean(const char *str) +{ + int result; + unsigned char value, temp; + + result = sscanf(str,"%c",&value); + temp = tolower(value); + + if ((result == 1) && ((temp == 't') || (temp == 'f'))) + { + return (temp == 't'); + } + else + { + fprintf(stderr,"GetBoolean: some error occurred when parsing options.\n"); + exit (1); + } +} + +void GetExtension(const char *str,char *ext) +{ + if (strlen(str) > MAX_EXTENSION_SIZE) + usage(); + + strcpy(ext, str); +} + +/* Adds an extension to a file name */ +void PutExtension(char *Flnm, char *Extension) +{ + char *Period; /* location of period in file name */ + bool Samename; + + /* This assumes DOS like file names */ + /* Don't use strchr(): consider the following filename: + ../my.dir/file.hex + */ + if ((Period = strrchr(Flnm,'.')) != NULL) + *(Period) = '\0'; + + Samename = false; + if (strcmp(Extension, Period+1) == 0) + Samename = true; + + strcat(Flnm,"."); + strcat(Flnm, Extension); + if (Samename) + { + fprintf (stderr,"Input and output filenames (%s) are the same.", Flnm); + exit(1); + } +} + +void VerifyChecksumValue(void) +{ + if ((Checksum != 0) && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error in record %d: should be %02X\n", + Record_Nb, (256 - Checksum) & 0xFF); + Status_Checksum_Error = true; + } +} + +void CrcParamsCheck(void) +{ + switch (Cks_Type) + { + case CRC8: + Crc_Poly &= 0xFF; + Crc_Init &= 0xFF; + Crc_XorOut &= 0xFF; + break; + case CRC16: + Crc_Poly &= 0xFFFF; + Crc_Init &= 0xFFFF; + Crc_XorOut &= 0xFFFF; + break; + case CRC32: + break; + default: + fprintf (stderr,"See file CRC list.txt for parameters\n"); + exit(1); + } +} + +void WriteMemBlock16(uint16_t Value) +{ + if (Endian == 1) + { + Memory_Block[Cks_Addr - Lowest_Address] = u16_hi(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u16_lo(Value); + } + else + { + Memory_Block[Cks_Addr - Lowest_Address +1] = u16_hi(Value); + Memory_Block[Cks_Addr - Lowest_Address] = u16_lo(Value); + } +} + +void WriteMemBlock32(uint32_t Value) +{ + if (Endian == 1) + { + Memory_Block[Cks_Addr - Lowest_Address] = u32_b3(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u32_b2(Value); + Memory_Block[Cks_Addr - Lowest_Address +2] = u32_b1(Value); + Memory_Block[Cks_Addr - Lowest_Address +3] = u32_b0(Value); + } + else + { + Memory_Block[Cks_Addr - Lowest_Address +3] = u32_b3(Value); + Memory_Block[Cks_Addr - Lowest_Address +2] = u32_b2(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u32_b1(Value); + Memory_Block[Cks_Addr - Lowest_Address] = u32_b0(Value); + } +} + +void WriteMemory(void) +{ + if ((Cks_Addr >= Lowest_Address) || (Cks_Addr < Highest_Address)) + { + if(Force_Value) + { + switch (Cks_Type) + { + case 0: + Memory_Block[Cks_Addr - Lowest_Address] = Cks_Value; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, Cks_Value); + break; + case 1: + WriteMemBlock16(Cks_Value); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, Cks_Value); + break; + case 2: + WriteMemBlock32(Cks_Value); + fprintf(stdout,"Addr %08X set to %08X\n",Cks_Addr, Cks_Value); + break; + default:; + } + } + else if (Cks_Addr_set) + { + /* Add a checksum to the binary file */ + if (!Cks_range_set) + { + Cks_Start = Lowest_Address; + Cks_End = Highest_Address; + } + /* checksum range MUST BE in the array bounds */ + + if (Cks_Start < Lowest_Address) + { + fprintf(stdout,"Modifying range start from %X to %X\n",Cks_Start,Lowest_Address); + Cks_Start = Lowest_Address; + } + if (Cks_End > Highest_Address) + { + fprintf(stdout,"Modifying range end from %X to %X\n",Cks_End,Highest_Address); + Cks_End = Highest_Address; + } + + switch (Cks_Type) + { + case CHK8_SUM: + { + uint8_t wCKS = 0; + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + wCKS += Memory_Block[i - Lowest_Address]; + } + + fprintf(stdout,"8-bit Checksum = %02X\n",wCKS & 0xff); + Memory_Block[Cks_Addr - Lowest_Address] = wCKS; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, wCKS); + } + break; + + case CHK16: + { + uint16_t wCKS, w; + + wCKS = 0; + + if (Endian == 1) + { + for (unsigned int i=Cks_Start; i<=Cks_End; i+=2) + { + w = Memory_Block[i - Lowest_Address +1] | ((word)Memory_Block[i - Lowest_Address] << 8); + wCKS += w; + } + } + else + { + for (unsigned int i=Cks_Start; i<=Cks_End; i+=2) + { + w = Memory_Block[i - Lowest_Address] | ((word)Memory_Block[i - Lowest_Address +1] << 8); + wCKS += w; + } + } + fprintf(stdout,"16-bit Checksum = %04X\n",wCKS); + WriteMemBlock16(wCKS); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, wCKS); + } + break; + + case CRC8: + { + uint8_t CRC8; + crc_table = NoFailMalloc(256); + + if (Crc_RefIn) + { + init_crc8_reflected_tab(Reflect8[Crc_Poly]); + CRC8 = Reflect8[Crc_Init]; + } + else + { + init_crc8_normal_tab(Crc_Poly); + CRC8 = Crc_Init; + } + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC8 = update_crc8(CRC8,Memory_Block[i - Lowest_Address]); + } + + CRC8 = (CRC8 ^ Crc_XorOut) & 0xff; + Memory_Block[Cks_Addr - Lowest_Address] = CRC8; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, CRC8); + } + break; + + case CRC16: + { + uint16_t CRC16; + crc_table = NoFailMalloc(256 * 2); + + if (Crc_RefIn) + { + init_crc16_reflected_tab(Reflect16(Crc_Poly)); + CRC16 = Reflect16(Crc_Init); + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC16 = update_crc16_reflected(CRC16,Memory_Block[i - Lowest_Address]); + } + } + else + { + init_crc16_normal_tab(Crc_Poly); + CRC16 = Crc_Init; + + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC16 = update_crc16_normal(CRC16,Memory_Block[i - Lowest_Address]); + } + } + + CRC16 = (CRC16 ^ Crc_XorOut) & 0xffff; + WriteMemBlock16(CRC16); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, CRC16); + } + break; + + case CRC32: + { + uint32_t CRC32; + + crc_table = NoFailMalloc(256 * 4); + if (Crc_RefIn) + { + init_crc32_reflected_tab(Reflect32(Crc_Poly)); + CRC32 = Reflect32(Crc_Init); + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC32 = update_crc32_reflected(CRC32,Memory_Block[i - Lowest_Address]); + } + } + else + { + init_crc32_normal_tab(Crc_Poly); + CRC32 = Crc_Init; + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC32 = update_crc32_normal(CRC32,Memory_Block[i - Lowest_Address]); + } + } + + CRC32 ^= Crc_XorOut; + WriteMemBlock32(CRC32); + fprintf(stdout,"Addr %08X set to %08X\n",Cks_Addr, CRC32); + } + break; + + default: + ; + } + + free(crc_table); + } + } + else + { + fprintf (stderr,"Force/Check address outside of memory range\n"); + } + + /* write binary file */ + fwrite (Memory_Block, + Max_Length, + 1, + Filout); + + free (Memory_Block); + + // Minimum_Block_Size is set; the memory buffer is multiple of this? + if (Minimum_Block_Size_Setted==true) + { + Module = Max_Length % Minimum_Block_Size; + if (Module) + { + Memory_Block = (byte *) NoFailMalloc(Module); + memset (Memory_Block,Pad_Byte,Module); + fwrite (Memory_Block, + Module, + 1, + Filout); + free (Memory_Block); + if (Max_Length_Setted==true) + fprintf(stdout,"Attention Max Length changed by Minimum Block Size\n"); + } + } +} diff --git a/tools/hex2bin-2.0/src/common.h b/tools/hex2bin-2.0/src/common.h new file mode 100644 index 0000000..64caff5 --- /dev/null +++ b/tools/hex2bin-2.0/src/common.h @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +#include "binary.h" +#include "libcrc.h" + +/* To compile with Microsoft Visual Studio */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(MSDOS) || defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) +#define _IS_OPTION_(x) (((x) == '-') || ((x) == '/')) +#else +/* Assume unix and similar */ +/* We don't accept an option beginning with a '/' because it could be a file name. */ +#define _IS_OPTION_(x) ((x) == '-') +#endif + +/* We use buffer to speed disk access. */ +#ifdef USE_FILE_BUFFERS +#define BUFFSZ 4096 +#endif + +/* FIXME how to get it from the system/OS? */ +#define MAX_FILE_NAME_SIZE 81 + +#ifdef DOS +#define MAX_EXTENSION_SIZE 4 +#else +#define MAX_EXTENSION_SIZE 16 +#endif + +/* The data records can contain 255 bytes: this means 512 characters. */ +#define MAX_LINE_SIZE 1024 + +typedef char filetype[MAX_FILE_NAME_SIZE]; +typedef unsigned char byte; +typedef unsigned short word; + +#define LAST_CHECK_METHOD 4 + +typedef enum Crc +{ + CHK8_SUM =0, + CHK16, + CRC8, + CRC16, + CRC32 +} t_CRC; + +extern const char *Pgm_Name; +void usage(void); +void DisplayCheckMethods(void); + +void *NoFailMalloc (size_t size); +void NoFailOpenInputFile (char *Flnm); +void NoFailOpenOutputFile (char *Flnm); +void GetLine(char* str,FILE *in); +int GetBin(const char *str); +int GetDec(const char *str); +int GetHex(const char *str); +bool GetBoolean(const char *str); +void GetExtension(const char *str,char *ext); +void PutExtension(char *Flnm, char *Extension); + +filetype Filename; /* string for opening files */ +char Extension[MAX_EXTENSION_SIZE]; /* filename extension for output files */ + +FILE *Filin, /* input files */ + *Filout; /* output files */ + +#ifdef USE_FILE_BUFFERS +char *FilinBuf, /* text buffer for file input */ + *FiloutBuf; /* text buffer for file output */ +#endif + +int Pad_Byte; +bool Enable_Checksum_Error; +bool Status_Checksum_Error; +byte Checksum; +unsigned int Record_Nb; + +/* This will hold binary codes translated from hex file. */ +byte *Memory_Block; +unsigned int Lowest_Address, Highest_Address; +unsigned int Starting_Address; +unsigned int Max_Length; +unsigned int Minimum_Block_Size; +int Module; +bool Minimum_Block_Size_Setted; +bool Starting_Address_Setted; +bool Max_Length_Setted; +bool Swap_Wordwise; + +int Endian; + +t_CRC Cks_Type; +unsigned int Cks_Start, Cks_End, Cks_Addr, Cks_Value; +bool Cks_range_set; +bool Cks_Addr_set; +bool Force_Value; + +unsigned int Crc_Poly, Crc_Init, Crc_XorOut; +bool Crc_RefIn; +bool Crc_RefOut; + +void VerifyChecksumValue(void); +void CrcParamsCheck(void); +void WriteMemBlock16(uint16_t Value); +void WriteMemBlock32(uint32_t Value); +void WriteMemory(void); + diff --git a/tools/hex2bin-2.0/src/hex2bin.1 b/tools/hex2bin-2.0/src/hex2bin.1 new file mode 100644 index 0000000..c2e5e89 --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.1 @@ -0,0 +1,294 @@ +.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{ +. if \nF \{ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "HEX2BIN 1" +.TH HEX2BIN 1 "2015-02-28" "perl v5.18.2" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +hex2bin/mot2bin \e\- converts Intel/Motorola hex files into binary +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +hex2bin [options] file +.PP +Option list: + [\-c] + [\-C Poly Init RefIn RefOut XorOut] + [\-e extension] + [\-E 0|1] + [\-f address] + [\-F address value] + [\-k checksum type] + [\-l length] + [\-m minimum block size] + [\-p pad byte] + [\-r start end] + [\-s address] + [\-w] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBHex2bin\fR +is a program that converts an Intel hex format into binary. +It can handle the extended Intel hex format. Both the segmented +and linear address records are supported. +Records need not be sorted and there can be gaps between records. +Records are assumed to be non-overlapping. +Padding bytes may be specified and a checksum may be inserted in the +binary file. +.PP +\&\fBMot2bin\fR +does the same with Motorola hex files. It has the same features and command line +options. 24 bit and 32 bit records are supported. +.SH "OPTIONS" +.IX Header "OPTIONS" +Options can be specified in any order, with the file name at the end. Options are +now case sensitive. All option values are specified in hexadecimal. +.PP +\&\fB\-c\fR +.PP +Enables checksum verification. +.PP +By default, it ignores checksum errors in the hex file, so that someone can change +by hand some bytes with a text editor, allowing quick fixes without recompiling a source +code all over again. This is useful when tweaking constants directly in the code or +something similar. If you want checksum error reporting, specify the option \-c. +.PP +\&\fBEx.: hex2bin \-c example.hex\fR +.PP +If there is a checksum error somewhere, the program will continue the +conversion anyway. +.PP +\&\fB\-C Poly Init RefIn RefOut XorOut\fR +.PP +\&\s-1CRC\s0 parameters. See the doc/CRC list.txt file for a description of common CRCs. See also +the test/Makefile for examples of command lines. Needs \fB\-k\fR and \fB\-f\fR option. +RefIn and RefOut parameters are specified by \fBt\fR or \fBf\fR for true or false. +.PP +\&\fB\-d\fR +.PP +Display the list of available check methods and sizes. +.PP +\&\fB\-e extension\fR +.PP +By default, the output file will have an extension \fBfilename.bin\fR. +Another extension may be specified with this command: +.PP +\&\fBEx.: hex2bin \-e com example.hex\fR +.PP +The output file will be example.com +.PP +\&\fB\-E 0|1\fR +.PP +Endianness for writing the check result or forcing a 16\-bit value. + \fB0\fR: little, \fB1\fR: big. +.PP +By default, little endian is used. +.PP +\&\fB\-f address\fR +.PP +Address in hexadecimal for inserting the check value in the binary file. Needs \fB\-k\fR +option to specify the check method. A range can be specified with option \fB\-r\fR. +.PP +\&\fB\-F address value\fR +.PP +Address and value of checksum to insert (force) in the binary file. Needs \fB\-k\fR +option to specify the size. The value is written as is. +.PP +\&\fB\-k 0\-4\fR +.PP +In many cases, someone needs to insert a check value in the binary file. For example, +a boot rom is programmed with a checksum which is verified at power-up. This feature +uses also options \fB\-r\fR, \fB\-C\fR and \fB\-f\fR. Display the list with \fB\-d\fR. +.PP +Select the checksum type to insert into the binary file + 0: Checksum 8\-bit + 1: Checksum 16\-bit + 2: \s-1CRC8 + 3: CRC16 + 4: CRC32\s0 +.PP +\&\fB\-l length\fR +.PP +The binary file will be padded with \s-1FF\s0 or pad bytes as specified by the option +below, up to a maximal Length (Starting address + Length \-1 is Max Address) +.PP +\&\fB\-m minimum_block_size\fR +.PP +File Size Dimension will be a multiple of Minimum block size. +File will be filled with Pattern. +Length must be a power of 2 in hexadecimal [see \fB\-l\fR option] +Attention this option is \s-1STRONGER\s0 than Maximal Length +.PP +\&\fB\-p pad_byte\fR +.PP +Pads unused locations with the specified byte. +.PP +By default, this byte is \s-1FF,\s0 which is the unprogrammed value for most EPROM/EEPROM/Flash. +.PP +\&\fBEx.: hex2bin \-p 3E example.hex\fR +.PP +\&\fB\-r [start] [end]\fR +.PP +Range to compute binary checksum over (default is min and max addresses) +.PP +\&\fB\-s address\fR +.PP +Specify the starting address of the binary file. +.PP +Normally, hex2bin will generate a binary file starting at the lowest address in +the hex file. If the lowest address isn't 0000, ex: 0100, the first byte that +should be at 0100 will be stored at address 0000 in the binary file. This may +cause problems when using the binary file to program an \s-1EPROM.\s0 +.PP +If you can't specify the starting address (or offset) to your \s-1EPROM\s0 programmer, +you can specify a starting address on the command line: +.PP +\&\fBEx.: hex2bin \-s 0000 records_start_at_0100.hex\fR +.PP +The bytes will be stored in the binary file with a padding from 0000 to the +lowest address (00FF in this case). Padding bytes are all \s-1FF\s0 by default so an \s-1EPROM\s0 +programmer can skip these bytes when programming. The padding value can be changed +with the \-p option. +.PP +\&\fB\-w\fR +.PP +Swap wordwise (low <\-> high). Used by Microchip's \s-1MPLAB IDE\s0 +.SH "NOTES" +.IX Header "NOTES" +This program does minimal error checking since many hex files are +generated by known good assemblers. +.SH "AUTHOR Jacques Pelletier (jpelletier@ieee.org) \- version 2.0" +.IX Header "AUTHOR Jacques Pelletier (jpelletier@ieee.org) - version 2.0" diff --git a/tools/hex2bin-2.0/src/hex2bin.c b/tools/hex2bin-2.0/src/hex2bin.c new file mode 100644 index 0000000..7537d8c --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.c @@ -0,0 +1,587 @@ +/* + hex2bin converts an Intel hex file to binary. + + Copyright (C) 2015, Jacques Pelletier + checksum extensions Copyright (C) 2004 Rockwell Automation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + 20040617 Alf Lacis: Added pad byte (may not always want FF). + Added 'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + + 20071005 PG: Improvements on options parsing + 20091212 JP: Corrected crash on 0 byte length data records + 20100402 JP: Corrected bug on physical address calculation for extended + linear address record. + ADDRESS_MASK is now calculated from MEMORY_SIZE + + 20120125 Danny Schneider: + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + 20120509 Yoshimasa Nakane: + modified error checking (also for output file, JP) + 20141005 JP: added support for byte swapped hex files + corrected bug caused by extra LF at end or within file + 20141008 JP: removed junk code + 20141121 Slucx: added line for removing extra CR when entering file name at run time. + 20141122 Simone Fratini: small feature added + 20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag + 20150122 JP: added support for different check methods + 20150221 JP: rewrite of the checksum write/force value +*/ + +#define PROGRAM "hex2bin" +#define VERSION "2.0" + +#include "common.h" + +#define NO_ADDRESS_TYPE_SELECTED 0 +#define LINEAR_ADDRESS 1 +#define SEGMENTED_ADDRESS 2 + +const char *Pgm_Name = PROGRAM; + +int main (int argc, char *argv[]) +{ + /* line inputted from file */ + char Line[MAX_LINE_SIZE]; + + /* flag that a file was read */ + bool Fileread; + + /* cmd-line parameter # */ + char *p; + + int Param,result; + + /* Application specific */ + + unsigned int Nb_Bytes; + unsigned int First_Word, Address, Segment, Upper_Address; + unsigned int Phys_Addr, Type; + unsigned int temp; + unsigned int Records_Start; // Lowest address of the records + + /* We will assume that when one type of addressing is selected, it will be valid for all the + current file. Records for the other type will be ignored. */ + unsigned int Seg_Lin_Select = NO_ADDRESS_TYPE_SELECTED; + + unsigned int temp2; + + byte Data_Str[MAX_LINE_SIZE]; + + fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n"); + + if (argc == 1) + usage(); + + strcpy(Extension, "bin"); /* default is for binary file extension */ + + /* read file */ + Starting_Address = 0; + + /* + use p for parsing arguments + use i for number of parameters to skip + use c for the current option + */ + for (Param = 1; Param < argc; Param++) + { + int i = 0; + char c; + + p = argv[Param]; + c = *(p+1); /* Get option character */ + + if ( _IS_OPTION_(*p) ) + { + // test for no space between option and parameter + if (strlen(p) != 2) usage(); + + switch(c) + { + /* file extension */ + case 'c': + Enable_Checksum_Error = true; + i = 0; + break; + case 'd': + DisplayCheckMethods(); + case 'e': + GetExtension(argv[Param + 1],Extension); + i = 1; /* add 1 to Param */ + break; + case 'E': + Endian = GetBin(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'f': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Addr_set = true; + i = 1; /* add 1 to Param */ + break; + case 'F': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Value = GetHex(argv[Param + 2]); + Force_Value = true; + i = 2; /* add 2 to Param */ + break; + case 'k': + Cks_Type = GetHex(argv[Param + 1]); + { + if (Cks_Type > LAST_CHECK_METHOD) usage(); + } + i = 1; /* add 1 to Param */ + break; + case 'l': + Max_Length = GetHex(argv[Param + 1]); + if (Max_Length > 0x800000) + { + fprintf(stderr,"Max_Length = %u\n", Max_Length); + exit(1); + } + Max_Length_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'm': + Minimum_Block_Size = GetHex(argv[Param + 1]); + Minimum_Block_Size_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'p': + Pad_Byte = GetHex(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'r': + Cks_Start = GetHex(argv[Param + 1]); + Cks_End = GetHex(argv[Param + 2]); + Cks_range_set = true; + i = 2; /* add 2 to Param */ + break; + case 's': + Starting_Address = GetHex(argv[Param + 1]); + Starting_Address_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'w': + Swap_Wordwise = true; + i = 0; + break; + case 'C': + Crc_Poly = GetHex(argv[Param + 1]); + Crc_Init = GetHex(argv[Param + 2]); + Crc_RefIn = GetBoolean(argv[Param + 3]); + Crc_RefOut = GetBoolean(argv[Param + 4]); + Crc_XorOut = GetHex(argv[Param + 5]); + CrcParamsCheck(); + i = 5; /* add 5 to Param */ + break; + + case '?': + case 'h': + default: + usage(); + } /* switch */ + + /* Last parameter is not a filename */ + if (Param == argc-1) usage(); + + /* if (Param + i) < (argc -1) */ + if (Param < argc -1 -i) Param += i; + else usage(); + + } + else + break; + /* if option */ + } /* for Param */ + + /* when user enters input file name */ + + /* Assume last parameter is filename */ + strcpy(Filename,argv[argc -1]); + + /* Just a normal file name */ + NoFailOpenInputFile (Filename); + PutExtension(Filename, Extension); + NoFailOpenOutputFile(Filename); + Fileread = true; + + /* To begin, assume the lowest address is at the end of the memory. + While reading each records, subsequent addresses will lower this number. + At the end of the input file, this value will be the lowest address. + + A similar assumption is made for highest address. It starts at the + beginning of memory. While reading each records, subsequent addresses will raise this number. + At the end of the input file, this value will be the highest address. */ + Lowest_Address = (unsigned int)-1; + Highest_Address = 0; + Records_Start = 0; + Segment = 0; + Upper_Address = 0; + Record_Nb = 0; // Used for reporting errors + + /* get highest and lowest addresses so that we can allocate the right size */ + do + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan the first two bytes and nb of bytes. + The two bytes are read in First_Word since its use depend on the + record type: if it's an extended address record or a data record. + */ + result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 0: + if (Nb_Bytes == 0) + break; + + Address = First_Word; + + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + Phys_Addr = (Segment << 4) + Address; + } + else + { + /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED + Upper_Address = 0 as specified in the Intel spec. until an extended address + record is read. */ + Phys_Addr = ((Upper_Address << 16) + Address); + } + + /* Set the lowest address as base pointer. */ + if (Phys_Addr < Lowest_Address) + Lowest_Address = Phys_Addr; + + /* Same for the top address. */ + temp = Phys_Addr + Nb_Bytes -1; + + if (temp > Highest_Address) + Highest_Address = temp; + + break; + + case 2: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended segment address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = SEGMENTED_ADDRESS; + + /* Then ignore subsequent extended linear address records */ + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Segment,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Segment << 4); + } + else + { + fprintf(stderr,"Ignored extended linear address record %d\n", Record_Nb); + } + break; + + case 4: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended linear address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = LINEAR_ADDRESS; + + /* Then ignore subsequent extended segment address records */ + if (Seg_Lin_Select == LINEAR_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Upper_Address,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Upper_Address << 16); + } + else + { + fprintf(stderr,"Ignored extended segment address record %d\n", Record_Nb); + } + break; + + default: + break; + } + } + } + while (!feof (Filin)); + + rewind(Filin); + Segment = 0; + Upper_Address = 0; + Record_Nb = 0; + + if (Starting_Address_Setted == true) + { + Records_Start = Lowest_Address; + Lowest_Address = Starting_Address; + } + else + { + Records_Start = Lowest_Address; + Starting_Address = Lowest_Address; + } + + if (Max_Length_Setted == false) + Max_Length = Highest_Address - Lowest_Address + 1; + else + Highest_Address = Lowest_Address + Max_Length - 1; + + /* Now, that we know the buffer size, we can allocate it. */ + /* allocate a buffer */ + Memory_Block = (byte *) NoFailMalloc(Max_Length); + + /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */ + memset (Memory_Block,Pad_Byte,Max_Length); + + /* Read the file & process the lines. */ + do /* repeat until EOF(Filin) */ + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + //fprintf(stderr,"Record: %d; length: %d\n", Record_Nb, i); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan the first two bytes and nb of bytes. + The two bytes are read in First_Word since its use depend on the + record type: if it's an extended address record or a data record. + */ + result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + Checksum = Nb_Bytes + (First_Word >> 8) + (First_Word & 0xFF) + Type; + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 0: + if (Nb_Bytes == 0) + { + fprintf(stderr,"0 byte length Data record ignored\n"); + break; + } + + Address = First_Word; + + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + Phys_Addr = (Segment << 4) + Address; + else + /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED + Upper_Address = 0 as specified in the Intel spec. until an extended address + record is read. */ + Phys_Addr = ((Upper_Address << 16) + Address); + + /* Check that the physical address stays in the buffer's range. */ + if ((Phys_Addr >= Lowest_Address) && (Phys_Addr <= Highest_Address)) + { + /* The memory block begins at Lowest_Address */ + Phys_Addr -= Lowest_Address; + + /* Read the Data bytes. */ + /* Bytes are written in the Memory block even if checksum is wrong. */ + i = Nb_Bytes; + + do + { + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + p += 2; + + /* Check that the physical address stays in the buffer's range. */ + if (Phys_Addr < Max_Length) + { + /* Overlapping record will erase the pad bytes */ + if (Swap_Wordwise) + { + if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++ ^ 1] = temp2; + } + else + { + if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++] = temp2; + } + + Checksum = (Checksum + temp2) & 0xFF; + } + } + while (--i != 0); + + /* Read the Checksum value. */ + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Verify Checksum value. */ + Checksum = (Checksum + temp2) & 0xFF; + VerifyChecksumValue(); + } + else + { + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + fprintf(stderr,"Data record skipped at %4X:%4X\n",Segment,Address); + else + fprintf(stderr,"Data record skipped at %8X\n",Phys_Addr); + } + + break; + + /* End of file record */ + case 1: + /* Simply ignore checksum errors in this line. */ + break; + + /* Extended segment address record */ + case 2: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended segment address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = SEGMENTED_ADDRESS; + + /* Then ignore subsequent extended linear address records */ + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Segment,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Segment << 4); + + /* Verify Checksum value. */ + Checksum = (Checksum + (Segment >> 8) + (Segment & 0xFF) + temp2) & 0xFF; + VerifyChecksumValue(); + } + break; + + /* Start segment address record */ + case 3: + /* Nothing to be done since it's for specifying the starting address for + execution of the binary code */ + break; + + /* Extended linear address record */ + case 4: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended linear address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = LINEAR_ADDRESS; + + /* Then ignore subsequent extended segment address records */ + if (Seg_Lin_Select == LINEAR_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Upper_Address,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Upper_Address << 16); + + /* Verify Checksum value. */ + Checksum = (Checksum + (Upper_Address >> 8) + (Upper_Address & 0xFF) + temp2) + & 0xFF; + VerifyChecksumValue(); + } + break; + + /* Start linear address record */ + case 5: + /* Nothing to be done since it's for specifying the starting address for + execution of the binary code */ + break; + default: + fprintf(stderr,"Unknown record type\n"); + break; + } + } + } + while (!feof (Filin)); + /*-----------------------------------------------------------------------------*/ + + fprintf(stdout,"Binary file start = %08X\n",Lowest_Address); + fprintf(stdout,"Records start = %08X\n",Records_Start); + fprintf(stdout,"Highest address = %08X\n",Highest_Address); + fprintf(stdout,"Pad Byte = %X\n", Pad_Byte); + + WriteMemory(); + +#ifdef USE_FILE_BUFFERS + free (FilinBuf); + free (FiloutBuf); +#endif + + fclose (Filin); + fclose (Filout); + + if (Status_Checksum_Error && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error detected.\n"); + return 1; + } + + if (!Fileread) + usage(); + return 0; +} diff --git a/tools/hex2bin-2.0/src/hex2bin.pod b/tools/hex2bin-2.0/src/hex2bin.pod new file mode 100644 index 0000000..a8eb238 --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.pod @@ -0,0 +1,161 @@ +HEX2BIN 1 "2015 february 22nd" "Hex2bin Version 2.0" +=head1 NAME + +hex2bin/mot2bin \- converts Intel/Motorola hex files into binary + +=head1 SYNOPSIS + +hex2bin [options] file + +Option list: + [-c] + [-C Poly Init RefIn RefOut XorOut] + [-e extension] + [-E 0|1] + [-f address] + [-F address value] + [-k checksum type] + [-l length] + [-m minimum block size] + [-p pad byte] + [-r start end] + [-s address] + [-w] + +=head1 DESCRIPTION + +B +is a program that converts an Intel hex format into binary. +It can handle the extended Intel hex format. Both the segmented +and linear address records are supported. +Records need not be sorted and there can be gaps between records. +Records are assumed to be non-overlapping. +Padding bytes may be specified and a checksum may be inserted in the +binary file. + +B +does the same with Motorola hex files. It has the same features and command line +options. 24 bit and 32 bit records are supported. + +=head1 OPTIONS + +Options can be specified in any order, with the file name at the end. Options are +now case sensitive. All option values are specified in hexadecimal. + +B<-c> + +Enables checksum verification. + +By default, it ignores checksum errors in the hex file, so that someone can change +by hand some bytes with a text editor, allowing quick fixes without recompiling a source +code all over again. This is useful when tweaking constants directly in the code or +something similar. If you want checksum error reporting, specify the option -c. + +B + +If there is a checksum error somewhere, the program will continue the +conversion anyway. + +B<-C Poly Init RefIn RefOut XorOut> + +CRC parameters. See the doc/CRC list.txt file for a description of common CRCs. See also +the test/Makefile for examples of command lines. Needs B<-k> and B<-f> option. +RefIn and RefOut parameters are specified by B or B for true or false. + +B<-d> + +Display the list of available check methods and sizes. + +B<-e extension> + +By default, the output file will have an extension B. +Another extension may be specified with this command: + +B + +The output file will be example.com + +B<-E 0|1> + +Endianness for writing the check result or forcing a 16-bit value. + B<0>: little, B<1>: big. + +By default, little endian is used. + +B<-f address> + +Address in hexadecimal for inserting the check value in the binary file. Needs B<-k> +option to specify the check method. A range can be specified with option B<-r>. + +B<-F address value> + +Address and value of checksum to insert (force) in the binary file. Needs B<-k> +option to specify the size. The value is written as is. + +B<-k 0-4> + +In many cases, someone needs to insert a check value in the binary file. For example, +a boot rom is programmed with a checksum which is verified at power-up. This feature +uses also options B<-r>, B<-C> and B<-f>. Display the list with B<-d>. + +Select the checksum type to insert into the binary file + 0: Checksum 8-bit + 1: Checksum 16-bit + 2: CRC8 + 3: CRC16 + 4: CRC32 + +B<-l length> + +The binary file will be padded with FF or pad bytes as specified by the option +below, up to a maximal Length (Starting address + Length -1 is Max Address) + +B<-m minimum_block_size> + +File Size Dimension will be a multiple of Minimum block size. +File will be filled with Pattern. +Length must be a power of 2 in hexadecimal [see B<-l> option] +Attention this option is STRONGER than Maximal Length + +B<-p pad_byte> + +Pads unused locations with the specified byte. + +By default, this byte is FF, which is the unprogrammed value for most EPROM/EEPROM/Flash. + +B + +B<-r [start] [end]> + +Range to compute binary checksum over (default is min and max addresses) + +B<-s address> + +Specify the starting address of the binary file. + +Normally, hex2bin will generate a binary file starting at the lowest address in +the hex file. If the lowest address isn't 0000, ex: 0100, the first byte that +should be at 0100 will be stored at address 0000 in the binary file. This may +cause problems when using the binary file to program an EPROM. + +If you can't specify the starting address (or offset) to your EPROM programmer, +you can specify a starting address on the command line: + +B + +The bytes will be stored in the binary file with a padding from 0000 to the +lowest address (00FF in this case). Padding bytes are all FF by default so an EPROM +programmer can skip these bytes when programming. The padding value can be changed +with the -p option. + +B<-w> + +Swap wordwise (low <-> high). Used by Microchip's MPLAB IDE + +=head1 NOTES + +This program does minimal error checking since many hex files are +generated by known good assemblers. + +=head1 AUTHOR +Jacques Pelletier (jpelletier@ieee.org) - version 2.0 diff --git a/tools/hex2bin-2.0/src/libcrc.c b/tools/hex2bin-2.0/src/libcrc.c new file mode 100644 index 0000000..02bcd4b --- /dev/null +++ b/tools/hex2bin-2.0/src/libcrc.c @@ -0,0 +1,204 @@ +/********************************************************************* + * * + * Library : lib_crc * + * File : lib_crc.c * + * Author : Lammert Bies 1999-2008 * + * E-mail : info@lammertbies.nl * + * Language : ANSI C * + * * + * * + * Description * + * =========== * + * * + * The file lib_crc.c contains the private and public func- * + * tions used for the calculation of CRC-16, CRC-CCITT and * + * CRC-32 cyclic redundancy values. * + * * + * * + * Dependencies * + * ============ * + * * + * libcrc.h CRC definitions and prototypes * + * * + ********************************************************************/ +#include + +#ifndef G_GUINT64_CONSTANT +#define G_GUINT64_CONSTANT(val) (val##UL) +#endif + +void *crc_table; + +/* private */ + +void init_crc8_normal_tab(uint8_t polynom) +{ + int i, j; + uint8_t crc; + uint8_t *p; + + p = (uint8_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint8_t) i; + + for (j=0; j<8; j++) + { + if (crc & 0x80) crc = (crc << 1) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc8_reflected_tab(uint8_t polynom) +{ + int i, j; + uint8_t crc; + uint8_t *p; + + p = (uint8_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint8_t) i; + + for (j=0; j<8; j++) + { + if (crc & 0x01) crc = (crc >> 1) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +/* Common routines for calculations */ +void init_crc16_normal_tab(uint16_t polynom) +{ + int i, j; + uint16_t crc; + uint16_t *p; + + p = (uint16_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = ((uint16_t) i) << 8; + + for (j=0; j<8; j++) + { + if ( crc & 0x8000 ) crc = ( crc << 1 ) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc16_reflected_tab(uint16_t polynom) +{ + int i, j; + uint16_t crc; + uint16_t *p; + + p = (uint16_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint16_t) i; + + for (j=0; j<8; j++) + { + if ( crc & 0x0001 ) crc = ( crc >> 1 ) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +void init_crc32_normal_tab(uint32_t polynom) +{ + int i, j; + uint32_t crc; + uint32_t *p; + + p = (uint32_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = ((uint32_t) i) << 24; + + for (j=0; j<8; j++) + { + if ( crc & 0x80000000L ) crc = ( crc << 1 ) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc32_reflected_tab(uint32_t polynom) +{ + int i, j; + uint32_t crc; + uint32_t *p; + + p = (uint32_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint32_t) i; + + for (j=0; j<8; j++) + { + if ( crc & 0x00000001L ) crc = ( crc >> 1 ) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +/* Common routines for calculations */ + +uint8_t update_crc8(uint8_t crc, uint8_t c) +{ + return (((uint8_t *) crc_table)[crc ^ c]); +} + +uint16_t update_crc16_normal(uint16_t crc, char c ) +{ + uint16_t short_c; + + short_c = 0x00ff & (uint16_t) c; + + /* Normal form */ + return (crc << 8) ^ ((uint16_t *) crc_table)[(crc >> 8) ^ short_c]; +} + +uint16_t update_crc16_reflected(uint16_t crc, char c ) +{ + uint16_t short_c; + + short_c = 0x00ff & (uint16_t) c; + + /* Reflected form */ + return (crc >> 8) ^ ((uint16_t *) crc_table)[(crc ^ short_c) & 0xff]; +} + +uint32_t update_crc32_normal(uint32_t crc, char c ) +{ + uint32_t long_c; + + long_c = 0x000000ffL & (uint32_t) c; + + return (crc << 8) ^ ((uint32_t *) crc_table)[((crc >> 24) ^ long_c) & 0xff]; +} + +uint32_t update_crc32_reflected(uint32_t crc, char c ) +{ + uint32_t long_c; + + long_c = 0x000000ffL & (uint32_t) c; + + return (crc >> 8) ^ ((uint32_t *) crc_table)[(crc ^ long_c) & 0xff]; +} diff --git a/tools/hex2bin-2.0/src/libcrc.h b/tools/hex2bin-2.0/src/libcrc.h new file mode 100644 index 0000000..39f20d0 --- /dev/null +++ b/tools/hex2bin-2.0/src/libcrc.h @@ -0,0 +1,44 @@ + /******************************************************************** + * * + * Library : lib_crc * + * File : lib_crc.h * + * Author : Lammert Bies 1999-2008 * + * E-mail : info@lammertbies.nl * + * Language : ANSI C * + * * + * * + * Description * + * =========== * + * * + * The file lib_crc.h contains public definitions and proto- * + * types for the CRC functions present in lib_crc.c. * + * * + * * + * Dependencies * + * ============ * + * * + * none * + * * + * * + ********************************************************************/ +#ifndef _LIBCRC_H_ +#define _LIBCRC_H_ + +void *crc_table; + +void init_crc8_normal_tab(uint8_t polynom); +void init_crc8_reflected_tab(uint8_t polynom); + +void init_crc16_normal_tab(uint16_t polynom); +void init_crc16_reflected_tab(uint16_t polynom); +void init_crc32_normal_tab(uint32_t polynom); +void init_crc32_reflected_tab(uint32_t polynom); + +uint8_t update_crc8(uint8_t crc, uint8_t c); + +uint16_t update_crc16_normal(uint16_t crc, char c ); +uint16_t update_crc16_reflected(uint16_t crc, char c ); +uint32_t update_crc32_normal(uint32_t crc, char c ); +uint32_t update_crc32_reflected(uint32_t crc, char c ); + +#endif /* _LIBCRC_H_ */ diff --git a/tools/hex2bin-2.0/src/mot2bin.c b/tools/hex2bin-2.0/src/mot2bin.c new file mode 100644 index 0000000..9e0e23c --- /dev/null +++ b/tools/hex2bin-2.0/src/mot2bin.c @@ -0,0 +1,518 @@ +/* +mot2bin converts a Motorola hex file to binary. + +Copyright (C) 2015, Jacques Pelletier +checksum extensions Copyright (C) 2004 Rockwell Automation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +20040617 Alf Lacis: Added pad byte (may not always want FF). + Added initialisation to Checksum to remove GNU + compiler warning about possible uninitialised usage + Added 2x'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +20071005 PG: Improvements on options parsing +20091212 JP: Corrected crash on 0 byte length data records +20100402 JP: ADDRESS_MASK is now calculated from MEMORY_SIZE + +20120125 Danny Schneider: + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address +20120509 Yoshimasa Nakane: + modified error checking (also for output file, JP) +20141005 JP: added support for byte swapped hex files + corrected bug caused by extra LF at end or within file +20141121 Slucx: added line for removing extra CR when entering file name at run time. +20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag +20150122 JP: added support for different check methods +20150221 JP: rewrite of the checksum write/force value +*/ + +#define PROGRAM "mot2bin" +#define VERSION "2.0" + +#include "common.h" + +const char *Pgm_Name = PROGRAM; + +int main (int argc, char *argv[]) +{ + /* line inputted from file */ + char Line[MAX_LINE_SIZE]; + + /* flag that a file was read */ + bool Fileread; + + /* cmd-line parameter # */ + char *p; + + int Param, result; + + /* Application specific */ + + unsigned int Nb_Bytes; + unsigned int First_Word, Address; + + unsigned int Phys_Addr, Type; + unsigned int Exec_Address; + unsigned int temp; + unsigned int Record_Count, Record_Checksum; + unsigned int Records_Start; // Lowest address of the records + + unsigned int temp2; + + byte Data_Str[MAX_LINE_SIZE]; + + fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n"); + + if (argc == 1) + usage(); + + strcpy(Extension, "bin"); /* default is for binary file extension */ + + /* read file */ + Starting_Address = 0; + + /* + use p for parsing arguments + use i for number of parameters to skip + use c for the current option + */ + for (Param = 1; Param < argc; Param++) + { + int i = 0; + char c; + + p = argv[Param]; + c = *(p+1); /* Get option character */ + + if ( _IS_OPTION_(*p) ) + { + // test for no space between option and parameter + if (strlen(p) != 2) usage(); + + switch(c) + { + /* file extension */ + case 'c': + Enable_Checksum_Error = true; + i = 0; + break; + case 'd': + DisplayCheckMethods(); + case 'e': + GetExtension(argv[Param + 1],Extension); + i = 1; /* add 1 to Param */ + break; + case 'f': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Addr_set = true; + i = 1; /* add 1 to Param */ + break; + case 'F': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Value = GetHex(argv[Param + 2]); + Force_Value = true; + i = 2; /* add 2 to Param */ + break; + case 'k': + Cks_Type = GetHex(argv[Param + 1]); + { + if (Cks_Type > LAST_CHECK_METHOD) usage(); + } + i = 1; /* add 1 to Param */ + break; + case 'l': + Max_Length = GetHex(argv[Param + 1]); + Max_Length_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'm': + Minimum_Block_Size = GetHex(argv[Param + 1]); + Minimum_Block_Size_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'p': + Pad_Byte = GetHex(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'r': + Cks_Start = GetHex(argv[Param + 1]); + Cks_End = GetHex(argv[Param + 2]); + Cks_range_set = true; + i = 2; /* add 2 to Param */ + break; + case 's': + Starting_Address = GetHex(argv[Param + 1]); + Starting_Address_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'w': + Swap_Wordwise = true; + i = 0; + break; + case 'C': + Crc_Poly = GetHex(argv[Param + 1]); + Crc_Init = GetHex(argv[Param + 2]); + Crc_RefIn = GetBoolean(argv[Param + 3]); + Crc_RefOut = GetBoolean(argv[Param + 4]); + Crc_XorOut = GetHex(argv[Param + 5]); + CrcParamsCheck(); + i = 5; /* add 5 to Param */ + break; + + case '?': + case 'h': + default: + usage(); + } /* switch */ + + /* Last parameter is not a filename */ + if (Param == argc-1) usage(); + + // fprintf(stderr,"Param: %d, option: %c\n",Param,c); + + /* if (Param + i) < (argc -1) */ + if (Param < argc -1 -i) Param += i; + else usage(); + + } + else + break; + /* if option */ + } /* for Param */ + + /* when user enters input file name */ + + /* Assume last parameter is filename */ + strcpy(Filename,argv[argc -1]); + + /* Just a normal file name */ + NoFailOpenInputFile (Filename); + PutExtension(Filename, Extension); + NoFailOpenOutputFile(Filename); + Fileread = true; + + /* To begin, assume the lowest address is at the end of the memory. + While reading each records, subsequent addresses will lower this number. + At the end of the input file, this value will be the lowest address. + + A similar assumption is made for highest address. It starts at the + beginning of memory. While reading each records, subsequent addresses will raise this number. + At the end of the input file, this value will be the highest address. */ + Lowest_Address = (unsigned int)-1; + Highest_Address = 0; + Records_Start = 0; + Record_Nb = 0; + + /* get highest and lowest addresses so that we can allocate the right size */ + do + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + p = (char *) Data_Str; + + switch(Line[1]) + { + case '0': + break; + + /* 16 bits address */ + case '1': + result = sscanf (Line,"S%1x%2x%4x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 3; + break; + + /* 24 bits address */ + case '2': + result = sscanf (Line,"S%1x%2x%6x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 4; + break; + + /* 32 bits address */ + case '3': + result = sscanf (Line,"S%1x%2x%8x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 5; + break; + } + + Phys_Addr = First_Word; + + /* Set the lowest address as base pointer. */ + if (Phys_Addr < Lowest_Address) + Lowest_Address = Phys_Addr; + + /* Same for the top address. */ + temp = Phys_Addr + Nb_Bytes -1; + + if (temp > Highest_Address) + Highest_Address = temp; + } + } + while (!feof (Filin)); + + if (Starting_Address_Setted == true) + { + Records_Start = Lowest_Address; + Lowest_Address = Starting_Address; + } + else + { + Records_Start = Lowest_Address; + Starting_Address = Lowest_Address; + } + + if (Max_Length_Setted == false) + Max_Length = Highest_Address - Lowest_Address + 1; + else + Highest_Address = Lowest_Address + Max_Length - 1; + + /* Now, that we know the buffer size, we can allocate it. */ + /* allocate a buffer */ + Memory_Block = (byte *) NoFailMalloc(Max_Length); + + /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */ + memset (Memory_Block,Pad_Byte,Max_Length); + + rewind(Filin); + Record_Nb = 0; + + /* Read the file & process the lines. */ + do /* repeat until EOF(Filin) */ + { + int i; + + Checksum = 0; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan starting address and nb of bytes. */ + /* Look at the record type after the 'S' */ + Type = 0; + + switch(Line[1]) + { + case '0': + result = sscanf (Line,"S0%2x0000484452%2x",&Nb_Bytes,&Record_Checksum); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + 0x48 + 0x44 + 0x52; + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = 0; + break; + + /* 16 bits address */ + case '1': + result = sscanf (Line,"S%1x%2x%4x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 3; + break; + + /* 24 bits address */ + case '2': + result = sscanf (Line,"S%1x%2x%6x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 16) + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 4; + break; + + /* 32 bits address */ + case '3': + result = sscanf (Line,"S%1x%2x%8x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 24) + (Address >> 16) + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 5; + break; + + case '5': + result = sscanf (Line,"S%1x%2x%4x%2x",&Type,&Nb_Bytes,&Record_Count,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Record_Count >> 8) + (Record_Count & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = 0; + break; + + case '7': + result = sscanf (Line,"S%1x%2x%8x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 24) + (Exec_Address >> 16) + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + + case '8': + result = sscanf (Line,"S%1x%2x%6x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 16) + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + case '9': + result = sscanf (Line,"S%1x%2x%4x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + } + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 1: + case 2: + case 3: + if (Nb_Bytes == 0) + { + fprintf(stderr,"0 byte length Data record ignored\n"); + break; + } + + Phys_Addr = Address; + + /* Read the Data bytes. */ + i = Nb_Bytes; + + do + { + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + p += 2; + + /* Overlapping record will erase the pad bytes */ + if (Swap_Wordwise) + { + if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++ ^ 1] = temp2; + } + else + { + if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++] = temp2; + } + + Checksum = (Checksum + temp2) & 0xFF; + } + while (--i != 0); + + /* Read the Checksum value. */ + result = sscanf (p, "%2x",&Record_Checksum); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + break; + + case 5: + fprintf(stderr,"Record total: %d\n",Record_Count); + break; + + case 7: + fprintf(stderr,"Execution Address (unused): %08X\n",Exec_Address); + break; + + case 8: + fprintf(stderr,"Execution Address (unused): %06X\n",Exec_Address); + break; + + case 9: + fprintf(stderr,"Execution Address (unused): %04X\n",Exec_Address); + break; + + /* Ignore all other records */ + default:; + } + + Record_Checksum &= 0xFF; + + /* Verify Checksum value. */ + if (((Record_Checksum + Checksum) != 0xFF) && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error in record %d: should be %02X\n",Record_Nb, 255-Checksum); + Status_Checksum_Error = true; + } + } + } + while (!feof (Filin)); + /*-----------------------------------------------------------------------------*/ + + fprintf(stdout,"Binary file start = %08X\n",Lowest_Address); + fprintf(stdout,"Records start = %08X\n",Records_Start); + fprintf(stdout,"Highest address = %08X\n",Highest_Address); + fprintf(stdout,"Pad Byte = %X\n", Pad_Byte); + + WriteMemory(); + +#ifdef USE_FILE_BUFFERS + free (FilinBuf); + free (FiloutBuf); +#endif + + fclose (Filin); + fclose (Filout); + + if (Status_Checksum_Error && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error detected.\n"); + return 1; + } + + if (!Fileread) + usage(); + return 0; +} -- cgit v1.2.3