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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [tools/] [build/] [unhex.c] - Blame information for rev 1778

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

Line No. Rev Author Line
1 1026 ivang
/*
2
 * unhex
3
 *      convert a hex file to binary equivalent.  If more than one file name
4
 *      is given, then the output will be logically concatenated together.
5
 *      stdin and stdout are defaults. Verbose will enable checksum output.
6
 *
7
 *  Supported input formats are Intel hex, Motorola S records, and TI 'B'
8
 *  records.
9
 *
10
 * Intel hex input format is
11
 *      Byte
12
 *       1          Colon :
13
 *       2..3       Record length, eg: "20"
14
 *       4..7       load address nibbles
15
 *       8..9       record type: "00" (data) or "02" base addr
16
 *       10..x      data bytes in ascii-hex
17
 *       x+1..x+2   cksum (2's compl of (len+addr+data))
18
 *       x+3        \n -- newline
19
 *
20
 *  unhex.c,v 1.9 1998/03/03 16:20:52 joel Exp
21
 */
22
 
23
char *USAGE = "\
24
usage:    unhex [-va] [ -o file ] [ file [file ... ] ]\n\
25
                -v          -- verbose\n\
26
                -a base     -- 1st byte of output corresponds to this address\n\
27
                -l          -- linear, just writes data out\n\
28
                -o file     -- output file; must not be input file\n\
29
                -F k_bits   -- \"holes\" in input will be filled with 0xFF's\n\
30
                                  up to \"k_bits\" * 1024 bits\n\
31
";
32
 
33
#include <stdio.h>
34
#include <fcntl.h>
35
#include <ctype.h>
36
#include <string.h>
37
#include <unistd.h>
38
#include <stdlib.h>
39
#include <stdarg.h>
40
#include <errno.h>
41
 
42
#include "config.h"
43
 
44
#ifndef VMS
45
#ifndef HAVE_STRERROR
46
extern int sys_nerr;
47
extern char *sys_errlist[];
48
 
49
#define strerror( _err ) \
50
  ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
51
 
52
#else   /* HAVE_STRERROR */
53
char *strerror ();
54
#endif
55
#else   /* VMS */
56
char *strerror (int,...);
57
#endif
58
 
59
 
60
#define OK      0
61
#define FAILURE (-1)
62
#define Failed(x)       ((x) == FAILURE)
63
#define TRUE    1
64
#define FALSE   0
65
typedef char bool;
66
#define STREQ(a,b)      (strcmp(a,b) == 0)
67
 
68
typedef unsigned char u8;
69
typedef unsigned short u16;
70
typedef unsigned long u32;
71
 
72
/*
73
 * Pick out designated bytes
74
 */
75
 
76
#define B0(x)       ((x) & 0xff)
77
#define B1(x)       B0((x) >> 8)
78
#define B2(x)       B0((x) >> 16)
79
#define B3(x)       B0((x) >> 24)
80
 
81
typedef struct buffer_rec {
82
    u32 dl_destaddr;
83
    u32 dl_jumpaddr;
84
    int dl_count;
85
    u8  dl_buf[512];
86
} buffer_rec;
87
 
88
/*
89
 * vars controlled by command line options
90
 */
91
 
92
bool verbose = FALSE;                   /* be verbose */
93
bool linear = FALSE;                    /* just write out linear data */
94
char *outfilename = "-";                /* default output is stdout */
95
u32 base = 0L;                         /* base address */
96
u32 FFfill = 0L;                       /* how far to fill w 0xFF's */
97
 
98
extern char *optarg;                    /* getopt(3) control vars */
99
extern int optind;
100
 
101
char *progname;                         /* for error() */
102
 
103
void error(int errn, ...);
104
#define ERR_ERRNO  (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
105
#define ERR_FATAL  (ERR_ERRNO / 2)              /* error is fatal; no return */
106
#define ERR_ABORT  (ERR_ERRNO / 4)              /* error is fatal; abort */
107
#define ERR_MASK   (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
108
 
109
#ifdef HAVE_STRTOUL
110
#define stol(p) strtoul(p, (char **) NULL, 0)
111
#else
112
#define stol(p) strtol(p, (char **) NULL, 0)
113
#endif
114
 
115
int   unhex(FILE *ifp, char *inm, FILE *ofp, char *onm);
116
int   convert_Intel_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
117
int   convert_S_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
118
int   convert_TI_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
119
void  write_record(buffer_rec *tb, FILE *fp);
120
int   getnibble(char **p);
121
int   getbyte(char **p);
122
long  getNbytes(char **p, int n);
123
void  badformat(char *s, char *fname, char *msg);
124
 
