OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems/] [tools/] [build/] [packhex.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 158 chris
 
2
/*****  P A C K H E X . C  ************************************************
3
 *
4
 *   Packhex is a hex-file compaction utility.  It attempts to concatenate
5
 *   hex records to produce more size-efficient packaging.
6
 *
7
 *   Limitations: Input files must be correctly formatted.  This utility
8
 *                is not robust enough to detect hex-record formatting
9
 *                errors.
10
 *
11
 *   Published:   May 1993 Embedded Systems Programming magazine
12
 *                "Creating Faster Hex Files"
13
 *
14
 *   URL:         ESP magazine: http://www.embedded.com
15
 *                Source Code:  ftp://ftp.mfi.com/pub/espmag/1993/pakhex.zip
16
 *
17
 *   Author:      Mark Gringrich
18
 *
19
 *   Compiler:    Microsoft C 6.0
20
 *                cl /F 1000 packhex.c
21
 *
22
 *
23 208 chris
 *   $Id: packhex.c,v 1.2 2001-09-27 12:02:53 chris Exp $
24 158 chris
 *
25
 **************************************************************************/
26
 
27
 
28
/* #define SMALLER_RECORDS */
29
#ifdef SMALLER_RECORDS
30
#define MAX_LEN_S1_RECS 128
31
#define MAX_LEN_S2_RECS 128
32
#define MAX_LEN_S3_RECS 128
33
#else
34
#define MAX_LEN_S1_RECS 252
35
#define MAX_LEN_S2_RECS 251
36
#define MAX_LEN_S3_RECS 250
37
#endif
38
 
39
 
40
/*--------------------------------- includes ---------------------------------*/
41
 
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
 
46
#include "config.h"
47
 
48
#ifndef VMS
49
#ifndef HAVE_STRERROR
50
extern int sys_nerr;
51
extern char *sys_errlist[];
52
 
53
#define strerror( _err ) \
54
  ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
55
 
56
#else   /* HAVE_STRERROR */
57
char *strerror ();
58
#endif
59
#else   /* VMS */
60
char *strerror (int,...);
61
#endif
62
 
63
#if defined(__unix__) && !defined(EXIT_FAILURE)
64
#define EXIT_FAILURE -1
65
#define EXIT_SUCCESS  0
66
#endif
67
 
68
/*--------------------------------- defines ----------------------------------*/
69
 
70
#define YES                   1
71
#define MAX_LINE_SIZE       600
72
#define EOS                 '\0'
73
 
74
 
75
/*---------------------------------- macros ----------------------------------*/
76
 
77
/* Convert ASCII hexadecimal digit to value. */
78
 
79
#define HEX_DIGIT( C )   ( ( ( ( C ) > '9' ) ? ( C ) + 25 : ( C ) ) & 0xF )
80
 
81
 
82
/*--------------------------------- typedefs ---------------------------------*/
83
 
84
typedef unsigned char   Boolean;
85
typedef unsigned char   Uchar;
86
typedef unsigned int    Uint;
87
typedef unsigned long   Ulong;
88
 
89
typedef struct   /* Functions and constant returning Hex-record vital stats. */
90
{
91
    Boolean    ( *is_data_record  )( char *              );
92
    Ulong      ( *get_address     )( char *              );
93
    Uint       ( *get_data_count  )( char *              );
94
    const Uint    max_data_count;
95
    char      *( *get_data_start  )( char *              );
96
    void       ( *put_data_record )( Uint, Ulong, char * );
97
} Rec_vitals;
98
 
99
 
100
/*--------------------------- function prototypes ----------------------------*/
101
 
102
Rec_vitals  * identify_first_data_record( char *, int );
103
Ulong         get_ndigit_hex( char *, int );
104
 
105
 
106
/*----------------------------- Intel Hex format -----------------------------*/
107
 
108
/*
109
 *    Intel Hex data-record layout
110
 *
111
 *    :aabbbbccd...dee
112
 *
113
 *    :      - header character
114
 *    aa     - record data byte count, a 2-digit hex value
115
 *    bbbb   - record address, a 4-digit hex value
116
 *    cc     - record type, a 2-digit hex value:
117
 *              "00" is a data record
118
 *              "01" is an end-of-data record
119
 *              "02" is an extended-address record
120
 *              "03" is a start record
121
 *    d...d  - data (always an even number of chars)
122
 *    ee     - record checksum, a 2-digit hex value
123
 *             checksum = 2's complement
124
 *                 [ (sum of bytes: aabbbbccd...d) modulo 256 ]
125
 */
126
 
127
 
128
Boolean is_intel_data_rec( char * rec_str )
129
{
130
    return( ( rec_str[ 0 ] == ':' )  &&  ( rec_str[ 8 ] == '0' ) );
131
}
132
 
133
Uint get_intel_rec_data_count( char * rec_str )
134
{
135
    return( ( Uint ) get_ndigit_hex( rec_str + 1, 2 ) );
136
}
137
 
138
Ulong get_intel_rec_address( char * rec_str )
139
{
140
    return( get_ndigit_hex( rec_str + 3, 4 ) );
141
}
142
 
143
char * get_intel_rec_data_start( char * rec_str )
144
{
145
    return( rec_str + 9 );
146
}
147
 
148
void put_intel_data_rec( Uint count, Ulong address, char * data_str )
149
{
150
    char    *ptr;
151
    Uint    sum = count + ( address >> 8 & 0xff ) + ( address & 0xff );
152
 
153
    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
154
        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
155
 
156
    printf(
157
      ":%02X%04lX00%s%02X\n", count, address, data_str, (~sum + 1) & 0xff
158
    );
159
}
160
 
161
 
162
Rec_vitals  intel_hex =
163
{
164
    is_intel_data_rec,
165
    get_intel_rec_address,
166
    get_intel_rec_data_count,
167
    255,                        /* Maximum data bytes in a record. */
168
    get_intel_rec_data_start,
169
    put_intel_data_rec
170
};
171
 
172
 
173
/*------------------------- Motorola S1-record format ------------------------*/
174
 
175
/*
176
 *    Motorola S-record data-record layout
177
 *
178
 *    Sabbc...cd...dee
179
 *
180
 *    S      - header character
181
 *    a      - record type, a 1-digit value:
182
 *               "0" is a header record
183
 *               "1" is a 2-byte-address data record
184
 *               "2" is a 3-byte-address data record
185
 *               "3" is a 4-byte-address data record
186
 *               "7" is a 4-byte-address end-of-data record
187
 *               "8" is a 3-byte-address end-of-data record
188
 *               "9" is a 2-byte-address end-of-data record
189
 *    bb     - record length in bytes, a 2-digit hex value
190
 *             (record length doesn't count the header/type
191
 *              chars and checksum byte)
192
 *    c...c  - record address, a 4-, 6-, or 8-digit value,
193
 *               depending on record type
194
 *    d...d  - data (always an even number of chars)
195
 *    ee     - record checksum, a 2-digit hex value
196
 *             checksum = 1's complement
197
 *             [ (sum of all bytes: bbc..cd...d) modulo 256 ]
198
 */
199
 
200
#define S1_COUNT_OFFSET         3
201
 
202
 
203
Boolean is_moto_s1_data_rec( char * rec_str )
204
{
205
    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '1' ) );
