搜索
bottom↓
回复: 0

《新起点V2之FPGA开发指南》第十八章 IP核之单端口RAM实验

[复制链接]

出0入234汤圆

发表于 2021-10-8 17:19:55 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2021-10-30 10:30 编辑

1)实验平台:正点原子新起点V2FPGA开发板
2)  章节摘自【正点原子】《新起点之FPGA开发指南 V2.1》
3)购买链接:https://detail.tmall.com/item.htm?id=609758951113
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-328002-1-1.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流QQ群:712557122
1.png

2.jpg


3.png


第十八章 IP核之单端口RAM实验

       RAM的英文全称是Random Access Memory,即随机存取存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频率决定的。RAM主要用来存放程序及程序执行过程中产生的中间数据、运算结果等。本章我们将对Quartus II软件生成的RAM IP核进行读写测试,来向大家介绍Altera RAM IP核的使用方法。
       本章包括以下几个部分:
       1.1简介
       1.2实验任务
       1.3硬件设计
       1.4程序设计
       1.5下载验证

1.1简介
       Cyclone IV器件具有嵌入式存储器结构,满足了Altera Cyclone IV器件设计对片上存储器的需求。嵌入式存储器结构由一列M9K存储器模块组成,通过对这些M9K存储器模块进行配置,可以实现各种存储器的功能,例如:RAM、移位寄存器、ROM以及FIFO缓冲器。
       Quartus II软件自带的随机存储器IP核分为RAM IP核和ROM IP核。这两种IP核的区别是RAM是一种随机存取存储器,不仅仅可以存储数据,同时支持对存储的数据进行修改;而ROM是一种只读存储器,也就是说,在正常工作时只能读出数据,而不能写入数据。需要注意的是,这两种存储器使用的资源都是FPGA的内部嵌入式RAM块,只不过ROM IP核只用到了嵌入式RAM块的读数据端口。本章我们主要介绍RAM IP核的使用方法。
       Altera推出的RAM IP核分为两种类型:单端口RAM和双端口RAM。单端口RAM只有一组地址线,这组地址线控制着写数据端口和读数据端口,而双端口RAM具有两组地址线,这两组地址线分别控制着写数据端口和读数据端口。单端口RAM类型和双端口RAM类型在操作上都是一样的,我们只要学会了单端口RAM的使用,那么学习双端口RAM的读写操作也是非常容易的。下面我们以单端口RAM IP核为例进行讲解。
       下图为单端口RAM的端口框图。
第十八章 IP核之单端口RAM实验813.png

图 18.1.1 单端口RAM端口框图

       单端口RAM的端口描述如下:
       data:RAM写数据端口;
       address:RAM读写地址端口,对于单口RAM来说,读地址和写地址共用同一组地址;
       wren:写使能信号,高电平有效;
       byteena:字节使能控制,该功能屏蔽了输入数据,这样仅写入数据中指定字节,未被写入的字节保留之前写入的值。当写入数据的位宽为16位、18位、32位和36位时,M9K模块将支持字节使能,wren信号以及字节byteena信号一起控制RAM模块的写操作。byteena信号在RAM IP核创建过程中是可选的,可选择是否使用字节使能控制功能。
        addressstall:地址时钟使能控制,当addressstall信号为高电平时,有效地址时钟使能就会保持之前的地址。              addressstall信号在RAM IP核创建过程中是可选的,可选择是否使用地址使能控制功能。
        clockena:时钟使能控制,高电平有效;
        rden:读使能信号,高电平有效;
        aclr:异步复位信号,高电平有效;
        q:从RAM中读出的数据;
        inclock、outclock:单端口RAM支持输入与输出时钟模式和单时钟模式。在输入与输出时钟模式下,输入时钟控制存储器模块的所有输入寄存器,其中包括数据、地址、byteena、wren以及rden寄存器;输出时钟控制数据输出寄存器。在单时钟模式下,没有inclock信号与outclock信号,只有一个clock信号,可以通过单时钟以及时钟使能来控制M9K存储器模块中的所有寄存器。
1.2实验任务
       本节实验任务是使用Altera RAM IP核生成一个单端口的RAM,然后对RAM进行读写操作,并通过Modelsim软件进行仿真及SignalTap软件进行在线调试。
1.3硬件设计
       本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设。
       本实验中,各端口信号的管脚分配如下表所示。
1.png

表 18.3.1 IP核之RAM实验管脚分配

       因为引脚数极少这里就不再给出TCL管脚约束语句了。
