diff options
Diffstat (limited to 'rtl/wb2axip/axixclk.v')
| -rw-r--r-- | rtl/wb2axip/axixclk.v | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/rtl/wb2axip/axixclk.v b/rtl/wb2axip/axixclk.v new file mode 100644 index 0000000..670f606 --- /dev/null +++ b/rtl/wb2axip/axixclk.v @@ -0,0 +1,312 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 |
