Исправление кода отладки для проекта десятичного счетчика в скорости подсчета 1 Гц - PullRequest
0 голосов
/ 18 января 2020

Я новичок в разработке плат FPGA и basys3. У меня есть проект для счетчика на 7 сегментных дисплеях на плате. Мы получили 3 разных слоя в качестве дизайна.

cntr / cntr_rtl / cntr_top / cntr_top_stru c / io_ctrl / io_ctrl_rtl /

И в проекте он должен отображать 7 сегмент, управляемый переключателями: считать вверх / считать вниз / параметры удержания / сброса:

Приоритеты для этих переключателей:

  1. сброс

  2. удержание

  3. направление счета

VHDL-файл верхнего уровня cntr_top.vhd

Имя порта Направление Описание

clk_i In Системные часы (100 МГц) )

reset_i In Асинхронный высокий активный сброс

sw_i (15: 0) В 16 переключателях

pb_i (3: 0) В 4 кнопках

ss_o (7: 0) Out Содержит значение для всех 7-сегментных цифр

ss_sel_o (3: 0) Out Выберите 7-сегментный ди git

io_ctrl clk_i In Системные часы (100 МГц)

reset_i In Асинхронный высокий активный сброс

cntr0_i (n: 0) In Di git 0 (из внутреннего лога c)

cntr1_i (n: 0) В Di git 1 (из целого rnal logi c)

cntr2_i (n: 0) в Di git 2 (из внутренней логики c)

cntr3_i (n: 0) в Di git 3 (из внутренней логики c)

sw_i (15: 0) В 16 переключателях (с платы ПЛИС)

pb_i (3: 0) В 4 кнопках (с платы ПЛИС)

ss_o (7: 0) Out на 7-сегментный дисплей платы FPGA

ss_sel_o (3: 0) Out Выбор 7-сегментного ди git

swclean_o (15: 0) Out 16 переключателей (для внутренней логики c)

pbclean_o (3: 0) Out 4 кнопки (для внутренней логики c)

cntr.vhd

clk_i In Системные часы (100 МГц)

reset_i In Асинхронный высокий активный сброс

cntrup_i In Считает, если сигнал равен '1'

cntrdown_i In Считает вниз если сигнал равен '1'

cntrreset_i In Устанавливает счетчик на 0x0, если сигнал равен '1'

cntrhold_i In Имеет значение счетчика, если сигнал равен '1'

cntr0_o (n : 0) Out Di git 0 (из внутренней логики c)

cntr1_o (n: 0) Out Di git 1 (из внутренней логики c)

cntr2_o (n: 0) Out Di git 2 (из внутренней логики c)

cntr3_o (n: 0) Out Di git 3 (из внутренней logi c)

Я также прикреплю файл к приложению. Теперь мой код работает и выполняет все функции правильно, но есть только одна проблема - это часть кода DEBOUNCE.

Я не использовал сигнал clk для кода, и я должен изменить его. Определенный данный тактовый сигнал должен быть использован.

Так что любой может дать мне предложение, как я могу исправить концепцию debounce в коде.

io_ctrl_rtl.vhd - код внизу:

library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


architecture rtl of io_ctrl is

constant COUNTVALUE : std_logic_vector(16 downto 0):= "01100001101010000"; 

