Sei sulla pagina 1di 82

VHDL for Synthesis

Dr T D Binnie 2010

Copyright: 2010 David Binnie, All Rights Reserved 2

Contents
1
1a. 1b.

Introduction
Background..................................................................................................................... 7 Key Features.................................................................................................................. 8

2. 3.
3a. 3b

VHDL Levels of Abstraction Basic Structure of a VHDL file


Structure ..................................................................................................................... 13 VHDL Keywords........................................................................................................... 14

9 13

4.

Entities and Architectures


4a. 4b. 4d. 4e. 4f 4g.

15

Entities ......................................................................................................................... 15 Architectures.............................................................................................................. 18 A Complete VHDL (behavioural) Example ............................................................ 21 Concurrent and Sequential Statements ............................................................... 23 Further examples of entity-architecture pairs ................................................ 24 Structural VHDL........................................................................................................ 25

5.
5a. 5b. 5c.

Data Objects: Signals, Variables and Constants

27

Constants..................................................................................................................... 27 Variables...................................................................................................................... 28 Signals .......................................................................................................................... 29

6.
6a. 6b. 6c. 6d.

Concurrent Statements

31

Simple Concurrent Signal Assignments. ................................................................ 31 Conditional Signal Assignments.............................................................................. 31 Selected Signal Assignments ................................................................................ 37 Tristate Output ......................................................................................................... 39

7.
7a. 7b. 7c. 7d.

Sequential Modelling

41

Process.......................................................................................................................... 41 If - then - else statement....................................................................................... 47 Case statement ........................................................................................................... 51 Multiple Processes..................................................................................................... 53

8.
8a. 8b

VHDL State Machines

55

Example of a Moore Machine.................................................................................. 55 FSM: Two Process Style .......................................................................................... 57

9. 10.

Additional VHDL Notes and Examples Structural Modelling

59 63

10a. Component declaration ............................................................................................. 64 10b. Component Instantiation and Interconnections ................................................. 65

11.
11a. 11b. 11c

Writing Test Benches

71

Introduction ................................................................................................................ 71 Testbench Structure................................................................................................ 74 Test Bench Example.................................................................................................. 76

Index of Code Examples


Example 1: Behavioural VHDL ........................................................................................................... 9 Example 2: Structural VHDL .......................................................................................................... 10 Example 3: Register Transfer Level VHDL .................................................................................. 11 Example 4: Logic Circuit Entity Declaration ............................................................................... 16 Example 5 a,b,& c: Entity Declarations ........................................................................................ 17 Example 6: Buzzer Circuit Architecture...................................................................................... 18 Example 7: Buzzer circuit with internal signals ......................................................................... 19 Example 8: AND Gate....................................................................................................................... 21 Example 9: XNOR Gate ....................................................................................................................22 Example 10: Concurrent VHDL: when-else...................................................................................24 Example 11: Sequential VHDL: if-then-else.................................................................................24 Example 12: Structural VHDL.........................................................................................................25 Example 13: Concurrent Conditional Assignment ....................................................................... 31 Example 14: 4-to-1 Multiplexor using when-else ........................................................................32 Example 15: 4-to-1 Bus Multiplexor ..............................................................................................33 Example 16: Compound Selection Statement ..............................................................................33 Example 17: 8-to-3 Priority Encoder ............................................................................................35 Example 18: Priority Encoder..........................................................................................................35 Example 19: std_logic_vector - Addition and Subtraction......................................................36 Example 20: 4-to-1 MUX using with-select-when ......................................................................37 Example 21: Arithmetic Unit ..........................................................................................................38 Example 22: Tri-State Buffer .......................................................................................................39 Example 23: D Flip-flop using if-else............................................................................................43 Example 24: D Flip-flop using wait ................................................................................................44 Example 25: D Flip-flop with asynchronous reset .....................................................................45 Example 26: Clocked Sequential Assignment ..............................................................................46 Example 27 MUX using if-else in a process ................................................................................47 Example 28: 4 Bit up-counter with asynchronous reset...........................................................48 Example 29: Generic Register ........................................................................................................49 Example 30: 8-Bit Shift Register..................................................................................................50 Example 31: MUX using case statement....................................................................................... 51 Example 32: Registered ALU using case ......................................................................................52 Example 33: Two Processes - Full Adder .....................................................................................53 Example 34: Direct state assignment...........................................................................................55 Example 35: Sequence Detector (101) Moore Model ................................................................56 Example 36: FSM clock process.....................................................................................................57 Example 37: FSM State transitions (011 detector).................................................................58 Example 38: 32 x 4 ROM .................................................................................................................59 Example 39: 16 x 8 RAM ..................................................................................................................60 Example 40: Shift Register using loop statement ..................................................................... 61 Example 41: One's Counter .............................................................................................................62 Example 42: Component declarations............................................................................................64 Example 43: port map statement...................................................................................................65 Example 44: Top level structural code for one's counter .......................................................68 Example 45: Component level of one's counter ..........................................................................69 Example 46: VHDL Test Bench.......................................................................................................76 Example 47: Simplified CHECK procedure...................................................................................77 Example 48: Test Bench for BUZZER circuit.............................................................................77

Introduction
1a. Background
VHDL is a language that was developed during the 1970s to describe and model complex digital circuits and systems. VHDL is an acronym: the V stands for VHSIC (Very High Speed Integrated Circuit) and the HDL stands for Hardware Description Language. It is only recently that manufacturers of programmable logic devices have produced software which allows the VHDL descriptive code to be synthesised into to an actual digital circuit. This translation from software code into hardware is called digital synthesis. Synthesis is the process which translates VHDL, which is just abstract code, into a digital circuit. Designers must be aware that VHDL is primarily a descriptive language and not all VHDL code can be synthesised. In this book we will concentrate on VHDL for synthesis. Although VHDL looks similar to conventional programming languages like C or Pascal, there are some important differences. A hardware description language is inherently parallel, i.e. commands, which correspond to logic gates, are executed (computed) in parallel, as soon as a new input arrives. A HDL program emulates the behaviour of a physical digital system. It can also be used to describe digital systems as hierarchy of logic components.

architecture RTL of mux_gate is begin process (SEL,A,B,C,D,E) begin case SEL is when "000" => SIG <= A; when "001" => SIG <= B; when "010" => SIG <= C; when "011" => SIG <= D; when others => SIG <= E; end case; end process; end RTL;

Synthesis

Figure 1: Circuit Synthesis

This book was written as a very simple introduction to VHDL for students who want to get quickly to circuit design and synthesis. Some knowledge of digital electronics is assumed. The next section shows how VHDL can be used to simply define connectivity between components or as an abstract description language. In Section 3, the structure of a VHDL module is introduced. This is followed in Section 4 by a quick overview of VHDL coding using concurrent and sequential statements. Sections 5 gives an important introduction to Data Objects - signals variables and constants - in VHDL. More detailed VHDL examples and a discussion of concurrent and sequential modelling follow in Sections 6 and 7. Section 8 gives examples of coding sequential state machines. Section 9 has tested examples of synthesisable code for a range of digital components. Section 10 gives examples of port mapping and structural code. Lastly Section 11 gives details of VHDL testbenches.

1b.

Some Key Features

<= is the signal assignment operator. e.g. A <= B; means that signal B is assigned the value of signal A; Signal assignments are concurrent statements. The order in which assignment statements are executed cannot be fixed. When a signal on the right changes its value then the statement is executed. Thus an event on one signal will lead to an event on another. Sequential events on the other hand are described using a process statement. Within a process, the statements are executed sequentially. All signal values in a process are updated at the same time. Comment Lines start with two dashes: -- comments VHDL is not case sensitive: 'ABCD' is the same as 'abcd'.

2.

VHDL Levels of Description


A digital system can be represented at different levels of abstraction. This keeps the description and design of complex systems manageable. The simplest description of a digital circuit in VHDL is to define an output assignment in terms of Boolean logic functions. e.g. F <= (A or B) and C; Example 1: Simple Gate Level Description A higher level of abstraction is called the behavioural level which describes a system in terms of what it does or how it behaves - like an algorithm. (rather than a description in terms of its components and interconnection between them.) e.g.

F <= 1 when (C =1 and (A=1 or B=1)) else 0;

Example 2: Behavioural VHDL These two pieces of VHDL code would actually synthesise the same circuit, shown in Figure 2.

