To help demonstrate some of the important concepts we have covered in the first half of this chapter, we will present a very simple circuit and show how the function of this circuit can be described in VHDL. The design descriptions we will show are intended for synthesis and therefore do not include timing specifications or other information not directly applicable to today’s synthesis tools.

 

This sample circuit combines the comparator circuit presented earlier with a simple 8-bit loadable shift register. The shift register will allow us to examine in detail how higher-level VHDL descriptions can be written for synthesis of both combinational and registered logic.

 

The two subcircuits (the shifter and comparator) will be connected using VHDL’s hierarchy features and will demonstrate the third level of abstraction: structure.

 

This diagram has been intentionally drawn to look like a hierarchical schematic with each of the lower-level circuits represented as blocks. In fact, many of the concepts we will cover during the development of this circuit are the same concepts familiar to users of schematic hierarchy. These concepts include the ideas of component instantiation, mapping of ports, and design partitioning.

In a more structured project environment, you would probably enter a circuit such as this by first defining the interface requirements of each block, then describing the overall design of the circuit as a collection of blocks connected together through hierarchy at the top level. Later, after the system interfaces had been designed, you would proceed down the hierarchy (using a top-down approach to design) and fill in the details of each subcircuit.

 

In this example, however, we will begin by describing each of the lower-level blocks first and then connect them to form the complete circuit.

 

Comparator

The comparator portion of the design will be identical to the simple 8-bit comparator we have already seen. The only difference is that we will use the IEEE 1164 standard logic data types (std_logic and std_logic_vector) rather than the bit and bit_vector data types used previously. Using standard logic data types for all system interfaces is highly recommended, as it allows circuit elements from different sources to be easily combined. It also provides you the opportunity to perform more detailed and precise simulation than would otherwise be possible.

 

The updated comparator design description, using the IEEE 1164 standard logic data types, is shown below:

 

------------------------------

-- Eight-bit comparator

--            

library ieee;        

use ieee.std_logic_1164.all;

entity compare is

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

              EQ: out std_logic);

end compare;

 

architecture compare1 of compare is

begin

    EQ <= ‘1’ when (A = B) else ‘0’;

end compare1;

 

Let’s take a closer look at this simple VHDL design description. Reading from the top of the source file, we see:

 

•  a comment field, indicated by the leading double-dash symbol ("--"). VHDL allows comments to be embedded anywhere in your source file, provided they are prefaced by the two hyphen characters as shown. Comments in VHDL extend from the double-dash symbol to the end of the current line. There is no block comment facility in VHDL.

 

•  a library statement that causes the named library IEEE to be loaded into the current compile session. When you use VHDL libraries, it is recommended that you include your library statements once at the beginning of the source file, before any use clauses or other VHDL statements.

 

•  a use clause, specifying which items from the IEEE library are to be made available for the subsequent design unit (the entity and its corresponding architecture). The general form of a use statement includes three fields delimited by a period: the library name (in this case ieee), a design unit within the library (normally a package, in this case named std_logic_1164), and the specific item within that design unit (or, as in this case, the special keyword all, which means everything) to be made visible.

 

•  an entity declaration describing the interface to the comparator. Note that we have now specified std_logic and std_logic_vector, which are standard data types provided in the IEEE 1164 standard and in the associated IEEE library.

 

•  an architecture declaration describing the actual function of the comparator circuit.

 

Conditional signal assignment

The function of the comparator is defined using a simple concurrent assignment to port EQ. The type of statement used in the assignment to EQ is called a conditional signal assignment.

 

Conditional signal assignments make use of the when-else language feature and allow complex conditional logic to be described. The following VHDL description of a multiplexer makes the use of the conditional signal assignment more clear:

 

architecture mux1 of mux is                

begin

    Y <=  A when (Sel = "00") else

             B when (Sel = "01") else

             C when (Sel = "10") else

             D when (Sel = "11");

end mux1;

 

Selected signal assignment

Another form of signal assignment can be used as an alternative to the conditional signal assignment. The selected signal assignment has the following general form (again, using a multiplexer as an example):

 

architecture mux2 of mux is

begin

    with Sel select

        Y <=   A when "00",

                 B when "01",

                 C when "10",

                 D when "11";

end mux2;

 

Choosing between a conditional or selected signal assignment for circuits such as this is largely a matter of taste. For most designs, there is no difference in the results obtained with either type of assignment statement.  For some circuits, however, the conditional signal assignment can imply priorities that result in additional logic being required. This difference is discussed in detail in the section, Concurrent Statements.

 

