| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Filename: axi32axi.v |
| // |
| // Project: WB2AXIPSP: bus bridges and other odds and ends |
| // |
| // Purpose: Bridge from an AXI3 slave to an AXI4 master |
| // {{{ |
| // The goal here is to support as high a bus speed as possible, maintain |
| // burst support (if possible) and (more important) allow bus requests |
| // coming from the ARM within either the Zynq or one of Intel's SOC chips |
| // to speak with an AutoFPGA based design. |
| // |
| // Note that if you aren't using AutoFPGA, then you probably don't need |
| // this core--the vendor tools should be able to handle this conversion |
| // quietly and automatically for you. |
| // |
| // Notes: |
| // AxCACHE is remapped as per the AXI4 specification, since the values |
| // aren't truly equivalent. This forces a single clock delay in the Ax* |
| // channels and (likely) the W* channel as well as a system level |
| // consequence. |
| // |
| // AXI3 locking is not supported under AXI4. As per the AXI4 spec, |
| // AxLOCK is converteted from AXI3 to AXI4 by just dropping the high |
| // order bit. |
| // |
| // The WID input is ignored. Whether or not this input can be ignored |
| // is based upon how the ARM is implemented internally. After a bit |
| // of research into both Zynq's and Intel SOCs, this appears to be the |
| // appropriate answer here. |
| // |
| // Creator: Dan Gisselquist, Ph.D. |
| // Gisselquist Technology, LLC |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| // }}} |
| // Copyright (C) 2020, Gisselquist Technology, LLC |
| // {{{ |
| // This file is part of the WB2AXIP project. |
| // |
| // The WB2AXIP project contains free software and gateware, licensed under the |
| // Apache License, Version 2.0 (the "License"). You may not use this project, |
| // or this file, except in compliance with the License. You may obtain a copy |
| // of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations |
| // under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // |
| `default_nettype none |
| // }}} |
| module axi32axi #( |
| // {{{ |
| parameter C_AXI_ID_WIDTH = 1, |
| parameter C_AXI_ADDR_WIDTH = 32, |
| parameter C_AXI_DATA_WIDTH = 32, |
| parameter OPT_REORDER_METHOD = 0, |
| parameter [0:0] OPT_TRANSFORM_AXCACHE = 1, |
| parameter [0:0] OPT_LOWPOWER = 0, |
| parameter [0:0] OPT_LOW_LATENCY = 0, |
| parameter WID_LGAWFIFO = 3, |
| parameter WID_LGWFIFO = 3, |
| // |
| localparam ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3, |
| localparam IW=C_AXI_ID_WIDTH |
| // }}} |
| ) ( |
| // {{{ |
| input wire S_AXI_ACLK, |
| input wire S_AXI_ARESETN, |
| // |
| // The AXI3 incoming/slave interface |
| input reg S_AXI_AWVALID, |
| output wire S_AXI_AWREADY, |
| input reg [C_AXI_ID_WIDTH-1:0] S_AXI_AWID, |
| input reg [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR, |
| input reg [3:0] S_AXI_AWLEN, |
| input reg [2:0] S_AXI_AWSIZE, |
| input reg [1:0] S_AXI_AWBURST, |
| input reg [1:0] S_AXI_AWLOCK, |
| input reg [3:0] S_AXI_AWCACHE, |
| input reg [2:0] S_AXI_AWPROT, |
| input reg [3:0] S_AXI_AWQOS, |
| // |
| // |
| input wire S_AXI_WVALID, |
| output wire S_AXI_WREADY, |
| input wire [C_AXI_ID_WIDTH-1:0] S_AXI_WID, |
| input wire [C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA, |
| input wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB, |
| input wire S_AXI_WLAST, |
| // |
| // |
| output wire S_AXI_BVALID, |
| input wire S_AXI_BREADY, |
| output wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID, |
| output wire [1:0] S_AXI_BRESP, |
| // |
| // |
| input wire S_AXI_ARVALID, |
| output wire S_AXI_ARREADY, |
| input wire [C_AXI_ID_WIDTH-1:0] S_AXI_ARID, |
| input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR, |
| input wire [3:0] S_AXI_ARLEN, |
| input wire [2:0] S_AXI_ARSIZE, |
| input wire [1:0] S_AXI_ARBURST, |
| input wire [1:0] S_AXI_ARLOCK, |
| input wire [3:0] S_AXI_ARCACHE, |
| input wire [2:0] S_AXI_ARPROT, |
| input wire [3:0] S_AXI_ARQOS, |
| // |
| output wire S_AXI_RVALID, |
| input wire S_AXI_RREADY, |
| output wire [C_AXI_ID_WIDTH-1:0] S_AXI_RID, |
| output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA, |
| output wire S_AXI_RLAST, |
| output wire [1:0] S_AXI_RRESP, |
| // |
| // |
| // The AXI4 Master (outgoing) interface |
| output wire M_AXI_AWVALID, |
| input wire M_AXI_AWREADY, |
| output wire [C_AXI_ID_WIDTH-1:0] M_AXI_AWID, |
| output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR, |
| output wire [7:0] M_AXI_AWLEN, |
| output wire [2:0] M_AXI_AWSIZE, |
| output wire [1:0] M_AXI_AWBURST, |
| output wire M_AXI_AWLOCK, |
| output wire [3:0] M_AXI_AWCACHE, |
| output wire [2:0] M_AXI_AWPROT, |
| output wire [3:0] M_AXI_AWQOS, |
| // |
| // |
| output wire M_AXI_WVALID, |
| input wire M_AXI_WREADY, |
| output wire [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA, |
| output wire [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB, |
| output wire M_AXI_WLAST, |
| // |
| // |
| input wire M_AXI_BVALID, |
| output wire M_AXI_BREADY, |
| input wire [C_AXI_ID_WIDTH-1:0] M_AXI_BID, |
| input wire [1:0] M_AXI_BRESP, |
| // |
| // |
| output wire M_AXI_ARVALID, |
| input wire M_AXI_ARREADY, |
| output wire [C_AXI_ID_WIDTH-1:0] M_AXI_ARID, |
| output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR, |
| output wire [7:0] M_AXI_ARLEN, |
| output wire [2:0] M_AXI_ARSIZE, |
| output wire [1:0] M_AXI_ARBURST, |
| output wire M_AXI_ARLOCK, |
| output wire [3:0] M_AXI_ARCACHE, |
| output wire [2:0] M_AXI_ARPROT, |
| output wire [3:0] M_AXI_ARQOS, |
| // |
| input wire M_AXI_RVALID, |
| output wire M_AXI_RREADY, |
| input wire [C_AXI_ID_WIDTH-1:0] M_AXI_RID, |
| input wire [C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA, |
| input wire M_AXI_RLAST, |
| input wire [1:0] M_AXI_RRESP |
| // }}} |
| ); |
| |
| // Register/net declarations |
| // {{{ |
| reg [3:0] axi4_awcache, axi4_arcache; |
| reg axi4_awlock, axi4_arlock; |
| wire awskd_ready; |
| wire wid_reorder_awready; |
| wire [IW-1:0] reordered_wid; |
| // }}} |
| |
| // Write cache remapping |
| // {{{ |
| always @(*) |
| case(S_AXI_AWCACHE) |
| 4'b1010: axi4_awcache = 4'b1110; |
| 4'b1011: axi4_awcache = 4'b1111; |
| default: axi4_awcache = S_AXI_AWCACHE; |
| endcase |
| // }}} |
| |
| // AWLOCK |
| // {{{ |
| always @(*) |
| axi4_awlock = S_AXI_AWLOCK[0]; |
| // }}} |
| |
| // AW Skid buffer |
| // {{{ |
| generate if (OPT_TRANSFORM_AXCACHE) |
| begin |
| // {{{ |
| skidbuffer #( |
| .DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH |
| + 4 + 3 + 2 + 1+4+3+4), |
| .OPT_OUTREG(1'b1) |
| ) awskid ( |
| .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), |
| .i_valid(S_AXI_AWVALID && wid_reorder_awready), |
| .o_ready(awskd_ready), |
| .i_data({ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN, |
| S_AXI_AWSIZE, S_AXI_AWBURST,axi4_awlock, |
| axi4_awcache, S_AXI_AWPROT, S_AXI_AWQOS |
| }), |
| .o_valid(M_AXI_AWVALID), .i_ready(M_AXI_AWREADY), |
| .o_data({ M_AXI_AWID, M_AXI_AWADDR, |
| M_AXI_AWLEN[3:0], |
| M_AXI_AWSIZE,M_AXI_AWBURST,M_AXI_AWLOCK, |
| M_AXI_AWCACHE,M_AXI_AWPROT, M_AXI_AWQOS |
| }) |
| ); |
| |
| assign M_AXI_AWLEN[7:4] = 4'h0; |
| assign S_AXI_AWREADY = awskd_ready && wid_reorder_awready; |
| // }}} |
| end else begin |
| // {{{ |
| assign M_AXI_AWVALID = S_AXI_AWVALID && wid_reorder_awready; |
| assign S_AXI_AWREADY = M_AXI_AWREADY; |
| assign M_AXI_AWID = S_AXI_AWID; |
| assign M_AXI_AWADDR = S_AXI_AWADDR; |
| assign M_AXI_AWLEN = { 4'h0, S_AXI_AWLEN }; |
| assign M_AXI_AWSIZE = S_AXI_AWSIZE; |
| assign M_AXI_AWBURST = S_AXI_AWBURST; |
| assign M_AXI_AWLOCK = axi4_awlock; |
| assign M_AXI_AWCACHE = axi4_awcache; |
| assign M_AXI_AWPROT = S_AXI_AWPROT; |
| assign M_AXI_AWQOS = S_AXI_AWQOS; |
| |
| assign awskd_ready = 1; |
| // }}} |
| end endgenerate |
| // }}} |
| |
| // Handle write channel de-interleaving |
| // {{{ |
| axi3reorder #( |
| // {{{ |
| .C_AXI_ID_WIDTH(C_AXI_ID_WIDTH), |
| .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), |
| .OPT_METHOD(OPT_REORDER_METHOD), |
| .OPT_LOWPOWER(OPT_LOWPOWER), |
| .OPT_LOW_LATENCY(OPT_LOW_LATENCY), |
| .LGAWFIFO(WID_LGAWFIFO), |
| .LGWFIFO(WID_LGWFIFO), |
| // }}} |
| ) widreorder ( |
| // {{{ |
| .S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN), |
| // Incoming Write address ID |
| .S_AXI3_AWVALID(S_AXI_AWVALID && S_AXI_AWREADY), |
| .S_AXI3_AWREADY(wid_reorder_awready), |
| .S_AXI3_AWID(S_AXI_AWID), |
| // Incoming Write data info |
| .S_AXI3_WVALID(S_AXI_WVALID), |
| .S_AXI3_WREADY(S_AXI_WREADY), |
| .S_AXI3_WID(S_AXI_WID), |
| .S_AXI3_WDATA(S_AXI_WDATA), |
| .S_AXI3_WSTRB(S_AXI_WSTRB), |
| .S_AXI3_WLAST(S_AXI_WLAST), |
| // Outgoing write data channel |
| .M_AXI_WVALID(M_AXI_WVALID), |
| .M_AXI_WREADY(M_AXI_WREADY), |
| .M_AXI_WID(reordered_wid), |
| .M_AXI_WDATA(M_AXI_WDATA), |
| .M_AXI_WSTRB(M_AXI_WSTRB), |
| .M_AXI_WLAST(M_AXI_WLAST) |
| // }}} |
| ); |
| // }}} |
| |
| // Forward the B* channel return |
| // {{{ |
| assign S_AXI_BVALID = M_AXI_BVALID; |
| assign M_AXI_BREADY = S_AXI_BREADY; |
| assign S_AXI_BID = M_AXI_BID; |
| assign S_AXI_BRESP = M_AXI_BRESP; |
| // }}} |
| |
| // Read cache remapping |
| // {{{ |
| always @(*) |
| case(S_AXI_ARCACHE) |
| 4'b0110: axi4_arcache = 4'b1110; |
| 4'b0111: axi4_arcache = 4'b1111; |
| default: axi4_arcache = S_AXI_ARCACHE; |
| endcase |
| // }}} |
| |
| // ARLOCK |
| // {{{ |
| always @(*) |
| axi4_arlock = S_AXI_ARLOCK[0]; |
| // }}} |
| |
| // AR Skid buffer |
| // {{{ |
| generate if (OPT_TRANSFORM_AXCACHE) |
| begin |
| // {{{ |
| skidbuffer #( |
| .DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH |
| + 4 + 3 + 2 + 1+4+3+4), |
| .OPT_OUTREG(1'b1) |
| ) arskid ( |
| .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), |
| .i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY), |
| .i_data({ S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN, |
| S_AXI_ARSIZE, S_AXI_ARBURST, axi4_arlock, |
| axi4_arcache, S_AXI_ARPROT, S_AXI_ARQOS }), |
| .o_valid(M_AXI_ARVALID), .i_ready(M_AXI_ARREADY), |
| .o_data({ M_AXI_ARID, M_AXI_ARADDR, M_AXI_ARLEN[3:0], |
| M_AXI_ARSIZE, M_AXI_ARBURST, M_AXI_ARLOCK, |
| M_AXI_ARCACHE, M_AXI_ARPROT, M_AXI_ARQOS }) |
| ); |
| |
| assign M_AXI_ARLEN[7:4] = 4'h0; |
| // }}} |
| end else begin |
| // {{{ |
| assign M_AXI_ARVALID = S_AXI_ARVALID; |
| assign S_AXI_ARREADY = M_AXI_ARREADY; |
| assign M_AXI_ARID = S_AXI_ARID; |
| assign M_AXI_ARADDR = S_AXI_ARADDR; |
| assign M_AXI_ARLEN = { 4'h0, S_AXI_ARLEN }; |
| assign M_AXI_ARSIZE = S_AXI_ARSIZE; |
| assign M_AXI_ARBURST = S_AXI_ARBURST; |
| assign M_AXI_ARLOCK = axi4_arlock; |
| assign M_AXI_ARCACHE = axi4_arcache; |
| assign M_AXI_ARPROT = S_AXI_ARPROT; |
| assign M_AXI_ARQOS = S_AXI_ARQOS; |
| // }}} |
| end endgenerate |
| // }}} |
| |
| // Forward the R* channel return |
| // {{{ |
| assign S_AXI_RVALID = M_AXI_RVALID; |
| assign M_AXI_RREADY = S_AXI_RREADY; |
| assign S_AXI_RID = M_AXI_RID; |
| assign S_AXI_RDATA = M_AXI_RDATA; |
| assign S_AXI_RLAST = M_AXI_RLAST; |
| assign S_AXI_RRESP = M_AXI_RRESP; |
| // }}} |
| |
| // Verilator lint_off UNUSED |
| wire unused; |
| assign unused = &{ 1'b0, S_AXI_AWLOCK[1], S_AXI_ARLOCK[1], |
| reordered_wid }; |
| // Verilator lint_on UNUSED |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Formal property section |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////// |
| `ifdef FORMAL |
| // |
| // This design has not been formally verified. |
| // |
| `endif |
| endmodule |