A B C

OR AND F

Figure 2: Example of a digital logic circuit.

A behavioural description specifies the relationship between the input and output signals. This could be an algorithmic description or a less abstract Boolean expression. The above example is a very simple circuit. The code is a behavioural level description of a logic operation. This type of description is at the highest level of abstraction from gate level. This code contains no timing or structural information.

The structural level of description, on the other hand, describes a system as a collection of gates and components that are interconnected to perform a desired function. A structural description is like a circuit net list and can be compared to a schematic of interconnected logic gates.

signal X: bit; begin Gate1: OR_comp port map (A, B, X); Gate2: AND_comp port map (C, X, F); end;

Example 3: Structural VHDL

Example 3 is a structural level description of the logic circuit in Figure 2. This type of description is at the lowest level of abstraction. This code simply defines the connections between basic logic gates or other components. VHDL allows the description of digital systems both at the behavioural level and the structural level or a mix of both. Behavioural levels description can be further divided into two styles: algorithmic and dataflow (also termed Register Transfer Level - RTL). The algorithmic description is specified in terms of computational steps, whereas the dataflow-RTL representation describes how data moves between registers though a system. RTL is used predominantly in sequential systems.

logic

reg

logic

reg

Figure 3: RTL - Dataflow

10

process(clock) begin if rising_edge (clock) then if (C =1 and (A=1 or B=1)) then F <="00000001" else F <= "10000000"; end if; end if; end process;

Example 4: Register Transfer Level VHDL Example 4 is a simple RTL representation of a circuit. This description contains functional and timing information. The logic for the register F is clearly defined; the output will change on the clock edge. At the RTL level, a description details the behavioural of a sequential design at the clock-cycle level.

More Abstract

Behavioural Architecture

Model does not represent internal structure only functionality

Dataflow (RTL) Architecture

Model gives timing and some detail of internal architecture but does not use sub components Model describes the components and connections to make the functionality

More Detailed

Structural Architecture

Figure 4: Levels of Description

These notes are about writing VHDL for the synthesis of digital circuitry. To do this successfully, we write behavioural code at RTL level. When designing larger circuits with VHDL it is important to consider hierarchy and coding style. Using vendor advised coding styles will produce a more effective and efficient implementation.

11

12

3.

Basic Structure of a VHDL file


3a. Structure
A VHDL design consists of a design entity. The entity, often called a module, consists of an entity declaration and an architecture body. The entity declaration represents the interface and defines the input and output signals. The architecture body contains the behavioural or structural description of the entity. A VHDL entity can be hierarchical and contain other VHDL entities that are components of the top-level entity. In a typical design there will be many such entities connected together to perform the desired function.

VHDL Module
Libraries Entity
( Interface: Input and Output Ports )

Architecture
( Combinational Description and Sequential Processes, Subprograms )

Figure 5: Structure of a VHDL Module

13

3b

VHDL Keywords

abs access after alias all and architecture array assert attribute begin block body buffer bus case component configuration constant disconnect

downto else elsif and entity exit file for function generate generic group guarded if impure in inertial inout is

label library linkage literal loop map mod nand new next nor null of on open others out package

port postponed procedure process pure range record register reject rem report return ror rol select severity shared signal sla sll sra

srl subtype then to transport type units unaffected until use variable wait when while with xor xnor

Notes

VHDL uses reserved keywords which cannot be used as signal names or identifiers. Keywords and user-defined identifiers are case insensitive. Lines with comments start with two adjacent hyphens (--) and are ignored by the compiler. VHDL also ignores line breaks and extra spaces. VHDL is a strongly typed language which means that the type of signals always has to be declared.

14

4.

Entities and Architectures


4a. Entities
The entity declaration defines the NAME of the VHDL module and lists the input and output ports.

entity NAME is port ( signal_names: mode type; ); end NAME ;

An entity always starts with the keyword entity, followed by its NAME and the keyword is. Next are the port declarations using the keyword port. An entity declaration always ends with the keyword end, optionally followed by the name of the entity. The signal_names consists of a comma separated list of one or more user-selected identifiers that specify external interface signals. Followed by the signal mode - a reserved word to indicate the signal direction: in, out or inout. Then a built-in signal type: bit, std_logic etc.

Notes

Xilinx ISE Tools have an HDL Design Wizard (which pops up when a new HDL module is to be written.) This wizard writes the VHDL entity declaration for the designer when the user enters the number and name of input and output ports. The component entity declaration then appears in the new VHDL script. It is still important to understand the entity declaration as it may need to be edited later if changes to the design are made.

15

For the example of Figure 2 above, the entity declaration looks as follows.

entity Logic is port (A, B, C: in std_logic; F: out std_logic); end Logic;

Example 2: Logic Circuit Entity Declaration

The entity name is Logic and the entity has three input ports: A, B and C and one output port: F. Notice the use and placement of semicolons. Note that VHDL is not case sensitive.

Each port has to have a mode (in, out or inout) and a defined type. In this case, the std_logic type. This is the preferred type of digital signals. The simplest type is the bit type that can only have the values '1' and '0', The std_logic type signals can have nine values. As we will appreciate later, this is important to describe a digital hardware system accurately. The std_logic type is defined in the std_logic_1164 package within in the IEEE library.

16

Here are a few other examples of entity declarations: An example of the entity declaration of a D flip-flop with set and reset inputs is

entity dff_sr is port (D, CLK, S, R: in std_logic; Q, Qnot: out std_logic); end dff_sr;

An example of the entity declaration for a 4 bit counter with enable, reset and clock inputs entity count4 is port ( reset: in std_logic; enable: in std_logic; clock: in std_logic; count: inout std_logic_vector (3 downto 0) ); end count4;

Four-to-one multiplexer of which each input is an 8-bit word and is a std_logic_vector type.

entity mux4_to_1 is port ( In0,In1,In2,In3: in std_logic_vector(7 downto 0); Out1: out std_logic_vector(7 downto 0));

end mux4_to_1;

Example 3 a,b,& c: Entity Declarations

17

4b.

Architectures
The architecture body specifies how the circuit operates and how it is structured. A circuit can be specified in a variety of ways, such as behavioural or structural, or a combination of the both. The form of an architecture body is shown below:

architecture architecture_name of NAME_OF_ENTITY is -- Declarations -- components declarations -- internal signal declarations -- type declarations begin -- VHDL statements; end architecture_name;

The architecture body for a simple car alarm circuit, described at the behavioural level, is given below,

architecture behavioural of Buzzer is begin WARNING <= (not DOOR and IGNITION) or (not SBELT and IGNITION); end behavioural;

Example 4: Buzzer Circuit Architecture The header line of the architecture body defines the architecture name, e.g. behavioural, and associates it with the entity, BUZZER. Note, the name: behavioural is not a reserved word. The main body of the architecture starts with the keyword, begin and gives the Boolean expression of the function.

18

Importantly, the ' <= ' symbol represents an assignment operator. This assigns the value of the expression on the right to the signal on the left. It does not mean 'equal to'. It cannot be reversed. The architecture body ends with an end keyword followed by the architecture name. More examples are shown in the next section.

Not all signals needs be ports of the module. Internal signals can be declared in the architectures before the begin.

DOOR

B1 WARNING
B2

IGNITION

SEATBELT

Figure 6: Buzzer Circuit Schematic with internal nodes

Here is a car alarm circuit with internal nodes labelled as signals: B1 and B2.

architecture behavioral of Buzzer is signal B1, B2: std_logic; begin B1 <= not door and ignition; B2 <= not seatbelt and ignition; warning <= B1 or B2; end behavioral;

Example 5: Buzzer circuit with internal signals

19

4c.

Libraries and Packages

The VHDL design entity for the circuit shown above circuit will not compile without access to a library. A VHDL package is a file in a library that contains declarations (not the definition) of commonly used objects, data types, component declarations, signals, procedures and functions that can be shared among different VHDL designs. The std_logic type is defined in the ieee.std_logic_1164 package in the ieee library. In order to use the std_logic one needs to specify the library and package. This must be done at the beginning of the VHDL file, before the entity declaration, using the library and the use keywords as follows:

library ieee; use ieee.std_logic_1164.all ;

Notes

The Xilinx HDL design wizard will automatically insert the available package and library lines for the VHDL module. You can write your own package to access commonly used components, and access it using a statement such as:
use work.my_package.all;