Note: In the 1993 version of the VHDL language standard, there is one important difference between the conditional signal assignment and a selected signal assignment that may cause some confusion. In Standard 1076-1993, a conditional assignment statement does not have to include a final, terminating else clause, and the conditions specified do not have to be all-inclusive. When one or more possible input conditions are missing from a conditional assignment, the default behavior under those conditions is for the target signal to hold its value. This means that the conditional assignment statement can be used to effectively create a latch. Some synthesis tools support this use of a conditional signal assignment, while others do not. The best advice: do not write incomplete conditional signal assignments.

 

Shifter (entity)

The second and most complex part of this design is the 8-bit shifter. This circuit accepts 8-bit input data, loads this data into a register and, when the load input signal is low, rotates this data by one bit with each rising edge clock signal. The shift register is provided with an asynchronous reset, and the data stored in the register are accessible via the output signal Q.

 

They are many ways to describe a shifter such as this in VHDL. If you are going to use synthesis tools to process the design description into an actual device technology, however, you must restrict yourself to well established synthesis conventions when entering the design description. We will examine two of these conventions when entering this design.

 

Using a process

The first design description that we will write for this shifter is a description that uses a VHDL process statement to describe the behavior of the entire circuit over time. The process is a behavioral language feature, but its use for synthesis is quite constrained, as we will see in this and later chapters.

 

The VHDL source code for the shifter is shown below:

 

--------------------------------------------------------

-- Eight-bit  shifter

--

library ieee;

use ieee.std_logic_1164.all;

entity rotate is

    port( Clk, Rst, Load: in std_logic;

              Data: in std_logic_vector(0 to 7);

              Q: out std_logic_vector(0 to 7));

end rotate;

 

architecture rotate1 of rotate is

    signal Qreg: std_logic_vector(0 to 7);

begin

    reg: process(Rst,Clk)

    begin

        if Rst = ‘1’ then   -- Async reset

            Qreg <= "00000000";

        elsif (Clk = ‘1’ and Clk’event) then

            if (Load = ‘1’) then

                Qreg <= Data;

            else

                Qreg <= Qreg(1 to 7) & Qreg(0);

            end if;

        end if;

    end process;

    Q <= Qreg;

end rotate1;

 

Let’s look closely at this source file. Reading from the top, we see:

 

•    a comment field, as described previously.

•    library and use statements, allowing us to use the IEEE 1164 standard logic data types.

•    an entity declaration defining the interface to the circuit. Note that the direction (mode) of Q is written as out, indicating that we will not attempt to read its value within this design unit. (If Q was to be used directly as the register, rather than introducing an intermediate signal Qreg, it would need to be of mode inout or buffer.)

•    an architecture declaration, consisting of a single process statement that defines the operation of the shifter over time in response to events appearing on the clock (Clk) and asynchronous reset (Rst).

 

Process statement

The process statement in VHDL is the primary means by which sequential operations (such as registered circuits) can be described. For use in describing registered circuits, the most common form of a process statement is:

 

  architecture  arch_name  of  ent_name  is

  begin

      process_name: process(sensitivity_list)

          local_declaration;

          local_declaration;

          . . .

      begin

          sequential statement;

          sequential statement;

          sequential statement;

          .

          .

          .

      end process;

  end arch_name;

 

A process statement consists of the following items:

 

•    An optional process name (an identifier followed by a colon character).

•    The process keyword.

•    An optional sensitivity list, indicating which signals result in the process being executed when there is some event detected. (The sensitivity list is required if the process does not include one or more wait statements to suspend its execution at certain points. We will look at examples that do not use a sensitivity list later on in this section).

•    An optional declarations section, allowing local objects and subprograms to be defined.

•    A begin keyword.

•    A sequence of statements to be executed when the process runs.

•    an end process statement.

 

The easiest way to think of a VHDL process such as this is to relate it to a small software program that executes (in simulation) any time there is an event on one of the process inputs, as specified in the sensitivity list. A process describes the sequential execution of statements that are dependent on one or more events occurring. A flip-flop is a perfect example of such a situation; it remains idle, not changing state, until there is a significant event (either a rising edge on the clock input or an asynchronous reset event) that causes it to operate and potentially change its state.

 

