Heterogeneous Interfaces with Emphasis on Reusing Existing VHDL Concepts

Proposal Details

  • Who Updates: ErnstChristen
  • Date Proposed: 2015-11-05
  • Date Last Updated:
  • Priority:
  • Complexity:
  • Focus: Flexibility, reuse of existing VHDL concepts

Bundles and Interfaces

A bundle is an ordered collection of objects. This makes it different from a signal of a record type or of an array type, which each are a single object. The difference is significant for bundles at ports: According to LRM 6.4.2.3:

%TABLE{ databg="#ffffff" tableborder="0" }%

  A signal may have one or more sources. For a signal of a scalar type, each source is either a driver (see 14.7.2) or an out, inout, buffer, or linkage port of a component instance or of a block statement with which the signal is associated. For a signal of a composite type, each composite source is a collection of scalar sources, one for each scalar subelement of the signal.

Consequently, if an actual signal is associated with more than one formal signal of mode out, inout, buffer, or linkage, then the actual must be of a resolved type. Conversely, each signal that is part of a bundle has its own source (if any) that is independent of the sources of the other signals of the bundle. This makes it possible to combine resolved and unresolved signals in a bundle.

A bundle doesn’t have a type; it’s the elements of a bundle that have a type. The properties of a bundle, such as its elements, are specified by an interface:

interface_unit_declaration ::=
    interface identifier is
        { interface_element_declaration }
    end [ interface ] [ interface_simple_name ] ;

interface_element_declaration ::=
      signal_declaration
    | bundle_declaration

bundle_declaration ::=
    bundle identifier_list : interface_mark ;

interface_mark ::= interface_name

A bundle declaration declares a bundle, which includes the creation of the objects that are elements of the bundle. In this regard a bundle behaves like a macro: it provides a convenient shorthand to work with a collection of objects.

The following basic operations apply to an interface:

  • A selected name, an indexed name, or a slice name

A selected name whose prefix is a bundle denotes an element of a bundle. Note that assignment is not a basic operation of an interface. Any assignment must be made to the elements of a bundle individually, as each element is a separate object.

Interfaces may be composite, in particular arrays. This makes it possible to specify different modes for different elements of a bundle of an array interface. The syntax to declare an array interface is similar to the declaration of an array type, and the semantics parallel each other.

A bundle can be associated as an actual in whole with a formal bundle port. Association in parts will require further investigations.

Interface Bundles and Port Views

The bundle concept also applies to ports. An interface bundle is declared to be of a particular port view. The primary function of a port view is to define the mode of each element of the bundle port. Therefore, the port view is related to an interface. A port view may be declared, in which case it is named. An anonymous port view may be created by specifying its properties as part of the interface bundle declaration.

interface_bundle_declaration ::=
   bundle interface_list : view port_view_indication

port_view_indication ::=
     port_view_name [ generic_map_clause ]
   | interface_name port_view_header

port_view_declaration ::=
   port view identifier of interface_name is
       port_view_header
   end [ port view ] [ port_view_simple_name ] ;

port_view_header ::=
     mode_map_clause
   | [ generic_clause ] [ port_clause [ port_map_clause ]]

mode_map_clause ::=
   mode map ( mode_association_list )

mode_association_list ::=
   mode_association_element { , mode_association_element }

mode_association_element ::=
   [ choices => ] mode

A secondary function of a port view is to specify those elements of the interface that are visible in the design unit. This is accomplished with a port clause in the definition of the port view. In the absence of a port clause all elements of the interface are visible in the scope of the port declaration. In this case their mode is specified with a port map clause. Conversely, if a port clause appears in a port view, the port clause defines the port properties. Each element listed in the port clause is a member of the interface bundle. If these members differ from those of the interface, a port map clause is required. For each association element, the formal in the port map clause is the local name for the corresponding actual.

Properties

New reserved words: interface, bundle, view, mode

Properties of a signal, including a composite signal, are untouched.

The effective value of a signal is the same everywhere the signal is visible.

Syntax reuse where possible.

Examples

Complex RTL Example

Many aspects of theis approach are demonstrated by the following 3 examples. The files not presented here are similar. The complete collection of files is available here.

