【问题标题】:VHDL driving signal from different processes来自不同进程的 VHDL 驱动信号
【发布时间】:2012-01-31 18:34:30
【问题描述】:

我对下面的 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。如果我不尝试在两个进程中设置它的值,那么我没有任何问题......所以我知道我不能驱动一个信号来自多个进程,但我不知道如何以不同的方式编写... 有谁知道我该如何解决这个问题?

谢谢!

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

【问题讨论】:

  • odzumi 和 zbroji 是时钟还是信号?

标签: vhdl


【解决方案1】:

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

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 and clk='1')

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

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    如果您从多个进程驱动std_logic 信号(请记住,进程外部的连续分配也会创建隐含进程!)那么除了其中一个之外,所有进程都必须将Z 驱动到信号上。大致而言,分辨率函数(决定最终值应该是什么)将产生Xs,除非发生这种情况。

    我不确定如何最好地更改您的代码 - 您需要确定特定进程何时应该驱动信号并让它在此时驱动 Z


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

    【讨论】:

      【解决方案3】:

      除非您真的知道自己在做什么,否则从多个进程驱动信号是个坏主意。您可以像这样在单个进程中重写此代码。

      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;
      

      请注意,如果您这样做,并且在 zbrojioduzmi 上都出现上升沿,那么 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;
      

      【讨论】:

      • 除非 zbroji 和 oduzmi 是时钟,否则我不会使用rising_edge 语句。我认为替代方法是您提出的两种方法中更好的方法。
      • 上升沿语句来自原代码。我也不会用。
      【解决方案4】:

      除非 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) 语句

      【讨论】:

        【解决方案5】:

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

        为了克服这个问题,您需要实现一个解析函数,该函数将输出驱动为信号。

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-04-17
          • 1970-01-01
          • 2022-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-15
          相关资源
          最近更新 更多