////////////////////////////////////////////////////////////////////////////////
//
// Filename:	rtl/axilsafety.v
// {{{
// Project:	WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose:	A AXI-Lite bus fault isolator.  This core will isolate any
//		downstream AXI-liite slave faults from the upstream channel.
//	It sits as a bump in the wire between upstream and downstream channels,
//	and so it will consume two clocks--slowing down the slave, but
//	potentially allowing developer to recover in case of a fault.
//
//	This core is configured by a couple parameters, which are key to its
//	functionality.
//
//	OPT_TIMEOUT	Set this to a number to be roughly the longest time
//		period you expect the slave to stall the bus, or likewise
//		the longest time period you expect it to wait for a response.
//		If the slave takes longer for either task, a fault will be
//		detected and reported.
//
//	OPT_SELF_RESET	If set, this will send a reset signal to the downstream
//		core so that you can attempt to restart it without reloading
//		the FPGA.  If set, the o_reset signal will be used to reset
//		the downstream core.
//
//	A second key feature of this core are the outgoing fault indicators,
//	o_write_fault and o_read_fault.  If either signal is ever raised, the
//	slave has (somehow) violated protocol on either the write or the
//	read channels respectively.  Such a violation may (or may not) return an
//	error upstream.  For example, if the slave returns a response
//	following no requests from the master, then no error will be returned
//	up stream (doing so would be a protocol violation), but a fault will
//	still be detected.  Use this line to trigger any internal logic
//	analyzers.
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2019-2025, 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 axilsafety #(
	// {{{
	parameter	C_AXI_ADDR_WIDTH = 28,
	parameter	C_AXI_DATA_WIDTH = 32,
	parameter	OPT_TIMEOUT = 12,
	parameter	MAX_DEPTH = (OPT_TIMEOUT),
	localparam	AW = C_AXI_ADDR_WIDTH,
	localparam	DW = C_AXI_DATA_WIDTH,
	localparam	LGTIMEOUT = $clog2(OPT_TIMEOUT+1),
	localparam	LGDEPTH   = $clog2(MAX_DEPTH+1),
	parameter [0:0]	OPT_SELF_RESET = 1'b1,
	parameter 	OPT_MIN_RESET = 16
`ifdef	FORMAL
	, parameter [0:0] F_OPT_WRITES = 1'b1,
	parameter [0:0] F_OPT_READS  = 1'b1,
	parameter [0:0]	F_OPT_FAULTLESS = 1'b1
`endif
	// }}}
	) (
		// {{{
		output	reg	o_write_fault,
		output	reg	o_read_fault,
		//
		input	wire			S_AXI_ACLK,
		input	wire			S_AXI_ARESETN,
		output	reg			M_AXI_ARESETN,
		//
		input	wire			S_AXI_AWVALID,
		output	reg			S_AXI_AWREADY,
		input	wire	[AW-1:0]	S_AXI_AWADDR,
		input	wire	[2:0]		S_AXI_AWPROT,
		//
		input	wire			S_AXI_WVALID,
		output	reg			S_AXI_WREADY,
		input	wire	[DW-1:0]	S_AXI_WDATA,
		input	wire	[DW/8-1:0]	S_AXI_WSTRB,
		//
		output	reg			S_AXI_BVALID,
		input	wire			S_AXI_BREADY,
		output	reg	[1:0]		S_AXI_BRESP,
		//
		input	wire			S_AXI_ARVALID,
		output	reg			S_AXI_ARREADY,
		input	wire	[AW-1:0]	S_AXI_ARADDR,
		input	wire	[2:0]		S_AXI_ARPROT,
		//
		output	reg			S_AXI_RVALID,
		input	wire			S_AXI_RREADY,
		output	reg	[DW-1:0]	S_AXI_RDATA,
		output	reg	[1:0]		S_AXI_RRESP,
		//
		//
		//
		output	reg			M_AXI_AWVALID,
		input	wire			M_AXI_AWREADY,
		output	reg	[AW-1:0]	M_AXI_AWADDR,
		output	reg	[2:0]		M_AXI_AWPROT,
		//
		output	reg			M_AXI_WVALID,
		input	wire			M_AXI_WREADY,
		output	reg	[DW-1:0]	M_AXI_WDATA,
		output	reg	[DW/8-1:0]	M_AXI_WSTRB,
		//
		input	wire			M_AXI_BVALID,
		output	wire			M_AXI_BREADY,
		input	wire	[1:0]		M_AXI_BRESP,
		//
		output	reg			M_AXI_ARVALID,
		input	wire			M_AXI_ARREADY,
		output	reg	[AW-1:0]	M_AXI_ARADDR,
		output	reg	[2:0]		M_AXI_ARPROT,
		//
		input	wire			M_AXI_RVALID,
		output	wire			M_AXI_RREADY,
		input	wire	[DW-1:0]	M_AXI_RDATA,
		input	wire	[1:0]		M_AXI_RRESP
		// }}}
	);

	// localparam, wire, and register declarations
	// {{{
	localparam	OPT_LOWPOWER = 1'b0;
	localparam	OKAY = 2'b00,
			EXOKAY = 2'b01,
			SLVERR = 2'b10;

	reg	[LGDEPTH-1:0]	aw_count, w_count, r_count;
	reg			aw_zero, w_zero, r_zero,
				aw_full, w_full, r_full,
				aw_w_greater, w_aw_greater;
	reg	[LGDEPTH-1:0]	downstream_aw_count, downstream_w_count, downstream_r_count;
	reg			downstream_aw_zero, downstream_w_zero, downstream_r_zero;
				// downstream_aw_w_greater, downstream_w_aw_greater;

	wire			awskd_valid;
	wire	[2:0]		awskd_prot;
	wire	[AW-1:0]	awskd_addr;
	reg			awskd_ready;

	wire			wskd_valid;
	wire	[DW-1:0]	wskd_data;
	wire	[DW/8-1:0]	wskd_strb;
	reg			wskd_ready;

	wire			bskd_valid;
	wire	[1:0]		bskd_resp;
	reg			bskd_ready;

	reg			last_bvalid;
	reg	[1:0]		last_bdata;
	reg			last_bchanged;

	wire			arskd_valid;
	wire	[2:0]		arskd_prot;
	wire	[AW-1:0]	arskd_addr;
	reg			arskd_ready;

	reg			last_rvalid;
	reg [DW+1:0]		last_rdata;
	reg			last_rchanged;

	wire			rskd_valid;
	wire	[1:0]		rskd_resp;
	wire	[DW-1:0]	rskd_data;
	reg			rskd_ready;

	reg [LGTIMEOUT-1:0]	aw_stall_counter, w_stall_counter,
				r_stall_counter, w_ack_timer, r_ack_timer;
	reg 			aw_stall_limit, w_stall_limit, r_stall_limit,
				w_ack_limit, r_ack_limit;
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Write signaling
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	//
	// Write address channel
	// {{{

	skidbuffer #(.DW(AW+3)
		// {{{
