OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1258|回复: 0

[国产FPGA] 《ATK-DFPGL22G 之FPGA开发指南》第十八章 IP核之单端口RAM实验

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4666
金钱
4666
注册时间
2019-5-8
在线时间
1224 小时
发表于 2023-11-16 17:38:20 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2023-11-16 17:38 编辑

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

1)实验平台:正点原子 ATK-DFPGL22G开发板

2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0


4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-PGL22G.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)FPGA技术交流QQ群:435699340

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

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

1.1 RAM IP核简介
Memory IP分为“Distributed RAM”与“DRM”。

DRM   
DRM(Dedicated RAM Module)既专用RAM模块,DRM Based RAM/FIFO IP是基于DRM设计的IP,通过对DRM的级联调用实现RAM/ROM/FIFO等IP设计。这里主要说明如何用深圳市紫光同创电子有限公司的 QQ截图20231116173106.png Pango Design Suite套件(后文简称PDS)中IP Compiler工具(后文简称IPC)生成并配置此类IP。DRM Based RAM/FIFO IP的分类为:
DRMBased Dual Port RAM:基于DRM的双端口RAM
 DRMBased Simple Dual Port RAM:基于DRM的简单双端口RAM
 DRMBased Single Port RAM:基于DRM的单端口RAM
 DRMBased ROM:基于DRM的ROM
 DRMBased FIFO:基于DRM的FIFO
Logos系列FPGA的DRM有高达18K bits的存储单元并且容量可被独立配置为2个9K bits或者1个18K bits。每个DRM都能支持DP(True Dual Port,双口)RAM模式,同时也以被配置为SP(Single Port,单口)RAM模式,SDP(Simple Dual Port,简单双口)RAM模式,ROM模式,以及可选丢包重发的同步\异步FIFO模式。DRM资源还支持输入寄存器(IR)、输出寄存器(OR)以及Core Latch,这使得DRM级联使用时拥有更加出色的性能表现。DRM的总数取决于Logos系列器件类型。
Logos系列FPGA DRM的原语是各种模式的基础,其原语有两种:GTP_DRM9K和GTP_DRM18K,其支持类型如表 18.1.1所示:
表18.1.1 Logos系列FPGA DRM原语
注:1.所有原语模块在软件安装路径..\arch\vendor\pango\verilog\simulation可找出。
Distributed RAM
DistributedRAM IP是紫光同创基于FPGA片内资源设计的IP,适用于全系列FPGA产品,用户可以通过公司PDS(Pango Design Suite)套件中的IPC(IPCompiler)工具完成IP模块的配置和生成。Distributed RAM IP包含5个子IP:
Distributed ROM:分布式ROM
Distributed Single Port RAM:分布式单口RAM
Distributed Simple Dual Port RAM:分布式简单双端口RAM
Distributed Shift Register:分布式移位寄存器
Distributed FIFO:分布式FIFO

Pango PGL22G系列的Memory存储单元可以实现各种存储器的功能,PDS软件自带的IP Compiler(IP编译器)已经生成了各种存储器,例如RAM、移位寄存器、ROM以及FIFO缓冲器。
RAM与ROM这两者的区别是RAM是一种随机存取存储器,不仅仅可以存储数据,同时支持对存储的数据进行修改;而ROM是一种只读存储器,也就是说,在正常工作时只能读出数据,而不能写入数据。需要注意的是,配置成RAM或者ROM使用的资源都是FPGA内部的Distributed RAM,只不过配置成ROM时只用到了嵌入式Distributed RAM的读数据端口。本章我们主要介绍使用IPC(IP Compiler)工具生成的单口RAM实现读写的功能。
单端口RAM(DRM Based Single Port RAM)只有一个端口,读/写只能通过这一个端口来进行。单端口RAM只有一组数据总线、地址总线、时钟信号以及其他控制信号。有关DRM的更详细的介绍,请读者参阅Pango官方的手册文档“Logos系列FPGA专用RAM模块(DRM)用户指南(UG020002,Version1.1)”。
DRM BaseSingle Port RAM的单端口RAM的框图如下图所示。                              
image001.png
图 18.1.1 单端口RAM框图
各个端口的功能描述如下:
addr:写地址信号。
addr_strobe:写地址选锁存号,高电平对应地址无效,上一个地址被保持,低电平对应地址有效。
wr_data:写数据信号。
rd_data:读数据信号。
wr_en:写使能信号,高电平表示向RAM中写入数据,低电平表示从RAM中读出数据。
clk:RAM的时钟信号。
clk_en:时钟使能信号,高电平对应地址有效,低电平对应地址无效。
rst:复位信号,高有效
wr_byte_en:Byte Write使能信号,当配置“Enable Byte Write”选项勾选时有效,位宽范围1~128。高电平对应Byte值有效,低电平对应Byte值无效。
rd_oce:输出寄存使能信号,高电平对应地址有效,读数据寄存输出,低电平对应地址无效,读数据保持。

