Joseph Tarango
Department of Computer Science and Engineering
Bourns College of Engineering
University of California, Riverside

Home
CS122A | Syllabus
Intro to FPGAs | Basics of VHDL | Intro to Xilinx | Turnin
Lab 1 | Lab 2 | Lab 3 | Lab 4 | Lab 5 | Project

Basics of VHDL

Table of Contents

Introduction to VHDL
Basic Language Concepts
Language Reference
Basics Elements
Data Types and Declarations
Structural Syntax
Module Structure
Declarations
Create Architecture
Create Behavioral
Test Bench
UCF
VHDL Resources

Introduction

VHDL is an acronym for VHSIC Hardware Description Language (VHSIC is an acronym for Very High Speed Integrated Circuits). With HDL we can describe and model a system in several levels of abstraction, making management relatively clear and easy. In these systems, we can model combinational and sequential architectures/behaviors. VHDL was originally developed by the United States Department of Defense in order to document application specific integrated circuits (ASICs) to silicon chip manufactures.

In VHDL, we can describe five different primary constructs called design units. The design units are: entity declaration, architecture body, configuration declaration, package declaration, and package body. In this class, we will only use entity declaration, architecture body, and package declaration.

An entity declaration is model of one or more particular architectures; where we define inputs, input/output, and output data flow. Architecture body can contain either a specific architecture description of a single or multiple combinational or sequential components. Package declaration summarizes type, subtype, and sub-entities to be used across design spaces.

In the architecture body we can describe two models behavioral and structural. Structural modeling is a set of interconnected components relating to a combinational circuit in a concurrent structure. The data flow of the interconnected signals is significant, so independent signals must be declared first. The expression representing these statements is on the right-hand-side of the assignment operator and the left-hand-side of the statement is known as a target signal.

In contrast, behavioral modeling is set of sequential statements executed in specified order; these sequential statements are described in a process statement. A process statement is a concurrent statement that appears within an architecture body. Each process statement requires a sensitivity list, where independent must be checked before evaluating target signals. A process statement executes it contents in the ordered sequence continuously, which is why a process statement is a concurrent statement because multiple processes can be executing at the same time. It is possible to mix the modeling styles, just remember what you are trying to represent.

When a model is described, it can be testing using a test bench simulation. The simulation is used in advanced timing and result analysis. The simulation can be halted by using assert or wait statement indicating an error or successful test run.

The tool-chain to compile the HDL onto the fabric happens in several steps. These steps are logical synthesis, translation, technology mapping, and placement and routing. Logical synthesis is the process of abstracting the HDL in terms of logical gates; an example is Berkeley's ABC. The logical synthesis process uses algorithms and data structures to reduce and optimize the logical gates for several design strategies, including area and delay. When the logical synthesis process is complete, the data is sent to translation. The translation is the first step in the implementation process, where all inputs, outputs, and design constraints are put into a logical structure to be used for the target fabric; translation then sends the data to technology mapping. Technology mapping takes the logical structure and creates lower-level primitives for placement and routing; and example is VPR. Placement and routing then takes the primitives and places these on the specific fabric with all logical structure and interconnect.

Basic Language Concepts

Signals are similar to variables and constants and can be assigned and read values, however a signal cannot be read and written at the same time because these relate to physical wires. Signals can be many types and the convention for synthesis is standard logic or standard logic vector, which is essentially a bit or group of bits. Signals of type standard logic can take the values 0, 1, or Z (high-impedance).

Basic Language Concepts

Signals are similar to variables and constants and can be assigned and read values, however a signal cannot be read and written at the same time because these relate to physical wires. Signals can be many types and the convention for synthesis is standard logic or standard logic vector, which is essentially a bit or group of bits. Signals of type standard logic can take the values 0, 1, or Z (high-impedance).
signal A_signal : std_logic;
signal B_signal : std_logic_vector (15 downto 0);
constant C_constant : std_logic := '1';
constant D_constant : std_logic_vector(7 downto 0) := "01101011";
constant E_constant : std_logic_vector(7 downto 0) := x"F2";
constant F_constant : std_logic_vector(7 downto 0) := conv_std_logic_vector(3, 8);

An entity describes the interface to a design describing the inputs and outputs of the hardware module. Below is an example of a single bit full adder interface.
entity full_adder is
	port(
		Carry_in	: in  std_logic;
		A	        : in  std_logic;
		B	        : in  std_logic;
		Sum	        : out std_logic;
		Carry_out	: out std_logic
	);
end full_adder;

A module is complete description either structurally or behaviorally of hardware design.
-----------------------------------------
architecture Combinational of full_adder is

begin

   Sum  <= A XOR B XOR Carry_in;
   Carry_out <= (A AND B) OR (A OR Carry_in) OR (B AND Carry_in);

end Combinational;
-----------------------------------------

