原创 【博客大赛】自己定制DPRAM的读写操作

2014-1-3 21:02 3675 14 25 分类: FPGA/CPLD
DPRAM的读写操作

下面是本人写的DPRAM的读写操作,自己定制DPRAM,不用altera FPGA 内部自带的IP core,选择的存储器块类型是M9K(对于不同类型的存储器块,当同时对某一个地址进行读写操作时读出来的结果不一样),当dpram的读写操作对同一个地址进行操作的时候,读出的数据是该地址中原来的数据,当下一个时钟上升沿到来时,读出的数据是刚才写入的数据。如果想避免两个端口同时对某一地址写操作的冲突就要用以下方法进行避免。避免就要用一下方法 

双口RAM 是在一个SRAM 存储器上具有两套完全独立的数据线、地址线和读写控制线,并允许两个独立的系统同时对该存储器进行随机性的访问。双口RAM最大的特点是存储数据共享。一个存储器配备两套独立的地址、数据和控制线,允许两个独立的CPU或控制器同时异步地访问存储单元。因为数据共享,就必须存在访问仲裁控制。内部仲裁逻辑控制提供以下功能:对同一地址单元访问的时序控制;存储单元数据块的访问权限分配;信令交换逻辑(例如中断信号)等。

双口RAM可用于提高RAM的吞吐率,适用于作于实时的数据缓存

如果同时访问双口RAM的同一存储单元,势必造成数据访问失真。为了防止冲突的发生,采用Busy逻辑控制,也称硬件地址仲裁逻辑。此处只给出了地址总线选通信信号先于片选脉冲信号的情况,而且,两端的片选信号至少相差tAPS——仲裁最小时间间隔,内部仲裁逻辑控制才可给后访问的一方输出Busy闭锁信号,将访问权交给另一方直至结束对该地址单元的访问,才撤消Busy闭锁信号,将访问权交给另一方直至结束对该地址单元的访问,才撤消Busy闭锁信号。即使在极限情况,两个CPU几乎同时访问同一单元——地址匹配时片选信号低跳变之差少于tAPS,Busy闭锁信号也仅输出给其中任一CPU,只允许一个CPU访问该地址单元。仲裁控制不会同时向两个CPU发Busy闭锁信号。

存储单元数据块的访问权限分配只允许在某一时间段内由1个CPU对自定义的某一数据块进行读写操作,这将有助于存储数据的保护,更有效地避免地址冲突。信号(Semaphore,简称SEM)仲裁闭锁就是一种硬件电路结合软件实现访问权限分配方法。SEM单元是与存储单元无关的独立标志单元。两个触发器在初始化时均使SEM允许输出为高电平,等待双方申请SEM。如果收到一方写入的SEM信号(通常低电平写入),仲裁电路将使其中一个触发器的SEM允许输出端为低电平,而闭锁另一个SEM允许输出端使其继续保持高电平。只有当先请求的一方撤消SEM信号,即写入高电平,才使另一SEM允许输出端的闭锁得到解除,恢复等待新的SEM申请。

 

 下面是具体代码及结果分析:

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_unsigned.all;

use ieee.std_logic_arith.all;

entity test_dpram is

       port(

              clk1: in std_logic;

              clr: in std_logic;

              addr_a,addr_b: in std_logic_vector(9 downto 0);

              we_a,we_b: in std_logic;

              rd_a,rd_b: in std_logic;

              cs_a,cs_b: in std_logic;

              data_a,data_b: in std_logic_vector(15 downto 0);

              q_a,q_b: out std_logic_vector(15 downto 0)

       );

end entity;

 

architecture behav of test_dpram is

type ram_t is array(2**10-1 downto 0) of std_logic_vector(15 downto 0);      

signal ram: ram_t;

signal addr_a_temp: std_logic_vector(9 downto 0);

signal addr_b_temp: std_logic_vector(9 downto 0);

attribute ram_init_file: string;

attribute ram_init_file of ram: signal is "test_dpram.mif";

begin

process(clk1,we_a,cs_a,rd_a)

begin

       if(rising_edge(clk1)) then                                         -- port a' read or write

              if(we_a='1' and rd_a='0') then

                     ram(conv_integer(addr_a))<=data_a;

                     end if;

              q_a<=ram(conv_integer(addr_a));

       end if;

end process;

process(clk1,we_b,cs_b,rd_b)      

begin     

       if(rising_edge(clk1)) then                                         -- port b' read or write

              if(we_b='1' and rd_b='0') then

                     ram(conv_integer(addr_b))<=data_b;

              end if;

              q_b<=ram(conv_integer(addr_b));

       end if;

end process;   

end architecture behav;

仿真结果及分析:

对于第一个时钟上升沿,A端口的地址为1,B端口的地址为2,而A是写,B端口读操作,由于初始化存储器文件中地址1,2的内容均为0000,且当dpram的读写操作对同一个地址进行操作的时候,读出的数据是该地址中原来的数据,所以A,B端口读出的数据均为0000,

  

 