1.2 实验任务
本节实验任务是使用PDS的IP Compiler配置一个单口RAM IP并对该单口RAM进行读写操作,通过PDS与Modelsim联合仿真观察波形是否正确,最后将设计下载到ATK-DFPGL22G开发板中,并使用Inserter对其进行在线调试观察。

1.3 硬件设计
本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设,各端口信号的管脚分配如下表所示:
QQ截图20231116173401.png
表 18.3.1 IP核之单口RAM实验管脚分配

对应的FDC约束语句如下所示:
  1. define_attribute{p:sys_clk} {PAP_IO_DIRECTION} {INPUT}
  2. define_attribute{p:sys_clk} {PAP_IO_LOC} {B5}
  3. define_attribute{p:sys_clk} {PAP_IO_VCCIO} {3.3}
  4. define_attribute{p:sys_clk} {PAP_IO_STANDARD} {LVCMOS12}
  5. define_attribute{p:sys_clk} {PAP_IO_NONE} {TRUE}
  6. define_attribute{p:sys_rst_n} {PAP_IO_DIRECTION} {INPUT}
  7. define_attribute{p:sys_rst_n} {PAP_IO_LOC} {G5}
  8. define_attribute{p:sys_rst_n} {PAP_IO_VCCIO} {1.5}
  9. define_attribute{p:sys_rst_n} {PAP_IO_STANDARD} {LVCMOS12}
  10. define_attribute{p:sys_rst_n} {PAP_IO_NONE} {TRUE}
复制代码

1.4 程序设计
首先在PDS软件中创建一个名为ip_1port_ram的工程,工程创建完成后,在PDS软件的上方的菜单栏中“Tools”栏中单击“IP Compiler”按钮后弹出的“IP Compiler”窗口如图 18.4.2所示。
image003.png
图 18.4.1 点击“IPCompiler”

image005.png
图18.4.2 “IP Compiler”窗口

本实验使用的IP核路径是Module→Memory→DRM→DRM Base Single Port RAM IP核,如下图所示。
image007.png
图 18.4.3DRM Based Single Port RAM

点击上图中红框中的IP后如下图所示:
image009.png
图 18.4.4 DRM Based Single Port RAM IP详情页面

Pathname:新建IP核在工程所在路径,这里保持默认即可。
InstanceName:在这里给新建的RAM IP命名,我们这里命名为“ram_1port”。
接下来的IP框里面的内容是该IP的基础信息,例如名称、版本号与所属公司(Pango)。Part框中的信息为工程所使用的芯片的详细信息“PGL22G-6CMBG324”。
点击上图中的“Customize”按钮进入“Customize IP”窗口对RAM IP的参数进行配置,“Customize IP”窗口界面如下图所示:图中的“Add IP”弹窗点击“Yes”后进入“CustomizeIP”界面进行单口RAM的参数配置,“Customize IP”界面如图 18.4.6所示。
image011.png
图 18.4.5 “Add IP”弹窗

image013.png
图18.4.6 Customize IP界面

本实验我们主要进行如下配置:
image015.png
图 18.4.7 “DRM BasedSingle Port RAM”参数配置界面

