首页 > 其他分享 >Xilinxddr3 mig ip核:基于AXI接口的ddr3读写控制

Xilinxddr3 mig ip核:基于AXI接口的ddr3读写控制

时间:2024-06-19 20:24:46浏览次数:23  
标签:Xilinxddr3 wire ip fifo axi rd mig AXI wr

  本文完全参考野火的DDR3读写控制设计,原文十分详细,需要的可以去看看。


一、AXI4接口详解

  AXI接口由5个独立的通道构成,分别是读地址、读数据、写地址、写数据、写响应。
  如下是读传输过程示意图,使用读地址与读数据通道。主机首先在读地址通道给出读地址和控制信号,然后从机由读数据通道返回读出的数据。且可以看到,主机只给出了一个地址,从该地址连续突发读出4个数据。

  写传输过程如下图所示。使用写地址、写数据和写响应三个通道。主机在写地址通道给出写地址和控制信号,然后在写数据通道连续突发写四个数据。从机在接收数据之后,在写响应通道给出响应信号。

  如下图是AXI4的接口描述,左侧是IP核生成的接口信号,括号里的是本工程定义的信号。可以发现,接口信号中以“s_axi_aw”开头的是写地址通道信号,以“s_axi_w”开头的是写数据通道信号,以“s_axi_b”开头的是写响应通道信号,以“s_axi_ar”开头的是读地址通道信号,以“s_axi_r”开头的是读数据响应通道信号。


  这里也顺便将DDR3 IP核所有的接口描述一下。带ddr3的信号是引脚信号,与外部ddr3存储器相连,不需要管;带app的信号是本地接口维护命令信号,不用使用,输入信号给0,输出信号空接;带ui的信号是给用户侧使用的时钟信号和复位信号,注意复位信号是高电平有效;sys_clk_i是ip核系统时钟,一般设置为200M,这样参考时钟可以选择use system clk,所以这里的clk_ref_i被注释了;还要注意ip系统复位输入信号sys_rst,是低电平有效。

突发写时序

  写数据时序图如下。

  AXI4突发写可以分为7个状态,分别为:
  1.写空闲:等待突发写触发信号。
  2.写通道地址等待:准备好写地址AWADDR,然后拉高AWVALID。
  3.写通道写地址:从机接受到AWVALID,发出AWREADY。
  4.写数据等待:准备好写数据WDATA,拉高WVALID。
  5.写数据循环:从机接受WVALID,确认数据WDATA有效并且接受,发出WREADY,AXI是突发传输:循环该操作到接受到WLAST最后一个数据标志位。
  6.接受写应答:接受到从机发出的BVALID,主机发出BREADY。
  7.写结束:拉低未拉低的信号,进入写空闲。

突发读时序

  读数据时序图如下。

  AXI4突发读可以分为6个状态,分别为:
  1.读空闲:等待突发读触发信号。
  2.读通道写地址等待:准备好写地址ARADDR,然后拉高ARVALID。
  3.读通道写地址:从机接收到ARVALID,发出ARREADY。
  4.读数据等待:从机准备好读数据RDATA,并拉高RVALID。
  5.读数据循环:主机接收RVALID,确认数据RDATA有效并接收,发出RREADY给从机,AXI是突发传输:循环该操作到接收到RLAST最后一个数据标志位。
  6.读结束:拉低未拉低的信号,进入读空闲。

接口信号详解

  • VALID和READY信号:AXI接口的读写在于握手信号VALID与READY。VALID信号由源端产生,表示当前地址或数据线上的信息是有效的;READY信号由目的端产生,表示已经准备好接收地址、数据以及控制信息。VALID和READY信号提供了3种握手机制,即VALIDbeforeREADY握手,READYbeforeVALID握手,VALIDwithREADY握手。
  • AWID与ARID:对于只有一个主从设备,该值可设置为任意值。
  • AWADDR与ARADDR:主机只给出突发传输第一个字节的地址,从机必须计算突发传输后续的地址。突发传输不能跨4KB边界。这是因为每一个从机分配的是4KB空间。以32位地址为例,[31:12]相等的地址都是同一个page,没有跨4K边界。即[11:0]可以为0~0xFFF。 例如0x1000和0x2000就是在不同的page,跨了4K边界。0x1000和0x1FFF则是在同一个page,没有跨4K边界。同理,0x1FFF和0x2000,虽然他们是相邻的byte,但也跨了4K边界。所以,这是为了防止一次突发跨越两个从机的边界。
  • AWLEN与ARLEN:读写传输的突发长度。突发长度==AxLEN[7:0]+1。
  • ARSIZE与AWSIZE:读写突发传输大小。突发大小==2^(AxSIZE[2:0])字节。
  • AWBURST与ARBURST:突发类型。2'b00:FIXED,2'b01:INCR,2'b10:WRAP,2'b11:Reserved。FIXED:突发传输过程中地址固定;INCR:增量突发,传输过程中,地址递增,增加量取决于AxSIZE的值。WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。
  • WSTRB:有效字节,WSTRB[n:0]对应于对应的写字节,WSTRB[n]对应WDATA[8n+7:8n],也就是对于的数据宽度的字节数是否有效。对于一般应用,将WSTRB全部置1即可,保证全部数据有效。读通道无该信号。
  • WLAST与RLAST:拉高表示传输最后一个数据,意味着传输结束。

IP核配置

  选择AXI4 Interface。

  Data Width根据开发板板载DDR3数据位宽设置即可,在我们的程序设计中没有体现,关注点还应该是AXI。

  接下来是AXI接口的参数配置界面,本工程将AXI的Data_Width设置为64。

  200M的IP核系统时钟。

  参考时钟选择系统时钟。

  这里选择第二个。

  其他选项保持默认即可,生成IP核。
  这里强调一点,AXI接口的地址是一个字节一个地址的,千万不要和native接口的ddr芯片的地址混淆。


二、代码设计

  模块框图如下。具体流程为:用户将需要存储的数据存入写fifo,axi_ctrl模块根据写fifo的状态产生写突发信号控制axi_master_write模块,完成写操作;用户给出读请求,axi_ctrl模块根据读fifo的状态产生读突发信号控制axi_master_read模块,完成读操作。

axi_master_write模块