Although there is a definite order of operations within a process (from top to bottom), you can think of a process as executing in zero time. This means that (a) a process can be used to describe circuits functionally, without regard to their actual timing, and (b) multiple processes can be "executed" in parallel with little or no concern for which processes complete their operations first. (There are certain caveats to this behavior of VHDL processes. These caveats will be described in detail in the section Sequential Statements.)

 

Let’s see how the process for our shifter operates. For your reference, the process is shown below:

 

    reg: process(Rst,Clk)

    begin

        if Rst = ‘1’ then   -- Async reset

            Qreg <= "00000000";

        elsif (Clk = ‘1’ and Clk’event) then

            if (Load = ‘1’) then

                Qreg <= Data;

            else

                Qreg <= Qreg(1 to 7) & Qreg(0);

            end if;

        end if;

     end process;

 

As written, the process is dependent on (or sensitive to) the asynchronous inputs Rst and Clk. These are the only signals that can have events directly affecting the operation of the circuit; in the absence of any event on either of these signals, the circuit described by the process will simply hold its current value (that is, the process will remain suspended).

 

Now let’s examine what happens when an event occurs on either one of these asynchronous inputs. First, consider what happens when the input Rst has an event in which it transitions to a high state (represented by the std_ulogic value of ‘1’). In this case, the process will begin execution and the first if statement will be evaluated. Because the event was a transition to ‘1’, the simulator will see that the specified condition (Rst = ‘1’) is true and the assignment of signal Qreg to the reset value of "00000000" will be performed. The remaining statements of the if-then-elsif expression (those that are dependent on the elsif condition) will be ignored. (The assignment statement immediately following the process, the assignment of output signal Q to the value of Qreg, is not subject to the if-then-elsif expression of the process or its sensitivity list, and is therefore valid at all times.) Finally, the process suspends, all signals that were assigned values in the process (in this case Qreg) are updated, and the process waits for another event on Clk or Rst.

 

What about the case in which there is an event on Clk? In this case, the process will again execute, and the if-then-elsif expressions will be evaluated, in turn, until a valid condition is encountered. If the Rst input continues to have a high value (a value of ‘1’), then the simulator will evaluate the first if test as true, and the reset condition will take priority. If, however, the Rst input is not a value of ‘1’, then the next expression (Clk = ‘1’ and Clk’event) will be evaluated. This expression is the most commonly-used convention for detecting clock edges in VHDL. To detect a rising edge clock, we write the expression Clk = ‘1’ in the conditional expression, just as we did when detecting a reset condition. For this circuit, however, the expression Clk = ‘1’ would not be specific enough, since the process may have begun execution as the result of an event on Rst that did not result in Rst transitioning to a ‘1’. To ensure that the event we are responding to is actually an event on Clk, we use the built-in VHDL attribute ‘event to check if Clk was that signal triggering the process execution.

 

If the event that triggered the process execution was actually a rising edge on Clk, then the simulator will go on to check the remaining if-then logic to determine which assignment statement is to be executed. If Load is determined to be ‘1’, then the first assignment statement is executed and the data is loaded from input Data to the registers. If Load is not ‘1’, then the data in the registers is shifted, as specified, using the bit slice and concatenation operations available in the language.

 

Confusing? Perhaps; but if you simply use the style just presented as a template for describing registered logic and don’t worry too much about the details of how it is executed during simulation, you should be in pretty good shape. Just keep in mind that every assignment to a signal you make that is dependent on a Clk = ‘1’ and Clk’event expression will result in at least one register when synthesized. (More detailed discussions of how flip-flops and latches are generated from synthesis tools can be found in the section Sequential Statements.)

 

Process statements without sensitivity lists

VHDL process statements have two primary forms. The first form uses the sensitivity list described in the previous section and executes during simulation whenever there is an event on any signal in the sensitivity list. This first form of a process statement is the most common (and recommended) method for describing registered sequential logic for the purposes of synthesis.

 

There is another form of process statement that is useful for other applications, however. This form does not include a sensitivity list. Instead, it includes one or more statements that suspend the execution of the process until some condition has been met. The best example of such a process is a test bench, in which a sequence of test inputs are applied over time, with a predefined time value (or external triggering event) defined as the condition for re-activation of the process. The general form of such a process is:

 

  architecture  arch_name  of  ent_name  is

  begin

      process_name: process

          local_declaration;

          local_declaration;

          . . .

      begin

          sequential statement;

          sequential statement;

          wait until (condition);

          sequential statement;

          . . .

          wait for (time);

          . . .

      end process;

  end arch;

 

Examples of this form of process will be examined later in this chapter and in the section Test Benches.

 

