summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axixclk.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axixclk.v')
-rw-r--r--rtl/wb2axip/axixclk.v312
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