我想知道是否有更短的方法来触发不是时钟的信号边缘。
考虑以下示例:
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信号乱丢了我的代码。这似乎是一种常见的范例,我认为我错过了一些语言或库构造,可以帮助我保持代码清洁和精益。
答案 0 :(得分:3)
您可以用两行写出上升沿或下降沿检测:
示例代码:
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;
当然,你也可以通过定义一些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
信号,尽管您可以根据需要重复使用每个边缘检测器多次在这个过程中。