VHDL requires that all processes include either a sensitivity list, or one or more wait statements to suspend the process. (It is not legal to have both a sensitivity list and a wait statement.)

 

Concurrent and sequential VHDL

Understanding the fundamental difference between concurrent and sequential statements in VHDL is important to making effective use of the language.

 

Concurrent statements are those statements that appear between the begin and end statements of a VHDL architecture. This area of your VHDL architecture is what is known as the concurrent area. In VHDL, all statements in the concurrent area are executed at the same time, and there is no significance to the order in which the statements are entered.

 

Sequential statements are executed one after the other in the order that they appear between the begin and end statements of a VHDL process, procecure or function.

 

The interaction of concurrent and sequential statements is illustrated in the example below. While the if-elsif-end-if statements in the body of the process are executed sequentially (i.e., one after the other), the body of the process is treated by VHDL as a single concurrent statement and is executed at the same time as all other concurrent statements in the simulation.

 

   architecture rotate2 of rotate is

       signal Qreg: std_logic_vector(0 to 7);

   begin    -- Concurrent section starts here

       reg: process(Rst,Clk)

       begin    -- Sequential section starts here

           if Rst = ‘1’ then -- Async reset

               Qreg <= "00000000";

           elsif (Clk = ‘1’ and Clk’event) then

               if (Load = ‘1’) then

                   Qreg <= Data;

               else

                   Qreg <= Qreg(1 to 7) & Qreg(0);

               end if;

           end if;

       end process;  -- Sequential section ends here

 

      Q <= Qreg;

 

   end rotate2;    -- Concurrent section ends here

 

Note: Writing a description of a circuit using the sequential programming features of VHDL (statements entered within processes and subprograms) does not necessarily mean that the circuit being described is sequential in its operation. Sequential circuits require some sort of internal memory (such as one or more flip-flops or latches) to operate, and a VHDL process or subprogram may or may not imply such memory elements. As we will see in later chapters, it is actually quite common to describe strictly combinational circuits—circuits having no memory and, hence, no sequential behavior—using sequential statements within processes and subprograms.

 

Signals and variables

There are two fundamental types of objects used to carry data from place to place in a VHDL design description: signals and variables. You can use variables to simplify sequential statements (within processes, procedures and functions), but you must always use signals to carry information between concurrent elements of your design (such as between two independent processes).

 

Signals and variables are described in more detail in a later chapter. For now, it is useful to think of signals as wires (as in a schematic) and variables as temporary storage areas similar to variables in a traditional software programming language.

 

In many cases, you can choose whether to use signals or variables to perform the same task. For your first design efforts you should probably stick to using signals, unless you fully understand the consequences of using variables for your particular application.

 

Using a procedure to describe registers

As we have seen from the first version of the 8-bit shifter, describing registered logic using processes requires you to follow some established conventions (if you intend to synthesize the design) and to consider the behavior of the entire circuit. In the shifter design description previously shown, the registers were implied by the placement and use of statements such as if Clk = ‘1’ and Clk’event. Assignment statements subject to that clause resulted in D-type flip-flops being implied for the signals.

 

For smaller circuits, this mixing of combinational logic functions and registers is fine and not difficult to understand. For larger circuits, however, the complexity of the system being described can make such descriptions hard to manage, and the results of synthesis can often be confusing. For these circuits, you might choose to retreat to more of a dataflow level of abstraction and to clearly define the boundaries between registered and combinational logic.

 

One way to do this is to remove the process from your design and replace it with a series of concurrent statements representing the combinational and registered portions of the circuit. You can do this using either procedures or lower-level components to represent the registers. The following VHDL design description uses a register procedure to describe the same shifter circuit previously described:

 

architecture shift3 of shift is

    signal D,Qreg: std_logic_vector(0 to 7);

begin

 

    D <= Data when (Load = ‘1’) else

                  Qreg(1 to 7) & Qreg(0);

 

    dff(Rst, Clk, D, Qreg);

 

    Q <= Qreg;

 

end rotate3;

 

In the shift3 version of the design description above, the behavior of the D-type flip-flop has been placed in an external procedure, dff(), and intermediate signals have been introduced to more clearly describe the separation between the combinational and registered parts of the circuit.

 

In this example, the combinational logic of the counter has been written in the form of a single concurrent signal assignment, while the registered operation of the counter’s output has been described using a call to a procedure named dff.

 

What does the dff procedure look like?  The following is one possible procedure for a D-type flip-flop:

 