125
#define get1bytes(p)    ((int) getbyte(p))
126
#define get2bytes(p)    ((int) getNbytes(p, 2))
127
#define get3bytes(p)    getNbytes(p, 3)
128
#define get4bytes(p)    getNbytes(p, 4)
129
 
130
char *BADADDR = "Invalid record address";
131
char *BADLEN  = "Invalid record length";
132
char *BADBASE = "Bad base or starting address";
133
char *BADFMT =  "Unrecognized record type";
134
char *BADDATA = "Invalid data byte";
135
char *BADCSUM = "Invalid checksum";
136
char *MISCSUM = "Checksum mismatch";
137
char *BADTYPE = "Unrecognized record type";
138
char *MISTYPE = "Incompatible record types";
139
 
140
int main(
141
  int argc,
142
  char **argv
143
)
144
{
145
    register int c;
146
    bool showusage = FALSE;                     /* usage error? */
147
    int rc = 0;
148
    FILE *outfp, *infp;
149
 
150
    /*
151
     * figure out invocation leaf-name
152
     */
153
 
154
    if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
155
        progname = argv[0];
156
    else
157
        progname++;
158
 
159
    argv[0] = progname;                         /* for getopt err reporting */
160
 
161
    /*
162
     *  Check options and arguments.
163
     */
164
 
165
    progname = argv[0];
166
    while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF)
167
        switch (c)
168
        {
169
            case 'a':                           /* base address */
170
                base = stol(optarg);
171
                break;
172
 
173
            case 'l':                           /* linear output */
174
                linear = TRUE;
175
                break;
176
 
177
            case 'v':                           /* toggle verbose */
178
                verbose = ! verbose;
179
                break;
180
 
181
            case 'o':                           /* output file */
182
                outfilename = optarg;
183
                break;
184
 
185
            case 'F':                           /* 0xFF fill amount (bytes) */
186
                FFfill = stol(optarg) * 1024L / 8L;
187
                break;
188
 
189
            case '?':
190
                showusage = TRUE;
191
        }
192
 
193
    if (showusage)
194
    {
195
        (void) fprintf(stderr, "%s", USAGE);
196
        exit(1);
197
    }
198
 
199
    if (linear && (base != 0))
200
    {
201
        error(0, "-l and -a may not be specified in combination");
202
        exit(1);
203
    }
204
 
205
    if (STREQ(outfilename, "-"))
206
    {
207
        outfp = stdout;
208
        outfilename = "stdout";
209
    }
210
    else
211
        if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL)
212
        {
213
            error(-1, "couldn't open '%s' for output", outfilename);
214
            exit(1);
215
        }
216
 
217
    /*
218
     * Now process the input files (or stdin, if none specified)
219
     */
220
 
221
    if (argv[optind] == (char *) NULL)          /* just stdin */
222
        exit(unhex(stdin, "stdin", outfp, outfilename));
223
    else
224
        for (; (optarg = argv[optind]); optind++)
225
        {
226
            if (STREQ(optarg, "-"))
227
                rc += unhex(stdin, "stdin", outfp, outfilename);
228
            else
229
            {
230
                if ((infp = fopen(optarg, "r")) == (FILE *) NULL)
231
                {
232
                    error(-1, "couldn't open '%s' for input", optarg);
233
                    exit(1);
234
                }
235
                rc += unhex(infp, optarg, outfp, outfilename);
236
            }
237
        }
238
 
239
    return(rc);
240
}
241
 
242
u16 filesum;
243
 
244
int
245
unhex(FILE *ifp,
246
      char *inm,
247
      FILE *ofp,
248
      char *onm)
249
{
250
    int c;
251
 
252
    filesum = 0;
253
 
254
    /*
255
     * Make sure holes will be filled with 0xFF's if requested.  We
256
     *  do this the easy way by just filling the file with FF's before
257
     *  getting started.  To do it more optimally would be quite a bit
258
     *  more difficult since the user can skip around as much as he/she
259
     *  likes in the input hex file addressing.
260
     *
261
     *  We'll clean this up later (after this program has run) with
262
     *  'stripffs'
263
     */
264
 
265
    if (FFfill)
266
    {
267
        (void) fseek(ofp, 0, 0);
268
        for (c = FFfill; c > 0; c--)
269
            (void) fputc(0xFF, ofp);
270
    }
271
 
272
    /*
273
     * Read the first char from file and determine record types
274
     */
275
 
276
    if ((c = getc(ifp)) != EOF)
277
    {
278
        ungetc(c, ifp);
279
        switch(c)
280
        {
281
            case 'S':
282
                convert_S_records(ifp, inm, ofp, onm);
283
                break;
284
 
285
            case ':':
286
                convert_Intel_records(ifp, inm, ofp, onm);
287
                break;
288
 
289
            case '9':
290
            case 'B':
291
                convert_TI_records(ifp, inm, ofp, onm);
292
                break;
293
 
294
            default:
295
            {
296
                char tmp[2];
297
                tmp[0] = c; tmp[1] = 0;
298
                badformat(tmp, inm, BADFMT);
299
            }
300
        }
301
    }
302
 
303
    if (verbose)
304
        fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum);
