/src/binutils-gdb/bfd/verilog.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* BFD back-end for verilog hex memory dump files. |
2 | | Copyright (C) 2009-2025 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 | 0 | d[1] = digs[(x) & 0xf]; \ |
77 | 0 | 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 | 0 | { |
105 | 0 | if (arch != bfd_arch_unknown) |
106 | 0 | return bfd_default_set_arch_mach (abfd, arch, mach); |
107 | | |
108 | 0 | abfd->arch_info = & bfd_default_arch_struct; |
109 | 0 | return true; |
110 | 0 | } |
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 | 0 | { |
121 | 0 | tdata_type *tdata = abfd->tdata.verilog_data; |
122 | 0 | verilog_data_list_type *entry; |
123 | |
|
124 | 0 | entry = (verilog_data_list_type *) bfd_alloc (abfd, sizeof (* entry)); |
125 | 0 | if (entry == NULL) |
126 | 0 | return false; |
127 | | |
128 | 0 | if (bytes_to_do |
129 | 0 | && (section->flags & SEC_ALLOC) |
130 | 0 | && (section->flags & SEC_LOAD)) |
131 | 0 | { |
132 | 0 | bfd_byte *data; |
133 | |
|
134 | 0 | data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); |
135 | 0 | if (data == NULL) |
136 | 0 | return false; |
137 | 0 | memcpy ((void *) data, location, (size_t) bytes_to_do); |
138 | |
|
139 | 0 | entry->data = data; |
140 | 0 | entry->where = section->lma + offset; |
141 | 0 | 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 | 0 | if (tdata->tail != NULL |
146 | 0 | && entry->where >= tdata->tail->where) |
147 | 0 | { |
148 | 0 | tdata->tail->next = entry; |
149 | 0 | entry->next = NULL; |
150 | 0 | tdata->tail = entry; |
151 | 0 | } |
152 | 0 | else |
153 | 0 | { |
154 | 0 | verilog_data_list_type **look; |
155 | |
|
156 | 0 | for (look = &tdata->head; |
157 | 0 | *look != NULL && (*look)->where < entry->where; |
158 | 0 | look = &(*look)->next) |
159 | 0 | ; |
160 | 0 | entry->next = *look; |
161 | 0 | *look = entry; |
162 | 0 | if (entry->next == NULL) |
163 | 0 | tdata->tail = entry; |
164 | 0 | } |
165 | 0 | } |
166 | 0 | return true; |
167 | 0 | } |
168 | | |
169 | | static bool |
170 | | verilog_write_address (bfd *abfd, bfd_vma address) |
171 | 0 | { |
172 | 0 | char buffer[20]; |
173 | 0 | char *dst = buffer; |
174 | 0 | bfd_size_type wrlen; |
175 | | |
176 | | /* Write the address. */ |
177 | 0 | *dst++ = '@'; |
178 | 0 | #ifdef BFD64 |
179 | 0 | if (address >= (bfd_vma)1 << 32) |
180 | 0 | { |
181 | 0 | TOHEX (dst, (address >> 56)); |
182 | 0 | dst += 2; |
183 | 0 | TOHEX (dst, (address >> 48)); |
184 | 0 | dst += 2; |
185 | 0 | TOHEX (dst, (address >> 40)); |
186 | 0 | dst += 2; |
187 | 0 | TOHEX (dst, (address >> 32)); |
188 | 0 | dst += 2; |
189 | 0 | } |
190 | 0 | #endif |
191 | 0 | TOHEX (dst, (address >> 24)); |
192 | 0 | dst += 2; |
193 | 0 | TOHEX (dst, (address >> 16)); |
194 | 0 | dst += 2; |
195 | 0 | TOHEX (dst, (address >> 8)); |
196 | 0 | dst += 2; |
197 | 0 | TOHEX (dst, (address)); |
198 | 0 | dst += 2; |
199 | 0 | *dst++ = '\r'; |
200 | 0 | *dst++ = '\n'; |
201 | 0 | wrlen = dst - buffer; |
202 | |
|
203 | 0 | return bfd_write (buffer, wrlen, abfd) == wrlen; |
204 | 0 | } |
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 | 0 | { |
215 | 0 | char buffer[52]; |
216 | 0 | const bfd_byte *src = data; |
217 | 0 | char *dst = buffer; |
218 | 0 | bfd_size_type wrlen; |
219 | | |
220 | | /* Paranoia - check that we will not overflow "buffer". */ |
221 | 0 | if (((end - data) * 2) /* Number of hex characters we want to emit. */ |
222 | 0 | + ((end - data) / VerilogDataWidth) /* Number of spaces we want to emit. */ |
223 | 0 | + 2 /* The carriage return & line feed characters. */ |
224 | 0 | > (long) sizeof (buffer)) |
225 | 0 | { |
226 | | /* FIXME: Should we generate an error message ? */ |
227 | 0 | return false; |
228 | 0 | } |
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 | 0 | if (VerilogDataWidth == 1) |
235 | 0 | { |
236 | 0 | for (src = data; src < end;) |
237 | 0 | { |
238 | 0 | TOHEX (dst, *src); |
239 | 0 | dst += 2; |
240 | 0 | src ++; |
241 | 0 | if (src < end) |
242 | 0 | *dst++ = ' '; |
243 | 0 | } |
244 | 0 | } |
245 | 0 | else if ((VerilogDataEndianness == BFD_ENDIAN_UNKNOWN && bfd_little_endian (abfd)) /* FIXME: Can this happen ? */ |
246 | 0 | || (VerilogDataEndianness == BFD_ENDIAN_LITTLE)) |
247 | 0 | { |
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 | 0 | int i; |
253 | |
|
254 | 0 | for (src = data; src < (end - VerilogDataWidth); src += VerilogDataWidth) |
255 | 0 | { |
256 | 0 | for (i = VerilogDataWidth - 1; i >= 0; i--) |
257 | 0 | { |
258 | 0 | TOHEX (dst, src[i]); |
259 | 0 | dst += 2; |
260 | 0 | } |
261 | 0 | *dst++ = ' '; |
262 | 0 | } |
263 | | |
264 | | /* Emit any remaining bytes. Be careful not to read beyond "end". */ |
265 | 0 | while (end > src) |
266 | 0 | { |
267 | 0 | -- end; |
268 | 0 | TOHEX (dst, *end); |
269 | 0 | dst += 2; |
270 | 0 | } |
271 | | |
272 | | /* FIXME: Should padding bytes be inserted here ? */ |
273 | 0 | } |
274 | 0 | else /* Big endian output. */ |
275 | 0 | { |
276 | 0 | for (src = data; src < end;) |
277 | 0 | { |
278 | 0 | TOHEX (dst, *src); |
279 | 0 | dst += 2; |
280 | 0 | ++ src; |
281 | 0 | if ((src - data) % VerilogDataWidth == 0) |
282 | 0 | *dst++ = ' '; |
283 | 0 | } |
284 | | /* FIXME: Should padding bytes be inserted here ? */ |
285 | 0 | } |
286 | |
|
287 | 0 | *dst++ = '\r'; |
288 | 0 | *dst++ = '\n'; |
289 | 0 | wrlen = dst - buffer; |
290 | |
|
291 | 0 | return bfd_write (buffer, wrlen, abfd) == wrlen; |
292 | 0 | } |
293 | | |
294 | | static bool |
295 | | verilog_write_section (bfd *abfd, |
296 | | tdata_type *tdata ATTRIBUTE_UNUSED, |
297 | | verilog_data_list_type *list) |
298 | 0 | { |
299 | 0 | unsigned int octets_written = 0; |
300 | 0 | bfd_byte *location = list->data; |
301 | | |
302 | | /* Insist that the starting address is a multiple of the data width. */ |
303 | 0 | if (list->where % VerilogDataWidth) |
304 | 0 | { |
305 | 0 | bfd_set_error (bfd_error_invalid_operation); |
306 | 0 | return false; |
307 | 0 | } |
308 | | |
309 | 0 | verilog_write_address (abfd, list->where / VerilogDataWidth); |
310 | 0 | while (octets_written < list->size) |
311 | 0 | { |
312 | 0 | unsigned int octets_this_chunk = list->size - octets_written; |
313 | |
|
314 | 0 | if (octets_this_chunk > 16) |
315 | 0 | octets_this_chunk = 16; |
316 | |
|
317 | 0 | if (! verilog_write_record (abfd, |
318 | 0 | location, |
319 | 0 | location + octets_this_chunk)) |
320 | 0 | return false; |
321 | | |
322 | 0 | octets_written += octets_this_chunk; |
323 | 0 | location += octets_this_chunk; |
324 | 0 | } |
325 | | |
326 | 0 | return true; |
327 | 0 | } |
328 | | |
329 | | static bool |
330 | | verilog_write_object_contents (bfd *abfd) |
331 | 0 | { |
332 | 0 | tdata_type *tdata = abfd->tdata.verilog_data; |
333 | 0 | verilog_data_list_type *list; |
334 | | |
335 | | /* Now wander though all the sections provided and output them. */ |
336 | 0 | list = tdata->head; |
337 | |
|
338 | 0 | while (list != (verilog_data_list_type *) NULL) |
339 | 0 | { |
340 | 0 | if (! verilog_write_section (abfd, tdata, list)) |
341 | 0 | return false; |
342 | 0 | list = list->next; |
343 | 0 | } |
344 | 0 | return true; |
345 | 0 | } |
346 | | |
347 | | /* Initialize by filling in the hex conversion array. */ |
348 | | |
349 | | static void |
350 | | verilog_init (void) |
351 | 0 | { |
352 | 0 | static bool inited = false; |
353 | |
|
354 | 0 | if (! inited) |
355 | 0 | { |
356 | 0 | inited = true; |
357 | 0 | hex_init (); |
358 | 0 | } |
359 | 0 | } |
360 | | |
361 | | /* Set up the verilog tdata information. */ |
362 | | |
363 | | static bool |
364 | | verilog_mkobject (bfd *abfd) |
365 | 0 | { |
366 | 0 | tdata_type *tdata; |
367 | |
|
368 | 0 | verilog_init (); |
369 | |
|
370 | 0 | tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); |
371 | 0 | if (tdata == NULL) |
372 | 0 | return false; |
373 | | |
374 | 0 | abfd->tdata.verilog_data = tdata; |
375 | 0 | tdata->head = NULL; |
376 | 0 | tdata->tail = NULL; |
377 | |
|
378 | 0 | return true; |
379 | 0 | } |
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 | | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
396 | | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
397 | | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
398 | | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
399 | | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
400 | | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs. */ |
401 | | |
402 | | { |
403 | | _bfd_dummy_target, |
404 | | _bfd_dummy_target, |
405 | | _bfd_dummy_target, |
406 | | _bfd_dummy_target, |
407 | | }, |
408 | | { |
409 | | _bfd_bool_bfd_false_error, |
410 | | verilog_mkobject, |
411 | | _bfd_bool_bfd_false_error, |
412 | | _bfd_bool_bfd_false_error, |
413 | | }, |
414 | | { /* bfd_write_contents. */ |
415 | | _bfd_bool_bfd_false_error, |
416 | | verilog_write_object_contents, |
417 | | _bfd_bool_bfd_false_error, |
418 | | _bfd_bool_bfd_false_error, |
419 | | }, |
420 | | |
421 | | BFD_JUMP_TABLE_GENERIC (_bfd_generic), |
422 | | BFD_JUMP_TABLE_COPY (_bfd_generic), |
423 | | BFD_JUMP_TABLE_CORE (_bfd_nocore), |
424 | | BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
425 | | BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), |
426 | | BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
427 | | BFD_JUMP_TABLE_WRITE (verilog), |
428 | | BFD_JUMP_TABLE_LINK (_bfd_nolink), |
429 | | BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
430 | | |
431 | | NULL, |
432 | | |
433 | | NULL |
434 | | }; |