Home | History | Annotate | Line # | Download | only in bfd
verilog.c revision 1.1.1.11
      1 /* BFD back-end for verilog hex memory dump files.
      2    Copyright (C) 2009-2026 Free Software Foundation, Inc.
      3    Written by Anthony Green <green (at) moxielogic.com>
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 
     23 /* SUBSECTION
     24 	Verilog hex memory file handling
     25 
     26    DESCRIPTION
     27 
     28 	Verilog hex memory files cannot hold anything but addresses
     29 	and data, so that's all that we implement.
     30 
     31 	The syntax of the text file is described in the IEEE standard
     32 	for Verilog.  Briefly, the file contains two types of tokens:
     33 	data and optional addresses.  The tokens are separated by
     34 	whitespace and comments.  Comments may be single line or
     35 	multiline, using syntax similar to C++.  Addresses are
     36 	specified by a leading "at" character (@) and are always
     37 	hexadecimal strings.  Data and addresses may contain
     38 	underscore (_) characters.
     39 
     40 	If no address is specified, the data is assumed to start at
     41 	address 0.  Similarly, if data exists before the first
     42 	specified address, then that data is assumed to start at
     43 	address 0.
     44 
     45 
     46    EXAMPLE
     47 	@1000
     48 	01 ae 3f 45 12
     49 
     50    DESCRIPTION
     51 	@1000 specifies the starting address for the memory data.
     52 	The following characters describe the 5 bytes at 0x1000.  */
     53 
     54 
     55 #include "sysdep.h"
     56 #include "bfd.h"
     57 #include "libbfd.h"
     58 #include "libiberty.h"
     59 #include "safe-ctype.h"
     60 
     61 /* Modified by obcopy.c
     62    Data width in bytes.  */
     63 unsigned int VerilogDataWidth = 1;
     64 
     65 /* Modified by obcopy.c
     66    Data endianness.  */
     67 enum bfd_endian VerilogDataEndianness = BFD_ENDIAN_UNKNOWN;
     68 
     69 /* Macros for converting between hex and binary.  */
     70 
     71 static const char digs[] = "0123456789ABCDEF";
     72 
     73 #define NIBBLE(x)    hex_value (x)
     74 #define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1]))
     75 #define TOHEX(d, x) \
     76 	d[1] = digs[(x) & 0xf]; \
     77 	d[0] = digs[((x) >> 4) & 0xf];
     78 
     79 /* When writing a verilog memory dump file, we write them in the order
     80    in which they appear in memory. This structure is used to hold them
     81    in memory.  */
     82 
     83 struct verilog_data_list_struct
     84 {
     85   struct verilog_data_list_struct *next;
     86   bfd_byte * data;
     87   bfd_vma where;
     88   bfd_size_type size;
     89 };
     90 
     91 typedef struct verilog_data_list_struct verilog_data_list_type;
     92 
     93 /* The verilog tdata information.  */
     94 
     95 typedef struct verilog_data_struct
     96 {
     97   verilog_data_list_type *head;
     98   verilog_data_list_type *tail;
     99 }
    100 tdata_type;
    101 
    102 static bool
    103 verilog_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach)
    104 {
    105   if (arch != bfd_arch_unknown)
    106     return bfd_default_set_arch_mach (abfd, arch, mach);
    107 
    108   abfd->arch_info = & bfd_default_arch_struct;
    109   return true;
    110 }
    111 
    112 /* We have to save up all the output for a splurge before output.  */
    113 
    114 static bool
    115 verilog_set_section_contents (bfd *abfd,
    116 			      sec_ptr section,
    117 			      const void * location,
    118 			      file_ptr offset,
    119 			      bfd_size_type bytes_to_do)
    120 {
    121   tdata_type *tdata = abfd->tdata.verilog_data;
    122   verilog_data_list_type *entry;
    123 
    124   entry = (verilog_data_list_type *) bfd_alloc (abfd, sizeof (* entry));
    125   if (entry == NULL)
    126     return false;
    127 
    128   if (bytes_to_do
    129       && (section->flags & SEC_ALLOC)
    130       && (section->flags & SEC_LOAD))
    131     {
    132       bfd_byte *data;
    133 
    134       data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
    135       if (data == NULL)
    136 	return false;
    137       memcpy ((void *) data, location, (size_t) bytes_to_do);
    138 
    139       entry->data = data;
    140       entry->where = section->lma + offset;
    141       entry->size = bytes_to_do;
    142 
    143       /* Sort the records by address.  Optimize for the common case of
    144 	 adding a record to the end of the list.  */
    145       if (tdata->tail != NULL
    146 	  && entry->where >= tdata->tail->where)
    147 	{
    148 	  tdata->tail->next = entry;
    149 	  entry->next = NULL;
    150 	  tdata->tail = entry;
    151 	}
    152       else
    153 	{
    154 	  verilog_data_list_type **look;
    155 
    156 	  for (look = &tdata->head;
    157 	       *look != NULL && (*look)->where < entry->where;
    158 	       look = &(*look)->next)
    159 	    ;
    160 	  entry->next = *look;
    161 	  *look = entry;
    162 	  if (entry->next == NULL)
    163 	    tdata->tail = entry;
    164 	}
    165     }
    166   return true;
    167 }
    168 
    169 static bool
    170 verilog_write_address (bfd *abfd, bfd_vma address)
    171 {
    172   char buffer[20];
    173   char *dst = buffer;
    174   bfd_size_type wrlen;
    175 
    176   /* Write the address.  */
    177   *dst++ = '@';
    178 #ifdef BFD64
    179   if (address >= (bfd_vma)1 << 32)
    180     {
    181       TOHEX (dst, (address >> 56));
    182       dst += 2;
    183       TOHEX (dst, (address >> 48));
    184       dst += 2;
    185       TOHEX (dst, (address >> 40));
    186       dst += 2;
    187       TOHEX (dst, (address >> 32));
    188       dst += 2;
    189     }
    190 #endif
    191   TOHEX (dst, (address >> 24));
    192   dst += 2;
    193   TOHEX (dst, (address >> 16));
    194   dst += 2;
    195   TOHEX (dst, (address >> 8));
    196   dst += 2;
    197   TOHEX (dst, (address));
    198   dst += 2;
    199   *dst++ = '\r';
    200   *dst++ = '\n';
    201   wrlen = dst - buffer;
    202 
    203   return bfd_write (buffer, wrlen, abfd) == wrlen;
    204 }
    205 
    206 /* Write a record of type, of the supplied number of bytes. The
    207    supplied bytes and length don't have a checksum.  That's worked
    208    out here.  */
    209 
    210 static bool
    211 verilog_write_record (bfd *abfd,
    212 		      const bfd_byte *data,
    213 		      const bfd_byte *end)
    214 {
    215   char buffer[52];
    216   const bfd_byte *src = data;
    217   char *dst = buffer;
    218   bfd_size_type wrlen;
    219 
    220   /* Paranoia - check that we will not overflow "buffer".  */
    221   if (((end - data) * 2) /* Number of hex characters we want to emit.  */
    222       + ((end - data) / VerilogDataWidth) /* Number of spaces we want to emit.  */
    223       + 2 /* The carriage return & line feed characters.  */
    224       > (long) sizeof (buffer))
    225     {
    226       /* FIXME: Should we generate an error message ?  */
    227       return false;
    228     }
    229 
    230   /* Write the data.
    231      FIXME: Under some circumstances we can emit a space at the end of
    232      the line.  This is not really necessary, but catching these cases
    233      would make the code more complicated.  */
    234   if (VerilogDataWidth == 1)
    235     {
    236       for (src = data; src < end;)
    237 	{
    238 	  TOHEX (dst, *src);
    239 	  dst += 2;
    240 	  src ++;
    241 	  if (src < end)
    242 	    *dst++ = ' ';
    243 	}
    244     }
    245   else if ((VerilogDataEndianness == BFD_ENDIAN_UNKNOWN && bfd_little_endian (abfd)) /* FIXME: Can this happen ?  */
    246 	   || (VerilogDataEndianness == BFD_ENDIAN_LITTLE))
    247     {
    248       /* If the input byte stream contains:
    249 	   05 04 03 02 01 00
    250 	 and VerilogDataWidth is 4 then we want to emit:
    251            02030405 0001  */
    252       int i;
    253 
    254       for (src = data; src < (end - VerilogDataWidth); src += VerilogDataWidth)
    255 	{
    256 	  for (i = VerilogDataWidth - 1; i >= 0; i--)
    257 	    {
    258 	      TOHEX (dst, src[i]);
    259 	      dst += 2;
    260 	    }
    261 	  *dst++ = ' ';
    262 	}
    263 
    264       /* Emit any remaining bytes.  Be careful not to read beyond "end".  */
    265       while (end > src)
    266 	{
    267 	  -- end;
    268 	  TOHEX (dst, *end);
    269 	  dst += 2;
    270 	}
    271 
    272       /* FIXME: Should padding bytes be inserted here ?  */
    273     }
    274   else /* Big endian output.  */
    275     {
    276       for (src = data; src < end;)
    277 	{
    278 	  TOHEX (dst, *src);
    279 	  dst += 2;
    280 	  ++ src;
    281 	  if ((src - data) % VerilogDataWidth == 0)
    282 	    *dst++ = ' ';
    283 	}
    284       /* FIXME: Should padding bytes be inserted here ?  */
    285     }
    286 
    287   *dst++ = '\r';
    288   *dst++ = '\n';
    289   wrlen = dst - buffer;
    290 
    291   return bfd_write (buffer, wrlen, abfd) == wrlen;
    292 }
    293 
    294 static bool
    295 verilog_write_section (bfd *abfd,
    296 		       tdata_type *tdata ATTRIBUTE_UNUSED,
    297 		       verilog_data_list_type *list)
    298 {
    299   unsigned int octets_written = 0;
    300   bfd_byte *location = list->data;
    301 
    302   /* Insist that the starting address is a multiple of the data width.  */
    303   if (list->where % VerilogDataWidth)
    304     {
    305       bfd_set_error (bfd_error_invalid_operation);
    306       return false;
    307     }
    308 
    309   verilog_write_address (abfd, list->where / VerilogDataWidth);
    310   while (octets_written < list->size)
    311     {
    312       unsigned int octets_this_chunk = list->size - octets_written;
    313 
    314       if (octets_this_chunk > 16)
    315 	octets_this_chunk = 16;
    316 
    317       if (! verilog_write_record (abfd,
    318 				  location,
    319 				  location + octets_this_chunk))
    320 	return false;
    321 
    322       octets_written += octets_this_chunk;
    323       location += octets_this_chunk;
    324     }
    325 
    326   return true;
    327 }
    328 
    329 static bool
    330 verilog_write_object_contents (bfd *abfd)
    331 {
    332   tdata_type *tdata = abfd->tdata.verilog_data;
    333   verilog_data_list_type *list;
    334 
    335   /* Now wander though all the sections provided and output them.  */
    336   list = tdata->head;
    337 
    338   while (list != (verilog_data_list_type *) NULL)
    339     {
    340       if (! verilog_write_section (abfd, tdata, list))
    341 	return false;
    342       list = list->next;
    343     }
    344   return true;
    345 }
    346 
    347 /* Initialize by filling in the hex conversion array.  */
    348 
    349 static void
    350 verilog_init (void)
    351 {
    352   static bool inited = false;
    353 
    354   if (! inited)
    355     {
    356       inited = true;
    357       hex_init ();
    358     }
    359 }
    360 
    361 /* Set up the verilog tdata information.  */
    362 
    363 static bool
    364 verilog_mkobject (bfd *abfd)
    365 {
    366   tdata_type *tdata;
    367 
    368   verilog_init ();
    369 
    370   tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
    371   if (tdata == NULL)
    372     return false;
    373 
    374   abfd->tdata.verilog_data = tdata;
    375   tdata->head = NULL;
    376   tdata->tail = NULL;
    377 
    378   return true;
    379 }
    380 
    381 const bfd_target verilog_vec =
    382 {
    383   "verilog",			/* Name.  */
    384   bfd_target_verilog_flavour,
    385   BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
    386   BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
    387   EXEC_P,			/* Object flags.  */
    388   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
    389    | SEC_ALLOC | SEC_LOAD),	/* Section flags.  */
    390   0,				/* Leading underscore.  */
    391   ' ',				/* AR_pad_char.  */
    392   16,				/* AR_max_namelen.  */
    393   0,				/* match priority.  */
    394   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
    395   false,			/* merge sections */
    396   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    397   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    398   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
    399   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    400   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    401   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Hdrs.  */
    402 
    403   {
    404     _bfd_dummy_target,
    405     _bfd_dummy_target,
    406     _bfd_dummy_target,
    407     _bfd_dummy_target,
    408   },
    409   {
    410     _bfd_bool_bfd_false_error,
    411     verilog_mkobject,
    412     _bfd_bool_bfd_false_error,
    413     _bfd_bool_bfd_false_error,
    414   },
    415   {				/* bfd_write_contents.  */
    416     _bfd_bool_bfd_false_error,
    417     verilog_write_object_contents,
    418     _bfd_bool_bfd_false_error,
    419     _bfd_bool_bfd_false_error,
    420   },
    421 
    422   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
    423   BFD_JUMP_TABLE_COPY (_bfd_generic),
    424   BFD_JUMP_TABLE_CORE (_bfd_nocore),
    425   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
    426   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
    427   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
    428   BFD_JUMP_TABLE_WRITE (verilog),
    429   BFD_JUMP_TABLE_LINK (_bfd_nolink),
    430   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    431 
    432   NULL,
    433 
    434   NULL
    435 };
    436