1052|0

866

帖子

3

TA的资源

版主

楼主
 

05、国产FPGA 正点原子DFPGL22G开发板测评【学习篇】IP核双端口RAM [复制链接]

 
本帖最后由 1nnocent 于 2023-2-4 13:01 编辑

    1、简介

    双端口 RAM 又分为简单双端口 RAM 和真双端口 RAM,顾名思义,简单双端口 RAM 虽然有两个端口,但是一个端口只能用来写,另一个端口只能用来读,所以简单双端口 RAM 也称为伪双端口 RAM。而真双端口 RAM 是指两个端口都可以用来写或者读,可以理解成具有两个独立的单端口的 RAM,一般用于需要多路写入和读出的情况,而不用例化两个单端口的 RAM,在使用上更为方便。
    2、实验任务

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

    该程序需要5个模块:简单双端口 RAM 模块、写 RAM模块、读 RAM 模块、 PLL IP 核模块以及顶层模块,顶层模块例化其余模块实现前四个模块的数据交互。由于双端口 RAM 多用于跨时钟域信号的处理,所以本实验我们使用两个不同的时钟分别作为 RAM 的写时钟和读时钟,这两个时钟由 PLL IP 核生成,输出的时钟分别是 50Mhz 和 25Mhz。系统功能框图:

 

        ram_wr.v:模块中定义了一个写计数器(wr_cnt),从 0 累加至 63,此后一直保持在数值 63。当计数范围在0~31 之间时,向 ram 中写入数据,而其它计数值时停止写入。实现的功能是向 RAM 的地址 0 写入数据0,地址 1 写入数据 1,一直到地址 31 写入数据 31,只在上电后写入一次。

  • module ram_wr(
  • input clk,
  • input rst_n,
  • output ram_wr_en,
  • output reg[4:0] ram_wr_addr,
  • output reg[7:0] ram_wr_data
  • );
  • reg[5:0] wr_cnt;
  • assign ram_wr_en = ((wr_cnt >= 6'd0)&&(wr_cnt <= 6'd31)&& rst_n) ? 1'b1 : 1'b0;
  • always@(posedge clk or negedge rst_n)begin
  • if(!rst_n)begin
  • wr_cnt <= 6'd0;
  • end
  • else if(wr_cnt == 6'd63)begin
  • wr_cnt <= wr_cnt;
  • end
  • else begin
  • wr_cnt <= wr_cnt + 1'b1;
  • end
  • end
  • always@(posedge clk or negedge rst_n)begin
  • if(!rst_n)begin
  • ram_wr_data <= 8'd0;
  • end
  • else if(wr_cnt >= 6'd0 && wr_cnt <= 6'd31)begin
  • ram_wr_data <= ram_wr_data + 1'b1;
  • end
  • else begin
  • ram_wr_data <= 8'd0;
  • end
  • end
  • always@(posedge clk or negedge rst_n)begin
  • if(!rst_n)begin
  • ram_wr_addr <= 5'd0;
  • end
  • else if(wr_cnt >= 6'd0 && wr_cnt <= 6'd31)begin
  • ram_wr_addr <= ram_wr_addr + 1'b1;
  • end
  • else begin
  • ram_wr_addr <= 5'd0;
  • end
  • end
  • endmodule


    ram_rd.v:模块中定义了一个读计数器(rd_cnt),循环的从 0 累加至 63。当计数范围在 0~31 之间时,从 ram 中读出数据,而其它计数值时停止读数据。

  • module ram_rd(
  • input clk,
  • input rst_n,
  • output ram_rd_en,
  • output reg[4:0]ram_rd_addr,
  • input [7:0]ram_rd_data
  • );
  • reg[5:0] rd_cnt;
  • assign ram_rd_en = ((rd_cnt >= 6'd0)&&(rd_cnt <= 6'd31)&& rst_n)? 1'b1 : 1'b0;
  • always@(posedge clk or negedge rst_n)begin
  • if(!rst_n)begin
  • rd_cnt <= 6'd0;
  • end
  • else if(rd_cnt == 6'd63)begin
  • rd_cnt <= 6'd0;
  • end
  • else begin
  • rd_cnt <= rd_cnt + 1'b1;
  • end
  • end
  • always@(posedge clk or negedge rst_n)begin
  • if(!rst_n)begin
  • ram_rd_addr <= 5'd0;
  • end
  • else if(rd_cnt >= 6'd0 && rd_cnt <= 6'd31)begin
  • ram_rd_addr <= ram_rd_addr + 1'b1;
  • end
  • else begin
  • ram_rd_addr <= 5'd0;
  • end
  • end
  • endmodule


    ip_2port_ram.v:例化创建的 PLL IP 核、 RAM IP 核、 RAM 写模块和 RAM 读模块。程序中例化了 ram_rw 模块和单口 ram IP 核,其中 ram_rw 模块负责产生对 ram IP 核读/写所需的所有数据、地址以和读写使能信号,同时从 ram IP 读出的数据也连接至 ram_rw 模块。
 

  • module ip_2port_ram(
  • input sys_clk,
  • input sys_rst_n,
  • output clk_50m,
  • output clk_25m,
  • output locked,
  • output ram_wr_en,
  • output [4:0] ram_wr_addr,
  • output [7:0] ram_wr_data,
  • output ram_rd_en,
  • output [4:0] ram_rd_addr,
  • output [7:0] ram_rd_data
  • );
  • pll_clk u_pll_clk(
  • .pll_rst (!sys_rst_n),
  • .clkin1 (sys_clk),
  • .pll_lock (locked),
  • .clkout0 (clk_50m),
  • .clkout1 (clk_25m)
  • );
  • ram_wr u_ram_wr(
  • .clk (sys_clk),
  • .rst_n (sys_rst_n),
  • .ram_wr_en (ram_wr_en),
  • .ram_wr_addr (ram_wr_addr),
  • .ram_wr_data (ram_wr_data)
  • );
  • ram_2port ram_2port_inst (
  • .wr_data (ram_wr_data),
  • .wr_addr (ram_wr_addr),
  • .wr_en (ram_wr_en ),
  • .wr_clk (clk_50m ),
  • .wr_rst (~sys_rst_n ),
  • .rd_addr (ram_rd_addr),
  • .rd_data (ram_rd_data),
  • .rd_clk (clk_25m ),
  • .rd_rst (~sys_rst_n )
  • );
  • ram_rd u_ram_rd(
  • .clk (clk_25m),
  • .rst_n (sys_rst_n),
  • .ram_rd_en (ram_rd_en ),
  • .ram_rd_addr (ram_rd_addr),
  • .ram_rd_data (ram_rd_data)
  • );
  • endmodule

 

    ip_1port_ram_tb:

  • `timescale 1ns / 1ps
  • module ip_2port_ram_tb;
  • reg grs_n;
  • //GTP_GRS I_GTP_GRS(
  • GTP_GRS GRS_INST(
  • .GRS_N (grs_n)
  • );
  • initial begin
  • grs_n = 1'b0;
  • #5000 grs_n = 1'b1;
  • end
  • reg sys_clk;
  • reg sys_rst_n;
  • wire clk_50m ;
  • wire clk_25m ;
  • wire locked ;
  • wire wr_en_tb ;
  • wire [4:0] wr_addr_tb;
  • wire [7:0] wr_data_tb;
  • wire rd_en_tb ;
  • wire [4:0] rd_addr_tb;
  • wire [7:0] rd_data_tb;
  • ip_2port_ram uut (
  • .sys_clk (sys_clk ),
  • .sys_rst_n (sys_rst_n ),
  • .clk_50m (clk_50m ),
  • .clk_25m (clk_25m ),
  • .locked (locked ),
  • .ram_wr_en (wr_en_tb ),
  • .ram_wr_addr (wr_addr_tb),
  • .ram_wr_data (wr_data_tb),
  • .ram_rd_en (rd_en_tb ),
  • .ram_rd_addr (rd_addr_tb),
  • .ram_rd_data (rd_data_tb)
  • );
  • initial begin
  • sys_clk = 0;
  • sys_rst_n = 0;
  • #100;
  • sys_rst_n=1;
  • end
  • always #10 sys_clk=~sys_clk;
  • endmodule

仿真波形图如下图所示:可以发现wr_data_tb是蓝色波形存在问题,展开每个bit的数据发现第5、6、7位是“”Z"状态。把这个信号查一遍发现是ram_wr定义这个信号时位宽写成了[4:0]只有底五位有数据。

  

 

 

更改错误之后:各位的数据正确。

 

写人数据时wr_en_tb为高,写入32个数据之后不再写入;

 

读出数据时rd_en_tb为高,写入32个数据之后不再写入;

 

查看本帖全部内容,请登录或者注册
点赞 关注(1)
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
【干货上新】电源解决方案和技术第二趴 | DigiKey 应用探索站
当月好物、电源技术资源、特色活动、DigiKey在线实用工具,干货多多~

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 15

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表