The package and the component definitions must be compiled into the local work directory.

20

4d.

A Complete VHDL (behavioural) Example


A few compilable, synthesisable behavioural examples follow. The behavioural description of a two-input AND gate is shown below. This example shows the entity and library declarations and the architecture body. It uses one of the standard libraries and packages available to the VHDL compiler.

library ieee; use ieee.std_logic_1164.all; entity AND2 is port (in1, in2: in std_logic; out1: out std_logic); end AND2; architecture behavioral_2 of AND2 is begin out1 <= in1 and in2; end behavioral_2;

Example 6: AND Gate This is a complete piece of VHDL code which can be compiled and synthesised and downloaded on to an FPGA. The behavioural logic in the code is written using the logical and operator. The basic logic functions for the bit type are generic but logic functions for the std_logic type are defined in the ieee library.

Notes

21

A further example of a two-input XNOR gate is shown below. library ieee; use ieee.std_logic_1164.all; entity name

entity XNOR2 is port (A, B: in std_logic; Z: out std_logic); end XNOR2; architecture behavioural of XNOR2 is -- signal declaration (of internal signals X, Y) signal X, Y: std_logic; begin X <= A and B; Y <= (not A) and (not B); Z <= X or Y; end behavioural; architecture name

Example 7: XNOR Gate

Notes

The statements in the body of the architecture make use of logic operators. The allowed logic operators are: and, or, nand, nor, xor, xnor and not. In addition, other types of operators are allowed including relational, shift, and arithmetic operators.

22

4e.

Concurrent and Sequential Statements

It is worth noting that the signal assignments in the above examples are concurrent statements. This means that the statements are executed only when one or more of the signals on the right hand side change their value (i.e. an event occurs on one of the signals). For instance, when the input A changes, the internal signals X and Y change values that in turn causes the last statement to update the output Z. There may be a propagation delay associated with this change. The logic described is asynchronous combinational logic. Digital systems are basically datadriven and an event which occurs on one signal will lead to an event on another signal, etc. The execution of the statements is determined by the flow of signal values. Not the order in which they are written (The order in which these statements are written does not matter!) This is in sharp contrast to conventional, software programs that execute the statements in a sequential or procedural manner. The programs you have looked at already are simple logic statements. It is also straight forward to use a conditional signal assignment in concurrent VHDL. To do this we use the when else selection statement. In the example shown on the following page, you can see that the output Y is assigned the value of 1 depending on the values of inputs A, B and C.

(For more on Concurrent Modelling see Section 6 )

Where sequential operation is required in a VHDL module then a process statement must be used within the architecture. The process is a piece of code within the architecture where the order of execution of the statements is sequential. This is the most common form of logic design and is covered in detail in the next section. There is an example following which implements the same logic as the concurrent logic above it but it is written using the if then else selection statement.

(For more on Sequential Modelling see Section 7 )

23

4f

Further examples of entity-architecture pairs


Concurrent Selection Statement: when-else library ieee; use ieee.std_logic_1164.all; entity logic1 is port (A : in std_logic; B: in std_logic; C: in std_logic; Y: out std_logic); end logic1; architecture dataflow of logic1 is begin Y <= '1' when (A='0' and B = '0' ) or C='0' else '0'; end dataflow;

Example 8: Concurrent VHDL: when-else Sequential Selection Statement: if then - else library ieee; use ieee.std_logic_1164.all; entity logic2 is port (A : in std_logic; B: in std_logic; C: in std_logic; Y: out std_logic); end logic2; architecture behavioral of logic2 is begin process (A,B,C) begin if (A='0' and B = '0') then Y <= '1'; elsif C = '1' then Y <= '1'; else Y <= '0'; end if; end process; end behavioral;

Example 9: Sequential VHDL: if-then-else

24

4g.

Structural VHDL
Structural VHDL is just a netlist of connection and is usually at the top level of a VHDL design. It can replace a schematic. In fact Xilinx ISE toolscan generate a schematic from any structural description. Here is a simple example of structural VHDL code. It is representative of a netlist connecting basic logic components.

architecture structural of BUZZER2 is -- Component declarations component AND2 port (in1, in2: in std_logic;out1: out std_logic); end component; component OR2 port (in1, in2: in std_logic;out1: out std_logic); end component; component NOT1 port (in1: in std_logic;out1: out std_logic); end component; -- declaration of signals used to interconnect gates signal DOOR_NOT, SEATBELT_NOT, B1, B2: std_logic; begin -- Component instantiations statements U0: NOT1 port map (DOOR, DOOR_NOT); U1: NOT1 port map (SEATBELT, SEATBELT_NOT); U2: AND2 port map (IGNITION, DOOR_NOT, B1); U3: AND2 port map (IGNITION, SEATBELT_NOT, B2); U4: OR2 port map (B1, B2, WARNING); end structural;

component declarations

internal signal declarations

component connections

Example 10: Structural VHDL Following the header is the component declaration part that gives the components (in this case: gates) that are going to be used in the description of the circuits. In our example, we use a two- input AND gate, two-input OR gate and an inverter. The function of the components is defined in another vhdl module. The components can be stored in one of the packages that are referred to in the header of the file. The declarations for the components give the inputs (in1, in2) and the output (out1). Next, the internal nets (signal names) are defined. In our example these signals are called DOOR_NOT, SEATBELT_NOT, B1, B2.

25

The statements after the begin keyword gives the instantiations of the components and describes how these are interconnected. Each line starts with an instance name (e.g. U0) followed by a colon and a component name and the keyword port map. This keyword defines how the components are connected. In the example above, this is done through positional association. DOOR corresponds to the input, in1 of the NOT1 gate and DOOR_NOT to the output. Similarly, for the AND2 gate where the first two signals (IGNITION and DOOR_NOT) correspond to the inputs in1 and in2, respectively, and the signal B1 to the output out1.

(For Structural Modelling see Section 10 )

NOT1 DOOR AND1 B1 OR2 IGNITION NOT2 SEATBELT AND2 B2 WARNING

Figure 7 : Schematic of Structural Code

26

5.

Data Objects: Signals, Variables and Constants


A data object is created by an object declaration and has a value and type associated with it. A data object can be a Constant, Variable, or a Signal. Signals are used as input ports, output ports or internal nets. Signals represent nets in a circuit and as such can have current and future values. Variables and Constants are an abstract number representation and are used to model the behaviour of a circuit. Variables can only be used in processes, procedures and functions. Variables are translated into signals during synthesis.

5a.

Constants
A constant can have a single value of a given type and cannot be changed during the simulation. A constant is declared as follows, constant list_of_name_of_constant: type [ := initial value] ; where the initial value is optional. Constants can be declared at the start of an architecture and can then be used anywhere within the architecture. Constants declared within a process can only be used inside that specific process.

constant state1: std_logic vector := "001"; constant rise_time: time:= 2 ns; constant data_bus_width: integer:= 16;

27

5b.

Variables
Variables can only be used inside a process. A variable can have a single value, as with a constant, but a variable can be updated using a variable assignment statement. The variable is updated without any delay as soon as the statement is executed. The variable declaration is as follows:

variable list_of_variable_names: type [ := initial value] ;

For example: variable test: boolean :=FALSE; variable result: integer range 0 to 256 :=16; variable count: bit_vector (7 downto 0);

The variable result, in the example above, is an integer that has a range from 0 to 256 with initial value of 16 at the start of the simulation. A variable can be updated using a variable assignment statement such as variable_name := expression;

Note: Care must be taken when variables are used in code which is to be synthesised. Variables are updated earlier than signals. This means that the synthesised circuit will be different to one which uses signals.

28

5c.

Signals
Signals are declared with the following statement: signal list_of_signal_names: type [ := initial value] ; For example: signal sum, carry: std_logic; signal address: integer :=0; signal data_bus: std_logic_vector (0 downto 7); signal temp: integer range 0 to 100;

