正点原子 发表于 2023-1-30 10:02:05

《ATK-DFPGL22G之FPGA开发指南_V1.0》第十九章 IP核之双端口RAM实验

本帖最后由 正点原子 于 2023-1-30 10:01 编辑

1)实验平台:正点原子紫光PGL22G开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340253-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:435699340





第十九章 IP核之双端口RAM实验
在“IP核之单端口RAM实验”中,我们成功实现了对单端口RAM IP核的读写操作,本章我们将通
过Quartus II软件生成一个双端口的RAM IP核,并对其进行读写操作。
本章包括以下几个部分:
19.1简介
19.2实验任务
19.3硬件设计
19.4程序设计
19.5下载验证


19.1简介
我们知道,RAM IP核分为单端口RAM和双端口RAM,即表示RAM IP核有几个读写端口。对于单端口RAM来说,由于读写共用一对地址线,所以没有办法同时读写不同地址的数据;而对于双端口RAM来说,由于读写地址线是分开的,所以可以同时读写不同地址的数据。
双端口RAM又分为简单双端口RAM和真双端口RAM,顾名思义,简单双端口RAM虽然有两个端口,但是一个端口只能用来写,另一个端口只能用来读,所以简单双端口RAM也称为伪双端口RAM。而
真双端口RAM是指两个端口都可以用来写或者读,可以理解成具有两个独立的单端口的RAM,一般用于
需要多路写入和读出的情况,而不用例化两个单端口的 RAM,在使用上更为方便。
    在实际开发应用中,对于单端口RAM、伪双端口RAM和真双端口RAM的选择,需要根据项目需求来选择合适的RAM。对于不需要同时读写RAM的情况,可以选择单端口RAM;对于需要同时读写RAM,但是只需要一路数据写入,一路数据读出的情况,可以选择简单双端口RAM;而对于需要同时读写RAM,
