diff options
Diffstat (limited to 'bfd/verilog.c')
-rw-r--r-- | bfd/verilog.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/bfd/verilog.c b/bfd/verilog.c new file mode 100644 index 0000000..175e1f0 --- /dev/null +++ b/bfd/verilog.c @@ -0,0 +1,377 @@ +/* BFD back-end for verilog hex memory dump files. + Copyright 2009 + Free Software Foundation, Inc. + Written by Anthony Green <green@moxielogic.com> + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + + +/* SUBSECTION + Verilog hex memory file handling + + DESCRIPTION + + Verilog hex memory files cannot hold anything but addresses + and data, so that's all that we implement. + + The syntax of the text file is described in the IEEE standard + for Verilog. Briefly, the file contains two types of tokens: + data and optional addresses. The tokens are separated by + whitespace and comments. Comments may be single line or + multiline, using syntax similar to C++. Addresses are + specified by a leading "at" character (@) and are always + hexadecimal strings. Data and addresses may contain + underscore (_) characters. + + If no address is specified, the data is assumed to start at + address 0. Similarly, if data exists before the first + specified address, then that data is assumed to start at + address 0. + + + EXAMPLE + @1000 + 01 ae 3f 45 12 + + DESCRIPTION + @1000 specifies the starting address for the memory data. + The following characters describe the 5 bytes at 0x1000. */ + + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "libiberty.h" +#include "safe-ctype.h" + +/* Macros for converting between hex and binary. */ + +static const char digs[] = "0123456789ABCDEF"; + +#define NIBBLE(x) hex_value(x) +#define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1])) +#define TOHEX(d, x) \ + d[1] = digs[(x) & 0xf]; \ + d[0] = digs[((x) >> 4) & 0xf]; + +/* When writing a verilog memory dump file, we write them in the order + in which they appear in memory. This structure is used to hold them + in memory. */ + +struct verilog_data_list_struct +{ + struct verilog_data_list_struct *next; + bfd_byte * data; + bfd_vma where; + bfd_size_type size; +}; + +typedef struct verilog_data_list_struct verilog_data_list_type; + +/* The verilog tdata information. */ + +typedef struct verilog_data_struct +{ + verilog_data_list_type *head; + verilog_data_list_type *tail; +} +tdata_type; + +static bfd_boolean +verilog_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach) +{ + if (arch != bfd_arch_unknown) + return bfd_default_set_arch_mach (abfd, arch, mach); + + abfd->arch_info = & bfd_default_arch_struct; + return TRUE; +} + +/* We have to save up all the outpu for a splurge before output. */ + +static bfd_boolean +verilog_set_section_contents (bfd *abfd, + sec_ptr section, + const void * location, + file_ptr offset, + bfd_size_type bytes_to_do) +{ + tdata_type *tdata = abfd->tdata.verilog_data; + verilog_data_list_type *entry; + + entry = bfd_alloc (abfd, sizeof (* entry)); + if (entry == NULL) + return FALSE; + + if (bytes_to_do + && (section->flags & SEC_ALLOC) + && (section->flags & SEC_LOAD)) + { + bfd_byte *data; + + data = bfd_alloc (abfd, bytes_to_do); + if (data == NULL) + return FALSE; + memcpy ((void *) data, location, (size_t) bytes_to_do); + + entry->data = data; + entry->where = section->lma + offset; + entry->size = bytes_to_do; + + /* Sort the records by address. Optimize for the common case of + adding a record to the end of the list. */ + if (tdata->tail != NULL + && entry->where >= tdata->tail->where) + { + tdata->tail->next = entry; + entry->next = NULL; + tdata->tail = entry; + } + else + { + verilog_data_list_type **look; + + for (look = &tdata->head; + *look != NULL && (*look)->where < entry->where; + look = &(*look)->next) + ; + entry->next = *look; + *look = entry; + if (entry->next == NULL) + tdata->tail = entry; + } + } + return TRUE; +} + +static bfd_boolean +verilog_write_address (bfd *abfd, bfd_vma address) +{ + char buffer[12]; + char *dst = buffer; + bfd_size_type wrlen; + + /* Write the address. */ + *dst++ = '@'; + TOHEX (dst, (address >> 24)); + dst += 2; + TOHEX (dst, (address >> 16)); + dst += 2; + TOHEX (dst, (address >> 8)); + dst += 2; + TOHEX (dst, (address)); + dst += 2; + *dst++ = '\r'; + *dst++ = '\n'; + wrlen = dst - buffer; + + return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; +} + +/* Write a record of type, of the supplied number of bytes. The + supplied bytes and length don't have a checksum. That's worked out + here. */ + +static bfd_boolean +verilog_write_record (bfd *abfd, + const bfd_byte *data, + const bfd_byte *end) +{ + char buffer[48]; + const bfd_byte *src = data; + char *dst = buffer; + bfd_size_type wrlen; + + /* Write the data. */ + for (src = data; src < end; src++) + { + TOHEX (dst, *src); + dst += 2; + *dst++ = ' '; + } + *dst++ = '\r'; + *dst++ = '\n'; + wrlen = dst - buffer; + + return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; +} + +static bfd_boolean +verilog_write_section (bfd *abfd, + tdata_type *tdata ATTRIBUTE_UNUSED, + verilog_data_list_type *list) +{ + unsigned int octets_written = 0; + bfd_byte *location = list->data; + + verilog_write_address (abfd, list->where); + while (octets_written < list->size) + { + bfd_vma address; + unsigned int octets_this_chunk = list->size - octets_written; + + if (octets_this_chunk > 16) + octets_this_chunk = 16; + + address = list->where + octets_written / bfd_octets_per_byte (abfd); + + if (! verilog_write_record (abfd, + location, + location + octets_this_chunk)) + return FALSE; + + octets_written += octets_this_chunk; + location += octets_this_chunk; + } + + return TRUE; +} + +static bfd_boolean +verilog_write_object_contents (bfd *abfd) +{ + tdata_type *tdata = abfd->tdata.verilog_data; + verilog_data_list_type *list; + + /* Now wander though all the sections provided and output them. */ + list = tdata->head; + + while (list != (verilog_data_list_type *) NULL) + { + if (! verilog_write_section (abfd, tdata, list)) + return FALSE; + list = list->next; + } + return TRUE; +} + +/* Initialize by filling in the hex conversion array. */ + +static void +verilog_init (void) +{ + static bfd_boolean inited = FALSE; + + if (! inited) + { + inited = TRUE; + hex_init (); + } +} + +/* Set up the verilog tdata information. */ + +static bfd_boolean +verilog_mkobject (bfd *abfd) +{ + tdata_type *tdata; + + verilog_init (); + + tdata = bfd_alloc (abfd, sizeof (tdata_type)); + if (tdata == NULL) + return FALSE; + + abfd->tdata.verilog_data = tdata; + tdata->head = NULL; + tdata->tail = NULL; + + return TRUE; +} + +#define verilog_close_and_cleanup _bfd_generic_close_and_cleanup +#define verilog_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define verilog_new_section_hook _bfd_generic_new_section_hook +#define verilog_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#define verilog_bfd_is_local_label_name bfd_generic_is_local_label_name +#define verilog_get_lineno _bfd_nosymbols_get_lineno +#define verilog_find_nearest_line _bfd_nosymbols_find_nearest_line +#define verilog_find_inliner_info _bfd_nosymbols_find_inliner_info +#define verilog_make_empty_symbol _bfd_generic_make_empty_symbol +#define verilog_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define verilog_read_minisymbols _bfd_generic_read_minisymbols +#define verilog_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +#define verilog_get_section_contents_in_window _bfd_generic_get_section_contents_in_window +#define verilog_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define verilog_bfd_relax_section bfd_generic_relax_section +#define verilog_bfd_gc_sections bfd_generic_gc_sections +#define verilog_bfd_merge_sections bfd_generic_merge_sections +#define verilog_bfd_is_group_section bfd_generic_is_group_section +#define verilog_bfd_discard_group bfd_generic_discard_group +#define verilog_section_already_linked _bfd_generic_section_already_linked +#define verilog_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define verilog_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#define verilog_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define verilog_bfd_link_just_syms _bfd_generic_link_just_syms +#define verilog_bfd_final_link _bfd_generic_final_link +#define verilog_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target verilog_vec = +{ + "verilog", /* Name. */ + bfd_target_verilog_flavour, + BFD_ENDIAN_UNKNOWN, /* Target byte order. */ + BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ + (HAS_RELOC | EXEC_P | /* Object flags. */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ + 0, /* Leading underscore. */ + ' ', /* AR_pad_char. */ + 16, /* AR_max_namelen. */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs. */ + + { + _bfd_dummy_target, + _bfd_dummy_target, + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + verilog_mkobject, + bfd_false, + bfd_false, + }, + { /* bfd_write_contents. */ + bfd_false, + verilog_write_object_contents, + bfd_false, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (verilog), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + NULL +}; |