#PCIE-XDMA AXI_MM接口转普通接口

PCIE-XDMA AXI_MM接口转普通接口

一、自定义IP核

自定义一个 AXI_full 接口的IP核,自定义IP核教程可参考我的上一篇文章 :
[PCIE-XDMA之AXI_lite接口解析](https://mp.csdn.net/mp_blog/creation/editor/140236567)

二、编辑自定义IP核

  1. 编辑IP核界面中,编辑顶层模块
    在顶层文件中的**/ /Users to add ports here和 // User ports ends**这两条语句中间添加用户端口
		// Users to add ports here
        output                              apb_wren        ,
        output [C_S00_AXI_ADDR_WIDTH-1:0]   apb_waddr       ,
        output [C_S00_AXI_DATA_WIDTH-1:0]   apb_wdata       ,
        output [C_S00_AXI_DATA_WIDTH/8-1:0] apb_wstrb       ,
        output                              apb_rden        ,
        output [C_S00_AXI_ADDR_WIDTH-1:0]   apb_raddr       ,
        input                               apb_rdata_en    ,
        input  [C_S00_AXI_DATA_WIDTH-1:0]   apb_rdata       ,
		// User ports ends
  1. 在顶层文件实例话子文件的位置将添加的用户端口连接到子模块文件,其中axi_mm_v1_0是我自己的自定义IP核名字,中间有一行空行,空行上面是用户添加端口,空行下面是原有端口
// Instantiation of Axi Bus Interface S00_AXI
   axi_mm_v1_0_S00_AXI # ( 
		.C_S_AXI_ID_WIDTH(C_S00_AXI_ID_WIDTH),
		.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
		.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH),
		.C_S_AXI_AWUSER_WIDTH(C_S00_AXI_AWUSER_WIDTH),
		.C_S_AXI_ARUSER_WIDTH(C_S00_AXI_ARUSER_WIDTH),
		.C_S_AXI_WUSER_WIDTH(C_S00_AXI_WUSER_WIDTH),
		.C_S_AXI_RUSER_WIDTH(C_S00_AXI_RUSER_WIDTH),
		.C_S_AXI_BUSER_WIDTH(C_S00_AXI_BUSER_WIDTH)
	) axi_mm_v1_0_S00_AXI_inst (
	    .apb_wren        ( apb_wren     ),
        .apb_waddr       ( apb_waddr    ),
        .apb_wdata       ( apb_wdata    ),
        .apb_wstrb       ( apb_wstrb    ),
        .apb_rden        ( apb_rden     ),
        .apb_raddr       ( apb_raddr    ),
        .apb_rdata_en    ( apb_rdata_en ),
        .apb_rdata       ( apb_rdata    ),

		.S_AXI_ACLK(s00_axi_aclk),
		.S_AXI_ARESETN(s00_axi_aresetn),
		.S_AXI_AWID(s00_axi_awid),
		.S_AXI_AWADDR(s00_axi_awaddr),
		.S_AXI_AWLEN(s00_axi_awlen),
		.S_AXI_AWSIZE(s00_axi_awsize),
		.S_AXI_AWBURST(s00_axi_awburst),
		.S_AXI_AWLOCK(s00_axi_awlock),
		.S_AXI_AWCACHE(s00_axi_awcache),
		.S_AXI_AWPROT(s00_axi_awprot),
		.S_AXI_AWQOS(s00_axi_awqos),
		.S_AXI_AWREGION(s00_axi_awregion),
		.S_AXI_AWUSER(s00_axi_awuser),
		.S_AXI_AWVALID(s00_axi_awvalid),
		.S_AXI_AWREADY(s00_axi_awready),
		.S_AXI_WDATA(s00_axi_wdata),
		.S_AXI_WSTRB(s00_axi_wstrb),
		.S_AXI_WLAST(s00_axi_wlast),
		.S_AXI_WUSER(s00_axi_wuser),
		.S_AXI_WVALID(s00_axi_wvalid),
		.S_AXI_WREADY(s00_axi_wready),
		.S_AXI_BID(s00_axi_bid),
		.S_AXI_BRESP(s00_axi_bresp),
		.S_AXI_BUSER(s00_axi_buser),
		.S_AXI_BVALID(s00_axi_bvalid),
		.S_AXI_BREADY(s00_axi_bready),
		.S_AXI_ARID(s00_axi_arid),
		.S_AXI_ARADDR(s00_axi_araddr),
		.S_AXI_ARLEN(s00_axi_arlen),
		.S_AXI_ARSIZE(s00_axi_arsize),
		.S_AXI_ARBURST(s00_axi_arburst),
		.S_AXI_ARLOCK(s00_axi_arlock),
		.S_AXI_ARCACHE(s00_axi_arcache),
		.S_AXI_ARPROT(s00_axi_arprot),
		.S_AXI_ARQOS(s00_axi_arqos),
		.S_AXI_ARREGION(s00_axi_arregion),
		.S_AXI_ARUSER(s00_axi_aruser),
		.S_AXI_ARVALID(s00_axi_arvalid),
		.S_AXI_ARREADY(s00_axi_arready),
		.S_AXI_RID(s00_axi_rid),
		.S_AXI_RDATA(s00_axi_rdata),
		.S_AXI_RRESP(s00_axi_rresp),
		.S_AXI_RLAST(s00_axi_rlast),
		.S_AXI_RUSER(s00_axi_ruser),
		.S_AXI_RVALID(s00_axi_rvalid),
		.S_AXI_RREADY(s00_axi_rready)
	);
  1. 编辑子模块
    在子模块的**/ /Users to add ports here和 // User ports ends**语句之间加上用户端口
		// Users to add ports here
		output                            apb_wren        ,
        output [C_S_AXI_ADDR_WIDTH-1:0]   apb_waddr       ,
        output [C_S_AXI_DATA_WIDTH-1:0]   apb_wdata       ,
        output [C_S_AXI_DATA_WIDTH/8-1:0] apb_wstrb       ,
        output                            apb_rden        ,
        output [C_S_AXI_ADDR_WIDTH-1:0]   apb_raddr       ,
        input                             apb_rdata_en    ,
        input  [C_S_AXI_DATA_WIDTH-1:0]   apb_rdata       ,
		// User ports ends