signal s_enctr : std_logic_vector(16 downto 0):="00000000000000000";
signal s_2khzen : std_logic :='0';
signal s_1hzen : std_logic :='0';
signal s_2khzcount : std_logic_vector(3 downto 0) := "0000";
signal swsync0 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync0 : std_logic_vector(3 downto 0):="0000";
signal swsync1 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync1 : std_logic_vector(3 downto 0):="0000";
signal swtmp : std_logic_vector(15 downto 0):="0000000000000000";
signal pbtmp : std_logic_vector(3 downto 0):="0000";
signal swdebounced : std_logic_vector(15 downto 0):="0000000000000000";
signal pbdebounced : std_logic_vector(3 downto 0):="0000";
signal s_ss_sel : std_logic_vector(3 downto 0) := "0000";
signal s_ss : std_logic_vector(7 downto 0) := "00000000";
begin -- rtl
-----------------------------------------------------------------------------
--
-- Synchronize the inputs
--
-----------------------------------------------------------------------------
p_sync: process (clk_i, reset_i)
begin 
if reset_i = '1' then 
swsync0 <= (others => '0');
pbsync0 <= (others => '0');
swsync1 <= (others => '0');
pbsync1 <= (others => '0');
elsif clk_i'event and clk_i = '1' then

    swsync0 <=    sw_i;
    pbsync0 <=    pb_i;
    swsync1 <=     swsync0;
    pbsync1    <=    pbsync0;
    else null;
end if;
end process;

-----------------------------------------------------------------------------
--
-- Generate 1 KHz enable signal.
--
-----------------------------------------------------------------------------
p_slowen: process (clk_i, reset_i)
begin
if reset_i = '1' then        
    s_enctr <= (others => '0');
    s_2khzen <= '0';

elsif clk_i'event and clk_i = '1' then 
    if s_enctr = COUNTVALUE then    -- When the terminal counter is reached, set the release flag and reset the counter
        s_enctr <= (others => '0');
        s_2khzen <= '1';
        s_2khzcount <= std_logic_vector(to_unsigned(to_integer(unsigned( s_2khzcount )) + 1, 4));
    else 
        s_enctr <= std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 17)); -- As long as the terminal count is not reached: increment the counter.
        if    s_2khzen = '1' then 
        s_2khzen <= '0';
        end if; 
        end if;
    if s_2khzcount = "1010" then
        s_1hzen <= not s_1hzen;
        s_2khzcount <= "0000";
    end if;
end if;
end process p_slowen;
-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (s_1hzen, reset_i)
variable dbouncecntr : integer:=0;
begin 
if reset_i = '1' then 
        swdebounced <= "0000000000000000";
        pbdebounced <= "0000";
        dbouncecntr :=0;                                 -- Change clocking the process with signal from sens list.
else
    if (dbouncecntr = 0) then
                swtmp <= swsync1;
                pbtmp <= pbsync1;
                dbouncecntr := dbouncecntr + 1;
    elsif (dbouncecntr = 1) then
                if (swtmp = swsync1) then
                    swdebounced <= swsync1;
                end if;
                if (pbtmp = pbsync1) then
                    pbdebounced <= pbsync1;
                end if;
                dbouncecntr := 0;

        end if;
     end if;
end process p_debounce;
swclean_o <= swdebounced;
pbclean_o <= pbdebounced;
-----------------------------------------------------------------------------
--
-- Display controller for the 7-segment display
--
-----------------------------------------------------------------------------
p_displaycontrol: process (clk_i, reset_i)

variable v_scancnt : std_logic_vector(1 downto 0):= "00";
variable v_output : std_logic_vector(3 downto 0):="0000"; 
begin 
if reset_i = '1' then
v_scancnt := "00";
s_ss <= "00000000";
elsif clk_i'event and clk_i = '1' then 
     if    s_2khzen = '1' then 

        case v_scancnt is
            when "00" =>    
            v_output    := cntr0_i;
            s_ss_sel    <=    "0001";
            when "01" =>
            v_output     := cntr1_i;
            s_ss_sel    <=    "0010";
            when "10" =>
            v_output     := cntr2_i;
            s_ss_sel    <=    "0100";
            when "11" =>
            v_output     := cntr3_i;
            s_ss_sel    <=    "1000";
            when others =>
            v_output    := "1111";
            s_ss_sel    <=    "0001";
        end case;

        case v_output is             --ABCDEFG,    
            when "0000" => s_ss <= "11111100";  --0
            when "0001" => s_ss <= "01100000";  --1
            when "0010" => s_ss <= "11011010";  --2
            when "0011" => s_ss <= "11110010";  --3
            when "0100" => s_ss <= "01100110";  --4
            when "0101" => s_ss <= "10110110";  --5
            when "0110" => s_ss <= "10111110";  --6
            when "0111" => s_ss <= "11100000";  --7
            when "1000" => s_ss <= "11111110";  --8
            when "1001" => s_ss <= "11110110";  --9
            when others => s_ss <= v_scancnt & "000000";
        end case;

    if v_scancnt = "11" then
    v_scancnt := "00";
    else
        v_scancnt := std_logic_vector(to_unsigned(to_integer(unsigned( v_scancnt )) + 1, 2));
    end if;

    else null;
    end if;
    else null;