procedure dff (signal Rst, Clk: in std_logic;

                        signal D: in std_logic_vector(0 to 7);

                        signal Q: out std_logic_vector(0 to 7)) is

begin

    if Rst = ‘1’ then

        Q <= "00000000";

    elsif Clk = ‘1’ and Clk’event then

        Q <= D;

    end if;

end dff;

 

Warning:  bad code!

The above procedure is actually rather poorly written, as it assumes a specific width (eight bits) for the D and Q parameters. A more flexible and reusable procedure could be written that makes use of attributes (such as ‘length) to determine the actual number of bits of the signals within the procedure.

 

Notice that this procedure has a striking resemblance to the process statement presented earlier. The same if-then-elsif structure used in the process is used to describe the behavior of the registers. Instead of a sensitivity list, however, the procedure has a parameter list describing the inputs and outputs of the procedure.

 

The parameters defined within a procedure or function definition are called its formal parameters. When the procedure or function is executed in simulation, the formal parameters are replaced by the values of the actual parameters specified when the procedure or function is used. If the actual parameters being passed into the procedure or function are signal objects, then the signal keyword can be used (as shown above) to ensure that all information about the signal object, including its value and all of its attributes, is passed into the procedure or function.

 

Using a component to describe registers

It is important to note that if you wish to use procedures to describe your registers, you will need to make sure the synthesis tool you are using allows this. While most VHDL synthesis tools support the use of procedures for registers, some do not, while others have severe restrictions on the use of procedures. If you are not sure, or if you want to have the most portable design descriptions possible, you should replace procedures such as this with components, as in the following example:

 

architecture shift4 of shift is

    component dff

        port(Rst, Clk: std_logic;

                D: in std_logic_vector(0 to 7);

                Q: out std_logic_vector(0 to 7));

    end component;

 

    signal D, Qreg: std_logic_vector(0 to 7);

 

begin

 

    D <= Data when (Load = ‘1’) else

                Qreg(1 to 7) & Qreg(0);

    REG1: dff port map(Rst, Clk, D, Qreg);

    Q <= Qreg;

 

end shift4;

 

An entity and architecture pair describing exactly the same behavior as the dff procedure is shown below:

 

library ieee;

use ieee.std_logic_1164.all;

 

entity dff is

    port (Rst, Clk: in std_logic;

              D: in std_logic_vector(0 to 7);

              Q: out std_logic_vector(0 to 7));

end dff;

 

architecture behavior of dff is

begin

    process (Rst, Clk)

    begin

        if Rst = ‘1’ then

            Q <= "00000000";

        elsif Clk = ‘1’ and Clk’event then

            Q <= D;

        end if;

    end process;

end behavior;

 

Structural VHDL

The structure level of abstraction is used to combine multiple components to form a larger circuit or system. As such, structure can be used to help manage a large and complex design, and structure can make it possible to reuse components of a system in other design projects.

 

Because structure only defines the interconnections between components, it cannot be used to completely describe the function of a circuit; at the lowest level, all components of your system must be described using behavioral and/or dataflow levels of abstraction.

To demonstrate how the structure level of abstraction can be used to connect lower-level circuit elements into a larger circuit, we will connect the comparator and shift register circuits into a larger circuit.

 

Notice that we have drawn this diagram in much the same way you might enter it into a schematic capture system. Structural VHDL has many similarities with schematic-based design, as we will see.

 

Design hierarchy

When you write structural VHDL, you are in essence writing a textual description of a schematic netlist (a description of how the components on the schematic are connected by wires, or nets). In the world of schematic entry tools, such netlists are usually created for you automatically by the schematic editor. When writing VHDL, you enter the same sort of information by hand. (Note: many schematic capture tools in existence today are capable of writing netlist information in the form of a VHDL source file. This can save you a lot of time if you are used to drawing block diagrams in a schematic editor.)

 

When you use components and wires (signals, in VHDL) to connect multiple circuit elements together, it is useful to think of your new, larger circuit in terms of a hierarchy of components. In this view, the top-level drawing (or top-level VHDL entity and architecture) can be seen as the highest level in a hierarchy.

 

In this example, we have introduced a new top-level component (called shiftcomp) that references the two lower-level components shift and compare. Because the new shiftcomp design entity can itself be viewed as a component, and considering the fact that any component can be referenced more than once, we quickly see how very large circuits can be constructed from smaller building blocks.

 

