Signals are objects that are used to connect concurrent elements (such as components, processes and concurrent assignments), similar to the way that wires are used to connect components on a circuit board or in a schematic. Signals can be declared globally in an external package or locally within an architecture, block or other declarative region.

 

To declare a signal, you write a signal statement such as the following:

 

    architecture arch1 of my_design is

        signal Q: std_logic;

    begin

        . . .

    end arch1;

 

In this simple example, the signal Q is declared within the declaration section of the arch1 architecture. At a minimum, a signal declaration must include the name of the signal (in this case Q) and its type (in this case the standard type std_logic). If more than one signal of the same type is required, multiple signal names can be specified in a single declaration:

 

    architecture arch2 of my_design is

        signal Bus1, Bus2: std_logic_vector(7 downto 0);

    begin

        . . .

    end declare;

 

In the first example above, the declaration of Q was entered in the declaration area of architecture arch1. Thus, the signal Q will be visible anywhere within the arch1 design unit, but it will not be visible within other design units. To make the signal Q visible to the entire design (a global signal), you would have to move the declaration into an external package, as shown below:

 

package my_package is

    signal Q: std_logic;     -- Global signal

end my_package;

. . .

use work.my_package.Q;   -- Make Q visible to the architecture

architecture arch1 of my_design is

begin

    . . .

end arch1;

 

In this example, the declaration for Q has been moved to an external package, and a use statement has been specified, making the contents of that package visible to the subsequent architecture.

 

Signal initialization

In addition to creating one or more signals and assigning them a type, the signal declaration can also be used to assign an initial value to the signal, as shown below:

 

signal BusA: std_logic_vector(15 downto 0) := (others => 'Z');

 

This particular initialization uses a special kind of assignment, called an aggregate assignment, to assign all signals of the array BusA to an initial value of 'Z'. (The 'Z' value is defined in the IEEE 1164 standard as a high-impedence state.)

 

Initialization values are useful for simulation modeling, but they are not recommended for design descriptions that will be processed by synthesis tools. Synthesis tools typically ignore initialization values because they cannot assume that the target hardware will power up in a known state.

 

Using signals

You will use signals in VHDL in two primary ways. First, if you want signals to carry information between different functional parts of your design, such as between two components, you will probably use them in a way similar to the following:

 

library ieee;

use ieee.std_logic_1164.all;

entity shiftcomp is port(Clk, Rst, Load: in std_logic;

                                   Init: in std_logic_vector(0 to 7);

                                   Test: in std_logic_vector(0 to 7);

                                   Limit: out std_logic);

end shiftcomp;

 

architecture structure of shiftcomp is

 

    component compare

        port(A, B: in std_logic_vector(0 to 7); EQ: out bit);

    end component;

 

    component shift

        port(Clk, Rst, Load: in std_logic;

               Data: in std_logic_vector(0 to 7);

               Q: out std_logic_vector(0 to 7));

    end component;

 

    signal Q: std_logic_vector(0 to 7);

 

begin

 

    COMP1: compare port map (Q, Test, Limit);

    SHIFT1: shift port map (Clk, Rst, Load, Init, Q);

 

end structure;

 

This example (described in Chapter 2, A First Look At VHDL) declares the signal Q within the architecture, then uses Q to connect the two components COMP1 and SHIFT1 together.

 

A second way of using signals is demonstrated by the following example in which signals are used within logic expressions and are assigned values directly (in this case within a process):

 

library ieee;

use ieee.std_logic_1164.all;

entity synch is

    port (Rst, Clk, Grant, nSelect: in std_logic;

             Request: out std_logic);

end synch;

 

architecture dataflow of synch is

    signal Q1, Q2, Q3, D3: std_logic;

begin

 

    dff: process (Rst, Clk)

    begin

        if Rst = ‘1’ then

            Q1 <= '0';

            Q2 <= '0';

            Q3 <= '0';

        elsif Clk = ‘1’ and Clk’event then

            Q1 <= Grant;

            Q2 <= Select;

            Q3 <= D3;

        end if;

    end process;

 

    D3 <= Q1 and Q3 or Q2;

    Request <= Q3;

 

end dataflow;

 

This example (which is a simplified synchronizer circuit) uses three signals, Q1, Q2 and Q3, to represent register elements, with the signal D3 being used as an intermediate signal representing a combinational logic function connecting the outputs of registers Q1, Q2 and Q3 to the input of Q3. The final assignment assigns the Q3 register output to the Request output port. The register behavior is encapsulated into a process, dff, simplifying the concurrent statements that follow.

 

It is important to note that there is no significance to the order in which these concurrent statements occur. Like wires drawn between symbols on a schematic, signals assigned and used within a VHDL architecture are independent of each other and are not position dependent.