点击查看代码
module axi_master_write
(
  input           ARESETN    , //axi复位
  input           ACLK       , //axi总时钟
//axi4写通道地址通道
  output [3:0]  M_AXI_AWID   , //写地址ID,用来标志一组写信号
  output [31:0] M_AXI_AWADDR , //写地址,给出一次写突发传输的写地址
  output [7:0]  M_AXI_AWLEN  , //突发长度,给出突发传输的次数  
  output [2:0]  M_AXI_AWSIZE , //突发大小,给出每次突发传输的字节数  
  output [1:0]  M_AXI_AWBURST, //突发类型  
  output        M_AXI_AWLOCK , //总线锁信号,可提供操作的原子性  
  output [3:0]  M_AXI_AWCACHE, //内存类型,表明一次传输是怎样通过系统的  
  output [2:0]  M_AXI_AWPROT , //保护类型,表明一次传输的特权级及安全等级  
  output [3:0]  M_AXI_AWQOS  , //质量服务QoS     
  output        M_AXI_AWVALID, //有效信号,表明此通道的地址控制信号有效
  input         M_AXI_AWREADY, //表明“从”可以接收地址和对应的控制信号
//axi4写通道数据通道
  output [63:0] M_AXI_WDATA  , //写数据
  output [7:0]  M_AXI_WSTRB  , //写数据有效的字节线
  output        M_AXI_WLAST  , //表明此次传输是最后一个突发传输
  output        M_AXI_WVALID , //写有效,表明此次写有效
  input         M_AXI_WREADY , //表明从机可以接收写数据
//axi4写通道应答通道
  input [3:0]   M_AXI_BID    , //写响应ID TAG
  input [1:0]   M_AXI_BRESP  , //写响应,表明写传输的状态
  input         M_AXI_BVALID , //写响应有效
  output        M_AXI_BREADY , //表明主机能够接收写响应
  //用户端信号
  input         WR_START     , //写突发触发信号
  input [31:0]  WR_ADRS      , //地址  
  input [9:0]   WR_LEN       , //长度
  output        WR_READY     , //写空闲
  output        WR_FIFO_RE   , //连接到写fifo的读使能
  input [63:0]  WR_FIFO_DATA , //连接到fifo的读数据
  output        WR_DONE        //完成一次突发
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

localparam S_WR_IDLE  = 3'd0;//写空闲
localparam S_WA_WAIT  = 3'd1;//写地址等待
localparam S_WA_START = 3'd2;//写地址
localparam S_WD_WAIT  = 3'd3;//写数据等待
localparam S_WD_PROC  = 3'd4;//写数据循环
localparam S_WR_WAIT  = 3'd5;//接受写应答
localparam S_WR_DONE  = 3'd6;//写结束
//reg define  
reg [2:0]   wr_state   ; //状态寄存器
reg [31:0]  reg_wr_adrs; //地址寄存器
reg         reg_awvalid; //地址有效握手信号
reg         reg_wvalid ; //数据有效握手信号
reg         reg_w_last ; //传输最后一个数据
reg [7:0]   reg_w_len  ; //突发长度最大256,实测128最佳

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//写完成信号的写状态完成
assign WR_DONE = (wr_state == S_WR_DONE);
//写fifo的读使能为axi数据握手成功
assign WR_FIFO_RE         = ((reg_wvalid & M_AXI_WREADY ));
//只有一个主机,可随意设置
assign M_AXI_AWID         = 4'b1111;
//把地址赋予总线
assign M_AXI_AWADDR[31:0] = reg_wr_adrs[31:0];
//一次突发传输1长度
assign M_AXI_AWLEN[7:0]   = WR_LEN-'d1;
//表示AXI总线每个数据宽度是8字节,64位
assign M_AXI_AWSIZE[2:0]  = 3'b011;
//01代表地址递增,10代表递减
assign M_AXI_AWBURST[1:0] = 2'b01; 
assign M_AXI_AWLOCK       = 1'b0;
assign M_AXI_AWCACHE[3:0] = 4'b0000;
assign M_AXI_AWPROT[2:0]  = 3'b000;
assign M_AXI_AWQOS[3:0]   = 4'b0000;
//地址握手信号AWVALID
assign M_AXI_AWVALID      = reg_awvalid;
//fifo数据赋予总线
assign M_AXI_WDATA[63:0]  = WR_FIFO_DATA[63:0];
assign M_AXI_WSTRB[7:0]   = 8'hFF;
//写到最后一个数据
assign M_AXI_WLAST        =(reg_w_len[7:0] == 8'd0)?'b1:'b0;
//数据握手信号WVALID
assign M_AXI_WVALID       = reg_wvalid;
//这个信号是告诉AXI我收到你的应答
assign M_AXI_BREADY       = M_AXI_BVALID;
//axi状态机空闲信号
assign WR_READY           = (wr_state == S_WR_IDLE)?1'b1:1'b0;

//axi写过程状态机
  always @(posedge ACLK or negedge ARESETN) begin
    if(!ARESETN) begin
      wr_state            <= S_WR_IDLE;
      reg_wr_adrs[31:0]   <= 32'd0;
      reg_awvalid         <= 1'b0;
      reg_wvalid          <= 1'b0;
      reg_w_last          <= 1'b0;
      reg_w_len[7:0]      <= 8'd0;
      
  end else begin
      case(wr_state)
        S_WR_IDLE: begin //写空闲
          if(WR_START) begin //触发写过程
            wr_state          <= S_WA_WAIT;
            reg_wr_adrs[31:0] <= WR_ADRS[31:0];
          end
          reg_awvalid         <= 1'b0;
          reg_wvalid          <= 1'b0;
          reg_w_len[7:0]      <= 8'd0;
        end
        S_WA_WAIT: begin//写地址等待
          wr_state        <= S_WA_START;//等待一个周期
        end
        S_WA_START: begin
          wr_state        <= S_WD_WAIT;//写数据等待
          reg_awvalid     <= 1'b1; //拉高地址有效信号 
          reg_wvalid      <= 1'b1;//拉高数据有效信号
        end
        S_WD_WAIT: begin
          if(M_AXI_AWREADY) begin//等待写地址就绪
            wr_state        <= S_WD_PROC;
            reg_w_len<=WR_LEN-'d1;//127代表128个长度,0代表1个长度
            reg_awvalid     <= 1'b0;
          end
        end
        S_WD_PROC: begin//等待AXI写数据就绪信号
          if(M_AXI_WREADY) begin//拉高了就可以输出fifo使能信号开始读
            
            if(reg_w_len[7:0] == 8'd0) begin//完成数据写过程
              wr_state        <= S_WR_WAIT;
              reg_wvalid      <= 1'b0;//此信号拉低,写fifo读使能无效
              reg_w_last<='b1;
              //读到最后一个数据,拉高这个标志信号告诉AXI总线这是最后一个
              //如果不拉高传输不会成功
            end           
            else begin
              reg_w_len[7:0]  <= reg_w_len[7:0] -8'd1;
            end
          end
        end
        S_WR_WAIT: begin//等待写的AXI应答信号
          reg_w_last<='b0;
          //M_AXI_BVALID拉高表示写成功,然后状态机完成一次突发传输
          if(M_AXI_BVALID) begin
              wr_state          <= S_WR_DONE;
          end
        end
        S_WR_DONE: begin //写完成           
            wr_state <= S_WR_IDLE;
          end
        
        default: begin
          wr_state <= S_WR_IDLE;
        end
      endcase
      end
  end

endmodule
  该模块所有的AXI接口模块都用组合逻辑赋值,根据与axi_ctrl模块交互的用户端信号来进行突发写传输。整体编写思路就是前面所说的7个状态的状态机。写数据状态,当当前写数据是最后一个时,需要即时拉低reg_wvalid信号,拉低写fifo的读使能。写fifo的读数据是直接通过组合逻辑给AXI接口的。

axi_master_read模块

点击查看代码
module axi_master_read
(
  input           ARESETN,//axi复位
  input           ACLK,  //axi时钟
//axi读通道写地址
  output [3:0]  M_AXI_ARID   , //读地址ID,用来标志一组写信号
  output [31:0] M_AXI_ARADDR , //读地址,给出一次写突发传输的读地址
  output [7:0]  M_AXI_ARLEN  , //突发长度,给出突发传输的次数
  output [2:0]  M_AXI_ARSIZE , //突发大小,给出每次突发传输的字节数
  output [1:0]  M_AXI_ARBURST, //突发类型
  output [1:0]  M_AXI_ARLOCK , //总线锁信号,可提供操作的原子性
  output [3:0]  M_AXI_ARCACHE, //内存类型,表明一次传输是怎样通过系统的
  output [2:0]  M_AXI_ARPROT , //保护类型,表明一次传输的特权级及安全等级
  output [3:0]  M_AXI_ARQOS  , //质量服务QOS
  output        M_AXI_ARVALID, //有效信号,表明此通道的地址控制信号有效
  input         M_AXI_ARREADY, //表明“从”可以接收地址和对应的控制信号
    
  //axi读通道读数据
  input [3:0]   M_AXI_RID   , //读ID tag
  input [63:0]  M_AXI_RDATA , //读数据
  input [1:0]   M_AXI_RRESP , //读响应,表明读传输的状态
  input         M_AXI_RLAST , //表明读突发的最后一次传输
  input         M_AXI_RVALID, //表明此通道信号有效
  output        M_AXI_RREADY, //表明主机能够接收读数据和响应信息
   //用户端fifo接口    
  input         RD_START    , //读突发触发信号
  input [31:0]  RD_ADRS     , //地址  
  input [9:0]   RD_LEN       , //长度
  output        RD_READY    , //读空闲
  output        RD_FIFO_WE  , //连接到读fifo的写使能
  output [63:0] RD_FIFO_DATA, //连接到读fifo的写数据
  output        RD_DONE       //完成一次突发
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//parameter  define
localparam S_RD_IDLE  = 3'd0; //读空闲
localparam S_RA_WAIT  = 3'd1; //读地址等待
localparam S_RA_START = 3'd2; //读地址
localparam S_RD_WAIT  = 3'd3; //读数据等待
localparam S_RD_PROC  = 3'd4; //读数据循环
localparam S_RD_DONE  = 3'd5; //写结束
//reg define                               
reg [2:0]   rd_state   ; //状态寄存器
reg [31:0]  reg_rd_adrs; //地址寄存器
reg [31:0]  reg_rd_len ; //突发长度寄存器
reg         reg_arvalid; //地址有效寄存器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

assign RD_DONE = (rd_state == S_RD_DONE) ;
assign M_AXI_ARID         = 4'b1111;//地址id
assign M_AXI_ARADDR[31:0] = reg_rd_adrs[31:0];//地址
assign M_AXI_ARLEN[7:0]   = RD_LEN-32'd1;//突发长度
assign M_AXI_ARSIZE[2:0]  = 3'b011;//表示AXI总线每个数据宽度是8字节,64位
assign M_AXI_ARBURST[1:0] = 2'b01;//地址递增方式传输
assign M_AXI_ARLOCK       = 1'b0;
assign M_AXI_ARCACHE[3:0] = 4'b0000;
assign M_AXI_ARPROT[2:0]  = 3'b000;
assign M_AXI_ARQOS[3:0]   = 4'b0000;
assign M_AXI_ARVALID      = reg_arvalid;
assign M_AXI_RREADY       = M_AXI_RVALID;
assign RD_READY           = (rd_state == S_RD_IDLE)?1'b1:1'b0;//读空闲
assign RD_FIFO_WE         = M_AXI_RVALID;//读fifo的写使能信号
assign RD_FIFO_DATA[63:0] = M_AXI_RDATA[63:0];//读fifo的写数据信号 

  // 读状态机
  always @(posedge ACLK or negedge ARESETN) begin
    if(!ARESETN) begin
      rd_state          <= S_RD_IDLE;
      reg_rd_adrs[31:0] <= 32'd0;
      reg_rd_len[31:0]  <= 32'd0;
      reg_arvalid       <= 1'b0;
    end else begin
      case(rd_state)
        S_RD_IDLE: begin//读空闲
          if(RD_START) begin//突发触发信号
            rd_state          <= S_RA_WAIT;
            reg_rd_adrs[31:0] <= RD_ADRS[31:0];
            reg_rd_len[31:0]  <= RD_LEN[9:0] -32'd1;
          end
          reg_arvalid     <= 1'b0;
        end
        S_RA_WAIT: begin//写地址等待
            rd_state          <= S_RA_START;
        end
        S_RA_START: begin//写地址
          rd_state          <= S_RD_WAIT;
          reg_arvalid       <= 1'b1;//拉高地址有效
        end
        S_RD_WAIT: begin //读取数据等待
          if(M_AXI_ARREADY) begin
            rd_state        <= S_RD_PROC;
            reg_arvalid     <= 1'b0;//握手成功就拉低
          end
        end
        S_RD_PROC: begin //接受循环
          if(M_AXI_RVALID) begin //收到数据有效,握手成功
            if(M_AXI_RLAST) begin //收到最后一个数据
                rd_state<= S_RD_DONE;
            end
          end
        end
    S_RD_DONE:begin 
      rd_state          <= S_RD_IDLE;
    end
    endcase
    end
  end
   
endmodule
  每当AXI接口的读数据发送出来,都直接传给读fifo的写数据端了。

axi_ctrl模块

点击查看代码
module axi_ctrl
#(
parameter  DDR_WR_LEN=128,//写突发长度 128个64bit
parameter  DDR_RD_LEN=128 //读突发长度 128个64bit

)
(
   input   wire        ui_clk     , //时钟
   input   wire        ui_rst     , //复位,高电平有效
   input   wire        pingpang   ,   //乒乓操作
   //写fifo写数据端
   input   wire [31:0] wr_b_addr  ,   //写DDR首地址
   input   wire [31:0] wr_e_addr  ,   //写DDR末地址
   input   wire        user_wr_clk,   //写FIFO写时钟
   input   wire        data_wren  ,   //写FIFO写请求
   //写进fifo数据长度,可根据写fifo的写端口数据长度自行修改
   //写FIFO写数据 16位,此时用64位是为了兼容32,64位
   input   wire [63:0] data_wr    ,    
   input   wire        wr_rst     ,
   
   //读fifo读数据端
   input   wire [31:0] rd_b_addr  ,   //读DDR首地址
   input   wire [31:0] rd_e_addr  ,   //读DDR末地址    
   input   wire        user_rd_clk,   //读FIFO读时钟
   input   wire        data_rden  ,   //读FIFO读请求  
   //读出fifo数据长度,可根据读fifo的读端口数据长度自行修改
   //读FIFO读数据,16位,此时用64位是为了兼容32,64位
   output  wire [63:0] data_rd    ,   
   input   wire        rd_rst     ,
   input   wire        read_enable,//读ddr使能
   output  wire        data_rd_valid,
   //突发写模块控制信号   
   output  wire        wr_burst_req    , //写突发触发信号
   output  wire[31:0]  wr_burst_addr   , //地址  
   output  wire[9:0]   wr_burst_len    , //长度
   input   wire        wr_ready        , //写空闲
   input   wire        wr_fifo_re      , //连接到写fifo的读使能
   output  wire [63:0] wr_fifo_data    , //连接到fifo的读数据
   input   wire        wr_burst_finish , //完成一次突发
    //突发读模块控制信号                                 
   output  wire        rd_burst_req    , //读突发触发信号
   output  wire[31:0]  rd_burst_addr   , //地址  
   output  wire[9:0]   rd_burst_len    ,  //长度
   input   wire        rd_ready        , //读空闲
   input   wire        rd_fifo_we      , //连接到读fifo的写使能
   input   wire[63:0]  rd_fifo_data    , //连接到读fifo的写数据
   input   wire        rd_burst_finish   //完成一次突发
   );
 
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg       wr_burst_req_reg ; //写突发寄存器
reg [31:0]wr_burst_addr_reg; //写地址寄存器
reg [9:0] wr_burst_len_reg ; //写长度寄存器

reg       rd_burst_req_reg ; //读突发寄存器
reg [31:0]rd_burst_addr_reg; //读地址寄存器
reg [9:0] rd_burst_len_reg ; //读长度寄存器
//读写地址复位打拍寄存器
reg wr_rst_reg1;
reg wr_rst_reg2;
reg rd_rst_reg1;
reg rd_rst_reg2;

reg pingpang_reg;//乒乓操作指示寄存器

//wire define
//写fifo信号
wire        wr_fifo_wr_clk        ;
wire        wr_fifo_rd_clk        ;
wire [63:0] wr_fifo_din           ;
wire        wr_fifo_wr_en         ;
wire        wr_fifo_rd_en         ;
wire [63:0] wr_fifo_dout          ;
wire        wr_fifo_full          ;
wire        wr_fifo_almost_full   ;
wire        wr_fifo_empty         ;
wire        wr_fifo_almost_empty  ;
wire  [9:0] wr_fifo_rd_data_count ;
wire  [11:0] wr_fifo_wr_data_count;

//读fifo信号
wire        rd_fifo_wr_clk        ;
wire        rd_fifo_rd_clk        ;
wire [63:0] rd_fifo_din           ;
wire        rd_fifo_wr_en         ;
wire        rd_fifo_rd_en         ;
wire [63:0] rd_fifo_dout          ;
wire        rd_fifo_full          ;
wire        rd_fifo_almost_full   ;
wire        rd_fifo_empty         ;
wire        rd_fifo_almost_empty  ;
wire  [11:0]rd_fifo_rd_data_count ;
wire  [9:0] rd_fifo_wr_data_count ;

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

assign wr_burst_req  = wr_burst_req_reg;  //写突发请求
assign wr_burst_addr = wr_burst_addr_reg; //写地址
assign wr_burst_len  = DDR_WR_LEN;        //写长度

assign rd_burst_req  = rd_burst_req_reg;  //读突发请求
assign rd_burst_addr = rd_burst_addr_reg; //读地址
assign rd_burst_len  = DDR_RD_LEN;        //读长度

//写fifo写时钟位用户端时钟
assign wr_fifo_wr_clk = user_wr_clk;
//写fifo读时钟位axi总时钟
assign wr_fifo_rd_clk = ui_clk;     //axi接口时钟是ui_clk
//写fifo非满为用户输入数据        
assign wr_fifo_din    = data_wr;   
//写fifo非满为用户输入数据使能
assign wr_fifo_wr_en  = data_wren;
//写fifo非空为axi写主机读取使能
assign wr_fifo_rd_en  = wr_fifo_re;
//写fifo非空为axi写主机读取数据
assign wr_fifo_data   = wr_fifo_dout;
//读fifo写时钟位axi读主机时钟
assign rd_fifo_wr_clk=ui_clk;   //axi接口时钟是ui_clk
//读fifo读时钟位用户时钟
assign rd_fifo_rd_clk=user_rd_clk;
//读fifo读使能为用户使能
assign rd_fifo_rd_en =data_rden;
//读fifo读数据为用户使能
assign data_rd       =rd_fifo_dout;
//读fifo写使能为axi读主机写使能
assign rd_fifo_wr_en =rd_fifo_we;
//读fifo写使能为axi读主机写数据
assign rd_fifo_din   =rd_fifo_data;

assign data_rd_valid=~rd_fifo_empty;

//对写复位信号的跨时钟域打2拍
always@(posedge ui_clk or posedge ui_rst) begin
    if(ui_rst==1'b1)begin
        wr_rst_reg1<=1'b0;
        wr_rst_reg2<=1'b0;
    end
    else begin
        wr_rst_reg1<=wr_rst;
        wr_rst_reg2<=wr_rst_reg1;
    end

end

//对读复位信号的跨时钟域打2拍
always@(posedge ui_clk or posedge ui_rst) begin
    if(ui_rst==1'b1)begin
        rd_rst_reg1<=1'b0;
        rd_rst_reg2<=1'b0;
    end
    else begin
        rd_rst_reg1<=rd_rst;
        rd_rst_reg2<=rd_rst_reg1;
    end

end


//写burst请求产生
always@(posedge ui_clk or posedge ui_rst) begin
    if(ui_rst==1'b1)begin
        wr_burst_req_reg<=1'b0;    
    end
    //fifo数据长度大于一次突发长度并且axi写空闲
    else if((wr_fifo_rd_data_count+9'd2)>=DDR_WR_LEN && wr_ready==1'b1 ) begin 
        wr_burst_req_reg<=1'b1;      
    end
    else begin
        wr_burst_req_reg<=1'b0;
    end
end

//完成一次突发对地址进行相加
//相加地址长度=突发长度x8,64位等于8字节
//128*8=1024
always@(posedge ui_clk or posedge ui_rst) begin
    if(ui_rst==1'b1)begin
        wr_burst_addr_reg<=wr_b_addr;
        pingpang_reg<=1'b0;  
    end
    //写复位信号上升沿
    else if(wr_rst_reg1&(~wr_rst_reg2)) begin
        wr_burst_addr_reg<=wr_b_addr;
    end 
    else if(wr_burst_finish==1'b1)begin
        wr_burst_addr_reg<=wr_burst_addr_reg+DDR_WR_LEN*8;
        //判断是否是乒乓操作
        if(pingpang==1'b1) begin
        //结束地址为2倍的接受地址,有两块区域
            if(wr_burst_addr_reg>=(
            (wr_e_addr-wr_b_addr)*2+wr_b_addr-DDR_WR_LEN*8)) 
            begin
                wr_burst_addr_reg<=wr_b_addr;
            end
            //根据地址,pingpang_reg为0或者1
            //用于指示读操作与写操作地址不冲突
            if(wr_burst_addr_reg<wr_e_addr) begin
                pingpang_reg<=1'b0;
            end
            else begin
                pingpang_reg<=1'b1;
            end
        end
        //非乒乓操作
        else begin
            if(wr_burst_addr_reg>=(wr_e_addr-DDR_WR_LEN*8)) 
            begin
                wr_burst_addr_reg<=wr_b_addr;
            end
        end
    end
    else begin
        wr_burst_addr_reg<=wr_burst_addr_reg;
    end

end

//读burst请求产生
always@(posedge ui_clk or posedge ui_rst) begin
    if(ui_rst==1'b1)begin
        rd_burst_req_reg<=1'b0;
    end
    //fifo可写长度大于一次突发长度并且axi读空闲,fifo总长度1024
    else if(rd_fifo_wr_data_count<=(10'd1000-DDR_RD_LEN) 
            && rd_ready==1'b1 &&read_enable==1'b1) 
    begin
        rd_burst_req_reg<=1'b1;
    end
    else begin
        rd_burst_req_reg<=1'b0;
    end
end

//完成一次突发对地址进行相加
//相加地址长度=突发长度x8,64位等于8字节
//128*8=1024
always@(posedge ui_clk or posedge ui_rst) begin
    if(ui_rst==1'b1)begin
        if(pingpang==1'b1) rd_burst_addr_reg<=rd_e_addr;
        else rd_burst_addr_reg<=rd_b_addr;
    end
    else if(rd_rst_reg1&(~rd_rst_reg2)) begin
        rd_burst_addr_reg<=rd_b_addr;
    end 
    else if(rd_burst_finish==1'b1)begin
          rd_burst_addr_reg<=rd_burst_addr_reg+DDR_RD_LEN*8;//地址累加
        //乒乓操作
         if(pingpang==1'b1) begin
           //到达结束地址 
           if((rd_burst_addr_reg==(rd_e_addr-DDR_RD_LEN*8))||
    (rd_burst_addr_reg==((rd_e_addr-rd_b_addr)*2+rd_b_addr-DDR_RD_LEN*8))) 
           begin
                //根据写指示地址信号,对读信号进行复位
               if(pingpang_reg==1'b1) rd_burst_addr_reg<=rd_b_addr;
               else rd_burst_addr_reg<=rd_e_addr;
           end
                    
        end
        else begin  //非乒乓操作
            if(rd_burst_addr_reg>=(rd_e_addr-DDR_RD_LEN*8)) 
            begin
            rd_burst_addr_reg<=rd_b_addr;
            end
        end
    end
    else begin
        rd_burst_addr_reg<=rd_burst_addr_reg;
    end

end

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- wr_fifo_inst -------------
//写fifo
wr_fifo wr_fifo_inst (
  .wr_rst(wr_rst||ui_rst), // 写复位
  .rd_rst(wr_rst||ui_rst), //读复位
  .wr_clk(wr_fifo_wr_clk), // 写时钟
  .rd_clk(wr_fifo_rd_clk), // 读时钟
  .din   (wr_fifo_din   ), // 外部写进fifo的数据 16位
  .wr_en (wr_fifo_wr_en ), // 写使能
  .rd_en (wr_fifo_rd_en ), // 读使能
  .dout  (wr_fifo_dout  ), // 输出给ddr的axi写数据,写进ddr 64位
  .full  (wr_fifo_full  ), // fifo满信号
  .almost_full  (wr_fifo_almost_full  ), //fifo几乎满信号
  .empty (wr_fifo_empty ), //fifo空信号 
  .almost_empty (wr_fifo_almost_empty ),
  .rd_data_count(wr_fifo_rd_data_count), // 可读数据个数
  .wr_data_count(wr_fifo_wr_data_count)  // 可写数据个数
);

//------------- rd_fifo_inst -------------
//读fifo
rd_fifo rd_fifo_inst (
  .wr_rst(rd_rst||ui_rst), // 写复位
  .rd_rst(rd_rst||ui_rst), //读复位
  .wr_clk(rd_fifo_wr_clk), // 写时钟
  .rd_clk(rd_fifo_rd_clk), // 读时钟
  .din   (rd_fifo_din   ), // ddr读出的数据,写进fifo 64位
  .wr_en (rd_fifo_wr_en ), // 写使能
  .rd_en (rd_fifo_rd_en ), // 读使能
  .dout  (rd_fifo_dout  ), // 最终我们读出的数据 64位
  .full  (rd_fifo_full  ), // fifo满信号
  .almost_full  (rd_fifo_almost_full  ),//fifo几乎满信号
  .empty (rd_fifo_empty ), //空信号
  .almost_empty (rd_fifo_almost_empty ),
  .rd_data_count(rd_fifo_rd_data_count), // 可读数据个数
  .wr_data_count(rd_fifo_wr_data_count)  // 可写数据个数
);

endmodule
  对于突发写请求的产生,当写fifo中的读数据长度大于一次突发长度且此时axi写空闲,产生写突发请求信号。因为rd_data_count和wr_data_count永远不会报告比实际数据量更小的数字,所以这里不加2也可以,因为生成IP核时没有点more accurate count,所以报告的数据量比实际的数据量少2个。产生第一次写突发后,将突发长度、突发地址(第一次即为首地址)传输给突发写模块,接下来写突发模块会产生读写fifo使能信号,然后产生突发完成信号,axi_ctrl模块检测到突发完成信号,需要进行突发地址的更新,即在上次突发地址的基础上加上突发长度 * AXI数据位宽 / 8,因为AXI地址是一个字节一个地址。更新地址完成,还需判断是否超过用户设置的结束地址,若超过,则需将突发地址设置为起始地址。然后等待下一次的写突发请求信号。这里野火的代码加了一个乒乓操作时的地址更新,不用管他,将pingpang设置为零即可。  

  对于读突发请求的产生,也是一样的道理,当读fifo中的可写数据长度大于一次突发长度并且axi读空闲,且用户侧给ddr3读使能read_enable有效,就拉高突发读请求。代码中fifo总长度设置的是1024,所以用了一个1000,这个数据要求并不严格,只要能保证我再进行一次突发。不会将读fifo存满即可。突发读模块检测到有效信号开始突发读,读出的数据直接存进读fifo中,当检测到突发读完成信号,就需要更新突发地址。

axi_ddr_top模块

  该模块将各个模块以及IP核集成,封装成一个类FIFO的结构。

点击查看代码
module axi_ddr_top #
(
parameter  DDR_WR_LEN=128,//写突发长度 最大128个64bit
parameter  DDR_RD_LEN=128//读突发长度 最大128个64bit
)

(
    //50m的时钟与复位信号
    input wire ddr3_clk          , //ddr3 ip核时钟200M
    input wire sys_rst_n         , //外部复位
       
    inout  [31:0] ddr3_dq        , //数据线
    inout  [3:0]  ddr3_dqs_n     , //数据选取脉冲差分信号
    inout  [3:0]  ddr3_dqs_p     , //数据选取脉冲差分信号
    output [14:0] ddr3_addr      , //地址线
    output [2:0]  ddr3_ba        , //bank线
    output        ddr3_ras_n     , //行使能信号,低电平有效
    output        ddr3_cas_n     , //列使能信号,低电平有效
    output        ddr3_we_n      , //写使能信号,低电平有效
    output        ddr3_reset_n   , //ddr3复位
    output [0:0]  ddr3_ck_p      , //ddr3差分时钟
    output [0:0]  ddr3_ck_n      , //ddr3差分时钟
    output [0:0]  ddr3_cke       , //ddr3时钟使能信号
    output [0:0]  ddr3_cs_n      , //ddr3片选信号
    output [3:0]  ddr3_dm        , //ddr3掩码
    output [0:0]  ddr3_odt       , //odt阻抗
    
    input   wire      pingpang   , //乒乓操作,1使能,0不使能
    
    input   wire[31:0]wr_b_addr  , //写DDR首地址
    input   wire[31:0]wr_e_addr  , //写DDR末地址
    input   wire      user_wr_clk, //写FIFO写时钟
    input   wire      data_wren  , //写FIFO写请求
//写进fifo数据长度,可根据写fifo的写端口数据长度自行修改
//写FIFO写数据 16位,此时用64位是为了兼容32,64位
    input   wire[63:0]data_wr    , //写数据 低16有效    
    input   wire      wr_rst     , //写地址复位
     
    input   wire[31:0]rd_b_addr  , //读DDR首地址
    input   wire[31:0]rd_e_addr  , //读DDR末地址    
    input   wire      user_rd_clk, //读FIFO读时钟
    input   wire      data_rden  , //读FIFO读请求  
//读出fifo数据长度,可根据读fifo的读端口数据长度自行修改
//读FIFO读数据,16位,此时用64位是为了兼容32,64位
    output  wire[63:0]data_rd    , //读数据 低16有效   
    input   wire      rd_rst     , //读地址复位
    input   wire      read_enable, //读使能
    output  wire      data_rd_valid,
    
    output  wire      ui_clk     , //输出时钟125m
    output  wire      ui_rst     , //输出复位,高有效
    output  wire      calib_done   //ddr初始化完成
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//wire  define
 //axi写通道写地址
wire [3:0] M_AXI_WR_awid;   //写地址ID,用来标志一组写信号
wire [31:0]M_AXI_WR_awaddr; //写地址,给出一次写突发传输的写地址
wire [7:0] M_AXI_WR_awlen;  //突发长度,给出突发传输的次数
wire [2:0] M_AXI_WR_awsize; //突发大小,给出每次突发传输的字节数
wire [1:0] M_AXI_WR_awburst;//突发类型
wire [0:0] M_AXI_WR_awlock; //总线锁信号,可提供操作的原子性
wire [3:0] M_AXI_WR_awcache;//内存类型,表明一次传输是怎样通过系统的
wire [2:0] M_AXI_WR_awprot; //保护类型,表明一次传输的特权级及安全等级
wire [3:0] M_AXI_WR_awqos;  //质量服务QoS
wire       M_AXI_WR_awvalid;//有效信号,表明此通道的地址控制信号有效
wire       M_AXI_WR_awready;//表明“从”可以接收地址和对应的控制信号                           
//axi写通道读数据           
wire [63:0]M_AXI_WR_wdata;  //写数据
wire [7:0] M_AXI_WR_wstrb;  //写数据有效的字节线
                            //用来表明哪8bits数据是有效的
wire       M_AXI_WR_wlast;  //表明此次传输是最后一个突发传输
wire       M_AXI_WR_wvalid; //写有效,表明此次写有效
wire       M_AXI_WR_wready; //表明从机可以接收写数据
//axi写通道读应答           
wire [3:0] M_AXI_WR_bid;    //写响应ID TAG
wire [1:0] M_AXI_WR_bresp;  //写响应,表明写传输的状态
wire       M_AXI_WR_bvalid; //写响应有效
wire       M_AXI_WR_bready; //表明主机能够接收写响应
 //axi读通道写地址          
wire [3:0] M_AXI_RD_arid;   //读地址ID,用来标志一组写信号
wire [31:0]M_AXI_RD_araddr; //读地址,给出一次写突发传输的读地址
wire [7:0] M_AXI_RD_arlen;  //突发长度,给出突发传输的次数
wire [2:0] M_AXI_RD_arsize; //突发大小,给出每次突发传输的字节数
wire [1:0] M_AXI_RD_arburst;//突发类型
wire [1:0] M_AXI_RD_arlock; //总线锁信号,可提供操作的原子性
wire [3:0] M_AXI_RD_arcache;//内存类型,表明一次传输是怎样通过系统的
wire [2:0] M_AXI_RD_arprot; //保护类型,表明一次传输的特权级及安全等级
wire [3:0] M_AXI_RD_arqos;  //质量服务QOS
wire       M_AXI_RD_arvalid;//有效信号,表明此通道的地址控制信号有效
wire       M_AXI_RD_arready;//表明“从”可以接收地址和对应的控制信号
//axi读通道读数据
wire [3:0] M_AXI_RD_rid;    //读ID tag
wire [63:0]M_AXI_RD_rdata;  //读数据
wire [1:0] M_AXI_RD_rresp;  //读响应,表明读传输的状态
wire       M_AXI_RD_rlast;  //表明读突发的最后一次传输
wire       M_AXI_RD_rvalid; //表明此通道信号有效
wire       M_AXI_RD_rready; //表明主机能够接收读数据和响应信息

//axi主机用户写控制信号
wire        wr_burst_req   ;
wire [31:0] wr_burst_addr  ;
wire [9:0]  wr_burst_len   ; 
wire        wr_ready       ;
//axi写数据与使能fifo接口
wire        wr_fifo_re     ;
wire [63:0] wr_fifo_data   ;
wire        wr_burst_finish;
//axi主机用户读控制信号
wire        rd_burst_req   ;
wire [31:0] rd_burst_addr  ;
wire [9:0]  rd_burst_len   ; 
wire        rd_ready       ;
//axi读数据与使能fifo接口
wire        rd_fifo_we     ;
wire [63:0] rd_fifo_data   ;
wire        rd_burst_finish;

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- axi_ctrl_inst -------------
axi_ctrl
#(
.DDR_WR_LEN(DDR_WR_LEN),//写突发长度 128个64bit
.DDR_RD_LEN(DDR_RD_LEN)//读突发长度 128个64bit

)
axi_ctrl_inst
(
  .ui_clk     (ui_clk     ),
  .ui_rst     (ui_rst     ),
  .pingpang   (pingpang   ),//乒乓操作
              
  .wr_b_addr  (wr_b_addr  ), //写DDR首地址
  .wr_e_addr  (wr_e_addr  ), //写DDR末地址
  .user_wr_clk(user_wr_clk), //写FIFO写时钟
  .data_wren  (data_wren  ), //写FIFO写请求            
  .data_wr    (data_wr    ), //写FIFO写数据 16位
                             //此时用64位是为了兼容32,64位
  .wr_rst     (wr_rst     ), //写地址复位
                             
  .rd_b_addr  (rd_b_addr  ), //读DDR首地址
  .rd_e_addr  (rd_e_addr  ), //读DDR末地址    
  .user_rd_clk(user_rd_clk), //读FIFO读时钟
  .data_rden  (data_rden  ), //读FIFO读请求             
  .data_rd    (data_rd    ), //读FIFO读数据,16位,此时用64位是为了兼容32位
                             //64位,增强复用性,只需修改fifo即可
  .rd_rst     (rd_rst     ),
  .read_enable(read_enable),
  .data_rd_valid(data_rd_valid),
  //连接到axi写主机
  .wr_burst_req     (wr_burst_req   ),
  .wr_burst_addr    (wr_burst_addr  ),
  .wr_burst_len     (wr_burst_len   ),
  .wr_ready         (wr_ready       ),
  .wr_fifo_re       (wr_fifo_re     ),
  .wr_fifo_data     (wr_fifo_data   ),
  .wr_burst_finish  (wr_burst_finish),
  //连接到axi读主机                 
  .rd_burst_req     (rd_burst_req   ),
  .rd_burst_addr    (rd_burst_addr  ),
  .rd_burst_len     (rd_burst_len   ),
  .rd_ready         (rd_ready       ),
  .rd_fifo_we       (rd_fifo_we     ),
  .rd_fifo_data     (rd_fifo_data   ),
  .rd_burst_finish  (rd_burst_finish)
);

//------------- axi_master_write_inst -------------
axi_master_write axi_master_write_inst
(
  .ARESETN      (~ui_rst         ), //axi复位
  .ACLK         (ui_clk          ), //axi总时钟
  .M_AXI_AWID   (M_AXI_WR_awid   ), //写地址ID
  .M_AXI_AWADDR (M_AXI_WR_awaddr ), //写地址
  .M_AXI_AWLEN  (M_AXI_WR_awlen  ), //突发长度 
  .M_AXI_AWSIZE (M_AXI_WR_awsize ), //突发大小  
  .M_AXI_AWBURST(M_AXI_WR_awburst), //突发类型  
  .M_AXI_AWLOCK (M_AXI_WR_awlock ), //总线锁信号 
  .M_AXI_AWCACHE(M_AXI_WR_awcache), //内存类型
  .M_AXI_AWPROT (M_AXI_WR_awprot ), //保护类型
  .M_AXI_AWQOS  (M_AXI_WR_awqos  ), //质量服务QoS     
  .M_AXI_AWVALID(M_AXI_WR_awvalid), //有效信号
  .M_AXI_AWREADY(M_AXI_WR_awready), //握手信号awready
 
  .M_AXI_WDATA (M_AXI_WR_wdata   ), //写数据
  .M_AXI_WSTRB (M_AXI_WR_wstrb   ), //写数据有效的字节线
  .M_AXI_WLAST (M_AXI_WR_wlast   ), //表明此次传输是最后一个突发传输
  .M_AXI_WVALID(M_AXI_WR_wvalid  ), //写有效
  .M_AXI_WREADY(M_AXI_WR_wready  ), //表明从机可以接收写数据                         
  
  .M_AXI_BID   (M_AXI_WR_bid     ), //写响应ID TAG
  .M_AXI_BRESP (M_AXI_WR_bresp   ), //写响应
  .M_AXI_BVALID(M_AXI_WR_bvalid  ), //写响应有效
  .M_AXI_BREADY(M_AXI_WR_bready  ), //表明主机能够接收写响应  
  
  .WR_START    (wr_burst_req     ), //写突发触发信号
  .WR_ADRS     (wr_burst_addr    ), //地址  
  .WR_LEN      (wr_burst_len     ), //长度
  .WR_READY    (wr_ready         ), //写空闲
  .WR_FIFO_RE  (wr_fifo_re       ), //连接到写fifo的读使能
  .WR_FIFO_DATA(wr_fifo_data     ), //连接到fifo的读数据
  .WR_DONE     (wr_burst_finish  )  //完成一次突发              
);
 
//------------- axi_master_read_inst -------------    
axi_master_read axi_master_read_inst
(
  . ARESETN      (~ui_rst),
  . ACLK         (ui_clk),
  . M_AXI_ARID   (M_AXI_RD_arid   ), //读地址ID
  . M_AXI_ARADDR (M_AXI_RD_araddr ), //读地址
  . M_AXI_ARLEN  (M_AXI_RD_arlen  ), //突发长度
  . M_AXI_ARSIZE (M_AXI_RD_arsize ), //突发大小
  . M_AXI_ARBURST(M_AXI_RD_arburst), //突发类型
  . M_AXI_ARLOCK (M_AXI_RD_arlock ), //总线锁信号
  . M_AXI_ARCACHE(M_AXI_RD_arcache), //内存类型
  . M_AXI_ARPROT (M_AXI_RD_arprot ), //保护类型
  . M_AXI_ARQOS  (M_AXI_RD_arqos  ), //质量服务QOS
  . M_AXI_ARVALID(M_AXI_RD_arvalid), //有效信号
  . M_AXI_ARREADY(M_AXI_RD_arready), //握手信号arready
  
  . M_AXI_RID   (M_AXI_RD_rid   ), //读ID tag
  . M_AXI_RDATA (M_AXI_RD_rdata ), //读数据
  . M_AXI_RRESP (M_AXI_RD_rresp ), //读响应,表明读传输的状态
  . M_AXI_RLAST (M_AXI_RD_rlast ), //表明读突发的最后一次传输
  . M_AXI_RVALID(M_AXI_RD_rvalid), //表明此通道信号有效
  . M_AXI_RREADY(M_AXI_RD_rready), //表明主机能够接收读数据和响应信息

  . RD_START    (rd_burst_req   ), //读突发触发信号
  . RD_ADRS     (rd_burst_addr  ), //地址  
  . RD_LEN      (rd_burst_len   ), //长度
  . RD_READY    (rd_ready       ), //读空闲
  . RD_FIFO_WE  (rd_fifo_we     ), //连接到读fifo的写使能
  . RD_FIFO_DATA(rd_fifo_data   ), //连接到读fifo的写数据
  . RD_DONE     (rd_burst_finish)  //完成一次突发
);

//------------- u_axi_ddr -------------
//xilinx提供的mig ip核,开启axi4接口

axi_ddr  u_axi_ddr
(
  .ddr3_dq   (ddr3_dq   ),     //数据线
  .ddr3_dqs_n(ddr3_dqs_n),     //数据选取脉冲差分信号
  .ddr3_dqs_p(ddr3_dqs_p),     //数据选取脉冲差分信号
  .ddr3_addr (ddr3_addr ),     //地址线
  .ddr3_ba   (ddr3_ba   ),     //bank线
  .ddr3_ras_n(ddr3_ras_n),     //行使能信号,低电平有效
  .ddr3_cas_n(ddr3_cas_n),     //列使能信号,低电平有效
  .ddr3_we_n (ddr3_we_n ),     //写使能信号,低电平有效
  .ddr3_reset_n(ddr3_reset_n), //ddr3复位
  .ddr3_ck_p (ddr3_ck_p ),     //ddr3差分时钟
  .ddr3_ck_n (ddr3_ck_n ),     //ddr3差分时钟
  .ddr3_cke  (ddr3_cke  ),     //ddr3时钟使能信号
  .ddr3_cs_n (ddr3_cs_n ),     //ddr3片选信号
  .ddr3_dm   (ddr3_dm   ),     //ddr3掩码
  .ddr3_odt  (ddr3_odt  ),     //odt阻抗
  
  .sys_clk_i(ddr3_clk),        //ip核时钟
//  .clk_ref_i(ddr3_clk),        //ip核参考时钟
  .ui_clk   (ui_clk),          //用户端口时钟
  .ui_clk_sync_rst(ui_rst),    //复位
  .mmcm_locked(),
  .aresetn    (sys_rst_n),    //异步复位
  .app_sr_req ('b0),
  .app_ref_req('b0),
  .app_zq_req ('b0),
  .app_sr_active(),
  .app_ref_ack(),
  .app_zq_ack(),
  //axi写通道地址与控制信号
  .s_axi_awid    (M_AXI_WR_awid   ), //写地址ID                        输入[3:0]
  .s_axi_awaddr  (M_AXI_WR_awaddr ), //写地址                          输入[29:0]
  .s_axi_awlen   (M_AXI_WR_awlen  ), //突发长度                        输入[7:0]
  .s_axi_awsize  (M_AXI_WR_awsize ), //突发大小                        输入[2:0]
  .s_axi_awburst (M_AXI_WR_awburst), //突发类型                        输入[1:0]
  .s_axi_awlock  (M_AXI_WR_awlock ), //总线锁信号                      输入[0:0]
  .s_axi_awcache (M_AXI_WR_awcache), //内存类型                        输入[3:0]
  .s_axi_awprot  (M_AXI_WR_awprot ), //保护类型                        输入[2:0]
  .s_axi_awqos   (M_AXI_WR_awqos  ), //质量服务QoS                     输入[3:0]
  .s_axi_awvalid (M_AXI_WR_awvalid), //有效信号                        输入[0:0]
  .s_axi_awready (M_AXI_WR_awready), //握手信号awready                 输出[0:0]
  //axi写通道数据
  .s_axi_wdata   (M_AXI_WR_wdata  ), //写数据                          输入[63:0]
  .s_axi_wstrb   (M_AXI_WR_wstrb  ), //写数据有效的字节线              输入[7:0]
  .s_axi_wlast   (M_AXI_WR_wlast  ), //表明此次传输是最后一个突发传输  输入[0:0]
  .s_axi_wvalid  (M_AXI_WR_wvalid ), //写有效,表明此次写有效          输入[0:0]
  .s_axi_wready  (M_AXI_WR_wready ), //表明从机可以接收写数据          输出[0:0]
  //axi写通道应答                    
  .s_axi_bid     (M_AXI_WR_bid    ), //写响应ID TAG                    输出[3:0]
  .s_axi_bresp   (M_AXI_WR_bresp  ), //写响应,表明写传输的状态        输出[1:0]
  .s_axi_bvalid  (M_AXI_WR_bvalid ), //写响应有效                      输出[0:0]
  .s_axi_bready  (M_AXI_WR_bready ), //表明主机能够接收写响应          输入[0:0]
  //axi读通道地址与控制信号                                            
  .s_axi_arid    (M_AXI_RD_arid   ), //读地址ID                        输入[3:0]
  .s_axi_araddr  (M_AXI_RD_araddr ), //读地址                          输入[29:0]
  .s_axi_arlen   (M_AXI_RD_arlen  ), //突发长度                        输入[7:0]
  .s_axi_arsize  (M_AXI_RD_arsize ), //突发大小                        输入[2:0]
  .s_axi_arburst (M_AXI_RD_arburst), //突发类型                        输入[1:0]
  .s_axi_arlock  (M_AXI_RD_arlock ), //总线锁信号                      输入[0:0]
  .s_axi_arcache (M_AXI_RD_arcache), //内存类型                        输入[3:0]
  .s_axi_arprot  (M_AXI_RD_arprot ), //保护类型                        输入[2:0]
  .s_axi_arqos   (M_AXI_RD_arqos  ), //质量服务QOS                     输入[3:0]
  .s_axi_arvalid (M_AXI_RD_arvalid), //有效信号                        输入[0:0]
  .s_axi_arready (M_AXI_RD_arready), //握手信号arready                 输出[0:0]
  //axi读通道数据,包括应答          
  .s_axi_rid     (M_AXI_RD_rid    ), //读ID tag                        输出[3:0]  
  .s_axi_rdata   (M_AXI_RD_rdata  ), //读数据                          输出[63:0]
  .s_axi_rresp   (M_AXI_RD_rresp  ), //读响应,表明读传输的状态        输出[1:0]
  .s_axi_rlast   (M_AXI_RD_rlast  ), //表明读突发的最后一次传输        输出[0:0]
  .s_axi_rvalid  (M_AXI_RD_rvalid ), //表明此通道信号有效              输出[0:0]
  .s_axi_rready  (M_AXI_RD_rready ), //表明主机能够接收读数据          输入[0:0]
                                     
  .init_calib_complete(calib_done) , //ip核初始化完成
  .sys_rst(sys_rst_n)                //ip核复位
);

endmodule

标签:Xilinxddr3,wire,ip,fifo,axi,rd,mig,AXI,wr
From: https://www.cnblogs.com/xzjfindgoodjob/p/18254505

相关文章

  • 通过阿里云OOS定时升级EIP实例临时带宽
    功能背景随着业务的不断发展和互联网应用场景的多样化,企业或个人用户在特定时间段内面临网络流量剧增的挑战变得尤为常见。这些流量高峰,如大规模促销活动、热门直播事件、重大新闻发布或季节性数据备份等场景,往往会导致原有带宽瞬间饱和,影响用户体验甚至导致服务短暂不可用。......
  • Javascript入门博客【入门复习(学习)使用】
    JavaScript是一门高级,解释形语言,大量用于关于web网站的开发,可以和网页联动做出更多有趣的动画效果。其运行方式大都是嵌入在网页中运行。其实在定义方面如果过你是初学者来学习和这方面相关的知识,知道上面这些就已经足够了。我们可以在浏览器中直接进行对代码的控制,进入浏览器......
  • DNS与IP地址的那些事
    1.上期问题答案"www"只是Web服务器上的一种命名,并不是一种协议。在互联网发展初期,"www"成为网站地址的标准前缀,但实际上并不是所有网站都需要使用"www"这个子域名。2.本章主题上一篇我们讲了如何生成HTTP请求,那么我们要怎么发送给Web服务器呢?相信看完这一章,你便会有答案......
  • 如何使用JavaScript实现在线Excel附件的上传与下载?
    前言在本地使用Excel时,经常会有需要在Excel中添加一些附件文件的需求,例如在Excel中附带一些Word,CAD图等等。同样的,类比到Web端,现在很多人用的在线Excel是否也可以像本地一样实现附件文件的操作呢?答案是肯定的,不过和本地不同的是,Web端不会直接打开附件,而是使用超链接单元格的......
  • 在Vue 2中使用Swiper,你需要安装与Vue 2兼容的Swiper版本
    在Vue2中使用Swiper,你需要安装与Vue2兼容的Swiper版本,并且通常还需要安装vue-awesome-swiper这个Vue组件来更方便地集成Swiper。以下是如何在Vue2项目中使用Swiper的步骤:1.安装Swiper和vue-awesome-swiper首先,你需要通过npm或yarn来安装Swiper和vue-awesome-swiper。确保安......
  • iptables 四表五链
    https://blog.csdn.net/weixin_48190891/article/details/107815698iptables是基于内核态框架netfilter实现。他们共同组成的Linux包过滤防火墙。组成默认五种规则链:INPUTOUTPUTFORWARDPREROUTINGPOSTROUTING默认四种规则表:filter:包过滤nat:源及目的地址转换ma......
  • P1064 [NOIP2006 提高组] 金明的预算方案
    金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 ......
  • 深入理解JavaScript中的闭包与作用域链
    作为一名JavaScript开发者,了解闭包与作用域链是非常重要的。本文将深入探讨这两个概念,帮助您更好地理解JavaScript的运行机制。作用域链在JavaScript中,每个函数都有一个属于自己的作用域,称为局部作用域。当函数被执行时,会创建一个执行上下文,其中包括局部作用域和其父级作用域......
  • 掌握异步编程:探索JavaScript中的Promise与async/await
    在现代JavaScript开发中,异步编程已经成为了不可或缺的一部分。为了更好地处理异步操作,JavaScript引入了Promise和async/await两个重要概念。本文将带您了解这两个概念,帮助您掌握异步编程。 PromisePromise是异步编程的一种解决方案,它表示一个异步操作的最终完成(或失败)及其结......
  • HarmonyOS NEXT - 从TypeScript到ArkTS的适配指导
    一:ArkTS语法适配背景二:从TypeScript到ArkTS的适配规则三:适配指导案例ArkTS语法适配背景 ArkTS在保持TypeScript(简称TS)基本语法风格的基础上,进一步通过规范强化静态检查和分析,使得在程序开发期能检测更多错误,提升程序稳定性,并实现更好的运行性能。本文将进一步解释为什么......