找到** axi_rvalid 和 axi_rresp **信号所在的always语句块,将其注释

//	always @( posedge S_AXI_ACLK )
//	begin
//	  if ( S_AXI_ARESETN == 1'b0 )
//	    begin
//	      axi_rvalid <= 0;
//	      axi_rresp  <= 0;
//	    end 
//	  else
//	    begin    
//	      if (axi_arv_arr_flag && ~axi_rvalid)
//	        begin
//	          axi_rvalid <= 1'b1;
//	          axi_rresp  <= 2'b0; 
//	          // 'OKAY' response
//	        end   
//	      else if (axi_rvalid && S_AXI_RREADY)
//	        begin
//	          axi_rvalid <= 1'b0;
//	        end            
//	    end
//	end    

找到** axi_rdata **信号所在的always语句块,将其注释

//	always @( mem_data_out, axi_rvalid)
//	begin
//	  if (axi_rvalid) 
//	    begin
//	      // Read address mux
//	      axi_rdata <= mem_data_out[0];
//	    end   
//	  else
//	    begin
//	      axi_rdata <= 32'h00000000;
//	    end       
//	end    

找到** // Add user logic here **该语句,在该语句下面添加用户代码

	wire [63:0]reg_wstrb;
    
    genvar k;
     generate
         for(k=0;k<C_S_AXI_DATA_WIDTH/8;k=k+1)
         begin
         assign reg_wstrb[k*8+7:k*8] = {8{S_AXI_WSTRB[k]}};
         end
     endgenerate
	
	assign apb_wren  = axi_wready && S_AXI_WVALID;
    assign apb_waddr = {{ADDR_LSB{1'b0}},axi_awaddr[C_S_AXI_ADDR_WIDTH-1:ADDR_LSB]};
    assign apb_wdata = S_AXI_WDATA & reg_wstrb;
    assign apb_wstrb = S_AXI_WSTRB;
    assign apb_rden  = axi_arv_arr_flag & ~axi_rvalid;
    assign apb_raddr = {{ADDR_LSB{1'b0}},axi_araddr[C_S_AXI_ADDR_WIDTH-1:ADDR_LSB]};
    
    always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_rvalid <= 0;
	      axi_rresp  <= 0;
	    end 
	  else
	    begin    
	      if (apb_rdata_en && ~axi_rvalid)
	        begin
	          axi_rvalid <= 1'b1;
	          axi_rresp  <= 2'b0; 
	          // 'OKAY' response
	        end   
	      else if (axi_rvalid && S_AXI_RREADY)
	        begin
	          axi_rvalid <= 1'b0;
	        end            
	    end
	end   
	
	always @(*)
	begin
	  if (axi_rvalid) 
	    begin
	      // Read address mux
	      axi_rdata <= apb_rdata;
	    end   
	  else
	    begin
	      axi_rdata <= 32'h00000000;
	    end       
	end    

	// User logic ends

三、实例话自定义IP核

在自己的项目中调用自定义好了的IP核。其中** axi_mm_0 **就是我通过上述步骤自定义好了的IP核

    (*mark_debug = "true"*)wire            apb_mm_wren     ;     
    (*mark_debug = "true"*)wire [63 : 0]   apb_mm_waddr    ;
    (*mark_debug = "true"*)wire [63 : 0]   apb_mm_wdata    ;
    (*mark_debug = "true"*)wire [7 : 0]    apb_mm_wstrb    ;
    (*mark_debug = "true"*)wire            apb_mm_rden     ;     
    (*mark_debug = "true"*)wire [63 : 0]    apb_mm_raddr    ;
    (*mark_debug = "true"*)wire            apb_mm_rdata_en ;      
    (*mark_debug = "true"*)wire [63 : 0]   apb_mm_rdata    ;

    axi_mm_0 axi_mm_0 (
      .apb_wren(apb_mm_wren),                  // output wire apb_wren
      .apb_waddr(apb_mm_waddr),                // output wire [5 : 0] apb_waddr
      .apb_wdata(apb_mm_wdata),                // output wire [31 : 0] apb_wdata
      .apb_wstrb(apb_mm_wstrb),                // output wire [3 : 0] apb_wstrb
      .apb_rden(apb_mm_rden),                  // output wire apb_rden
      .apb_raddr(apb_mm_raddr),                // output wire [5 : 0] apb_raddr
      .apb_rdata_en(apb_mm_rdata_en),          // input wire apb_rdata_en
      .apb_rdata(apb_mm_rdata),                // input wire [31 : 0] apb_rdata
      .s00_axi_awid(m_axi_awid),          // input wire [3 : 0] s00_axi_awid
      .s00_axi_awaddr(m_axi_awaddr),      // input wire [63 : 0] s00_axi_awaddr
      .s00_axi_awlen(m_axi_awlen),        // input wire [7 : 0] s00_axi_awlen
      .s00_axi_awsize(m_axi_awsize),      // input wire [2 : 0] s00_axi_awsize
      .s00_axi_awburst(m_axi_awburst),    // input wire [1 : 0] s00_axi_awburst
      .s00_axi_awlock(m_axi_awlock),      // input wire s00_axi_awlock
      .s00_axi_awcache(m_axi_awcache),    // input wire [3 : 0] s00_axi_awcache
      .s00_axi_awprot(m_axi_awprot),      // input wire [2 : 0] s00_axi_awprot
      .s00_axi_awregion('d0),  // input wire [3 : 0] s00_axi_awregion
      .s00_axi_awqos('d0),        // input wire [3 : 0] s00_axi_awqos
      .s00_axi_awuser('d0),      // input wire [0 : 0] s00_axi_awuser
      .s00_axi_awvalid(m_axi_awvalid),    // input wire s00_axi_awvalid
      .s00_axi_awready(m_axi_awready),    // output wire s00_axi_awready
      .s00_axi_wdata(m_axi_wdata),        // input wire [63 : 0] s00_axi_wdata
      .s00_axi_wstrb(m_axi_wstrb),        // input wire [7 : 0] s00_axi_wstrb
      .s00_axi_wlast(m_axi_wlast),        // input wire s00_axi_wlast
      .s00_axi_wuser('d0),        // input wire [0 : 0] s00_axi_wuser
      .s00_axi_wvalid(m_axi_wvalid),      // input wire s00_axi_wvalid
      .s00_axi_wready(m_axi_wready),      // output wire s00_axi_wready
      .s00_axi_bid(m_axi_bid),            // output wire [3 : 0] s00_axi_bid
      .s00_axi_bresp(m_axi_bresp),        // output wire [1 : 0] s00_axi_bresp
      .s00_axi_buser(m_axi_buser),        // output wire [0 : 0] s00_axi_buser
      .s00_axi_bvalid(m_axi_bvalid),      // output wire s00_axi_bvalid
      .s00_axi_bready(m_axi_bready),      // input wire s00_axi_bready
      .s00_axi_arid(m_axi_arid),          // input wire [3 : 0] s00_axi_arid
      .s00_axi_araddr(m_axi_araddr),      // input wire [63 : 0] s00_axi_araddr
      .s00_axi_arlen(m_axi_arlen),        // input wire [7 : 0] s00_axi_arlen
      .s00_axi_arsize(m_axi_arsize),      // input wire [2 : 0] s00_axi_arsize
      .s00_axi_arburst(m_axi_arburst),    // input wire [1 : 0] s00_axi_arburst
      .s00_axi_arlock(m_axi_arlock),      // input wire s00_axi_arlock
      .s00_axi_arcache(m_axi_arcache),    // input wire [3 : 0] s00_axi_arcache
      .s00_axi_arprot(m_axi_arprot),      // input wire [2 : 0] s00_axi_arprot
      .s00_axi_arregion('d0),  // input wire [3 : 0] s00_axi_arregion
      .s00_axi_arqos('d0),        // input wire [3 : 0] s00_axi_arqos
      .s00_axi_aruser('d0),      // input wire [0 : 0] s00_axi_aruser
      .s00_axi_arvalid(m_axi_arvalid),    // input wire s00_axi_arvalid
      .s00_axi_arready(m_axi_arready),    // output wire s00_axi_arready
      .s00_axi_rid(m_axi_rid),            // output wire [3 : 0] s00_axi_rid
      .s00_axi_rdata(m_axi_rdata),        // output wire [63 : 0] s00_axi_rdata
      .s00_axi_rresp(m_axi_rresp),        // output wire [1 : 0] s00_axi_rresp
      .s00_axi_rlast(m_axi_rlast),        // output wire s00_axi_rlast
      .s00_axi_ruser(m_axi_ruser),        // output wire [0 : 0] s00_axi_ruser
      .s00_axi_rvalid(m_axi_rvalid),      // output wire s00_axi_rvalid
      .s00_axi_rready(m_axi_rready),      // input wire s00_axi_rready
      .s00_axi_aclk(axi_aclk),          // input wire s00_axi_aclk
      .s00_axi_aresetn(axi_aresetn)    // input wire s00_axi_aresetn
    ); 

四、用户寄存器读写逻辑

读写寄存器代码如下:

module axi_mm_register(
    input clk,
    input rstn,
    
    input wire          apb_mm_wren           ,     
    input wire [63 : 0] apb_mm_waddr          ,
    input wire [63 : 0] apb_mm_wdata          ,
    input wire [7 : 0]  apb_mm_wstrb          ,
    input wire          apb_mm_rden           ,
    input wire [63 : 0] apb_mm_raddr          ,
    output reg          apb_mm_rdata_en    ,
    output reg [63 : 0] apb_mm_rdata          
    );
    
    localparam reg_num = 16;    
    //user register   
    (*mark_debug = "true"*)reg [63:0]register[reg_num-1:0];
    reg [63:0]fix_register;
       
     wire [63:0]reg_wstrb_n;
    
    genvar k;
     generate
         for(k=0;k<8;k=k+1)
         begin
         assign reg_wstrb_n[k*8+7:k*8] = {8{~apb_mm_wstrb[k]}};
         end
     endgenerate
     
     generate
         for(k=0;k<reg_num;k=k+1)
         begin
             always@(posedge clk or negedge rstn)begin
             if(!rstn)begin
                register[k] <= 64'd0;
             end
             else if(apb_mm_wren)begin
                case(apb_mm_waddr)
                k:register[k] <= (register[k] & reg_wstrb_n)|apb_mm_wdata;
                default:;
                endcase
             end
             else begin
                register[k] <= register[k];
             end
             end
         end
     endgenerate
     
    always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        apb_mm_rdata_en <= 1'd0;
        apb_mm_rdata <= 64'd0;
    end
    else if(apb_mm_rden)begin
        case(apb_mm_raddr)
        'd0:begin
            apb_mm_rdata_en <= 'd1;
            apb_mm_rdata <= register[0];
        end
        'd1:begin
            apb_mm_rdata_en <= 'd1;
            apb_mm_rdata <=  register[1];
        end
        'd2:begin
            apb_mm_rdata_en <= 'd1;
            apb_mm_rdata <=  register[2];
        end
        'd3:begin
            apb_mm_rdata_en <= 'd1;
            apb_mm_rdata <=  64'hf2f2f2f2_f2f2f2f2;
        end
        default:begin
            apb_mm_rdata_en <= 'd1;
            apb_mm_rdata <= 64'd0 - 1;
        end
        endcase
    end
    else begin
        apb_mm_rdata_en <= 'd0;
        apb_mm_rdata <= apb_mm_rdata;
    end
    end
   
    
    
endmodule

然后在上层文件中实例话该文件,让该文件的端口连接到自定义的IP核端口

axi_mm_register axi_mm_register(
    .clk   (axi_aclk),
    .rstn  (axi_aresetn),
    
    .apb_mm_wren           (apb_mm_wren    ),     
    .apb_mm_waddr          (apb_mm_waddr   ),
    .apb_mm_wdata          (apb_mm_wdata   ),
    .apb_mm_wstrb          (apb_mm_wstrb   ),
    .apb_mm_rden           (apb_mm_rden    ),
    .apb_mm_raddr          (apb_mm_raddr   ),
    .apb_mm_rdata_en       (apb_mm_rdata_en),
    .apb_mm_rdata          (apb_mm_rdata   )
    );
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值