Signals are updated when their signal assignment statement is executed, after a certain delay, as shown below, sum <= ( A xor B ); One can also specify multiple waveforms using multiple events as illustrated below, signal wavefrm : std_logic; wavefrm <= '0', '1' after 5ns, '0' after 10ns, '1' after 20 ns; Time values in signal assignment statements are not synthesisable but can be used in test benches. Signal initial values are also ignored in synthesis. It is important to understand the difference between variables and signals, particularly how it relates to when their value changes: A variable changes instantaneously when the variable assignment is executed, whereas a signal changes a delay after the assignment expression is evaluated. If no delay is specified, the signal will change after a 'delta delay'. Signals used in a process have implicit memory. A process is a queue of statements in time order. This is significant as it means that when a signal is assigned a value it only takes this value at some later point in time - even if there is no stated delay. This zero time delay is called delta delay. The actual delay will be determined by the implementation logic. In a process all signal values in the process are updated at the end of the process whereas variable values are updated instantaneously.

Note: If you are new to VHDL, in the first instance, use signals only.

29

30

6.

Concurrent Statements
In this section, we will use concurrent statements to describe behaviour. This method is usually called data flow modelling. The data flow modelling describes a circuit in terms of its function and the flow of data, between registers, through the circuit. Concurrent signal assignments are event triggered and executed as soon as an event on one of the signals occurs.

6a.

Simple Concurrent Signal Assignments.


We have discussed several concurrent examples earlier in the tutorial. In this section we will review the different types of concurrent signal assignments. A simple concurrent signal assignment using Boolean logic is given in the following examples:

Sum <= (A xor B) xor Cin; Carry <= (A and B); Z <= (not X) or Y after 2 ns;

Example 11: Concurrent Conditional Assignment

As soon as an event occurs on one of the signals, the expression will be evaluated. The type of the target signal has to be the same as the type of the value of the expression. Statements like "after 2ns" can be used for modelling but cannot be synthesised.

6b.

Conditional Signal Assignments


The syntax for the conditional signal assignment is as follows:

signal <= expression when condition else expression when condition else expression; The target signal will receive the value of the first expression whose Boolean condition is TRUE. If no condition is found to be TRUE, the target signal will receive the value of the final expression. If more than one condition is true, the value of the first condition that is TRUE will be assigned.

31

An example of a four-to-one multiplexor using conditional signal assignments is shown below:

S0 S1

A B C D

MUX output

input ABCD

SELECT 0 0 0 1 1 0 1 1

output A B C D

Figure 8: 4-to-1 Multiplexor

entity MUX_4a is port (S1, S0, A, B, C, D: in std_logic; Z: out std_logic); end MUX_4a; architecture concurrent of MUX_4a is begin Z <= A when S1='0' and S0='0' else B when S1='0' and S0='1' else C when S1='1' and S0='0' else D; end concurrent;

Example 12: 4-to-1 Multiplexor using when-else The conditional signal assignment will be re-evaluated as soon as any of the signals in the conditions or expression change. The when-else construct is useful to express logic function in the form of a truth table.

32

An example of the same multiplexer as above is given below in a more compact form. entity MUX_4b is port (A, B, C, D: in std_logic; SEL: in std_logic_vector (1 downto 0); Z: out std_logic); end MUX_4b; architecture concurrent of MUX_4b is begin Z <= A when SEL = "00" else B when SEL = "01" else C when SEL = "10" else D; end concurrent;

Example 13: 4-to-1 Bus Multiplexor The condition in a selection statement can be a compound condition as shown in the next example of a four-to-one bus multiplexor. A bus in VHDL is, as we have seen, described as a vector. The width of the bus (the number of signals) is defined in the brackets after the port or signal declaration. As binary numbers start with the Most Significant Bit (MSB) the vectors are usually written (X downto 0) where X is the value of the bus width minus 1. (downto is a key word.)

library ieee; use ieee.std_logic_1164.all; entity MUX_4c is port(in0, in1, in2, in3 : in std_logic_vector(7 downto 0); s0, s1 : in std_logic; z : out std_logic_vector(7 downto 0)); end MUX_4c; architecture imp of MUX_4c is begin z <= in0 when (s0 = 0 and s1 = 0) else in1 when (s0 = 1 and s1 = 0) else in2 when (s0 = 0 and s1 = 1) else in3 when (s0 = 1 and s1 = 1) else "XXXXXXXX"; end imp;

Example 14: Compound Selection Statement

33

Notes

The when-else statement does not have semicolons after the 'else'. The numerical values of vectors are contained within double quotes. The concurrent construct is simpler than the sequential if-then-else construct within a process statement.

34

Here is the truth table of a 8 Bit Priority Encoder. The input is an 8 bit bus, illustrated here as bit B7 downto B0. The output, F, a 3 bit bus, simply gives the position of the '1' on the input vector as a binary number: 8 bit INPUT B7 B6 B5 B4 B3 B2 B1 B0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 B7 B6 B5 B4 B3 B2 B1 B0 Priority Encoder 3 bit OUTPUT 2 0 0 F2 F1 F0 0 0 1 1 1 1
2

2 0 0 1 1 0 0 1 1

2 0 1 0 1 0 1 0 1

Example 15: 8-to-3 Priority Encoder

VHDL code for the priority encoder is shown below: library ieee; use ieee.std_logic_1164.all; entity priority is port ( B : in std_logic_vector(7 downto 0); F : out std_logic_vector(2 downto 0)); end priority; architecture imp of priority is begin F <= "000" when B(0) = 1 else "001" when B(1) = 1 else "010" when B(2) = 1 else "011" when B(3) = 1 else "100" when B(4) = 1 else "101" when B(5) = 1 else "110" when B(6) = 1 else "111" when B(7) = 1 else "---"; -- output is a "dont care" end imp;

Example 16: Priority Encoder

35

The last example of the conditional selection statement when-else shows how easy it is to use VHDL to carry out simple arithmetic operations.

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity addsub is port ( A, B : in std_logic_vector(7 downto 0); ADSUB : in std_logic; RES : out std_logic_vector(7 downto 0)); end addsub; architecture imp of addsub is begin RES <= A + B when ADSUB = 1 else A - B; end imp;

Example 17: std_logic_vector - Addition and Subtraction

Note that for this arithmetic operation to work on a std_logic_vector, the library ieee.std_logic_unsigned.all; must be included.

36

6c.

Selected Signal Assignments


The selected signal assignment, with-select-when, is similar to the conditional one described above but is easier to use when there are multiple choices. The syntax is as follows:

with choice_expression select target_name <= expression when choice, target_name <= expression when choice, target_name <= expression when choice;

The target is a signal that will receive the value of an expression whose choice includes the value of the choice expression. The expression selected is the first with a matching choice. The choice can be static (e.g. 7) or a range (e.g. 2 to 5). The following rules must be followed for the choices:

An example of the four-to-one multiplexer, using with-select-when,is given below.

entity MUX_4d is port (A, B, C, D: in std_logic; SEL: in std_logic_vector(1 downto 0); Z: out std_logic); end MUX_4d; architecture concur of MUX_4d is begin with SEL select Z <= A when "00", B when "01", C when "10", D when "11";

end concur;

Example 18: 4-to-1 MUX using with-select-when

37

The next example shows an arithmetic unit which uses with-select-when to select the arithmetic operations on bus inputs A and B chosen by the select input, sel. sel 3

8 A Arith Unit 8 B 8 F

carry_in Figure 9: Arithmetic Unit

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity arith_unit is port (A, B: in std_logic_vector(7 downto 0); sel: in std_logic_vector(2 downto 0); carry_in: in std_logic; F: out std_logic_vector(7 downto 0 )); end arith_unit; architecture Behavioral of arith_unit is begin with sel(2 downto 0) select F <= A when "000", A + 1 when "001", A - 1 when "010", B when "011", B + 1 when "100", B - 1 when "101", A + B when "110", A + B + carry_in when "111", "XXXXXXXX" when others; end Behavioral;

Example 19: Arithmetic Unit

38

6d.

Tristate Output
This next example shows how to implement a tristate buffer using VHDL. Tristate buffers are simple devices which facilitate connection to a common bus. The buffer output can be set to high impedance when a connection is not required.

Tristate enable input output input output 0 0 enable 1 1 0 1 0 1 Z Z 0 1

Figure 10: Tri-State Buffer

entity tristate is port (input, enable: in std_logic; output: out std_logic); end tristate; architecture concur of tristate is begin output <= input when enable = '1'; else 'Z'; end concur;

Example 20: Tri-State Buffer

39

40

7.

Sequential Modelling
Concurrent modelling is easier to write but more prone to error in operation as the timing is not prescribed. In the above examples of concurrent modelling a when-else statement is used as a conditional statement. In most complex digital systems the timing of data transfer and computational events is critical to correct operation. To describe and model these systems we use the process construct and write behavioural - RTL VHDL to define sequential systems.

