6
VHDL entities, architectures and components- describing structure and its attributes

prepared by P. Bakowski


Introduction

In the previous lesson we have presented the entity module and we have discussed different aspects of behavioral architecture descriptions. Recall  that the main building block  for behavioral description are processes and  eventually concurrent procedure calls. The behavioral architectures are the bottom-end of complex descriptions. The development of complex models requires the use of  components. Each component may be in turn described in terms of smaller components or in the form of behavioral architecture.
In order to provide this lesson self-contained we start by presentation of entity and architecture modules. Then we introduce the notion of VHDL  component and  the mechanisms allowing us to build structural architectures.

Contents: entity declaration, architecture declaration, components, component instantiation, components configuration, simple structural descriptions ,blocks, generate statement, configuration modules, user-defined attributes, exercises


VHDL entity declaration [syntax]
The basic descriptional element of VHDL is entity; each description must be composed from at least one entity.  Each entity has a set of ports which constitute its interface to the outside world. In VHDL, an entity may be the top level module of the design or  may be used as a component in a design.
entity horloge is
port(horl:out bit);
end horloge;
entity ones_counter is
port(a:in bit_vector(0 to 2); c:out bit_vector(0 to 1));
end ones_counter;
In general, the entity modules consist of two parts: The declarative part may be used to declare items (e.g. types, functions,..)  to be used in the implementation of the entity.  Optional statements in the entity declaration may be inserted to define some special behavior for monitoring operation of the entity (e.g.  checks on the input signals).

The  header may include specification of generic constants. Generics allow to determine some quantitative aspects of the structure (e.g. size of the bus) and behavior (e.g. number of counting steps) of the entity.

entity ones_counter is
generic(retard: time:= 10 ns);
port(a:in bit_vector(0 to 2); c:out bit_vector(0 to 1));
end ones_counter;
The generics are actualized when the entity is instantiated as a component in a design.


ports and signals

An entity port contains the  list of  items that must all be of class signal. Consequently, we are not required to write the word signal it is assumed.
port(signal a:in bit_vector(0 to 2); signal c:out bit_vector(0 to 1));
port(a:in bit_vector(0 to 2); c:out bit_vector(0 to 1));
-- both expressions are equivalent
The ports may specify the input (in), the output (out) and the input-output signals (inout).
port(reset:in bit;abus:out address; dbus:inout word);
The word buffer is a kind of inout signal.  It should be applied if the port is to be connected to an output -input signals used as a component in a design.
port(counter:buffer word);
A buffer port may have at most one signal assignment within the architecture.
 

elements of entity declaration