The following VHDL source file describes our complete circuit using structural VHDL statements (component declarations and component instantiations) to connect together the compare and shift portions of the circuit:

 

library ieee;

use ieee.std_logic_1164.all;

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

                                   Init: in std_ulogic_vector(0 to 7);

                                   Test: in std_ulogic_vector(0 to 7);

                                   Limit: out std_ulogic);

end shiftcomp;

 

architecture structure of shiftcomp is

 

    component compare

        port(A, B: in std_ulogic_vector(0 to 7); EQ: out std_ulogic);

    end component;

 

    component shift

        port(Clk, Rst, Load: in std_ulogic;

               Data: in std_ulogic_vector(0 to 7);

               Q: out std_ulogic_vector(0 to 7));

    end component;

 

    signal Q: std_ulogic_vector(0 to 7);

 

begin

 

    COMP1: compare port map (A=>Q, B=>Test, EQ=>Limit);

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

 

end structure;

 

Note: In the above context, the VHDL symbol => is used to associate the signals within an architecture to ports defined within the lower-level component.

 

There are many ways to express the interconnection of components and to improve the portability and reusability of those components. We will examine these more advanced uses of components in a later chapter.

 

Test benches

At this point, our sample circuit is complete and ready to be processed by a synthesis tool. Before processing the design, however, we should take the time to verify that it actually does what it is intended to do, by running a simulation.

 

Simulating a circuit such as this one requires that we provide more than just the design description itself. To verify the proper operation of the circuit over time in response to input stimulus, we will need to write a test bench.

 

The easiest way to understand the concept of a test bench is to think of it as a virtual circuit tester. This tester, which you will describe in VHDL, applies stimulus to your design description and (optionally) verifies that the simulated circuit does what it is intended to do.

 

To apply stimulus to your design, your test bench will probably be written using one or more sequential processes, and it will use a series of signal assignments and wait statements to describe the actual stimulus. You will probably use VHDL’s looping features to simplify the description of repetitive stimulus (such as the system clock), and you may also use VHDL’s file and record features to apply stimulus in the form of test vectors.

 

To check the results of simulation, you will probably make use of VHDL’s assert feature, and you may also use the text I/O features to write the simulation results to a disk file for later analysis.

 

For complex design descriptions, developing a comprehensive test bench can be a large-scale project in itself. In fact, it is not unusual for the test bench to be larger and more complex than the underlying design description. For this reason, you should plan your project so that you have the time required to develop the test bench in addition to developing the circuit being tested. You should also plan to create test benches that are re-usable, perhaps by developing a master test bench that reads test data from a file.

 

When you create a test bench for your design, you use the structural level of abstraction to connect your lower-level (previously top-level) design description to the other parts of the test bench.

 

Sample test bench

The following VHDL source statements, with explanatory comments, describe a simple test bench for our sample circuit:

 

library ieee;

use ieee.std_logic_1164.all;

 

entity testbnch is      -- No ports needed in a

end testbnch;        -- testbench    

 

use work.shiftcomp;

architecture behavior of  testbnch is

    component shiftcomp is    -- Declares the lower-level

        port(Clk, Rst, Load: in std_logic;  -- component and its ports

                Init: in std_logic_vector(0 to 7);

                Test: in std_logic_vector(0 to 7);

                Limit: out std_logic);

    end component;

    signal Clk, Rst, Load: std_logic;  -- Introduces top-level signals

    signal Init: std_logic_vector(0 to 7);  -- to use when testing the

    signal Test: std_logic_vector(0 to 7);  -- lower-level circuit

    signal Limit: std_logic;

begin

    DUT: shiftcomp port map    -- Creates an instance of the

        (Clk, Rst, Load, Init, Test, Limit);  -- lower-level circuit (the

          -- unit under test)

    clock: process

        variable clktmp: std_logic := ‘0’;  -- This process sets up a

    begin        -- background clock of 100 ns

        clktmp := not clktmp;    -- period.

        Clk <= clktmp;

        wait for 50 ns;

    end process;

 

    stimulus: process      -- This process applies

    begin        -- stimulus to the design

        Rst <= ‘0’;        -- inputs, then waits for some

        Load <= ‘1’;      -- amount of time so we can

        Init <= "00001111";      -- observe the results during

        Test <= "11110000";    -- simulation.

        wait for 100 ns;

        Load <= ‘0’;

        wait for 600 ns;

    end process;

end behavior;

 

More advanced applications of test benches can be found in the section Test Benches.