The Basics Of VHDL Design
What & Why?
To accomplish a particular electronics application, a specific combination of hardware and software is needed. For instance, the CPU is a processor based system which is essentially just a silicon chip with software that enables serial execution of instruction sets. For larger applications, our silicon chips are usually PLDs(programmable logic devices) like PAL, CPLD and FPGA.
Now, the software required for these chips(and many others – including ASIC devices) is coded in a HARDWARE DESCRIPTION LANGUAGE(HDL) like VHDL or Verilog. VHDL is a nested acronym that stands for Very High Speed Integrated circuits(VHSIC) Hardware Description Language.
VHDL allows us to view a design at various levels of abstraction – Simulation gives us the waveforms of the circuit inputs and outputs & Synthesis gives us the possible combinations of gates/transistors to achieve the required operation.
In VHDL, any circuit/system is viewed as an entity(or a set of entities). The internal working of an entity is called its architecture. For instance, to design a half adder using VHDL, the entity would be the half adder itself with its input and output ports & the architecture would tell VHDL what happens between the input & the output ports.
A Sample Code in VHDL
Here is a sample code to design a half adder using VHDL. It is just to see how entity & architecture together make up the whole circuit design.
entity half_adder is port (A, B : in BIT; sum, carry : out BIT); end half_adder; architecture adder_architecture of half_adder is begin sum <= A xor B; carry <= A and B; end adder_architecture;
VHDL Libraries & Packages
Just like all other languages, VHDL has libraries that allow us to reuse certain frequently used pieces of code. The three basic libraries that go into almost all VHDL coding are -
library library_name; use library_name.package_name.package_part; --the syntax library ieee; use ieee.std_logic_1164.all; --use all parts of the std_logic_1164 package library std; use std.standard.all; --added by default library wprk; use work.all; --added by default --these are comment lines, by the way.
All packages contain useful data types & keywords. A full specification/definition of the packages can be seen at http://www.csee.umbc.edu/portal/help/VHDL/packages/
Data Objects & Data Types in VHDL
In VHDL, data can be in the form of a Constant, Variable or a Signal – which are also the keywords for declaring the same. “File” in VHDL is a sequence of values and hence, is also considered a data object. Each of these objects are of some specified data type.
constant RISE : TIME; --of type time variable COUNT : INTEGER; --of integer type signal CLOCK : BIT; --bit type
The following data types can be used in VHDL -
Scalar Types – enumeration, integer and floating point types including BOOLEAN, BIT, CHARACTER, INTEGER, NATURAL, REAL, etc.
Physical Literals – values representing physical quantities like CURRENT, VOLTAGE, etc. TIME is the only predefined literal(in the std package)
Composite types - contain a collection of values that may belong to different types like ARRAY and RECORD.
File Types – represents files in the host environment – help communicate with the host.
Operators in VHDL
Assignment Operators – used to assign a values to a data object. <= assigns a value to a signal & := assigns a value to a variable while => is used to assign values to individual/other vector elements.
signal x : bit; x <= '1'; variable y : std_logic_vector (0 to 3); --y is a vector with 4 elements y:="0000"; signal w : std_logic_vector (0 to 7); w <= (0=>'1', others=>'0'); --0th element is 1 and others are 0
Logical Operators – boolean logic ; all the basic logic gates. Data to be operated must be of type BIT, STD_LOGIC or STD_ULOGIC or their vector extentions.
Arithmetic Operators – for arithmetic (not boolean) operations including +, -, *, / , **, MOD, REM, ABS
Relational Operators – used for comparisons ( =, /=, > , < , <= & >= )
Shift Operators – shift logic left(sll), shift logic right(slr), shift left arithmetic(sla), shift right arithmetic(slr), rotate left(rol) & rotate right(ror) -
"1001010" sll 2 is "0101000" --shift left by 2 and replace missing digits on right by zeros "1001010" srl 4 is "0000100" --shift right by 4 and replace missing digits on left by zeros "1001010" sla 2 is "0101000" --shift left by 2 and replace missing digits by rightmost bit (here, 0) "1001010" sra 4 is "1111100" --shift right by 4 and replace missing digits by leftmost bit (here, 1) "1001010" rol 2 is "0101010" --shift left by 2 while moving overlapped digits to the right (here, 10) "1001010" ror 1 is "0100101" --shift right by 1 while moving overlapped digits to the left (here, 0)
Note : rol -1 is the same as ror 1, sla -2 is the same as sra 2 and so on.
Concurrent & Sequential Design Models
Unlike the sequential statements in other programming languages, VHDL code is concurrent code – which is good enough to build combinational circuits . However, to build sequential circuits, we need sequential code. We can implement sequential code in VHDL using some specific statements.
To write concurrent code, use WHEN, GENERATE & BLOCK statements & to write sequential code, use the PROCESS, FUNCTION & PROCEDURE statements.
Example – A 4:1 MUX using Concurrent Code
library ieee; use ieee.std_logic_1164.all; entity mux is port(a,b,c,d : in std_logic; sel : in std_logic_vector(1 downto 0); y : out std_logic); end mux; architecture mux_a of mux is begin y <= a when sel = "00" else b when sel = "01" else c when sel = "10" else d; end mux1;
Example – A Rising Edge-Triggered Delay FF using Sequential Code
library ieee; use ieee.std_logic_1164.all; entity dff is port(clock, reset, d : in std_logic; y : out std_logic); end dff; architecture dff_a of dff is begin process(reset, clock) --the sensitivity list contains objects that can cause the process to execute. begin if(reset <= '1') then q <= '0' elseif (clock'EVENT and clock = '1') then q <= d; --if an event occurs on clock and the event is a rising edge end if; end process; end dff_a;