blob: d36297405836bb528d3852b00dd990ec7cbccd0d [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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