此时地址1里面已经写入了1111,但是对于地址2,由于B端口没有进行写操作,地址2的内容仍为0000;当第二个时钟上升沿到来时,A,B端口均操作地址2,A端口仍为RDW(read during write)操作,写入数据为1234,A读出的仍是原来的数据0000,B端口只是读操作,所以读出的数据也是0000,此时地址2里已经写入了数据1234;当第三个上升沿到来时,两个端口都是读地址2中的数据,为1234(即刚才已经写入的数据);当第四个时钟上升沿到来时,A、B端口都是进行的RDW操作,读出来的数据均为原来的数据0000,但是这时由于两个端口同时同一个地址进行写操作,这样就会产生冲突,所以当下一个时钟上升沿到来时就会出现读出的数据为未知数据,如图中红色的部分所示。当第5个时钟上升沿到来时,A,B端口都是读操作,但是地址不同,所以不会产生冲突,对应的内容分别为地址768,769中的内容;第6个时钟上升沿到来时的情况与第5个类似,这里不再分析。

注:给双口RAM初始化的操作为

attribute ram_init_file: string;

attribute ram_init_file of ram: signal is "test_dpram.mif";

其中,test_fpram.mif为事先建立的存储器初始化文件。

 

另一种写法:读和写分开操作,

library ieee;

use ieee.std_logic_1164.all;  --调用常用的程序包

use ieee.std_logic_unsigned.all;

use ieee.std_logic_arith.all;

entity ram_test is         --定义实体

 generic(width:integer :=8;length:integer:=8);                                 --根据这个来改变RAM的大小,width为数据长度,length为数据个数            

 port(r_clk,w_clk:in std_logic;---定义写时钟和读时钟

      r_add,w_add:in std_logic_vector(2 downto 0);--写地址和读地址

      r_en,w_en:in std_logic;--读使能和写使能

      d_in:in std_logic_vector(width-1 downto 0);--数据输入

      d_out:out std_logic_vector(width-1 downto 0));--数据输出

end entity;

architecture art of ram_test is

 type memory is array (0 to length-1) of std_logic_vector(width-1 downto 0);---定义一数组类型来存储数据

 signal data:memory;

 begin

process(w_clk,w_add,w_en,d_in)--写数据进程

begin

   if w_clk'event and w_clk='1' then--在时钟上升沿来时

    if w_en='1' then              --若使能为1,则写数据

    data(conv_integer(w_add))<=d_in;

   end if;

  end if;

end process;

process(r_clk,r_add,r_en,data)--读数据进程

begin

    if r_clk'event and r_clk='1' then

        if r_en='1' then

     d_out<=data(conv_integer(r_add));

    end if;

   end if;

end process;

end art;

文章评论11条评论)

登录后参与讨论

用户377235 2014-3-6 13:47

是不是需要将内存空间写满才能读?

用户377235 2014-3-6 13:47

请问楼主,DPRAM和SDRAM在操作上有何区别?

用户377235 2014-2-22 09:18

能不能加好友,具体详寻呢

用户377235 2014-2-22 09:16

楼主有没有更细致一点的?

用户377235 2014-1-19 15:26

可不可以另外加一条控制线来作为读写的控制端呢?

用户377235 2014-1-19 15:22

如何实现读写分开呢?

用户1725879 2014-1-8 09:25

不明觉厉!

coyoo 2014-1-7 11:24

可能是我的理解有误,看你原文的意思是自己来coding一个dpram,而不是例化altera的IP。所以我觉得如果是自己coding一个,那么必然要更优于altera现成的IP核,否则何必要重新弄一个呢。因此,在自己弄的时候就可以将这种端口地址控制打包到你的这个dpram模块里。

1053683568_507245520 2014-1-5 21:01

dpram本身可以控制吗?我试了一下,会报错,怎么回事呢?

coyoo 2014-1-4 11:29

这种控制应该属于dpram的一部分吧。
相关推荐阅读
1053683568_507245520 2014-03-20 11:19
cadence16.6 软件绘制PCB板
   最近一直在学习cadence的使用,现在就对近来学习做个总结,虽然还没有达到熟练的程度,但是也希望可以给后来者做个借鉴吧。         本人的方向是硬件方向,马上面临着找工作的压力。...
1053683568_507245520 2013-12-15 20:51
【博客大赛】我的EDN
我的EDN 每次进入EDN网站,看到大家在踊跃的分享自己的学习经历,经验,以及聊生活谈梦想,都会激发我的热情,激发我对生活的热爱,对未来的幻想,对自己的思索。当我懒惰时,我会进来看看,看看特权...
1053683568_507245520 2013-12-07 11:31
【博客大赛】利用FPGA控制VGA接口来使显示器显示彩条纹(里面包括调试中的查错检查方法)
利用FPGA控制VGA接口来使显示器显示彩条纹 最近一直在调关于通过VGA接口来控制显示器的程序,今天终于调试出结果来了,赶紧上来与大家分享一下。 1、VGA显示原理 常见的彩色显示器...
1053683568_507245520 2013-12-06 11:45
【博客大赛】利用VHDL产生奇分频器
利用VHDL产生占空比为50%的奇倍数分频电路 一般的介绍VHDL语言的书在对分频器进行举例描述的时候,都是举得偶数倍分频的例子,因为那相对来说比较简单(只需要设置一个中间信号变量,然后在分频...
1053683568_507245520 2013-12-06 11:45
【博客大赛】VHDL进程语句的并行执行分析
相信许多人在学习VHDL时,都会对进程如何执行的,以及进程之间的并行执行产生疑问,本文将以下面一个具体的例子来分析单个进程的执行,与进程之间的并行执行。 library ieee; use...
我要评论
11
14
关闭 站长推荐上一条 /2 下一条