305
 
306
    return 0;
307
}
308
 
309
int
310
convert_Intel_records(
311
    FILE *ifp,
312
    char *inm,
313
    FILE *ofp,
314
    char *onm)
315
{
316
    char buff[512];
317
    char *p;
318
    u8 cksum;
319
    int incksum;
320
    int c;
321
    int rectype;                    /* record type */
322
    int len;                        /* data length of current line */
323
    u32 addr;
324
    u32 base_address = 0;
325
    bool endrecord = FALSE;
326
    buffer_rec tb;
327
 
328
    while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
329
    {
330
        p = &buff[0];
331
 
332
        if (p[strlen(p)-1] == '\n')                 /* get rid of newline */
333
            p[strlen(p)-1] = '\0';
334
 
335
        if (p[strlen(p)-1] == '\r')                 /* get rid of any CR */
336
            p[strlen(p)-1] = '\0';
337
 
338
        tb.dl_count = 0;
339
 
340
        if (*p != ':')
341
            badformat(p, inm, BADFMT);
342
        p++;
343
 
344
        if ((len = getbyte(&p)) == -1)      /* record len */
345
            badformat(buff, inm, BADLEN);
346
 
347
        if ((addr = get2bytes(&p)) == -1L)          /* record addr */
348
            badformat(buff, inm, BADADDR);
349
 
350
        rectype = getbyte(&p);
351
 
352
        cksum = len + B0(addr) + B1(addr) + rectype;
353
 
354
        switch (rectype)
355
        {
356
            case 0x00:                  /* normal data record */
357
                tb.dl_destaddr = base_address + addr;
358
                while (len--)
359
                {
360
                    if ((c = getbyte(&p)) == -1)
361
                        badformat(buff, inm, BADDATA);
362
                    cksum += c;
363
                    filesum += c;
364
                    tb.dl_buf[tb.dl_count++] = c;
365
                }
366
                break;
367
 
368
            case 0x01:                  /* execution start address */
369
                base_address = addr;
370
                endrecord = TRUE;
371
                break;
372
 
373
            case 0x02:                  /* new base */
374
                if ((base_address = get2bytes(&p)) == -1L)
375
                    badformat(buff, inm, BADBASE);
376
                cksum += B0(base_address) + B1(base_address);
377
                base_address <<= 4;
378
                break;
379
 
380
            case 0x03:                  /* seg/off execution start address */
381
            {
382
                u32 seg, off;
383
 
384
                seg = get2bytes(&p);
385
                off = get2bytes(&p);
386
                if ((seg == -1L) || (off == -1L))
387
                    badformat(buff, inm, BADADDR);
388
 
389
                cksum += B0(seg) + B1(seg) + B0(off) + B1(off);
390
 
391
                tb.dl_jumpaddr = (seg << 4) + off;
392
                break;
393
            }
394
 
395
            default:
396
                error(0, "unknown Intel-hex record type: 0x%02x", rectype);
397
                badformat(buff, inm, BADTYPE);
398
        }
399
 
400
        /*
401
         * Verify checksums are correct in file.
402
         */
403
 
404
        cksum = (-cksum) & 0xff;
405
        if ((incksum = getbyte(&p)) == -1)
406
            badformat(buff, inm, BADCSUM);
407
        if (((u8) incksum) != cksum)
408
            badformat(buff, inm, MISCSUM);
409
 
410
        if (tb.dl_count)
411
            write_record(&tb, ofp);
412
    }
413
    return 0;
414
}
415
 
416
int
417
convert_S_records(
418
    FILE *ifp,
419
    char *inm,
420
    FILE *ofp,
421
    char *onm)
