Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(一)

 Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(前导)


  四、AXI转FIFO接口模块设计

1.AXI接口知识

AXI协议是基于 burst的传输,并且定义了以下 5 个独立的传输通道:

  • 读地址通道(Read Address Channel, AR)
  • 读数据通道(Read Data Channel, R)
  • 写地址通道(Write Address Channel, AW)
  • 写数据通道(Write Data Channel, W)
  • 写响应通道(Write Response Channel, B)

  • 这 5 条独立的通道都包含一个双路的 VALD、 READY 握手机制。信息源通过 VALID 信号来指示通道中的数据和控制信息什么时候有效。目地源用READY 信号来表示何时准备好接收数据。传输地址信息和数据都是在 VALID和 READY 同时为高时有效。
  • 读数据和写数据通道都包括一个 LAST 信号,用来指明一个事物传输的最后一个数据
  • 读/写事务都有自己的地址通道,地址通道携带着传输事务所必需的地址和控制信息
  • 读数据通道传送着从设备到主机的读数据和读响应信息。读响应信息指明读事务的完成状态
  • 写数据通路传送着主机向从设备的写数据。写响应通道提供了设备响应写事务的一种方式。在每一次突发式写会产生一个完成信号

写事务时序

读事务时序

AXI 协议支持乱序传输。每一个通过接口的事务有一个 IDtag。协议要求相同 ID tag 的事务必须有序完成,而不同 ID tag 可以乱序完成


1.1写地址通道信号

1.2写数据通道信号

1.3写响应通道信号

1.4读地址通道信号

1.5读数据通道信号

2.ZynqAXI接口

红绿蓝三种颜色的箭头代表了几种不同位宽的 AXI 总线。 红色线条框是 PL 端访问 DDR控制器的路径,其中, High Performamce AXI 32/64b Slave Ports 便是我们所说的HP 接口, 该接口为 AXI 接口,通常用于大量数据的高速传输。

PS 端通过硬件电路实现 AXI 总线,而 PL 端则需要用户通过逻辑资源搭建 AXI 总线

3.AXI转换模块设计(fifo_axi4_adapter)

目的:为了解决上下游模块常常处于不同时钟域的问题。

fifo_axi4_adapter 负责FIFO接口到AXI4接口的转换,FIFO中的数据可以通过该模块写入PS端,PS端的数据也可以由该模块接收写入FIFO。通过这种方式,用户只需要操作FIFO,就能实现PL端数据对PS端DDR的读写。

wr_ddr3_fifo rd_ddr3_fifo 为上文中我们提到的读写 FIFO,用于存储读写数据,同时解决时钟域等问题。fifo2axi4 为 AXI4 接口转换模块,负责fifo 与 axi4 接口间的转换, 将写侧 FIFO 里的数据读出然后存储在 DDR 存储器以及将 DDR 存储器读出的数据存放到读侧 FIFO 缓存。

3.1接口转换模块设计(fifo2axi4)

写流程:主机向写地址通道写入地址和控制信息→写数据通道突发写入数据→收到设备的写数据响应。

读流程:主机向读地址通道写入地址和控制信息→ 收到设备的读数据响应和读的数据。

根据时序进行状态机设计:

//写信号状态机
always@(posedge clk or posedge reset)
begin
    if(reset)
        curr_wr_state <= S_IDLE;
    else
        curr_wr_state <= next_wr_state;
    end

