VHDL。新值分配后,信号值不会改变

时间:2015-05-24 16:17:14

标签: vhdl

我接到了一项描述我大学RAM的任务。在我看来,我已经编写了一个代码,可以模拟上述设备的行为。但它似乎不起作用。

我以下列方式描述的设备实体:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
LIBRARY RAM_lib;
USE RAM_lib.RAM_pkg.all;

ENTITY RAM IS
   GENERIC(
      WORD_LENGTH: INTEGER := 8;
      ADDRESS_LENGTH: integer := 8
    );
   PORT( 
      Enable   : IN     std_logic;
      DATA_IN  : IN     std_logic_vector(WORD_LENGTH - 1  downto 0);
      DATA_OUT : OUT    std_logic_vector(WORD_LENGTH  - 1 downto 0);
      ADDR     : IN     std_logic_vector(ADDRESS_LENGTH - 1 downto 0);
      RESET    : IN     std_logic;
      CLK      : IN     std_logic;
      WR       : IN     std_logic;
      RD       : IN     std_logic
   );

-- Declarations

END RAM ;

行为部分如下:

use work.RAM_pkg.all;

architecture behavior of ram is

  ---- DATA TYPES DECLARATIONS
  -- used type declarations
  subtype DATA is std_logic_vector(WORD_LENGTH - 1 downto 0);
  subtype ADDRESS is std_logic_vector(ADDRESS_LENGTH - 1 downto 0);
  type MEMORY is array (0 to 2**ADDRESS_LENGTH - 1) of DATA;

  ---- SIGNAL DECLARATION
  signal RAM : MEMORY;
begin  use work.RAM_pkg.all;

architecture behavior of ram is

  ---- DATA TYPES DECLARATIONS
  -- used type declarations
  subtype DATA is std_logic_vector(WORD_LENGTH - 1 downto 0);
  subtype ADDRESS is std_logic_vector(ADDRESS_LENGTH - 1 downto 0);
  type MEMORY is array (0 to 2**ADDRESS_LENGTH - 1) of DATA;

  ---- SIGNAL DECLARATION
  signal RAM : MEMORY;
begin

-- plug in or plug out ram
plug_in_out: process (enable) is  
  variable first_load : boolean := true;
  begin
    if ((enable = '0' and enable'event) or first_load = true) then
      data_out <= (others => 'Z');

      if (first_load = true) then
        first_load := false;
      end if;
    end if;  
  end process;

reset_ram: process (reset) is
    variable initialized: boolean := false;
  begin
    if ((reset = '1' and reset'event) or (initialized = false)) then
      ram <= (OTHERS => (OTHERS => '0'));

      if (initialized = false) then
        initialized := true;
      end if;
    end if;
  end process;

 -- it serves both "read" and "write" operation for the RAM
  read_write: process (clk) is
    variable index : integer range 0 to 2**address_length - 1;
  begin
      if (enable = '1' and clk = '1' and clk'event) then
        index := toInt(addr);

        if (wr = '1') then
          ram(index) <= data_in;
        end if;

        if (rd = '1') then
          data_out <= ram(index);
        end if;
      end if;
  end process;
end architecture behavior;



-- plug in or plug out ram
plug_in_out: process (enable) is  
  variable first_load : boolean := true;
  begin
    if ((enable = '0' and enable'event) or first_load = true) then
      data_out <= (others => 'Z');

      if (first_load = true) then
        first_load := false;
      end if;
    end if;  
  end process;

reset_ram: process (reset) is
    variable initialized: boolean := false;
  begin
    if ((reset = '1' and reset'event) or (initialized = false)) then
      ram <= (OTHERS => (OTHERS => '0'));

      if (initialized = false) then
        initialized := true;
      end if;
    end if;
  end process;

 -- it serves both "read" and "write" operation for the RAM
  read_write: process (clk) is
    variable index : integer range 0 to 2**address_length - 1;
  begin
      if (enable = '1' and clk = '1' and clk'event) then
        index := toInt(addr);

        if (wr = '1') then
          ram(index) <= data_in;
        end if;

        if (rd = '1') then
          data_out <= ram(index);
        end if;
      end if;
  end process;
end architecture behavior;

The timing diagram The timing diagram

因此,主要问题是为什么初始化没有按照reset_ram过程中的第5行所示进行。代码调试表明上述行已执行但RAM信号的值保持不变。

2 个答案:

答案 0 :(得分:1)

在VHDL中,应在单个过程中分配信号。否则,您将获得多个驱动程序,这些驱动程序通常无法合成。如果驱动值不兼容(例如同时驱动&#39; 0&#39;和&#39; 1',那么在模拟中为同一信号分配多个值将导致冲突,这将产生&#39; X&#39;。)

通过代码扫描,我发现至少data_outram在多个进程中都有分配。合并您的流程可以解决您的问题。

此外,RAM无法复位。这与模拟无关,但会影响合成。您可以重置输出寄存器(data_out),但RAM本身无法复位。如果这样做,合成器将使用寄存器而不是嵌入式RAM。但是,您可以通过像signal ram: MEMORY := (others => (others => '0'));这样定义RAM来获得RAM的初始内容。这得到了综合的支持。

答案 1 :(得分:0)

这里有几个问题。首先,如前所述,您不应该使用多个进程写入相同的信号,或者您有多个驱动程序问题。

如果你真的想要一个异步启用(最接近你在plug_in_out中描述的那个),那么你需要一个单独的信号用于实际输出。例如:

data_out_real <= (others => 'Z') when enable = '0' else data_out;

这是单行组合VHDL(不在进程内)。不过,我没有建议异步启用,你可以在主进程中运行同步启用。

用于获得初始状态的变量操作可能也不会合成,但您不需要。 data_out_real将始终具有显式("ZZZZ...")或data_out的副本的值。当您使用:

声明信号时,可以给data_out一个初始值
signal data_out : std_logic_vector(word_length-1 downto 0) := (others => '0');

假设您正在尝试创建一个针对FPGA的ram模块,那么您不能一次重置所有内容(您可以在寄存器文件中,但RAM不同),因为您尝试在{{1进程(它将模拟,可能合成,但不会进入FPGA的Block RAM)。执行此操作的常规方法是在复位变为高电平时触发复位状态,该复位状态具有计数器,该计数器遍历每个地址,每个时钟将一个位置指定为0。请注意,此状态机占用与正常读/写行为相同的进程(处于非重置状态)。另请注意,这不会像reset_ram中描述的那样进行异步重置。

实际的reset_ram进程对于ram的读/写状态看起来没问题,虽然您不需要索引变量/赋值,但在2 ram中进行转换同样容易使用更少的行进行索引操作。

要在此处实施启用,您可能需要将read_writeenable='1'分隔为单独的if图层。这允许您为数据输出默认值0或甚至Z(必须在clk上升沿检查内,在启用检查的else部分之外/之内)。如果你真的想要一个同步启用,那么最好做一些像这样的事情而不是我上面演示的组合比特。此外,如果 希望/有异步启用,则需要处理跨时钟路径以在此处的同步过程中使用它。

最后,考虑一下你真正希望你能做什么。在我所描述的大多数RAM中,当启用变低时,我不想丢失最后的读取值,我只是不想让它改变。这更容易实现,因为你可以不提及当启用低时要做什么,并且信号将保持其最后的值。