来自不同过程的VHDL驱动信号

时间:2012-01-31 18:34:31

标签: vhdl

我对以下VHDL代码有一点问题:

process (zbroji)
begin
    if rising_edge(zbroji) then
        oduzima <= '0';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;
end process;

process (oduzmi)
begin
    if rising_edge(oduzmi) then
        oduzima <= '1';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;

end process;

问题是信号ucitanPrvi总是有值X.如果我不尝试在两个进程中设置它的值,那么我没有任何问题...所以我知道我不能驱动一个信号从多个进程,但我不知道如何写这个不同... 有谁知道如何解决这个问题?

谢谢!

编辑:谢谢大家回复:)现在我理解为什么我不能从多个进程中驱动一个信号(至少以我希望它工作的方式)。

5 个答案:

答案 0 :(得分:6)

如果您想要为真正的FPGA或ASIC综合您的设计,您将不得不考虑真实硬件(电线,触发器,门等)的VHDL。此外,如果要在硬件中执行真正的上升沿检测,则需要一个驱动触发器的系统时钟。鉴于您的原始代码示例,zbroji或oduzmi似乎不是系统时钟,而只是std_logic信号。我编写了这个代码示例,假设您的示例中有基本功能,希望您可以获取我的代码和注释并完成您的需要。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity example is
  port (Reset      : in  std_logic;
        SysClk     : in  std_logic;
        zbroji     : in  std_logic;
        oduzmi     : in  std_logic;
        ulaz_broj  : in  std_logic;
        oduzima    : out std_logic;
        ucitanPrvi : out std_logic;
        broj1      : out std_logic
        );

end example;

architecture Behavioral of example is

  -- Delayed version of input signals (1 clock cycle delay)
  signal zbroji_d : std_logic;
  signal oduzmi_d : std_logic;

  signal zbrojiRE : std_logic;
  signal oduzmiRE : std_logic;