always@(*)
begin
    case(curr_wr_state)
        S_IDLE:
        begin
            if(wr_ddr3_req == 1'b1)
                next_wr_state = S_WR_ADDR;
            else
                next_wr_state = S_IDLE;
        end
        S_WR_ADDR:
        begin
            if(m_axi_awready && m_axi_awvalid)
                next_wr_state = S_WR_DATA;
            else
                next_wr_state = S_WR_ADDR;
        end
        S_WR_DATA:
        begin
            if(m_axi_wready && m_axi_wvalid && m_axi_wlast)
                next_wr_state = S_WR_RESP;
            else
                next_wr_state = S_WR_DATA;
        end
        S_WR_RESP:
        begin
            if(m_axi_bready && m_axi_bvalid && (m_axi_bresp == 2'b00) &&(m_axi_bid == AXI_ID[AXI_ID_WIDTH-1:0]))
                next_wr_state = S_IDLE;
            else
                next_wr_state = S_WR_RESP;
        end


    endcase
end




//awaddr信号
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
    else if(wr_addr_clr || axi_awaddr_clr)
        m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
    else if(m_axi_awaddr >= WR_AXI_BYTE_ADDR_END)
        m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
    else if((curr_wr_state == S_WR_RESP) && m_axi_bready && m_axi_bvalid && (m_axi_bresp == 2'b00) && (m_axi_bid == AXI_ID[AXI_ID_WIDTH-1:0]))
        //每次地址增加量应该是突发写数据个数*每个数据的字节数
        m_axi_awaddr <= m_axi_awaddr + ((m_axi_awlen + 1'b1)*(AXI_DATA_WIDTH/8));
    else
        m_axi_awaddr <= m_axi_awaddr;
end


//awvalid信号
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_awvalid <= 1'b0;
    else if((curr_wr_state == S_WR_ADDR) && m_axi_awready && m_axi_awvalid)
        m_axi_awvalid <= 1'b0;
    else if(curr_wr_state == S_WR_ADDR)
        m_axi_awvalid <= 1'b1;
    else
        m_axi_awvalid <= m_axi_awvalid;
end

//wvalid信号
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_wvalid <= 1'b0;
    else if((curr_wr_state == S_WR_DATA) && m_axi_wready && m_axi_wvalid && m_axi_wlast)
m_axi_wvalid <= 1'b0;
    else if(curr_wr_state == S_WR_DATA)
        m_axi_wvalid <= 1'b1;
    else
        m_axi_wvalid <= m_axi_wvalid;
end

//传输计数
always@(posedge clk or posedge reset)
begin
    if(reset)
        wr_data_cnt <= 1'b0;
    else if(curr_wr_state == S_IDLE)
        wr_data_cnt <= 1'b0;
    else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid)
        wr_data_cnt <= wr_data_cnt + 1'b1;
    else
        wr_data_cnt <= wr_data_cnt;
end

//wlast信号:
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_wlast <= 1'b0;
    else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid && m_axi_wlast)
        m_axi_wlast <= 1'b0;
    else if(curr_wr_state == S_WR_DATA && m_axi_awlen == 8'd0)
        //数据个数为1
        m_axi_wlast <= 1'b1;
    else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid && (wr_data_cnt == m_axi_awlen -1'b1))
        //传输完倒数第二个数
        m_axi_wlast <= 1'b1;
    else
        m_axi_wlast <= m_axi_wlast;
end

根据时序进行状态机设计:

//读状态机
always@(posedge clk or posedge reset)
begin
    if(reset)
        curr_rd_state <= S_IDLE;
    else
        curr_rd_state <= next_rd_state;
end
always@(*)
begin
    case(curr_rd_state)
        S_IDLE:
        begin
            if(rd_ddr3_req == 1'b1)
                next_rd_state = S_RD_ADDR;
            else
                next_rd_state = S_IDLE;
        end
        S_RD_ADDR:
        begin
            if(m_axi_arready && m_axi_arvalid)
                next_rd_state = S_RD_RESP;
            else
                next_rd_state = S_RD_ADDR;
        end
        S_RD_RESP:
        begin
            if(m_axi_rready && m_axi_rvalid && m_axi_rlast && (m_axi_rresp == 2'b00)&& (m_axi_rid == AXI_ID[AXI_ID_WIDTH-1:0]))
                next_rd_state = S_IDLE;
            else
                next_rd_state = S_RD_RESP;
        end
    endcase
end

//araddr
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
    else if(rd_addr_clr || axi_araddr_clr)
        m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
    else if(m_axi_araddr >= RD_AXI_BYTE_ADDR_END)
        m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
    else if((curr_rd_state == S_RD_RESP) && m_axi_rready && m_axi_rvalid && m_axi_rlast && (m_axi_rresp == 2'b00) && (m_axi_rid == AXI_ID[AXI_ID_WIDTH-1:0]))
        m_axi_araddr <= m_axi_araddr + ((m_axi_arlen + 1'b1)*(AXI_DATA_WIDTH/8));
    else
        m_axi_araddr <= m_axi_araddr;
end

//m_axi_arvalid
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_arvalid <= 1'b0;
    else if((curr_rd_state == S_RD_ADDR) && m_axi_arready && m_axi_arvalid)
        m_axi_arvalid <= 1'b0;
    else if(curr_rd_state == S_RD_ADDR)
        m_axi_arvalid <= 1'b1;
    else
    m_axi_arvalid <= m_axi_arvalid;
end

其他信号定义:

assign m_axi_awid = AXI_ID[AXI_ID_WIDTH-1:0];
assign m_axi_awsize = DATA_SIZE;
assign m_axi_awburst = 2'b01;
assign m_axi_awlock = 1'b0;
assign m_axi_awcache = 4'b0000;
assign m_axi_awprot = 3'b000;
assign m_axi_awqos = 4'b0000;
assign m_axi_awregion= 4'b0000;
assign m_axi_awlen = AXI_BURST_LEN[7:0];
assign m_axi_wstrb = 16'hffff;
assign m_axi_wdata = wr_fifo_rddata;
assign m_axi_bready = 1'b1;
assign m_axi_arid = AXI_ID[AXI_ID_WIDTH-1:0];
assign m_axi_arsize = DATA_SIZE;
assign m_axi_arburst = 2'b01;
assign m_axi_arlock = 1'b0;
assign m_axi_arcache = 4'b0000;
assign m_axi_arprot = 3'b000;
assign m_axi_arqos = 4'b0000;
assign m_axi_arregion= 4'b0000;
assign m_axi_arlen = AXI_BURST_LEN[7:0];
assign m_axi_rready = ~rd_fifo_alfull;

assign wr_fifo_rdreq = (~axi_awaddr_clr) && m_axi_wvalid && m_axi_wready;
assign rd_fifo_wrreq = (~axi_araddr_clr) && m_axi_rvalid && m_axi_rready;
assign rd_fifo_wrdata = m_axi_rdata;

assign wr_req_cnt_thresh = (m_axi_awlen == 'd0)? 1'b1 : (AXI_BURST_LEN[7:0]+1'b1-2'd2);//计数比实际数量少 2
assign rd_req_cnt_thresh = AXI_BURST_LEN[7:0];
assign wr_ddr3_req = (wr_fifo_rst_busy == 1'b0) && (wr_fifo_rd_cnt >= wr_req_cnt_thresh) ? 1'b1:1'b0;
assign rd_ddr3_req = (rd_fifo_rst_busy == 1'b0) && (rd_fifo_wr_cnt <= rd_req_cnt_thresh) ? 1'b1:1'b0;

3.2FIFO IP创建(wr_ddr3_fifo、rd_ddr3_fifo)

wr_ddr3_fifo: 

设置写FIFO接口类型,写入和读出的时钟不一致, 所以这里需要创建一个独立时钟 FIFO。

设置写FIFO端口

rd_ddr3_fifo:

设置读FIFO接口类型,写入和读出的时钟不一致, 所以这里需要创建一个独立时钟 FIFO。

设置读 FIFO 端口

设置读FIFO数据计数

 3.3 封装接口转换模块

module fifo_axi4_adapter #(
    parameter FIFO_DW = 16 ,
    parameter WR_AXI_BYTE_ADDR_BEGIN = 0 ,
    parameter WR_AXI_BYTE_ADDR_END = 1023 ,
    parameter RD_AXI_BYTE_ADDR_BEGIN = 0 ,
    parameter RD_AXI_BYTE_ADDR_END = 1023 ,
    parameter AXI_DATA_WIDTH = 128 ,
    parameter AXI_ADDR_WIDTH = 29 ,
    parameter AXI_ID_WIDTH = 4 ,
    parameter AXI_ID = 4'b0000,
    parameter AXI_BURST_LEN = 8'd31 //burst length = 32
) 
(
// clock reset
input                     clk ,
input                     reset ,

// wr_fifo wr Interface
input                     wrfifo_clr ,
input                     wrfifo_clk ,
input                     wrfifo_wren ,
input [FIFO_DW-1:0]       wrfifo_din ,
output                    wrfifo_full ,
output [15:0]             wrfifo_wr_cnt ,

// rd_fifo rd Interface
input                     rdfifo_clr ,
input                     rdfifo_clk ,
input                     rdfifo_rden ,
output [FIFO_DW-1:0]      rdfifo_dout ,
output                    rdfifo_empty ,
output [15:0]             rdfifo_rd_cnt ,

// Master Interface Write Address Ports
output [AXI_ID_WIDTH-1:0]        m_axi_awid ,
output [AXI_ADDR_WIDTH-1:0]      m_axi_awaddr ,
output [7:0]                     m_axi_awlen ,
output [2:0]                     m_axi_awsize ,
output [1:0]                     m_axi_awburst ,
output [0:0]                     m_axi_awlock ,
output [3:0]                     m_axi_awcache ,
output [2:0]                     m_axi_awprot ,
output [3:0]                     m_axi_awqos ,
output [3:0]                     m_axi_awregion,
output                           m_axi_awvalid ,
input                            m_axi_awready ,

// Master Interface Write Data Ports
output [AXI_DATA_WIDTH-1:0]           m_axi_wdata ,
output [AXI_DATA_WIDTH/8-1:0]         m_axi_wstrb ,
output                                m_axi_wlast ,
output                                m_axi_wvalid ,
input                                 m_axi_wready ,

// Master Interface Write Response Ports
input [AXI_ID_WIDTH-1:0]            m_axi_bid ,
input [1:0]                         m_axi_bresp ,
input                               m_axi_bvalid ,
output                              m_axi_bready ,

// Master Interface Read Address Ports
output [AXI_ID_WIDTH-1:0]            m_axi_arid ,
output [AXI_ADDR_WIDTH-1:0]          m_axi_araddr ,
output [7:0]                         m_axi_arlen ,
output [2:0]                         m_axi_arsize ,
output [1:0]                         m_axi_arburst ,
output [0:0]                         m_axi_arlock ,
output [3:0]                         m_axi_arcache ,
output [2:0]                         m_axi_arprot ,
output [3:0]                         m_axi_arqos ,
output [3:0]                         m_axi_arregion,
output                               m_axi_arvalid ,
input                                m_axi_arready ,

// Master Interface Read Data Ports
input [AXI_ID_WIDTH-1:0]              m_axi_rid ,
input [AXI_DATA_WIDTH-1:0]            m_axi_rdata ,
input [1:0]                           m_axi_rresp ,
input                                 m_axi_rlast ,
input                                 m_axi_rvalid ,
output                                m_axi_rready
);

wire                                 wrfifo_rden;
wire [AXI_DATA_WIDTH-1:0]            wrfifo_dout;
wire [5 : 0]                         wrfifo_rd_cnt;
wire                                 wrfifo_empty;
wire                                 wrfifo_wr_rst_busy;
wire                                 wrfifo_rd_rst_busy;
wire                                 rdfifo_wren;
wire [AXI_DATA_WIDTH-1:0]            rdfifo_din;
wire [5 : 0]                         rdfifo_wr_cnt;
wire                                 rdfifo_full;
wire                                 rdfifo_wr_rst_busy;
wire                                 rdfifo_rd_rst_busy;
reg                                  wrfifo_clr_sync_clk;
reg                                  wr_addr_clr;
reg                                  rdfifo_clr_sync_clk;
reg                                  rd_addr_clr;

wr_ddr3_fifo wr_ddr3_fifo
(
    .rst (wrfifo_clr ),
    .wr_clk (wrfifo_clk ),
    .rd_clk (clk ),
    .din (wrfifo_din ),
    .wr_en (wrfifo_wren ),
    .rd_en (wrfifo_rden ),
    .dout (wrfifo_dout ),
    .full (wrfifo_full ),
    .empty (wrfifo_empty ),
    .rd_data_count (wrfifo_rd_cnt ),
    .wr_data_count (wrfifo_wr_cnt ),
    .wr_rst_busy (wrfifo_wr_rst_busy ),
    .rd_rst_busy (wrfifo_rd_rst_busy )
);

rd_ddr3_fifo rd_ddr3_fifo
(
    .rst (rdfifo_clr ),
    .wr_clk (clk ),
    .rd_clk (rdfifo_clk ),
    .din (rdfifo_din ),
    .wr_en (rdfifo_wren ),
    .rd_en (rdfifo_rden ),
    .dout (rdfifo_dout ),
    .full (rdfifo_full ),
    .empty (rdfifo_empty ),
    .rd_data_count (rdfifo_rd_cnt ),
    .wr_data_count (rdfifo_wr_cnt ),
    .wr_rst_busy (rdfifo_wr_rst_busy ),
    .rd_rst_busy (rdfifo_rd_rst_busy )
);

always@(posedge clk)
begin
    wrfifo_clr_sync_clk <= wrfifo_clr;
    wr_addr_clr <= wrfifo_clr_sync_clk;
end

always@(posedge clk)
begin
    rdfifo_clr_sync_clk <= rdfifo_clr;
    rd_addr_clr <= rdfifo_clr_sync_clk;
end

fifo2axi4
#(
    .WR_AXI_BYTE_ADDR_BEGIN (WR_AXI_BYTE_ADDR_BEGIN ),
    .WR_AXI_BYTE_ADDR_END (WR_AXI_BYTE_ADDR_END ),
    .RD_AXI_BYTE_ADDR_BEGIN (RD_AXI_BYTE_ADDR_BEGIN ),
    .RD_AXI_BYTE_ADDR_END (RD_AXI_BYTE_ADDR_END ),
    .AXI_DATA_WIDTH (AXI_DATA_WIDTH ),
    .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ),
    .AXI_ID_WIDTH (AXI_ID_WIDTH ),
    .AXI_ID (AXI_ID ),
    .AXI_BURST_LEN (AXI_BURST_LEN )//burst length = 32
)fifo2axi4_inst
(
//clock reset
    .clk (clk ),
    .reset (reset ),

//FIFO Interface ports
    .wr_addr_clr (wr_addr_clr ), //1:clear, sync clk
    .wr_fifo_rdreq (wrfifo_rden ),
    .wr_fifo_rddata (wrfifo_dout ),
    .wr_fifo_empty (wrfifo_empty ),
    .wr_fifo_rd_cnt (wrfifo_rd_cnt ),
    .wr_fifo_rst_busy (wrfifo_rd_rst_busy ),
    .rd_addr_clr (rd_addr_clr ), //1:clear, sync clk
    .rd_fifo_wrreq (rdfifo_wren ),
    .rd_fifo_wrdata (rdfifo_din ),
    .rd_fifo_alfull (rdfifo_full ),
    .rd_fifo_wr_cnt (rdfifo_wr_cnt ),
    .rd_fifo_rst_busy (rdfifo_wr_rst_busy ),

// Slave Interface Write Address Ports
    .m_axi_awid (m_axi_awid ),
    .m_axi_awaddr (m_axi_awaddr ),
    .m_axi_awlen (m_axi_awlen ),
    .m_axi_awsize (m_axi_awsize ),
    .m_axi_awburst (m_axi_awburst ),
    .m_axi_awlock (m_axi_awlock ),
    .m_axi_awcache (m_axi_awcache ),
    .m_axi_awprot (m_axi_awprot ),
    .m_axi_awqos (m_axi_awqos ),
    .m_axi_awregion (m_axi_awregion ),
    .m_axi_awvalid (m_axi_awvalid ),
    .m_axi_awready (m_axi_awready ),

// Slave Interface Write Data Ports
    .m_axi_wdata (m_axi_wdata ),
    .m_axi_wstrb (m_axi_wstrb ),
    .m_axi_wlast (m_axi_wlast ),
    .m_axi_wvalid (m_axi_wvalid ),
    .m_axi_wready (m_axi_wready ),

// Slave Interface Write Response Ports
    .m_axi_bid (m_axi_bid ),
    .m_axi_bresp (m_axi_bresp ),
    .m_axi_bvalid (m_axi_bvalid ),
    .m_axi_bready (m_axi_bready ),

// Slave Interface Read Address Ports
    .m_axi_arid (m_axi_arid ),
    .m_axi_araddr (m_axi_araddr ),
    .m_axi_arlen (m_axi_arlen ),
    .m_axi_arsize (m_axi_arsize ),
    .m_axi_arburst (m_axi_arburst ),
    .m_axi_arlock (m_axi_arlock ),
    .m_axi_arcache (m_axi_arcache ),
    .m_axi_arprot (m_axi_arprot ),
    .m_axi_arqos (m_axi_arqos ),
    .m_axi_arregion (m_axi_arregion ),
    .m_axi_arvalid (m_axi_arvalid ),
    .m_axi_arready (m_axi_arready ),

// Slave Interface Read Data Ports
    .m_axi_rid (m_axi_rid ),
    .m_axi_rdata (m_axi_rdata ),
    .m_axi_rresp (m_axi_rresp ),
    .m_axi_rlast (m_axi_rlast ),
    .m_axi_rvalid (m_axi_rvalid ),
    .m_axi_rready (m_axi_rready )
);
endmodule

4.AXI 接口转换模块仿真

1.仿真设计结构

2.DDR控制器(MIG IP)创建

1、配置MIG IP

DDR3存储器驱动的时钟周期(Clock Period)设置为2500ps(即400MHz),这个时钟是用于 FPGA 输出给到 DDR 存储器时钟管脚的时钟。注意这里根据实际情况是有设置区间范围的,并非可以设置任意值,这里的区间范围为 2500~3300ps(即 300~400MHz)。


TMD(Time DivisionMultiplexing),该设置读写优先级相同,读写交替进行。



仿真选New Design,上板测试选Fixed Pin Out。


在 Vivado 的 Source 窗口中,出现了新配置生成的 IP 核文件mig_7series_0(mig_7series_0.xci)。

在上面窗口的 IP Sources 一栏,可以找到 IP 例化模板文件(mig_7series_0.veo)。

3.产生时钟和复位、数据产生和数据读取的激励

DDR控制器时钟200MHz(T=5ns,每2.5ns翻转一次)

wr_ddr3_fifo、rd_ddr3_fifo时钟100MHz(T=10ns,每5ns翻转一次)

fifo_axi4_adapter模块时钟使用DDR控制器输出的供用户侧使用的ui_clk。

仿真的时间单位1ns,精度100ps。具体可以看一下Verilog(未完待续)里面的编译指令timescale部分。每2.5ns翻转一次,它的最低精度就是0.1ns=100ps,时间单位就是1ns。

`timescale 1ns/100ps
initial sys_clk_i = 1'b1;
always #2.5 sys_clk_i = ~sys_clk_i;
initial wrfifo_clk = 1'b1;
always #2.5 wrfifo_clk = ~wrfifo_clk;
initial rdfifo_clk = 1'b1;
always #2.5 rdfifo_clk = ~rdfifo_clk;

数据产生和读取的激励设计上将其封装成任务 task 形式,方便调用。

//向 wr_ddr3_fifo 中写入以起始数据 data_begin 开始递增的wr_data_cnt 个数据。
task wr_data;
input [15:0]data_begin;
input [15:0]wr_data_cnt;
begin
    wrfifo_wren = 1'b0;
    wrfifo_din = data_begin;
    @(posedge wrfifo_clk);
    #1 wrfifo_wren = 1'b1;
    repeat(wr_data_cnt)
    begin
        @(posedge wrfifo_clk);
        wrfifo_din = wrfifo_din + 1'b1;
    end
    #1 wrfifo_wren = 1'b0;
end
endtask



//向 rd_ddr3_fifo 中读出个 rd_data_cnt 数据
task rd_data;
input [15:0]data_begin;
input [15:0]rd_data_cnt;
begin
    rdfifo_rden = 1'b0;
    expect_rd_data = data_begin;
    @(posedge rdfifo_clk);
    #1 rdfifo_rden = 1'b1;
    repeat(rd_data_cnt)
    begin
        @(posedge rdfifo_clk);
        if(rdfifo_dout != expect_rd_data)
        begin
            $display("SIM is failed");
            $finish;
        end
        expect_rd_data = expect_rd_data + 1'b1;
    end
    #1 rdfifo_rden = 1'b0;
end
endtask

/*
先产生 DDR 控制器的复位以及 FIFO 的复位。
等 DDR 控制器内部锁相环锁定后,延时 200ns 后对 FIFO 解复位。
等待 DDR 初始化校准完成后,延时 200n 往 wr_ddr3_fifo 写入 1024 个数据,
数据写完后,对rd_ddr3_fifo 进行复位,清空里面的缓存,
等 FIFO 复位结束一段时间后,等待rd_ddr3_fifo 非空后开始对 rd_ddr3_fifo 进行读取数据,
读取 1024 个数据。整个仿真结束后打印“SIM is successfully”信息
*/


initial begin
    sys_rst = 1'b0;
    aresetn = 1'b0;
    expect_rd_data = 16'd0;
    wrfifo_clr = 1'b1;
    wrfifo_wren = 1'b0;
    wrfifo_din = 16'd0;
    rdfifo_clr = 1'b1;
    rdfifo_rden = 1'b0;
    #201;
    sys_rst = 1'b1;
    aresetn = 1'b1;
    @(posedge mmcm_locked);
    #200;
    wrfifo_clr = 1'b0;
    rdfifo_clr = 1'b0;
    @(posedge init_calib_complete);
    #200;
    wr_data(SIM_DATA_BEGIN,SIM_DATA_CNT);
    #2000;
    rdfifo_clr = 1'b1;
    #20;
    rdfifo_clr = 1'b0;
    #2000;
    wait(rdfifo_empty == 1'b0)
    rd_data(SIM_DATA_BEGIN,SIM_DATA_CNT);
    #5000;
    $display("SIM is successfully");
    $stop;
end

4.运行仿真

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/421539.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python统计分析——广义线性模型的评估

参考资料&#xff1a;用python动手学统计学 残差是表现数据与模型不契合的程度的重要指标。 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 导入绘图的库 import matplotlib.pyplot as plt i…

加密与安全_探索非对称加密算法_RSA算法

文章目录 Pre主流的非对称加密算法典型算法&#xff1a;RSACodeRSA的公钥和私钥的恢复小结 Pre 加密与安全_探索密钥交换算法&#xff08;Diffie-Hellman算法&#xff09; 中我们可以看到&#xff0c;公钥-私钥组成的密钥对是非常有用的加密方式&#xff0c;因为公钥是可以公开…

【Vue】npm run build 打包报错:请在[.env.local]中填入key后方可使用...

报错如下 根目录添加 .env.local 文件 .env.local &#xff1a;本地运行下的配置文件 配置&#xff1a;VUE_GITHUB_USER_NAME 及 VUE_APP_SECRET_KEY 原因

通过GitHub探索Python爬虫技术

1.检索爬取内容案例。 2.找到最近更新的。(最新一般都可以直接运行) 3.选择适合自己的项目&#xff0c;目前测试下面画红圈的是可行的。 4.方便大家查看就把代码粘贴出来了。 #图中画圈一代码 import requests import os import rewhile True:music_id input("请输入歌曲…

文本多分类

还在用BERT做文本分类&#xff1f;分享一套基于预训练模型ERNIR3.0的文本多分类全流程实例【文本分类】_ernir 文本分类-CSDN博客 /usr/bin/python3 -m pip install --upgrade pip python3-c"import platform;print(platform.architecture()[0]);print(platform.machine…

Mysql主从备份

主从复制概述 将主服务器的binlog日志复制到从服务器上执行一遍&#xff0c;达到主从数据的一致状态&#xff0c;称之为主从复制。一句话表示就是&#xff0c;主数据库做什么&#xff0c;从数据库就跟着做什么。 为什么要使用主从复制 为实现服务器负载均衡/读写分离做铺垫&…

Chrome插件 | WEB 网页数据采集和爬虫程序

无边无形的互联网遍地是数据&#xff0c;品类丰富、格式繁多&#xff0c;包罗万象。数据采集&#xff0c;或说抓取&#xff0c;就是把分散各处的内容&#xff0c;通过各种方式汇聚一堂&#xff0c;是个有讲究要思考的体力活。君子爱数&#xff0c;取之有道&#xff0c;得注意遵…

Tomcat 架构

一、Http工作原理 HTTP协议是浏览器与服务器之间的数据传送协议。作为应用层协议&#xff0c;HTTP是基于TCP/IP协议来传递数据的&#xff08;HTML文件、图片、查询结果等&#xff09;&#xff0c;HTTP协议不涉及数据包&#xff08;Packet&#xff09;传输&#xff0c;主要规定了…

Ai-WB2-32S在window下使用vs 和 msys2编译以及烧录

文章目录 前言一、使用前准备第一步 安装vscode第二步 安装msys2 二、使用步骤1.打开MSYS2 MINGW64&#xff08;1&#xff09;在开始栏中找到MSYS2 MINGW64并打开&#xff08;2&#xff09;安装git&#xff08;3&#xff09;安装make&#xff08;4&#xff09;安装好之后的文件…

端游如何防破解

在2023年这个游戏大年中&#xff0c;诸多热门大作涌现&#xff0c;作为世界级IP哈利哈利波特的衍生游戏——《霍格沃茨之遗》毫无悬念地成为2023年游戏圈的首款爆款作品&#xff0c;斩获了一众玩家的青睐。 在众多光环的加持下&#xff0c;《霍格沃茨之遗》很快被著名游戏破解…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《激发多元灵活性的数据中心协同优化运行方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 这篇文章标题表明&#xff0c;其主题…

网络防御第6次作业

防病毒网关 按照传播方式分类 病毒 病毒是一种基于硬件和操作系统的程序&#xff0c;具有感染和破坏能力&#xff0c;这与病毒程序的结构有关。病毒攻击的宿主程序是病毒的栖身地&#xff0c;它是病毒传播的目的地&#xff0c;又是下一次感染的出发点。计算机病毒感染的一般过…

持安科技亮相张江高科895创业营,总评分第三名荣获「最具创新性企业」!

近日&#xff0c;张江高科895创业营&#xff08;第十三季&#xff09;信息安全专场Demo day&结营仪式在上海集成电路设计产业园圆满落幕。本季创业营通过多种渠道在海内外甄选优秀创业项目&#xff0c;一共择优录取了29家入营&#xff0c;最终甄选出9家代表参加Demo day路演…

安装ProxySQL,教程及安装链接(网盘自提)

一、网盘下载&#xff0c;本地直传 我网盘分享的是proxysql-2.5.5-1-centos8.x86_64.rpm&#xff0c;yum或者dnf直接安装就行 提取码&#xff1a;rhelhttps://pan.baidu.com/s/1nmx8-h8JEhrxQE3jsB7YQw 官方安装地址 官网下载地址https://repo.proxysql.com/ProxySQL/ 二、…

c# cad2016系统变量解释说明

一、cad系统变量设置和获取 /// <summary> /// 设置CAD系统变量 /// </summary> /// <param name"name">变量名</param> /// <param name"value">变量值</param> public static void SetSystemVariable(string name,…

[pdf]《软件方法》2024版部分公开-共196页

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 潘加宇《软件方法》2024版部分公开pdf文件&#xff0c;共196页&#xff0c;已上传CSDN资源。 也可到以下地址下载&#xff1a; http://www.umlchina.com/url/softmeth2024.html 如果…

DDOS攻击处理方法

DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一种网络攻击&#xff0c;攻击者通过发送大量的请求&#xff0c;超过目标服务器的处理能力&#xff0c;导致服务器服务不可用。本文将介绍如何处理DDoS攻击&#xff0c;并提供几种防范措施。 1. 认识DDoS攻击 DDoS攻击通常通过…

JAVA对象内存模型

Java对象内存模型 > 一个Java对象在内存中包括3个部分&#xff1a;对象头、实例数据和对齐填充 > > 数据 内存 – CPU 寄存器 -127 补码 10000001 - 11111111 32位的处理器 一次能够去处理32个二进制位 4字节的数据 64位操作系统 8字节 2的64次方的寻址空间 指针压…

mac 本地使用dockerfile启动 springboot项目

1.创建Dockerfile放在项目的根目录下 2.编写Dockerfile FROM openjdk:11 MAINTAINER ChengLinADD target/JiaLi-0.0.1-SNAPSHOT.jar /app.jar# 暴露 Spring Boot 应用的端口号 EXPOSE 8088 # 启动 Spring Boot 应用 CMD ["java", "-jar", "app.jar&q…

机器学习 | 模型性能评估

目录 一. 回归模型的性能评估1. 平均平方误差(MSE)2. 平均绝对误差(MAE)3. R 2 R^{2} R2 值3.1 R 2 R^{2} R2优点 二. 分类模型的性能评估1. 准确率&#xff08;Accuracy&#xff09;2. 召回率&#xff08;Recall&#xff09;3. 精确率&#xff08;Precision&#xff09;4. …