-----------------------------------------
architecture Behavioral of full_adder is

signal sum_signal : std_logic_vector(1 downto 0);

begin

   Addition : process( A, B, Carry_in)
   	begin
   	sum_signal <= A + B + Carry_in;

   end process : Addition;
   
Sum <= sum_signal(0);
Carry_out <= sum_signal(1);

end Behavioral;
-----------------------------------------
As seen in the code above, a process describes a sequence of statements which are repeatedly executed only when a input changes on its sensitivity list. So if A was left out of the sensitivity list in the process above, only changes to B or Carry_in would force a re-execution of the sequential statements in the process. Processes are generally used in describing a behavior and concurrent statement are used in describing structures. Processes are useful for conditional code, such as,case switch statements and if else trees.

To use a previous made module, you must declare it as a component similarly to declaring a function call. Declaring the component will allow the use of this module in the code body.
component full_adder is
	port(
		Carry_in	: in  std_logic;
		A	        : in  std_logic;
		B	        : in  std_logic;
		Sum	        : out std_logic;
		Carry_out	: out std_logic
	);
end component;
To use a component in a hardware design after it has been declared you must port map it to existing signals or input/output ports. A module which only contains port maps is considered a structural hardware design.
Unique_name : full_adder
	port map(
		Carry_in   => carryin_signal,
		A          => a_signal,
		B          => b_signal,
		Sum        => sum_signal,
		Carry_out  => carryout_signal
	        );
When making modules, sometime it is useful to make them of variable bitwidth. To dynamically change a module for that particular use, we would want to use a generic. The generic below changes the width of the calculation based on the value used in the component port mapping.
entity subtractor is
   generic( WIDTH : Integer := 16);
	port(
		A	        : in  std_logic_vector(WIDTH-1 downto 0);
		B	        : in  std_logic_vector(WIDTH-1 downto 0);
		Difference      : out std_logic_vector(WIDTH-1 downto 0);
		Borrow   	: out std_logic
	);
end subtractor;

architecture Behavioral of subtractor is

signal difference_signal : std_logic_vector(WIDTH downto 0);

begin

   subtraction : process( A, B )
   	begin
   	difference_signal <= A - B;

   end process;
   
Difference <= difference_signal(WIDTH-1 downto 0);
Borrow <= difference_signal(WIDTH);

end Behavioral;

Reference

I. Basics Elements
A. Operators
1. Logical Operators
not complement, not logic, or Boolean
[name] <= not( [name] );

and logical and, operates on logical array or Boolean
[name] <= [name] and [name];

or logical or, operates on logical array or Boolean
[name] <= [name] or [name];

nand logical complement of and, operates on logical array or Boolean
[name] <= [name] nand [name];

nor logical complement of or, operates on logical array or Boolean
[name] <= [name] nor [name];

xor logical exclusive or, operates on logical array or Boolean
[name] <= [name] xor [name];

xnor logical complement of exclusive or, operates on logical array or Boolean
[name] <= [name] xnor [name];
2. Relational Operators
= test for equality, result is Boolean

/= test for inequality, result is Boolean

< test for less than, result is Boolean

<= test for less than or equal, result is Boolean

> test for greater than, result is Boolean

>= test for greater than or equal, result is Boolean
3. Shift Operators
sll shift left logical
[name] <= [name] sll [integer to shift by]

srl shift right logical
[name] <= [name] srl [integer to shift by]

sla shift left arithmetic
[name] <= [name] sla [integer to shift by]

sra shift right arithmetic
[name] <= [name] sra [integer to shift by]

rol rotate left
[name] <= [name] rol [integer to shift by]

ror rotate right
[name] <= [name] ror [integer to shift by]
4. Adding Operators
+ addition
[name] <= [name] + [name];

- subtraction
[name] <= [name] - [name];

& concatenation
[name] <= [name] & [name];
5. Multiply Operators
* multiplication
[name] <= [name] * [name];

/ division
[name] <= [name] / [name];

mod modulo
[name] <= [name] mod [name];

rem remainder
[name] <= [name] rem [name];
6. Miscellaneous Operators
** exponentiation
[name] <= [name] ** [name of power];