begin

  -- Generate 1 clock cycle delayed version of
  -- signals we want to detect the rising edge
  -- Assumes active high reset
  -- Note: You should only use the rising_edge macro
  -- on an actual global or regional clock signal. FPGA's and
  -- ASICs place timing constraints on defined clock signals
  -- that make it possible to use rising_edge, otherwise, we have
  -- to generate our own rising edge signals by comparing delayed
  -- versions of a signal with the current signal.
  -- Also, with any respectable synthesizer / simulator using
  -- rising_edge is almos exactly the same as (clk'event and clk='1')
  -- except rising_edge only returns a '1' when the clock makes a
  -- valid '0' to '1' transition. (see link below)
  EdgeDetectProc : process (Reset, SysClk)
  begin
    if Reset = '1' then
      zbroji_d <= '0';
      oduzmi_d <= '0';
    elsif rising_edge(SysClk) then
      zbroji_d <= zbroji;
      oduzmi_d <= oduzmi;
    end if;
  end process EdgeDetectProc;

  -- Assert risinge edge signals for one clock cycle 
  zbrojiRE <= '1' when zbroji = '1' and zbroji_d = '0' else '0';
  oduzmiRE <= '1' when oduzmi = '1' and oduzmi_d = '0' else '0';

  -- Assumes that you want a single cycle pulse on ucitanPrvi on the
  -- rising edege of zbroji or oduzmi;
  ucitanPrvi <= zbrojiRE or oduzmiRE;

  -- Based on your example, I can't tell what you want to do with the
  -- broj1 signal, but this logic will drive broj1 with ulaz_broj on
  -- either the zbroji or oduzmi rising edge, otherwise '0'.
  broj1 <= ulaz_broj when zbrojiRE = '1' else
           ulaz_broj when oduzmiRE = '1' else
           '0';

  -- Finally, it looks like you want to clear oduzima on the rising
  -- edge of zbroji and assert oduzima on the rising edge of
  -- oduzmi
  LatchProc : process (Reset, SysClk)
  begin
    if Reset = '1' then
      oduzima <= '0';
    elsif rising_edge(SysClk) then
      if zbrojiRE = '1' then
        oduzima <= '0';
      elsif oduzmiRE = '1' then
        oduzima <= '1';
      end if;
    end if;
  end process LatchProc;

end Behavioral;

前面的代码假设您有一个系统时钟。在像ModelSim(免费学生版)这样的模拟器中,你可以生成一个带有非可合成测试平台代码的100 MHz时钟......

ClockProc : process
begin 
   SysClk <= '0';
   wait for 5 ns;
   SysClk <= '1';
   wait for 5 ns;
end process ClockProc;

在实际的FPGA / ASIC实现中,您可能需要使用插入芯片的外部振荡器,将信号驱动到DCM(数字时钟管理器),这将向所有人输出一个非常干净的时钟信号。你的VHDL逻辑,所以你可以有一个无故障的设计。

最后,这是对rising_edge和。之间差异的一个很好的解释 (clk'event和clk ='1')

http://vhdlguru.blogspot.com/2010/04/difference-between-risingedgeclk-and.html

希望有所帮助。

答案 1 :(得分:4)

如果您从多个进程中发送std_logic信号(并且记住进程外的连续分配也会创建隐含进程!)那么除了其中一个进程外,其他所有进程都必须正在驱动Z在信号上。对于第一个近似值,除非发生这种情况,否则分辨率函数(决定最终值应该是什么)将产生X s。

我不确定如何更好地更改代码 - 您需要确定特定进程何时驱动信号并让它在此时驱动Z。< / p>


在ieee.std_logic_1164包中定义了如何解析多个驱动程序的完整定义,并涵盖了所有可能性,例如1L驱动等.IEEE对版权的评价很高,所以我不会在这里发布一个摘录,但你可以在你的模拟器的源库中找到它。

答案 2 :(得分:4)

来自多个进程的驱动信号是一个坏主意,除非你真的知道你正在做什么。您可以在这样的单个过程中重写此代码。

process (zbroji, oduzmi)
begin
    if rising_edge(zbroji) then
        oduzima <= '0';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;
    if rising_edge(oduzmi) then
        oduzima <= '1';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;
end process;

请注意,如果您执行此操作,则zbroji和{} { oduzmi然后oduzima将获得值1,因为它在流程的最后发生。在您尝试同时将其设置为01之前。这将模拟到X,可能不会合成。如果它确实合成了,你就可以用CMOS设计将电源和地连接在一起。


另一种方法是让每个进程驱动它自己的信号版本,然后用你喜欢的函数(或其他进程)在外部解析它们。在这种情况下,我使用了or

process (zbroji)
begin
    if rising_edge(zbroji) then
        ucitanPrvi_1 <= '1';
    end if;
end process;

process (oduzmi)
begin
    if rising_edge(oduzmi) then
        ucitanPrvi_2 <= '1';
    end if;

end process;

ucitanPrvi <= ucitanPrvi_1 or ucitanPrvi_2;

答案 3 :(得分:1)

除非zbroji和oduzmi是单独的时钟,否则这是我推荐的实现

注册zbroji和oduzmi并检查寄存器中的值是否与原始信号相反。这应该只在zbroji / oduzmi从0变为1并且寄存器尚未更新信号变化时才会发生。

process (clk)
begin
    if rising_edge(clk) then
        if zbroji = '1' and zbroji_old = '0' then
            oduzima <= '0';
            ucitanPrvi <= '1';
            broj1 <= ulaz_broj;
        elif oduzmi = '1' and oduzmi_old = '0' then
            oduzima <= '1';
            ucitanPrvi <= '1';
            broj1 <= ulaz_broj;
        end if;
        zbroji_old <= zbroji;
        oduzmi_old <= oduzmi;
    end if;
end process;

同样看来ucitanPrvi和broj1总是一样的。信号是无用的,这是一个错字或你正在创建“更新”脉冲,在这种情况下你需要声明

    ucitanPrvi <= '0'
    broj1 <= (others=>'0') -- assumed reset?

跟随if(rising_edge(clk)语句

答案 4 :(得分:1)

当您从多个进程更改相同的信号值时,模拟器将为此创建多个信号驱动程序。它们的输出基本上是未解决的。可以把它想象成连接在一起的多个门的输出,你期望什么?

为了解决这个问题,您需要实现的是一种分辨率功能,它可以驱动输出信号。

http://www.csee.umbc.edu/portal/help/VHDL/misc.html#resf

如果您有任何疑问,请告诉我。