This section is devoted VHDL coding examples. Each section shows how to create a specific logic or synthesis function in VHDL. These code examples are intended as a sort VHDL cookbook approach, the user can look up a specific example and use that code to implement the particular function in their design.
The following hypertext list is a table of contents for this document. The user can navigate to any section of this document by "Pointing and Clicking" on any of the blue highlighted text. This will automatically direct the user to that particular subsection.
Register with Active High Clock.
Register with Active High Clock, Asynchronous Clear & Preset.
Register with Active High Clock and Asynchronous Clear.
Register with Active High Clock and Asynchrnonous Load.
Register with Active High Clock and Asynchronous Preset.
Register with Active Low Clock.
Register with Active Low Clock and Asynchronous Clear.
Synchronous Counter with Enable.
Synchronous Load Counter with Enable
Synchronous Clear Counter with Enable.
Synchronous Load and Clear Counter.
Synchronous Clear and Load Counter with Enable.
Synchronous Up / Down Counter.
Synchronous Up / Down Counter with Enable.
Synchronous Clear Up / Down Counter.
Synchronous Clear Up / Down Counter with Enable.
Synchronous Load Up / Down Counter.
Synchronous Load Up / Down Counter with Enable.
Synchronous Counter with an Asynchronous Clear.
Synchronous Counter with Asynchronous Load Function.
Creating User Defined Macrofunctions.
Process Statements include a set of sequential statements that assign values to signals. These statements allow you to perform step-by-step computations. Process Statements that describe purely combinatorial behavior can also be used to create combinatorial logic. To ensure that a process is combinatorial, its sensitivity list--i.e., the signals that, if their value changes, trigger the statements in the Process Statement to execute--must contain all signals that are read in the process.
Process Statements are also used to create sequential logic. See Sequential Logic in Document #2,Logic for more information.
The following example shows a Process Statement that counts the number of bits in signal d, which is the only signal contained in the sensitivity list that follows the PROCESS keyword, i.e., the only signal to which the process is sensitive.
entity process_example is
port
d : in bit_vector (2 downto 0);
q : out integer range 0 to 3 );
end process_example;
architecture vhdl_example of process_example is
begin
process(d)
-- count the number of set bits with the value 1 in word d
variable num_bits : integer ;
begin
num_bits := 0;
for i in d'range loop
if d(i) = '1' then
num_bits := num_bits + 1;
end if ;
end loop;
q <= num_bits;
end process ;
end vhdl_example ;
In this example, d is declared as an array in the Entity Declaration. Every time through the FOR loop, i is set to the next value, and d(i) accesses information from the d array. If d(i) equals 1, the If Statement increments num_bits. The num_bits variable is then assigned to the signal q, which is also declared in the Entity Declaration.
A register is implemented implicitly with a Register Inference. Register Inferences in VHDL support any combination of Clear, Preset, Clock Enable, and asynchronous Load signals. VHDL can infer memory elements from the following VHDL statements, all of which are used within a Process Statement:
If Statements can be used to imply registers for signals and variables in the clauses of the If Statement. Wait Statements can be used to imply registers in a synthesized circuit. VHDL creates flip-flops for all signals and some variables that are assigned values in any process with a Wait Statement. If you use a Wait Statement, it must be listed at the beginning of the Process Statement.
During logic synthesis, the VHDL compiler automatically inserts an instance of the register and connects it as specified in the If and/or Wait Statement(s). You can also implement registers explicitly with Component Instantiation Statements. Unlike Component Instantiations, Register Inferences are technology-independent.
The following example shows four methods to infer registers that are controlled by a Clock and asynchronous Clear, Preset, and Load signals.
entity register_inference is
port
d, clk, clr, pre, load, data : in BIT;
q1, q2, q3, q4, q5, q6, q7 : out BIT );
end register_inference ;
architecture vhdl_example of register_inference is
begin
process
-- insert lines of code from subsequent-- examples here (see below ).
--
end vhdl_example ;In this example, all seven processes are sensitive only to changes on the control signals--i.e., clk, clr, pre, and load--and to changes on the data signal data.
In all other Process Statements, an If Statement is used to prioritize the statements so that the asynchronous controls have priority over the clk signal. This prioritization ensures that the asynchronous control signal will be implemented as an asynchronous control of the D flipflop, rather than as logic connected to the D input of the flipflop.
Register with Active-High Clock.
This first Process Statements use a Wait Statement to detect changes on the clk signal. The first process waits for a rising edge on the clk signal (i.e., until clk = '1') and assigns the value d to the signal q1.
process
begin
wait until clk = '1';
q1 <= d;
end process
Register with Active-Low Clock.
This Process Statement uses a Wait Statement to detect changes on the clk signal. The process waits for a falling clk edge and assigns the value d to q2.
process
begin
wait until clk = '1';
q2 <= d;
end process
Register with Active-High Clock & Asynchronous Clear.
The third and fourth Process Statements have sensitivity lists that detect changes in the clk and clr control signals and give the clr signal the higher priority. The circuit waits for an event on clk or clr, then sets q3 and q4 to '0' if clr is '1' or '0'. Otherwise, clk'event and clk are evaluated to determine whether clk is rising or falling. When clk rises, the value of d is assigned to q3; when clk falls, the value of d is assigned to q4.
process (clk, clr)
begin
if clr = '1' thenq3 <= '0';
elsif clk'event and clk = '1' thenq3 <= d;
end if;
end process;
Register with Active-Low Clock & Asynchronous Clear.
The third and fourth Process Statements have sensitivity lists that detect changes in the clk and clr control signals and give the clr signal the higher priority. The circuit waits for an event on clk or clr, then sets q3 and q4 to '0' if clr is '1' or '0'. Otherwise, clk'event and clk are evaluated to determine whether clk is rising or falling. When clk rises, the value of d is assigned to q3; when clk falls, the value of d is assigned to q4.
process (clk, clr)
begin
if clr = '0' then
q4 <= '0';
elsif clk'event and clk = '0' then
q4 <= d;
end if ;
end process ;
Register with Active-High Clock & Asynchronous Preset.
This Process Statement is sensitive to clk and pre. The circuit waits for an event on clk or pre, then sets q5 to '1' if pre is '1'. Otherwise, clk'event and clk are evaluated to determine whether clk is rising. When clk rises, the value of d is assigned to q5.
process (clk, pre)
begin
if pre = '1' then
q5 <= '1';
elsif clk'event and clk = '1' then
q5 <= d;
end if;
end process;
Register with Active-High Clock & Asynchronous Load.
The sixth Process Statement is sensitive to clk , load, and data. The circuit waits for an event on any of these signals, then lets q6 to data if load is '1'. Otherwise, clk'event and clk are evaluated to determine whether clk is rising. When clk rises, the value of d is assigned to q6.
process (clk, load, data)
begin
if load = '1' then
q6 <= data;
elsif clk'event and clk = '1' then
q6 <= d;
end if;
end process;
Register with Active-High Clock & Asynchronous Clear & Preset.
This Process Statement is sensitive to clk, clr, and pre. The circuit waits for an event on any of these signals, then sets q7 to '0' if clr is '1' and to '1' if pre is '1'. Otherwise, clk'event and clk are evaluated to determine whether clk is rising. When clk rises, the value of d is assigned to q7.
process (clk, clr, pre)
begin
if clr = '1' then
q7 <= '0';
elsif pre = '1' then
q7 <= '1';
elsif clk'event and clk = '1' then
q7 <= d;
end if;
end process;
Implementing Counters.
A counter can be implemented implicitly with a Register Inference. VHDL can infer a counter from an if Statement that specifies a Clock edge together with logic that adds or subtracts a value from the signal or variable. The if Statement and additional logic should be inside a Process Statement.
In this example, all 14 processes are sensitive only to changes on the clk signal. All other control signals are synchronous. The first Process Statement describes an enabled counter. An If Statement describes the Clock edge, and an additional embedded If Statement uses the enable signal to control counter operation. At each rising Clock edge, the cnt variable is incremented by 1 and assigned to itself if the enable signal is '1'.
The next 12 counters are described in the same manner. An if Statement describes the Clock edge, and one or more embedded if Statement(s) use the enable, ld, d, clear, and up_down signals to control counter operation. The last counter uses the constant modulus declared in the process to control when the counter is reset to zero. At each Clock edge, the counter variable is cleared; loaded with the value d; or incremented or decremented by 1 then assigned to itself based on the value of the control signal(s).
The initial sections of code, the entity and architecture sections apply to all the subsequent counter examples. The actual functional difference between the counters occurs in the subsequent process statements.
entity counters is
port (
clk, clear, ld, enable, up_down : in bit;
d : in integer range 0 to 255;
qa, qb, qc, qd qe, qf, qg, qh, qi, qj, qk , ql, qm, qn :
out integer range 0 to 255;
);
end counters;
architecture counter_process_examples of counters is
begin
process
------
------ { this is where all following process statements are inserted }
------
end counter_process_examples ;
Synchronous Counter with Enable.
This counter does not count unless the enable line is active high.
process (clk) -- sensitive to clock.
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if enable = '1' then
cnt := cnt + 1;
end if;
end if ;
qa <= cnt;
end process;
Synchronous Load Counter.
This counter loads a value which is at the D inputs when the load signal "ld" is active and there is a rising edge on the clock.
process (clk)
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if ld = '0' then
cnt := d;
else
cnt := cnt + 1;
end if ;
end if ;
qb <= cnt;
end process ;
Synchronous Clear Counter.
This is a synchronous clear counter. This counter will be reset to zero on the positive transition of the clock when the clear input is zero. The counter will increment by one with each subsequent positive going clock transition.
process (clk)
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if clear = '0' then
cnt := 0;
else
cnt := cnt + 1;
end if ;
end if ;
qc <= cnt;
end process ;
Up / Down Counter.
In this implementation of an up / down counter the direction of the count is decided by the value assigned to the input up_down. If up_down = 1, then the count increments by one with each clock pulse. If up_down = 0 then the count is decremented by one with each clock pulse.
process (clk)
variable cnt : integer range 0 to 255;
variable direction : integer ;
begin
if (up_down = '1') then
direction := 1;
else
direction := -1;
end if ;
if (clk'event and clk = '1') then
cnt := cnt + direction;
end if ;
qd <= cnt;
end process ;
Synchronous Load Counter with Enable.
This synchronous load enable counter can only count or load on the rising edge of the clock. If load is zero, the value at the d inputs is loaded into the registers. If enable is 1, then the counter increments with each clock. The code is set such that the counter can not load and increment on the same clock cycle, this is due to the if-then-else statement.
process ( clk )
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if ld = '0' then
cnt := d;
elsif enable = '1' then
cnt := cnt + 1;
end if ;
end if ;
qe <= cnt;
end process ;
Synchronous Up / Down Counter with Enable.
The following is an example of a synchronous up / down counter with an enable function. This counter will only increment when the enable input is active high. Once again the integer variable "direction" is used to define whether the count is incremented or decremented. A different value beside one could be used if there was a need to count in a different discrete step.
process (clk)
variable cnt : integer range 0 to 255;
variable direction : integer ;
begin
if (up_down = '1') then
direction := 1;
else
direction := -1;
end if ;
if (clk'event and clk = '1') then
if enable = '1' then
cnt := cnt + direction;
end if ;
end if ;
qd <= cnt;
end process ;
Synchronous Clear Counter with Enable.
This is an example of a synchronous clear counter with an enable. The counter will be reset to zero on the rising edge of the clock when the clear input is 0. The counter increments with each clock when the enable input is active high. The if-then-else structure of the code prevents the counter from incrementing while a clear occurs.
process (clk)
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if clear = '0' then
cnt := 0;
elsif enable = '1' then
cnt := cnt + 1;
end if ;
end if ;
end if ;
qc <= cnt;
end process ;
Synchronous Load and Clear Counter.
This is a counter with a synchronous load and clear. The counter will only load, clear or count, on the rising edge of the clock. The if-then-else structure of the code prevents the counter from incrementing while either being cleared or loaded. The load function allows the values at the d inputs to be loaded into the counter registers when the ld input is active low and the clock transitions high.
process (clk)
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if clear = '0' then
cnt := 0;
else
if ld = '0' then
cnt := d;
else
cnt := cnt + 1;
end if ;
end if ;
end if ;
qh <= cnt;
end process ;
Synchronous Load Up / Down Counter.
This is an example of a synchronous load up/down counter. The variable direction controls whether the counter increments or decrements. While the variable cnt holds the actual counter value. This counter can be loaded with a pre-determined value; when the ld signal is active low the values at the d inputs is stored in the counter registers on a positive clock transition.
process (clk)
variable cnt : integer range 0 to 255;
variable direction : integer ;
begin
if (up_down = '1') then
direction := 1;
else
direction := -1;
end if;
if (clk'event and clk = '1') then
if ld = '0' then
cnt := d;
else
cnt := cnt + direction;
end if ;
end if ;
qi <= cnt;
end process ;
Synchronous Load Up / Down Counter with Enable.
This is an example of a synchronous load up/down counter. The variable direction controls whether the counter increments or decrements. While the variable cnt holds the actual counter value. This counter can be loaded with a pre-determined value, on a positive clock transition when the ld signal is active low. This counter will only count when the enable signal is active high.
process (clk)
variable cnt : integer range 0 to 255;
variable direction : integer;
begin
if (up_down = '1') then
direction := 1;
else
direction := -1;
end if ;
if (clk'event and clk = '1') then
if ld = '0' then
cnt := d;
elsif enable = '1' then
cnt := cnt + direction ;
end if ;
end if ;
end if ;
qj <= cnt;
end process ;
Synchronous Clear and Load Counter with Enable.
A synchronous clear load enable counter. This counter can be loaded or cleared synchronously. The if-then-else code structure prevents the counter from incrementing when clearing or loading. It can only count when the enable signal is active high.
process (clk)
variable cnt : integer range 0 to 255;
begin
if (clk'event and clk = '1') then
if clear = '0' then
cnt := 0;
elsif ld = '0' then
cnt := d;
elsif enable = '1' then
cnt := cnt + 1;
end if;
end if ;
qk <= cnt;
end process ;
Synchronous Clear Up / Down Counter.
A synchronous clear up/down counter. This counter will be cleared to zero on the rising edge of the clock when the clear input is active low. The if-then-else structure of the code prevents the count from incrementing when the counter is being cleared.
process (clk)
variable cnt : integer range 0 to 255;
variable direction : integer;
begin
if (up_down = '1') then
direction := 1;
else
direction := -1;
end if;
if (clk'event and clk = '1') then
if clear = '0' then
cnt := 0;
else
cnt := cnt + direction;
end if;
end if;
ql <= cnt;
end process;
Synchronous Clear Up / Down Counter with Enable.
A synchronous clear enable up/down counter. It will be cleared to zero on the rising edge of the clock, when the clear input is active low . The counter will only transition when the enable input is active high.
process (clk)
variable cnt : integer range 0 to 255;
variable direction : integer;
begin
if (up_down = '1') then
direction := 1;
else
direction := -1;
end if;
if (clk'event and clk = '1') then
if clear = '0' then
cnt := 0;
elsif enable = '1' then
cnt := cnt + direction;
end if ;
end if ;
end if ;
qm <= cnt;
end process ;
Modulus 100 Counter.
This is a synchronous modulus 100 Up counter. Any modulus counter is easy to build in VHDL. In this case, we assign an integer value to a constant called modulus. By comparing the value of the count cnt with modulus we create the roll over point of the counter. To change the modulus of the counter we just assign a new value to that constant.
process ( clk )
variable integer range 0 to 255;
constant modulus : integer := 100;
begin
if (clk'event and clk = '1') then
if cnt = modulus then
cnt := 0;
else
cnt := cnt + 1;
end if ;
end if ;
qn <= cnt;
end process ;
Synchronous Counter with Asynchronous Clear.
This is a synchronous counter with an asynchronous clear function. This counter will be reset to zero when the clear input is zero regardless of the state of the clock. The counter will increment by one with each subsequent positive going clock transition. Make sure that the clear signal is added to the process sensitivity list.
process (clk, clear )-- process is sensitive to both clk and clear.
variable cnt : integer range 0 to 255;
begin
if clear = '0' then
cnt := '0' ;
elsif (clk'event and clk = '1') then
cnt := cnt + 1;
end if ;
qc <= cnt;
end process ;
Synchronous Counter with Asynchronous Load function.
This is a synchronous counter with an asynchronous load function. This counter will be loaded with the values at the d inputs when the ld input is zero, regardless of the state of the clock. The counter will increment by one with each subsequent positive going clock transition. Make sure that the load signal is added to the process sensitivity list.
process (clk, ld )-- process is sensitive to both clk and load.
variable cnt : integer range 0 to 255;
begin
if ld = '0' then
cnt := d ;
elsif (clk'event and clk = '1') then
cnt := cnt + 1;
end if ;
qc <= cnt;
end process ;
Creating Multiplexers.
Selected Signal Assignment Statements list alternatives that are available for each value of an expression, then select a course of action based on the value of the expression. You can use Selected Signal Assignments to create multiplexers of any size , as shown below.
Selected Signals Example.
entity select_signals is
port (
d0, d1, d2, d3 : in bit
s : in integer range 0 to 3;
output : out bit );
end select_signals ;
architecture vhdl_example of select_signals is
begin
with s select -- creates a 4-to-1 multiplexer
output <= d0 when 0,
d1 when 1,
d2 when 2,
d3 when 3;
end vhdl_example ;Multiplexer Enumeration Example.
The selected signal can also be declared as an Enumeration Type, as shown below:
package meals_pkg is
type meal is ( breakfast, lunch, dinner, midnight_snack);
end meals_pkg;
use work.meals_pkg.all;
entity select_signals is
port (
previous_meal : in meal;
next_meal : out meal
);
end select_signals;
architecture vhdl_example of select_signals is
begin
with previous_meal select
next_meal <= breakfast when dinner | midnight_snack,
lunch when breakfast,
dinner when lunch;
end vhld_example ;When the value of the previous_meal multiplexer select signal is equal to the constant DINNER or MIDNIGHT_SNACK, the multiplexer output is BREAKFAST. When previous_meal is BREAKFAST, the output is LUNCH; when previous_meal is LUNCH, the output is DINNER.
Creating a User-Defined Macrofunction.
You can implement a user-defined macrofunction in VHDL with one of the following methods:
Declare a package for each project--containing Component Declarations for all lower-level entities--in the top-level design file. This method is described here.
Declare a component in the architecture in which it is instantiated.
The following example shows reg12.vhd, a 12-bit register that will be instantiated in a VHDL Design File that is higher in the project hierarchy. This register has an Entity Declaration and an Architecture Body for the user-defined macrofunction reg12.
entity reg12 is
port (
d : in bit_vector (11 downto 0);
clk : in bit ;
q : out bit_vector(11 downto 0));
end reg12;
architecture a of reg12 is
begin
process
begin
wait until clk = '1';
q <= d;
end process ;
end a ;The following example shows reg24.vhd, a VHDL Design File that declares reg24_package, identifies it with a Use Clause, then uses the reg12 component without requiring an additional Component Declaration.
package is
-- you must specify the ports of the macrofunction with-- Component Declaration.
component reg12
port(
d : in bit_vector(11 downto 0);
clk : in bit;
q : out bit_vector(11 downto 0));
end component ;
end reg24_package;
library work;
use work.reg24_package.all;
entity reg24 is
port (
d : in bit_vector (23 downto 0);
clk : in bit ;
q : out bit_vector (23 downto 0));
end reg24;
architecture a of reg24 is
begin
reg12a : reg12 port map (d => d(11 downto0 ), clk => clk,
q => q(11 downto 0));
reg12b : reg12 port map (d => d(23 downto 12), clk => clk,
q => q(23 downto 12));
end a;In this example, the ports for reg12 are listed in a Component Declaration in the reg24_package at the beginning of the file. The work library is declared with a Library Clause, and reg24_package in the work library is specified with a Use Clause. The Architecture Body for reg24 contains two instances of reg12.