级联计数器的十进制数字增量太晚

Decade Digit of Cascading Counter increments too late

我正在尝试设计一个两位数计数器,以循环方式向上和向下计数 00 和 99 之间的计数。我大部分时间都在使用它,但是,无论我尝试什么,我都无法让十进制数字与第一位数字保持同步。我现在的结果是这样的:

08 -> 09 -> 00 -> 11 ... 18 -> 19 -> 10 -> 21

21 -> 20 -> 29 -> 18 ... 11 -> 10 -> 19 -> 08

由此看来,从第一位溢出到十进制位似乎有所延迟。我已经尝试了几件事来尝试解决这个问题。提供任何有益结果的唯一方法是添加一个额外的 if 语句,提前发送溢出状态,但这只是表面修复。如果我在第一个数字为 8 或 0 时停止计数器,然后再次启动它,我会回到与以前相同的问题。

我也尝试制作一个额外的 'synchronizer' 模块,想也许我可以设置它,所以即使它们不同步,它们也会像同步一样显示,但它没有任何改变。

两周多来我一直在努力解决这个问题,但我已经束手无策了。

这是我的计数器代码,如果有人想检查同步器,我们将不胜感激。

**我正在使用 VHDL,使用 Vivado 2015.2 对 Zybo Digilent 开发板进行编程

个位数计数器模块,溢出成为十进制位使能。

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

entity counter is
    generic(N      : positive := 4);
    port(
        AR       : in  STD_LOGIC;
        clk      : in  STD_LOGIC;
        ld       : in  STD_LOGIC;
        en       : in  STD_LOGIC;
        up_dn    : in  STD_LOGIC;
        D        : in  STD_LOGIC_VECTOR(N - 1 downto 0);
        overflow : out STD_LOGIC;
        Q        : out STD_LOGIC_VECTOR(N - 1 downto 0);
        sync_in  : in STD_LOGIC;
        sync_out : out STD_LOGIC
    );
end counter;

architecture counter of counter is
    signal Qt : std_logic_vector(N - 1 downto 0);
    signal OvrFlw : std_logic;
    signal sync : std_logic;