abs absolute value
[name] <= abs( [name] );
B. Conditional Statements
1. If-Then-Else Statements
if [condition] then
elsif [condition] then
else
end if;
2. Case Statements
case [expression] is
when [choice] => [statement];
...
when [choice] => [statement];
when others => [statement];
end case;
II. Data Types and Declarations
A. Signal
1. Single Signal
signal [name] : std_logic;
2. Ranged
signal [name] : std_logic_vector( [range] );
B. Convert Integer to Ranged Signal
[name] <= conv_std_logic_vector( [integer], [no. of bits for vector] );
C. Set Target
[name] <= [name];
D. Constants
constant name : [single or ranged] := [initial value];
E. Enumerations
type enum_type is ( [name 1], [name 2], [name 3], ... , [name 4] );
F. Arrays and Vectors
type [name] is array ( [max value] downto [min value] ) of [single or ranged];
G. Subtypes: used to restrict range/values a type can have.
subtype [subtype name] is [ranged] range [max value] to [min value];
III. Structural Syntax
A. Signal Assignments
1. General
[signal name] <= [expression];
2. Set Ranged to a Single Bit Value
[signal name] <= (others => '[1,0]');
B. Process
[process name] : process( [sensitive signals] )
Begin
[statements];
end process [process name];
C. Signal Assign Statement
[target out signal] <= [signal choice or value] when [condition] else [signal choice];
D. Signal Select Statement
with [expression] select [target] <=
[out signal value] when [component name],
...,
[out signal value] when [component name],
[out signal value] when others;
E. Generate Statement
[generate name] : for [variable] in [min value] to [max value] generate
[array name] : [component name]
generic map (
[generic name] => [constant, value, or variables],
...
[generic name] => [constant, value, or variables],
)
port map (
[port name] => [single or ranged with variables],
...
[port name] => [single or ranged with variables]
);
end generate [generate name];
F. Component Instantiation
[component identifier] : [component name]
generic map (
[generic name] => [assigned generic],
...
[generic name] => [assigned generic],
[generic name] => [assigned generic]
)
port map (
[port name] => [assigned signal],
...
[port name] => [assigned signal],
[port name] => [assigned signal]
);
IV. Module Structure
A. Library
library [library name];
B. Use of Library
use [library name].[package].[all or parts];
C. Entity
entity [entity name] is
generic (
[name] : [data type] := [default value],
...
[name] : [data type] := [default value]
);
port (
[port name] : [direction] [single or ranged type];
...
[port name] : [direction] [single or ranged type];
[port name] : [direction] [single or ranged type]
);
end [entity name];
D. Architecture
architecture [entity architecture ] of [entity name] is
begin
[combinational];
end architecture;
V. Declarations
A. Component
component [component name] is
generic (
[name] : [type] := [default value],
...
[name] : [type] := [default value]
);
port (
[port name] : [direction] [single or ranged type];
...
[port name] : [direction] [single or ranged type]
);
end component;
VI. Create Architecture
entity [entity name] is
generic (
[name] : [data type] := [default value],
...
[name] : [data type] := [default value]
);
port (
[port name] : [direction] [single or ranged type];
...
[port name] : [direction] [single or ranged type];
[port name] : [direction] [single or ranged type]
);
end [entity name];

architecture [architecture name] of [entity name] is
[internal signals]
begin
[expression logic]

[signals to outputs]
end [architecture name];
VII. Create Behavioral
entity [entity name] is
generic (
[name] : [data type] := [default value],
...
[name] : [data type] := [default value]
);
port (
[port name] : [direction] [single or ranged type];
...
[port name] : [direction] [single or ranged type];
[port name] : [direction] [single or ranged type]
);
end [entity name];

architecture behavioral of [entity name] is
[internal signals]
begin
[processes]

[signals to outputs]
end behavioral;
VIII. Test Bench
A. Syntax for test bench only!
1. Loop statement
loop
[statement];
end loop;
2. For statement
for [variable] in [min integer] to [max integer] loop
[statement];
end loop;
3. While statement
while [condition] loop
[statement];
end loop;
4. Assertion Statement
assert [condition] "[report string]" severity [error, failure, note, warning];
5. Report Statement
report "[string]" severity [error, failure, note, warning];
B. Structure
[libraries]

entity [testing name] is
end [testing name];

architecture [test bench name] of [testing name] is
[component declaration to test]
[input and output signals for verification]
[clock signal]
[clock constant period]
begin
[component port mapping]

[clock process]

[assign component with signals]
[Process]
[assign inputs]
[wait for clock period]
[assert if wrong]
...
[assign inputs]
[wait for clock period]
[assert if wrong]
[assert complete is all tests are valid]
[Indefinite wait statement]
[end process]
end [test bench name];
IX. UCF
#[comment]
NET "[clock name]" LOC=[PIN/PORT];
NET "[clock name]" TNM_NET = LOC= "[clock name]";
TIMESPEC "TS_[clock name]" = PERIOD "[clock name]" [time frame] [metric prefix]hz HIGH 50%;

NET [signal name] LOC=[PIN/PORT];

NET [signal name]<[bit]> LOC=[PIN/PORT];

VHDL Resources

Comprehensive Source http://www.csee.umbc.edu/portal/help/VHDL/
Semantics and Language explanation http://www.cs.umbc.edu/portal/help/VHDL/summary.html
Slides on the basics http://users.ece.gatech.edu/~sudha/book/starters-guide/
VHDL by example http://esd.cs.ucr.edu/labs/tutorial/#gates