在非时钟信号上使用 rising_edge 是不好的做法吗?有其他选择吗?

Is the use of rising_edge on non-clock signal bad practice? Are there alternatives?

我正在研究 VHDL 设计并且我已经开始工作了,但是代码非常丑陋而且我似乎正在尝试围绕语言的设计来实现我的目标这一事实让我觉得有些东西是错误的。我是 VHDL 的新手,但我已经在该项目的较小部分上工作了将近一个月,所以我有大致的想法。但是,这部分有点复杂。

我需要一个在信号上升沿 (END_ADC) 之后创建一个时钟周期长脉冲 (LOAD_PULSE) 的过程,但直到从最近的 4 个时钟开始该信号的上升沿 (END_ADC) 或第二个信号 (LVAL) 的下降沿。

为了完成等待时间,我构建了一个计时器模块来计算微秒和周期,这里:

entity uS_generator is
    generic(
        Frequency       : integer := 66                                     -- Frequency in MHz
    );
    Port ( 
        CLK     : in STD_LOGIC;
        RESET   : in STD_LOGIC;
        T_CNT   : out integer range Frequency downto 1 := 1;
        uS_CNT  : out integer range 65535 downto 0 := 0
    );
end uS_generator;

architecture behavior of uS_generator is

    signal T_CNT_INT        : integer range Frequency downto 1 := 1;        -- Counter for 1 uS
    signal uS_CNT_INT       : integer range 65535 downto 0 := 0;

begin

    COUNT: process(CLK, RESET)
    begin
        if RESET = '1' then
            T_CNT_INT   <= 1;
            uS_CNT_INT  <= 0;
        elsif rising_edge(CLK) then
            if T_CNT_INT = (Frequency - 1) then                             -- Increment one clock early so last rising edge sees one uS elapsed.
                uS_CNT_INT <= uS_CNT_INT + 1;
                T_CNT_INT <= T_CNT_INT + 1;
                if uS_CNT_INT = 65535 then
                    uS_CNT_INT <= 0;
                end if;
            elsif T_CNT_INT = Frequency then
                T_CNT_INT <= 1;
            else
                T_CNT_INT <= T_CNT_INT + 1;
            end if;
        end if;
    end process COUNT;

    T_CNT   <= T_CNT_INT;
    uS_CNT  <= uS_CNT_INT;

end behavior;

我在设计的脉冲生成部分使用的过程如下:

loadPulseProc: process(PIXEL_CLK, END_ADC, RESET)
begin

    if RESET = '1' then
        PULSE_FLAG <= '0';
        LOAD_PULSE <= '0';
    elsif rising_edge(END_ADC) then
        PULSE_FLAG <= '1';
    end if;

    if rising_edge(PIXEL_CLK) then
        if PULSE_FLAG = '1' and END_ADC = '1' and LVAL <= '0' and ADC_TMR_T >= 4 and LVAL_TMR_T >= 4 then
            LOAD_PULSE <= '1', '0' after PIXEL_CLK_T;
            PULSE_FLAG <= '0';
        end if;
    end if;

end process loadPulseProc;

ADCTimerProc: process(END_ADC, RESET)
begin

    if RESET = '1' then
        ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
    end if;

    if rising_edge(END_ADC) then
        ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
    end if;

    if falling_edge(END_ADC) then
        ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
    end if;

end process ADCTimerProc;

LVALTimerProc: process(LVAL, RESET)
begin

    if RESET = '1' then
        LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
    end if;

    if rising_edge(LVAL) then
        LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
    end if;

    if falling_edge(LVAL) then
        LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10;
    end if;         

end process LVALTimerProc;

PIXEL_CLK_T是时钟的周期,15.152 ns。

这个设计有效,模拟表明它按照我的要求进行,但只有在通过将它们分成单独的 if 语句来避免由于使用多个 rising_edge of falling_edge 调用而导致的错误之后应该在一起据我所知,使用 rising_edge 和 falling_edge 似乎只为时钟保留,所以这是不好的做法吗?如何避免这种行为但仍然创建相同的输出?

谢谢!

是的,rising_edge()/falling_edge()应该只用于时钟信号。虽然它在模拟中工作,但它可能会在综合中导致问题和意外的硬件。

综合工具从函数的参数中推断出一个时钟,并将此类 signals/wires 放置在 FPGA 的特殊轨道上(假设您的设计目标是 FPGA)。该工具将进一步推断特殊的时钟缓冲器,并在您的输入时钟引脚不是支持时钟的引脚时发出警告。

引入多个时钟会导致异步设计并使其易受跨时钟故障的影响。

检测信号的上升沿或下降沿是由边缘检测电路完成的,如下所示,它将前一个时钟周期中的信号与当前值进行比较。

需要信号:

signal mySignal_d : std_logic := '0'; 
signal mySignal_re : std_logic;

需要的逻辑:

mySignal_d <= mySignal when rising_edge(Clock); 
mySignal_re <= not mySignal_d and mySignal; 

第一行转换为 1 位 D 触发器(您也可以使用进程)。第二行在mySignal由低变高时产生一个周期的选通信号。我使用 *_d 表示原始输入的延迟信号,*_re 表示上升沿。

生成的信号仍然与Clock同步。