end if;

end process p_displaycontrol;

ss_o <= not s_ss;
ss_sel_o <= not s_ss_sel;
end rtl;

Код для: cntr_top_stru c .vhd

library IEEE;
use IEEE.std_logic_1164.all;

architecture rtl of cntr_top is

  component cntr                                                    -- component of cntr

    port (clk_i:        in  std_logic;                              -- 100 MHz system clock
          reset_i:        in  std_logic;                                -- async high active reset
          cntrup_i :    in  std_logic;                                --counts up if signal is '1'
          cntrdown_i :  in  std_logic;                                --counts down if signal is '1'
          cntrreset_i : in  std_logic;                                --sets counter to 0x0 if signal is '1'
          cntrhold_i :  in  std_logic;                                --holds count value if signal is '1'

          cntr0_o:        out std_logic_vector(3 downto 0);            --    Digit 0 (from internal logic)
          cntr1_o:        out std_logic_vector(3 downto 0);            --    Digit 1 (from internal logic)
          cntr2_o:        out std_logic_vector(3 downto 0);            --    Digit 2 (from internal logic)
          cntr3_o:        out std_logic_vector(3 downto 0));            --    Digit 3 (from internal logic)

  end component;

  component io_ctrl   ---- component io_crtl
    port (clk_i:        in  std_logic;                                -- 100 MHz system clock
          reset_i:        in  std_logic;                                -- async high active reset

          cntr0_i:        in std_logic_vector(3 downto 0);            --    Digit 0 (from internal logic)
          cntr1_i:        in std_logic_vector(3 downto 0);            --    Digit 1 (from internal logic)
          cntr2_i:        in std_logic_vector(3 downto 0);            --    Digit 2 (from internal logic)
          cntr3_i:        in std_logic_vector(3 downto 0);            --    Digit 3 (from internal logic)

          swclean_o:    out std_logic_vector(15 downto 0);
          pbclean_o:    out std_logic_vector(3 downto 0);

          ss_o:            out std_logic_vector(7 downto 0);            -- Contain the Value for All 7-Segment Digits     
          ss_sel_o:        out std_logic_vector(3 downto 0);            -- Select a 7-segment digits

          pb_i:            in std_logic_vector(3 downto 0);            --4 Buttons
          sw_i:            in std_logic_vector(15 downto 0) );              --16 Switches

  end component;

  -- Declare the signals that are used to connect the submodules.
  signal s_cntr0 : std_logic_vector(3 downto 0);
  signal s_cntr1 : std_logic_vector(3 downto 0);
  signal s_cntr2 : std_logic_vector(3 downto 0);
  signal s_cntr3 : std_logic_vector(3 downto 0);  
  signal s_cntrup         : std_logic;  
  signal s_cntrdown        : std_logic;  
  signal s_cntrreset     : std_logic; 
  signal s_cntrhold        : std_logic; 
  signal s_overflow : std_logic_vector(11 downto 0);
begin

--Instantiate the counter that is connected to the IO-Control
  i_cntr_top1 : cntr
  port map              
    (clk_i   => clk_i,
     reset_i   => reset_i,
     -- cntrdir_i  => s_cntrdir,                   --swsync_o(13);
     cntrup_i       => s_cntrup,                 --swsync_o(13);
     cntrdown_i     => s_cntrdown,                 --swsync_o(12);
     cntrreset_i    => s_cntrreset,             --swsync_o(15),
     cntrhold_i     => s_cntrhold,                 --swsync_o(14),

     cntr0_o   => s_cntr0,
      cntr1_o   => s_cntr1,
      cntr2_o   => s_cntr2,
     cntr3_o   => s_cntr3);