7a.

Process
The basis for sequential modelling is the process construct. As you will see, the process construct allows us to model complex digital systems, in particular sequential circuits. A process statement is the main construct in behavioural modelling. It allows you to use sequential statements to describe the behaviour of a system in time. The syntax for a process statement is label: process (sensitivity_list) is process_declarations begin -- sequential statements; end process label;

The statements for sequential modelling within a process are: signal assignments variable assignments if else elsif end if statements case when statement wait statement null statement loop statement next statement exit statement procedure call

A process without a wait statement must have a sensitivity list.

41

A process is called once at the start of simulation, and thereafter when any of the signals in the sensitivity list changes. Simple conditional statements in a process infer combinatorial logic but conditional statements which are sensitive to a clock or statements which read an output (feedback) infer flip-flops or registers - sequential logic. In a sequential circuit the output depends not only on the present inputs but on the previous state of the circuit. This means that a sequential circuit must contain some sort of memory.

Combinational Logic Circuit

k present state

next state

Memory

Figure 11: General Model of a Sequential System

Memory elements are implied when VHDL is written in a process where the assignment of signal values are dependent on a clock edge. In other words, for any coding where the value of a signal has to be stored or held, e.g. using wait or if-else, a storage element is inferred and the synthesis tool will implement a memory element. Variables and constants that are used inside a process have to be defined in the process declarations part before the keyword begin. The keyword begin indicates the start of the computational part of the process. The statements are executed sequentially. Note that variable assignments inside a process are executed immediately and denoted by the ":=" operator. This is in contrast to signal assignments denoted by "<=" and which changes occur after a delay. As a result, changes made to variables will be available immediately to all subsequent statements within the same process.

42

The simplest sequential circuit and the basic building block and storage element of sequential logic circuits is the D-type Flip Flop.

DFF

D 0

Q 0 1 0 1

Q+ 0 0 1 1

clock

0 1 1 Figure 12: D Flip-flop

The output Q changes to the value of the input D on the (usually rising) edge of the clock pulse. Q+ is called the "next state" of the flip flop. The characteristic equation of the flip flop is thus Q+ = D.