The declarative part of an entity may contain several kinds of items including:
  • type declarations
  • procedure or function definitions
  • assertions concerning the input signals
  • e.g. assert s'stable(10 ns)
    report "message"
    severity warning;

    An example:

    entity complex is end complex;
    ..

    VHDL architecture declaration [syntax]
    The architecture is a module used to define how entity behaves or what it is composed of. The architecture description may be abstract implying the use of abstract objects; RTL (register transfer level) oriented implying the use of hardware related object types like registers or buses or structural implying the use of smaller hardware modules referred to as components.
    Depending on the character of the design or description, the components may be embraced at block or core level or be may be much more detailed and imply the creation of logic level structures (logic netlists).
     
    Each architecture body can describe a different implementation of the entity.

    The potential composition of architecture module comprises:


    architecture declarative part

    The declarative part of the architecture may contain: Example:
    architecture exemple of entite_une is
    signal tmp:bit:=0;
    constant ret:time:=10 ns;
    function complement(mot:word) return word is
    -- local variables are not allowed
    begin
    for i in mot'range loop
    tmp(i) := not word(i);
    return tmp;
    end complement;
    component horl_comp
    port(horl:out bit)
    end component;
    begin
    -- architecture body starts here

    VHDL components

    Structural architecture descriptions use extensively the predefined components. Each VHDL entity, when used as a part of some bigger structure, becomes a component. The components are interconnected to form structural descriptions. VHDL provides mapping mechanism allowing to associate the inputs and outputs of the components with external connections (signals). All components are potentially active and perform their internal operations concurrently. These operations are carried out through the internal processes. They are activated through  events on signals generated outside (or inside) of the components.
    The components used in a description may be declared and defined inside the architecture. However, in the practice we try to separate the preparation of the components from their actual use and we place the components in design libraries.
    If the components are to be imported from outside, the architecture must declare a component, which can be thought of as a template defining a virtual design entity to be instantiated within the architecture. VHDL provides a special  mechanism of configuration specification which permits to specify the library and the components to be used in the model.

    Basic structural description

    A basic structural description is built from interconnected components. The components must be declared and configured. Then they can be instantiated.


    Component declaration

    Each component  to be used in the description must be declared in either the current architecture or in a package. The component identifier represents the entity name. If there is only one architecture provided for the given entity then no configuration is required to identify which architecture is attached to this entity. Component declaration corresponds to the interface part of entity. If the entity has generic and port clauses; the same clauses must be copied into the component declaration.
     
    entity declaration component declaration
    entity nand is 
      generic(g_delay:time:= 3ns) 
      port(a,b:in std_logic;y:out std_logic)
    end nand ;
    component nand 
      generic(g_delay:time:= 3ns) 
      port(a,b:in std_logic;y:out std_logic)
    end component ;
    Different instances of the component nand can later be used with possibly different propagation delays (g_delay).

    The following example declares a RAM block component with address depth and data width dependent on generic constants. This component can act as a template for a RAM entity .

     Component configuration

    When several types architectures are defined for a given entity the compiler must know the precise name of the required architecture. If there is only one architecture for this entity the configuration operation is not needed.
    The selection of  the required architecture is performed either through an independent configuration module or via simple configuration statements.

    The configuration statement looks as follows:

    If all components are instantiated using the same architecture the term all may be used: Note that if you use the configuration statement, the name of the component need not be the same as entity name. The instance name should be different from component name.
    For example,  in the following description
    entity fun_gate is
    port(x: in bit; y: out bit)
    end fun_gate;
    architecture first of fun_gate is
    begin
    y <= f(x);
    end first;
    architecture second of fun_gate is
    begin
    y <= g(x);
    end second;
    architecture third of fun_gate is
    begin
    y <= h(x);
    end third;
    entity fun_gate_syst is
    end fun_gate_sys;entity
    architecture simple of fun_gate_sys is
    signal sigx: bit;
    signal sigy: bit;
    component gate   -- component declaration
    port(fx: in bit; fy: out bit)
    end component;
    for inst1:  gate use work.fun_gate(first) port map (fx=>x, fy=>y);  -- component configuration with instance name
    begin
    inst1: gate port map(sigx,sigy); -- instance instatiation
    end simple;
    The keyword others may be used in place of the instantiation label in configuration statement. Such a configuration statement applies to all instantiations of the given component except for those instances whose labels appear in preceding configuration statements. We can illustrate this on a fragment of modified example from above.
     
    for inst1:  gate use work.fun_gate(first) port map (fx=>x, fy=>y);  -- instance name inst1
    for inst2:  gate use work.fun_gate(second) port map (fx=>x, fy=>y);  -- instance name inst2
    for others: gate use work.fun_gate(third) port map (fx=>x, fy=>y);  -- other instances
    begin
    inst1: gate port map(sigx,sigy); -- instance instantiation
    inst2: gate port map(sigx,sigy); -- instance instantiation
    inst3: gate port map(sigx,sigy); -- instance instantiation
    inst4: gate port map(sigx,sigy); -- instance instantiation
    ...

     Component instantiation - connection

    A component defined in an architecture may be instantiated using the syntax: This indicates that the architecture contains an instance of the named component, with actual values specified for generic constants, and with the component ports connected to actual signals or entity ports.

    The nand component declared in the previous page may be instantiated as (positional association):

    The RAM_block component declared in the above page may be instantiated twice as follows:  

    Default values

    The signals provided by the ports (out, inout and buffer) have  implicit default values defined as follows: Initial values of signal drivers are computed during the elaboration phase situated just before the simulation execution phase.

    Type conversion

    Type conversion may be used for port  mapping. It allows to ensure type matching.  These conversions imply the use of conversion functions: function to_real(val_int:integer) return real is
    ..
    end to_real;

    function to_int (val_real:real) return integer is
    ..
    end to_int;
    ..
    component conv_example
    port(in_real: in real; out_int:out int);
    end component;

    signal real_s: real:= 2.74;
    signal int_s: integer:= 2;

    inst1: conv_example
    port map(in_real=>to_real(int_s),out_int=>to_int(real_s)); -- actual_to_formal type conversion
    ins2: conv_example
    port map(to_int(in_real)=>int_s,to_real(out_int)=>real_s);-- formal_to_actual type conversion
    ..
     

    Open connections

    The rules of VHDL port mapping require that in a component instantiation all formal signals have their actual counterpart. It means that even unconnected ports must be characterized. In such a case the modeler can create a dummy signal which is not used in the final design. This solution however may lead to design error. Much proper solution is to use the reserved word open.
    Any port signal of mode out, inout or buffer may be unconnected provided its type is not an unconstrained array type. The port signals in mode in may be unconnected only if their declarations include default initialization.
    architecture simple of ff_syst is
    component Dff
    port(clk,d: in  bit; q,q_bar: out bit)
    end component;
    signal sclk,sd,sq: bit;
    begin
    inst1: Dff
    port map(sclk,sd,sq,open);  -- q_bar is unconnected
    end simple;

    Example:
    The gate components are declared in a package and there is only one architecture per entity declaration.

    VHDL configuration modules [syntax]

    An important feature of VHDL and its simulation environment  is the possibility to organize different views of a single design by configuring it differently, without the necessary recompilation of any part of the design. This capability allows to reconstruct the design using different architectures of the same components/subcomponents.
    The configuration statement alone permits to perform the reconfigurations; however each modification of the architecture module requires its recompilation.
    In order to separate the configuration phase and statements  from the architectural body VHDL provides the modeler with an independent configuration module. Configuration module allows the designer to collect all the bindings for a model in a separate place. The particular instances of the components in the system can be changed without the recompilation of the components.
    Given a particular entity representing a multi-component system the configuration declaration takes the name of the entity and declares the components bindings.
    configuration configuration_name of configured_entity is
    for architecture_name     -- of the configured entity
    for instance_name: comp_name use entity entity_name(architecture_name);
    ..
    end for;
    end for;
    end configuration_name;
    If the components used in configuration have their sub-components the configuration module can be further extended down to the smallest components.
     
    configuration configuration_name of configured_entity is
    for architecture_name_high     -- configured entity
    for architecture_name_low
      for lower_instance_name1: comp_name use entity entity_name1(architecture_name1);end for;
      for lower_instance_name2: comp_name use entity entity_name2(architecture_name2);end for;
    end for;
    ..
    end for;
    end for;
    end configuration_name;

    Example of configuration module elaborated for the full adder description;

    configuration conf_adder of adder is
    for structural
    for all: xorg use entity work.xorg(only);
    end for;
    for and1: andg use entity work.andg(first);
    end for;
    for and2: andg use entity work.andg(second);
    end for;
    for all: org use entity work.org(only);
    end for;
    end for;
    end conf_adder;

     
     entity adder is end adder;
     
    use work.bgates.all; -- all necessary components are declared in the package
    architecture structural of adder is
    begin
    end structural;
    This configuration module presented above configures the adder entity built from several logic gates. The instantiated gates are chosen from the bgates package illustrated below. 
    Note that the package bgates contains 3 versions of the architectures for the and gate: architecture only .., architecture first.. and architecture second...
    The configuration module called conf_adder is used to chose architecture first for the first and gate instantiation (and1), and the architecture second for the second and gate instantiation (and2).
    The instances of org and xorg use the same unique architecture; that is why they are instantiated with  all keyword.
    -- package bgates with gate component declarations
    package bgates is
    component andg
    generic (tpd_hl : time := 1 ns; tpd_lh : time := 1 ns);
    port (in1, in2 :in  bit; out1 : out bit);
    end component;
    component org
    generic (tpd_hl : time := 1 ns; tpd_lh : time := 1 ns);
    port (in1, in2 : in bit; out1 : out bit);
    end component;
    component xorg
    generic (tpd_hl : time := 1 ns; tpd_lh : time := 1 ns);
    port (in1, in2 : in bit; out1 : out bit);
    end component;
    end bgates;
    -- gate entities
    entity andg is
    generic (tpd_hl : time := 1 ns; tpd_lh : time := 1 ns);
    port (in1, in2 : in bit; out1 : out bit);
    end andg;
    -- the only architectures responds with different delays for low to high and high to low transitions
    architecture only of andg is
    begin
    p1: process(in1, in2)
    variable val : bit;
    begin
    val := in1 and in2;
    case val is
    when '0' => out1 <= '0' after tpd_hl;
    when '1' => out1 <= '1' after tpd_lh;
    when others => out1 <= val;
    end case;
    end process;
    end only;
    -- the first architectures involves no explicit timing
    architecture first of andg is
    begin
    p1: process(in1, in2)
    begin
    out1 <= in1 and in2;
    end process;
    end first;
    -- the second architectures involves maximum output delay
    architecture second of andg is
    begin
    p1: process(in1, in2)
    variable val : bit;
    begin
    if(tpd_hl> tpd_lh) then
    out1 <= in1 and in2 after tpd_hl;
    else
    out1 <= in1 and in2 after tpd_lh;
    end if;
    end process;
    end second;
    -- or gate entity
    entity org is
    generic (tpd_hl : time := 1 ns; tpd_lh : time := 1 ns);
    port (in1, in2 : in bit; out1 : out bit);
    end org;
    architecture only of org is
    begin
    p1: process(in1, in2)
    variable val : bit;
    begin
    val := in1 or in2;
    case val is
    when '0' => out1 <= '0' after tpd_hl;
    when '1' => out1 <= '1' after tpd_lh;
    when others => out1 <= val;
    end case;
    end process;
    end only;
    -- xor gate entity
    entity xorg is
    generic (tpd_hl : time := 1 ns; tpd_lh : time := 1 ns);
    port (in1, in2 : in bit; out1 : out bit);
    end xorg;
    architecture only of xorg is
    begin
    p1: process(in1, in2)
    variable val : bit;
    begin
    val := in1 xor in2;
    case val is
    when '0' => out1 <= '0' after tpd_hl;
    when '1' => out1 <= '1' after tpd_lh;
    when others => out1 <= val;
    end case;
    end process;
    end only;

    generate statement

    Some structural description features a high degree of regularity and repetitivness which allows iterative instantiation of components. This kind of instantiation can be performed with  VHDL generate statement. Generate statement indicates the compiler how to multiply the instantiations of the components in order to build a regular structure.

    The general form of generate statement is illustrated below:

    The generation_scheme includes for loop with some internal conditions allowing to differentiate the instantiations: The following is an example of counter circuit generated from simple T-flip-flops and and gates.
    The components provided to build the counter: The counter architecture is instantiated with generate statements. Note that the if conditions differentiate the instantiations for the first and the last  tff flip-flop. The G3 loop instantiates six tff  flip-flops and six and2 gates with the corresponding indexes going from 1 to 6 for outputs dout(i) and from 0 to 5 for inputs s(i-1).

    VHDL block [syntax]

    The architecture modules written in VHDL may be internally decomposed into blocks. A block is a piece of architecture behaving as a substructure. The VHDL blocks are labeled ; the block headers may contain conditional activation statements called guards.

    The general form of  block construct :

    The guard expression allows to formulate the control conditions required  for the activation/inhibition of the signal assignments inside the block.

    The following example shows an architecture containing only one block. The signal assignments inside the block are guarded by the condition specified in the header of the block.

    The VHDL blocks may be nested. If a block is nested inside another one, the internal block activation condition may be combined with the external block guard. For example, the above architecture may be embedded into a higher level block providing an enable (enb) signal.

    The enable signal is validated by the state '1'.  Now, the completed architecture may be described as follows:

    architecture garde2 of d_ff is
    begin
    e_ff: block(enb='1')
    b_ff: block (clk'event and clk='1' and guard)
    begin
    q <= guarded d after delai;
    qbar <= guarded not d after delai;
    end block b_ff;
    end block e_ff;
    end garde;

    Blocks and multiplexed signals

    In general, when a multiple source signal is used the application of resolution function becomes necessary. However, this solution is inconvenient for the modeling of time-multiplexed signals. The time- multiplexed signals are not active in the same time slots, so there are no potential conflicts at the signal output. For the guarded signals the implicit use of the resolution function may provoke the simulation errors which  do not occur actually. That is why an additional mechanism was added to disable the application of the resolution function to guarded signals. This mechanism is based on two special designators register and bus . The resolved signals declared with register behave as unresolved signals memorized in the output register. The resolved signals declared with bus designator behave as unresolved transient signals.
    Let us consider a tri-state buffer driven by two data signals validated by two non overlapping clock phases (ph1 and ph2). In this case, the d1 and d2 signals are never selected at the same time so no resulution function is required.
    The model with bus designator: Now consider a d-latch driven by two data signals validated by two non overlapping clock phases.

    The modeling solution  with register designator:


    User defined attributes

    User defined attributes are used to characterize the non-simulation oriented design features. They are often exploited by tools such as ASIC/FPGA synthesizers.

    User attribute declaration and specification

    User defined attributes are constants of arbitrary types. Such constants are associated to attribute specification. They quantify additional information about an item, for example the capacitance load on ports. Note that VHDL does not allow any calculation of  attribute values. Attributes may be related to an entity unit, an architecture unit, a configuration unit, a procedure or function module, a package, a type or subtype, a signal, a variable, a component, a file, a label, a literal, a unit or a group.

    The following is a general form of attribute declaration/specification:

    Example:

    package freq_package is
    type frequency is range 0 to 4400000;
    units
    Hz; -- base unit
    KHz = 1000 Hz;
    MHz = 1000 KHz;
    end units;
    attribute max_freq: frequency;
    constant max_freq_constant: frequency:= 10 MHz;
    end package freq_package;
    use work.freq_package.all;
    entity clock is
    port(ph1,ph2:out bit; quartz:in bit);
    attribute max_freq of quartz: signal is max_freq_constant;
    ..
    Examples of specification:  (the units gates and pf must be defined earlier):

    Some possible applications of user defined attributes:

     
    item attribute application attribute specification example remarks
    signal characteristics of input/output pins such as  

    capacitance and drive loading, driver type,  

    pin numbering, signal arrival time, ...

    attribute capacitance of clk: signal is 10 pf; 

    attribute arrival_time of clk: signal is 4 ns; 

    attribute pin_number of a_bus: signal is "24";

    These attributes can be used by  placement & route program or
    by synthesizer to optimize the design
    entity general characteristics of component such as  
    power supply, voltages, maximum frequency,  temperature range, packaging, ...
    attribute max_area of my_FPGA: entity is 25.5; 

    attribute max_freq of my_FPGA: entity is 10 MHz; 

    attribute min_power of my_FPGA: entity is 10 mW;

    These attributes are used to document the characteristics of the component.  

    Timing delays may be modified to correspond to the constraints

    architecture specification of the technology or other aspects 

    related to the architecture

    attribute techno of my_ASIC: architecture is CMOS-0.18; 

    attribute max_freq of my_ASIC: architecture is 10 MHz; 

    attribute max_size of my_FPGA: architecture is 100 s_mm

    These attributes are used to indicate the non-functional characteristics of the architecture. 

    They may be used by a synthesizer to select the required library.

    function / procedure characterization of the complexity of a  

    given function/procedure 

    attribute complexity of my_mult: function is 248; They may be used by synthesizer to choose the  
    optimal functional implementation

    Exercises