--Instantiate the IO control to which it is connected
  i_io_ctrl : io_ctrl
  port map
    (clk_i           => clk_i,
     reset_i           => reset_i,   
     swclean_o(12)    => s_cntrdown,
     swclean_o(13)    => s_cntrup,
     swclean_o(15)    => s_cntrreset,
     swclean_o(14)    => s_cntrhold,
     swclean_o(11 downto 0)    => s_overflow(11 downto 0),
     cntr0_i           => s_cntr0,
      cntr1_i           => s_cntr1,
      cntr2_i           => s_cntr2,
     cntr3_i           => s_cntr3,    

     ss_o            =>    ss_o,
     ss_sel_o        =>    ss_sel_o,
     sw_i            =>    sw_i,
     pb_i            =>    pb_i);

end rtl;

cntr_top.vhd

library IEEE;
use IEEE.std_logic_1164.all;

entity cntr_top is 
  port (clk_i :     in std_logic;                           -- First Data Bit
        reset_i :   in std_logic;                           -- Second Data Bit
        sw_i :      in std_logic_vector (15 downto 0);      -- 16 Switches Input    
        pb_i :      in std_logic_vector(3 downto 0);        -- 4 Buttons Input              
        ss_o :      out std_logic_vector(7 downto 0);       -- Contain the Value for All 7-Segment Digits           
        ss_sel_o :  out std_logic_vector(3 downto 0));      -- Select a 7-segment digits


end cntr_top;

io_ctrl.vhd

library IEEE;
use IEEE.std_logic_1164.all;
entity io_ctrl is
  port (clk_i :     in std_logic;                           --  System clock (100 MHZ)
        reset_i :   in std_logic;                           --  Asynchronous high active reset
        cntr0_i :   in std_logic_vector(3 downto 0);        --  Digit 0 from internal logic
        cntr1_i :   in std_logic_vector(3 downto 0);        --  Digit 1 from internal logic
        cntr2_i :   in std_logic_vector(3 downto 0);        --  Digit 2 from internal logic
        cntr3_i :   in std_logic_vector(3 downto 0);        --  Digit 3 from internal logic
        sw_i :      in std_logic_vector(15 downto 0);       --  16 switches (from FPGA board)
        pb_i :      in std_logic_vector(3 downto 0);        --  4 buttons (from FPGA board)             
        ss_o :      out std_logic_vector(7 downto 0);       --  to 7 segment displays of the FPGA board                     
        ss_sel_o :  out std_logic_vector(3 downto 0);       --  Selection of a 7 segment digit
        swclean_o:  out std_logic_vector(15 downto 0);      --  16 switches (to internal logic)
        pbclean_o : out std_logic_vector(3 downto 0));      --  4 buttons   
end io_ctrl;

cntr_rtl.vhd

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
architecture rtl of cntr is

constant COUNTVALUE : std_logic_vector(26 downto 0):= "000000000000000001111101000";
--constant COUNTVALUE : std_logic_vector(26 downto 0):= "101111101011110000100000000";

signal s_enctr : std_logic_vector(26 downto 0) := "000000000000000000000000000";
signal s_1hzen : std_logic :='0';
signal s_cntr0 : std_logic_vector(3 downto 0) :="0000";    -- All digits set to zero. 
signal s_cntr1 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr2 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr3 : std_logic_vector(3 downto 0) :="0000";

type s_state is (reset, hold, up, down);
signal s_present_state : s_state;
signal s_next_state : s_state;

begin

p_cntr: process(clk_i, reset_i)

