969|0

845

帖子

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/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

北京市海淀区中关村大街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
快速回复 返回顶部 返回列表