422
{
423
    char buff[512];
424
    char *p;
425
    u8 cksum;
426
    int incksum;
427
    int c;
428
    int len;                        /* data length of current line */
429
    int rectype;                    /* record type */
430
    u32 addr;
431
    bool endrecord = FALSE;
432
    buffer_rec tb;
433
 
434
    while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
435
    {
436
        p = &buff[0];
437
 
438
        if (p[strlen(p)-1] == '\n')                 /* get rid of newline */
439
            p[strlen(p)-1] = '\0';
440
 
441
        if (p[strlen(p)-1] == '\r')                 /* get rid of any CR */
442
            p[strlen(p)-1] = '\0';
443
 
444
        tb.dl_count = 0;
445
 
446
        if (*p != 'S')
447
            badformat(p, inm, BADFMT);
448
        p++;
449
 
450
        if ((rectype = getnibble(&p)) == -1)        /* record type */
451
            badformat(buff, inm, BADTYPE);
452
 
453
        if ((len = getbyte(&p)) == -1)              /* record len */
454
            badformat(buff, inm, BADLEN);
455
        cksum = len;
456
 
457
        switch (rectype)
458
        {
459
            case 0x00:                  /* comment field, ignored */
460
                goto write_it;
461
 
462
            case 0x01:                          /* data record, 16 bit addr */
463
                if ((addr = get2bytes(&p)) == -1L)
464
                    badformat(buff, inm, BADADDR);
465
                len -= 3;
466
                goto doit;
467
 
468
            case 0x02:                          /* ... 24 bit addr */
469
                if ((addr = get3bytes(&p)) == -1L)
470
                    badformat(buff, inm, BADADDR);
471
                len -= 4;
472
                goto doit;
473
 
474
            case 0x03:                          /* ... 32 bit addr */
475
                if ((addr = get4bytes(&p)) == -1L)
476
                    badformat(buff, inm, BADADDR);
477
                len -= 5;
478
    doit:
479
                cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
480
 
481
                tb.dl_destaddr = addr;
482
                while (len--)
483
                {
484
                    if ((c = getbyte(&p)) == -1)
485
                        badformat(buff, inm, BADDATA);
486
                    cksum += c;
487
                    filesum += c;
488
                    tb.dl_buf[tb.dl_count++] = c;
489
                }
490
                break;
491
 
492
            case 0x07:                  /* 32 bit end record */
493
                if ((addr = get4bytes(&p)) == -1L)
494
                    badformat(buff, inm, BADADDR);
495
                goto end_rec;
496
 
497
            case 0x08:                  /* 24 bit end record */
498
                if ((addr = get3bytes(&p)) == -1L)
499
                    badformat(buff, inm, BADADDR);
500
                goto end_rec;
501
 
502
            case 0x09:                  /* 16 bit end record */
503
                if ((addr = get2bytes(&p)) == -1L)
504
                    badformat(buff, inm, BADADDR);
505
 
506
end_rec:
507
                cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
508
                tb.dl_jumpaddr = addr;
509
                break;
510
 
511
            default:
512
                error(0, "unknown Motorola-S record type: 0x%02x", rectype);
513
                badformat(buff, inm, BADTYPE);
514
                break;
515
        }
516
 
517
        /*
518
         * Verify checksums are correct in file.
519
         */
520
 
521
        cksum = (~cksum) & 0xff;
522
        if ((incksum = getbyte(&p)) == -1)
523
            badformat(buff, inm, BADCSUM);
524
        if (((u8) incksum) != cksum)
525
            badformat(buff, inm, MISCSUM);
526
 
527
write_it:
528
        if (tb.dl_count)
529
            write_record(&tb, ofp);
530
    }
531
    return 0;
532
}
533
 
534
int
535
convert_TI_records(
536
    FILE *ifp,
537
    char *inm,
538
    FILE *ofp,
539
    char *onm)
540
{
541
    char buff[512];
542
    char *p;
543
    int c;
544
    bool endrecord = FALSE;
545
    bool eol;
546
    buffer_rec tb;
547
 
548
    while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
549
    {
550
        if (p[strlen(p)-1] == '\n')                 /* get rid of newline */
551
            p[strlen(p)-1] = '\0';
552
 
553
        if (p[strlen(p)-1] == '\r')                 /* get rid of any CR */
554
            p[strlen(p)-1] = '\0';
555
 
556
        tb.dl_count = 0;
557
 
558
        p = &buff[0];
559
        eol = FALSE;
560
        while ( ! eol && ! endrecord)
561
        {
562
            switch (*p++)
563
            {
564
                case '9':
565
                    if (tb.dl_count)
566
                        write_record(&tb, ofp);
567
                    tb.dl_destaddr = get2bytes(&p);
568
                    break;
569
 
570
                case 'B':
571
                    c = getbyte(&p);
572
                    filesum += c;
573
                    tb.dl_buf[tb.dl_count++] = c;
574
                    c = getbyte(&p);
575
                    filesum += c;
576
                    tb.dl_buf[tb.dl_count++] = c;
577
                    break;
578
 
579
                case 'F':
580
                    eol = TRUE;
581
                    break;
582
 
583
                case ':':
584
                    endrecord = TRUE;
585
                    break;
586
 
587
                default:
588
                    badformat(p, inm, BADFMT);
589
            }
590
        }
591
        if (tb.dl_count)
592
            write_record(&tb, ofp);
593
    }
594
    return 0;
595
}
596
 
