一、Quartus

1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager

2.弹出创建页面,选择Creat a new custom megafunction variation,点Next

3.选择IP核,可以直接搜索ram,选择RAM:2-PORT,右上方选择器件型号,语言选成Verilog,再填写一下路径名字,点Next,后面就是参数设置了。

4.设置读写需要几个端口,深度计算按word还是bit。Next

5.设置深度,位宽,类型。Next

6.设置读写需要几个端口,深度计算按word还是bit,一般选word。Next

7.是否为输出添加一个寄存器(加了寄存器可以使RAM输出的数据更稳定)?本来ram的输出就是会慢1clk,勾选后又慢1clk,所以一般不勾选。Next

8.输出的是新数据还是老数据,一般是要新数据,所以I don't care就行。Next

9.是否添加初始化文件mif ? Next

10.告诉你此IP核的编译库是什么,Next

11.输出的文件列表,除了正常IP核,还可以选择例化文件,注意bb.v文件用不到,一般是不勾选的。之后点finish就生成IP核了。

二、ISE

1.创建ISE工程,IP核需要在ISE工程里面进行调用。点击Tools---Core Generator...

2.在新弹出来的界面中创建一个属于IP核的工程:file---new project,并填写文件存储位置和文件名称,一般为ipcore_dir文件夹,点击保存

3.弹出的Part处填写器件的系列、型号、封装以及速度等级,Generation处设置语言为Verilog,点击OK

4.点击文件夹,找到Memories & Storage Elements---RAMs & ROMs---Block Memory Generator,(也可以直接搜索)双击打开,进行参数设置

5.设置模块名称,Next

6.类型选择,一般选Single Dual RAM,该RAM为“a口负责写,b口负责读”,而对于真双口RAM来说,a和b都是可读可写。其他选项根据需要勾选。Next

7.RAM的位宽、深度、使能选择,Next

8.是否在B端添加一个寄存器(加了寄存器可以使RAM输出的数据更稳定)?本来ram的输出就慢1clk,勾选了又慢1clk,所以一般不勾选。是否需要初始化并加载初始化ceo文件,Next

9.是否对B口添加复位键,Next

10.总结页面,注意里面一句话:B口的读取有1clk的延迟,点击Generate即可生成RAM。大功告成!

三、单RAM读写操作(by威三学院FPGA教程)

