RAM仿真代码在VHDL中无法很好地模拟

时间:2014-05-31 00:13:54

标签: vhdl

我正在尝试模拟RAM类型的存储器,输入和输出呈现在相同的线路和功能上,并通过3个控制引脚选择。 ceN用于启用器件(否则输出为高Z),weN用于允许写入RAM,而oeN不启用输出到data_io向量。这些控件都是低电平有效类型。

这通过了Quartus II下的编译,但是不能很好地模拟Modelsim或Quartus的内置模拟。

library ieee ;
use ieee.std_logic_1164.all ;

entity ram1 is
    port ( address    : in     integer range 0 to 255       ;
             ceN        : in     std_logic                    ;
             weN        : in     std_logic                    ;
             oeN        : in     std_logic                    ;
             data_io    : buffer std_logic_vector(7 downto 0) ) ;
end ram1 ;

architecture arc_ram1 of ram1 is
    type mem_array is array (0 to 255) of std_logic_vector(7 downto 0) ;
    signal ram  : mem_array ;
    signal data : std_logic_vector(7 downto 0) ;

begin
    process ( address , ceN , weN , oeN , data_io )
    begin
        -- write to RAM
        if ceN = '0' then
            if weN = '0' then
                ram(address) <= to_x01(data_io) ;
            elsif oeN = '0' then
                data_io <= ram(address) ;
            end if ;
        else
            data_io <= (others => 'Z') ;
        end if ;
    end process ;
end arc_ram1 ;

2 个答案:

答案 0 :(得分:1)

您确实希望将data_io信号的类型切换为inout。当你这样做时,你暗示一个三态缓冲区。这意味着在您的逻辑(包括您的测试平台)中,您必须确保无论何时一方正在驱动接口,另一方正在驱动'Z',否则总线将有两个驱动程序,如果两者都模拟器将显示'X'司机有相同的驱动力。

这是一个简单的测试序列,可以与您的DUT一起使用,以显示RAM读/写逻辑是否正常工作:

test: process is
begin
  address  <= 0;
  data_io  <= (others => 'Z');
  ceN      <= '0';
  oeN      <= '0';
  weN      <= '1';
  wait for 20 ns;

  address  <= 0;
  data_io  <= (others => '1');
  oeN      <= '1';
  weN      <= '0';
  wait for 20 ns;

  address  <= 0;
  data_io  <= (others => 'Z');
  oeN      <= '0';
  weN      <= '1';
  wait for 20 ns;

  address  <= 1;
  data_io  <= (others => '0');
  oeN      <= '1';
  weN      <= '0';
  wait for 20 ns;

  address  <= 1;
  data_io  <= (others => 'Z');
  oeN      <= '0';
  weN      <= '1';
  wait for 20 ns;

  address  <= 0;
  wait for 20 ns;

end process test;

我必须修改你的逻辑,以确保当测试平台在内存写入期间尝试驱动RAM时,RAM没有驱动data_io总线:

process ( address , ceN , oeN, weN , data_io )
begin
    -- write to RAM
    if ceN = '0' then
        if weN = '0' then
            ram(address) <= to_x01(data_io) ;
            data_io <= (others => 'Z') ;  -- *** Added this ***
        elsif oeN = '0' then
            data_io <= ram(address) ;
        end if ;
    else
        data_io <= (others => 'Z') ;
    end if ;
end process ;

如果以这种方式编写进程代码,我必须在写入期间添加三态data_io总线的原因可能更容易理解:

process ( address , ceN , oeN, weN , data_io )
begin
    -- write to RAM
    if ((ceN = '0') and (weN = '0')) then
        ram(address) <= to_x01(data_io) ;
    end if ;

    -- read from RAM
    if ((ceN = '0') and (oeN = '0')) then
        data_io <= ram(address) ;
    else
        data_io <= (others => 'Z') ;
    end if ;
end process ;

答案 1 :(得分:0)

你已经创建了一些透明锁存器!

让您的流程同步,例如

process(clk)
begin
    if rising_edge(clk) then
        ...
    end if;
end process;

例如,以下内容之间存在很大差异:

process(en, d)
    signal q : std_logic;
begin
    if en = '1' then
        q <= d;
    end if;
end process;

以及以下内容:

process(clk)
    signal q : std_logic;
begin
    if rising_edge(clk) then
        if en = '1' then
            q <= d;
        end if;
    end if;
end process;

这些示例中的第一个是透明锁存器,后者是常规触发器。前者容易受到输入中的短暂错误的影响,并且通常无法映射到真实硬件。后者是设计合适的FPGA逻辑的方法。 Quartus可能会让你通过警告来逃避它,但它肯定不是你想要的!

另外,检查您的警告,看看Quartus是否推断了透明锁存器而不是您想要的RAM块。它仍然可以构建,即使这种行为几乎从来都不是故意的。