0

我正在参加 vhdl 在线课程。其中一项实验室工作是:“基于分频器和8位循环移位寄存器实现移位周期为1 s的环形计数器”。

任务说计数器的最高位不能作为移位寄存器的时钟信号(即在ifrising_edge(移位器(MSB))结构中。需要形成使能信号作为选通。

我做了这项工作。结果被接受。

我有一个关于启用移位寄存器的问题。

    shift_reg_proc : process(clk)
    begin
        if (rising_edge(clk)) then
            if    (srst = '1') then
                shift_reg <= "10000000";
            elsif (en = '1') then
                shift_reg <= shift_reg(0) & shift_reg(7 downto 1);
            end if;
        end if;
    end process shift_reg_proc

如果使能信号的持续时间为 1 个周期 clk,那么在上升沿 (clk) 时刻,en 信号电平有可能没有时间变为 = 1。如果是这种情况,则不能保证寄存器移位将在下一秒发生。有没有“正确”的方法来完成这项任务?是这样吗?我的决定正确吗?实验室线索是否具有误导性?

我附上了实现代码、测试台和波形图。

ring_counter.vhd

--------------------------------------------------------------------------------
-- Based on frequency divider and 8-bit cyclic shift register implement a ring 
-- counter with a shift period of 1 s.
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity ring_counter is
    
    port(clk  : in  std_logic;
         srst : in  std_logic;
         dout : out std_logic_vector(7 downto 0);
         en_o : out std_logic
    );

end entity ring_counter;

architecture behave of ring_counter is

    signal   cntr             : std_logic_vector(26 downto 0) := (others => '0');
    signal   cntr_msb_delayed : std_logic;
    signal   shift_reg        : std_logic_vector(7 downto 0);
    signal   en               : std_logic;
    constant cntr_msb_num     : integer := 4; -- 26 for DE board, 4 for test bench 

begin
    
    -- signal for test bench
    en_o <= en;

    --------------------------------------------------------------------------------
    -- Counter implementation
    --------------------------------------------------------------------------------

    cntr_proc : process(clk)
    begin
        if (rising_edge(clk)) then
            if (srst = '1') then
                cntr <= (others => '0');
            else
                cntr <= unsigned(cntr) + 1;
            end if;
        end if;
    end process cntr_proc;

    ----------------------------------------------------------------------------
    -- Shift register implementation
    ----------------------------------------------------------------------------

    shift_reg_proc : process(clk)
    begin
        if (rising_edge(clk)) then
            if    (srst = '1') then
                shift_reg <= "10000000";
            elsif (en = '1') then
                shift_reg <= shift_reg(0) & shift_reg(7 downto 1);
            end if;
        end if;
    end process shift_reg_proc;
    
    dout <= shift_reg;

    ----------------------------------------------------------------------------
    -- Enable signal generation
    ----------------------------------------------------------------------------

    -- Counter MSB delay for 1 period of clk
    delay_proc : process(clk)
    begin
        if (rising_edge(clk)) then
            cntr_msb_delayed <= cntr(cntr_msb_num);
        end if;
    end process delay_proc;

    en <= cntr(cntr_msb_num) and not cntr_msb_delayed;


end architecture behave;

ring_counter_tb.vhd

library ieee;
use ieee.std_logic_1164.all;

entity ring_counter_tb is
    
end entity ring_counter_tb;

architecture behave of ring_counter_tb is

    component ring_counter is
        port(clk  : in  std_logic;
             srst : in  std_logic;
             dout : out std_logic_vector(7 downto 0);
             en_o : out std_logic
        );
    end component ring_counter;

    signal clk  : std_logic;
    signal srst : std_logic;
    signal dout : std_logic_vector(7 downto 0);
    signal en_o : std_logic;

    constant clk_period : time := 4 ns;

begin

    dut : ring_counter
        port map (
            clk  => clk,
            srst => srst,
            dout => dout,
            en_o => en_o
        );

    clk_gen : process
    begin
        clk <= '0';
        wait for clk_period;
        loop
            clk <= '0';
            wait for clk_period/2;
            clk <= '1';
            wait for clk_period/2;
        end loop;
    end process clk_gen;

    srst <= '0',
            '1' after 100 ns,
            '0' after 150 ns;

    
end architecture behave;

测试台波

4

1 回答 1

0

TL;博士

clk之后的上升沿与移位寄存器移位en的上升沿不同。上升沿置为高电平,上升沿置为无效。因此,您的移位寄存器在上升沿移位。clkenNN+1N+1

所以你在断言en和寄存器移位之间有大约一个时钟周期延迟。您不在乎,因为您的规范说您需要 1 秒的换档周期。只要en是周期为一秒的周期,即使en与您的移位寄存器之间有一个小的恒定延迟,您也符合规范。

但是最重​​要的是,正如您的移位寄存器所看到的那样,在上升沿之后en被断言为足够高以避免过早的移位,并且在上升沿之后被充分地取消断言以允许良好的移位。如果你也对此感兴趣,请继续阅读。NN+1

详细解释

您的信号是根据与移位寄存器en在同一时钟上同步的寄存器的输出计算得出的。clk你不会有任何保持时间问题:从时钟上升沿到你的cntrcntr_msb_delayed寄存器输出的传播延迟保证在导致它的时钟上升沿之后充分en到达你的移位寄存器(假设你没有' t 有大的时钟偏差)。它不能太早到达。

会不会来得太晚(设置时间问题)?是的,如果你的时钟频率太高。那么时钟周期会太短,en在时钟的下一个上升沿之前没有足够的时间来计算、稳定和传播到您的移位寄存器,并且任何事情都可能发生(根本没有移位、部分移位、亚稳态...... )

这是数字设计中非常常见的问题:您不能以任意高的时钟频率运行。如果可以的话,您可以将自己的计算机时钟设置为 yotta-Hz 甚至更高,而不是 giga-Hz,然后一切都将变得即时。这会很好,但这不是现实世界的运作方式

在数字设计中,您始终拥有所谓的关键路径。它是一组源寄存器和目标寄存器之间的特定逻辑门链,在整个设计中,电信号的传播延迟是最大的。

它是所有可能的路径以及沿该路径的总延迟取决于您的设计复杂性(例如计数器的位数)、目标硬件技术(例如原型板的 FPGA)和操作条件(温度、电源电压,FPGA的速度等级)。

(是的,这也取决于温度,这也是硬核游戏玩家使用高性能冷却系统冷却计算机的原因。这避免了硅的破坏,并允许以更高的时钟频率运行计算机,每秒帧数更多,并且更好的用户体验。)

信号从源时钟边沿到到达目的地所花费的最长时间,加上一个称为目标寄存器设置时间的小安全裕度,是您可以使用的最小时钟周期(最高时钟频率)可以运行您的设计。只要您不超过此限制,您的系统就会按预期工作。

硬件设计工具链通常包含一个静态时序分析器 (STA),它可以告诉您这个最大时钟频率对于您的设计、目标和操作条件是多少。如果它告诉您 500 MHz 并且您只需要 350 MHz,那么一切都很好(但是您可以调查并查看是否可以修改您的设计,节省一些硬件,并且仍然以 350 MHz 运行)。

但是,如果您需要 650 MHz,是时候卷起袖子,查看关键路径(STA 也会显示路径),理解它并重新设计您的设计以加快速度(例如,流水线长计算,使用进位前瞻加法器而不是进位纹波...)请注意,通常,当您遇到时序收敛问题时,您不会只考虑一条关键路径,而是考虑超出时间预算的所有路径的集合,因为您想消除它们,而不仅仅是最坏的。这就是为什么 STA 不仅为您提供最差的关键路径,而且还提供关键路径列表,按严重性降序排列。

于 2020-08-24T12:22:05.270 回答