lightbulb Tip of the Month


We can update you automatically when our Tip of the Month changes.
To receive regular notification of updates to our Tip of the Month section, click here.


Top-down Design and Synthesis Issues for
Sequential Processes (that's two tips!)

The Doulos Design Fitness Challenge is an annual event held at an EDA-oriented UK show. The focus of the Challenge this year was on measuring engineers’ ability to use VHDL for a real design task.

Engineers were asked to design a counter in VHDL by writing a complete register transfer level VHDL architecture from the following specification and entity declaration. The VHDL description was to be synthesizable, and had to be legal VHDL!

The circuit is an 8 bit synchronous counter, with an enable, a parallel load, and an asynchronous reset. The counter loads or counts only when the enable is active. When the load is active, Data is loaded into count.

The counter has two modes: binary and decade. In binary mode, it is an 8 bit binary counter. In decade mode, it counts in two 4 bit nibbles, each nibble counting from 0 to 9, and the bottom nibble carrying into the top nibble, such that it counts from 00 to 99 decimal.

The truth table of the counter is as follows (- means don’t care):

Reset	Clock	Enable	Load	Mode	Count	
0	-	-	-	-	0	
1	^	1	-	-	Count	
1	^	0	0	-	Data	
1	^	0	1	0	Count + 1 (binary)	
1	^	0	1	1	Count + 1 (decade)	

and this is the VHDL entity declaration:

library IEEE;
use IEEE.Std_logic_1164.all;

entity COUNTER is
  port (Clock : in  Std_logic;
        Reset : in  Std_logic;
        Enable: in  Std_logic;
        Load  : in  Std_logic;
        Mode  : in  Std_logic;
        Data  : in  Std_logic_vector(7 downto 0);
        Count : out Std_logic_vector(7 downto 0));

end;

So, how do you apply top-down design principles, a knowledge of synthesizable VHDL constructs and good coding finesse to this problem? Let's have a look...

It is important to understand that conceptually, a counter is a register with the output fed back to the input via an incrementer. Hence the VHDL code will reflect this concept. For example,

  -- inside a process
    Q <= Q + 1;

The design challenge introduces some key VHDL coding aspects that need to borne in mind for synthesis. The most fundamental is the use of the classic asynchronous-reset-plus-clock single-process style of VHDL code.

  process (Clock, Reset)
  begin
    if Reset = '0' then
      -- reset register, Q <= 0
    elsif Clock'event and Clock = '1' then
      -- increment register, Q <= Q + 1;
    end if;
  end process;

The essence of the code structure is that the clock and reset need to be in the sensitivity list; an appropriate event on either signal will cause one of the two ‘if’ branches to execute. Now that we have defined the basic structure of the process, we will go on to fill in the two ‘if’ branches.

The reset branch is very simple:

    -- inside a process
    if Reset = '0' then
      Q  <= "00000000"; -- alternatively, Q <= (others => '0');

The clock branch needs to contain the functionality of the other four truth table entries; the code reflects the priority of those inputs directly. The enable signal has the highest priority, with nothing happening when it is high; next in priority is the load signal. Hence inside the enable block we will have,

    -- inside a process
      if Enable = '0' then
      -- enable counter functionality
        if Load = '0' then
        -- load data
        else
        -- implement counting based on mode signal
        end if;
      end if; 

For the actual increment statement (remember, Q <= Q + 1;), it is desirable to combine this functionality for either mode to ensure that only one piece of incrementer hardware is synthesised. So far, the detailed structure of the process has been derived from the truth table in a top-down design manner. Now we need to code the VHDL with a view to its implementation.

    -- inside a process
      if Load = '0' then
        -- load data
      else
        if lower_nibble_count /= max_in_either_mode then
          -- increment lower nibble
        else
          -- wrap lower nibble back to zero
          if upper_nibble_count /= max_in_either_mode then
            -- increment upper nibble
          else
            -- wrap upper nibble back to zero
          end if;
        end if; 
      end if; 

Although we are only providing a structure for the detail of the VHDL code in the above code snippet, it is notable that the word ‘increment’ appears only twice and that it applies to nibbles - the code is structured to synthesise two 4-bit incrementers. This is a subtle point that was missed by all who entered the challenge!

OK, let's fill out the detail of the code structure presented so far in order to generate a model solution. This is given at then end of the section.

Note that the “+” operator needs to be overloaded because “+” is not defined in the IEEE std_logic_1164 package for std_logic_vector types. Typically, it is defined in a synthesis vendor’s tool-specific package (or you can write your own!). In the model solution, you will see the use clause, use ieee.std_logic_unsigned.all; which makes the overloaded “+” operator visible to this architecture.

A more subtle aspect is the use of the “+” operator to produce the incrementer hardware. In order to avoid duplication of incrementers, each nibble is regarded separately. Discounting this approach may lead to the creation of duplicate incrementers. For example,

  -- inside a clocked process
    if mode = '0' then                   -- 8-bit binary
      Q <= Q + '1';
    else                                 -- two decade counters
      if Q(3 downto 0) = "1001" then     -- wrap lower decade
        Q(3 downto 0) <= "0000";          
        if Q(7 downto 4) /= "1001" then  -- increment upper decade
          Q(7 downto 4) <= Q(7 downto 4) + '1';
        else                             -- wrap upper decade
          Q(7 downto 4) <= "0000";
        end if;
      else                               -- increment lower decade
        Q(3 downto 0) <= Q(3 downto 0) + '1';
      end if;
    end if;

This leads to the creation of an 8-bit incrementer for the binary mode of counting, plus one or two individual 4-bit incrementers for the decade count mode. The actual number of incrementers depends on the synthesis tool’s ability to share resources.

Finally, note that an internal signal Q was used, rather than the port signal count, which, as an output, may not be read in a process.

In summary, we have applied top-down design principles to create a synthesizable VHDL architecture containing a single process. The detailed code implementation was produced with the pitfalls of synthesis clearly borne in mind.

The rest of this section gives a model solution:

-- counter
-- 8 bits
-- synchronous, positive edge
-- binary/decade
-- asynchronous reset, active low
-- synchronous parallel load, active high
-- synchronous enable, active low
-- binary counter mode 0 = 8 bits
-- decade counter mode 1 = 2x4 bits
-- reset has priority over enable over load

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity COUNTER is
  port (Clock : in  Std_logic;
        Reset : in  Std_logic;
        Enable: in  Std_logic;
        Load  : in  Std_logic;
        Mode  : in  Std_logic;
        Data  : in  Std_logic_vector(7 downto 0);
        Count : out Std_logic_vector(7 downto 0));
end;

architecture Model_Solution of Counter is
  constant nibble_max : std_logic_vector(3 downto 0) := "1111";
  constant decade_max : std_logic_vector(3 downto 0) := "1001";
  constant zero_nibble : std_logic_vector(3 downto 0) := "0000";
  constant zero_byte : std_logic_vector(7 downto 0) := "00000000";
  signal Q: Std_logic_vector(7 downto 0);
begin
  process (Clock, Reset)
  begin
    if Reset = '0' then
      Q <= zero_byte;
    elsif Clock'event and Clock = '1' then
      if Enable = '0' then
        if Load = '0' then
          Q <= Data;
        elsif (Mode = '0' and Q(3 downto 0) /= nibble_max) or
              (Mode = '1' and Q(3 downto 0) /= decade_max) then
          Q(3 downto 0) <= Q(3 downto 0) + '1';

        else
          Q(3 downto 0) <= zero_nibble;
          if (Mode = '0' and Q(7 downto 4) /= nibble_max) or
             (Mode = '1' and Q(7 downto 4) /= decade_max) then
            Q(7 downto 4) <= Q(7 downto 4) + '1';
          else
            Q(7 downto 4) <= zero_nibble;
          end if; 
        end if;
      end if;
    end if;
  end process;
  Count <= Q;
end;

teaching pointerComprehensive VHDL for FPGA/ASIC
chip iconAdvanced VHDL for Synthesis


river sceneDoulos Home Page

Copyright 1995-1996 Doulos
This page was last updated 12th March 1996.

mail iconWe welcome your e-mail comments. Please contact us at: webmaster@doulos.co.uk