`ifdef	FORMAL
		, .OPT_PASSTHROUGH(1'b1)
`endif
		// }}}
	) awskd(S_AXI_ACLK, !S_AXI_ARESETN,
		// {{{
		S_AXI_AWVALID, S_AXI_AWREADY, { S_AXI_AWPROT, S_AXI_AWADDR },
		awskd_valid, awskd_ready, { awskd_prot, awskd_addr});
		// }}}

	// awskd_ready
	// {{{
	// awskd_ready is the critical piece here, since it determines when
	// we accept a packet from the skid buffer.
	//
	always @(*)
	if (!M_AXI_ARESETN || o_write_fault)
		// On any fault, we'll always accept a request (and return an
		// error).  We always accept a value if there are already
		// more writes than write addresses accepted.
		awskd_ready = (w_aw_greater)
			||((aw_zero)&&(!S_AXI_BVALID || S_AXI_BREADY));
	else
		// Otherwise, we accept if ever our counters aren't about to
		// overflow, and there's a place downstream to accept it
		awskd_ready = (!M_AXI_AWVALID || M_AXI_AWREADY)&& (!aw_full);
	// }}}

	// M_AXI_AWVALID
	// {{{
	initial	M_AXI_AWVALID = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN)
		M_AXI_AWVALID <= 1'b0;
	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
		M_AXI_AWVALID <= awskd_valid && awskd_ready && !o_write_fault;
	// }}}

	// M_AXI_AWADDR, M_AXI_AWPROT
	// {{{
	always @(posedge S_AXI_ACLK)
	if (OPT_LOWPOWER && (!M_AXI_ARESETN || o_write_fault))
	begin
		M_AXI_AWADDR <= 0;
		M_AXI_AWPROT <= 0;
	end else if (!M_AXI_AWVALID || M_AXI_AWREADY)
	begin
		M_AXI_AWADDR <= awskd_addr;
		M_AXI_AWPROT <= awskd_prot;
	end
	// }}}
	// }}}

	//
	// Write data channel
	// {{{

	skidbuffer #(.DW(DW+DW/8)
		// {{{
`ifdef	FORMAL
		, .OPT_PASSTHROUGH(1'b1)
`endif
		// }}}
	) wskd(S_AXI_ACLK, !S_AXI_ARESETN,
		// {{{
		S_AXI_WVALID, S_AXI_WREADY, { S_AXI_WDATA, S_AXI_WSTRB },
		wskd_valid, wskd_ready, { wskd_data, wskd_strb});
		// }}}

	// wskd_ready
	// {{{
	// As with awskd_ready, this logic is the critical key.
	//
	always @(*)
	if (!M_AXI_ARESETN || o_write_fault)
		wskd_ready = (aw_w_greater)
			|| ((w_zero)&&(!S_AXI_BVALID || S_AXI_BREADY));
	else
		wskd_ready = (!M_AXI_WVALID || M_AXI_WREADY) && (!w_full);
	// }}}

	// M_AXI_WVALID
	// {{{
	initial	M_AXI_WVALID = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN)
		M_AXI_WVALID <= 1'b0;
	else if (!M_AXI_WVALID || M_AXI_WREADY)
		M_AXI_WVALID <= wskd_valid && wskd_ready && !o_write_fault;
	// }}}

	// M_AXI_WDATA, M_AXI_WSTRB
	// {{{
	always @(posedge S_AXI_ACLK)
	if (OPT_LOWPOWER && (!M_AXI_ARESETN || o_write_fault))
	begin
		M_AXI_WDATA <= 0;
		M_AXI_WSTRB <= 0;
	end else if (!M_AXI_WVALID || M_AXI_WREADY)
	begin
		M_AXI_WDATA <= wskd_data;
		M_AXI_WSTRB <= (o_write_fault) ? 0 : wskd_strb;
	end
	// }}}
	// }}}

	//
	// Write return channel
	// {{{

	// bskd_valid, M_AXI_BREADY, bskd_resp
	// {{{
`ifdef	FORMAL
	assign	bskd_valid = M_AXI_BVALID;
	assign	M_AXI_BREADY= bskd_ready;
	assign	bskd_resp  = M_AXI_BRESP;
`else
	skidbuffer #(.DW(2)
	) bskd(S_AXI_ACLK, !S_AXI_ARESETN || !M_AXI_ARESETN,
		M_AXI_BVALID, M_AXI_BREADY, M_AXI_BRESP,
		bskd_valid, bskd_ready,  bskd_resp);