1.4程序设计
       首先创建一个名为ip_1port_ram的工程,在这里我们就不再给出Quartus II软件创建工程的详细过程,如果大家对Quartus II软件的创建过程还不熟悉的话,可以参考“第四章 Quartus II软件的安装和使用”章节中的Quartus II软件的使用部分。新建后的工程如下图所示:
第十八章 IP核之单端口RAM实验1991.png

图 18.4.1工程新建完成页面

        创建好了工程以后,接下来我们创建RAM IP核。我们在Quartus II软件的菜单栏中找到【Tools】→【MegaWizard Plug-In Manager】按钮并点击打开,Tool工具栏打开页面及打开后弹出的页面如图 18.4.2和图 18.4.3所示。
第十八章 IP核之单端口RAM实验2267.png

图 18.4.2 工具栏打开IP核页面

第十八章 IP核之单端口RAM实验2332.png

图 18.4.3 创建IP核向导页面

       在该页面中,可以看到有三个选项,第一个是创建一个新的IP核,第二个是编辑一个已经创建好的IP核,第三个是复制一个已经创建好的IP核。因为我们这里是首次创建IP核,因此直接选择默认的第一个选项,然后点击【Next>】,进入如图 18.4.4所示页面。
第十八章 IP核之单端口RAM实验2562.png

图 18.4.4 选择ALTPLL IP核页面

       在该页面中,我们在Memory Compiler下找到RAM:1-PORT,单击选中它,然后我们需要为RAM IP核选择保存的路径及名称,首先大家先在工程所在路径par文件夹下创建一个文件夹ipcore,用于存放工程中用到的IP核(如果之前没有创建ipcore文件夹的话),然后在“What name do you want for the output file”一栏中输入IP存放的路径及名称,这里我们命名为ram_1port并且选择创建的IP核代码为Verilog HDL。完成这些设置以后,我们点击【Next>】,进入如图 18.4.5所示页面。
第十八章 IP核之单端口RAM实验2950.png

图 18.4.5 RAM IP核参数配置页面

“How wide should the ‘q’ output bus be?”:用于指定输出数据端口的位宽,我们这里保持默认,选择8bit;
“How many 8-bit words of memory?”:用于指定存储器的容量大小,我们这里选择存储容量为32words;
“What should the memory block type be?”:用于指定实现存储器使用的存储块类型,具体可选值与使用的 FPGA 芯片型号有关,一般选择默认AUTO就可以了;
“What clocking method would you like to use?”:用于指定使用的时钟模式,可选择单时钟和双时钟,一般对于单口ram选择单时钟就可以了。
然后我们直接点击【Next>】,进入如图 18.4.6所示页面。
第十八章 IP核之单端口RAM实验3417.png

图 18.4.6 寄存输出、读使能等信号设置页面

在该页面中,我们取消选中q输出端口,否则读出的数据会多延时一个时钟周期;aclr信号用于复位RAM中的数据,由于本次实验不需要对RAM中的数据清零,所以这里没有选中aclr信号;然后我们添加了一个rden读使能信号,读使能是高电平有效的,用于控制数据的输出。该信号配置完成后,我们就可以点击【Next】,进入如图 18.4.7所示页面。
第十八章 IP核之单端口RAM实验3697.png

图 18.4.7 写入数据时读数据输出选项页面

该页面指定在对RAM进行写操作时,读数据输出选择,可选项包括新数据(New Data)和不关心(Don’t Care),默认选项为 New Data,也即在写数据的同一个时钟周期的上升沿新数据可用;如果选择 Don’t Care,存储器输出不确定。我们保持默认设置即可,直接点击【Next】,进入如图 18.4.8所示页面。
第十八章 IP核之单端口RAM实验3970.png

图 18.4.8 RAM初始化页面

从该页面中,我们可以看出,该页面就是对RAM初始化页面。需要注意的是,后面我们还会学习ROM IP核的创建过程,这里和ROM IP核不同的是,ROM IP核不能设置为 No,只能设置为Yes,而我们的 RAM IP 核,我们可以设置为空,也可以进行初始化。在这里我们保持默认设置即可,直接点击【Next】,进入如图 18.4.9所示页面。
第十八章 IP核之单端口RAM实验4244.png

图 18.4.9 EDA的配置页面