206
}
207
 
208
Uint get_moto_s1_rec_data_count( char * rec_str )
209
{
210
    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S1_COUNT_OFFSET );
211
}
212
 
213
Ulong get_moto_s1_rec_address( char * rec_str )
214
{
215
    return( get_ndigit_hex( rec_str + 4, 4 ) );
216
}
217
 
218
char * get_moto_s1_rec_data_start( char * rec_str )
219
{
220
    return( rec_str + 8 );
221
}
222
 
223
void put_moto_s1_data_rec( Uint count, Ulong address, char * data_str )
224
{
225
    char   *ptr;
226
    Uint    sum = S1_COUNT_OFFSET + count +
227
                    ( address >> 8 & 0xff ) + ( address & 0xff );
228
 
229
    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
230
        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
231
 
232
    printf(
233
      "S1%02X%04lX%s%02X\n",
234
      count + S1_COUNT_OFFSET, address, data_str, ~sum & 0xff
235
    );
236
}
237
 
238
 
239
Rec_vitals  motorola_s1_rec =
240
{
241
    is_moto_s1_data_rec,
242
    get_moto_s1_rec_address,
243
    get_moto_s1_rec_data_count,
244
    MAX_LEN_S1_RECS,            /* Maximum data bytes in a record. */
245
    get_moto_s1_rec_data_start,
246
    put_moto_s1_data_rec
247
};
248
 