`endif
	// }}}

	// bskd_ready
	// {{{
	always @(*)
	if (o_write_fault)
		bskd_ready = 1'b1;
	else
		bskd_ready = (!S_AXI_BVALID || S_AXI_BREADY);
	// }}}

	// S_AXI_BVALID
	// {{{
	initial	S_AXI_BVALID = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_BVALID <= 1'b0;
	else if (!S_AXI_BVALID || S_AXI_BREADY)
	begin
		if (o_write_fault || !M_AXI_ARESETN)
			S_AXI_BVALID <= (!S_AXI_BVALID&&(!aw_zero)&&(!w_zero));
		else
			S_AXI_BVALID <= (!downstream_aw_zero)
				&&(!downstream_w_zero)&&(bskd_valid);
	end
	// }}}

	// last_bvalid
	// {{{
	initial	last_bvalid = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!M_AXI_ARESETN || o_write_fault)
		last_bvalid <= 1'b0;
	else
		last_bvalid <= (M_AXI_BVALID && !M_AXI_BREADY);
	// }}}

	// last_bdata
	// {{{
	always @(posedge S_AXI_ACLK)
	if (M_AXI_BVALID)
		last_bdata <= M_AXI_BRESP;
	// }}}

	// last_bchanged
	// {{{
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
		last_bchanged <= 1'b0;
	else
		last_bchanged <= (last_bvalid && (!M_AXI_BVALID
					|| last_bdata != M_AXI_BRESP));
	// }}}

	// S_AXI_BRESP
	// {{{
	initial	S_AXI_BRESP = OKAY;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_BVALID || S_AXI_BREADY)
	begin
		if (o_write_fault)
			S_AXI_BRESP <= SLVERR;
		else if (bskd_resp == EXOKAY)
			S_AXI_BRESP <= SLVERR;
		else
			S_AXI_BRESP <= bskd_resp;
	end
	// }}}
	// }}}
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Read signaling
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	//
	// Read address channel
	// {{{

	skidbuffer #(.DW(AW+3)
		// {{{
`ifdef	FORMAL
		, .OPT_PASSTHROUGH(1'b1)
`endif
		// }}}
	) arskd(S_AXI_ACLK, !S_AXI_ARESETN,
		// {{{
		S_AXI_ARVALID, S_AXI_ARREADY, { S_AXI_ARPROT, S_AXI_ARADDR },
		arskd_valid, arskd_ready,  { arskd_prot, arskd_addr });
		// }}}

	// arskd_ready
	// {{{
	always @(*)
	if (!M_AXI_ARESETN || o_read_fault)
		arskd_ready =((r_zero)&&(!S_AXI_RVALID || S_AXI_RREADY));
	else
		arskd_ready = (!M_AXI_ARVALID || M_AXI_ARREADY) && (!r_full);
	// }}}

	// M_AXI_ARVALID
	// {{{
	initial	M_AXI_ARVALID = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN)
		M_AXI_ARVALID <= 1'b0;
	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
		M_AXI_ARVALID <= arskd_valid && arskd_ready && !o_read_fault;
	// }}}

	// M_AXI_ARADDR, M_AXI_ARPROT
	// {{{
	always @(posedge S_AXI_ACLK)
	if (OPT_LOWPOWER && (!M_AXI_ARESETN || o_read_fault))
	begin
		M_AXI_ARADDR <= 0;
		M_AXI_ARPROT <= 0;
	end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
	begin
		M_AXI_ARADDR <= arskd_addr;
		M_AXI_ARPROT <= arskd_prot;
	end
	// }}}
	// }}}

	//
	// Read data channel
	// {{{

	// rskd_valid, rskd_resp, rskd_data skid buffer
	// {{{
`ifdef	FORMAL
	assign	rskd_valid = M_AXI_RVALID;
	assign	M_AXI_RREADY = rskd_ready;
	assign	{ rskd_resp, rskd_data } = { M_AXI_RRESP, M_AXI_RDATA };
`else
	skidbuffer #(.DW(DW+2)
	) rskd(S_AXI_ACLK, !S_AXI_ARESETN || !M_AXI_ARESETN,
		M_AXI_RVALID, M_AXI_RREADY, { M_AXI_RRESP, M_AXI_RDATA },
		rskd_valid, rskd_ready,  { rskd_resp, rskd_data });
`endif
	// ?}}}

	// rskd_ready
	// {{{
	always @(*)
	if (o_read_fault)
		rskd_ready = 1;
	else
		rskd_ready = (!S_AXI_RVALID || S_AXI_RREADY);
	// }}}

	// S_AXI_RVALID
	// {{{
	initial	S_AXI_RVALID = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_RVALID <= 1'b0;
	else if (!S_AXI_RVALID || S_AXI_RREADY)
	begin
		if (o_read_fault || !M_AXI_ARESETN)
			S_AXI_RVALID <= (!S_AXI_RVALID && !r_zero)
					|| (arskd_valid && arskd_ready);
		else
			S_AXI_RVALID <= (!downstream_r_zero)&&(rskd_valid);
	end
	// }}}

	// S_AXI_RDATA, S_AXI_RRESP
	// {{{
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_RVALID || S_AXI_RREADY)
	begin
		if (o_read_fault || !M_AXI_ARESETN)
			S_AXI_RDATA <= 0;
		else
			S_AXI_RDATA <= rskd_data;

		S_AXI_RRESP <= OKAY;
		if (o_read_fault || rskd_resp == EXOKAY || !M_AXI_ARESETN)
			S_AXI_RRESP <= SLVERR;
		else if (!downstream_r_zero)
			S_AXI_RRESP <= rskd_resp;
	end
	// }}}

	// last_rvalid
	// {{{
	initial	last_rvalid = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
		last_rvalid <= 1'b0;
	else
		last_rvalid <= (M_AXI_RVALID && !M_AXI_RREADY);
	// }}}

	// last_rdata
	// {{{
	always @(posedge S_AXI_ACLK)
	if (M_AXI_RVALID)
		last_rdata <= { M_AXI_RRESP, M_AXI_RDATA };
	// }}}

	// last_rchanged
	// {{{
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
		last_rchanged <= 1'b0;
	else
		last_rchanged <= (last_rvalid && (!M_AXI_RVALID
			|| last_rdata != { M_AXI_RRESP, M_AXI_RDATA }));
	// }}}
	// }}}
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Usage counters
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	//
	// Write address channel
	// {{{

	initial	aw_count = 0;
	initial	aw_zero  = 1;
	initial	aw_full  = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
	begin
		aw_count <= 0;
		aw_zero  <= 1;
		aw_full  <= 0;
	end else case({(awskd_valid && awskd_ready),S_AXI_BVALID&&S_AXI_BREADY})
	2'b10: begin
		aw_count <= aw_count + 1;
		aw_zero <= 0;
		aw_full <= (aw_count == { {(LGDEPTH-1){1'b1}}, 1'b0 });
		end
	2'b01: begin
		aw_count <= aw_count - 1;
		aw_zero <= (aw_count <= 1);
		aw_full <= 0;
		end
	default: begin end
	endcase
	// }}}

	//
	// Write data channel
	// {{{
	initial	w_count = 0;
	initial	w_zero  = 1;
	initial	w_full  = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
	begin
		w_count <= 0;
		w_zero  <= 1;
		w_full  <= 0;
	end else case({(wskd_valid && wskd_ready), S_AXI_BVALID&& S_AXI_BREADY})
	2'b10: begin
		w_count <= w_count + 1;
		w_zero <= 0;
		w_full <= (w_count == { {(LGDEPTH-1){1'b1}}, 1'b0 });
		end
	2'b01: begin
		w_count <= w_count - 1;
		w_zero <= (w_count <= 1);
		w_full <= 1'b0;
		end
	default: begin end
	endcase
	// }}}

	// aw_w_greater, w_aw_greater
	// {{{
	initial	aw_w_greater = 0;
	initial	w_aw_greater = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
	begin
		aw_w_greater <= 0;
		w_aw_greater <= 0;
	end else case({(awskd_valid && awskd_ready),
			(wskd_valid && wskd_ready)})
	2'b10: begin
		aw_w_greater <= (aw_count + 1 >  w_count);
		w_aw_greater <= ( w_count     > aw_count + 1);
		end
	2'b01: begin
		aw_w_greater <= (aw_count     >  w_count + 1);
		w_aw_greater <= ( w_count + 1 > aw_count);
		end
	default: begin end
	endcase
	// }}}
	//
	// Read channel
	// {{{

	// r_count, r_zero, r_full
	initial	r_count = 0;
	initial	r_zero  = 1;
	initial	r_full  = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
	begin
		r_count <= 0;
		r_zero  <= 1;
		r_full  <= 0;
	end else case({(arskd_valid&&arskd_ready), S_AXI_RVALID&&S_AXI_RREADY})
	2'b10: begin
		r_count <= r_count + 1;
		r_zero <= 0;
		r_full <= (r_count == { {(LGDEPTH-1){1'b1}}, 1'b0 });
		end
	2'b01: begin
		r_count <= r_count - 1;
		r_zero <= (r_count <= 1);
		r_full <= 0;
		end
	default: begin end
	endcase
	// }}}

	//
	// Downstream write address channel
	// {{{

	initial	downstream_aw_count = 0;
	initial	downstream_aw_zero = 1;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
	begin
		downstream_aw_count <= 0;
		downstream_aw_zero <= 1;
	end else case({(M_AXI_AWVALID && M_AXI_AWREADY), M_AXI_BVALID && M_AXI_BREADY})
	2'b10: begin
		downstream_aw_count <= downstream_aw_count + 1;
		downstream_aw_zero <= 0;
		end
	2'b01: begin
		downstream_aw_count <= downstream_aw_count - 1;
		downstream_aw_zero <= (downstream_aw_count <= 1);
		end
	default: begin end
	endcase
	// }}}

	//
	// Downstream write data channel
	// {{{
	initial	downstream_w_count = 0;
	initial	downstream_w_zero  = 1;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
	begin
		downstream_w_count <= 0;
		downstream_w_zero  <= 1;
	end else case({(M_AXI_WVALID && M_AXI_WREADY), M_AXI_BVALID && M_AXI_BREADY})
	2'b10: begin
		downstream_w_count <= downstream_w_count + 1;
		downstream_w_zero <= 0;
		end
	2'b01: begin
		downstream_w_count <= downstream_w_count - 1;
		downstream_w_zero <= (downstream_w_count <= 1);
		end
	default: begin end
	endcase
	// }}}

	//
	// Downstream read channel
	// {{{

	initial	downstream_r_count = 0;
	initial	downstream_r_zero  = 1;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
	begin
		downstream_r_count <= 0;
		downstream_r_zero  <= 1;
	end else case({M_AXI_ARVALID && M_AXI_ARREADY, M_AXI_RVALID && M_AXI_RREADY})
	2'b10: begin
		downstream_r_count <= downstream_r_count + 1;
		downstream_r_zero  <= 0;
		end
	2'b01: begin
		downstream_r_count <= downstream_r_count - 1;
		downstream_r_zero  <= (downstream_r_count <= 1);
		end
	default: begin end
	endcase
	// }}}
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Timeout checking
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	// The key piece here is that we define the timeout depending upon
	// what happens (or doesn't happen) *DOWNSTREAM*.  These timeouts
	// will need to propagate upstream before taking place.

	//
	// Write address stall counter
	// {{{
	initial	aw_stall_counter = 0;
	initial	aw_stall_limit   = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_write_fault || !M_AXI_ARESETN)
	begin
		aw_stall_counter <= 0;
		aw_stall_limit   <= 0;
	end else if (!M_AXI_AWVALID || M_AXI_AWREADY || M_AXI_BVALID)
	begin
		aw_stall_counter <= 0;
		aw_stall_limit   <= 0;
	end else if (aw_w_greater && !M_AXI_WVALID)
	begin
		aw_stall_counter <= 0;
		aw_stall_limit   <= 0;
	end else // if (!S_AXI_BVALID || S_AXI_BREADY)
	begin
		aw_stall_counter <= aw_stall_counter + 1;
		aw_stall_limit   <= (aw_stall_counter+1 >= OPT_TIMEOUT);
	end
	// }}}

	//
	// Write data stall counter
	// {{{
	initial	w_stall_counter = 0;
	initial	w_stall_limit   = 1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
	begin
		w_stall_counter <= 0;
		w_stall_limit   <= 0;
	end else if (!M_AXI_WVALID || M_AXI_WREADY || M_AXI_BVALID)
	begin
		w_stall_counter <= 0;
		w_stall_limit   <= 0;
	end else if (w_aw_greater && !M_AXI_AWVALID)
	begin
		w_stall_counter <= 0;
		w_stall_limit   <= 0;
	end else // if (!M_AXI_BVALID || M_AXI_BREADY)
	begin
		w_stall_counter <= w_stall_counter + 1;
		w_stall_limit   <= (w_stall_counter + 1 >= OPT_TIMEOUT);
	end
	// }}}

	//
	// Write acknowledgment delay counter
	// {{{
	initial w_ack_timer = 0;
	initial	w_ack_limit = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
	begin
		w_ack_timer <= 0;
		w_ack_limit <= 0;
	end else if (M_AXI_BVALID || downstream_aw_zero || downstream_w_zero)
	begin
		w_ack_timer <= 0;
		w_ack_limit <= 0;
	end else
	begin
		w_ack_timer <= w_ack_timer + 1;
		w_ack_limit <= (w_ack_timer + 1 >= OPT_TIMEOUT);
	end
	// }}}

	//
	// Read request stall counter
	// {{{
	initial r_stall_counter = 0;
	initial	r_stall_limit   = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
	begin
		r_stall_counter <= 0;
		r_stall_limit   <= 0;
	end else if (!M_AXI_ARVALID || M_AXI_ARREADY || M_AXI_RVALID)
	begin
		r_stall_counter <= 0;
		r_stall_limit   <= 0;
	end else begin
		r_stall_counter <= r_stall_counter + 1;
		r_stall_limit   <= (r_stall_counter + 1 >= OPT_TIMEOUT);
	end
	// }}}

	//
	// Read acknowledgement delay counter
	// {{{
	initial r_ack_timer = 0;
	initial	r_ack_limit = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
	begin
		r_ack_timer <= 0;
		r_ack_limit <= 0;
	end else if (M_AXI_RVALID || downstream_r_zero)
	begin
		r_ack_timer <= 0;
		r_ack_limit <= 0;
	end else begin
		r_ack_timer <= r_ack_timer + 1;
		r_ack_limit <= (r_ack_timer + 1 >= OPT_TIMEOUT);
	end
	// }}}
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Fault detection
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	//
	// Determine if a write fault has taken place
	// {{{
	initial	o_write_fault =1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		o_write_fault <= 1'b0;
	else if (OPT_SELF_RESET && o_write_fault)
	begin
		//
		// Clear any fault on reset
		if (!M_AXI_ARESETN)
			o_write_fault <= 1'b0;
	end else begin
		//
		// A write fault takes place if you respond without a prior
		// bus request on both write address and write data channels.
		if ((downstream_aw_zero || downstream_w_zero)&&(bskd_valid))
			o_write_fault <= 1'b1;

		// AXI-lite slaves are not allowed to return EXOKAY responses
		// from the bus
		if (bskd_valid && bskd_resp == EXOKAY)
			o_write_fault <= 1'b1;

		// If the downstream core refuses to accept either a
		// write address request, or a write data request, or for that
		// matter if it doesn't return an acknowledgment in a timely
		// fashion, then a fault has been detected.
		if (aw_stall_limit || w_stall_limit || w_ack_limit)
			o_write_fault <= 1'b1;

		// If the downstream core changes BRESP while VALID && !READY,
		// then it isn't stalling the channel properly--that's a fault.
		if (last_bchanged)
			o_write_fault <= 1'b1;
	end
	// }}}

	// o_read_fault
	// {{{
	initial	o_read_fault =1'b0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		o_read_fault <= 1'b0;
	else if (OPT_SELF_RESET && o_read_fault)
	begin
		//
		// Clear any fault on reset
		if (!M_AXI_ARESETN)
			o_read_fault <= 1'b0;
	end else begin
		// Responding without a prior request is a fault.  Can only
		// respond after a request has been made.
		if (downstream_r_zero && rskd_valid)
			o_read_fault <= 1'b1;

		// AXI-lite slaves are not allowed to return EXOKAY.  This is
		// an error.
		if (rskd_valid && rskd_resp == EXOKAY)
			o_read_fault <= 1'b1;

		// The slave cannot stall the bus forever, nor should the
		// master wait forever for a response from the slave.
		if (r_stall_limit || r_ack_limit)
			o_read_fault <= 1'b1;

		// If the slave changes the data, or the RRESP on the wire,
		// while the incoming bus is stalled, then that's also a fault.
		if (last_rchanged)
			o_read_fault <= 1'b1;
	end
	// }}}
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Self reset handling
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	generate if (OPT_SELF_RESET)
	begin : SELF_RESET_GENERATION
		// {{{
		wire		min_reset;

		if (OPT_MIN_RESET > 1)
		begin : MIN_RESET
			// {{{
			reg	r_min_reset;
			reg	[$clog2(OPT_MIN_RESET+1):0]	reset_counter;

			//
			// Optionally insist that any downstream reset have a
			// minimum duration.  Many Xilinx components require
			// a 16-clock reset.  This ensures such reset
			// requirements are achieved.
			//

			initial reset_counter = OPT_MIN_RESET-1;
			initial	r_min_reset = 1'b0;
			always @(posedge S_AXI_ARESETN)
			if (M_AXI_ARESETN)
			begin
				reset_counter <= OPT_MIN_RESET-1;
				r_min_reset <= 1'b0;
			end else if (!M_AXI_ARESETN)
			begin
				if (reset_counter > 0)
					reset_counter <= reset_counter-1;
				r_min_reset <= (reset_counter <= 1);
			end

			assign	min_reset = r_min_reset;
`ifdef	FORMAL
			always @(*)
				assert(reset_counter < OPT_MIN_RESET);
			always @(*)
				assert(min_reset == (reset_counter == 0));
`endif
			// }}}
		end else begin : NO_MIN_RESET
			// {{{
			assign	min_reset = 1'b1;
			// }}}
		end

		// M_AXI_ARESETN
		// {{{
		// Reset the downstream bus on either a write or a read fault.
		// Once the bus returns to idle, and any minimum reset durations
		// have been achieved, then release the downstream from reset.
		//
		initial	M_AXI_ARESETN = 1'b0;
		always @(posedge S_AXI_ACLK)
		if (!S_AXI_ARESETN)
			M_AXI_ARESETN <= 1'b0;
		else if (o_write_fault || o_read_fault)
			M_AXI_ARESETN <= 1'b0;
		else if (aw_zero && w_zero && r_zero && min_reset
			&& !awskd_valid && !wskd_valid && !arskd_valid)
			M_AXI_ARESETN <= 1'b1;
		// }}}
		// }}}
	end else begin : SAME_RESET
		// {{{
		//
		// The downstream reset equals the upstream reset
		//
		always @(*)
			M_AXI_ARESETN = S_AXI_ARESETN;
		// }}}
	end endgenerate
	// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal property section
// {{{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef	FORMAL
	// {{{
	//
	// The following proof comes in several parts.
	//
	// 1. PROVE that the upstream properties will hold independent of
	//	what the downstream slave ever does.
	//
	// 2. PROVE that if the downstream slave follows protocol, then
	//	neither o_write_fault nor o_read_fault will never get raised.
	//
	// We then repeat these proofs again with both OPT_SELF_RESET set and
	// clear.  Which of the four proofs is accomplished is dependent upon
	// parameters set by the formal engine.
	//
	//
	wire	[LGDEPTH:0]	faxils_awr_outstanding, faxils_wr_outstanding,
				faxils_rd_outstanding;

	reg	f_past_valid;
	initial	f_past_valid = 0;
	always @(posedge S_AXI_ACLK)
		f_past_valid <= 1;
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Upstream master Bus properties
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//
	always @(*)
	if (!f_past_valid)
	begin
		assume(!S_AXI_ARESETN);
		assert(!M_AXI_ARESETN);
	end

	faxil_slave #(
		// {{{
		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
		.F_OPT_ASSUME_RESET(1'b1),
		.F_OPT_NO_RESET((OPT_MIN_RESET == 0) ? 1:0),
//		.F_AXI_MAXWAIT((F_OPT_FAULTLESS) ? (2*OPT_TIMEOUT+2) : 0),
		.F_AXI_MAXRSTALL(3),
//		.F_AXI_MAXDELAY(OPT_TIMEOUT+OPT_TIMEOUT+5),
		.F_LGDEPTH(LGDEPTH+1),
		//
		.F_AXI_MAXWAIT((F_OPT_FAULTLESS) ? (2*OPT_TIMEOUT+2) : 0),
		.F_AXI_MAXDELAY(2*OPT_TIMEOUT+3)
		// }}}
	) axils (
		// {{{
		.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( S_AXI_AWADDR),
		.i_axi_awprot( S_AXI_AWPROT),
		//
		.i_axi_wvalid(S_AXI_WVALID),
		.i_axi_wready(S_AXI_WREADY),
		.i_axi_wdata( S_AXI_WDATA),
		.i_axi_wstrb( S_AXI_WSTRB),
		//
		.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( S_AXI_ARADDR),
		.i_axi_arprot( S_AXI_ARPROT),
		//
		.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_awr_outstanding(faxils_awr_outstanding),
		.f_axi_wr_outstanding(faxils_wr_outstanding),
		.f_axi_rd_outstanding(faxils_rd_outstanding)
		// }}}
	);

	always @(*)
	if (!F_OPT_WRITES)
	begin
		// {{{
		assume(!S_AXI_AWVALID);
		assume(!S_AXI_WVALID);
		assert(aw_count == 0);
		assert(w_count == 0);
		assert(!M_AXI_AWVALID);
		assert(!M_AXI_WVALID);
		// }}}
	end

	always @(*)
	if (!F_OPT_READS)
	begin
		// {{{
		assume(!S_AXI_ARVALID);
		assert(r_count == 0);
		assert(!S_AXI_RVALID);
		assert(!M_AXI_ARVALID);
		// }}}
	end
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// General Induction properties
	// {{{
	////////////////////////////////////////////////////////////////////////
	//

	always @(*)
	begin
		// {{{
		assert(aw_zero == (aw_count  == 0));
		assert(w_zero  == (w_count   == 0));
		assert(r_zero  == (r_count   == 0));

		//
		assert(aw_full == (&aw_count));
		assert(w_full  == (&w_count));
		assert(r_full  == (&r_count));
		//
		if (M_AXI_ARESETN && !o_write_fault)
		begin
			assert(downstream_aw_zero  == (downstream_aw_count == 0));
			assert(downstream_w_zero   == (downstream_w_count  == 0));
			assert(downstream_aw_count + (M_AXI_AWVALID ? 1:0)
					+ (S_AXI_BVALID ? 1:0) == aw_count);
			assert(downstream_w_count + (M_AXI_WVALID ? 1:0)
					+ (S_AXI_BVALID ? 1:0) ==  w_count);
		end

		if (M_AXI_ARESETN && !o_read_fault)
		begin
			assert(downstream_r_zero   == (downstream_r_count  == 0));
			assert(downstream_r_count + (M_AXI_ARVALID ? 1:0)
					+ (S_AXI_RVALID ? 1:0) ==  r_count);
		end
		//
		assert(aw_count == faxils_awr_outstanding);
		assert(w_count  == faxils_wr_outstanding);
		assert(r_count  == faxils_rd_outstanding);

		assert(aw_w_greater == (aw_count > w_count));
		assert(w_aw_greater == (w_count > aw_count));
		// }}}
	end
	// }}}
	generate if (F_OPT_FAULTLESS)
	begin : ASSUME_FAULTLESS
		// {{{
		////////////////////////////////////////////////////////////////
		//
		// Assume the downstream core is protocol compliant, and
		// prove that o_fault stays low.
		// {{{
		////////////////////////////////////////////////////////////////
		//
		wire	[LGDEPTH:0]	faxilm_awr_outstanding,
					faxilm_wr_outstanding,
					faxilm_rd_outstanding;

		faxil_master #(
			// {{{
			.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
			.F_OPT_NO_RESET((OPT_MIN_RESET == 0) ? 1:0),
			.F_AXI_MAXWAIT(OPT_TIMEOUT),
			.F_AXI_MAXRSTALL(4),
			.F_AXI_MAXDELAY(OPT_TIMEOUT),
			.F_LGDEPTH(LGDEPTH+1)
			// }}}
		) axilm (
			// {{{
			.i_clk(S_AXI_ACLK),
			.i_axi_reset_n(M_AXI_ARESETN && S_AXI_ARESETN),
			//
			.i_axi_awvalid(M_AXI_AWVALID),
			.i_axi_awready(M_AXI_AWREADY),
			.i_axi_awaddr( M_AXI_AWADDR),
			.i_axi_awprot( M_AXI_AWPROT),
			//
			.i_axi_wvalid(M_AXI_WVALID),
			.i_axi_wready(M_AXI_WREADY),
			.i_axi_wdata( M_AXI_WDATA),
			.i_axi_wstrb( M_AXI_WSTRB),
			//
			.i_axi_bvalid(M_AXI_BVALID),
			.i_axi_bready(M_AXI_BREADY),
			.i_axi_bresp( M_AXI_BRESP),
			//
			.i_axi_arvalid(M_AXI_ARVALID),
			.i_axi_arready(M_AXI_ARREADY),
			.i_axi_araddr( M_AXI_ARADDR),
			.i_axi_arprot( M_AXI_ARPROT),
			//
			.i_axi_rvalid(M_AXI_RVALID),
			.i_axi_rready(M_AXI_RREADY),
			.i_axi_rdata( M_AXI_RDATA),
			.i_axi_rresp( M_AXI_RRESP),
			//
			.f_axi_awr_outstanding(faxilm_awr_outstanding),
			.f_axi_wr_outstanding(faxilm_wr_outstanding),
			.f_axi_rd_outstanding(faxilm_rd_outstanding)
			// }}}
		);

		//
		// Here's the big proof
		// {{{
		always @(*)
			assert(!o_write_fault);
		always @(*)
			assert(!o_read_fault);
		// }}}
		// }}}
		////////////////////////////////////////////////////////////////
		//
		// The following properties are necessary for passing induction
		// {{{
		////////////////////////////////////////////////////////////////
		//
		//
		always @(*)
		begin
			assert(!aw_stall_limit);
			assert(!w_stall_limit);
			assert(!w_ack_limit);

			assert(!r_stall_limit);
			assert(!r_ack_limit);

			if (M_AXI_ARESETN)
			begin
			assert(downstream_aw_count == faxilm_awr_outstanding);
			assert(downstream_w_count  == faxilm_wr_outstanding);
			assert(downstream_r_count  == faxilm_rd_outstanding);
			end
		end

		if (OPT_SELF_RESET)
		begin
			always @(posedge S_AXI_ACLK)
			if (f_past_valid)
				assert(M_AXI_ARESETN == $past(S_AXI_ARESETN));
		end

`ifdef	VERIFIC
		wire	[LGDEPTH:0]	f_axi_arstall;
		wire	[LGDEPTH:0]	f_axi_awstall;
		wire	[LGDEPTH:0]	f_axi_wstall;

		assign	f_axi_awstall = axilm.CHECK_STALL_COUNT.f_axi_awstall;
		assign	f_axi_wstall  = axilm.CHECK_STALL_COUNT.f_axi_wstall;
		assign	f_axi_arstall = axilm.CHECK_STALL_COUNT.f_axi_arstall;

		always @(*)
		if (M_AXI_ARESETN && S_AXI_ARESETN && !o_write_fault)
			assert(f_axi_awstall == aw_stall_counter);

		always @(*)
		if (M_AXI_ARESETN && S_AXI_ARESETN && !o_write_fault)
			assert(f_axi_wstall == w_stall_counter);

		always @(*)
		if (M_AXI_ARESETN && S_AXI_ARESETN && !o_read_fault)
			assert(f_axi_arstall == r_stall_counter);
`endif
		// }}}
		// }}}
	end else begin : WILD_DOWNSTREAM
		// {{{
		////////////////////////////////////////////////////////////////
		//
		// cover() checks, checks that only make sense if faults are
		// possible
		//

		reg		write_faulted, read_faulted, faulted;
		reg	[3:0]	cvr_writes, cvr_reads;


		if (OPT_SELF_RESET)
		begin
			////////////////////////////////////////////////////////
			//
			// Prove that we can actually reset the downstream
			// bus/core as desired
			// {{{
			////////////////////////////////////////////////////////
			//
			//
			initial	write_faulted = 0;
			always @(posedge S_AXI_ACLK)
			if (!S_AXI_ARESETN)
				write_faulted <= 0;
			else if (o_write_fault)
				write_faulted <= 1;


			initial	faulted = 0;
			always @(posedge S_AXI_ACLK)
			if (!S_AXI_ARESETN)
				read_faulted <= 0;
			else if (o_read_fault)
				read_faulted <= 1;

			always @(*)
				faulted = (write_faulted || read_faulted);

			always @(posedge S_AXI_ACLK)
				cover(write_faulted && $rose(M_AXI_ARESETN));

			always @(posedge S_AXI_ACLK)
				cover(read_faulted && $rose(M_AXI_ARESETN));

			always @(posedge S_AXI_ACLK)
				cover(faulted && M_AXI_ARESETN && S_AXI_BVALID);

			always @(posedge S_AXI_ACLK)
				cover(faulted && M_AXI_ARESETN && S_AXI_RVALID);


			initial	cvr_writes = 0;
			always @(posedge S_AXI_ACLK)
			if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
				cvr_writes <= 0;
			else if (write_faulted && S_AXI_BVALID && S_AXI_BREADY
				&& S_AXI_BRESP == OKAY
				&&(!(&cvr_writes)))
				cvr_writes <= cvr_writes + 1;

			always @(*)
				cover(cvr_writes > 5);

			initial	cvr_reads = 0;
			always @(posedge S_AXI_ACLK)
			if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
				cvr_reads <= 0;
			else if (read_faulted && S_AXI_RVALID && S_AXI_RREADY
				&& S_AXI_RRESP == OKAY
				&&(!(&cvr_reads)))
				cvr_reads <= cvr_reads + 1;

			always @(*)
				cover(cvr_reads > 5);
			// }}}
		end

		// }}}
	end endgenerate
	////////////////////////////////////////////////////////////////////////
	//
	// Never data properties
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//
	(* anyconst *) reg [C_AXI_DATA_WIDTH-1:0]	fc_never_read_data;
	(* anyconst *) reg [C_AXI_DATA_WIDTH+C_AXI_DATA_WIDTH/8-1:0]
						fc_never_write_data;

	(* anyconst *) reg [C_AXI_ADDR_WIDTH-1:0]	fc_never_read_addr,
						fc_never_write_addr;

	// Write address checking
	// {{{
	always @(*)
	if (S_AXI_ARESETN && S_AXI_AWVALID)
		assume(S_AXI_AWADDR != fc_never_write_addr);

	always @(*)
	if (S_AXI_ARESETN && M_AXI_ARESETN && !o_write_fault && M_AXI_AWVALID)
		assert(M_AXI_AWADDR != fc_never_write_addr);
	// }}}

	// Write checking
	// {{{
	always @(*)
	if (S_AXI_ARESETN && S_AXI_WVALID)
		assume({ S_AXI_WDATA, S_AXI_WSTRB } != fc_never_write_data);

	always @(*)
	if (S_AXI_ARESETN && M_AXI_ARESETN && !o_write_fault && M_AXI_WVALID)
		assert({ M_AXI_WDATA, M_AXI_WSTRB } != fc_never_write_data);
	// }}}

	// Read address checking
	// {{{
	always @(*)
	if (S_AXI_ARESETN && S_AXI_ARVALID)
		assume(S_AXI_ARADDR != fc_never_read_addr);

	always @(*)
	if (S_AXI_ARESETN && M_AXI_ARESETN && !o_read_fault && M_AXI_ARVALID)
		assert(M_AXI_ARADDR != fc_never_read_addr);
	// }}}

	// Read checking
	// {{{
	always @(*)
	if (S_AXI_ARESETN && M_AXI_ARESETN && M_AXI_RVALID)
		assume(M_AXI_RDATA != fc_never_read_data);

	always @(*)
	if (S_AXI_ARESETN && S_AXI_RVALID && S_AXI_RRESP == 2'b00)
		assert(S_AXI_RDATA != fc_never_read_data);
	// }}}

	// }}}

`endif
// }}}
endmodule
