This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: verilog hex memory dump backend for BFD


The following patch adds a new output-only format to BFD called
"verilog hex memory dump format".

When developing a new microprocessor in verilog it is important to
develop testbenches using simulated memory containing real programs.
In order to help populate this memory, verilog provides the 
$readmemh() function to load an array of verilog registers (memory) 
with the contents of a file.  The file must be in the verilog hex 
memory dump format as defined by the IEEE verilog standard.

Adding support for this format directly into BFD greatly simplifies
the workflow:

$ moxie-elf-gcc -o hello.x hello.c
$ moxie-elf-objcopy -O verilog hello.x hello.vh

Now hello.vh can be used to populate memory modules directly in
verilog like so:

module memory();
  reg [7:0] my_memory [0:64000];
  initial begin
    $readmemh("hello.vh", my_memory);
  end
endmodule;

This new feature was tested with a Free Software verilog
implementation called Icarus Verilog.

Ok?


2009-04-22  Anthony Green  <green@moxielogic.com>

        * verilog.c: New file.
        * Makefile.am (BFD32_LIBS): Add verilog.c.
        (BFD32_LIBS_CFILES): Add verilog.c.
        (verilog.lo): New build rule.
        * Makefile.in: Rebuilt.
        * targets.c: Add verilog support.
        * bfd-in2.h: Add verilog support.

diff -r cca56f4724f7 src/bfd/Makefile.am
--- a/src/bfd/Makefile.am	Thu Apr 16 23:00:44 2009 -0400
+++ b/src/bfd/Makefile.am	Wed Apr 22 12:10:34 2009 -0400
@@ -43,7 +43,7 @@
 	format.lo init.lo libbfd.lo opncls.lo reloc.lo \
 	section.lo syms.lo targets.lo hash.lo linker.lo \
 	srec.lo binary.lo tekhex.lo ihex.lo stabs.lo stab-syms.lo \
-	merge.lo dwarf2.lo simple.lo compress.lo
+	merge.lo dwarf2.lo simple.lo compress.lo verilog.lo
 
 BFD64_LIBS = archive64.lo
 
@@ -53,7 +53,7 @@
 	format.c init.c libbfd.c opncls.c reloc.c \
 	section.c syms.c targets.c hash.c linker.c \
 	srec.c binary.c tekhex.c ihex.c stabs.c stab-syms.c \
-	merge.c dwarf2.c simple.c compress.c
+	merge.c dwarf2.c simple.c compress.c verilog.c
 
 BFD64_LIBS_CFILES = archive64.c
 
@@ -1087,6 +1087,8 @@
   $(INCDIR)/bfdlink.h genlink.h
 srec.lo: srec.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
   $(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h
+verilog.lo: verilog.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
+  $(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h
 binary.lo: binary.c $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \
   $(INCDIR)/hashtab.h
 tekhex.lo: tekhex.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
diff -r cca56f4724f7 src/bfd/bfd-in2.h
--- a/src/bfd/bfd-in2.h	Thu Apr 16 23:00:44 2009 -0400
+++ b/src/bfd/bfd-in2.h	Wed Apr 22 12:10:34 2009 -0400
@@ -4855,6 +4860,7 @@
       struct ieee_data_struct *ieee_data;
       struct ieee_ar_data_struct *ieee_ar_data;
       struct srec_data_struct *srec_data;
+      struct verilog_data_struct *verilog_data;
       struct ihex_data_struct *ihex_data;
       struct tekhex_data_struct *tekhex_data;
       struct elf_obj_tdata *elf_obj_data;
@@ -5176,6 +5182,7 @@
   bfd_target_oasys_flavour,
   bfd_target_tekhex_flavour,
   bfd_target_srec_flavour,
+  bfd_target_verilog_flavour,
   bfd_target_ihex_flavour,
   bfd_target_som_flavour,
   bfd_target_os9k_flavour,
diff -r cca56f4724f7 src/bfd/bfd.c
--- a/src/bfd/bfd.c	Thu Apr 16 23:00:44 2009 -0400
+++ b/src/bfd/bfd.c	Wed Apr 22 12:10:34 2009 -0400
@@ -220,7 +220,8 @@
 .      struct ieee_data_struct *ieee_data;
 .      struct ieee_ar_data_struct *ieee_ar_data;
 .      struct srec_data_struct *srec_data;
+.      struct verilog_data_struct *verilog_data;
 .      struct ihex_data_struct *ihex_data;
 .      struct tekhex_data_struct *tekhex_data;
 .      struct elf_obj_tdata *elf_obj_data;
--- a/src/bfd/targets.c	Thu Apr 16 23:00:44 2009 -0400
+++ b/src/bfd/targets.c	Wed Apr 22 12:10:34 2009 -0400
@@ -157,6 +157,7 @@
 .  bfd_target_oasys_flavour,
 .  bfd_target_tekhex_flavour,
 .  bfd_target_srec_flavour,
+.  bfd_target_verilog_flavour,
 .  bfd_target_ihex_flavour,
 .  bfd_target_som_flavour,
 .  bfd_target_os9k_flavour,
@@ -820,6 +821,7 @@
 /* These are always included.  */
 extern const bfd_target srec_vec;
 extern const bfd_target symbolsrec_vec;
+extern const bfd_target verilog_vec;
 extern const bfd_target tekhex_vec;
 extern const bfd_target binary_vec;
 extern const bfd_target ihex_vec;
@@ -1210,6 +1212,8 @@
 /* Always support S-records, for convenience.  */
 	&srec_vec,
 	&symbolsrec_vec,
+/* And verilog */
+	&verilog_vec,
 /* And tekhex */
 	&tekhex_vec,
 /* Likewise for binary output.  */
diff -r cca56f4724f7 src/bfd/verilog.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bfd/verilog.c	Wed Apr 22 12:10:34 2009 -0400
@@ -0,0 +1,378 @@
+/* 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 abre
+	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
+};
+
diff -r cca56f4724f7 src/bfd/doc/ChangeLog
--- a/src/bfd/doc/ChangeLog	Thu Apr 16 23:00:44 2009 -0400
+++ b/src/bfd/doc/ChangeLog	Wed Apr 22 12:32:21 2009 -0400
@@ -1,4 +1,9 @@
+2009-04-22  Anthony Green  <green@moxielogic.com>
+
+	* bfdint.texi (BFD target vector miscellaneous): Mention verilog
+	flavour.
+
 2008-11-19  Nick Clifton  <nickc@redhat.com>
 
 	* fdl.texi: Update to v1.3
--- a/src/bfd/doc/bfdint.texi	Thu Apr 16 23:00:44 2009 -0400
+++ b/src/bfd/doc/bfdint.texi	Wed Apr 22 12:32:21 2009 -0400
@@ -356,6 +356,8 @@
 SOM (used on HP/UX).
 @item bfd_target_os9k_flavour
 os9000.
+@item bfd_target_verilog_flavour
+Verilog memory hex dump format.
 @item bfd_target_versados_flavour
 VERSAdos.
 @item bfd_target_msdos_flavour

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]