Customize IP界面主要包括如下选项:
DRM Resource Usage:选项主要说明DRM资源使用情况。该选项下的“DRM Resource Type”是DRM资源类型,可以设置“AUTO”、“DRM9K”、“DRM18K”三种模式。三种模式可以根据你需要地址宽度与数据宽度来来设置,一般我们设置为“AUTO”模式。
image017.png
表 18.4.1 9Kb DRM模式Single Port RAM模式和ROM模式列表
image019.png
表 18.4.2 18Kb DRM模式Single Port RAM模式和ROM模式列表
Enable Byte Write:配置是否使能Byte Write功能,其含义是Byte写使能,也就是以字节为单位写入数据;Byte Write使能时,同时需要配置字节(Byte)的位宽(Byte Size)与字节个数(Byte Numbers),Byte Size可选择8或者9;Byte Numbers即配置所使用的Byte个数(注:Byte Write使能时,关闭Address Strobe功能。)举例说明:输入数据为32-bit,字节的位宽(Byte Size)设置为8bit,那么就需要4-bit Byte写使能信号,这个使能信号与输入数据各位的对应关系如下图所示。从图中不难看出,当we[3]有效时,只会将输入数据的高8-bit写入到目标地址;当we[0]有效时,只会将输入数据的低8-bit写入到目标地址。其实,也就是根据写使能来更新指定地址上原始数据的某些位,本实验不需要使能Byte Write功能即不需要勾选该配置。
QQ截图20231116173613.png
图 18.4.8 Byte写使能与输入数据的对应关系
Address and Data Width Config:选项即地址与位宽配置,Address Width配置地址位宽,Data Width配置数据位宽。地址位宽合法配置范围为1~20,数据位宽合法配置范围为1~1152,但是所占用的DRM9K或者DRM18K个数必须小于总资源个数。本实验我们配置的地址位宽为5,数据位宽为8位。
Enable clk_en Signal:配置是否使能clk_en信号(注:Clock Enable与Address Strobe功能互斥),本实验未使用保持默认不用勾选。
Enable Address Strobe Signal:配置是否使能addr_strobe信号(注:1.Byte Write使能时,关闭Address Strobe功能2.Clock Enable与Address Strobe功能互斥), 本实验未使用保持默认不用勾选。
Write Mode:配置写模式。共分为三种模式,分别是NORMAL_WRITE(正常模式)、TRANSPARENT_WRITE(写优先模式)和READ_BEFORE_WRITE(读优先模式)。正常模式指读写分开操作,不能同时进行读写,本实验选择NORMAL_WRITE模式;写优先模式指数据先写入RAM中,然后在下一个时钟输出该数据;读优先模式指数据先写入RAM中,同时输出RAM中同地址的上一次数据。
Enablerd_oce Signal:配置是否使能rd_oce(输出寄存器选项)信号,使能rd_oce信号时,默认且必须使能读端口输出寄存“Enable Output Register”,本实验不需要使能读信号,所以不勾选该选项。
Enable Output Register:输出寄存器选项。如果勾选了“Enable rd_oce Signal”信号,输出寄存器默认是选中状态,作用是打开DRM内部位于输出数据总线之后的输出流水线寄存器,虽然在一般设计中为了改善时序性能会保持此选项的默认勾选状态,但是这会使得DRM输出的数据延迟一拍,这不利于我们在调试窗口中直观清晰地观察信号;而且在本实验中我们仅仅是把DRM的数据输出总线连接到了调试的探针端口上来进行观察,除此之外数据输出总线没有别的负载,不会带来难以满足的时序路径,因此这里取消勾选。
Enable Clock Polarity Invert for OutputRegister:配置是否使能读端口输出时钟极性反向,使能读端口输出时钟极性反向时,默认且必须使能读端口输出寄存(Enable Output Register),这里不需要使能读端口输出时钟极即不需要勾选该配置。
Enable Low Power Mode:配置是否使能低功耗模式,本实验不需要配置成低功耗模式,即不勾选使能低功耗模式。
Reset Type:配置复位方式:"ASYNC"异步复位,"SYNC"同步复位,"Sync_Internally "异步复位同步释放,本实验选择异步复位。
Enable Init:配置是否使能对当前RAM进行初始化,这里不需要该配置即不用勾选使能初始化选项。
Init File:配置使能对当前RAM进行初始化,指定初始化文件路径,若不指定,则生成初始值为全“0”的初始化文件.v文件。
File Type:配置初始化文件数据格式:"BIN"二进制,"HEX"十六进制。
至此本实验所需要的单口RAM IP已配置完成,接下来点击“Customize IP”窗口左上角的“Generate”在弹出的“Question”对话框选择“OK”即可,如下图所示。
image021.png
图 18.4.9 点击“Generate”按钮
image023.png
图 18.4.10点击“OK”
点击“OK”后打印如下左图信息,至此单口RAM IP核配置成功,并生成ram_1port_tmpl.v文件。例化单口RAM IP时可以使用下图中ram_1port_tmpl.v文件红框中的代码。
image025.png
图 18.4.11 单口RAM IP创建成功
然后如下图所示,关闭“Customize IP”页面与“IP Compiler”页面。
image027.png
图 18.4.12 关闭创建IP的窗口
之后我们就可以在“Sources”窗口的“Designs”一栏中出现了该IP核“ram_1port”如下图所示。
image029.png
图 18.4.13 ram_1port IP核
接下来我们创建一个新的设计文件,命名为ram_rw.v,代码如下:
  1. 1 module ram_rw(
  2. 2      input              clk        ,  //时钟信号
  3. 3      input              rst_n      ,  //复位信号,低电平有效
  4. 4
  5. 5      output             ram_en     ,  //ram使能信号
  6. 6      output             ram_wea    ,  //ram读写选择
  7. 7      output  reg  [4:0  ram_addr   ,  //ram读写地址
  8. 8      output  reg  [7:0 ram_wr_data   //ram写数据  
  9. 9      );
  10. 10
  11. 11 //reg define
  12. 12 reg  [5:0  rw_cnt;        //读写控制计数器
  13. 13
  14. 14 //*****************************************************
  15. 15 //**                   main code
  16. 16 //*****************************************************
  17. 17
  18. 18 //控制RAM使能信号
  19. 19 assign ram_en = rst_n;
  20. 20 //rw_cnt计数范围在0~31,写入数据;32~63时,读出数据
  21. 21 assign ram_wea =(rw_cnt <= 6'd31 && ram_en == 1'b1) ? 1'b1 : 1'b0;
  22. 22
  23. 23 //读写控制计数器,计数器范围0~63
  24. 24 always @(posedge clk or negedge rst_n) begin
  25. 25     if(rst_n == 1'b0)
  26. 26         rw_cnt <= 1'b0;   
  27. 27     else if(rw_cnt == 6'd63)
  28. 28         rw_cnt <= 1'b0;
  29. 29     else
  30. 30         rw_cnt <= rw_cnt + 1'b1;
  31. 31 end  
  32. 32
  33. 33 //产生RAM写数据
  34. 34 always @(posedge clk or negedge rst_n) begin
  35. 35     if(rst_n == 1'b0)
  36. 36         ram_wr_data <= 1'b0;
  37. 37     else if(rw_cnt <= 6'd31)  //在计数器的0-31范围内,RAM写地址累加
  38. 38         ram_wr_data <= ram_wr_data + 1'b1;
  39. 39     else
  40. 40         ram_wr_data <= 1'b0 ;
  41. 41 end  
  42. 42
  43. 43 //读写地址信号 范围:0~31
  44. 44 always @(posedge clk or negedge rst_n) begin
  45. 45     if(rst_n == 1'b0)
  46. 46         ram_addr <= 1'b0;
  47. 47     else if(ram_addr ==5'd31)
  48. 48         ram_addr <= 1'b0;
  49. 49     else   
  50. 50         ram_addr <= ram_addr + 1'b1;
  51. 51 end
  52. 52
  53. 53 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      output        ena  ,
  7. 7      output        wea  ,
  8. 8      output [4 : 0 addra,
  9. 9      output [7 : 0 dina ,
  10. 10     output [7 : 0 douta
  11. 11     );
  12. 12
  13. 13 //*****************************************************
  14. 14 //**                   main code
  15. 15 //*****************************************************
  16. 16
  17. 17 ram_1port u_ram_1port (
  18. 18  .wr_data    (dina      ),    // input [7:0]
  19. 19  .addr       (addra     ),    // input [4:0]
  20. 20  .wr_en      (wea       ),    // input
  21. 21  .clk        (sys_clk   ),    // input
  22. 22  .rst        (~sys_rst_n),    //input
  23. 23  .rd_data    (douta     )     // output [7:0]
  24. 24 );
  25. 25
  26. 26 ram_rw u_ram_rw (
  27. 27     .clk            (sys_clk  ),
  28. 28     .rst_n          (sys_rst_n),
  29. 29     .ram_en         (ena      ),
  30. 30     .ram_wea        (wea      ),
  31. 31     .ram_addr       (addra    ),
  32. 32     .ram_wr_data    (dina     )
  33. 33     );
  34. 34     
  35. 35 endmodule
复制代码
程序中例化了ram_rw模块和单口ram IP核,其中ram_rw模块负责产生对ram IP核读/写所需的所有数据、地址以和读写使能信号,同时从ram IP读出的数据也连接至ram_rw模块。

接下来对单口RAM IP核进行仿真,来验证对单口RAM的读写操作是否正确。ip_1port_ram_tb仿真文件源代码如下:
  1. 1  `timescale 1ns/ 1ps
  2. 2  module ip_1port_ram_tb;
  3. 3  
  4. 4  reg  grs_n;
  5. 5  //GTP_GRS I_GTP_GRS(
  6. 6      GTP_GRSGRS_INST(
  7. 7      .GRS_N(grs_n)
  8. 8      );
  9. 9      
  10. 10     initial begin
  11. 11     grs_n =1'b0;
  12. 12     #5000 grs_n = 1'b1;
  13. 13     end
  14. 14
  15. 15     // Inputs
  16. 16     regsys_clk;
  17. 17     regsys_rst_n;
  18. 18     
  19. 19     // Outputs
  20. 20     wire ena_tb;
  21. 21     wire wea_tb;
  22. 22     wire [4:0 addra_tb;
  23. 23     wire [7:0 dina_tb;
  24. 24     wire [7:0 douta_tb;
  25. 25     // Instantiate the Unit Under Test (UUT)
  26. 26     ip_1port_ram uut(
  27. 27     .sys_clk      (sys_clk  ),
  28. 28     .sys_rst_n    (sys_rst_n),
  29. 29     .ena          (ena_tb   ),
  30. 30     .wea          (wea_tb   ),
  31. 31     .addra        (addra_tb ),
  32. 32     .dina         (dina_tb  ),
  33. 33     .douta        (douta_tb)
  34. 34     );
  35. 35     
  36. 36     initial begin
  37. 37     // Initialize Inputs
  38. 38     sys_clk =0;
  39. 39     sys_rst_n =0;
  40. 40     
  41. 41     // Wait 100 ns for global reset to finish
  42. 42     #100;
  43. 43     sys_rst_n=1;
  44. 44     // Add stimulus here
  45. 45     end
  46. 46     
  47. 47     always #10sys_clk=~sys_clk;
  48. 48     
  49. 49 endmodule
复制代码
代码第4行到第13行例化了一个GTP_GRS模块 ,GTP_GRS是一个全局复位,在FIFO或者RAMIP中使用了这个全局复位,所以使用了FIFO或者RAMIP的文件的仿真代码里面就需要对GTP_GRS模块进行例化,不然联合仿真会报错。
接下来就可以开始仿真了,仿真过程这里不再赘述,仿真波形图如下图所示。
image031.png
图18.4.14 单口RAM写操作波形图
图 18.4.14为单口RAM的写操作仿真波形图,由上图可知,地址和数据初始化赋值为0,当wea_tb信号拉高,说明此时是对ram进行写操作。wea_tb信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1,我们总共向ram中写入32个数据。
单口RAM读操作仿真波形图如下图所示:
image033.png
图 18.4.15 单口RAM读操作波形图
由上图可知,ram_wea信号拉低,说明此时是对ram进行读操作。ram_wea信号拉低之后,ram_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据ram_rd_data在延时1个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的,也就是说,我们创建的单口RAM IP核从仿真结果上来看是正确的。
接下来新建DebugCore,将ena、wea、addra、dina和dout信号添加至观察列表中,新建DebugCore核的方法这里不再赘述。

1.5 下载验证
编译工程并生成比特流.sbit文件后,此时将下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,连接电源线,并打开开发板的电源开关。
点击PDS工具栏的下载按钮,在弹出的Fabric Configuration界面中双击“Boundary Scan”,我们将生成好的sbit流文件下载到开发板中去。
单口RAM写操作在Fabric Debugger中观察的波形如下图所示:
image035.png
图 18.5.1 RAM写操作波形图
wea信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1。我们可以发现,上图中的数据变化和在PDS仿真的波形是一致的。
单口RAM读操作在Fabric Debugger中观察的波形如下图所示:
image037.png
图 18.5.2 RAM读操作波形图
wea(写使能)信号拉低之后进行读使能,addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据douta在延时1个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的。我们可以发现,上图中的数据变化同样和PDS仿真的波形是一致的。本次实验的IP核之单口RAM读写实验验证成功。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 17:24

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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