An example of a process architecture is shown here. A positive edgetriggered D flip-flop is shown. library ieee; use ieee.std_logic_1164.all; entity DFF_1 is port (CLK, D : in std_logic; Q : out std_logic); end DFF_1; architecture BEHAV_DFF of DFF_1 is begin DFF_PROCESS: process (CLK) begin if (CLK'event and CLK = '1') then Q <= D; end if; end process; end BEHAV_DFF;

Example 21: D Flip-flop using if-else On the positive (rising) edge of the clock, Q is assigned the value of D. The process will on run when there is a change in the value of the clock.

43

A process is declared within an architecture and is itself a concurrent statement. However, the statements inside a process are executed sequentially. The sensitivity list is a set of signals to which the process is sensitive. Any change in the value of the signals in the sensitivity list will cause immediate execution of the process. The single comma ' means attribute. 'event is an attribute of CLOCK. The expression (CLK'event and CLK = '1') checks for a positive clock edge.

library ieee; use ieee.std_logic_1164.all; entity DFF_1 is port (CLK, D : in std_logic; Q : out std_logic); end DFF_1; architecture BEHAV_DFF of DFF_1 is begin DFF_PROCESS: process begin wait until rising_edge(clk); Q <= D; end process; end BEHAV_DFF;

Example 22: D Flip-flop using wait If the sensitivity list is not specified, a process has to include one wait statement as the first line of the process to make sure that the process will halt. Notice that one cannot include both a sensitivity list and a wait statement. Library: std_logic_1164 also contains the "rising_edge" and "falling_edge" attributes which can also be used for synchronous timing. A process statement that is sensitive to the clock or waits for the clock edge infers edge sensitive memory and will usually synthesise into a flip flop. For negative or falling edge you can use (CLK'event and CLK = '0') A process that is level sensitive only will infer a latch not a flip-flop. Dtype flip flops general have asynchronous Reset (Q to '0' ) inputs. To add this to our code we simply add a few more lines.

44

library ieee; use ieee.std_logic_1164.all; entity DFF_1 is port (CLK, D, Reset : in std_logic; Q : out std_logic); end DFF_1; architecture BEHAV of DFF_1 is begin process (CLK) begin if Reset = '1' then Q <= '1' ; elsif (CLK'event and CLK = '1') then Q <= D; end if; end process; end BEHAV;

Example 23: D Flip-flop with asynchronous reset If we take our earlier BUZZER combinational example:

architecture behavioral of BUZZER is begin WARNING <= (not DOOR and IGNITION) or (not SBELT and IGNITION); end behavioral; T Then a synthesis tool will generate the following circuit: DOOR

IGNITION

WARNING

SEATBELT Figure 13: Synthesis of combinational circuit

45

If we make the signal assignment dependent on a clock edge within a process, then the assignment of the output will only update on the rising clock edge.

architecture BEHAV_SEQ of SEQ_1 is signal F; std_logic; begin process (CLK) begin if (CLK'event and CLK = '1') WARNING <= (not DOOR and IGNITION) or (not SBELT and IGNITION); else 0; end if; end process; end BEHAV_SEQ;

Example 24: Clocked Sequential Assignment

Synthesis of this code will generate a clocked output. DOOR

IGNITION

WARNING

SEATBELT

CLOCK

Figure 14: Synthesis of clocked circuit

This illustration shows how we can write RTL style VHDL with computational elements clocked in sequence through a logic system.

46

7b.

If - then - else statement


In the above examples we introduced the if-else statement. The if statement executes a sequence of statements whose sequence depends on one or more conditions. The syntax is as follows: if condition then sequential statements; elsif condition then sequential statements; else sequential statements; end if; Each condition is a Boolean expression. The if statement is performed by checking each condition in the order they are presented until a "true" is found. Nesting of if statements is allowed. An example of an if statement was given earlier for a D Flip-flop with asynchronous clear input. The if statement can be used to describe combinational circuits as well. The following example illustrates this for a 4-to-1 multiplexer with inputs A, B, C and D, and select signals S0 and S1. This statement must be inside a process construct. entity MUX4e is port (S1, S0, A, B, C, D: in std_logic; Z: out std_logic); end MUX4e; architecture behav of MUX4e is begin process (S1, S0, A, B, C, D) begin if S1='0' and S0='0' then Z <= A; elsif S1='0' and S0='1' then Z <= B; elsif S1='1' and S0='0' then Z <= C; elsif S1='1' and S0='1' then Z <= D; end if; end process; end behav;

Example 25 MUX using if-else in a process Note that although this code uses if-else inside a process it does not describe a sequential circuit and the synthesis tools would infer a simple multiplexor.

47

if-elsif and case statements (see below) are commonly used for the implementation of sequential arithmetic and functional blocks in processes. Here is an example of a simple counter with enable and reset. Synthesis tools pick up statements like: count <= count + 1; to synthesise counters efficiently. 4 UpCounter count 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 Clock count

en reset

library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use IEEE.std_logic_arith.all; entity upcounter is port ( reset, clock, en: in STD_LOGIC; count: inout STD_LOGIC_VECTOR (3 downto 0) ); end upcounter; architecture arch of upcounter is begin process (clock, reset. en) begin if reset='1' then count <= "0000"; elsif clock'event and clock='1' then if en ='1' then count <= count + 1; end if; end if; end process; end arch;

Example 26: 4 Bit up-counter with asynchronous reset

Notes To use arithmetic functions on std_logic signals, such as: count <= count + 1; the library ieee.std_logic_unsigned must be used. Signal count must be made inout as it has to read its own value in the same line else an internal signal can be used.

48

D7 clock Q7

D6

D5

D4

D3

D2

D1

D0 reset load

Q6

Q5 Q4 Q3 Q2 Q1 Figure 15: 8 Bit Register

Q0

library ieee; use ieee.std_logic_1164.all; entity regn is generic (n: integer := 8); port ( D: in std_logic_vector (n-1 downto 0); clock, reset, enable : in std_logic; Q : out std_logic_vector( n-1 downto 0 )); end regn; architecture Behaviour of regn is begin process(clock, reset, enable) begin if reset=0 then Q <= ( others => 0); elsif (clockevent and clock=1) then if enable = 1 then Q <= D; else null; end if; end if; end process; end Behaviour;

Example 27: Generic Register Here is an 8 bit generic shift register. The declaration of the generic parameter, n, in the entity allows the width of the register to be controlled by one parameter. To set the data to a value the line: Q <= ( others => 0); is used. (others =>'0') simply means assign all the values in the output bus to '0'.

49

Shift Register Q clock dir enable serial_in n data_ out Here we have an 8 bit shift register. Very useful sequential building block. Constructed out of 1-bit registers. Used to perform either parallel to serial data conversion or serial to parallel data conversion.

Figure 16: Shift Register library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity Shift_Reg is port( enable: in STD_LOGIC; serial_in: in STD_LOGIC; dir: in STD_LOGIC; clock: in STD_LOGIC; data_out: out STD_LOGIC_VECTOR (7 downto 0)); end Shift_Reg; architecture Behavioral of Shift_Reg is signal reg: std_logic_vector(7 downto 0); begin process (CLOCK, enable,dir) begin if enable ='1' then if clock'event and clock='1' then if dir = '0' then reg(7 downto 0) <= '0' & reg(7 downto 1) ; else reg(7 downto 0) <= reg(6 downto 0) & serial_in; end if; end if; end if; end process; data_out <= reg; end Behavioral;

-- shift right -- shift left

Example 28: 8-Bit Shift Register The bits in this register can be shifted to the right or left depending on the value of the control input: dir. Note the use of the concatenate operator: &. This is used to join two vectors together.

50

7c.

Case statement
The case statement executes one of several sequences of statements, based on the value of a single expression. The syntax is as follows, case expression is when choices => sequential statements; when choices => sequential statements; when others => sequential statements; end case; The expression must evaluate to an enumerated type of a onedimensional array, such as a std_logic_vector. The case statement evaluates the expression and compares the value to each of the choices. The when clause corresponding to the matching choice will have its statements executed. The following rules must be adhered to: no two choices can overlap (i.e. each choice can be covered only once) if the "when others" choice is not present, all possible values of the expression must be covered by the set of choices. entity MUX_4f is port ( SEL: in std_logic_vector(2 downto 1); A, B, C, D: in std_logic; Z: out std_logic); end MUX_4f; architecture behav of MUX_4f is begin process (SEL, A, B, C, D) begin case SEL is when "00" => Z <= A; when "01" => Z <= B; when "10" => Z <= C; when "11" => Z <= D; when others => Z <= 'X'; end case; end process; end behav;

Example 29: MUX using case statement The "when others" covers the cases when SEL = "0X", "0Z", "XZ", "UX", etc. It should be noted that these combinational circuits can be expressed in other ways, using concurrent statements such as the with select construct. Since the case statement is a sequential statement, nested case statements are possible.

51

A second example of a case statement is an Arithmetic and Logic Unit

architecture behv of ALU is begin process(A, B, opcode) begin if clk'event and clk = '1' then if reset ='1' then Accumulator <= (others => 'Z'); else case opcode is when "000" => Accumulator <= (others => '0'); when "001" => Accumulator <= A; when "010" => Accumulator <= A + 1; when "011" => Accumulator <= A - 1; when "100" =>Accumulator <= A + B; when "101" => Accumulator <= A and B; when "110" =>Accumulator <= A or B; when "111" => Accumulator <= (others => '1'); when others => Accumulator <= (others => 'X'); end case; end if; end if; end process; end behv;

Example 30: Registered ALU using case

52

7d.

Multiple Processes
The following example illustrates the use of more than one process. One process can use signals that will trigger another process when events on the signals in its sensitivity list occur. This example is a Full Adder, composed of two Half Adders: S_ha = (A B) and C_ha = AB For the Full Adder: Sum = (A B) Cin = S_ha Cin Cout = (A B) Cin + AB = S_ha.Cin + C_ha
P1 ints1 P2 Sum Half Adder2 ints3

A B

Half Adder1

ints2

Cout

Cin

library ieee; use ieee.std_logic_1164.all; entity Full_Add is port (A, B, Cin : in std_logic; Sum, Cout : out std_logic); end FULL_ADDER; architecture behav of Full_Add is signal ints1, ints2, ints3: std_logic; begin Proc1: process (A, B) begin ints1<= A xor B; ints2<= A and B; end process Pro1; Proc2: process (int1, int2, Cin) begin Sum <= ints1 xor Cin; ints3 <= ints1 and Cin; Cout <= ints2 or int3; end process Pro2; end behav;

Example 31: Two Processes - Full Adder

53

54

8.

VHDL State Machines


8a. Example of a Moore Machine
The following sequence detector recognises the input bit sequence, Din: "101". The machine will keep checking for the proper bit sequence and does not reset to the initial state after it recognizes the string. In this case we are implementing a Moore machine, the output is associated with the states as indicated on the following state diagram (Figure 6).

0 1 0 S1 Z=0 1 S2 Z=0 0 S3 Z=0 1 0 1 S4 Z=1

Figure 17: State Diagram, 101 Sequence Detector

The VHDL file for the sequence detector is given on the next page. Note the use on an enumerated data type: Streg_type. This restricts the allowed state values of Streg to S1, S2, S3, S4. The next state is conditional only on the present state which is the value of Streg. The four possible states are accessed via the value of Streg within a case statement and the transition from each state is implemented using ifelsif-else statements. Alternatively the states assignment can be defined directly using the constant statement.

architecture arch of fsm is constant S1 : std_logic_vector(2 downto 0) := 000; constant S2 : std_logic_vector(2 downto 0) := 001; constant S3 : std_logic_vector(2 downto 0) := 011; constant S4 : std_logic_vector(2 downto 0) := 010; begin

Example 32: Direct state assignment

55

library ieee; use ieee.std_logic_1164.all; entity seq_det is port (CLK, RST, Din: in STD_LOGIC; Z: out STD_LOGIC); end;

architecture arch of seq_det is type Streg_type is ( S1, S2, S3, S4 ); signal Streg: Streg_type; begin process (CLK) begin if CLK'event and CLK = '1' then if RST='1' then Streg <= S1; else case Streg is when S1 => if Din='0' then Streg <= S1; elsif Din='1' then Streg <= S2; end if; when S2 => if Din='1' then Streg <= S2; elsif Din='0' then Streg <= S3; end if; when S23 => if Din='1' then Streg <= S4; elsif Din='0' then Streg <= S1; end if; when S4 => if Din='0' then Streg <= S3; elsif Din='1' then Streg <= S2; end if; when others => null; end case; end if; end if; end process; -- signal assignment statements for combinatorial outputs Z <= '1' when (Streg = S4) else '0'; end arch;

Example 33: Sequence Detector (101) Moore Model

56

8b

FSM: Two Process Style


An alternative form of state machine representation is the two process style. Here the one process defines the timing, sensitivity and reset. The other defines the state transitions. The output logic is combinatorial and can be coded in a third process.

architecture process 1 case statement for state transitions process 2 Clock timing Sensitivity, Reset

Figure 18: Two Process FSM

begin -- the synchronous state transition process process (clk, reset) begin if (reset = 0) then present_state <= state0; elsif (clkevent and clk = 1) then present_state <= next_state; end if ; end process; -- state transition on clock edge

Example 34: FSM clock process

57

process (present_state, Din) -- start transitions begin case present_state is when state0 => if (Din = 0) then next_state <= state1; else next_state <= state0; end if ; when state1 => if (Din = 1) then next_state <= state2; else next_state <= state1; end if ; when state2 => if (Din = 1) then next_state <= state3; else next_state <= state1; end if ; when state3 => if (Din = 1) then next_state <= state0; else next_state <= state1; end if ; when others => next_state <= state0; end case; end process; end arch;

Example 35: FSM State transitions (011 detector)

58

9.

Additional VHDL Notes and Examples

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity rom_32x4 is port ( Clk : in std_logic; en : in std_logic; -- Read enable addr : in std_logic_vector (4 downto 0); data : out std_logic_vector(3 downto 0)); end rom_32x4; architecture imp of rom_32x4 is subtype word is std_logic_vector (3 downto 0); type rom_type is array (31 downto 0) of word; constant ROM : rom_type := ("1001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", "0000", "0010"); begin process (Clk) begin if (Clkevent and Clk = 1) then if (en = 1) then data <= ROM(conv_integer(addr)); end if; end if; end process; end imp;

Example 36: 32 x 4 ROM

This is an example of a 32 x 4 bit Read Only Memory. The memory contents are defined by the value of the constants, and are hardwired on implementation. Note that the index of the address must be an integer. The use of a subtype is optional. The ROM code can be synthesised, and would be implemented by logic blocks.

59

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity ram_16x8 is port ( Clk : in std_logic; we : in std_logic; -- Write enable en : in std_logic; -- Read enable addr : in std_logic_vector(4 downto 0); di : in std_logic_vector(7 downto 0); -- Data in do : out std_logic_vector(7 downto 0)); -- Data out end ram_16x8; architecture impl of ram_16x8 is type ram_type is array (15 downto 0) of std_logic_vector (7 downto 0); signal RAM : ram_type; begin process (Clk) begin if (Clkevent and Clk = 1) then if (en = 1) then if (we = 1) then RAM(conv_integer(addr)) <= di; do <= di; else do <= RAM(conv_integer(addr)); end if; end if; end if; end process; end impl;

Example 37: 16 x 8 RAM

This is an example of a 16 x 8 bit read-write RAM. Note that the index of the address must be an integer, thus conversion functions must be used on the address vector. The RAM code can be synthesised, and would be implemented in Block RAM.

60

library ieee; use ieee.std_logic_1164.all; entity shiftreg is port ( clock : in std_logic; serial_in: in std_logic; serial_out : out std_logic); end shiftreg; architecture impl of shiftreg is signal temp : std_logic_vector(7 downto 0); begin process (clock) begin if (Clkevent and Clk = 1) then for i in 0 to 6 loop temp(i + 1) <= temp(i); end loop; tmp(0) <= serial_in; end if; end process; serial_out <= temp(7); end impl;

Example 38: Shift Register using loop statement This is an example of an 8 bit right shift register, coded using a loop statement. Loop statements can only be used in a process. (Outside a process the generate statement can be used for a similar operation.) The loop statement is a succinct method for the description of repetitive structures. The number of iterations must be defined. The loop is expanded at compile time.

61

entity Count_1s is generic (width: integer := 8); port (datain: in std_logic_vector(width - 1 downto 0); count: out std_logic_vector(3 downto 0)); end Count_1s; architecture algorithm of Count_1s is signal temp: std_logic_vector(3 downto 0) ; begin process(datain) variable temp : unsigned(3 downto 0); begin temp := "0000"; for i in 0 to (width-1) loop if datain(i) = '1' then temp := temp + '1'; else null; end if; end loop; count <= std_logic_vector (temp); end process; end algorithm;

Example 39: One's Counter This is an example of one's counter using a loop statement. The algorithm will return the number of '1's in a binary number. e.g. "01011011" would return 5. The code requires the use of a variable in the loop statement as a signal would not update in each iteration. Note the width of the input vector is controlled by a generic parameter.

62

10.

Structural Modelling
Structural modelling was described briefly in the section Structural Modelling in Section 3: "Basic Structure of a VHDL file". Structural modelling describes a circuit in terms of components and its interconnection. There is no behavioural representation. Each component has to predefined (e.g. in the architecture or in a package) and can be described as structural, a behavioural or dataflow model. At the lowest hierarchy each component is described as a behavioural model, using the basic logic operators defined in VHDL. In general, structural modelling is very good to describe the top level of complex digital systems, through a set of components in a hierarchical fashion. A structural description can best be compared to a schematic block diagram that can be described by the components and the interconnections. VHDL provides a formal way to do this by: Declaring a list of components being used, Declaring signals which define the nets that interconnect , Labelling multiple instances of the same component so that each instance is uniquely defined.

The components and signals are declared within the architecture body, architecture architecture_name of NAME_OF_ENTITY is component declarations signal declarations begin component instantiation and connections : end architecture_name;

63

10a.

Component declaration
Before components can be instantiated they need to be declared in the architecture declaration section or they can be declared in a separate vhd file called a package. The component declaration consists of the component name and the interface (ports). The syntax is as follows: component component_name is port ( port_signal_names: mode type; port_signal_names: mode type; port_signal_names: mode type); end component component_name The component name refers to either the name of an entity defined in a library or an entity explicitly defined in the VHDL file (see example of the four bit adder). The list of interface ports gives the name, mode and type of each port, similarly as is done in the entity declaration. A few examples of component declarations follow: component OR2 port (in1, in2: in std_logic; out1: out std_logic); end component; component PROC port (CLK, RST, RW, STP: in std_logic; ADDRBUS: out std_logic_vector (31 downto 0); DATA: inout integer range 0 to 1024); end component; component FULLADDER port(a, b, c: in std_logic; sum, carry: out std_logic); end component;

Example 40: Component declarations

As mentioned earlier, the component declaration has to be done either in the architecture body or in a package. If the component is declared in a package, one does not have to declare it again in the architecture body as long as one uses the library and use clause to allow access to the package.

64

10b.

Component Instantiation and Interconnections


The component instantiation statement references a component that can be previously defined at the current level of the hierarchy or defined in a technology library (vendor's library). The syntax for the components instantiation is as follows, instance_name : component name port map (port1=>signal1, port2=> signal2,... port3=>signaln); The instance name or label can be any legal identifier and is the name of this particular instance. The component name is the name of the component declared earlier using the component declaration statement. The port name is the name of the port and signal is the name of the signal to which the specific port is connected. The above port map associates the ports to the signals through named association. An alternative method is the positional association shown below, port map (signal1, signal2,...signaln); in which the first port in the component declaration corresponds to the first signal, the second port to the second signal, etc. The signal position must be in the same order as the declared component's ports. One can mix named and positional associations as long as one puts all positional associations before the named ones. The following example illustrates this,

component NAND2 port (in1, in2: in std_logic; out1: out std_logic); end component; signal int1, int2: std_logic; architecture struct of EXAMPLE is U1: NAND2 port map (A,B,int1); U2: NAND2 port map (in2=>C, in2=>D, out1=>int2); U3: NAND3 port map (in1=>int1, int2, Z); end

Example 41: port map statement

65

A further complete hierarchical structural example of a One's Counter is given below and in the following pages:

A2 0 0 0 0 1 1 1 1

A1 0 0 1 1 0 0 1 1

A0 0 1 0 1 0 1 0 1

C2 0 0 0 1 0 1 1 1

C1 0 1 1 0 1 0 0 1

Figure 19: Truth table for one's counter

count_1s

sub_1

sub_2

and2

or3

and3

or4

inv

Figure 20 Hierarchy of one's counter

66

use work.all; entity count_1s is port (A: in BIT_VECTOR(2 downto 0); B: out BIT_VECTOR(1 downto 0)); end count_1s; architecture struct of count_1s is component sub_1 port (X: in BIT_VECTOR(2 downto 0); Z: out BIT); end component; component sub_2 port (X: in BIT_VECTOR(2 downto 0); Z: out BIT); end component; begin COMPONENT_1: sub_1 port map (A,B(1)); COMPONENT_2: sub_2 port map (A,B(0)); end struct;

use work.all; entity sub_1 is port (X: in BIT_VECTOR(2 downto 0); Z: out BIT); end sub_1; architecture andor of sub_1 is component AND2 port (Ip1,Ip2: in BIT; Op: out BIT); end component; component OR3 port (Ip1,Ip2,pI3: in BIT; Op: out BIT); end component; signal A1,A2,A3: BIT; begin D1: AND2 port map (X(0),X(1),A1); D2: AND2 port map (X(0),X(2),A2); D3: AND2 port map (X(1),X(2),A3); D4: OR3 port map (A1,A2,A3,Z); end andor;

67

use work.all; entity sub_2 is port(X: in BIT_VECTOR(2 downto 0); Z: out BIT); end sub_2; architecture andorinv of sub_2 is component AND3 port(Ip1,Ip2,Ip3: in BIT;Op: out BIT); end component; component OR4 port(Ip1,Ip2,Ip3,Ip4: in BIT;Op: out BIT); end component; component INV port(Ip: in BIT;Op: out BIT); end component; signal T0,T1,T2,A1,A2,A3,A4: BIT; begin D5: INV port map(X(0),T0); D6: INV port map(X(1),NT1); D7: INV port map(X(2),T2); D8: AND3 port map(X(2),T1,T0,A1); D9: AND3 port map(T2,T1,X(0),A2); D10: AND3 port map(X(2),X(1),X(0),A3); D11: AND3 port map(T2,X(1),T0,A4); D12: OR4 port map(A1,A2,A3,A4,Z); end andorinv;

Example 42: Top level structural code for one's counter

68

entity AND2 is port (Ip1,Ip2: in BIT; Op: out BIT); end AND2; architecture BEHAV of AND2 is begin Op <= Ip1 and Ip2; end BEHAV; entity OR3 is port (Ip1,Ip2,Ip3: in BIT; Op: out BIT); end OR3; architecture BEHAV of OR3 is begin Op <= Ip1 or Ip2 or Ip3; end BEHAV; entity AND3 is port(Ip1,Ip2,Ip3: in BIT;Op: out BIT); end AND3; architecture BEHAV of AND3 is begin Op<=Ip1 and Ip2 and Ip3; end BEHAV; entity OR4 is port(Ip1,Ip2,Ip3,pI4: in BIT;Op: out BIT); end OR4; architecture BEHAV of OR4 is begin Op<=Ip1 or Ip2 or Ip3 or Ip4; end BEHAV; entity INV is port(Ip: in BIT;Op: out BIT); end INV; architecture BEHAV of INV is begin Op<= not Ip; end BEHAV;

Example 43: Component level of one's counter

69

70

11.

Writing Test Benches


This page introduces the concept of writing test benches to verify the work of a modelled digital system. The elements and programming techniques used for this purpose are explained below. In the Xilinx ISE design environment writing test benches is made easier due to the use of the tool: HDL Bencher. This tool has an easy to use graphical interface where input stimuli and predicted output waveforms can be set by the

designer. The tool then runs ModelSim in the background and gives a graphical output confirming results or showing errors. The test bench waveform is only recognised by Xilinx software. The more general way to write a test bench is using VHDL. The VHDL code generated by HDL Bencher can be viewed in ISE by selecting: View Behavioural Testbench. Remember when writing any test bench to check all input combinations for complete verification of DUT operation.

11a.

Introduction
After writing the VHDL code for a certain system and before processing the design, however, we should take the time to verify that the code actually does what it is intended to do, by running a simulation. VHDL can be used as a powerful test stimulus language. VHDL code which is written to stimulate and verify a VHDL Design is called a Test bench. Test benches are VHDL descriptions of circuit stimuli and corresponding expected outputs that verify the behaviour of a circuit over time. They should be an integral part of any VHDL project and should be created together with other description of the system. 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 is intended to do. After creating one or more test benches as part of your design specification, you will need to use a simulator to apply the test bench to your design as it was originally written. This simulation will ensure that the design operates as expected. This type of simulation is called functional simulation, which will uncover most logical errors in the design. A Test Bench is VHDL code which includes the Design Under Test ( DUT sometimes called UUT) as a structural element within the code. The VHDL test bench has no ports. The basic structural element of a Test bench is shown below.

71

Figure 21: HDL Bencher simulation output

72

Test Bench Structure

entity (empty)

architecture

DUT: component declaration internal signal declarations begin DUT: Port Map

testbench:process procedure( ) end process

end arch

Figure 22: Test Bench Structure

73

11b.

Testbench Structure
When writing test benches, you will most likely use a broader range of language features. The simplest test benches are those that apply some sequence of inputs to the Device Under Test (DUT) so that its operation can be observed in simulation. Such a test bench must consist of a declaration for a test component. In what follows, we will discuss the main structure and features of this test component: Empty entity declaration. The entity declaration of the test component does not include an interface (port) list. Local signals. The architecture of the test component has declarations for local signals. These signals are used to apply inputs to the DUT and observe the behaviour or the output during simulation. DUT instantiation. The architecture for the test bench should use the structural level of abstraction (in the form of port mapping statements) to connect the low-level (previously top level) design description to the other parts of the test bench (including signals and components). It is worth noticing that to the simulator, there is no distinction between those parts of the design that are being tested and the test bench itself. Process statement. To apply stimulus to the design, the test bench will probably be written using one or more sequential processes. A process that is intended for testing will normally have no sensitivity list. Instead it will have a series of signal assignments and wait statements. Signal assignments wait statements. The wait statements provide a specific amount of delay between each new combination of inputs for the DUT to stabilize between the assignments of test inputs. This process statement will be used to apply a sequence of input values (the actual stimulus) to a low-level circuit and (if desired) check the state ot that circuit's outputs at various points in time. Transport statements. There are two ways to write stimulus vectors: using wait statement (as just explained) or using transport statements. Transport-based test benches are smaller and easier to read than waitbased test-benches, but wait-based test benches are easier to understand when simulation is single stepped for debugging. Assert statements. Assert statements are used to verify that the DUT is operating correctly for each combination of inputs. In case of fallacy operation, the text you have specified in the optional report statement clause is displayed on your simulator's window.

74

Multiple processes. Separate processes running in the background can be used to generate some useful signals like clocks. Loop statement. You will probably use VHDL's looping features to simplify the description of repetitive stimulus (such as the system clock). Loops can be used to apply inputs and monitor outputs over potentially long periods of time. Using file I/O. Storing the test data in files can reduce the time required to add or modify test data. In this case, the test bench does not have to be recompiled when test stimulus is added or modified. You should plan to create test benches that are re-usable, by developing a master test bench that reads test data from a file. You may also need to write the simulation results to a disk file for later analysis.

75

11c

Test Bench Example


A simple example of a test bench for the original Buzzer circuit is shown below:

USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY testbench IS END testbench; ARCHITECTURE testbench_arch OF testbench IS COMPONENT warning PORT ( Ignition : In std_logic; SBelt : In std_logic; Door : In std_logic; Warning : Out std_logic ); END COMPONENT; SIGNAL Ignition : std_logic; SIGNAL SBelt : std_logic; SIGNAL Door : std_logic; SIGNAL Warning : std_logic; BEGIN UUT : warning PORT MAP ( Ignition => Ignition, SBelt => SBelt, Door => Door, Warning => Warning PROCESS BEGIN -- -------------------Ignition <= transport '0'; SBelt <= transport '0'; Door <= transport '0'; -- -------------------WAIT FOR 200 ns; -- Time=200 ns Ignition <= transport '1'; -- -------------------WAIT FOR 100 ns; -- Time=300 ns SBelt <= transport '1'; -- -------------------WAIT FOR 100 ns; -- Time=400 ns Door <= transport '1'; -- -------------------WAIT FOR 100 ns; -- Time=500 ns Ignition <= transport '0'; -- -------------------END PROCESS; END testbench_arch; Example 44: VHDL Test Bench

);

76

PROCEDURE CHECK_Warning ( next_Warning : std_logic; TX_TIME : INTEGER ) IS VARIABLE TX_LOC : LINE; BEGIN IF (Warning /= next_Warning) THEN STD.TEXTIO.write(TX_LOC,string'("Error at time=")); STD.TEXTIO.write(TX_LOC, TX_TIME); STD.TEXTIO.write(TX_LOC,string'("ns Warning=")); END IF; END; Example 45: Simplified Check procedure PROCESS BEGIN -- -------------------Ignition <= transport '0'; SBelt <= transport '0'; Door <= transport '0'; -- -------------------WAIT FOR 200 ns; -- Time=200 ns Ignition <= transport '1'; CHECK_Warning('1',200); -- -------------------WAIT FOR 100 ns; -- Time=300 ns SBelt <= transport '1'; CHECK_Warning('0',300); -- -------------------WAIT FOR 100 ns; -- Time=400 ns Door <= transport '1'; CHECK_Warning('0',400); -- -------------------WAIT FOR 100 ns; -- Time=500 ns Ignition <= transport '0'; CHECK_Warning('1',500); -- -------------------WAIT FOR 100 ns; -- Time=600 ns SBelt <= transport '0'; CHECK_Warning('0',600); -- -------------------WAIT FOR 100 ns; -- Time=700 ns Door <= transport '0'; CHECK_Warning('1',700); -- -------------------WAIT FOR 150 ns; -- Time=850 ns -- -------------------END PROCESS

Example 46: Test Bench for Buzzer circuit

77

78

79

80

81

82

Potrebbero piacerti anche