2

我正在学习 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而不是 a 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 作为一个单独的进程会导致所有这些奇怪的问题。任何人都可以阐明这是如何发生的吗?

4

2 回答 2

2

mem您有两个同时使用不同(非)值驱动的进程Z- 这就是导致“X”值的原因。

此外,如果您计划综合您的代码,您可能需要查看推荐的用于推断触发器的流程模板(如果您使用的是 Xilinx ISE,您可以在 Edit > Language Templates > VHDL > Synthesis Constructs 中找到这些模板> 编码示例 > 人字拖)。这将帮助您为您的复位/时钟使能引脚确定优先级,以获得有效映射到 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根据合成器的智能程度,这可能会使您的时钟启用 (当然。

如果你把它写成:

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获得您的优先事项正确的白皮书。

于 2012-04-30T09:05:33.843 回答
2

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

每个写入信号(或总线的一部分)的进程都会创建一个驱动程序。当多个驱动程序连接到一个信号时,会调用一个“解析函数”来决定结果值应该是什么。当具有相反值 (和) 的驱动器被驱动到信号上时,(对于第一个近似值)std_logic(因此对于 a std_logic_vectors 位)的分辨率函数会产生 Xs 。还有一个名为的值被视为非驱动值,可以被其他值覆盖。(还有,和,但我们暂时将它们放在一边,未初始化)10ZWLHU

这个过程:

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 and clock) then drive zeros to mem

如果条件为假,它没有说明要做什么,因此它继续驱动零(在其余时间)。X当您的其他流程驱动价值时,它们会发生冲突并产生

出于模拟目的,您可以这样做

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

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


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

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

signal mem: memorytype := (others => (others => '0'));
于 2012-04-30T09:54:15.267 回答