PCIE-XDMA AXI_MM接口转普通接口
一、自定义IP核
自定义一个 AXI_full 接口的IP核,自定义IP核教程可参考我的上一篇文章 :
[PCIE-XDMA之AXI_lite接口解析](https://mp.csdn.net/mp_blog/creation/editor/140236567)
二、编辑自定义IP核
- 编辑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
- 在顶层文件实例话子文件的位置将添加的用户端口连接到子模块文件,其中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)
);
- 编辑子模块
在子模块的**/ /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 )
);