Up Counter - red-bote/VHDL_Demos GitHub Wiki
A demonstration of a Modulo Maximum counter from the Xilinx XST User Guide UG687.
You can clone a github repo to obtain the code files for the Xilinx XST Examples.
Setup
In a new Vivado project, create a top VHDL file, and copy the Basys3 constraints into the project. External ports are created for clk and reset, and enabled in the constraints file. In the generated top file, uncomment use IEEE.NUMERIC_STD.ALL;
to make the VHDL unsigned type available.
Add Sources, Add Files and browse to counters_8.vhd in XSTUG examples
A description of counters_8 is provided in the comment block, shown here along with the entity declaration:
--
-- 4-bit Signed Up Counter with Asynchronous Reset and Modulo Maximum
--
-- Download: ftp://ftp.xilinx.com/pub/documentation/misc/xstug_examples.zip
-- File: HDL_Coding_Techniques/counters/counters_8.vhd
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity counters_8 is
generic (MAX : integer := 12);
port(C, CLR : in std_logic;
Q : out integer range 0 to MAX-1);
end counters_8;
The counters_8 component implements output Q as unsigned, so the counter actually has a possible range far beyond that of 4-bit (probably a copy-and-paste error in the comment block). MAX is also defined as an integer quantity with a default value of 12 that would establish Q as an integer with range 0 to 11. The VHDL generic attribute allows the entity to be parameterized. The value of MAX can be specified in the component instantiation allowing counters_8 to implement counters with different terminal counts. The range of Q then is not necessarily limited to power-of-2, as a 32-bit signed integer could have a range of [-(2^31),(2^31)-1]. However, counters_8 is strictly an up-counter and provides no input to specify the start value at reset, so the range of Q is [0,2147483647] as a 32-bit signed integer.
In the example, u_counter is an entity instantiation, which avoids having to make a copy of the component declaration. A generic MODN with value 16 is declared in the counters_top entity.
entity counters_top is
generic ( constant MODN : integer := 16);
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC);
end counters_top;
architecture archi of counters_top is
signal counter : integer range 0 to MODN-1;
begin
u_modulo_counter : entity work.counters_8
generic map (MAX => MODN)
port map(
C => clk,
CLR => reset,
Q => counter -- integer range 0 to MAX-1
);
end archi;
In a simulation the counter is shown to reset/roll-over as expected:
For further development and experimentation, the counter limit is increased and the upper-bits connected to LEDs on the board.
Note that attempting to define an integer larger than (2**31)-1 results in an error [Synth 8-278] expression -2147483648 out of range ...
For the following code example, the integer must convert to a std_logic_vector to drive the LED bus. Credit and appreciation must be given to NANDLAND upon which I rely extensively for straightforward examples of VHDL type conversions.
Uncomment --use IEEE.NUMERIC_STD.ALL;
Add new signal of type std_logic_vector to convert counter to 31-bit register:
signal led_out : std_logic_vector(30 downto 0); -- 2^31-1 = 2147483647d = 7FFFFFFFh
The conversion step first uses the to_unsigned
macro to convert counter from integer to unsigned type. The unsigned type is defined in terms of a bit-width, and the length operator is used to inform the to_unsigned macro about the bit-width of the led_out register that receives the converted counter value:
led_out <= std_logic_vector(to_unsigned(counter, led_out'length));
led <= led_out(30 downto 15);
Code:
entity counters_top is
generic ( constant MODN : integer := (2**31)-1);
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
led : out STD_LOGIC_VECTOR (15 downto 0));
end counters_top;
architecture archi of counters_top is
signal counter : integer range 0 to MODN-1;
signal led_out : std_logic_vector(30 downto 0); -- 2^31-1 = 2147483647d = 7FFFFFFFh
begin
u_modulo_counter : entity work.counters_8
generic map (MAX => MODN)
port map(
C => clk,
CLR => reset,
Q => counter -- integer range 0 to MAX-1
);
led_out <= std_logic_vector(to_unsigned(counter, led_out'length));
led <= led_out(30 downto 15);
end archi;
DRC Warnings
Future editions of this guide will likely discuss VHDL processes in more detail and about warnings from design rule checks (DRC warnings):
- Implementation warning: [Place 46-29] place_design is not in timing mode. Skip physical synthesis in placer
The process block drives the LED output register and satisfies the timing expectation of the synthesis tool.
- the process is triggered when any of the signals in the sensitivity list change
- the process synchronized to clock signal should only have the clock signal in the sensitivity list
- statements within a process block occur sequentially (signal updates occur only at the end of the process though)
clk_proc: process(clk)
begin
if rising_edge(clk)
then
led_out_reg <= std_logic_vector(to_unsigned(counter_out, counter_reg'length));
end if;
end process;
The complete demo project can be found in the VHDL Demos repo.