249
 
250
/*------------------------- Motorola S2-record format ------------------------*/
251
 
252
#define S2_COUNT_OFFSET         4
253
 
254
Boolean is_moto_s2_data_rec( char * rec_str )
255
{
256
    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '2' ) );
257
}
258
 
259
Uint get_moto_s2_rec_data_count( char * rec_str )
260
{
261
    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S2_COUNT_OFFSET );
262
}
263
 
264
Ulong get_moto_s2_rec_address( char * rec_str )
265
{
266
    return( get_ndigit_hex( rec_str + 4, 6 ) );
267
}
268
 
269
char * get_moto_s2_rec_data_start( char * rec_str )
270
{
271
    return( rec_str + 10 );
272
}
273
 
274
void put_moto_s2_data_rec( Uint count, Ulong address, char * data_str )
275
{
276
    char    *ptr;
277
    Uint    sum = S2_COUNT_OFFSET + count + ( address >> 16 & 0xff ) +
278
                                            ( address >>  8 & 0xff ) +
279
                                            ( address       & 0xff );
280
 
281
    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
282
        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
283
 
284
    printf(
285
      "S2%02X%06lX%s%02X\n",
286
      count + S2_COUNT_OFFSET, address, data_str, ~sum & 0xff
287
    );
288
}
289
 
290
 
291
Rec_vitals  motorola_s2_rec =
292
{
293
    is_moto_s2_data_rec,
294
    get_moto_s2_rec_address,
295
    get_moto_s2_rec_data_count,
296
    MAX_LEN_S2_RECS,            /* Maximum data bytes in a record. */
297
    get_moto_s2_rec_data_start,
298
    put_moto_s2_data_rec
299
};
300
 
301
 
302
/*------------------------- Motorola S3-record format ------------------------*/
303
 
304
#define S3_COUNT_OFFSET         5
305
 
306
Boolean is_moto_s3_data_rec( char * rec_str )
307
{
308
    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '3' ) );
309
}
310
 
311
Uint get_moto_s3_rec_data_count( char * rec_str )
312
{
313
    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S3_COUNT_OFFSET );
314
}
315
 
316
Ulong get_moto_s3_rec_address( char * rec_str )
317
{
318
    return( get_ndigit_hex( rec_str + 4, 8 ) );
319
}
320
 
321
char * get_moto_s3_rec_data_start( char * rec_str )
322
{
323
    return( rec_str + 12 );
324
}
325
 
326
void put_moto_s3_data_rec( Uint count, Ulong address, char * data_str )
327
{
328
    char    *ptr;
329
    Uint     sum = S3_COUNT_OFFSET + count + ( address >> 24 & 0xff ) +
330
                                             ( address >> 16 & 0xff ) +
331
                                             ( address >>  8 & 0xff ) +
332
                                             ( address       & 0xff );
333
 
334
    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
335
        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
336
 
337
    printf(
338
      "S3%02X%08lX%s%02X\n",
339
      count + S3_COUNT_OFFSET, address, data_str, ~sum & 0xff
340
   );
341
}
342
 
343
 
