Tips and Tricks Nuts and Bolts VHDL Coding Examples

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.



NOTE: Although Web Browsers will allow you to save this document, do not cut and paste this code into your VHDL editor. There are hidden Hyper Text Markup Language ( HTML ) commands embedded in this text which render in unuseable with a VHDL compiler.

vhdl around the globeReturn to top VHDL Document ( #1 ).

Go to Table of Contents




Hypertext Table of Contents

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.



Process Example.

Implementing Multiplexers.

Signal Selection Example.

Enumerated Types Example.

Implementing Registers.

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.

Implementing Counters.

Synchronous Counter with Enable.

Synchronous Clear Counter .

Synchronous Load Counter.

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 Modulus Counter.

Synchronous Counter with an Asynchronous Clear.

Synchronous Counter with Asynchronous Load Function.

Creating User Defined Macrofunctions.

Return to Top of Document.



Process Examples.

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.

Return to Top of Document.


Implementing Registers.

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.

Return to Top of Document.


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 

Return to Top of Document.


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 

Return to Top of Document.


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' then
                   q3 <= '0';

           elsif clk'event and clk = '1' then
                   q3 <= d;

           end if;

    end process; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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; 

Return to Top of Document.


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; 

Return to Top of Document.


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; 

Return to Top of Document.


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 ;

Return to Top of Document.


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; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ;

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ;

Return to Top of Document.


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;

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ;

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ; 

Return to Top of Document.


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 ;

Return to Top of Document.

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.

Return to Top of Document.


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.

Return to Top of Document.




Return to Intro Document.

Jump to Document 4: other VHDL & Synthesis Web Links

Return to Top of Document.