//////////////////////////////////////////////////////////////////////////////// // // 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-2024, 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, // 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