blob: c5f86214f7e1845fdf172649043f2cefb5670093 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Filename: axilempty.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: Modifies the simple AXI-lite interface to be an empty shell
//
// This is useful for a bus with masters but no slaves. When used,
// the interconnect can connect those masters to this slave to know
// that requests will still be properly handled--and get proper error
// returns.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 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 axilempty #(
// {{{
//
// Size of the AXI-lite bus. These are fixed, since 1) AXI-lite
// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
// we only ever have 4 configuration words.
parameter C_AXI_ADDR_WIDTH = 4,
localparam C_AXI_DATA_WIDTH = 32,
parameter [0:0] OPT_SKIDBUFFER = 1'b0,
parameter [0:0] OPT_LOWPOWER = 0,
localparam ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
// }}}
) (
// {{{
input wire S_AXI_ACLK,
input wire S_AXI_ARESETN,
//
input wire S_AXI_AWVALID,
output wire S_AXI_AWREADY,
//
input wire S_AXI_WVALID,
output wire S_AXI_WREADY,
//
output wire S_AXI_BVALID,
input wire S_AXI_BREADY,
output wire [1:0] S_AXI_BRESP,
//
input wire S_AXI_ARVALID,
output wire S_AXI_ARREADY,
//
output wire S_AXI_RVALID,
input wire S_AXI_RREADY,
output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,
output wire [1:0] S_AXI_RRESP
// }}}
);
////////////////////////////////////////////////////////////////////////
//
// Register/wire signal declarations
//
////////////////////////////////////////////////////////////////////////
//
// {{{
wire i_reset = !S_AXI_ARESETN;
wire axil_write_ready;
//
reg axil_bvalid;
//
wire axil_read_ready;
reg axil_read_valid;
////////////////////////////////////////////////////////////////////////
//
// AXI-lite signaling
//
////////////////////////////////////////////////////////////////////////
//
// {{{
//
// Write signaling
//
// {{{
generate if (OPT_SKIDBUFFER)
begin : SKIDBUFFER_WRITE
wire awskd_valid, wskd_valid, awskd_unused, wskd_unused;
skidbuffer #(.OPT_OUTREG(0),
.OPT_LOWPOWER(OPT_LOWPOWER), .DW(1))
axilawskid(//
.i_clk(S_AXI_ACLK), .i_reset(i_reset),
.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
.i_data(1'b0),
.o_valid(awskd_valid), .i_ready(axil_write_ready),
.o_data(awskd_unused));
skidbuffer #(.OPT_OUTREG(0), .OPT_LOWPOWER(OPT_LOWPOWER),
.DW(1))
axilwskid(//
.i_clk(S_AXI_ACLK), .i_reset(i_reset),
.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
.i_data({ 1'b0 }),
.o_valid(wskd_valid), .i_ready(axil_write_ready),
.o_data(wskd_unused));
assign axil_write_ready = awskd_valid && wskd_valid
&& (!S_AXI_BVALID || S_AXI_BREADY);
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, awskd_unused, wskd_unused };
// Verilator lint_on UNUSED
end else begin : SIMPLE_WRITES
reg axil_awready;
initial axil_awready = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axil_awready <= 1'b0;
else
axil_awready <= !axil_awready
&& (S_AXI_AWVALID && S_AXI_WVALID)
&& (!S_AXI_BVALID || S_AXI_BREADY);
assign S_AXI_AWREADY = axil_awready;
assign S_AXI_WREADY = axil_awready;
assign axil_write_ready = axil_awready;
end endgenerate
initial axil_bvalid = 0;
always @(posedge S_AXI_ACLK)
if (i_reset)
axil_bvalid <= 0;
else if (axil_write_ready)
axil_bvalid <= 1;
else if (S_AXI_BREADY)
axil_bvalid <= 0;
assign S_AXI_BVALID = axil_bvalid;
assign S_AXI_BRESP = 2'b11;
// }}}
//
// Read signaling
//
// {{{
generate if (OPT_SKIDBUFFER)
begin : SKIDBUFFER_READ
wire arskd_valid, arskd_unused;
skidbuffer #(.OPT_OUTREG(0),
.OPT_LOWPOWER(OPT_LOWPOWER),
.DW(C_AXI_ADDR_WIDTH-ADDRLSB))
axilarskid(//
.i_clk(S_AXI_ACLK), .i_reset(i_reset),
.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
.i_data( 1'b0 ),
.o_valid(arskd_valid), .i_ready(axil_read_ready),
.o_data(arskd_unused));
assign axil_read_ready = arskd_valid
&& (!axil_read_valid || S_AXI_RREADY);
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, arskd_unused };
// Verilator lint_on UNUSED
end else begin : SIMPLE_READS
reg axil_arready;
always @(*)
axil_arready = !S_AXI_RVALID;
assign S_AXI_ARREADY = axil_arready;
assign axil_read_ready = (S_AXI_ARVALID && S_AXI_ARREADY);
end endgenerate
initial axil_read_valid = 1'b0;
always @(posedge S_AXI_ACLK)
if (i_reset)
axil_read_valid <= 1'b0;
else if (axil_read_ready)
axil_read_valid <= 1'b1;
else if (S_AXI_RREADY)
axil_read_valid <= 1'b0;
assign S_AXI_RVALID = axil_read_valid;
assign S_AXI_RDATA = 0;
assign S_AXI_RRESP = 2'b11;
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// AXI-lite register logic
//
////////////////////////////////////////////////////////////////////////
//
// {{{
// }}}
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0 };
// Verilator lint_on UNUSED
// }}}
`ifdef FORMAL
////////////////////////////////////////////////////////////////////////
//
// Formal properties used in verfiying this core
//
////////////////////////////////////////////////////////////////////////
//
// {{{
reg f_past_valid;
initial f_past_valid = 0;
always @(posedge S_AXI_ACLK)
f_past_valid <= 1;
////////////////////////////////////////////////////////////////////////
//
// The AXI-lite control interface
//
////////////////////////////////////////////////////////////////////////
//
// {{{
localparam F_AXIL_LGDEPTH = 4;
wire [F_AXIL_LGDEPTH-1:0] faxil_rd_outstanding,
faxil_wr_outstanding,
faxil_awr_outstanding;
faxil_slave #(
// {{{
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
.F_LGDEPTH(F_AXIL_LGDEPTH),
.F_AXI_MAXWAIT(2),
.F_AXI_MAXDELAY(2),
.F_AXI_MAXRSTALL(3),
.F_OPT_COVER_BURST(0)
// }}}
) faxil(
// {{{
.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
//
.i_axi_awvalid(S_AXI_AWVALID),
.i_axi_awready(S_AXI_AWREADY),
.i_axi_awaddr({(C_AXI_ADDR_WIDTH){1'b0}}),
.i_axi_awcache(4'h0),
.i_axi_awprot( 3'h0),
//
.i_axi_wvalid(S_AXI_WVALID),
.i_axi_wready(S_AXI_WREADY),
.i_axi_wdata( {(C_AXI_DATA_WIDTH){1'b0}}),
.i_axi_wstrb( {(C_AXI_DATA_WIDTH/8){1'b0}}),
//
.i_axi_bvalid(S_AXI_BVALID),
.i_axi_bready(S_AXI_BREADY),
.i_axi_bresp( S_AXI_BRESP),
//
.i_axi_arvalid(S_AXI_ARVALID),
.i_axi_arready(S_AXI_ARREADY),
.i_axi_araddr( {(C_AXI_ADDR_WIDTH){1'b0}}),
.i_axi_arcache(4'h0),
.i_axi_arprot( 3'h0),
//
.i_axi_rvalid(S_AXI_RVALID),
.i_axi_rready(S_AXI_RREADY),
.i_axi_rdata( S_AXI_RDATA),
.i_axi_rresp( S_AXI_RRESP),
//
.f_axi_rd_outstanding(faxil_rd_outstanding),
.f_axi_wr_outstanding(faxil_wr_outstanding),
.f_axi_awr_outstanding(faxil_awr_outstanding)
// }}}
);
always @(*)
if (OPT_SKIDBUFFER)
begin
assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0)
+(S_AXI_AWREADY ? 0:1));
assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)
+(S_AXI_WREADY ? 0:1));
assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)
+(S_AXI_ARREADY ? 0:1));
end else begin
assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0));
assert(faxil_awr_outstanding == faxil_wr_outstanding);
assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0));
end
//
// Check that our low-power only logic works by verifying that anytime
// S_AXI_RVALID is inactive, then the outgoing data is also zero.
//
always @(*)
assert(S_AXI_RDATA == 0);
always @(*)
assert(S_AXI_RRESP == 2'b11);
always @(*)
assert(S_AXI_BRESP == 2'b11);
// }}}
////////////////////////////////////////////////////////////////////////
//
// Cover checks
//
////////////////////////////////////////////////////////////////////////
//
// {{{
// While there are already cover properties in the formal property
// set above, you'll probably still want to cover something
// application specific here
// }}}
// }}}
`endif
endmodule