用VHDL的简短形式来触发提高边的动作[英] VHDL short form to trigger actions on raising edges

本文是小编为大家收集整理的关于用VHDL的简短形式来触发提高边的动作的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我想知道是否有一种较短的方法来触发不是时钟的信号边缘.

考虑以下示例:

  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;

如果信号"准备就绪"获得了提高边缘,我想做一些事情.仅在某些_rare_condition为真时才能评估升高边缘.

我目前只记得闩锁中的"就绪信号的最后一个状态",并自己构建边缘检测逻辑.

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

我做正确的方法可以正常工作,但是我用所有这些last_ready信号将代码乱扔.这似乎是一个常见的范式,我想我错过了一些语言或库构造,可以帮助我保持代码清洁和瘦弱.

推荐答案

您可以用两行编写上升或下降的边缘检测:

  • 一个简单的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);

其他推荐答案

我不知道任何可综合的语言构造可以完成您正在寻找的内容,这并不涉及明确声明寄存器并以一种或另一种方式进行边缘检查自己.

可能会想尝试的事情:

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

不仅(可能是?)不合成,而且要整个rising_edge(ready)检查,这些事件必须完全同时发生(在SIM中,到达三角洲周期,这可能是非常不便).

或也许:

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

有点笨拙,不可合理(不过,在SIM中或多或少都可以使用),并且由于对CLK_PERIOD>的依赖而不是非常便携(尽管可能有一种更优雅的方法来使用我''的这种构造m不考虑).

您只使用一个额外的信号声明和分配,这不是太多的额外代码,但是如果您真的想减少它,则可以使用一个小的可重复使用的组件:

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
      ...

添加一些仿制药以涵盖微小的变化.如果您要这样做,则更多的代码,但信号较少. ( edit :嗯,我想并不少,但至少全部包裹了)

其他推荐答案

如果VHDL函数允许inot参数,则可以减轻痛苦:

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;

尽管某些合成工具可能不接受.

在任何情况下都不是很可扩展的,您需要一个单独的函数和last_xxx信号,每个信号都需要edge_detect,尽管您可以在过程中重复使用每个边缘检测器任意多次.

本文地址:https://www.itbaoku.cn/post/2090962.html

问题描述

I wonder if there is a shorter way to trigger on signal edges that are not the clock.

Consider the following example:

  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;

Here I want to do something if the signal 'ready' got a raising edge. The raising edge should only be evaluated if some_rare_condition is true.

I currently just remember the last state of the ready signal in a latch and build the edge detection logic myself.

Question: Is there a shorter, more elegant way to do this?

The way I do it right works just fine, but I litter up my code with all these last_ready signals. This seem to be such a common paradigm that I think I miss some language or library construct that helps me to keep my code clean and lean.

推荐答案

You can write a rising or falling edge detection in two lines:

  • a simple D-FF to register the old signal
  • a comparison for the rising edge

Example code:

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;

Edit 1

Of cause, you can also add an enable to this one-liner D-FF by defining some FF functions (this is still synthesizeable !).

-- 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;

Example:

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

其他推荐答案

I'm not aware of any synthesizable language construct that accomplishes what you're looking for that doesn't involve explicitly declaring a register and doing the edge check yourself in one way or another.

Among things one might think to try:

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

Not only will this (probably?) not synthesize, but to make it all the way through the rising_edge(ready) check, the events would have to be exactly simultaneous (in sim, down to the delta cycle, which would probably be extremely inconvenient).

Or maybe:

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

Kind of unwieldy, not synthesizable (more or less works in sim, though), and not very portable because of the dependence on CLK_PERIOD (though there may be a more elegant way to use this sort of construct that I'm not thinking of).

You're only using one extra signal declaration and assignment, which is not that much extra code, but if you really want to reduce that, you could use a small reusable component:

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
      ...

Add some generics to cover slight variations. Slightly more code, but fewer signals, if that's what you're going for. (edit: well, not actually fewer signals I suppose, but at least it's all wrapped up neatly)

其他推荐答案

If VHDL functions allowed inout parameters, you could ease the pain a little:

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;

Unfortunately they don't.

If you only need edge detection on one signal, an impure function can modify state (signals as here, or a variable declared in the same process as this function) the following should work :

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;

although some synthesis tools may not accept it.

In any case it's not very scalable, you need a separate function and last_xxx signal for each signal you need to edge_detect on, though you can reuse each edge detector as many times as you need it within the process.