| 1 | /* BFD back-end for verilog hex memory dump files. |
| 2 | Copyright 2009, 2010, 2011 |
| 3 | Free Software Foundation, Inc. |
| 4 | Written by Anthony Green <green@moxielogic.com> |
| 5 | |
| 6 | This file is part of BFD, the Binary File Descriptor library. |
| 7 | |
| 8 | This program is free software; you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation; either version 3 of the License, or |
| 11 | (at your option) any later version. |
| 12 | |
| 13 | This program is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with this program; if not, write to the Free Software |
| 20 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| 21 | MA 02110-1301, USA. */ |
| 22 | |
| 23 | |
| 24 | /* SUBSECTION |
| 25 | Verilog hex memory file handling |
| 26 | |
| 27 | DESCRIPTION |
| 28 | |
| 29 | Verilog hex memory files cannot hold anything but addresses |
| 30 | and data, so that's all that we implement. |
| 31 | |
| 32 | The syntax of the text file is described in the IEEE standard |
| 33 | for Verilog. Briefly, the file contains two types of tokens: |
| 34 | data and optional addresses. The tokens are separated by |
| 35 | whitespace and comments. Comments may be single line or |
| 36 | multiline, using syntax similar to C++. Addresses are |
| 37 | specified by a leading "at" character (@) and are always |
| 38 | hexadecimal strings. Data and addresses may contain |
| 39 | underscore (_) characters. |
| 40 | |
| 41 | If no address is specified, the data is assumed to start at |
| 42 | address 0. Similarly, if data exists before the first |
| 43 | specified address, then that data is assumed to start at |
| 44 | address 0. |
| 45 | |
| 46 | |
| 47 | EXAMPLE |
| 48 | @1000 |
| 49 | 01 ae 3f 45 12 |
| 50 | |
| 51 | DESCRIPTION |
| 52 | @1000 specifies the starting address for the memory data. |
| 53 | The following characters describe the 5 bytes at 0x1000. */ |
| 54 | |
| 55 | |
| 56 | #include "sysdep.h" |
| 57 | #include "bfd.h" |
| 58 | #include "libbfd.h" |
| 59 | #include "libiberty.h" |
| 60 | #include "safe-ctype.h" |
| 61 | |
| 62 | /* Macros for converting between hex and binary. */ |
| 63 | |
| 64 | static const char digs[] = "0123456789ABCDEF"; |
| 65 | |
| 66 | #define NIBBLE(x) hex_value(x) |
| 67 | #define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1])) |
| 68 | #define TOHEX(d, x) \ |
| 69 | d[1] = digs[(x) & 0xf]; \ |
| 70 | d[0] = digs[((x) >> 4) & 0xf]; |
| 71 | |
| 72 | /* When writing a verilog memory dump file, we write them in the order |
| 73 | in which they appear in memory. This structure is used to hold them |
| 74 | in memory. */ |
| 75 | |
| 76 | struct verilog_data_list_struct |
| 77 | { |
| 78 | struct verilog_data_list_struct *next; |
| 79 | bfd_byte * data; |
| 80 | bfd_vma where; |
| 81 | bfd_size_type size; |
| 82 | }; |
| 83 | |
| 84 | typedef struct verilog_data_list_struct verilog_data_list_type; |
| 85 | |
| 86 | /* The verilog tdata information. */ |
| 87 | |
| 88 | typedef struct verilog_data_struct |
| 89 | { |
| 90 | verilog_data_list_type *head; |
| 91 | verilog_data_list_type *tail; |
| 92 | } |
| 93 | tdata_type; |
| 94 | |
| 95 | static bfd_boolean |
| 96 | verilog_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach) |
| 97 | { |
| 98 | if (arch != bfd_arch_unknown) |
| 99 | return bfd_default_set_arch_mach (abfd, arch, mach); |
| 100 | |
| 101 | abfd->arch_info = & bfd_default_arch_struct; |
| 102 | return TRUE; |
| 103 | } |
| 104 | |
| 105 | /* We have to save up all the outpu for a splurge before output. */ |
| 106 | |
| 107 | static bfd_boolean |
| 108 | verilog_set_section_contents (bfd *abfd, |
| 109 | sec_ptr section, |
| 110 | const void * location, |
| 111 | file_ptr offset, |
| 112 | bfd_size_type bytes_to_do) |
| 113 | { |
| 114 | tdata_type *tdata = abfd->tdata.verilog_data; |
| 115 | verilog_data_list_type *entry; |
| 116 | |
| 117 | entry = (verilog_data_list_type *) bfd_alloc (abfd, sizeof (* entry)); |
| 118 | if (entry == NULL) |
| 119 | return FALSE; |
| 120 | |
| 121 | if (bytes_to_do |
| 122 | && (section->flags & SEC_ALLOC) |
| 123 | && (section->flags & SEC_LOAD)) |
| 124 | { |
| 125 | bfd_byte *data; |
| 126 | |
| 127 | data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); |
| 128 | if (data == NULL) |
| 129 | return FALSE; |
| 130 | memcpy ((void *) data, location, (size_t) bytes_to_do); |
| 131 | |
| 132 | entry->data = data; |
| 133 | entry->where = section->lma + offset; |
| 134 | entry->size = bytes_to_do; |
| 135 | |
| 136 | /* Sort the records by address. Optimize for the common case of |
| 137 | adding a record to the end of the list. */ |
| 138 | if (tdata->tail != NULL |
| 139 | && entry->where >= tdata->tail->where) |
| 140 | { |
| 141 | tdata->tail->next = entry; |
| 142 | entry->next = NULL; |
| 143 | tdata->tail = entry; |
| 144 | } |
| 145 | else |
| 146 | { |
| 147 | verilog_data_list_type **look; |
| 148 | |
| 149 | for (look = &tdata->head; |
| 150 | *look != NULL && (*look)->where < entry->where; |
| 151 | look = &(*look)->next) |
| 152 | ; |
| 153 | entry->next = *look; |
| 154 | *look = entry; |
| 155 | if (entry->next == NULL) |
| 156 | tdata->tail = entry; |
| 157 | } |
| 158 | } |
| 159 | return TRUE; |
| 160 | } |
| 161 | |
| 162 | static bfd_boolean |
| 163 | verilog_write_address (bfd *abfd, bfd_vma address) |
| 164 | { |
| 165 | char buffer[12]; |
| 166 | char *dst = buffer; |
| 167 | bfd_size_type wrlen; |
| 168 | |
| 169 | /* Write the address. */ |
| 170 | *dst++ = '@'; |
| 171 | TOHEX (dst, (address >> 24)); |
| 172 | dst += 2; |
| 173 | TOHEX (dst, (address >> 16)); |
| 174 | dst += 2; |
| 175 | TOHEX (dst, (address >> 8)); |
| 176 | dst += 2; |
| 177 | TOHEX (dst, (address)); |
| 178 | dst += 2; |
| 179 | *dst++ = '\r'; |
| 180 | *dst++ = '\n'; |
| 181 | wrlen = dst - buffer; |
| 182 | |
| 183 | return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; |
| 184 | } |
| 185 | |
| 186 | /* Write a record of type, of the supplied number of bytes. The |
| 187 | supplied bytes and length don't have a checksum. That's worked out |
| 188 | here. */ |
| 189 | |
| 190 | static bfd_boolean |
| 191 | verilog_write_record (bfd *abfd, |
| 192 | const bfd_byte *data, |
| 193 | const bfd_byte *end) |
| 194 | { |
| 195 | char buffer[48]; |
| 196 | const bfd_byte *src = data; |
| 197 | char *dst = buffer; |
| 198 | bfd_size_type wrlen; |
| 199 | |
| 200 | /* Write the data. */ |
| 201 | for (src = data; src < end; src++) |
| 202 | { |
| 203 | TOHEX (dst, *src); |
| 204 | dst += 2; |
| 205 | *dst++ = ' '; |
| 206 | } |
| 207 | *dst++ = '\r'; |
| 208 | *dst++ = '\n'; |
| 209 | wrlen = dst - buffer; |
| 210 | |
| 211 | return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; |
| 212 | } |
| 213 | |
| 214 | static bfd_boolean |
| 215 | verilog_write_section (bfd *abfd, |
| 216 | tdata_type *tdata ATTRIBUTE_UNUSED, |
| 217 | verilog_data_list_type *list) |
| 218 | { |
| 219 | unsigned int octets_written = 0; |
| 220 | bfd_byte *location = list->data; |
| 221 | |
| 222 | verilog_write_address (abfd, list->where); |
| 223 | while (octets_written < list->size) |
| 224 | { |
| 225 | unsigned int octets_this_chunk = list->size - octets_written; |
| 226 | |
| 227 | if (octets_this_chunk > 16) |
| 228 | octets_this_chunk = 16; |
| 229 | |
| 230 | if (! verilog_write_record (abfd, |
| 231 | location, |
| 232 | location + octets_this_chunk)) |
| 233 | return FALSE; |
| 234 | |
| 235 | octets_written += octets_this_chunk; |
| 236 | location += octets_this_chunk; |
| 237 | } |
| 238 | |
| 239 | return TRUE; |
| 240 | } |
| 241 | |
| 242 | static bfd_boolean |
| 243 | verilog_write_object_contents (bfd *abfd) |
| 244 | { |
| 245 | tdata_type *tdata = abfd->tdata.verilog_data; |
| 246 | verilog_data_list_type *list; |
| 247 | |
| 248 | /* Now wander though all the sections provided and output them. */ |
| 249 | list = tdata->head; |
| 250 | |
| 251 | while (list != (verilog_data_list_type *) NULL) |
| 252 | { |
| 253 | if (! verilog_write_section (abfd, tdata, list)) |
| 254 | return FALSE; |
| 255 | list = list->next; |
| 256 | } |
| 257 | return TRUE; |
| 258 | } |
| 259 | |
| 260 | /* Initialize by filling in the hex conversion array. */ |
| 261 | |
| 262 | static void |
| 263 | verilog_init (void) |
| 264 | { |
| 265 | static bfd_boolean inited = FALSE; |
| 266 | |
| 267 | if (! inited) |
| 268 | { |
| 269 | inited = TRUE; |
| 270 | hex_init (); |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | /* Set up the verilog tdata information. */ |
| 275 | |
| 276 | static bfd_boolean |
| 277 | verilog_mkobject (bfd *abfd) |
| 278 | { |
| 279 | tdata_type *tdata; |
| 280 | |
| 281 | verilog_init (); |
| 282 | |
| 283 | tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); |
| 284 | if (tdata == NULL) |
| 285 | return FALSE; |
| 286 | |
| 287 | abfd->tdata.verilog_data = tdata; |
| 288 | tdata->head = NULL; |
| 289 | tdata->tail = NULL; |
| 290 | |
| 291 | return TRUE; |
| 292 | } |
| 293 | |
| 294 | #define verilog_close_and_cleanup _bfd_generic_close_and_cleanup |
| 295 | #define verilog_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
| 296 | #define verilog_new_section_hook _bfd_generic_new_section_hook |
| 297 | #define verilog_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
| 298 | #define verilog_bfd_is_local_label_name bfd_generic_is_local_label_name |
| 299 | #define verilog_get_lineno _bfd_nosymbols_get_lineno |
| 300 | #define verilog_find_nearest_line _bfd_nosymbols_find_nearest_line |
| 301 | #define verilog_find_inliner_info _bfd_nosymbols_find_inliner_info |
| 302 | #define verilog_make_empty_symbol _bfd_generic_make_empty_symbol |
| 303 | #define verilog_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
| 304 | #define verilog_read_minisymbols _bfd_generic_read_minisymbols |
| 305 | #define verilog_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
| 306 | #define verilog_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
| 307 | #define verilog_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
| 308 | #define verilog_bfd_relax_section bfd_generic_relax_section |
| 309 | #define verilog_bfd_gc_sections bfd_generic_gc_sections |
| 310 | #define verilog_bfd_merge_sections bfd_generic_merge_sections |
| 311 | #define verilog_bfd_is_group_section bfd_generic_is_group_section |
| 312 | #define verilog_bfd_discard_group bfd_generic_discard_group |
| 313 | #define verilog_section_already_linked _bfd_generic_section_already_linked |
| 314 | #define verilog_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
| 315 | #define verilog_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
| 316 | #define verilog_bfd_link_add_symbols _bfd_generic_link_add_symbols |
| 317 | #define verilog_bfd_link_just_syms _bfd_generic_link_just_syms |
| 318 | #define verilog_bfd_final_link _bfd_generic_final_link |
| 319 | #define verilog_bfd_link_split_section _bfd_generic_link_split_section |
| 320 | |
| 321 | const bfd_target verilog_vec = |
| 322 | { |
| 323 | "verilog", /* Name. */ |
| 324 | bfd_target_verilog_flavour, |
| 325 | BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
| 326 | BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
| 327 | (HAS_RELOC | EXEC_P | /* Object flags. */ |
| 328 | HAS_LINENO | HAS_DEBUG | |
| 329 | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
| 330 | (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
| 331 | | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
| 332 | 0, /* Leading underscore. */ |
| 333 | ' ', /* AR_pad_char. */ |
| 334 | 16, /* AR_max_namelen. */ |
| 335 | 0, /* match priority. */ |
| 336 | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
| 337 | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
| 338 | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
| 339 | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
| 340 | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
| 341 | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs. */ |
| 342 | |
| 343 | { |
| 344 | _bfd_dummy_target, |
| 345 | _bfd_dummy_target, |
| 346 | _bfd_dummy_target, |
| 347 | _bfd_dummy_target, |
| 348 | }, |
| 349 | { |
| 350 | bfd_false, |
| 351 | verilog_mkobject, |
| 352 | bfd_false, |
| 353 | bfd_false, |
| 354 | }, |
| 355 | { /* bfd_write_contents. */ |
| 356 | bfd_false, |
| 357 | verilog_write_object_contents, |
| 358 | bfd_false, |
| 359 | bfd_false, |
| 360 | }, |
| 361 | |
| 362 | BFD_JUMP_TABLE_GENERIC (_bfd_generic), |
| 363 | BFD_JUMP_TABLE_COPY (_bfd_generic), |
| 364 | BFD_JUMP_TABLE_CORE (_bfd_nocore), |
| 365 | BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
| 366 | BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), |
| 367 | BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
| 368 | BFD_JUMP_TABLE_WRITE (verilog), |
| 369 | BFD_JUMP_TABLE_LINK (_bfd_nolink), |
| 370 | BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
| 371 | |
| 372 | NULL, |
| 373 | |
| 374 | NULL |
| 375 | }; |