xref: /netbsd-src/external/gpl3/binutils/dist/bfd/verilog.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* BFD back-end for verilog hex memory dump files.
2    Copyright (C) 2009-2024 Free Software Foundation, Inc.
3    Written by Anthony Green <green@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
verilog_set_arch_mach(bfd * abfd,enum bfd_architecture arch,unsigned long mach)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
verilog_set_section_contents(bfd * abfd,sec_ptr section,const void * location,file_ptr offset,bfd_size_type bytes_to_do)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
verilog_write_address(bfd * abfd,bfd_vma address)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
verilog_write_record(bfd * abfd,const bfd_byte * data,const bfd_byte * end)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
verilog_write_section(bfd * abfd,tdata_type * tdata ATTRIBUTE_UNUSED,verilog_data_list_type * list)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
verilog_write_object_contents(bfd * abfd)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
verilog_init(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
verilog_mkobject(bfd * abfd)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 #define verilog_close_and_cleanup		     _bfd_generic_close_and_cleanup
382 #define verilog_bfd_free_cached_info		     _bfd_generic_bfd_free_cached_info
383 #define verilog_new_section_hook		     _bfd_generic_new_section_hook
384 #define verilog_bfd_is_target_special_symbol	     _bfd_bool_bfd_asymbol_false
385 #define verilog_bfd_is_local_label_name		     bfd_generic_is_local_label_name
386 #define verilog_get_lineno			     _bfd_nosymbols_get_lineno
387 #define verilog_find_nearest_line		     _bfd_nosymbols_find_nearest_line
388 #define verilog_find_nearest_line_with_alt	     _bfd_nosymbols_find_nearest_line_with_alt
389 #define verilog_find_inliner_info		     _bfd_nosymbols_find_inliner_info
390 #define verilog_make_empty_symbol		     _bfd_generic_make_empty_symbol
391 #define verilog_bfd_make_debug_symbol		     _bfd_nosymbols_bfd_make_debug_symbol
392 #define verilog_read_minisymbols		     _bfd_generic_read_minisymbols
393 #define verilog_minisymbol_to_symbol		     _bfd_generic_minisymbol_to_symbol
394 #define verilog_get_section_contents_in_window	     _bfd_generic_get_section_contents_in_window
395 #define verilog_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
396 #define verilog_bfd_relax_section		     bfd_generic_relax_section
397 #define verilog_bfd_gc_sections			     bfd_generic_gc_sections
398 #define verilog_bfd_merge_sections		     bfd_generic_merge_sections
399 #define verilog_bfd_is_group_section		     bfd_generic_is_group_section
400 #define verilog_bfd_group_name			     bfd_generic_group_name
401 #define verilog_bfd_discard_group		     bfd_generic_discard_group
402 #define verilog_section_already_linked		     _bfd_generic_section_already_linked
403 #define verilog_bfd_link_hash_table_create	     _bfd_generic_link_hash_table_create
404 #define verilog_bfd_link_add_symbols		     _bfd_generic_link_add_symbols
405 #define verilog_bfd_link_just_syms		     _bfd_generic_link_just_syms
406 #define verilog_bfd_final_link			     _bfd_generic_final_link
407 #define verilog_bfd_link_split_section		     _bfd_generic_link_split_section
408 
409 const bfd_target verilog_vec =
410 {
411   "verilog",			/* Name.  */
412   bfd_target_verilog_flavour,
413   BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
414   BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
415   (HAS_RELOC | EXEC_P |		/* Object flags.  */
416    HAS_LINENO | HAS_DEBUG |
417    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
418   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
419    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
420   0,				/* Leading underscore.  */
421   ' ',				/* AR_pad_char.  */
422   16,				/* AR_max_namelen.  */
423   0,				/* match priority.  */
424   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
425   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
426   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
427   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
428   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
429   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
430   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Hdrs.  */
431 
432   {
433     _bfd_dummy_target,
434     _bfd_dummy_target,
435     _bfd_dummy_target,
436     _bfd_dummy_target,
437   },
438   {
439     _bfd_bool_bfd_false_error,
440     verilog_mkobject,
441     _bfd_bool_bfd_false_error,
442     _bfd_bool_bfd_false_error,
443   },
444   {				/* bfd_write_contents.  */
445     _bfd_bool_bfd_false_error,
446     verilog_write_object_contents,
447     _bfd_bool_bfd_false_error,
448     _bfd_bool_bfd_false_error,
449   },
450 
451   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
452   BFD_JUMP_TABLE_COPY (_bfd_generic),
453   BFD_JUMP_TABLE_CORE (_bfd_nocore),
454   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
455   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
456   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
457   BFD_JUMP_TABLE_WRITE (verilog),
458   BFD_JUMP_TABLE_LINK (_bfd_nolink),
459   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
460 
461   NULL,
462 
463   NULL
464 };
465