搜索
bottom↓
回复: 0

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

[复制链接]

出0入234汤圆

发表于 2023-1-30 10:02:05 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 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 lQLPJxaFi2zaB4UWWrDAMgIsFEW2pwLb3abnwDMA_90_22.png
lQDPJxaFi2nfFizMjM0CbLCPlxn_FVheIQLb3aGrwFQA_620_140.jpg

lQLPJxaFi2nfFhLMkM0BXrDNvOUyeU_FPgLb3aGvQNIA_350_144.png


第十九章 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的端口框图。
IP核之双端口RAM实验688.png
图 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实验管脚分配
lQLPJxR6LOzqdKBczQJwsESXrpbrhhZYA9G2besA_wA_624_92.png

对应的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。系统的功能框图如下所示:
IP核之双端口RAM实验2415.png
图 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所示。
IP核之双端口RAM实验2750.png
图 19.4.2 点击“IP Compiler”

IP核之双端口RAM实验2820.png
图 19.4.3 “IP Compiler”窗口

本实验使用的IP核路径是Module→Memory→DRM→DRM Base Simple Dual Port RAM IP核,如下图所示。
IP核之双端口RAM实验2961.png
图 19.4.4 DRM Base Simple Dual Port RAM

点击上图中红框中的IP后如下图所示:
IP核之双端口RAM实验3064.png
图 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所示。
IP核之双端口RAM实验3501.png
图 19.4.6 “Add IP”弹窗

lQLPJwhczIxziWDNAfXNAo-wFBGmTu7bmx0D0bVXfwDeAA_655_501.png
图 19.4.7 "Customize IP"界面

本实验我们主要进行如下配置:
lQLPJxrpRUA7xKDNAaXNAm6woHZgRq2C3nED0bVo_sCeAA_622_421.png
图 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模式允许的位宽组合
IP核之双端口RAM实验4002.png

表 19.4.2 18Kb DRM模式下Simple Dual Port RAM模式允许的位宽组合
IP核之双端口RAM实验4097.png

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[3]有效时,只会将输入数据的高8-bit写入到目标地址;当we[0]有效时,只会将输入数据的低8-bit写入到目标地址。其实,也就是根据写使能来更新指定地址上原始数据的某些位,本实验不需要使能Byte Write功能即不需要勾选该配置。
lQLPJwH4niPgjuAszQKKsFLvE07nlGyfA9G2qycA_QA_650_44.png
图 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”即可,如下图所示。
IP核之双端口RAM实验6675.png
图 19.4.10 点击“Generate”按钮

点击“OK”后打印如下左图信息,至此简单双单口RAM IP核配置成功,并生成ram_2port_tmpl.v文件。例化简单双单口RAM IP时可以使用下图中ram_2port_tmpl.v文件红框中的代码。
IP核之双端口RAM实验6849.png
图 19.4.11简单双端口RAM IP创建成功

然后如下图所示,关闭“Customize IP”页面与“IP Compiler”页面。
IP核之双端口RAM实验6963.png
图 19.4.12 关闭创建IP的窗口

之后我们就可以在“Sources”窗口的“Designs”一栏中出现了该IP核“pll_clk”如下图所示。
IP核之双端口RAM实验7083.png
图 19.4.13 "ram_2port"IP

除此之外,我们再创建一个PLL IP核(命名为pll_clk),共输出两路时钟,时钟频率分别是50Mhz和25Mhz,如下图所示,创建过程此处不再赘述。
IP核之双端口RAM实验7229.png
图 19.4.14 PLL IP核

接下来我们设计一个verilog文件对ram进行写入数据,文件名为ram_wr.v,编写的verilog代码如下。
1  module ram_wr(
2      input            clk,           //时钟信号
3      input            rst_n,         //复位信号,低电平有效
4                                      
5      //RAM写端口操作                 
6      output           ram_wr_en,     //ram写使能
7      output reg [4:0] ram_wr_addr,   //ram写地址        
8      output reg [7:0] ram_wr_data    //ram写数据
9  );
10
11 //reg define
12 reg  [5:0]  wr_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代码如下。
1  module ram_rd(
2      input            clk,           //时钟信号
3      input            rst_n,         //复位信号,低电平有效
4                                      
5      //RAM读端口操作               
6      output           ram_rd_en,     //ram读使能
7      output reg [4:0] ram_rd_addr,   //ram读地址        
8      input      [7:0] ram_rd_data    //ram读数据
9  );
10
11 reg  [5:0]  rd_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代码如下。
1  module 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    [4:0]     ram_wr_addr    ,
10     output    [7:0]     ram_wr_data    ,
11     output              ram_rd_en      ,
12     output    [4:0]     ram_rd_addr    ,
13     output    [7:0]     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 [7:0]  ram写数据
40   .wr_addr    (ram_wr_addr),    // input [4:0]  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 [4:0]  ram读地址
45   .rd_data    (ram_rd_data),    // output [7:0] 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
2  module ip_2port_ram_tb;
3  
4  reg  grs_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 [4:0]    wr_addr_tb; //ram写地址
26     wire [7:0]    wr_data_tb; //ram写数据
27     wire          rd_en_tb  ; //ram读使能
28     wire [4:0]    rd_addr_tb; //ram读地址
29     wire [7:0]    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
接下来就可以开始仿真了,仿真过程这里不再赘述,仿真波形图如下图所示。
IP核之双端口RAM实验14076.png
图 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读操作仿真波形图如下图所示:
IP核之双端口RAM实验14358.png
图 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核从仿真结果上来看是正确的。
接下来再看一张整体的仿真运行图。
IP核之双端口RAM实验14630.png
图 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信号设置为高电平触发:
IP核之双端口RAM实验15038.png
图 19.5.1设置触发信号

然后在如下界面点击触发按钮后进入如图 19.5.3等待触发界面:
IP核之双端口RAM实验15157.png
图 19.5.2 在线调试“Run”

IP核之双端口RAM实验15221.png
图 19.5.3 等待触发

在等待触发时按下开发板的复位按键,可以看到如下所示一张整体的在线调试运行图,由下图可知,我们只在开始时写入一次,随后不再写入,而是每隔一段时间读取一次。
IP核之双端口RAM实验15357.png
图 19.5.4 整体的在线调试运行图

下面是放大后简单双端口RAM写操作在Fabric Debugger中观察的波形如下图所示:
IP核之双端口RAM实验15468.png
图 19.5.5 RAM写操作波形图

wr_en_tb信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1。我们可以发现,上图中的数据变化和在PDS仿真的波形是一致的。
下面是放大后简单双端口RAM读操作在Fabric Debugger中观察的波形如下图所示:
IP核之双端口RAM实验15679.png
图 19.5.6 RAM读操作波形图

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

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

本版积分规则

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

GMT+8, 2024-4-29 20:16

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

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