请教关于SRAM(VHDL)建模的一些问题
最近在研究SRAM,然后自己写个VHDL程序来验证设计的SRAM模型是否正确。结果代码中存在一些问题:无语法错误,但是读取数据时不能有效读出。废话不多说。模型代码如下:
- library IEEE;
- use IEEE.STD_LOGIC_1164.ALL;
- use IEEE.STD_LOGIC_ARITH.ALL;
- use IEEE.STD_LOGIC_UNSIGNED.ALL;
- entity sram is
- port(
- sram_addr : in STD_LOGIC_VECTOR(3 DOWNTO 0);--地址信号
- sram_oe : in STD_LOGIC;--输出允许信号
- sram_we : in STD_LOGIC;--写允许信号
- sram_data : inout STD_LOGIC_VECTOR(7 DOWNTO 0);--读取到的数据或者写入的数据
- sram_ce : in STD_LOGIC--芯片有效信号
- );
- end sram;
- architecture Behavioral of sram is
- TYPE memory_array IS ARRAY ( 0 TO 15 )OF STD_LOGIC_VECTOR(7 DOWNTO 0);
- SIGNAL mysram : memory_array;--定义16*8bit SRAM
- SIGNAL int_addr : INTEGER RANGE 0 TO 15;
- SIGNAL we_rise,din_change :TIME := 0 ns;
- begin
- int_addr <= CONV_INTEGER(sram_addr);--将位矢量转换为int型数据
-
- PROCESS(sram_we)
- BEGIN
- IF(sram_we'EVENT AND sram_we = '1') THEN --当we上升沿
- IF(sram_ce ='0' AND sram_we ='1') THEN --检测片选是否有效,且sram_we是否为高电平,若是,则更新数据
- mysram(int_addr) <= sram_data AFTER 2 ns;
- END IF;
- END IF;-- IF(sram_we'EVENT AND sram_we = '1')
- we_rise <= NOW;
- ASSERT (NOW - din_change >= 2 ns);
- REPORT "SETUP ERROR din(SRAM)"
- SEVERITY WARNING; --din 建立时间检查
- END PROCESS;
- PROCESS(sram_oe,sram_ce)
- BEGIN
- IF(sram_oe = '0' AND sram_ce ='0') THEN
- sram_data <= mysram(int_addr) AFTER 3 ns;
- ELSE
- sram_data <= "ZZZZZZZZ" AFTER 4 ns;
- END IF;
- END PROCESS;
测试文件如下所示:
- LIBRARY IEEE;
- USE IEEE.STD_LOGIC_1164.ALL;
- ENTITY sram_test IS
- END sram_test;
- ARCHITECTURE behav OF sram_test IS
- COMPONENT sram
- PORT
- (
- sram_addr:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
- sram_oe :IN STD_LOGIC;
- sram_we :IN STD_LOGIC;
- sram_data :INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
- sram_ce :IN STD_LOGIC
- );
- END COMPONENT;
- SIGNAL addr:STD_LOGIC_VECTOR (3 DOWNTO 0);
- SIGNAL oe:STD_LOGIC;
- SIGNAL we:STD_LOGIC;
- SIGNAL io:STD_LOGIC_VECTOR(7 DOWNTO 0);
- SIGNAL ce:STD_LOGIC;
- BEGIN
- uut:sram PORT MAP
- (
- sram_addr => addr,
- sram_oe => oe,
- sram_we => we,
- sram_data => io,
- sram_ce => ce
- );
- PROCESS
- BEGIN
- addr <= "0000";
- io <= "00000001";
- wait for 2 ns;
- oe <= '1';
- we <= '1';
- ce <= '0';
- wait for 2 ns;
- we <= '0';
- wait for 8 ns;
- we <= '1';
- wait for 4 ns; --第一个上升沿
- addr <= "0001";
- io <= "00000010";
- wait for 2 ns;
- we <= '0';
- wait for 8 ns; --第二个上升沿
- we <= '1';
- wait for 2 ns;
- addr <= "0000";
- wait for 2 ns;
- oe <= '0';
- wait for 8 ns;
- oe <= '1';
- addr <= "0001";
- wait for 2 ns;
- oe <= '0';
- wait for 8 ns;
- oe <= '1';
- wait;
- END PROCESS;
- END behav;
仿真截图如下所示:

当sram_oe为低电平,地址sram_addr为"0000"时,此时应该端口sram_data应该读出数据"00000001"但是仿真图上显示为"000000xx",请高手指点!
你看数据是000000xx,也就是说高多少位都是确定数据,低多少位是不确定数据,而之前看到数据已经为00001过,说明原始数据也是确定的。
你查一下,是不是之前在地址为0时有个写使能写进去了数据,而这个数据刚好后面为XX,不小心把不要的数据写进去了一小半。
好像不是这个问题,并没有写入新的数据;应该是inout类型的问题吧,我重新修改了代码,在输出时重新定义了一个数据端口dout,这样读出的数据便是正确的;但我不知道怎么改。求进一步指导。修改的代码如下
- PROCESS(sram_oe,sram_ce)
- BEGIN
- IF(sram_oe = '0' AND sram_ce ='0') THEN
- dout <= mysram(int_addr) ;
- ELSE
- dout <= "ZZZZZZZZ" ;
- END IF;
- END PROCESS;
- sram_data <= dout WHEN sram_ce ='0' ELSE
- "ZZZZZZZZ";
反复看了几遍,终于看明白了,we是高有效,ce与oe是低有效,同时你还用组合逻辑使用了after 2ns之类的延迟。
你看出问题的地方附近,oe为0与we为1同时存在,表明这端口同时在读与写,这是不应该存在的啊?
另外,如果你最终是为了综合到CPLD中使用,那最好不要用after 2ns之类的语句,因为综合是无效的,同时会使仿真结果与上板结果不一致。 并且你一会用 after 2 ns, 一会3ns,这也最好不使用。建设统一不用,有相关需求都做在TB中,可综合的代码归综合,仿真的归仿真。
你关于双向数据的处理没有问题,输入时直接进来,输出时通过使能进行三向选择,这是标准做法。
你好,按照你说的问题改了,可是还是还存在那个问题,您能不能再帮忙修改下,谢谢!
你再贴波形出来看看,
另外,真的没有时钟吗?必须用全组合逻辑去完成?这个倒觉得关系不大。
你贴波形时,如果还有XX的,把相关部分的细节也贴出来看看
现在的仿真波形图:
图中黄色椭圆所画部分为我难以理解的地方,此时应该为“ZZZZZZZZ"的,但是输出却为”00000002“,在下降沿读出数据可以读到端口data_o上,但是当赋值给sram_data时,数据还是错误。很不理解。详细程序如下
:
- begin
- int_addr <= CONV_INTEGER(sram_addr);
- data_i <= sram_data WHEN dir = '0' ELSE (OTHERS => 'Z'); --当dir='0'用作输入,dir='1'用作输出
- write_data:PROCESS(sram_we)
- BEGIN
- IF(sram_we'EVENT AND sram_we ='1') THEN--上升沿写入数据
- IF(sram_ce ='1' AND dir = '0') THEN
- mysram(int_addr) <= data_i;
- END IF;
- END IF;
- END PROCESS write_data;
- read_data:PROCESS(sram_oe)
- BEGIN
- IF(sram_oe'EVENT AND sram_oe ='0') THEN --下降沿读数据到端口data_o
- IF(sram_ce ='1' AND dir ='1') THEN
- data_o <= mysram(int_addr);
- ELSE
- data_o <= (OTHERS => 'Z');
- END IF;
- END IF;
- END PROCESS read_data;
- PROCESS(data_o,dir,sram_ce,sram_oe) --
- BEGIN
- IF(dir = '1' AND sram_ce ='1' AND sram_oe ='0') THEN
- sram_data <= data_o ;
- ELSE
- sram_data <= (OTHERS => 'Z');
- END IF;
- END PROCESS;
- end Behavioral;
如果你能使用同步时钟最好,如果不能,还是要注意下异步信息的处理。
就是读写时,当你要切换到再一个地址时,先把读写使能关上,再跳到下一个地址,然后读写,结束后再关掉使能,再跳到下一个地址。这样做才能避免误写误读。
比如一个SRAM模型是相当简单的,你再弄异步的话,就做复杂了。 现在仿真出问题还算不了啥,上板实测出问题才纠结呢
兄弟写的代码风格
IF(sram_oe'EVENT AND sram_oe ='0') THEN --下降沿读数据到端口data_o
16. IF(sram_ce ='1' AND dir ='1') THEN
这个的意思是把sram_oe作为时钟信息来采集下降沿来取数据,
还有段是把sram_we作为时钟来采集上升沿的数据,
一半组合逻辑,一半时钟逻辑,
你先别纠结结果为啥错了,先引进个时钟来完全重新来写段同步代码吧,
嗯,好的,我试下。刚开始学VHDL,组合逻辑,时序逻辑这些都不太熟。见笑了,谢谢指点!
你好,你有SRAM现成的例子吗?。我在你书上找了个代码可是仿真时还是有错误。
你好,你有SRAM现成的例子吗?。我在书上找了个代码,可是仿真时还是有错误。
你和COREGEN 工具生成的,现成的,
嗯,好的。谢谢指点。