从该页面中,我们可以看出,如果我们想要仿真RAM IP核,那么我们需要添加 altera_mf仿真库。如果我们想要将此RAM IP核用在其他的EDA工具上,我们可以通过选择Generate netlist这个选项来生成IP_syn.v文件,用于其他的EDA工具中。这里需要注意的是,并不是所有的第三方 EDA工具都支持。在这里直接点击【Next】,进入如图 18.4.10所示页面。
第十八章 IP核之单端口RAM实验4540.png

图 18.4.10 Summary 的配置页面

然后我们点击【Finish】完成整个IP核的创建。接下来Quartus II软件会在ipcore文件夹下创建RAM IP核生成的文件,然后询问我们是否添加至工程,点击“YES”按钮将生成的IP核添加至工程,如图 18.4.11所示页面。
第十八章 IP核之单端口RAM实验4769.png

图 18.4.11 IP核添加至工程确认界面

接下来返回到工程界面,在File界面里,我们可以看到生成的ram_1port.qip和ram_1port.v已经添加到工程中。qip是Quartus IP的缩写,我们打开qip的文件可以看到如图 18.4.12所示的脚本代码。
第十八章 IP核之单端口RAM实验4992.png

图 18.4.12 ram_1port.qip文件内容

上图中红色框标注的意思是把ram_1port.v文件添加到工程,如果大家在添加IP核后工程里面只有ram_1port.qip文件,而没有ram_1port.v的话也没有关系,工程中只添加ram_1port.qip文件也是可以的。
添加完RAM IP核后,可以在IP核所在的路径下打开ram_1port.v代码,如图 18.4.13所示。
第十八章 IP核之单端口RAM实验5275.png

图 18.4.13 RAM IP核添加至工程界面

上图中我们可以看到,ram_1port模块的端口分别为:address(ram读写地址)、clock(ram读写驱动时钟)、data(ram写数据)、rden(ram读使能信号)、wren(ram写使能信号)和q(ram读出的数据),其中读地址和写地址都是共用address地址线的。当我们需要写入数据时,把wren信号拉高的同时,给出地址(address)和写数据(data),数据就会按照指定的地址写入对应的存储单元;当我们需要读数据时,把rden信号拉高,给出地址(address),q(ram读出的数据)就会根据指定的地址输出对应存储单元的数据。
至此,RAM IP核的创建已经全部完成,如果需要修改IP核的话,点击在Quartus II软件的菜单栏中找到【Tools】→【MegaWizard Plug-In Manager】按钮并点击打开,图 18.4.14为打开后的页面。
第十八章 IP核之单端口RAM实验5780.png

图 18.4.14 修改IP核页面

和我们第一次创建IP核不同的是,这一次我们选择第二个选项,修改已经存在的IP核,然后点击【Next>】,进入选择IP核路径页面,双击ipcore文件夹,进入如图 18.4.15所示页面。然后双击ram_1port.v文件或者选中ram_1port.v文件,点击【Next>】开始重新配置RAM IP核。
第十八章 IP核之单端口RAM实验6036.png

图 18.4.15 选择需要修改的IP核路径页面

