| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Filename: axixclk.v |
| // |
| // Project: WB2AXIPSP: bus bridges and other odds and ends |
| // |
| // Purpose: Cross AXI clock domains |
| // |
| // Performance: |
| // |
| // Creator: Dan Gisselquist, Ph.D. |
| // Gisselquist Technology, LLC |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Copyright (C) 2019-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 axixclk #( |
| parameter integer C_S_AXI_ID_WIDTH = 2, |
| parameter integer C_S_AXI_DATA_WIDTH = 32, |
| parameter integer C_S_AXI_ADDR_WIDTH = 6, |
| // Some useful short-hand definitions |
| localparam AW = C_S_AXI_ADDR_WIDTH, |
| localparam DW = C_S_AXI_DATA_WIDTH, |
| localparam IW = C_S_AXI_ID_WIDTH, |
| localparam LSB = $clog2(C_S_AXI_DATA_WIDTH)-3, |
| // |
| parameter [0:0] OPT_WRITE_ONLY = 1'b0, |
| parameter [0:0] OPT_READ_ONLY = 1'b0, |
| parameter XCLOCK_FFS = 2, |
| parameter LGFIFO = 5 |
| ) ( |
| // Users to add ports here |
| |
| // User ports ends |
| // Do not modify the ports beyond this line |
| |
| input wire S_AXI_ACLK, |
| input wire S_AXI_ARESETN, |
| // |
| input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID, |
| input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, |
| input wire [7 : 0] S_AXI_AWLEN, |
| input wire [2 : 0] S_AXI_AWSIZE, |
| input wire [1 : 0] S_AXI_AWBURST, |
| input wire S_AXI_AWLOCK, |
| input wire [3 : 0] S_AXI_AWCACHE, |
| input wire [2 : 0] S_AXI_AWPROT, |
| input wire [3 : 0] S_AXI_AWQOS, |
| input wire S_AXI_AWVALID, |
| output wire S_AXI_AWREADY, |
| // |
| input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, |
| input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, |
| input wire S_AXI_WLAST, |
| input wire S_AXI_WVALID, |
| output wire S_AXI_WREADY, |
| // |
| output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID, |
| output wire [1 : 0] S_AXI_BRESP, |
| output wire S_AXI_BVALID, |
| input wire S_AXI_BREADY, |
| // |
| input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID, |
| input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, |
| input wire [7 : 0] S_AXI_ARLEN, |
| input wire [2 : 0] S_AXI_ARSIZE, |
| input wire [1 : 0] S_AXI_ARBURST, |
| input wire S_AXI_ARLOCK, |
| input wire [3 : 0] S_AXI_ARCACHE, |
| input wire [2 : 0] S_AXI_ARPROT, |
| input wire [3 : 0] S_AXI_ARQOS, |
| input wire S_AXI_ARVALID, |
| output wire S_AXI_ARREADY, |
| // |
| output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID, |
| output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, |
| output wire [1 : 0] S_AXI_RRESP, |
| output wire S_AXI_RLAST, |
| output wire S_AXI_RVALID, |
| input wire S_AXI_RREADY, |
| |
| // |
| // Downstream port |
| // |
| input wire M_AXI_ACLK, |
| output wire M_AXI_ARESETN, |
| // |
| output wire [C_S_AXI_ID_WIDTH-1 : 0] M_AXI_AWID, |
| output wire [C_S_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_AWVALID, |
| input wire M_AXI_AWREADY, |
| // |
| output wire [C_S_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA, |
| output wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] M_AXI_WSTRB, |
| output wire M_AXI_WLAST, |
| output wire M_AXI_WVALID, |
| input wire M_AXI_WREADY, |
| // |
| input wire [C_S_AXI_ID_WIDTH-1 : 0] M_AXI_BID, |
| input wire [1 : 0] M_AXI_BRESP, |
| input wire M_AXI_BVALID, |
| output wire M_AXI_BREADY, |
| // |
| output wire [C_S_AXI_ID_WIDTH-1 : 0] M_AXI_ARID, |
| output wire [C_S_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, |
| output wire M_AXI_ARVALID, |
| input wire M_AXI_ARREADY, |
| // |
| input wire [C_S_AXI_ID_WIDTH-1 : 0] M_AXI_RID, |
| input wire [C_S_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA, |
| input wire [1 : 0] M_AXI_RRESP, |
| input wire M_AXI_RLAST, |
| input wire M_AXI_RVALID, |
| output wire M_AXI_RREADY |
| ); |
| |
| reg [2:0] mreset; |
| |
| (* ASYNC_REG = "TRUE" *) initial mreset = 3'b000; |
| always @(posedge M_AXI_ACLK, negedge S_AXI_ARESETN) |
| if (!S_AXI_ARESETN) |
| mreset <= 3'b000; |
| else |
| mreset <= { mreset[1:0], 1'b1 }; |
| |
| assign M_AXI_ARESETN = mreset[2]; |
| |
| generate if (OPT_READ_ONLY) |
| begin : READ_ONLY |
| |
| assign M_AXI_AWID = 0; |
| assign M_AXI_AWADDR = 0; |
| assign M_AXI_AWLEN = 0; |
| assign M_AXI_AWSIZE = 0; |
| assign M_AXI_AWBURST= 0; |
| assign M_AXI_AWLOCK = 0; |
| assign M_AXI_AWCACHE= 0; |
| assign M_AXI_AWPROT = 0; |
| assign M_AXI_AWQOS = 0; |
| // Either way we do these we're wrong, so don't try accessing |
| // the write side of the bus when OPT_READ_ONLY is set or your |
| // design will hang. |
| |
| assign M_AXI_AWVALID = 1'b0; |
| assign S_AXI_AWREADY = 1'b0; |
| |
| assign M_AXI_WDATA = 0; |
| assign M_AXI_WSTRB = 0; |
| assign M_AXI_WLAST = 0; |
| |
| assign M_AXI_WVALID = 1'b0; |
| assign S_AXI_WREADY = 1'b0; |
| |
| assign S_AXI_BID = 0; |
| assign S_AXI_BRESP = 2'b11; |
| |
| assign M_AXI_BREADY = 1'b0; |
| assign S_AXI_BVALID = 1'b0; |
| |
| end else begin : WRITE_FIFO |
| wire awfull, awempty, wfull, wempty, bfull, bempty; |
| |
| afifo #(.LGFIFO(LGFIFO), |
| .NFF(XCLOCK_FFS), |
| .WIDTH(C_S_AXI_ID_WIDTH + C_S_AXI_ADDR_WIDTH |
| + 8 + 3 + 2 + 1 + 4 + 3 + 4)) |
| awfifo(S_AXI_ACLK, S_AXI_ARESETN, S_AXI_AWVALID&& S_AXI_AWREADY, |
| { S_AXI_AWID, S_AXI_AWADDR, |
| S_AXI_AWLEN, S_AXI_AWSIZE, S_AXI_AWBURST, |
| S_AXI_AWLOCK, |
| S_AXI_AWCACHE, S_AXI_AWPROT, S_AXI_AWQOS }, |
| awfull, |
| M_AXI_ACLK, M_AXI_ARESETN, M_AXI_AWREADY, |
| { M_AXI_AWID, M_AXI_AWADDR, |
| M_AXI_AWLEN, M_AXI_AWSIZE, M_AXI_AWBURST, |
| M_AXI_AWLOCK, |
| M_AXI_AWCACHE, M_AXI_AWPROT, M_AXI_AWQOS }, |
| awempty); |
| |
| assign M_AXI_AWVALID = !awempty; |
| assign S_AXI_AWREADY = !awfull; |
| |
| afifo #(.LGFIFO(LGFIFO), |
| .NFF(XCLOCK_FFS), |
| .WIDTH(C_S_AXI_DATA_WIDTH + C_S_AXI_DATA_WIDTH/8 + 1)) |
| wfifo(S_AXI_ACLK, S_AXI_ARESETN, S_AXI_WVALID&& S_AXI_WREADY, |
| { S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST }, |
| wfull, |
| M_AXI_ACLK, M_AXI_ARESETN, M_AXI_WREADY, |
| { M_AXI_WDATA, M_AXI_WSTRB, M_AXI_WLAST }, |
| wempty); |
| |
| assign M_AXI_WVALID = !wempty; |
| assign S_AXI_WREADY = !wfull; |
| |
| afifo #(.LGFIFO(LGFIFO), |
| .NFF(XCLOCK_FFS), |
| .WIDTH(C_S_AXI_ID_WIDTH + 2)) |
| bfifo(M_AXI_ACLK, M_AXI_ARESETN, M_AXI_BVALID&& M_AXI_BREADY, |
| { M_AXI_BID, M_AXI_BRESP }, bfull, |
| S_AXI_ACLK, S_AXI_ARESETN, S_AXI_BREADY, |
| { S_AXI_BID, S_AXI_BRESP }, bempty); |
| |
| assign S_AXI_BVALID = !bempty; |
| assign M_AXI_BREADY = !bfull; |
| end endgenerate |
| |
| generate if (OPT_WRITE_ONLY) |
| begin : NO_READS |
| |
| assign M_AXI_ARID = 0; |
| assign M_AXI_ARADDR = 0; |
| assign M_AXI_ARLEN = 0; |
| assign M_AXI_ARSIZE = 0; |
| assign M_AXI_ARBURST= 0; |
| assign M_AXI_ARLOCK = 0; |
| assign M_AXI_ARCACHE= 0; |
| assign M_AXI_ARPROT = 0; |
| assign M_AXI_ARQOS = 0; |
| // Either way we do these we're wrong, so don't try accessing |
| // the write side of the bus when OPT_READ_ONLY is set or your |
| // design will hang. |
| |
| assign M_AXI_ARVALID = 1'b0; |
| assign S_AXI_ARREADY = 1'b0; |
| |
| assign S_AXI_RID = 0; |
| assign S_AXI_RDATA = 2'b11; |
| assign S_AXI_RLAST = 1'b1; |
| assign S_AXI_RRESP = 2'b11; |
| |
| assign M_AXI_RREADY = 1'b0; |
| assign S_AXI_RVALID = 1'b0; |
| |
| end else begin : READ_FIFO |
| wire arfull, arempty, rfull, rempty; |
| |
| afifo #(.LGFIFO(LGFIFO), |
| .NFF(XCLOCK_FFS), |
| .WIDTH(C_S_AXI_ID_WIDTH + C_S_AXI_ADDR_WIDTH |
| + 8 + 3 + 2 + 1 + 4 + 3 + 4)) |
| arfifo(S_AXI_ACLK, S_AXI_ARESETN, S_AXI_ARVALID&& S_AXI_ARREADY, |
| { S_AXI_ARID, S_AXI_ARADDR, |
| S_AXI_ARLEN, S_AXI_ARSIZE, S_AXI_ARBURST, |
| S_AXI_ARLOCK, |
| S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS }, |
| arfull, |
| M_AXI_ACLK, M_AXI_ARESETN, M_AXI_ARREADY, |
| { M_AXI_ARID, M_AXI_ARADDR, |
| M_AXI_ARLEN, M_AXI_ARSIZE, M_AXI_ARBURST, |
| M_AXI_ARLOCK, |
| M_AXI_ARCACHE, M_AXI_ARPROT, M_AXI_ARQOS }, |
| arempty); |
| |
| assign M_AXI_ARVALID = !arempty; |
| assign S_AXI_ARREADY = !arfull; |
| |
| |
| afifo #(.LGFIFO(LGFIFO), |
| .NFF(XCLOCK_FFS), |
| .WIDTH(C_S_AXI_ID_WIDTH + C_S_AXI_DATA_WIDTH+3)) |
| rfifo(M_AXI_ACLK, M_AXI_ARESETN, M_AXI_RVALID&& M_AXI_RREADY, |
| { M_AXI_RID, M_AXI_RDATA, M_AXI_RLAST, M_AXI_RRESP }, |
| rfull, |
| S_AXI_ACLK, S_AXI_ARESETN, S_AXI_RREADY, |
| { S_AXI_RID, S_AXI_RDATA, S_AXI_RLAST, S_AXI_RRESP }, |
| rempty); |
| |
| assign S_AXI_RVALID = !rempty; |
| assign M_AXI_RREADY = !rfull; |
| |
| end endgenerate |
| |
| endmodule |