有又两个写入或者读出的情况,可以选择真双端口RAM。双端口RAM一般对于异步数据的缓存使用较多,
因此本章使用的是简单双端口RAM IP。
下图为简单双单端口RAM的端口框图。
图 19.1.1 简单双单端口RAM的端口框图
简单双单端口RAM的端口描述如下:
wr_data:写数据信号,位宽范围1~1152;
wr_addr:写地址信号,位宽范围5~20;
wr_en:写使能信号,为高时进行写操作,为低时进行读操作;
wr_clk:写时钟信号;
wr_clk_en:写时钟使能信号,为高时对应地址有效,为低时对应地址无效;
wr_rst:写端口复位信号,高有效;
wr_byte_en:Byte Write使能信号,当配置“Enable Byte Write”选项勾选时有效,位宽范围1~128。为高时对应Byte值有效,为低时对应Byte值无效;
wr_addr_strobe:写地址锁存信号,为高时对应地址无效,上一个地址被保持,为低时对应地址有效;
rd_data:读数据信号,位宽范围1~1152;
rd_addr:读地址信号,位宽范围5~20;
rd_clk:读时钟信号;
rd_clk_en:读时钟使能信号,为高是对应地址有效,为低时对应地址无效;
rd_rst:读端口复位信号,高有效;
rd_oce:读数据输出寄存使能信号,为高时对应地址有效,读数据寄存输出,为低时对应地址无效,读数据保持;
rd_addr_strobe:读地址锁存信号,为高时对应地址无效,上一个地址被保持,为低时对应地址有效;
19.2实验任务
本节实验任务是使用PDS的IP Compiler配置一个简单双端口RAM IP并对该简单双端口RAM进行读写操作,通过PDS与Modelsim联合仿真观察波形是否正确,最后将设计下载到ATK-DFPGL22G开发板中,并使用Inserter对其进行在线调试观察。
19.3硬件设计
本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设,各端口信号的管脚分配如下表所示:
表 19.3.1IP核之简单双端口RAM实验管脚分配
对应的FDC约束语句如下所示:
define_attribute {p:sys_clk} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:sys_clk} {PAP_IO_LOC} {B5}
define_attribute {p:sys_clk} {PAP_IO_VCCIO} {3.3}
define_attribute {p:sys_clk} {PAP_IO_STANDARD} {LVCMOS12}
define_attribute {p:sys_clk} {PAP_IO_NONE} {TRUE}
define_attribute {p:sys_rst_n} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:sys_rst_n} {PAP_IO_LOC} {G5}
define_attribute {p:sys_rst_n} {PAP_IO_VCCIO} {1.5}
define_attribute {p:sys_rst_n} {PAP_IO_STANDARD} {LVCMOS12}
define_attribute {p:sys_rst_n} {PAP_IO_NONE} {TRUE}
19.4程序设计
根据实验任务要求和模块化设计的思想,我们需要如下5个模块:简单双端口RAM模块、写RAM模块、读RAM模块、PLL IP核模块以及顶层模块,顶层模块例化其余模块实现前四个模块的数据交互。由于双端口RAM多用于跨时钟域信号的处理,所以本实验我们使用两个不同的时钟分别作为RAM的写时钟和读时钟,这两个时钟由PLL IP核生成,输出的时钟分别是50Mhz和25Mhz。系统的功能框图如下所示:
图 19.4.1 核之双端口RAM IP核系统框图
由上图可知,PLL IP核输出两个时钟,分别作为写RAM模块和读RAM模块的时钟;写RAM模块负责向RAM中写入数据,而读RAM模块负责从RAM中读出数据。和“IP核之单端口RAM实验”不同的是,本次试验只在上电后写入一次,然后不断地从RAM中读出数据。
首先在PDS软件中创建一个名为ip_2port_ram的工程,工程创建完成后,在PDS软件的上方的菜单栏中“Tools”栏中单击“IP Compiler”按钮后弹出的“IP Compiler”窗口如图 19.4.3所示。
图 19.4.2 点击“IP Compiler”
图 19.4.3 “IP Compiler”窗口
本实验使用的IP核路径是Module→Memory→DRM→DRM Base Simple Dual Port RAM IP核,如下图所示。
图 19.4.4 DRM Base Simple Dual Port RAM
点击上图中红框中的IP后如下图所示:
图 19.4.5 DRM Base Simple Dual Port RAM详情页面
Pathname:新建IP核在工程所在路径,这里保持默认即可。
Instance Name:在这里给新建的RAM IP命名,我们这里命名为“ram_2port”。
接下来的IP框里面的内容是该IP的基础信息,例如名称、版本号与所属公司(Pango)。Part框中的信息为工程所使用的芯片的详细信息“PGL22G-6CMBG324”。
点击上图中的“Customize”按钮进入“Customize IP”窗口对RAM IP的参数进行配置,“Customize IP”窗口界面如下图所示:图中的“Add IP”弹窗点击“Yes”后进入“Customize IP”界面进行单口RAM的参数配置,“Customize IP”界面如图 19.4.7所示。
图 19.4.6 “Add IP”弹窗
图 19.4.7 "Customize IP"界面
本实验我们主要进行如下配置:
图 19.4.8 DRM Base Simple Dual Port RAM参数配置界面
Customize IP界面主要包括如下选项:
DRM Resource Usage:选项主要说明DRM资源使用情况。该选项下的“DRM Resource Type”是
DRM资源类型,可以设置“AUTO”、“DRM9K”、“DRM18K”三种模式。三种模式可以根据你需要地址宽度与数据宽度来来设置,一般我们设置为“AUTO”模式。表 19.4.1 9Kb DRM模式下Simple Dual Port RAM模式允许的位宽组合
表 19.4.2 18Kb DRM模式下Simple Dual Port RAM模式允许的位宽组合
Write/Read Port Use Same Data Widt:配置读写端口是否使用混合位宽模式(注:混合位宽时,关闭Address Strobe功能),本实验勾选该选项,使用混合位宽模式,只需要配置写入端口的地址位宽与数据位宽,读端口的地址位宽与数据位宽会与写入端口保持一致。
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有效时,只会将输入数据的高8-bit写入到目标地址;当we有效时,只会将输入数据的低8-bit写入到目标地址。其实,也就是根据写使能来更新指定地址上原始数据的某些位,本实验不需要使能Byte Write功能即不需要勾选该配置。
图 19.4.9 Byte写使能与输入数据的对应关系
Write Port:对写入端口进行配置。Address Width配置地址位宽,Data Width配置数据位宽。地址位宽合法配置范围为5~20,数据位宽合法配置范围为1~1152,但是所占用的DRM9K或者DRM18K个数必须小于总资源个数。本实验我们配置的地址位宽为5,数据位宽为8位。
Enable wr_clk_en Signal:配置是否使能写端口的wr_clk_en信号(注:Clock Enabel与Address Strobe互斥),本实验未使用保持默认不用勾选。
Enable wr_addr_strobe Signal:配置是否使能写端口的wr_addr_strobe信号(注:1.Byte Write 使能时,关闭Address Strobe功能2.混合位宽时,关闭Address Strobe功能3.Clock Enabel与Address Strobe互斥),本实验配置使用了混合位宽模式所以关闭Address Strobe功能,Enable wr_addr_strobe Signal选项保持默认不用勾选。
Read Port:对读出端口进行配置。Address Width配置地址位宽,Data Width配置数据位宽。地址位宽合法配置范围为5~20,数据位宽合法配置范围为1~1152,但是所占用的DRM9K或者DRM18K个数必须小于总资源个数。本实验我们配置使用了混合位宽模式,所以读端口的地址位宽与数据位宽会直接与写端口的配置保持一致。
Enable rd_clk_en Signal:配置是否使能读端口的rd_clk_en信号(注:Clock Enabel与Address Strobe互斥),本实验未使用保持默认不用勾选。
Enable rd_addr_strobe Signal:配置是否使能读端口的rd_addr_strobe信号(注:1.Byte Write 使能时,关闭Address Strobe功能2.混合位宽时,关闭Address Strobe功能3.Clock Enabel与Address Strobe互斥),本实验配置使用了混合位宽模式所以关闭Address Strobe功能,Enable rd_addr_strobe Signal选项保持默认不用勾选。
Enable rd_oce Signal:配置是否使能rd_oce(输出寄存器选项)信号,使能rd_oce信号时,默认且必须使能读端口输出寄存“Enable Output Register”,本实验不需要使能读信号,所以不勾选该选项。
Enable Output Register:输出寄存器选项。如果勾选了“Enable rd_oce Signal”信号,输出寄存器默认是选中状态,作用是打开DRM内部位于输出数据总线之后的输出流水线寄存器,虽然在一般设计中为了改善时序性能会保持此选项的默认勾选状态,但是这会使得BRM输出的数据延迟一拍,这不利于我们在调试窗口中直观清晰地观察信号;而且在本实验中我们仅仅是把BRM的数据输出总线连接到了调试的探针端口上来进行观察,除此之外数据输出总线没有别的负载,不会带来难以满足的时序路径,因此这里取消勾选。
Enable Clock Polarity Invert for Output Register:配置是否使能读端口输出时钟极性反向,使能读端口输出时钟极性反向时,默认且必须使能读端口输出寄存(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”即可,如下图所示。
图 19.4.10 点击“Generate”按钮
点击“OK”后打印如下左图信息,至此简单双单口RAM IP核配置成功,并生成ram_2port_tmpl.v文件。例化简单双单口RAM IP时可以使用下图中ram_2port_tmpl.v文件红框中的代码。
图 19.4.11简单双端口RAM IP创建成功
然后如下图所示,关闭“Customize IP”页面与“IP Compiler”页面。
图 19.4.12 关闭创建IP的窗口
之后我们就可以在“Sources”窗口的“Designs”一栏中出现了该IP核“pll_clk”如下图所示。
图 19.4.13 "ram_2port"IP
除此之外,我们再创建一个PLL IP核(命名为pll_clk),共输出两路时钟,时钟频率分别是50Mhz和25Mhz,如下图所示,创建过程此处不再赘述。
图 19.4.14 PLL IP核
接下来我们设计一个verilog文件对ram进行写入数据,文件名为ram_wr.v,编写的verilog代码如下。
1module ram_wr(
2      input            clk,         //时钟信号
3      input            rst_n,         //复位信号,低电平有效
4                                    
5      //RAM写端口操作               
6      output         ram_wr_en,   //ram写使能
7      output reg ram_wr_addr,   //ram写地址      
8      output reg ram_wr_data    //ram写数据
9);
10
11 //reg define
12 regwr_cnt;               //写计数器
13
14 //*****************************************************
15 //**                  main code
16 //*****************************************************
17
18 //wr_cnt计数范围在0~31,ram_wr_en为高电平
19 assign ram_wr_en = ((wr_cnt>=6'd0) && (wr_cnt<=6'd31) && rst_n) ? 1'b1 : 1'b0;
20
21 //写计数器,计数器范围0~63
22 always @(posedge clk or negedge rst_n) begin
23   if(!rst_n)
24         wr_cnt <= 6'd0;
25   else if(wr_cnt == 6'd63)
26         wr_cnt <= wr_cnt;
27   else   
28         wr_cnt <= wr_cnt + 1'b1;
29 end
30
31 //写计数器范围:0~31,产生ram写数据信号
32 always @(posedge clk or negedge rst_n) begin
33   if(!rst_n)
34         ram_wr_data <= 8'd0;
35   else if(wr_cnt >= 6'd0 && wr_cnt <= 6'd31)
36         ram_wr_data <= ram_wr_data + 1'b1;
37   else
38         ram_wr_data <= 8'd0;
39 end      
40
41 //写地址信号 范围:0~31      
42 always @(posedge clk or negedge rst_n) begin
43   if(!rst_n)      
44         ram_wr_addr <= 5'd0;
45   else if(wr_cnt >= 6'd0 && wr_cnt <= 6'd31)
46         ram_wr_addr <= ram_wr_addr + 1'b1;
47   else
48         ram_wr_addr <= 5'd0;
49 end      
50
51 endmodule
模块中定义了一个写计数器(wr_cnt),从0累加至63,此后一直保持在数值63。当计数范围在0~31之间时,向ram中写入数据,而其它计数值时停止写入。实现的功能是向RAM的地址0写入数据0,地址1写入数据1,一直到地址31写入数据31,只在上电后写入一次。
接下来我们设计一个verilog文件来从RAM中读出数据,文件名为ram_rd.v,编写的verilog代码如下。
1module ram_rd(
2      input            clk,         //时钟信号
3      input            rst_n,         //复位信号,低电平有效
4                                    
5      //RAM读端口操作               
6      output         ram_rd_en,   //ram读使能
7      output reg ram_rd_addr,   //ram读地址      
8      input       ram_rd_data    //ram读数据
9);
10
11 regrd_cnt;               //读控制计数器
12
13 //*****************************************************
14 //**                  main code
15 //*****************************************************
16
17 //rd_cnt计数范围在0~31,ram_rd_en为高电平
18 assign ram_rd_en = ((rd_cnt>=6'd0) && (rd_cnt<=6'd31) && rst_n) ? 1'b1 : 1'b0;
19
20 //读控制计数器,计数器范围0~63
21 always @(posedge clk or negedge rst_n) begin
22   if(!rst_n)
23         rd_cnt <= 6'd0;
24   else if(rd_cnt == 6'd63)
25         rd_cnt <= 6'd0;
26   else   
27         rd_cnt <= rd_cnt + 1'b1;
28 end      
29
30 //写地址信号 范围:0~31      
31 always @(posedge clk or negedge rst_n) begin
32   if(!rst_n)      
33         ram_rd_addr <= 5'd0;
34   else if(rd_cnt >= 6'd0 && rd_cnt <= 6'd31)
35         ram_rd_addr <= ram_rd_addr + 1'b1;
36   else
37         ram_rd_addr <= 5'd0;
38 end      
39
40 endmodule
模块中定义了一个读计数器(rd_cnt),循环的从0累加至63。当计数范围在0~31之间时,从ram中读出数据,而其它计数值时停止读数据。
接下来我们设计一个verilog文件来例化创建的PLL IP核、RAM IP 核、RAM写模块和RAM读模块,文件名为ip_2port_ram.v,编写的verilog代码如下。
1module ip_2port_ram(
2      input               sys_clk      ,//系统时钟
3      input               sys_rst_n      ,//系统复位,低电平有效
4      
5      output            clk_50m      ,
6      output            clk_25m      ,
7      output            locked         ,
8      output            ram_wr_en      ,
9      output       ram_wr_addr    ,
10   output       ram_wr_data    ,
11   output            ram_rd_en      ,
12   output       ram_rd_addr    ,
13   output       ram_rd_data
14   );
15   
16 //*****************************************************
17 //**                  main code
18 //*****************************************************
19 //锁相环模块
20 pll_clk u_pll_clk(
21   .pll_rst   (~sys_rst_n),   // input
22   .clkin1      (sys_clk),      // input
23   .pll_lock    (locked),       // output
24   .clkout0   (clk_50m),      // output
25   .clkout1   (clk_25m)       // output
26   );
27
28 //RAM写模块
29 ram_wr u_ram_wr(
30   .clk         (clk_50m),
31   .rst_n         (sys_rst_n),
32      
33   .ram_wr_en   (ram_wr_en), //ram写使能
34   .ram_wr_addr   (ram_wr_addr),
35   .ram_wr_data   (ram_wr_data)
36   );
37
38 ram_2port ram_2port_inst (
39   .wr_data    (ram_wr_data),    // input ram写数据
40   .wr_addr    (ram_wr_addr),    // input ram写地址
41   .wr_en      (ram_wr_en),    // input      
42   .wr_clk   (clk_50m    ),    // input
43   .wr_rst   (~sys_rst_n ),    // input
44   .rd_addr    (ram_rd_addr),    // input ram读地址
45   .rd_data    (ram_rd_data),    // output ram读数据
46   .rd_clk   (clk_25m    ),    // input
47   .rd_rst   (~sys_rst_n )   // input
48 );
49
50 //RAM读模块   
51 ram_rd u_ram_rd(
52   .clk         (clk_25m),
53   .rst_n         (sys_rst_n),
54   .ram_rd_en   (ram_rd_en), //ram读使能
55   .ram_rd_addr   (ram_rd_addr),
56   .ram_rd_data   (ram_rd_data)
57   );
58
59 endmodule
程序中例化了ram_rw模块和单口ram IP核,其中ram_rw模块负责产生对ram IP核读/写所需的所有数据、地址以和读写使能信号,同时从ram IP读出的数据也连接至ram_rw模块。
接下来对单口RAM IP核进行仿真,来验证对单口RAM的读写操作是否正确。ip_1port_ram_tb仿真文件源代码如下:
1`timescale 1ns / 1ps
2module ip_2port_ram_tb;
3
4reggrs_n;
5//GTP_GRS I_GTP_GRS(
6      GTP_GRS GRS_INST(
7      .GRS_N (grs_n)
8      );
9      
10   initial begin
11   grs_n = 1'b0;
12   #5000 grs_n = 1'b1;
13   end
14
15   // Inputs
16   reg sys_clk;
17   reg sys_rst_n;
18
19   // Outputs
20   wire          clk_50m ;
21   wire          clk_25m ;
22   wire          locked;
23   
24   wire          wr_en_tb; //ram写使能
25   wire     wr_addr_tb; //ram写地址
26   wire     wr_data_tb; //ram写数据
27   wire          rd_en_tb; //ram读使能
28   wire     rd_addr_tb; //ram读地址
29   wire     rd_data_tb; //ram读数据
30
31   // Instantiate the Unit Under Test (UUT)
32   ip_2port_ram uut (
33   .sys_clk      (sys_clk),
34   .sys_rst_n    (sys_rst_n),
35   .clk_50m      (clk_50m),
36   .clk_25m      (clk_25m),
37   .locked       (locked   ),
38   .wr_en      (wr_en_tb),
39   .wr_addr      (wr_addr_tb),
40   .wr_data      (wr_data_tb),
41   .rd_en      (rd_en_tb),
42   .rd_addr      (rd_addr_tb),
43   .rd_data      (rd_data_tb)
44   );
45   
46   initial begin
47   // Initialize Inputs
48   sys_clk = 0;
49   sys_rst_n = 0;
50   
51   // Wait 100 ns for global reset to finish
52   #100;
53   sys_rst_n=1;
54   // Add stimulus here
55   end
56   
57   always #10 sys_clk=~sys_clk;
58   
59 endmodule
接下来就可以开始仿真了,仿真过程这里不再赘述,仿真波形图如下图所示。
图 19.4.15 简单双端口RAM写操作波形图
图 19.4.15为简单双端口RAM的写操作仿真波形图,由上图可知,地址和数据初始化赋值为0,当wr_en_tb信号拉高,说明此时是对ram进行写操作。wr_en_tb信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1,我们总共向ram中写入32个数据。
简单双端口RAM读操作仿真波形图如下图所示:
图 19.4.16 单口RAM读操作波形图
由上图可以看到,ram_rd_en信号拉高,说明此时是对ram进行读操作。ram_rd_en(读使能)信号拉高之后,ram_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据 ram_rd_data在延时1个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的,也就是说,我们创建的RAM IP核从仿真结果上来看是正确的。
接下来再看一张整体的仿真运行图。
图 19.4.17 整体仿真运行图
由上图可知,我们只在开始时写入一次,随后不再写入,而是每隔一段时间读取一次。
19.5下载验证
新建DebugCore,将ram_wr_en、ram_wr_addr、ram_wr_data、ram_rd_en、ram_rd_addr和ram_rd_data这六个信号添加至观察列表中,新建DebugCore核的方法这里不再赘述。
编译工程并生成比特流.sbit文件后,此时将下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,连接电源线,并打开开发板的电源开关。
点击PDS工具栏的下载按钮,在弹出的Fabric Configuration界面中双击“Boundary Scan”,我们将生成好的sbit流文件下载到开发板中去。
在在线调试配置界面将ram_wr_en信号设置为高电平触发:
图 19.5.1设置触发信号
然后在如下界面点击触发按钮后进入如图 19.5.3等待触发界面:
图 19.5.2 在线调试“Run”
图 19.5.3 等待触发
在等待触发时按下开发板的复位按键,可以看到如下所示一张整体的在线调试运行图,由下图可知,我们只在开始时写入一次,随后不再写入,而是每隔一段时间读取一次。
图 19.5.4 整体的在线调试运行图
下面是放大后简单双端口RAM写操作在Fabric Debugger中观察的波形如下图所示:
图 19.5.5 RAM写操作波形图
wr_en_tb信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1。我们可以发现,上图中的数据变化和在PDS仿真的波形是一致的。
下面是放大后简单双端口RAM读操作在Fabric Debugger中观察的波形如下图所示:
图 19.5.6 RAM读操作波形图
rd_en(读使能)信号拉高之后,rd_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据ram_rd_data在延时两个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的。
我们可以发现,上图中的数据变化同样和PDS仿真的波形是一致的。本次实验的IP核之简单双端口RAM读写实验验证成功。

页: [1]
查看完整版本: 《ATK-DFPGL22G之FPGA开发指南_V1.0》第十九章 IP核之双端口RAM实验