begin
    process(clk, AR)
    begin
        if (AR = '1') then
            Qt       <= (others => '0');
            OvrFlw <= '0';
            sync <= sync_in;
        elsif (clk = '1' and clk'event) then
            if ld = '1' then
                Qt <= D;
                sync <= sync_in;
            elsif en = '1' then
                if up_dn = '0' then     -- if counting down
                    if (unsigned(Qt) = 0) then
                        Qt       <= "1001";--(others => '1');
                        OvrFlw <= '1';
                        sync <= sync_in and en;
                    --elsif (unsigned(Qt) = 1) then
                    --    Qt       <= std_logic_vector(unsigned(Qt) - 1);
                    --    OvrFlw <= '1';
                    else
                        Qt       <= std_logic_vector(unsigned(Qt) - 1);
                        OvrFlw <= '0';
                        sync <= sync_in and en;
                    end if;
                else                    -- if counting up
                    if (unsigned(Qt) = 2**N-7) then
                        Qt       <= (others => '0');
                        OvrFlw <= '1';
                        sync <= sync_in and en;
                    --elsif (unsigned(Qt) = 2**N-8) then
                    --    Qt       <= std_logic_vector(unsigned(Qt) + 1);
                    --    OvrFlw <= '1';
                    else
                        Qt       <= std_logic_vector(unsigned(Qt) + 1);
                        OvrFlw <= '0';
                        sync <= sync_in and en;
                    end if;
                end if;
            end if;
        end if;
    end process;

    sync_out <= sync;
    Q <= Qt;
    overflow <= OvrFlw;
end counter;

这是我尝试组合的同步器代码。不知道它是否真的相关,但我想我会把它放起来以防万一。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Synchronizer is
    generic(N      : positive := 4);
    Port (  
          MSB_Sync : in  STD_LOGIC;
          LSB_Sync : in  STD_LOGIC;
          MSB_Q    : in  STD_LOGIC_VECTOR(N-1 downto 0);
          LSB_Q    : in  STD_LOGIC_VECTOR(N-1 downto 0);
          MSB_Out  : out STD_LOGIC_VECTOR(N-1 downto 0);
          LSB_Out  : out STD_LOGIC_VECTOR(N-1 downto 0));
end Synchronizer;

architecture Behavioral of Synchronizer is

begin
process (MSB_Sync, LSB_Sync)
    begin
    if ((MSB_Sync and LSB_Sync) = '1') then
        MSB_Out <= MSB_Q;
        LSB_Out <= LSB_Q;
    end if;
end process;

end Behavioral;

您导致同步问题的明显基本问题是您的 'overflow' 信号已注册,它是在 if 语句中以时钟上升沿为条件的赋值。

我在以下示例中转储了同步内容并删除了溢出寄存器:

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

entity bcd_ud_ctr is
    port (
        AR:         in  std_logic;
        clk:        in  std_logic;
        ld:         in  std_logic;
        en:         in  std_logic;
        up_dn:      in  std_logic;
        D:          in  std_logic_vector (3 downto 0);
        overflow:   out std_logic;
        Q:          out std_logic_vector (3 downto 0)
    );
end entity;

architecture off of bcd_ud_ctr is
    signal Qt:      unsigned (3 downto 0);
    signal nine:    std_logic;
    signal zero:    std_logic;

begin
    -- Count recognizers
    nine <= '1' when Qt = "1001" else
            '0';
    zero <= '1' when Qt = "0000" else
            '0';
COUNT:
    process (clk, AR)
    begin
        if AR = '1' then
            Qt <= (others => '0');
        elsif rising_edge(clk) then
            if ld = '1' then
                Qt <= unsigned(D);
            elsif en = '1' then
                if up_dn = '0' then  -- up
                    if nine = '1' then
                        Qt <= (others => '0');
                    else
                        Qt <= Qt + 1;
                    end if;
                else                  -- down
                    if zero = '1' then 
                        Qt <= "1001"; 
                    else 
                        Qt <= Qt - 1;
                    end if;
                end if;
            end if;
        end if;
    end process;

BUFFERED_OUT:    
    Q <= std_logic_vector(Qt);

CARRY_BORROW:
    overflow <= (en and     up_dn and zero) or
                (en and not up_dn and nine);
end architecture;

请注意,我还将启用与溢出信号进行了 AND 运算,因此它可以用作下一阶段的启用:

library ieee;
use ieee.std_logic_1164.all;

entity bcd_2digit_tb is
end entity;

architecture foo of bcd_2digit_tb is
    signal AR:          std_logic;
    signal clk:         std_logic := '0';
    signal ld:          std_logic := '0'; 
    signal en:          std_logic := '0';
    signal up_dn:       std_logic := '1';
    signal rollover:    std_logic;
    signal Q:           std_logic_vector (7 downto 0);

    constant DIG_PAR:   std_logic_vector(3 downto 0) := "0010"; -- 2
    constant TEN_PAR:   std_logic_vector(3 downto 0) := "0100"; -- 4 (42)
begin

CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if Now > 500 ns then
            wait;
        end if;
    end process;

DIGITS:
    entity work.bcd_ud_ctr
        port map (
            AR => AR,
            clk => clk,
            ld => ld,
            en => en,
            up_Dn => up_dn,
            D => DIG_PAR,
            overflow => rollover,
            Q => Q(3 downto 0)
        );
TENS:
    entity work.bcd_ud_ctr
        port map (
            AR => AR,
            clk => clk,
            ld => ld,
            en => rollover, 
            up_Dn => up_dn,
            D => TEN_PAR,
            overflow => open,
            Q => Q(7 downto 4)
        );
STIMULUS:
    process
    begin
        wait for 10 ns;
        AR <= '1';
        wait for 10 ns;
        AR <= '0';
        up_dn <= '0'; -- up
        en <= '1';
        wait for 260 ns;
        up_dn <= '1';
        wait;
    end process;
end architecture;

这给出了:

(可点击)

虽然这里只是简单的表示个位翻滚,但是在测试台下的向下计数和翻滚是可以扩展的