本代码针对Quartus的RAM:2-PORT

  1. //==========================================================================
  2. // --- 名称 : ram_ctrl.v
  3. // --- 作者 : xianyu_FPGA
  4. // --- 日期 : 2019-06-23
  5. // --- 描述 : 单个ram读写操作
  6. //==========================================================================
  7.  
  8. module ram_ctrl
  9. //---------------------<端口声明>-------------------------------------------
  10. (
  11. input wire clk , //时钟,50Mhz
  12. input wire rst_n , //复位,低电平有效
  13. input wire [:] din , //写入的数据
  14. output wire [:] dout //读出的数据
  15. );
  16. //---------------------<信号定义>-------------------------------------------
  17. reg wr_en ; //写使能
  18. reg [:] wr_addr ; //写地址
  19. reg [:] rd_addr ; //读地址
  20.  
  21. //--------------------------------------------------------------------------
  22. //-- ram例化
  23. //--------------------------------------------------------------------------
  24. ram_256x8 u_ram_256x8
  25. (
  26. .clock (clk ),
  27. .wren (wr_en ),
  28. .wraddress (wr_addr ),
  29. .data (din ),
  30. .rdaddress (rd_addr ),
  31. .q (dout )
  32. );
  33.  
  34. //--------------------------------------------------------------------------
  35. //-- 产生写使能
  36. //--------------------------------------------------------------------------
  37. always @(posedge clk or negedge rst_n) begin
  38. if(!rst_n)
  39. wr_en <= 'b1;
  40. else if(wr_addr=='d255)
  41. wr_en <= 'b0;
  42. else if(rd_addr=='d255)
  43. wr_en <= 'b1;
  44. end
  45.  
  46. //--------------------------------------------------------------------------
  47. //-- 产生写地址
  48. //--------------------------------------------------------------------------
  49. always @(posedge clk or negedge rst_n) begin
  50. if(!rst_n)
  51. wr_addr <= 'd0;
  52. else if(wr_en==)
  53. wr_addr <= wr_addr+'d1;
  54. else
  55. wr_addr <= 'd0;
  56. end
  57.  
  58. //--------------------------------------------------------------------------
  59. //-- 产生读地址
  60. //--------------------------------------------------------------------------
  61. always @(posedge clk or negedge rst_n) begin
  62. if(!rst_n)
  63. rd_addr <= 'd0;
  64. else if(wr_en==)
  65. rd_addr <= rd_addr+'d1;
  66. else
  67. rd_addr <= 'd0;
  68. end
  69.  
  70. endmodule

四、双RAM乒乓操作(by威三学院FPGA教程

RAM的简单读写比较简单,平常也用不太到,比较重要的是异步双口RAM实现乒乓操作。

本代码针对ise的Simple Dual PORT RAM

  1. //==========================================================================
  2. // --- 名称 : ram_pp.v
  3. // --- 作者 : xianyu_FPGA
  4. // --- 日期 : 2019-06-23
  5. // --- 描述 : 异步双口ram乒乓操作
  6. //==========================================================================
  7.  
  8. module ram_pp
  9. //---------------------<端口声明>-------------------------------------------
  10. (
  11. input wire clk , //时钟,50Mhz
  12. input wire rst_n , //复位,低电平有效
  13. input wire [:] din , //输入的数据
  14. output wire [:] dout //输出的数据
  15. );
  16. //---------------------<信号定义>-------------------------------------------
  17. //ram_a
  18. reg wr_en_a ;
  19. reg [:] wr_addr_a ;
  20. reg [:] rd_addr_a ;
  21. wire [:] dout_a ;
  22. //ram_b
  23. reg wr_en_b ;
  24. reg [:] wr_addr_b ;
  25. reg [:] rd_addr_b ;
  26. wire [:] dout_b ;
  27. //缓一拍
  28. reg wr_en_a_r0 ;
  29.  
  30. //--------------------------------------------------------------------------
  31. //-- ip核例化
  32. //--------------------------------------------------------------------------
  33. //ram_a
  34. ram_1024x8 u_ram_1024x8_a
  35. (
  36. .clka (clk ), // input clka
  37. .wea (wr_en_a ), // input [0 : 0] wea
  38. .addra (wr_addr_a ), // input [9 : 0] addra
  39. .dina (din ), // input [7 : 0] dina
  40. .clkb (clk ), // input clkb
  41. .addrb (rd_addr_a ), // input [9 : 0] addrb
  42. .doutb (dout_a ) // output [7 : 0] doutb
  43. );
  44. //ram_b
  45. ram_1024x8 u_ram_1024x8_b
  46. (
  47. .clka (clk ), // input clka
  48. .wea (wr_en_b ), // input [0 : 0] wea
  49. .addra (wr_addr_b ), // input [9 : 0] addra
  50. .dina (din ), // input [7 : 0] dina
  51. .clkb (clk ), // input clkb
  52. .addrb (rd_addr_b ), // input [9 : 0] addrb
  53. .doutb (dout_b ) // output [7 : 0] doutb
  54. );
  55.  
  56. //--------------------------------------------------------------------------
  57. //-- ram_a
  58. //--------------------------------------------------------------------------
  59. // 写使能
  60. always @(posedge clk or negedge rst_n) begin
  61. if(!rst_n)
  62. wr_en_a <= 'b1;
  63. else if(rd_addr_a=='d1023)
  64. wr_en_a <= 'b1;
  65. else if(wr_addr_a=='d1023)
  66. wr_en_a <= 'b0;
  67. end
  68.  
  69. // 写地址
  70. always @(posedge clk or negedge rst_n) begin
  71. if(!rst_n)
  72. wr_addr_a <= 'd0;
  73. else if(wr_addr_a=='d1023)
  74. wr_addr_a <= 'd0;
  75. else if(wr_en_a=='b1)
  76. wr_addr_a <= wr_addr_a + 'b1;
  77. end
  78.  
  79. // 读地址
  80. always @(posedge clk or negedge rst_n) begin
  81. if(!rst_n)
  82. rd_addr_a <= 'd0;
  83. else if(rd_addr_a=='d1023)
  84. rd_addr_a <= 'd0;
  85. else if(wr_en_a=='b0)
  86. rd_addr_a <= rd_addr_a + 'b1;
  87. end
  88.  
  89. //--------------------------------------------------------------------------
  90. //-- ram_b
  91. //--------------------------------------------------------------------------
  92. // 写使能
  93. always @(posedge clk or negedge rst_n) begin
  94. if(!rst_n)
  95. wr_en_b <= 'b0;
  96. else if(wr_addr_a=='d1023) //关键之处!!!
  97. wr_en_b <= 'b1;
  98. else if(wr_addr_b=='d1023)
  99. wr_en_b <= 'b0;
  100. end
  101.  
  102. // 写地址
  103. always @(posedge clk or negedge rst_n) begin
  104. if(!rst_n)
  105. wr_addr_b <= 'd0;
  106. else if(wr_addr_b=='d1023)
  107. wr_addr_b <= 'd0;
  108. else if(wr_en_b=='b1)
  109. wr_addr_b <= wr_addr_b + 'b1;
  110. end
  111.  
  112. // 读地址
  113. always @(posedge clk or negedge rst_n) begin
  114. if(!rst_n)
  115. rd_addr_b <= 'd0;
  116. else if(rd_addr_b=='d1023)
  117. rd_addr_b <= 'd0;
  118. else if(wr_en_b=='b0)
  119. rd_addr_b <= rd_addr_b + 'b1;
  120. end
  121.  
  122. //--------------------------------------------------------------------------
  123. //-- wr_en_a缓一拍时序才对齐
  124. //--------------------------------------------------------------------------
  125. always @(posedge clk or negedge rst_n) begin
  126. if(!rst_n)
  127. wr_en_a_r0 <= ;
  128. else
  129. wr_en_a_r0 <= wr_en_a;
  130. end
  131.  
  132. //--------------------------------------------------------------------------
  133. //-- 数据输出
  134. //--------------------------------------------------------------------------
  135. assign dout = (wr_en_a_r0==) ? dout_a : dout_b;
  136.  
  137. endmodule

五、单口,伪双口,真双口的区别

1.单口:只有一组数据线和地址线,只生成一个addr,因此不能同时进行读写。

2.双口:拥有两组数据线和地址线,可以生成wr_addr和rd_addr,因此可以同时进行读写。

    ①伪双口:一个端口读,一个端口写。

    ②真双口:两个端口都能读能写。

ps:

无论是单口、伪双口还是真双口,他们都只使用一块Memory,真双口其实是两组地址对同一块Memory进行读写,如果真双口的两端口同时对同一地址进行写入数据,那实际情况是未知(仿真也不可信)。

六、ROM、RAM和FIFO的区别

1.ROM有地址,只能读而不能写。用初始化文件mif/ceo将内容存进去,读取不会使得数据减少消失。

2.RAM有地址,可以进行寻址读写,数据写进去后,读取不会使得数据减少消失。

3.FIFO没有地址,只能是先进先出,数据写进去后,读取会使得数据减少消失,读一个少一个。

参考资料:

[1]威三学院FPGA教程

[2]小梅哥FPGA教程

IP核——RAM的更多相关文章

  1. 用嵌入式块RAM IP核配置一个双口RAM

    本次设计源码地址:http://download.csdn.net/detail/noticeable/9914173 实验现象:通过串口将数据发送到FPGA 中,通过quartus II 提供的in ...

  2. 第7讲 SPI和RAM IP核

    学习目的: (1) 熟悉SPI接口和它的读写时序: (2) 复习Verilog仿真语句中的$readmemb命令和$display命令: (3) 掌握SPI接口写时序操作的硬件语言描述流程(本例仅以写 ...

  3. SPI和RAM IP核

    学习目的: (1) 熟悉SPI接口和它的读写时序: (2) 复习Verilog仿真语句中的$readmemb命令和$display命令: (3) 掌握SPI接口写时序操作的硬件语言描述流程(本例仅以写 ...

  4. 7系列高速收发器总结 GTP IP核使用篇

    上一篇7系列收发器博文讲解了GTP IP核的基本配置,本文继续分析如何将它使用起来.生成IP核后打开example design,先看看工程中包含的文件结构. 顶层文件下包含了gtp ip核系统顶层文 ...

  5. Vivado中xilinx_BRAM IP核使用

     Vivado2017.2 中BRAM版本为 Block Memory Generator Specific Features  8.3 BRAM IP核包括有5种类型: Single-port RA ...

  6. EMAC IP 核

    在有线连接的世界里,以太网(Ethernet)无所不在.以太网具有各种速度模式.接口方式.以及灵活的配置方式.现在的以太网卡都是10/100/1000Mbps自适应网卡.以太网的物理层(PHY)通常使 ...

  7. IP核——FIFO

    一.Quartus 1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager 2.弹出创建页面,选择Creat a new custom megafunc ...

  8. modelsim 独立仿真vivado的IP核及仿真脚本

    Modelsim独立仿真vivado的IP 最近一直在做local dimming项目的FPGA硬件实现,算法的其中一步就是直方图统计,即数字图像的某一灰度级的像素数,这个直方图的源码找了半天才搞到, ...

  9. 调用altera IP核的仿真流程—下

    调用altera IP核的仿真流程—下 编译 在 WorkSpace 窗口的 counter_tst.v上点击右键,如果选择Compile selected 则编译选中的文件,Compile All是 ...

随机推荐

  1. httpd.exe你的电脑中缺失msvcr110.dll怎么办(WIN2008服务器环境装WAMP2.5出现的问题)

    httpd.exe你的电脑中缺失msvcr110.dll怎么办 去微软官方下载相应的文件 1 打开上面说的网址 Download and install, if you not have it alr ...

  2. 梯形法求解常微分方程(c++)

    #include<iostream> #include<iomanip> using namespace std; int main() { double x,y,yn,h,t ...

  3. Ubuntu 16.04与Win10双系统双硬盘安装图解

    一.先做准备工作.建议:在当前系统所在的硬盘上,留一片空的主分区安装Ubuntu系统. 2.划分多大的空间够?安装的过程中需要涉及到分区,为了以免日后重装,我的建议是如下分区:1).5G,主分区,空间 ...

  4. SQL多个逗号分开的字段值 取对应的数据名称信息

    字段值 函数实现: )) ) as begin set @strs=','+@strs+',' ) ) set @str2='' declare SyncOrderCursor cursor for ...

  5. Spring cloud微服务安全实战-7-8ELK+SpringBoot环境搭建

    采集不可聚合的离散的.日志信息的e ELK是三个系统的简称 LogStash:用来做日志的收集.过滤.格式转换 Kibana:和普罗米修斯的grafana一个意思.主要用来展示数据. 用docker来 ...

  6. iOS - 点击UIButton不变灰,button的image不变灰

    要想让uibutton点击不变灰 初始化的时候就不能 UIButton *button = [[UIButton alloc]init]; 初始化的时候酱紫,可以保证button点击时不变灰 UIBu ...

  7. docker search mysql Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    1.docker search mysql 报错 [root@localhost usr]# docker search mysqlCannot connect to the Docker daemo ...

  8. Python - Django - AJAX 实现 POST 请求

    index.html: <input type="text" id="i1">+ <input type="text" i ...

  9. 网页视频直播、微信视频直播技术解决方案:EasyNVR与EasyDSS流媒体服务器组合之区分不同场景下的直播接入需求

    背景分析 熟悉EasyNVR产品的朋友们都知道,EasyNVR不仅可以独成体系,而且还可以跟其他系列产品相配合,形成各种不同类型的解决方案,满足各种不同应用场景的实际需求.针对很多设备现场没有固定公网 ...

  10. EasyNVR网页无插件播放摄像机RTSP流是如何调取接口在Web页实现多窗口同时直播的

    背景需求 在互联网飞速发展的时代,开发者常会说的一个词就是"跨平台".自从移动端的用户需求越来越大,H5逐渐发展,跨平台似乎已经成为了软件开发不可或缺的技术.EasyNVR互联网直 ...