variable v_digit0 : std_logic_vector(3 downto 0):= "0000";
variable v_digit1 : std_logic_vector(3 downto 0):= "0000";
variable v_digit2 : std_logic_vector(3 downto 0):= "0000";
variable v_digit3 : std_logic_vector(3 downto 0):= "0000";

begin

if reset_i = '1' then 

    v_digit0 := "0000";
    v_digit1 := "0000";
    v_digit2 := "0000";
    v_digit3 := "0000";
    s_enctr <= (others => '0');



elsif (clk_i'event and clk_i = '1') then
   s_present_state <= s_next_state;
   if s_enctr = COUNTVALUE then --When the number of terminals is reached, set the release flag and reset the counter
        s_enctr <= (others => '0');
        s_1hzen <= '1';

        case s_present_state is

            when up =>                                                                                      --counting up.
                if v_digit0 /= "1001" then
                    v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) + 1, 4));     -- incrementing the bits. 
                elsif v_digit0 = "1001" and v_digit1 /= "1001" then
                    v_digit0 := "0000";
                    v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) + 1, 4));
                elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 /= "1001" then
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) + 1, 4));
                elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 = "1001" and v_digit3 /= "1001"then
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := "0000";
                    v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) + 1, 4));
                else 
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := "0000";
                    v_digit3 := "0000";
                end if;

            when down =>                                                                                    --counting down.
                if v_digit0 /= "0000" then
                    v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) - 1, 4));     -- decrementing the bits. 
                elsif v_digit0 = "0000" and v_digit1 /= "0000" then
                    v_digit0 := "1001";
                    v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) - 1, 4));
                elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 /= "0000" then
                    v_digit0 := "1001";
                    v_digit1 := "1001";
                    v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) - 1, 4));
                elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 = "0000" and v_digit3 /= "0000"then
                    v_digit0 := "1001";
                    v_digit1 := "1001";
                    v_digit2 := "1001";
                    v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) - 1, 4));
                else 
                    v_digit0 := "1001";
                    v_digit1 := "1001";
                    v_digit2 := "1001";
                    v_digit3 := "1001";
                end if;

            when hold => null;                                                                              -- holding the counting. 
            when reset =>                                                                                   -- reset all the values to zero. 
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := "0000";
                    v_digit3 := "0000";

         end case;

    else 
        s_enctr <=std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 27)); 
        if  s_1hzen = '1' then 
        s_1hzen <= '0';
        end if; 
    end if;

    s_cntr0 <= v_digit0;
    s_cntr1 <= v_digit1;
    s_cntr2 <= v_digit2;
    s_cntr3 <= v_digit3;
end if;

end process  p_cntr;

    cntr0_o <= s_cntr0;
    cntr1_o <= s_cntr1;
    cntr2_o <= s_cntr2;
    cntr3_o <= s_cntr3;

----------------------------------------------------------------------------------------------------------------
-- State machine
----------------------------------------------------------------------------------------------------------------
p_states: process(s_present_state, cntrup_i, cntrdown_i, cntrreset_i, cntrhold_i,reset_i)
begin
case s_present_state is
when reset  =>                                                                      -- reset state conditions 

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when hold   =>                                                                      -- hold state conditions 

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when up =>                                                                          -- up count state conditions

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when down   =>                                                                      -- down count conditions 

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when others => s_next_state <= reset;
end case;

end process  p_states;

end rtl;

cntr.vhd

library IEEE;
use IEEE.std_logic_1164.all;

entity cntr is
  port (clk_i :     in std_logic;                           -- System clock (100 MHZ)
        reset_i :   in std_logic;                           -- Asysnchronous high active reset

        cntrup_i :      in std_logic;                       --counts up if signal is '1'
        cntrdown_i :    in std_logic;                       --counts down if signal is '1'
        cntrreset_i :   in std_logic;                       --sets counter to 0x0 if signal is '1'
        cntrhold_i :    in std_logic;                       --holds count value if signal is '1'

        cntr0_o :   out std_logic_vector(3 downto 0);       --  Digit 0 (from internal logic)
        cntr1_o :   out std_logic_vector(3 downto 0);       --  Digit 1 (from internal logic)
        cntr2_o :   out std_logic_vector(3 downto 0);       --  Digit 2 (from internal logic)
        cntr3_o :   out std_logic_vector(3 downto 0));      --  Digit 3 (from internal logic)