The Generic Package cpu_bus_pkg

 library ieee;
 use ieee.std_logic_1164.all;
 package cpu_bus_pkg is
   generic (
      masters_max_jg : positive;
      slaves_max_jg  : positive;
      awidth_jg      : positive;
      dwidth_jg      : positive
   );
 
   subtype  masters_total_jrt  is natural range masters_max_jg - 1 downto 0;
 
   constant slaves_total_jc: positive := slaves_max_jg   -- individual slaves
                                       + masters_max_jg  -- master's slave return
                                       + 1;              -- arbiter's slave return
   subtype  slaves_total_jrt   is natural range slaves_total_jc - 1 downto 0;
 
   subtype  addr_jrt           is natural range awidth_jg - 1 downto 0;
   subtype  data_jrt           is natural range dwidth_jg - 1 downto 0;
 
   subtype  master_ctrl_vst    is std_logic_vector(masters_total_jrt);
   subtype  slave_ctrl_vst     is std_logic_vector(slaves_total_jrt);
 
   subtype  addr_vst           is std_logic_vector(addr_jrt);
   subtype  data_vst           is std_logic_vector(data_jrt);
 
   type master_r is                      -- Master record
      record
         addr_vl : addr_vst;             -- Address bus to slave devices
         data_vl : data_vst;             -- Data bus from master to slave
         we_l    : std_logic;            -- Write enable from master to slave
         en_vl   : slave_ctrl_vst;       -- Slave enables from master to slave
      end record master_r;
 
   type slave_r is                       -- Slave record
      record
         data_vl : data_vst;             -- Data bus from slave to master
         ack_l   : std_logic;            -- Acknowledge to master from slave
         err_l   : std_logic;            -- Error report to master from slave
      end record slave_r;
 
   interface slave_i is
      signal slave_rl : slave_r;
   end interface slave_i;

   interface slave_a is
      array (slaves_total_jrt) of slave_i;-- Array of slave interfaces
   
   interface arbiter_i is                -- Arbiter bundle
      signal master_rl   : master_r;     -- Master record to the arbiter
      signal bus_req_l   : std_logic;    -- Bus request from master
      signal bus_grnt_l  : std_logic;    -- Bus grants to master
   end interface arbiter_i;

   interface arbiter_a is
      array(masters_total_jrt) of arbiter_i;-- Array of arbiter interfaces
  
   interface cpu_bus_i is                -- Bus interface record
      bundle arbiter_al : arbiter_a;     -- Arbiter array of arbiter master
                                         -- control records
      signal master_rl  : master_r;      -- Master record to slaves
      bundle slave_al   : slave_a;       -- Array of slave records to master
   end record cpu_bus_i;

   port view slave_ivw of cpu_bus_i is
      generic (
         slave_id_jg : slaves_total_jrt
      );
      port (
         signal master_rl : in     master_r;
         signal slave_rl  : buffer slave_r
      );
      port map (
         master_rl => master_rl,
         slave_rl  => slave_al(slave_id_jg)
      );
   end port view slave_ivw;

   port view arbiter_v_in of arbiter_i is
      mode map (master_rl => buffer, bus_req_l => buffer, bus_grnt_l => in);
--      This is equivalent to
--      port (
--         signal master_rl  : buffer master_r;
--         signal bus_req_l  : buffer std_logic;
--         signal bus_grnt_l : in     std_logic
--      );
   end port view arbiter_v_in;

   port view arbiter_v_out of arbiter_i is
      mode map (master_rl => in, bus_req_l => in, bus_grnt_l => buffer);
   end port view arbiter_v_out;

   port view master_ivw of cpu_bus_i is
      generic (
         slave_id_jg  : slaves_total_jrt;
         master_id_jg : masters_total_jrt
      );
      port (
         bundle arbiter_rl : view   arbiter_v_in;
         signal master_rl  : in     master_r;
         bundle slave_al   : view   slave_a 
                              mode map (slave_id_jg => buffer, others => in)
      );
      port map (
         arbiter_rl => arbiter_al(master_id_jg),
         master_rl =>  master_rl,
         slave_al =>   slave_al
      };
   end port view master_ivw;

   port view a_arbiter_avw of arbiter_a is
      mode map (
         others => view    arbiter_v_out
      );
   end port view a_arbiter_avw;

   port view arbiter_ivw of cpu_bus_i is
      generic (
         slave_id_jg  : slaves_total_jrt
      );
      port (
         bundle arbiter_al  : view   a_arbiter_avw;
         signal master_rl   : buffer master_r;
         signal slave_rl    : buffer slave_r
      );
      port map (
         arbiter_al => arbiter_al,
         master_rl  => master_rl,
         slave_rl   => slave_al(slave_id_jg)
      );
   end port view arbiter_grnt_ivw;
