Makefile cleanup
[keystone-rtos/ibl.git] / src / util / bconvert / bconvert.c
1 /*
2  *
3  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 
4  * 
5  * 
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions 
8  *  are met:
9  *
10  *    Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  *    Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the   
16  *    distribution.
17  *
18  *    Neither the name of Texas Instruments Incorporated nor the names of
19  *    its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
24  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
26  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
27  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
28  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
31  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
32  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34 */
38 /************************************************************************************
39  * FILE PURPOSE: Convert a hex55 boot table file into the format required
40  *               by the c6x chip boot loader. 
41  ************************************************************************************
42  * FILE NAME: bconvert.c
43  *
44  * DESCRIPTION: Converts a boot table. The boot table format is:
45  *
46  *    /--------------------------------------------------------\
47  *    |              32 bit entry point address                |
48  *    +--------------------------------------------------------+
49  *    |          32 bit register configuration count           |
50  *    +---------------------------+----------------------------+
51  *    |   16 bit register address |  16 bit register contents  | \
52  *    +---------------------------+----------------------------+   repeat reg count
53  *    |   16 bit delay indicator  |  16 bit delay count        | /
54  *    +---------------------------+----------------------------+
55  *    |              32 bit section byte count                 | \
56  *    +--------------------------------------------------------+  \
57  *    |         32 bit section byte start address              |   \
58  *    +-------------+-------------+-------------+--------------+    repeat each section
59  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   |   /
60  *    +-------------+-------------+-------------+--------------+  /
61  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   | /
62  *    +-------------+-------------+-------------+--------------+ 
63  *    |        32 bit zero byte count (end of boot table)      | 
64  *    \--------------------------------------------------------/
65  *
66  *
67  *  The C6x boot loader expects all 32 bit and 16 bit values to be in big endian
68  *  (most significant byte arrives first). Data bytes are also arranged to be 32 bit
69  *  big endian represented.
70  *
71  *  The hex55 tool is used to convert the coff output file to a boot table. But
72  *  the 55x processor is 16 bit based, creating a mix of output files depending
73  *  on if the c6x code was compiled big endian or little endian. 
74  *
75  *  If compiled and linked big endian, then the 32 and 16 bit values and the data 
76  *  will be in the correct big endian format. The program does nothing.
77  *
78  *  If compiled and linked little endian, then the each 16 bits of 32 bit values are
79  *  little endian, but the two 16 bit words are big endian. So for 32 bit values
80  *  the bytes are swapped over 16 bits, but not accross 32 bits. The data bytes
81  *  are converted into 32 bit values, and stored back out. If the size is not
82  *  evenly divisible by four, then in that final segment the least significant
83  *  bytes are written, but in big endian format.
84  *
85  *  If the -noreg option is used, then there will be no I/O register count or any
86  *  registers in the table. This is for c6x compatibility
87  *
88  *
89  *  Invokation:
90  *
91  *  bconvert -be|-le [-noreg] [-reg32 addr value delay [-reg32 addr value delay [...]]]  [input_file] [output_file]
92  *
93  ***************************************************************************************/
95 #include "stdio.h"
96 #include "malloc.h"
97 #include "string.h"
99 /* Global variable storing the invokation name */
100 char *invok;
102 /* Register configurations */
103 int nRegs = 0;
104 #define MAX_REG 128
105 typedef struct {
106   unsigned int addr;
107   unsigned int value;
108   unsigned int delay;
109 } regConfig_t;
111 regConfig_t regConfig[MAX_REG];
113 /* If includeIo is 0, no I/O space config is used */
114 int includeIO = 1;
117 /* Error values */
118 enum {
119   ERR_PARSE_TOO_MANY_ARGS = 1000,
120   ERR_PARSE_NO_ENDIAN,
121   ERR_PARSE_INPUT_OPEN_FAIL,
122   ERR_PARSE_OUTPUT_OPEN_FAIL,
123   ERR_READ_BFILE_INITIAL_MALLOC_FAIL,
124   ERR_READ_BFILE_REALLOC_FAIL,
125   ERR_VALUE32_SIZE_ERR,
126   ERR_VALUE16_SIZE_ERR,
127   ERR_DATA32_SIZE_ERR,
128   ERR_REG32_PARSE_ERROR
129 };
131 enum {
132   LITTLE,
133   BIG
134 };
136 /************************************************************************************
137  * FUNTION PURPOSE: Send an error string
138  ************************************************************************************
139  * DESCRIPTION: Prints an error to stderr
140  ************************************************************************************/
141 void showErr (int errflag)
143   char *s;
145   switch (errflag)  {
146     case ERR_PARSE_TOO_MANY_ARGS:
147        s = "Parse error: too many args specified";
148        break;
150     case ERR_PARSE_NO_ENDIAN:
151        s = "Parse error: no endian mode specified";
152        break;
154     case ERR_PARSE_INPUT_OPEN_FAIL:
155        s = "File error: failed to open specified input file";
156        break;
158     case ERR_PARSE_OUTPUT_OPEN_FAIL:
159        s = "File error: Failed to open specified output file";
160        break;
162     case ERR_READ_BFILE_INITIAL_MALLOC_FAIL:
163        s = "Memory error: Initial malloc call failed";
164        break;
166     case ERR_READ_BFILE_REALLOC_FAIL:
167        s = "Memory error: Subsequent realloc call failed";
168        break;
170     case ERR_VALUE32_SIZE_ERR:
171        s = "Data format error: End of data on 32 bit value read";
172        break;
174     case ERR_VALUE16_SIZE_ERR:
175        s = "Data format error: End of data on 16 bit value read";
176        break;
178     case ERR_REG32_PARSE_ERROR:
179        s = "Parse error: error parsing after reg32 arg";
180        break;
182     default:
183        s = "Unspecified error";
184        break;
186   }
188   fprintf (stderr, "%s: %s\n", invok, s);
190 } /* showErr */
193 /*************************************************************************************
194  * FUNCTION PURPOSE: Check if a string is prefixed with "0x".
195  *************************************************************************************
196  * DESCRIPTION: Returns non-zero if the string begins with "0x"
197  *************************************************************************************/
198 int isChex (char *s)
200   if ((s[0] == '0') && (s[1] == 'x'))
201     return (1);
203   return (0);
205 } /* isChex */
209 /*************************************************************************************
210  * FUNCTION PURPOSE: Parse the input parameters
211  *************************************************************************************
212  * DESCRIPTION: Checks for required args, opens source and destination streams.
213  *************************************************************************************/
214 int parseit (int argc, char *argv[], FILE **fin, FILE **fout, int *endian)
216   int inspec  = 0;
217   int outspec = 0;
218   int espec   = 0;
219   int c       = 1;
221   char *iname;
222   char *oname;
224   *endian = -1;
226   /* Store the invokation name */
227   invok = argv[0];
229   while (c < argc)  {
231     /* -be | -le */
232     if (!espec)  {
233       if (!strcmp (argv[c], "-be"))  {
234         *endian = BIG;
235         espec = 1;
236         c += 1;
237         continue;
238       } else if (!strcmp (argv[c], "-le"))  {
239         *endian = LITTLE;
240         espec = 1;
241         c += 1;
242         continue;
243       }
244     }
246     if (!strcmp (argv[c], "-noreg"))  {
247       includeIO = 0;
248       c += 1;
249       continue;
250     }
251       
253     if (!strcmp (argv[c], "-reg32"))  {
254       if ((c + 3) >= argc)  {
255         return (ERR_REG32_PARSE_ERROR);
256       }
258       if (isChex (argv[c+1]))
259         sscanf (&(argv[c+1][2]), "%x", &regConfig[nRegs].addr);
260       else
261         sscanf (argv[c+1], "%d", &regConfig[nRegs].addr);
263       if (isChex (argv[c+2]))
264         sscanf (&(argv[c+2][2]), "%x", &regConfig[nRegs].value);
265       else
266         sscanf (argv[c+2], "%d", &regConfig[nRegs].value);
268       if (isChex (argv[c+3]))
269         sscanf (&(argv[c+3][2]), "%x", &regConfig[nRegs].delay);
270       else
271         sscanf (argv[c+3], "%d", &regConfig[nRegs].delay);
273       c += 4;
274       nRegs += 1;
275       continue;
276     }
278     /* input file */
279     if (!inspec)  {
280       inspec = 1;
281       iname = argv[c];
282       c += 1;
283       continue;
284     }
286     /* output file */
287     if (!outspec)  {
288       outspec = 1;
289       oname = argv[c];
290       c += 1;
291       continue;
292     }
294     /* Don't know what to do with the arg */
295     return (ERR_PARSE_TOO_MANY_ARGS);
297   }
300   /* Make sure endian is known */
301   if (!espec) 
302     return (ERR_PARSE_NO_ENDIAN);
304   /* Open input file if not stdin */
305   if (inspec)  {
306     *fin = fopen (iname, "r");
307     if (*fin == NULL)
308       return (ERR_PARSE_INPUT_OPEN_FAIL);
309   }
311   /* Open output file if not stdin */
312   if (outspec)  {
313     *fout = fopen (oname, "w");
314     if (*fout == NULL)
315       return (ERR_PARSE_OUTPUT_OPEN_FAIL);
316   }
317  
318   return (0);
320 } /* parseit */
324 /***************************************************************************************
325  * FUNCTION PURPOSE: Check if data is ascii
326  ***************************************************************************************
327  * DESCRIPTION: Returns 1 if a byte is 0-9, a-f, 0 otherwise
328  ***************************************************************************************/
329 int asciiByte (unsigned char c)
331   if ((c >= '0') && (c <= '9'))
332     return (1);
334   if ((c >= 'A') && (c <= 'F'))
335     return (1);
337   return (0);
338 } /* asciiByte */
340 /**************************************************************************************
341  * FUNCTION PURPOSE: Returns the binary equivalent of an ascii byte
342  **************************************************************************************
343  * DESCRIPTION: Conversion from ascii to binary
344  **************************************************************************************/
345 int toNum (unsigned char c)
347   if ((c >= '0') && (c <= '9'))
348     return (c - '0');
350   return (c - 'A' + 10);
352 } /* toNum */
355 /**********************************************************************************
356  * FUNCTION PURPOSE: Read a line from a file, toss it
357  **********************************************************************************
358  * DESCRIPTION: Reads a line, including the newline character, and throws it away.
359  **********************************************************************************/
360 void  stripLine (FILE *s)
362   char iline[132];
364   fgets (iline, 131, s);
366 } /* stripLine */
368 /************************************************************************************
369  * FILE PURPOSE: Read the hex55 data file
370  ************************************************************************************
371  * DESCRIPTION: Reads the input data file. Strips the first two lines, reads
372  *              the byte stream.
373  ************************************************************************************/
374 #define MALLOC_BLOCK_SIZE   512000
375 unsigned char *readBFile (FILE *fin, unsigned *n, int *errcode)
377   unsigned char *d;
378   unsigned allocSize;
379   unsigned m;
380   unsigned char x, y;
382   /* Create a block of data */
383   allocSize = MALLOC_BLOCK_SIZE;
384   d = malloc (allocSize * sizeof (unsigned char));
385   if (d == NULL)  {
386     *errcode = ERR_READ_BFILE_INITIAL_MALLOC_FAIL;
387     if (fin != stdin)
388       fclose (fin);
389     return (NULL);
390   }
392   /* Strip the 1st two lines */
393   stripLine (fin);
394   stripLine (fin);
396   *errcode = 0;
397   m = 0;
399   for (;;)  {
401     /* Read the 1st ascii char */
402     do  {
403       x = fgetc (fin);
404       if (x == (unsigned char)EOF)  {
405         *errcode = 0;
406         *n = m;
407         if (fin != stdin)
408           fclose (fin);
409         return (d);
410       }
411     } while (!asciiByte(x));
413     /* Read the next ascii char */
414     y = fgetc(fin);
415     if (y == (unsigned char)EOF)  {
416       *errcode = 0;
417       *n = m;
418       if (fin != stdin)
419         fclose (fin);
420       return (d);
421     }
423     /* Convert the two characters into a byte */
424     if (asciiByte(y))
425       d[m++] = (toNum(x) << 4) | toNum(y);
427     /* Verify memory bounds */
428     if (m >= allocSize)  {
429       allocSize += MALLOC_BLOCK_SIZE;
430       d= realloc (d, allocSize);
431       if (d== NULL)  {
432         *errcode = ERR_READ_BFILE_REALLOC_FAIL;
433         if (fin != stdin)
434           fclose (fin);
435         return (NULL);
436       }
437     }
439   } /* end for */
441 } /* readBFile */
443 /**************************************************************************************
444  * FUNCTION PURPOSE: converts four bytes into an unsigned value
445  **************************************************************************************
446  * DESCRIPTION: Converts bytes to a value, depending on the endian configuration.
447  **************************************************************************************/
448 unsigned value32bitAdd (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag, unsigned add)
450   unsigned v;
451   unsigned w;
452   unsigned q;
454   /* Verify that there are 4 values still in the character array */
455   if ((*p + 4) > n)  {
456     *errflag = ERR_VALUE32_SIZE_ERR;
457     return (0);
458   }
460   /* Store the original pointer */
461   q = w = *p;
463   /* convert based on endianness. For little endain the 16 bit words are actually
464    * big endian, but the bytes in those words are not */
465   if (endian == BIG)  {
466     v = (unsigned)data[w+0] << 24 |
467         (unsigned)data[w+1] << 16 |
468         (unsigned)data[w+2] <<  8 |
469         (unsigned)data[w+3] <<  0 ; 
471   }  else  {
472     v = (unsigned)data[w+0] << 16 |
473         (unsigned)data[w+1] << 24 |
474         (unsigned)data[w+2] <<  0 |
475         (unsigned)data[w+3] <<  8 ;
476   }
478   *errflag = 0;
480   /* Add any additional value */
481   v = v + add;
483   /* Write the data back in big endian format */
484   data[q+0] = (v >> 24) & 0xff;
485   data[q+1] = (v >> 16) & 0xff;
486   data[q+2] = (v >>  8) & 0xff;
487   data[q+3] = (v >>  0) & 0xff;
489   *p = q+4;
490   return (v);
492 } /* value32bitAdd */
494 /**************************************************************************************
495  * FUNCTION PURPOSE: converts four bytes into an unsigned value
496  **************************************************************************************
497  * DESCRIPTION: Converts bytes to a value, depending on the endian configuration.
498  **************************************************************************************/
499 unsigned value32bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
501   return (value32bitAdd (endian, data, n, p, errflag, 0));
503 } /* value32bit */
508 /*********************************************************************************
509  * FUNCTION PURPOSE: Convert up to four bytes to big endian 
510  *********************************************************************************
511  * DESCRIPTION: Data bytes are converted. 
512  *********************************************************************************/
513 #define SWAP(x,y,z)  (z)=(x);(x)=(y);(y)=(z)
514 void data32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
517   unsigned char h;
518   unsigned      w;
520   /* Calculate the number of bytes to convert, limited to four bytes */
521   if (m > 4)
522     m = 4;
524   /* return an error if there are not enough values in the array */
525   if ((*p + m) >= n)  {
526     *errflag = ERR_DATA32_SIZE_ERR;
527     return;
528   }
530   /* Clear the error flag */
531   *errflag = 0;
534   /* For big endian there is nothing to do but advance the pointer */
535   if (endian == BIG)  {
536     *p += m;
537     return;
538   }
540    w = *p;
541   *p = *p + m;
543   /* Four is the most common size */
544   if (m == 4)  {
545     SWAP(data[w+0], data[w+3], h);
546     SWAP(data[w+1], data[w+2], h);
547     return;
548   }
551   /* Perform the conversion based on the size */
552   if (m == 1)  {
553     return;
554   }
556   if (m == 2)  {
557     SWAP(data[w+0], data[w+1], h);
558     return;
559   }
562   if (m == 3)  {
563     SWAP(data[w+0], data[w+2], h);
564     return;
565   }
567 } /* data32bit */
570 /*********************************************************************************
571  * FUNCTION PURPOSE: Convert 2 bytes into an unsigned value
572  *********************************************************************************
573  * DESCRIPTION: Converts the next two bytes into an unsigned value based on
574  *              the endian configuration.
575  *********************************************************************************/
576 unsigned value16bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
578   unsigned v;
579   unsigned q;
581   /* Verify that there are 4 values still in the character array */
582   if ((*p + 2) > n)  {
583     *errflag = ERR_VALUE16_SIZE_ERR;
584     return (0);
585   }
587   /* Store the original pointer */
588   q = *p;
590   /* convert based on endianness. For little endain the 16 bit words are actually
591    * big endian, but the bytes in those words are not */
592   if (endian == BIG)  {
593     v = data[(*p)++] <<  8 |
594         data[(*p)++] <<  0 ;
596   }  else  {
597     v = data[(*p)++] <<  0 |
598         data[(*p)++] <<  8 ;
599   }
601   *errflag = 0;
603   /* Write the data back in big endian format */
604   data[q++] = (v >>  8) & 0xff;
605   data[q++] = (v >>  0) & 0xff;
607   return (v);
609 } /* value16bit */
611 /**************************************************************************************
612  * FUNCTION PURPOSE: Writes a 16 bit value into the array
613  **************************************************************************************
614  * DESCRIPTION: Writes a big endian 16 bit value, increments the array pointer.
615  **************************************************************************************/
616 void write16bit (unsigned value, unsigned char *data, unsigned *p)
618   data[(*p)++] = (value >> 8) & 0xff;
619   data[(*p)++] = (value >> 0) & 0xff;
621 } /* write16bit */
624 /*************************************************************************************
625  * FUNCTION PURPOSE: Write the output file
626  *************************************************************************************
627  * DESCRIPTION: Writes the resulting output.
628  *************************************************************************************/
629 void writeBFile (FILE *fout, unsigned char *data, unsigned n)
631   unsigned i;
633   /* Write the two line header */
634   fprintf (fout, "%c\n$A000000\n", (unsigned char)2);
636   for (i = 0; i < n; i++)  {
637     if ( ((i+1)%24)  )
638       fprintf (fout, "%02X ", data[i]);
639     else
640       fprintf (fout, "%02X\n", data[i]);
641   }
643   /* Write the close character */
644   fprintf (fout, "\n%c", (unsigned char)3);
646   if (fout != stdout)
647     fclose (fout);
649 } /* writeBFile */
650   
652 /**************************************************************************************
653  * FUNCTION PURPOSE: Main 
654  **************************************************************************************
655  * DESCRIPTION: Provides the top level program flow.
656  **************************************************************************************/
657 int main (int argc, char *argv[])
659   FILE *fin;            /* input stream  */
660   FILE *fout;           /* output stream */
662   unsigned char *data;  /* The data set  */
663   unsigned n;           /* Data set size */
664   unsigned p;           /* Data index    */
665   unsigned v;           /* Data value    */
667   int endian;           /* Endian          */  
668   int errflag;          /* error indicator */
669   int i, j;             /* loop var        */
670   int origRegs;         /* original reg count */
671   int shift;            /* data shift amount  */
674   /* Parse the input */
675   if (errflag = parseit (argc, argv, &fin, &fout, &endian))  {
676     showErr (errflag);
677     return (-1);
678   }
680   /* Read the raw data file */
681   data = readBFile (fin, &n, &errflag);
682   if (data == NULL)  {
683     showErr (errflag);
684     return(-1);
685   }
687   /* Parse the sections */
688   p = 0;
690   /* The entry point */
691   v = value32bit (endian, data, n, &p, &errflag);
692   if (errflag)  {
693     showErr (errflag);
694     return(-1);
695   }
697   if (includeIO)  {
699     /* Read the register configuration count, but write back a different
700      * value if new register configs are required */
701     v = value32bitAdd (endian, data, n, &p, &errflag, 2*nRegs);
702     if (errflag)  {
703       showErr (errflag);
704       return(-1);
705     }
707     origRegs = v - (2*nRegs);  /* Each 32 bit register config requires 2 reg writes */
709     /* If any reg32 registers are added, the data array must be shifted
710      * and the new register configurations added */
711     for (i = 0; i < origRegs; i++)  {        /* number of register blocks */
712       for (j = 0; j < 4; j++)  {      /* register block values     */
713         value16bit (endian, data, n, &p, &errflag);
714         if (errflag)  {
715           showErr (errflag);
716           return(-1);
717         }
718       }
719     }
722     /* If there are additional registers, the data must be shifted down in the
723      * array to make room. Each register config required 2 configuration blocks,
724      * and each configuration block is 64 bits, or 8 characters */
725     if (nRegs)  {
727       shift = 2 * nRegs * 8;
728       for (i = 0; i < n - p; i++)
729         data[n+shift-i-1] = data[n-i-1];
730       n = n + shift;
732       /* Write in the new registers */
733       for (i = 0; i < nRegs; i++)  {
734         write16bit ((regConfig[i].addr >> 16) & 0xffff, data, &p);
735         write16bit ((regConfig[i].value >> 16) & 0xffff, data, &p);
736         write16bit (0, data, &p);
737         write16bit ((regConfig[i].delay >> 16) & 0xffff, data, &p);
739         write16bit (regConfig[i].addr & 0xffff, data, &p);
740         write16bit (regConfig[i].value & 0xffff, data, &p);
741         if (regConfig[i].delay)
742           write16bit (1, data, &p);
743         else
744           write16bit (0, data, &p);
745         write16bit (regConfig[i].delay & 0xffff, data, &p);
746       }
747     
748     }
750   }   else  {
753     /* If there is no I/O section desired in the output, strip out the I/O
754      * section entirely */
755     v = value32bit (endian, data, n, &p, &errflag);
756     if (errflag)  {
757       showErr (errflag);
758       return(-1);
759     }
761     /* back up in the array and remove the I/O configuration */
762     p = p - 4;
763     n = n - 4 - (v*8);
764     for (i = p; i < n; i++)
765       data[i] = data[i+4+(v*8)];
767   }
768     
770   /* The sections */
771   do  {
772   
773     /* Get the section byte count */   
774     v = value32bit (endian, data, n, &p, &errflag);
775     if (errflag)  {
776       showErr (errflag);
777       return(-1);
778     }
780     if (v)  {
781       /* Convert the start address */
782       value32bit (endian, data, n, &p, &errflag);
783       if (errflag)  {
784         showErr (errflag);
785         return(-1);
786       }
787     }
789     /* Convert the data to big endian format  */
790     for (i = 0; i < v; i += 4)  {
791       data32bit (endian, data, n, &p, v-i, &errflag);
792       if (errflag)  {
793         showErr (errflag);
794         return (-1);
795       }
796     }
799     /* Data does not need a conversion for either endian mode. However,
800      * if the length of the section is odd, then there will be one
801      * extra byte of padd that must be maintained */
802     if (v & 1)  {
803       data[p] = 0;
804       p = p + 1;
805     }
807   } while (v);
809   /*  Write out the data file */
810   writeBFile (fout, data, n);
812   /* Return resources */
813   free (data);
815   return (0); 
818     
825