end cntr;

Пожалуйста, ждите ваших предложений.

Любая помощь будет очень полезна, спасибо всем.

здесь ниже пример для debounce, но не смог найти способ реализации.

-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (clk_i, reset_i)
begin -- process debounce
if reset_i = '1' then -- asynchronous reset (active high)
elsif clk_i'event and clk_i = '1' then -- rising clock edge
end if;
end process p_debounce;
swsync_o <= swsync;
pbsync_o <= pbsync;
------------------------------------------------------------

1 Ответ

0 голосов
/ 30 января 2020

Вы на правильном пути в том, что вам нужно синхронизировать асинхронные входы и отменить их.

Но ваш код отказов должен использовать отдельный анализатор для каждого входа со значением времени ожидания около 100 для тактовая частота 1 кГц.

Вот обобщенный c синхронизатор и расширитель, который использует параметры для задания ширины шины, количества регистров syn c и значения времени ожидания.

Synchroniser.vhd

--
-- Synchronise an asynchronous bus input to avoid metastability problems
--

--
-- Signal Synchroniser (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity SynchroniserBit is
    generic
    (
        reg_size: integer := 3  -- Default number of bits in sync register.
    );
    port
    (
        clock: in std_logic;
        async_in: in std_logic := '0';
        sync_out: out std_logic := '0';
        rise: out std_logic := '0';
        fall: out std_logic := '0'
    );
end;

architecture V1 of SynchroniserBit is
    constant MSB: integer := reg_size - 1;
    signal sync_reg: std_logic_vector(MSB downto 0) := (others => '0');
begin
    process (clock)
    begin
        if rising_edge(clock) then
            rise <= not sync_reg(MSB) and sync_reg(MSB - 1);
            fall <= sync_reg(MSB) and not sync_reg(MSB - 1);
            sync_reg <= sync_reg(MSB - 1 downto 0) & async_in;
        end if;
    end process;

    sync_out <= sync_reg(MSB);

end;

--
-- Bus Synchroniser (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Synchroniser is
    generic
    (
        reg_size: integer := 3;  -- Default number of bits in sync register.
        bus_size: integer := 8   -- Default bus width.
    );
    port
    (
        clock: in std_logic;
        async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
        sync_bus_out: out std_logic_vector(bus_size - 1 downto 0);
        rise_bus_out: out std_logic_vector(bus_size - 1 downto 0);
        fall_bus_out: out std_logic_vector(bus_size - 1 downto 0)
    );
end;

architecture V1 of Synchroniser is

    component SynchroniserBit is
        generic
        (
            reg_size: integer := 3  -- Default number of bits in sync register.
        );
        port
        (
            clock: in std_logic;
            async_in: in std_logic;
            sync_out: out std_logic;
            rise: out std_logic;
            fall: out std_logic
        );
    end component;

begin
    SyncGen: for i in 0 to bus_size - 1 generate
    begin
        Sync: SynchroniserBit
            generic map
            (
                reg_size => reg_size
            )
            port map
            (
                clock => clock,
                async_in => async_bus_in(i),
                sync_out => sync_bus_out(i),
                rise  => rise_bus_out(i),
                fall => fall_bus_out(i)
            );
    end generate;
end;

Debouncer.vhd

--
-- Debounce a bus.
--

--
-- Signal Debouncer (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity DebouncerBit is
    port
    (
        clock: in std_logic;
        counter: in integer;
        input: in std_logic;
        output: out std_logic := '0'
    );
end;

architecture V1 of DebouncerBit is
begin
    process(clock)
        variable counter_snapshot: integer := 0;
        variable previous_input: std_logic := '0';
    begin
        if rising_edge(clock) then
            -- If counter wraps around to counter_snapshot,
            -- a full debounce period has elapsed without a change in input,
            -- so output the debounced value.
            if counter_snapshot = counter then
                output <= previous_input;
            end if;
            -- If the input has changed, save a snapshot of the counter.
            if not(input = previous_input) then
                counter_snapshot := counter;
            end if;
            previous_input := input;
        end if;
    end process;
end;

--
-- Bus Debouncer (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Debouncer is
    generic
    (
        timeout: integer := 100;  -- Default timeout value.
        bus_size: integer := 8    -- Default bus width.
    );
    port
    (
        clock: in std_logic;
        bus_in: in std_logic_vector(bus_size - 1 downto 0);
        bus_out: out std_logic_vector(bus_size - 1 downto 0)
    );
end;

architecture V1 of Debouncer is

    component DebouncerBit is
        port
        (
            clock: in std_logic;
            counter: in integer;
            input: in std_logic;
            output: out std_logic
        );
    end component;

    -- One counter to be shared by all debouncers.
    -- Each debouncer takes a snapshot of the count value when its input changes value.
    signal counter: integer := 0;

begin
    -- Create the debounce period.
    process(clock)
    begin
        if rising_edge(clock) then
            if counter = timeout then
                counter <= 0;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;

    DebouncerGen: for i in 0 to bus_size - 1 generate
    begin
        Debounce: DebouncerBit
            port map
            (
                clock => clock,
                counter => counter,
                input => bus_in(i),
                output => bus_out(i)
            );
    end generate;
end;

SynchroniseDebounce.vhd

--
-- SynchroniseDebounce
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity SynchroniseDebounce is
    generic
    (
        reg_size: integer := 3;   -- Default number of bits in sync register.
        timeout: integer := 100;  -- Default timeout value.
        bus_size: integer := 8    -- Default bus width.
    );
    port
    (
        clock: in std_logic;
        async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
        db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
    );
end;

architecture V1 of SynchroniseDebounce is

    component Synchroniser is
        generic
        (
            reg_size: integer := 3;  -- Default number of bits in sync register.
            bus_size: integer := 8   -- Default bus width.
        );
        port
        (
            clock: in std_logic;
            async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
            sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
            rise_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
            fall_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
        );
    end component;

    component Debouncer is
        generic
        (
            timeout: integer := 100;  -- Default timeout value.
            bus_size: integer := 8    -- Default bus width.
        );
        port
        (
            clock: in std_logic;
            bus_in: in std_logic_vector(bus_size - 1 downto 0);
            bus_out: out std_logic_vector(bus_size - 1 downto 0)
        );
    end component;

    signal sync_bus_out: std_logic_vector(bus_size - 1 downto 0);
    signal rise_bus_out: std_logic_vector(bus_size - 1 downto 0);
    signal fall_bus_out: std_logic_vector(bus_size - 1 downto 0);

begin

    Synchroniser_Inst: Synchroniser
        generic map
        (
            reg_size => REG_SIZE,  -- Override default value.
            bus_size => BUS_SIZE   -- Override default value.
        )
        port map
        (
            clock => clock,
            async_bus_in => async_bus_in,
            sync_bus_out => sync_bus_out,  -- Goes to Debouncer_Inst
            rise_bus_out => rise_bus_out,
            fall_bus_out => fall_bus_out
        );

    Debouncer_Inst: Debouncer
        generic map
        (
            timeout => TIMEOUT,   -- Override default value.
            bus_size => BUS_SIZE  -- Override default value.
        )
        port map
        (
            clock => clock,
            bus_in => sync_bus_out,  -- From Synchroniser_Inst
            bus_out => db_sync_bus_out
        );

end;

Testbench.vhd

--
-- Test Bench
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

entity testbench is
end;

architecture V1 of testbench is

    component SynchroniseDebounce is
        generic
        (
            reg_size: integer := 3;   -- Default number of bits in sync register.
            timeout: integer := 100;  -- Default timeout value.
            bus_size: integer := 8    -- Default bus width.
        );
        port
        (
            clock: in std_logic;
            async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
            db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0)
        );
    end component;

    constant NUM_SWITCHES: integer := 16;
    constant NUM_PUSH_BUTTONS: integer := 4;
    signal switches_async, switches_db_sync: std_logic_vector(NUM_SWITCHES - 1 downto 0) := (others => '0');
    signal push_buttons_async, push_buttons_db_sync: std_logic_vector(NUM_PUSH_BUTTONS - 1 downto 0) := (others => '0');

    constant REG_SIZE: integer := 3;
    constant BUS_SIZE: integer := NUM_SWITCHES + NUM_PUSH_BUTTONS;
    signal async_bus_in, db_sync_bus_out, rise_bus_out, fall_bus_out: std_logic_vector(BUS_SIZE - 1 downto 0) := (others => '0');

    constant TIMEOUT: integer := 10;  -- Number of clock cycles in debounce period.

    signal clock: std_logic;
    constant PERIOD: time := 10 ns;  -- System clock frequency.
    signal stop_clock: boolean := false;

begin
    ClockGenerator: process
    begin
        while not stop_clock loop
            clock <= '0';
            wait for PERIOD / 2;
            clock <= '1';
            wait for PERIOD / 2;
        end loop;
        wait;
    end process ClockGenerator;

    Stimulus: process
        variable seed1, seed2: positive;
        variable rrand: real;
        variable irand: integer;

    begin
        switches_async <= (others => '0');
        push_buttons_async <= (others => '0');
        wait for 23 ns;

        -- Some noisy inputs.
        seed1 := 1;
        seed2 := 1;
        for n in 1 to 500 loop
            for i in 0 to NUM_PUSH_BUTTONS - 1 loop
                uniform(seed1, seed2, rrand);
                irand := integer(round(rrand));
                if irand = 0 then
                    push_buttons_async(i) <= '0';
                else
                    push_buttons_async(i) <= '1';
                end if;
            end loop;
            for i in 0 to NUM_SWITCHES - 1 loop
                uniform(seed1, seed2, rrand);
                irand := integer(round(rrand));
                if irand = 0 then
                    switches_async(i) <= '0';
                else
                    switches_async(i) <= '1';
                end if;
            end loop;
            wait for 1 ns;
        end loop;

        -- Pulse the push buttons.
        for i in 0 to NUM_PUSH_BUTTONS - 1 loop
            push_buttons_async(i) <= '1';
            wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
            push_buttons_async(i) <= '0';
        end loop;

        -- Pulse the switches.
        for i in 0 to NUM_SWITCHES - 1 loop
            switches_async(i) <= '1';
            wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
            switches_async(i) <= '0';
        end loop;
        wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
        stop_clock <= true;
        wait;
    end process Stimulus;

    DUT: SynchroniseDebounce
        generic map
        (
            reg_size => REG_SIZE,  -- Override default value.
            timeout => TIMEOUT,    -- Override default value.
            bus_size => BUS_SIZE   -- Override default value.
        )
        port map
        (
            clock => clock,
            async_bus_in => async_bus_in,
            db_sync_bus_out => db_sync_bus_out
        );

    -- Connect the input switches and input push buttons to the asynchronous bus input.
    async_bus_in <= switches_async & push_buttons_async;

    -- Connect the debounced and synchronised output bus to the debounced synchronised switches and push buttons.
    switches_db_sync <= db_sync_bus_out(NUM_SWITCHES + NUM_PUSH_BUTTONS - 1 downto NUM_PUSH_BUTTONS);
    push_buttons_db_sync <= db_sync_bus_out(NUM_PUSH_BUTTONS - 1 downto 0);
end;

Wavebench Waveforms

Бит 2 дебазированной синхронной шины (db_sync_bus_out) имеет высокий уровень, только когда достаточно долго импульс подается на вход (async_bus_in).

Testbench waveforms of Bit 2 of synchroniser and debouncer

...