344
Rec_vitals  motorola_s3_rec =
345
{
346
    is_moto_s3_data_rec,
347
    get_moto_s3_rec_address,
348
    get_moto_s3_rec_data_count,
349
    MAX_LEN_S3_RECS,            /* Maximum data bytes in a record. */
350
    get_moto_s3_rec_data_start,
351
    put_moto_s3_data_rec
352
};
353
 
354
 
355
/*-------------------- Put your favorite hex format here ---------------------*/
356
 
357
/*
358
 *    * * *  The following is a template for an additional hex format:  * * *
359
 *
360
 *
361
 *    Boolean is_X_data_rec( char * rec_str ) {}
362
 *
363
 *    Uint get_X_rec_data_count( char * rec_str ) {}
364
 *
365
 *    Ulong get_X_rec_address( char * rec_str ) {}
366
 *
367
 *    char * get_X_rec_data_start( char * rec_str ) {}
368
 *
369
 *    void put_X_data_rec( Uint count, Ulong address, char * data_str ) {}
370
 *
371
 *    Rec_vitals  X_rec =
372
 *    {
373
 *        is_X_data_rec,
374
 *        get_X_rec_address,
375
 *        get_X_rec_data_count,
376
 *        MAXIMUM DATA BYTES IN A RECORD,
377
 *        get_X_rec_data_start,
378
 *        put_X_data_rec
379
 *    };
380
 *
381
 */
382
 
383
/*----------------------------------------------------------------------------*/
384
 
385
 
386
/*
387
 *   Put address of additional Rec_vitals structures
388
 *   in this array, before the NULL entry.
389
 */
390
 
391
Rec_vitals  *formats[] =
392
{
393
    &intel_hex,
394
    &motorola_s1_rec,
395
    &motorola_s2_rec,
396
    &motorola_s3_rec,
397
    ( Rec_vitals * ) NULL
398
};
399
 
400
 
401
/****   main   *****************************************************************
402
*
403
*
404
*       Expects: Nothing (no command-line parameters).
405
*
406
*       Returns: Exit status (EXIT_SUCCESS or EXIT_FAILURE).
407
*
408
*       Reads hex records on the standard input and attempts to
409
*       splice adjacent data fields together.  Results appear on
410
*       the standard output.
411
*
412
*******************************************************************************/
413
 
414
int main(
415
  int argc,
416
  char **argv
417
)
418
{
419
 
420
    char       inbuff[ MAX_LINE_SIZE ], outbuff[ MAX_LINE_SIZE ];
421
    char       *in_dptr, *out_dptr;
422
    int        d_total, d_count, d_excess, n;
423
    int        length;
424
    Ulong      in_rec_addr, out_rec_addr = 0;
425
    Rec_vitals *rptr;
426
 
427
 
428
    /* Sift through file until first hex record is identified.    */
429
 
430
    rptr = identify_first_data_record( inbuff, MAX_LINE_SIZE );
431
    if ( rptr == NULL )
432
    {
433
        fputs( "No hex records found.\n", stderr );
434
        exit( EXIT_FAILURE );
435
    }
436
 
437
 
438
    /* Attempt data-record splicing until end-of-file is reached. */
439
    d_total = 0;
440
    for (;;) {
441
        if ( rptr->is_data_record( inbuff ) == YES )
442
        { /* Input record is a data record. */
443
            d_count     = rptr->get_data_count( inbuff );
444
            in_rec_addr = rptr->get_address( inbuff );
445
            in_dptr     = rptr->get_data_start( inbuff );
446
 
447
            if ( d_total == 0  ||  in_rec_addr != out_rec_addr + d_total )
448
            { /* Begin a new output record. */
449
                if ( d_total != 0 )
450
                    rptr->put_data_record( d_total, out_rec_addr, outbuff );
451
                out_dptr     = outbuff;
452
                n = d_total  = d_count;
453
                out_rec_addr = in_rec_addr;
454
            }
455
            else if
456
              ( ( d_excess = d_total + d_count - rptr->max_data_count ) > 0 )
457
            { /* Output a maximum-length record, then start a new record. */
458
                strncat( outbuff, in_dptr, 2 * ( d_count - d_excess ) );
459
                rptr->put_data_record(
460
                  rptr->max_data_count, out_rec_addr, outbuff
461
                );
462
                in_dptr      += 2 * ( d_count - d_excess );
463
                out_dptr      = outbuff;
464
                n = d_total   = d_excess;
465
                out_rec_addr += rptr->max_data_count;
466
            }
467
            else
468
            { /* Append input record's data field with accumulated data. */
469
                out_dptr = outbuff + ( 2 * d_total );
470
                d_total += n = d_count;
471
            }
472
            strncpy( out_dptr, in_dptr, 2 * n );
473
            out_dptr[ 2 * n ] = EOS;
474
        }
475
        else
476
        { /* Not a data record;
477
           * flush accumulated data then echo non-data record.
478
           */
479
            if ( d_total != 0 )
480
            {
481
                rptr->put_data_record( d_total, out_rec_addr, outbuff );
482
                d_total = 0;
483
            }
484
            puts( inbuff );
485
        }
486
 
487
        inbuff[ MAX_LINE_SIZE - 1 ] = '\0';
488
        if ( !fgets( inbuff, MAX_LINE_SIZE, stdin ) )
489
           break;
490
        if ( inbuff[ MAX_LINE_SIZE - 1 ] ) {
491
           fprintf( stderr, "Input line too long" );
492
           exit( 1 );
493
        }
494
        length = strlen(inbuff);
495
        inbuff[length - 1] = '\0';
496
 
497
    }
498
 
499
 
500
    return ( EXIT_SUCCESS );
501
 
502
}
503
 