end package cpu_bus_pkg;

The slave_ent design unit

 library ieee;
 use ieee.std_logic_1164,all;
 use work.cpu_bus_2m8s_pkg.all;
 entity slave_ent is
      generic (
         slave_id_jg : slaves_total_jrt
      );
      port (
         signal rst_i       : in     std_logic;
         signal clk_i       : in     std_logic;
         bundle cpu_bus_rif : view   slave_ivw
                                          generic map (
                                             slave_id_jg => slave_id_jg
                                          )
      );
 end entity slave_ent;

 architecture rtl_arch of slave_ent is
         alias add_vs      is cpu_bus_rif.master_rl.addr_vl;
         alias data_in_vs  is cpu_bus_rif.master_rl.data_vl;
         alias we_s        is cpu_bus_rif.master_rl.we_l;
         alias en_s        is cpu_bus_rif.master_rl.en_vl(slave_id_jg);
 
         alias data_out_vs is cpu_bus_rif.slave_rl.data_vl;
         alias ack_s       is cpu_bus_rif.slave_rl.ack_l;
         alias err_s       is cpu_bus_rif.slave_rl.err_l;
 begin
      ...
 end architecture rtl_arch;

The master and arbiter design units are similar.

The AMandS design unit

 library ieee;
 use ieee.std_logic_1164.all;
 use work.cpu_bus_2m8s_pkg.all;
 entity AMandS_ent is
      port (
         signal rst_i       : in     std_logic;
         signal clk_i       : in     std_logic;
         bundle cpu_bus_rif : view   cpu_bus_i
                mode map (arbiter_al => view   a_arbiter_avw,
                          master_rl  => buffer master_r;
                          slave_al   => view   slave_a
                                  mode map (3|7|9|10 => buffer, others => in)
                           )
      );
 end entity AMandS_ent;

 architecture rtl_arch of AMandS_ent is
 begin
      arbiter_inst : entity work.arbiter_ent
         generic map (
            slave_id_jg  => 10
         )
         port map (
            rst_i       => rst_i,
            clk_i       => clk_i,
            cpu_bus_rif => cpu_bus_rif
         );

      master_inst2 : entity work.master_ent
         generic map (
            slave_id_jg  => 9,
            master_id_jg => 1
         )
         port map (
            rst_i       => rst_i,
            clk_i       => clk_i,
            cpu_bus_rif => cpu_bus_rif
         );

      slave_inst4 : entity work.slave_ent
         generic map (
            slave_id_jg => 3
         )
         port map (
            rst_i       => rst_i,
            clk_i       => clk_i,
            cpu_bus_rif => cpu_bus_rif
         );

      slave_inst8 : entity work.slave_ent
         generic map (
            slave_id_jg => 7
         )
         port map (
            rst_i       => rst_i,
            clk_i       => clk_i,
            cpu_bus_rif => cpu_bus_rif
         );
 end architecture rtl_arch;

The MplusS and Sonly design units are similar.

Questions

Comments

In the meeting on November 5, 2015, the following comments were made:

  • The syntax of port_view_header allows an empty production.
    Main.ErnstChristen: Yes. There must be either a semantic rule to prevent that, but more likely is that the port clause may not be optional. Investigation pending.
  • It seems that the generic map should be part of the interface, not of the port view.
    Main.ErnstChristen: Not for the functionality required in the Complex RTL example, for this it must be part of the port view. However, there are at this time a number of inconsistencies whose resolution may provide an answer.
  • It seems there is a lot of repetition/duplication. Elements have to be declared as part of the interface and again in the port clause of a port view. Finally, their names also appears in the port map clause. This is reminiscnent of the definnition of a block, but nobody uses a block this way.
    Person I have a faint recollection that some of the models in the Free Model Foundary may use the 'port map' technique in block structures. Brent Hayhoe - 2015-11-07

    Main.ErnstChristen: The port clause of a port view defines the elements of the formal bundle, which is the subset of the actual that is visible in a DU whose entity has a port with this port view. This use is quite similar to the port clause of an entity. The port map clause maps the elements of the bundle actual to the elements of the bundle formal. This is quite similar to a port map clause of a component instantiation statement.
  • It should be possible to combine port clause and port map clause, maybe by extending the semantics of an association element in a port map clause to include a mode.
    Main.ErnstChristen: This is an approach with a different emphasis, less on reuse of existing concepts and more on adding new ones. It should be investigated and presented as a different proposal.
  • Several syntax and typographical errors were pointed out.
    Main.ErnstChristen: These have now been corrected.

