Um contador de segundos é um bom exemplo para explorarmos alguns pontos do desenvolvimento de uma descrição de hardware. O contador aqui desenvolvido está em formato decimal (0000~9999).

O projeto foi desenvolvido com o kit de desenvolvimento Cyclone IV, disponível no mercado nacional, os detalhes deste kit podem ser visto no artigo Placa de FPGA com Cyclone IV.
A figura abaixo traz a representação do RTL (register transfer level) do nível mais alto do projeto (top level), nele podemos notar que o projeto está dividido em seis sub módulos de três componentes diferentes.
Contador
O primeiro módulo tem como função efetuar a contagem do ciclo de clock. No momento que este atingir o valor equivalente em Hz, o contador incrementa os dígitos em uma unidade, representando que um segundo se passou e distribui os dígitos em formato BCD ao próximo módulo. Por exemplo:
valor atual = 5639
saída esperada = 0101 0110 0011 1001
A descrição do hardware pode ser vista abaixo:
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
entity counter is
port (
clock_i : in std_logic;
reset_i : in std_logic;
-- output four digits
digit1_o : out std_logic_vector(3 downto 0);
digit2_o : out std_logic_vector(3 downto 0);
digit3_o : out std_logic_vector(3 downto 0);
digit4_o : out std_logic_vector(3 downto 0)
) ;
end counter ;
architecture rtl of counter is
-- 1 sec clock signals
constant value_1HZ_c : natural := 50000000; -- frequenci clock value.
signal clk_1s : std_logic;
signal cnt_s : integer := 0 ;
-- signals to count every digit 0001 up to 9999
signal unit_counter : integer := 0;
signal tens_counter : integer := 0;
signal hundred_counter : integer := 0;
signal thousand_counter : integer := 0;
begin
-- process for increment 1 sec clock
process(clock_i)
begin
if rising_edge(clock_i) then
if cnt_s = value_1HZ_c - 1 then
cnt_s <= 0;
clk_1s <= '1';
else
cnt_s <= cnt_s + 1;
clk_1s <= '0';
end if;
end if;
end process;
-- process for increment unit value,
-- reset retur all values to 0
process(clk_1s, reset_i)
begin
if reset_i = '0' then
unit_counter <= 0;
tens_counter <= 0;
hundred_counter <= 0;
thousand_counter <= 0;
else
if rising_edge(clk_1s) then
unit_counter <= unit_counter + 1;
if unit_counter >= 9 then
unit_counter <= 0;
tens_counter <= tens_counter + 1;
if tens_counter >= 9 then
tens_counter <= 0;
hundred_counter <= hundred_counter + 1;
if hundred_counter >= 9 then
hundred_counter <= 0;
thousand_counter <= thousand_counter + 1;
if thousand_counter >= 9 then
thousand_counter <= 0;
end if;
end if;
end if;
end if;
end if;
end if;
end process;
digit1_o <= std_logic_vector(to_unsigned(unit_counter , digit1_o'length));
digit2_o <= std_logic_vector(to_unsigned(tens_counter , digit2_o'length));
digit3_o <= std_logic_vector(to_unsigned(hundred_counter , digit3_o'length));
digit4_o <= std_logic_vector(to_unsigned(thousand_counter , digit4_o'length));
end architecture ;Note que no momento que o signal unit_counter atinge o valor de 10, esta retorna para 0 e incrementa o outro signal tens_counter. O processo se repete para os demais dígitos.
O bloco possui ainda um reset, para retornar ao valor 0.
Conversor BCD para 7- segmentos
Este é um módulo básico, presente em quase todos os cursos de FPGA disponíveis. Consiste de uma entrada em BCD e uma saída em 7 segmentos.
Neste projeto, foram utilizados quatro componentes desse, um para cada dígito.
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
entity bcd_seven_seg is
port (
clock_i : in std_logic;
bcd_i : in std_logic_vector(3 downto 0);
seven_o : out std_logic_vector(6 downto 0)
) ;
end bcd_seven_seg ;
architecture rtl of bcd_seven_seg is
begin
process (clock_i)
begin
if rising_edge(clock_i)then
case bcd_i is
when "0000" => seven_o <= "0000001"; -- "0"
when "0001" => seven_o <= "1001111"; -- "1"
when "0010" => seven_o <= "0010010"; -- "2"
when "0011" => seven_o <= "0000110"; -- "3"
when "0100" => seven_o <= "1001100"; -- "4"
when "0101" => seven_o <= "0100100"; -- "5"
when "0110" => seven_o <= "0100000"; -- "6"
when "0111" => seven_o <= "0001111"; -- "7"
when "1000" => seven_o <= "0000000"; -- "8"
when "1001" => seven_o <= "0000100"; -- "9"
when "1010" => seven_o <= "0000010"; -- a
when "1011" => seven_o <= "1100000"; -- b
when "1100" => seven_o <= "0110001"; -- C
when "1101" => seven_o <= "1000010"; -- d
when "1110" => seven_o <= "0110000"; -- E
when others => seven_o <= "0000001"; -- F
end case;
end if;
end process;
end architecture ;Mux 4 dígitos
O terceiro componente deste projeto está representado por um multiplexador, responsável por integrar os quatro dígitos ao display, variando o anodo, ativando um a cada ciclo de aproximadamente 330µs.
A cada ciclo a saída, o digit_o e o anode_o variam seus valores em quatro fases, sendo uma para unidade, outra para dezena, mais uma para centena e uma última para milhar.
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
entity four_digit_mux is
port (
clock_i : in std_logic;
reset_i : in std_logic;
digit1_i : in std_logic_vector (6 downto 0);
digit2_i : in std_logic_vector (6 downto 0);
digit3_i : in std_logic_vector (6 downto 0);
digit4_i : in std_logic_vector (6 downto 0);
segment_o : out std_logic_vector (6 downto 0);
anode_o : out std_logic_vector (3 downto 0)
) ;
end four_digit_mux ;
architecture arch of four_digit_mux is
signal period_display : std_logic_vector (17 downto 0);
signal led_activating_counter : std_logic_vector (1 downto 0);
begin
-- process add value in period_display
process (clock_i,reset_i)
begin
if reset_i = '0' then
period_display <= (others => '0');
elsif rising_edge(clock_i)then
period_display <= period_display + 1;
end if;
end process;
-- chance value each 25M/65536 = 2.6 ms
led_activating_counter <= period_display(17 downto 16);
process (led_activating_counter)
begin
case led_activating_counter is
when "11" =>
anode_o <= "0111";
segment_o <= digit1_i;
when "10" =>
anode_o <= "1011";
segment_o <= digit2_i;
when "01" =>
anode_o <= "1101";
segment_o <= digit3_i;
when others =>
anode_o <= "1110";
segment_o <= digit4_i;
end case;
end process;
end architecture;Contador de 4 dígitos (top level)
O top level deste projeto não possui nenhuma lógica em sua arquitetura, apenas a instância dos componentes e sua integração através dos signals.
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
entity counter_4_digt is
port (
clock_i : in std_logic;
reset_i : in std_logic;
digit_o : out std_logic_vector(6 downto 0);
anode_o : out std_logic_vector(3 downto 0)
) ;
end counter_4_digt ;
architecture rtl of counter_4_digt is
signal digit1_bcd , digit2_bcd , digit3_bcd , digit4_bcd : std_logic_vector(3 downto 0);
signal digit1_seven, digit2_seven, digit3_seven, digit4_seven : std_logic_vector(6 downto 0);
component counter is
port (
clock_i : in std_logic;
reset_i : in std_logic;
digit1_o : out std_logic_vector(3 downto 0);
digit2_o : out std_logic_vector(3 downto 0);
digit3_o : out std_logic_vector(3 downto 0);
digit4_o : out std_logic_vector(3 downto 0)
) ;
end component;
component bcd_seven_seg is
port (
clock_i : in std_logic;
bcd_i : in std_logic_vector(3 downto 0);
seven_o : out std_logic_vector(6 downto 0)
) ;
end component ;
component four_digit_mux is
port (
clock_i : in std_logic;
reset_i : in std_logic;
digit1_i : in std_logic_vector (6 downto 0);
digit2_i : in std_logic_vector (6 downto 0);
digit3_i : in std_logic_vector (6 downto 0);
digit4_i : in std_logic_vector (6 downto 0);
segment_o : out std_logic_vector (6 downto 0);
anode_o : out std_logic_vector (3 downto 0)
) ;
end component ;
begin
counter_1 : counter
port map (
clock_i => clock_i,
reset_i => reset_i,
digit1_o => digit1_bcd,
digit2_o => digit2_bcd,
digit3_o => digit3_bcd,
digit4_o => digit4_bcd
);
bcd_1 : bcd_seven_seg port map (clock_i => clock_i, bcd_i => digit1_bcd, seven_o => digit1_seven);
bcd_2 : bcd_seven_seg port map (clock_i => clock_i, bcd_i => digit2_bcd, seven_o => digit2_seven);
bcd_3 : bcd_seven_seg port map (clock_i => clock_i, bcd_i => digit3_bcd, seven_o => digit3_seven);
bcd_4 : bcd_seven_seg port map (clock_i => clock_i, bcd_i => digit4_bcd, seven_o => digit4_seven);
four_digit_mux_1 : four_digit_mux
port map(
clock_i => clock_i,
reset_i => reset_i,
digit1_i => digit1_seven,
digit2_i => digit2_seven,
digit3_i => digit3_seven,
digit4_i => digit4_seven,
segment_o => digit_o,
anode_o => anode_o
);
end architecture ;Testbench e forma de onda
Abaixo pode ser visto o Test Bench desenvolvido para simular este projeto. O Testbench, traduzido literalmente como bancada de teste, é uma descrição auxiliar (mas indispensável), que permite simular o funcionamento da descrição de hardware.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.env.finish;
entity counter_4_digit_tb is
end counter_4_digit_tb;
architecture sim of counter_4_digit_tb is
constant clk_hz : integer := 100e6;
constant clk_period : time := 1 sec / clk_hz;
signal clk : std_logic := '1';
signal rst : std_logic := '1';
signal digit_tb : std_logic_vector(6 downto 0);
signal anode_tb : std_logic_vector(3 downto 0);
begin
clk <= not clk after clk_period / 2;
DUT : entity work.counter_4_digt(rtl)
port map (
clock_i => clk,
reset_i => rst,
digit_o => digit_tb,
anode_o => anode_tb
);
SEQUENCER_PROC : process
begin
wait for clk_period * 2;
rst <= '1';
end process;
end architecture;Podemos notar na forma de onda da simulação o fato de que a partir do 1s um dígito apresenta valor 1 e os demais permanecem como 0.
Conexão com os pinos
Abaixo podemos ver a planilha de conexão com os pinos físicos do kit de desenvolvimento.
Conclusão
Esta proposta bem simples consegue nos fornecer a ideia de como integrar componentes em VHDL. Caso queira ver mais a fundo, os links do projeto estão disponíveis neste link!
Se interessou e não sabe por onde começar? Recomendo a publicação Projetos para Começar com HDL.









Trabalho muito bom. Parabéns!