VHDL学习—双端口存储器

存储器,顾名思义作用就是用于存储数据。存储器分RAM和ROM两种,其中ROM为只读存储器,而RAM为可读写存储器,既可写入数据,也可读取数据。常用的存储器都为单端口存储器,即数据输入端和数据输出端用同一个端口。所以通常RAM存储器的引脚通常有一组数据线(双向)、一组地址线、一个时钟入口以及一个读写控制信号。在时钟的边沿触发下,通过读写控制信号控制读写。当进行写操作时,将数据写入地址线指定的单元,当进行读操作时将地址线指定单元的内容读出。
由于笔者项目需求,需要一个双端口的存储器,即需要设计一个存储器带有两个数据端口和两个地址端口,可同时进行读、写操作。一个端口用于读写数据,另一端用于读写指令,以满足项目需要。
实际上,在quartus ii环境下,可以通过调用IP核的方式调用单或双端口的RAM存储器,在17.1版本中,可以点击Tools->IP Catalog,搜索RAM,调用现有的RAM,如图所示在这里插入图片描述
选中之后如图,可以设置存储器的数据位宽以及深度(即多少个单元)。还有多项设置,比如设置RAM初始的数据等。这也不是失去为一种调用存储器的方法。在这里插入图片描述
笔者这里之所以要用VHDL再写一个双端口存储器并不是闲着没事干(确实是),主要原因除了为了提高VHDL编程能力外,大家可以看到图中的RAM存储器虽然说是单端口,但实际上数据的输入和输出并不是同一个端口。数据从data[7…0]输入而从q[7…0]输出。笔者由于项目需要,RAM需要与CPU总线相连,数据口需要为双向,因此不得不自行撰写。
说了这么多,接下来介绍一下笔者所写的双端口RAM。此RAM为一个8X1k的双端口RAM,分为数据端口和指令端口。数据端口为可读写双向端口,包含数据线inout_data、数据地址线addr_d以及数据读写控制信号DRW。当DRW为高时进行读操作,低进行写操作。指令端口作为只可读端口,包含指令数据线(单向输出)、指令地址addr_c以及指令读写控制信号CRW,为高时进行读操作。还有一个CEL数据端口选择信号,当为低电平时有效,数据端口可进行读写操作,为高则禁止数据端口操作。
代码如下:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity RAM is 
  port
  ( 
	 T3: in std_logic;
	 DRW: in std_logic;   --数据读写控制信号,为高进行写操作,为低进行读操作
	 CRW: in std_logic;   --指令读写控制信号,为高进行读操作
	 CEL: in std_logic;   --双端口选择信号。为低从数据端口进,为高从指令端口进
    addr_c: in std_logic_vector(7 downto 0);--指令地址
	 addr_d: in std_logic_vector(7 downto 0);--数据地址
    inout_data: inout std_logic_vector(7 downto 0);
    output_cmd: out std_logic_vector(7 downto 0)
	);
end RAM;

architecture behave of RAM is
  type ram_type is array (0 to 1024) of std_logic_vector(7 downto 0);
  signal mem: ram_type;
begin 

process(T3,CEL,DRW)  -- 数据端口读写操作
begin  
  if rising_edge(T3) then
     if CEL='1' then  --数据端口选择信号,为1则禁止
	     inout_data<=(others=>'Z');
	  else
		 if DRW='1' then  --为1,数据写入内存;为0,从内存读取数据
          mem(to_integer(unsigned(addr_d)))<=inout_data; 
		 else
		    inout_data<=mem(to_integer(unsigned(addr_d)));
     end if; 
   end if;
  end if;
end process;
  
process(T3,CRW)  -- 指令端口读操作
  begin
    if rising_edge(T3) then
		 if CRW='1' then
		   output_cmd<=mem(to_integer(unsigned(addr_c)));
       end if;
      end if;
end process;
end behave;

注意了,数据端口用的信号类型是 inout std_logic_vector(7 downto 0),为双向端口。
这段代码的核心就是这一段
type ram_type is array (0 to 1024) of std_logic_vector(7 downto 0);
signal mem: ram_type;
通过这段代码,类似定义了一个ram_type类型的二维数组 mem(x)(y)。x为0 to 1024,即数据存储单元的地址,y则为0到7,用于存储数据。有了这样一个数组,就可以通过外部输入的地址信息,将外部数据写入内存单元,或者将指定内存单元的数据读出。例如写操作:
mem(to_integer(unsigned(addr_d)))<=inout_data;
将inout_data数据写入addr_d指定地址的单元中。由于输入的地址为8位2二进制数,所以需要用to_integer、unsigned,数据类型转换成整型数据。读操作同理:
output_cmd<=mem(to_integer(unsigned(addr_c)));
将指定单元的数据读出。
这样一个双端口RAM就完成了,实测有效。
若是需要在RAM初始化一部分数据,则在architecture 中定义的数组中添加如下代码

attribute ram_init_file:string;
attribute ram_init_file of mem:
signal is"RAM.hex";
其中mem为你的数组名称,RAM.hex为你预先写好的数据文件,可以通过new->file中新建下图任意一种格式的存储文件,在其中输入需要初始化的数据即可,两种文件的格式分别为.hex和.mif。
在这里插入图片描述
建立好数据文件后,和实体文件一同编译,之后就可以从RAM中读取初始化的数据了。
当写好了实体模块化以后,准备与其他器件相连时,要注意当双向数据端口inout_data[7…0]与其他数据线或者总线相连时,需要加上一个三态门控制端口才能正常通过编译(双击原理图输入tri即可找到),进行数据的双向传递。三态门有一个控制端口,高有效通过。
不只是双向口,当一条数据线有多个输入时,都需要加上三态门进行控制,否则数据就混乱了:)
在这里插入图片描述

  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
端口存储器是一种在数字集成电路设计中常见的存储器元件。它具有两个独立的写入端口和两个独立的读取端口,使得可以同时进行读写操作。在VHDL语言中,可以使用一系列的语句和结构来描述端口存储器的行为和功能。 在VHDL中描述端口存储器,需要定义存储器的输入输出端口、存储单元、读写控制逻辑等相关部分。可以使用entity来定义存储器模块的接口,包括输入输出端口的名称、数据位宽和控制信号。然后使用architecture来描述存储器的内部实现,包括存储单元的结构和读写控制逻辑的实现。 在描述存储单元时,可以使用寄存器数组或者RAM的结构来实现存储器的功能。同时需要考虑到端口存储器的并发读写操作,确保读写操作不会出现冲突或者数据混乱的情况。因此需要合理设计读写控制逻辑,并且在VHDL中使用适当的语句和时序控制来描述读写操作的同步和时序关系。 此外,还需要考虑到端口存储器VHDL中的时序和异步操作,确保存储器读写操作都能够按照预期的时序进行。最后,要注意使用VHDL模拟工具对端口存储器进行验证和调试,确保存储器的功能和性能符合设计要求。 总之,在VHDL中描述端口存储器需要考虑到存储器的接口定义、内部结构实现、读写控制逻辑的设计和时序同步等方面,以确保存储器在数字电路设计中的正确性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值