Xilinx FPGA IP之Block Memory Generator仿真

描述

上文对BMG ip的基本情况进行了简单的描述,本文通过例化仿真来实际使用功能一下这个IP。

首先使用简单双端口BRAM实现一个简单的跨时钟域操作:将16bit的a时钟域的数据跨到b时钟域,b时钟频率是a时钟频率的一半,为了操作方便,直接将b数据位宽扩展到32bit(这样就不用增加控制信息,数据流是满的)。BMG IP输入输出位宽比支持:1:32, 1:16, 1:8, 1:4, 1:2, 1:1, 2:1, 4:1, 8:1, 16:1, 32:1.位宽变换时BMG的AB端口数据映射关系如下:

FPGA

例化一个简单的ip,设置如下。这里选择简单双端口模式的本地接口,采用面积最小原则,端口A为16bit,深度为16,ram大小就是16*16bit,控制信号就使用ENA。对于端口B,将位宽设置为32bit,此时深度自动变换为8,使用写优先模式,同样使能ENB端口作为控制端口。

FPGA

FPGA

FPGA

这里对续写模式再做一个简单的说明,支持WRITE_FIRST, READ_FIRST或NO_CHANGE三种模式,这三种模式的读写时序如下图所示。

FPGA

FPGA

FPGA

WRITE_FIRST模式下,写优先级最高,同一地址,一旦写入,数据直接会透传到输出端。READ_FIRST模式,数据输出端口会锁存输出数据,有数据写入时,输出数据是上一次的数据。NO_CHANGE模式下,在写使能拉高后,输出将保持开始拉高时刻的数据,保持不变。注意这三种模式针对的是单端口,即端口A或者B。

编写一个简单的仿真测试代码如下:

// ============================================================
// File Name: tb_blk_mem_gen_sdp
// VERSION  : V1.0
// DATA     : 2023/8/5
// Author   : FPGA干货分享
// ============================================================
// 功能:xilinx blk_mem_gen_sdp ip 代码仿真
//       使用简单双端口实现一个简单的跨时钟域
// delay : 
// ============================================================




`timescale 1ns/100ps
module tb_blk_mem_gen_sdp ;


reg             clka   = 'd0 ;
reg             ena    = 'd1 ; 
reg  [0 : 0]    wea    = 'd1 ; 
reg  [3 : 0]    addra  = 'd0 ;
reg  [15 : 0]   dina   = 'd0 ;
reg             clkb   = 'd0 ;
reg             enb    = 'd1 ; 
reg  [2 : 0]    addrb  = 'd0 ;
wire [31 : 0]   doutb        ;




reg [2:0]   S_addr_a_flag   ='d0 ;
reg         S_a_flag        ='d0 ;
reg [2:0]   S_a_flag_2_b    ='d0 ;
reg         S_b_flag        ='d0 ;


reg [2:0]   S_clk_cnt8      ='d3   ;


always #1 clka = ~clka;
always #2 clkb = ~clkb;




//----------- clk_a  ---// 
always @(posedge clka)
    if(ena && wea)
        begin
            addra <= addra + 'd1;
            dina  <= dina + 'd1;
        end


always @(posedge clka)
    S_addr_a_flag[0] <= (addra == 4'd10);

always @(posedge clka)
    S_addr_a_flag[2:1] <= S_addr_a_flag[1:0] ; 


always @(posedge clka)
    S_a_flag <= |S_addr_a_flag ;


//----------- clk_b  ---// 
always @(posedge clkb)
    S_a_flag_2_b <= {S_a_flag_2_b[1:0],S_a_flag} ;


always @(posedge clkb)
    S_b_flag <= (!S_a_flag_2_b[2])&& S_a_flag_2_b[1] ;

always @(posedge clkb)
    if((S_clk_cnt8 > 3'd2)&&S_b_flag)
        S_clk_cnt8 <= 3'd2;
    else 
        S_clk_cnt8 <= S_clk_cnt8 + 'd1;




always @(posedge clkb)
    if(S_clk_cnt8 == 3'd1)
        addrb <= 'd0;
    else 
        addrb <= addrb + 'd1;




//----------- Begin Cut here for INSTANTIATION Template ---// 
blk_mem_gen_sdp blk_mem_gen_sdp (
  .clka     (clka       ), // input wire clka   
  .ena      (ena        ), // input wire ena     
  .wea      (wea        ), // input wire [0 : 0] wea     
  .addra    (addra      ), // input wire [3 : 0] addra 
  .dina     (dina       ), // input wire [15 : 0] dina   
  .clkb     (clkb       ), // input wire clkb   
  .enb      (enb        ), // input wire enb     
  .addrb    (addrb      ), // input wire [2 : 0] addrb 
  .doutb    (doutb      )  // output wire [31 : 0] doutb 
);


endmodule

仿真结果如下:clkb时钟频率是clka时钟频率的一半,dataa数据位宽16bit,datab数据位宽32bit,输入输出均为满速率,同时在代码中增加了防抖保护措施,防止跨时钟域中因为出现时钟抖动而产生的数据异常问题。

FPGA

以上就是Xilinx Block Memory Generator(BMG) IP的仿真。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分