504
 
505
/****   identify_first_data_record   *******************************************
506
*
507
*       Expects: Pointer to hex-record line buffer.
508
*
509
*       Returns: Pointer to hex-record structure (NULL if no match found).
510
*
511
*       Reads the standard input, line by line, searching for a valid
512
*       record header character.  If a valid header is found, a pointer
513
*       to the hex-record's type structure is returned, otherwise NULL.
514
*
515
*       The input-stream pointer is left pointing to the first valid hex record.
516
*
517
*******************************************************************************/
518
 
519
Rec_vitals * identify_first_data_record( char * buff_ptr, int max_length )
520
{
521
    Rec_vitals  ** ptr;
522
    int            length;
523
 
524
 
525
 
526
    for ( ;; ) {
527
 
528
        buff_ptr[ max_length - 1 ] = '\0';
529
        if ( !fgets( buff_ptr, max_length, stdin ) )
530
           break;
531
        if ( buff_ptr[ max_length - 1 ] ) {
532
           fprintf( stderr, "Input line too long" );
533
           exit( 1 );
534
        }
535
        length = strlen(buff_ptr);
536
        buff_ptr[length - 1] = '\0';
537
 
538
        for ( ptr = formats ; *ptr != ( Rec_vitals * ) NULL ; ptr++ )
539
            if ( ( *ptr )->is_data_record( buff_ptr ) == YES )
540
                return( *ptr );        /* Successful return.        */
541
 
542
        puts( buff_ptr );              /* Echo non-hex-record line. */
543
    }
544
 
545
    return( ( Rec_vitals * ) NULL );   /* Unsuccessful return.      */
546
}
547
 
548
 
549
/****   get_ndigit_hex   *******************************************************
550
*
551
*       Expects: Pointer to first ASCII hexadecimal digit, number of digits.
552
*
553
*       Returns: Value of hexadecimal string as an unsigned long.
554
*
555
*******************************************************************************/
556
 
557
Ulong get_ndigit_hex( char * cptr, int digits )
558
{
559
    Ulong    value;
560
 
561
    for ( value = 0 ; --digits >= 0 ; cptr++ )
562
        value = ( value * 16L ) + HEX_DIGIT( *cptr );
563
 
564
    return( value );
565
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.