接下来我们设计一个verilog文件对ram进行读写测试,文件名为ram_rw.v,编写的verilog代码如下。
  1. 1   module ram_rw(
  2. 2       input               clk        ,  //时钟信号
  3. 3       input               rst_n      ,  //复位信号,低电平有效
  4. 4      
  5. 5       output              ram_wr_en  ,  //ram写使能
  6. 6       output              ram_rd_en  ,  //ram读使能
  7. 7       output  reg  [4:0]  ram_addr   ,  //ram读写地址
  8. 8       output  reg  [7:0]  ram_wr_data,  //ram写数据
  9. 9      
  10. 10      input        [7:0]  ram_rd_data   //ram读数据        
  11. 11      );
  12. 12  
  13. 13  //reg define
  14. 14  reg    [5:0]  rw_cnt ;                //读写控制计数器
  15. 15  
  16. 16  //*****************************************************
  17. 17  //**                    main code
  18. 18  //*****************************************************
  19. 19  
  20. 20  //rw_cnt计数范围在0~31,ram_wr_en为高电平;32~63时,ram_wr_en为低电平
  21. 21  assign  ram_wr_en = ((rw_cnt >= 6'd0) && (rw_cnt <= 6'd31) && rst_n)  ?  1'b1  :  1'b0;
  22. 22  //rw_cnt计数范围在32~63,ram_rd_en为高电平;0~31时,ram_rd_en为低电平
  23. 23  assign  ram_rd_en = ((rw_cnt >= 6'd32) && (rw_cnt <= 6'd63))  ?  1'b1  :  1'b0;
  24. 24  
  25. 25  //读写控制计数器,计数器范围0~63
  26. 26  always @(posedge clk or negedge rst_n) begin
  27. 27      if(rst_n == 1'b0)
  28. 28          rw_cnt <= 6'd0;   
  29. 29      else if(rw_cnt == 6'd63)
  30. 30          rw_cnt <= 6'd0;
  31. 31      else
  32. 32          rw_cnt <= rw_cnt + 6'd1;   
  33. 33  end   
  34. 34  
  35. 35  //读写控制器计数范围:0~31 产生ram写使能信号和写数据信号
  36. 36  always @(posedge clk or negedge rst_n) begin
  37. 37      if(rst_n == 1'b0)
  38. 38          ram_wr_data <= 8'd0;  
  39. 39      else if(rw_cnt >= 6'd0 && rw_cnt <= 6'd31)
  40. 40          ram_wr_data <= ram_wr_data + 8'd1;
  41. 41      else
  42. 42          ram_wr_data <= 8'd0;         
  43. 43  end   
  44. 44  
  45. 45  //读写地址信号 范围:0~31
  46. 46  always @(posedge clk or negedge rst_n) begin
  47. 47      if(rst_n == 1'b0)
  48. 48          ram_addr <= 5'd0;
  49. 49      else if(ram_addr == 5'd31)
  50. 50          ram_addr <= 5'd0;
  51. 51      else
  52. 52          ram_addr <= ram_addr + 1'b1;
  53. 53  end
  54. 54  
  55. 55  endmodule
复制代码

模块中定义了一个读写控制计数器(rw_cnt),当计数范围在0~31之间时,向ram中写入数据;当计数范围在32~63之间时,从ram中读出数据。
接下来我们设计一个verilog文件来实例化创建的RAM IP核以及ram_rw模块,文件名为ip_1port_ram.v,编写的verilog代码如下。
  1. 1   module ip_1port_ram (
  2. 2       input               sys_clk        ,  //系统时钟
  3. 3       input               sys_rst_n         //系统复位,低电平有效
  4. 4       );
  5. 5   
  6. 6   //wire define
  7. 7   wire             ram_wr_en   ;  //ram写使能  
  8. 8   wire             ram_rd_en   ;  //ram读使能  
  9. 9   wire    [4:0]    ram_addr    ;  //ram读写地址
  10. 10  wire    [7:0]    ram_wr_data ;  //ram写数据  
  11. 11  
  12. 12  wire    [7:0]    ram_rd_data ;  //ram读数据  
  13. 13  
  14. 14  //*****************************************************
  15. 15  //**                    main code
  16. 16  //*****************************************************
  17. 17  
  18. 18  //ram读写模块
  19. 19  ram_rw  u_ram_rw(
  20. 20      .clk            (sys_clk),
  21. 21      .rst_n          (sys_rst_n),
  22. 22  
  23. 23      .ram_wr_en      (ram_wr_en  ),
  24. 24      .ram_rd_en      (ram_rd_en  ),
  25. 25      .ram_addr       (ram_addr   ),
  26. 26      .ram_wr_data    (ram_wr_data),
  27. 27  
  28. 28      .ram_rd_data    (ram_rd_data)
  29. 29      );
  30. 30  
  31. 31  //ram ip核
  32. 32  ram_1port  u_ram_1port(
  33. 33      .address      (ram_addr),
  34. 34      .clock        (sys_clk),
  35. 35      .data         (ram_wr_data),
  36. 36      .rden         (ram_rd_en),
  37. 37      .wren         (ram_wr_en),
  38. 38      .q            (ram_rd_data)
  39. 39      );
  40. 40  
  41. 41  endmodule
复制代码

程序中例化了ram_rw模块和ram_1port模块,ram_rw模块输出的写使能信号(ram_wr_en),写数据(ram_wr_data)、读使能信号(ram_rd_en)与读写地址(ram_addr)连接至ram_1port模块的输入端口;ram_1port模块输出的q(数据输出端口)连接至ram_rw模块的输入端口(ram_rd_data)。
ip_1port_ram模块添加至工程后,如果工程名字和ip_1port_ram模块名字不一致的话,必须先将ip_1port_ram模块设置为顶层模块,设置方法是右键选择ip_1port_ram.v文件,点击Set as Top-Level Entity。
第十八章 IP核之单端口RAM实验9619.png

图 18.4.16 ip_1port_ram设置为顶层文件

接下来点击分析和综合图标编译工程。
第十八章 IP核之单端口RAM实验9712.png

图 18.4.17 开始编译工程界面

工程编译成功后,打开Pin Planner配置FPGA的管脚,管脚按照本章硬件设计中的列表来分配,分配完成后重新编译工程。
接下来我们对RAM IP核进行仿真,来验证对RAM的读写操作是否正确。首先在Modelsim软件中创建一个名为tb_ip_1port_ram的工程,在这里我们就不再给出软件创建工程的详细过程,如果大家对Modelsim软件的创建过程还不熟悉的话,可以参考“第五章 Modelsim软件的安装和使用”章节中的Modelsim的使用部分。
tb_ip_1port_ram仿真文件源代码如下:
  1. 1  `timescale  1ns/1ns   //仿真的单位/仿真的精度
  2. 2  
  3. 3  module ip_1port_ram_tb();
  4. 4  
  5. 5  parameter T = 20;
  6. 6  
  7. 7  reg          sys_clk;
  8. 8  reg          sys_rst_n;   
  9. 9  
  10. 10 initial begin
  11. 11     sys_clk = 1'b0;
  12. 12     sys_rst_n = 1'b0;
  13. 13     #(T+1)
  14. 14     sys_rst_n = 1'b1;
  15. 15 end
  16. 16
  17. 17 always #(T/2) sys_clk = ~sys_clk;
  18. 18
  19. 19 ip_1port_ram u_ip_1port_ram(
  20. 20     .sys_clk            (sys_clk  ),
  21. 21     .sys_rst_n          (sys_rst_n)
  22. 22     );
  23. 23     
  24. 24 endmodule
复制代码

需要注意的是,对IP核的仿真需要在Modeslim工程中添加altera_mf文件仿真库,仿真库的路径在Quartus II软件的安装路径下,路径为:D:\altera\13.1\quartus\eda\sim_lib\altera_mf.v(如果大家把Quartus安装在其它磁盘,可在对应的安装路径下找到仿真库文件)。建议大家把alerta_mf文件拷贝到工程的sim\tb文件夹下,方便添加至工程。工程创建完成后,把ip_1port_ram_tb.v文件、ip_1port_ram.v文件、ram_rw.v文件、ram_1port.v文件和altera_mf文件添加至工程,然后编译各个文件(注意altera_mf文件编译时间较长),编译后的工程界面如图 18.4.18所示:
第十八章 IP核之单端口RAM实验10875.png

图 18.4.18 Modelsim工程界面

接下来就可以开始仿真了,仿真过程这里不再赘述,下图为Modelsim仿真的波形图。
第十八章 IP核之单端口RAM实验10985.png

图 18.4.19 Modelsim写数据仿真波形

由上图可以看到,ram_wr_en信号拉高,ram_rd_en信号拉低,说明此时是对ram进行写操作。ram_wr_en信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1,我们总共向ram中写入32个数据。
下图为读ram数据时Modelsim仿真的波形图。
第十八章 IP核之单端口RAM实验11223.png

图 18.4.20 Modelsim读数据仿真波形

由上图可以看到,ram_rd_en信号拉高,ram_wr_en信号拉低,说明此时是对ram进行读操作。ram_rd_en(读使能)信号拉高之后,ram_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据ram_rd_data在延时一个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的,也就是说,我们创建的RAM IP核从仿真结果上来看是正确的。
1.5下载验证
首先将下载器一端连接电脑,另一端与开发板上的JTAG下载口相连,最后连接电源线并打开电源开关。
接下来我们使用SignalTap II软件对RAM IP核进行调试,首先我们在Quartus II软件中创建一个SignalTap II调试文件,我们将ram_wr_en、ram_rd_en、ram_addr、ram_wr_data和ram_rd_data这五个信号添加至SignalTap II调试文件中,下图为SignalTap软件采集到的波形图。
第十八章 IP核之单端口RAM实验11726.png

图 18.5.1写ram数据SignalTap波形图

ram_wr_en信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1。我们可以发现,上图中的数据变化和Modelsim仿真软件仿真的波形是一致的。
下图为读ram数据时SignalTap采集的波形图。
第十八章 IP核之单端口RAM实验11936.png

图 18.5.2读ram数据SignalTap波形图

ram_rd_en(读使能)信号拉高之后,ram_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据ram_rd_data在延时一个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的。我们可以发现,上图中的数据变化同样和Modelsim仿真软件仿真的波形是一致的。本次实验的IP核之RAM读写实验验证成功。


阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 23:37

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表