为什么将此作为一个单独的过程会导致各种各样的怪异

时间:2012-04-29 22:17:50

标签: debugging vhdl

我正在学习VHDL,有什么比学习项目更好的学习方法。所以,我现在的项目部分是创建一个小内存组件。

这是我的完整代码:

entity memory is
  port(
    Address: in std_logic_vector(15 downto 0); --memory address
    Write: in std_logic; --write or read
    UseTopBits: in std_logic;  --if 1, top 8 bits of data is ignored and not written to memory
    Clock: in std_logic;
    DataIn: in std_logic_vector(15 downto 0);
    DataOut: out std_logic_vector(15 downto 0);
    Reset: in std_logic
  );
end memory;

architecture Behavioral of memory is
  constant SIZE : integer := 4096;
  type memorytype is array(0 to (size-1)) of std_logic_vector(7 downto 0);
  signal mem: memorytype;

begin
  resetmem: process(Clock, Reset) --this process is the troublemaker 
  begin
  if(Reset ='1' and rising_edge(Clock)) then
    mem <= (others => "00000000");
  end if;

  end process;
  writemem: process(Reset,Write, Address, UseTopBits, Clock)
    variable addr: integer;
  begin
    addr := conv_integer(Address);
    if(addr>size-1) then
      addr:=0;
    end if;
    if(Write='1' and Reset='0') then
      if(rising_edge(clock)) then
        mem(conv_integer(addr)) <= DataIn(7 downto 0);
        if(UseTopBits='1') then
          mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
        end if;
      end if;
    end if;
  end process;
  readmem: process(Reset,Address,Write,Clock)
    variable addr: integer;
  begin
    addr := conv_integer(Address);
    if(addr>size-1) then
      addr:=0;
    end if;
    if(Reset='1') then
      DataOut <= (others => '0');
    elsif(Write='0') then
      DataOut <= mem(conv_integer(addr)+1) & mem(conv_integer(addr));
    else 
      DataOut <= (others => '0');
    end if;
  end process;
end Behavioral;

在添加重置过程之前,根据我的测试平台,我的代码工作正常。在添加它之后,我在DataOut上得到了各种各样的怪异。看似随机的位将具有X而不是01的逻辑状态,这会导致我的所有测试平台失败(应该如此)

我通过将代码放入writemem进程来修复它:

begin
  --where resetmem process was
  writemem: process(Reset,Write, Address, UseTopBits, Clock)
    variable addr: integer;
  begin
    addr := conv_integer(Address);
    if(addr>size-1) then
      addr:=0;
    end if;
    if(Reset ='1' and rising_edge(Clock)) then --code is now here
      mem <= (others => "00000000");
    elsif(Write='1' and Reset='0') then
      if(rising_edge(clock)) then
        mem(conv_integer(addr)) <= DataIn(7 downto 0);
        if(UseTopBits='1') then
          mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
        end if;
      end if;
    end if;
  end process;

所以问题现在已解决,但我不明白为什么将resetmem作为一个单独的进程导致所有这些奇怪的问题。任何人都能说明这是怎么发生的吗?

2 个答案:

答案 0 :(得分:2)

您有两个同时驱动mem并具有不同(非Z)值的流程 - 这就是导致'X'值的原因。

另外,如果您计划合成代码,可能需要查看推荐的用于推断触发器的流程模板(如果您使用的是Xilinx ISE,可以在编辑&gt;语言模板&gt中找到这些模板; VHDL&gt;合成构建体&gt;编码实施例&gt;触发器)。这将有助于您优先考虑复位/时钟使能引脚,以获得有效映射到FPGA硬件的设计。

例如:

if(Write='1' and Reset='0') then
  if(rising_edge(clock)) then
    mem(conv_integer(addr)) <= DataIn(7 downto 0);
    if(UseTopBits='1') then
      mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
    end if;
  end if;
end if;

根据您的合成器的智能,这可能会使您的时钟使能(Write)处于比FPGA实际存在的“更高”的优先级 - 并且您在以后添加代码的风险很高这一点肯定会导致这种情况发生。

如果你把它写成:

if(Reset='1') then
  --Do nothing, for now
elsif(rising_edge(clock)) then
  if(Write='1') then
    mem(conv_integer(addr)) <= DataIn(7 downto 0);
    if(UseTopBits='1') then
      mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
    end if;
  end if;
end if;

您的代码将更加清晰,并且它还应该更好地合成底层硬件(至少在Xilinx FPGA的情况下)。

另外,请查看Ken Chapmans Get your priorities right白皮书。

答案 1 :(得分:2)

VHDL在信号上有“驱动程序”的概念。

写入信号的每个进程(或总线的一部分)都会创建一个驱动程序。当多个驱动器连接到信号时,调用“分辨率函数”,其决定结果值应该是什么。碰巧(对于第一次近似)std_logic(因此对于std_logic_vector位)的分辨率函数在具有相反值(10的驱动程序时产生Xs被驱使信号。还有一个名为Z的值,它被视为非驱动值,可以被其他值覆盖。 (并且有WLH,但我们暂时将这些留空,U未初始化

这个过程:

resetmem: process(Clock, Reset) --this process is the troublemaker 
  begin
  if(Reset ='1' and rising_edge(Clock)) then
    mem <= (others => "00000000");
  end if;
end process;

说(转述)

  
    
      

if(reset和clock)然后将零驱动到mem

    
  

如果条件为false,它不会说出该怎么做,因此它会继续驱动零(剩下的时间)。当您的其他流程驱动值时,它们会发生冲突并生成X s

出于模拟目的,您可以

else
  mem <= (others => 'Z');

这将使其“驱动”高阻抗,而另一个过程可以覆盖它。


但是我认为你要做的是将RAM初始化全部为零。 FPGA RAM不能通过信号复位到特定值,但可以在配置时使用值加载。模拟器对配置过程一无所知,在配置完成后,您认为模拟正在发生。

因此,模拟此行为的一种方法是在声明信号时初始化信号:

signal mem: memorytype := (others => (others => '0'));