VHDL简短形式触发提升边缘的动作

时间:2014-12-01 13:33:45

标签: vhdl fpga

我想知道是否有更短的方法来触发不是时钟的信号边缘。

考虑以下示例:

  signal clock               : std_logic;
  signal ready               : std_logic;  -- comes from some slow component
  signal last_ready          : std_logic;
  signal some_rare_condition : std_logic;

  ----------------------------------

  process (clock) is 
  begin

    if rising_edge (clock) then

      if (some_rare_condition = '1') then

        if (ready = '1') and (last_ready = '0') then
          -- do something here, writing data to UART for example.
        end if;

        last_ready <= ready;

      end if;
    end if;
  end process;

如果信号“准备就绪”,我想做点什么。获得了提升优势。只有在some_rare_condition为真时才应评估上升沿。

我目前只记得锁存器中就绪信号的最后状态,并自己构建边缘检测逻辑。

问题:是否有更简洁,更优雅的方法?

我这样做的方式工作得很好,但是我用所有这些last_ready信号乱丢了我的代码。这似乎是一种常见的范例,我认为我错过了一些语言或库构造,可以帮助我保持代码清洁和精益。

3 个答案:

答案 0 :(得分:3)

您可以用两行写出上升沿或下降沿检测:

  • 一个简单的D-FF来注册旧信号
  • 上升沿的比较

示例代码:

signal MMCM_Locked      : STD_LOGIC;
signal MMCM_Locked_d    : STD_LOGIC     := '0';
signal MMCM_Locked_re   : STD_LOGIC;

-- detect rising edge on CMB locked signals
MMCM_Locked_d   <= MMCM_Locked          when rising_edge(Control_Clock);
MMCM_Locked_re  <= not MMCM_Locked_d    and MMCM_Locked;

编辑1

当然,你也可以通过定义一些FF函数(这仍然是可合成的!)来为这个单行D-FF添加一个启用。

-- d-flipflop with reset and enable
function ffdre(q : STD_LOGIC; d : STD_LOGIC; rst : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC is
begin
    return ((d and en) or (q and not en)) and not rst;
end function;

function ffdre(q : STD_LOGIC_VECTOR; d : STD_LOGIC_VECTOR; rst : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC_VECTOR is
begin
    return ((d and (q'range => en)) or (q and not (q'range => en))) and not (q'range => rst);
end function;

-- d-flipflop with set and enable
function ffdse(q : STD_LOGIC; d : STD_LOGIC; set : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC is
begin
    return ((d and en) or (q and not en)) or set;
end function;

-- t-flipflop with reset and enable
function fftre(q : STD_LOGIC; rst : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC is
begin
    return ((not q and en) or (q and not en)) and not rst;
end function;

-- rs-flipflop with dominant rst
function ffrs(q : STD_LOGIC; rst : STD_LOGIC := '0'; set : STD_LOGIC := '0') return STD_LOGIC is
begin
    return (q or set) and not rst;
end function;

-- rs-flipflop with dominant set
function ffsr(q : STD_LOGIC; rst : STD_LOGIC := '0'; set : STD_LOGIC := '0') return STD_LOGIC is
begin
    return (q and not rst) or set;
end function;

示例:

mySignal_d <= ffdre(q => mySignal_d, d => mySignal, en => myEnable) when rising_edge(Clock);

答案 1 :(得分:1)

我不知道任何可综合的语言结构可以完成你正在寻找的东西,而不涉及明确地声明一个寄存器并以某种方式自行进行边缘检查。

人们可能会想到尝试的事情:

if rising_edge(clk) then
  if some_rare_condition = '1' then
    if rising_edge(ready) then
      ...

这不仅(可能?)没有合成,而是通过rising_edge(ready)检查完成,事件必须完全同时(在sim中,直到delta周期,这将可能非常不方便)。

或者也许:

if ready = '1' and ready'last_value = '0' and ready'last_event < CLK_PERIOD then

有点笨拙,不可综合(虽然或多或少在sim中工作),并且由于对CLK_PERIOD的依赖而不是非常便携(尽管可能有一种更优雅的方式来使用这种构造,我没想到。)

你只使用一个额外的信号声明和赋值,这不是那么多额外的代码,但如果你真的想减少它,你可以使用一个小的可重用组件:

ready_edge : edge_detect
  port map (
    clk  => clock,
    ena  => some_rare_condition,
    sig  => ready,
    edge => ready_edge
  );

process (clock)
begin
  if rising_edge(clock) then
    if ready_edge = '1' then
      ...

添加一些泛型以涵盖轻微的变化。代码略多,但信号较少,如果这就是你想要的。 (编辑:好吧,我猜的信号实际上并不少,但至少它们整齐地包裹起来)

答案 2 :(得分:1)

如果VHDL函数允许inout参数,你可以稍微减轻痛苦:

impure function first_time(ready : in std_logic; last : inout std_logic) 
   return boolean is
begin
   last <= ready;
   return ready = '1' and last = '0';
end first_time;

不幸的是他们没有。

如果你只需要对一个信号进行边缘检测,那么一个不纯的函数可以修改状态(这里的信号,或者在与此函数相同的过程中声明的变量),以下内容应该有效:

impure function first_ready return boolean is
begin
   last_ready <= ready;
   return ready = '1' and last_ready = '0';
end first_ready;

...
if first_ready then 
   do_something ...
end if;

虽然一些综合工具可能不接受它。

在任何情况下,它都不具备扩展性,您需要为edge_detect所需的每个信号提供单独的函数和last_xxx信号,尽管您可以根据需要重复使用每个边缘检测器多次在这个过程中。