597
void
598
write_record(buffer_rec *tb,
599
             FILE *fp)
600
{
601
    if ( ! linear)
602
    {
603
        if (tb->dl_destaddr < base)
604
            error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x",
605
                     tb->dl_destaddr, base);
606
        (void) fseek(fp, tb->dl_destaddr - base, 0);
607
    }
608
 
609
    (void) fwrite(tb->dl_buf, tb->dl_count, 1, fp);
610
    tb->dl_destaddr += tb->dl_count;
611
    tb->dl_count = 0;
612
}
613
 
614
int
615
getnibble(char **p)
616
{
617
    register int val;
618
 
619
    **p = toupper(**p);
620
    switch (**p)
621
    {
622
        case '0': case '1': case '2': case '3': case '4':
623
        case '5': case '6': case '7': case '8': case '9':
624
            val = **p - '0';
625
            break;
626
 
627
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
628
            val = 10 + (**p - 'A');
629
            break;
630
 
631
        default:
632
            return(-1);
633
    }
634
    *p += 1;
635
 
636
    return(val & 0x0f);
637
}
638
 
639
int
640
getbyte(char **p)
641
{
642
    int n0, n1;
643
 
644
    if ((n0 = getnibble(p)) == -1)
645
        return(-1);
646
    if ((n1 = getnibble(p)) == -1)
647
        return(-1);
648
 
649
    return(((n0 << 4) + n1) & 0xff);
650
}
651
 
652
long
653
getNbytes(char **p,
654
          int n)
655
{
656
    int t;
657
    u32 val = 0;
658
 
659
    while (n--)
660
    {
661
        if ((t = getbyte(p)) == -1)
662
            return(-1L);
663
        val <<= 8;
664
        val += t;
665
    }
666
 
667
    return(val);
668
}
669
 
670
void
671
badformat(char *s,
672
          char *fname,
673
          char *msg)
674
{
675
    if (s[strlen(s)-1] == '\n')             /* get rid of newline */
676
        s[strlen(s)-1] = '\0';
677
    error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg);
678
    exit(1);
679
}
680
 
681
/*
682
 * error(errn, arglist)
683
 *      report an error to stderr using printf(3) conventions.
684
 *      Any output is preceded by '<progname>: '
685
 *
686
 * Uses ERR_EXIT  bit to request exit(errn)
687
 *      ERR_ABORT to request abort()
688
 *      ERR_ERRNO to indicate use of errno instead of argument.
689
 *
690
 * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
691
 *      associated error message is appended to the output.
692
 */
693
 
694
/*VARARGS*/
695
 
696
void
697
error(int error_flag, ...)
698
{
699
    va_list arglist;
700
    register char *format;
701
    int local_errno;
702
 
703
    extern int errno;
704
 
705
    (void) fflush(stdout);          /* in case stdout/stderr same */
706
 
707
    local_errno = error_flag & ~ERR_MASK;
708
    if (error_flag & ERR_ERRNO)     /* use errno? */
709
        local_errno = errno;
710
 
711
    va_start(arglist, error_flag);
712
    format = va_arg(arglist, char *);
713
    (void) fprintf(stderr, "%s: ", progname);
714
    (void) vfprintf(stderr, format, arglist);
715
    va_end(arglist);
716
 
717
    if (local_errno)
718
      (void) fprintf(stderr, " (%s)\n", strerror(local_errno));
719
    else
720
      (void) fprintf(stderr, "\n");
721
 
722
    (void) fflush(stderr);
723
 
724
    if (error_flag & (ERR_FATAL | ERR_ABORT))
725
    {
726
        if (error_flag & ERR_FATAL)
727
        {
728
            error(0, "fatal error, exiting");
729
            exit(local_errno ? local_errno : 1);
730
        }
731
        else
732
        {
733
            error(0, "fatal error, aborting");
734
            abort();
735
        }
736
    }
737
}
738
 

powered by: WebSVN 2.1.0

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