上文对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端口数据映射关系如下:
例化一个简单的ip,设置如下。这里选择简单双端口模式的本地接口,采用面积最小原则,端口A为16bit,深度为16,ram大小就是16*16bit,控制信号就使用ENA。对于端口B,将位宽设置为32bit,此时深度自动变换为8,使用写优先模式,同样使能ENB端口作为控制端口。
这里对续写模式再做一个简单的说明,支持WRITE_FIRST, READ_FIRST或NO_CHANGE三种模式,这三种模式的读写时序如下图所示。
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,输入输出均为满速率,同时在代码中增加了防抖保护措施,防止跨时钟域中因为出现时钟抖动而产生的数据异常问题。
以上就是Xilinx Block Memory Generator(BMG) IP的仿真。
全部0条评论
快来发表一下你的评论吧 !