Some thoughts on bundle semantics

- Brent Hayhoe - 2015-11-09

  • The bundle is an "ordered collection of objects" a kind of composite object ( as opposed to a composite type).
    Main.ErnstChristen - 2015-11-10: Not quite. A composite object in VHDL terminology is an object of a composite type. A bundle is not a composite object, but a named collection of objects. A bundle declaration declares all the objects that are contained in the interface.
    Person I think we may need to specify the semantics in the LRM a bit more thoroughly:

    "An object of a composite type represents a collection of objects, one for each element of the composite object. [LRM 5.3.1]"

    What is missing from the composite object definition in the LRM (above) is the implicit assumption that the elements of the composite object are all of the same object class, i.e. the class of the object that the composite type is associated with (e.g. class signal).
    We can and should use the terminology 'composite object', but when used with the new bundle concept we state that the 'composite object' may now have elements of differing object class.
    Brent Hayhoe - 2015-11-12
    Main.ErnstChristen - 2015-11-17: Again "not quite". A bundle is not an object, it is a collection of objects. This puts it in some way above an object. There are many differences, as implied by comparing the basic operations of a type with those of an interface. A very important one is that a primary in an expression may denote an object, but not a bundle. A bundle may also not be the target of an assignment statement.
    Person This poses the important question: can a signal of composite type and associated with an interface record view (or array view) be the target of an assignment statement? Brent Hayhoe - 2015-11-18
    Main.ErnstChristen - 2015-11-18: Everything that a user can do with a signal is independent of whether the signal is an element of the bundle or not. The only difference is the name of the object.

  • A signal object is associated (when declared) with its type.
  • We need to associate a bundle with something, but it is not a type. Let's call it a structure for now.
    Main.ErnstChristen - 2015-11-10: The properties of a bundle are described by an interface, that is, the interface takes the place of the type in a bundle declaration. For a bundle port the properties are defined by a port view.
  • We can order the structure and call it a cluster (can't use 'structure' - how many architectures in peoples code are called that!!!!)
  • We can now give it order by defining it as record cluster or an array cluster:
    Main.ErnstChristen - 2015-11-10: As described above, there are array interfaces. Each element of a 1-dimensional interface array is a scalar interface, and the same applies to bundles.
    Person I guess what I was questioning was how you intend to define an interface array. As Jim mentioned (I think) the interface production is similar to a record type structure of objects in its format (without the keywords), so how do we specify the array form of the interface production? Brent Hayhoe - 2015-11-12
    Main.ErnstChristen - 2015-11-17: As described in the text, the syntax to declare an interface array parallels the syntax of declaring an array type. There are examples in package cpu_bus_pkg.
    Person Does this mean that we cannot have an array of signals or an array of bundles? Brent Hayhoe - 2015-11-18
    Main.ErnstChristen - 2015-11-18: You can have both, and each has its dedicated use.
bundle_declaration ::=
    bundle identifier_list : structure_indication ;

structure_definition ::= 
    record_structure_definition
    | array_structure_definition

record_stucture_definition ::= 
    cluster identifier is record
         { cluster_element_declaration }
    end record [ record_cluster_simple_name ]

array_stucture_definition ::= 
    cluster identifier is array
         ( index_subtype_definition { , index_subtype_definition } )
               of cluster_element_declaration ;

cluster_element_declaration ::=
      signal_declaration
    | bundle_declaration
  • So what does this give us - just as a bundle is a composite group object of a signal, a signal is associated with a type, a bundle is now associated with a cluster. I feel it could give us better semantics/syntax, I'm just not sure which!
  • This could then lead on to a record cluster view and an array cluster view

Arguments FOR

Arguments AGAINST

Supporters

-- ErnstChristen - 2015-11-05</sticky>

I Attachment Action Size Date Who Comment
Unknown file formatgz ComplexRTLWithBundle.tar.gz manage 2.8 K 2015-11-17 - 21:42 ErnstChristen VHDL files supporting this approach
Topic revision: r9 - 2015-11-19 - 21:46:39 - ErnstChristen
 
Copyright © 2008-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback