////////////////////////////////////////////////////////////////////////////////
//
// Filename:	rtl/axisafety.v
// {{{
// Project:	WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose:	Given that 1) AXI interfaces can be difficult to write and to
//		get right, 2) my experiences with the AXI infrastructure of an
//	ARM+FPGA is that the device needs a power cycle following a bus fault,
//	and given that I've now found multiple interfaces that had some bug
//	or other within them, the following is a bus fault isolator.  It acts
//	as a bump in the log between the interconnect and the user core.  As
//	such, it has two interfaces:  The first is the slave interface,
//	coming from the interconnect.  The second interface is the master
//	interface, proceeding to a slave that might be faulty.
//
//		INTERCONNECT --> (S) AXISAFETY (M) --> POTENTIALLY FAULTY CORE
//
//	The slave interface has been formally verified to be a valid AXI
//	slave, independent of whatever the potentially faulty core might do.
//	If the user core (i.e. the potentially faulty one) responds validly
//	to the requests of a master, then this core will turn into a simple
//	delay on the bus.  If, on the other hand, the user core suffers from
//	a protocol error, then this core will set one of two output
//	flags--either o_write_fault or o_read_fault indicating whether a write
//	or a read fault was detected.  Further attempts to access the user
//	core will result in bus errors, generated by the AXISAFETY core.
//
//	Assuming the bus master can properly detect and deal with a bus error,
//	this should then make it possible to properly recover from a bus
//	protocol error without later needing to cycle power.
//
//	The core does have a couple of limitations.  For example, it can only
//	handle one burst transaction, and one ID at a time.  This matches the
//	performances of Xilinx's example AXI full core, from which many user
//	cores have have been copied/modified from.  Therefore, there will be
//	no performance loss for such a core.
//
//	Because of this, it is still possible that the user core might have an
//	undetected fault when using this core.  For example, if the interconnect
//	issues more than one bus request before receiving the response from the
//	first request, this safety core will stall the second request,
//	preventing the downstream core from seeing this second request.  If the
//	downstream core would suffer from an error while handling the second
//	request, by preventing the user core from seeing the second request this
//	core eliminates that potential for error.
//
// Usage:	The important part of using this core is to connect the slave
//		side to the interconnect, and the master side to the user core.
//
//	Some options are available:
//
//	1) C_S_AXI_ADDR_WIDTH	The number of address bits in the AXI channel
//	1) C_S_AXI_DATA_WIDTH	The number of data bits in the AXI channel
//	3) C_S_AXI_ID_WIDTH	The number of bits in an AXI ID.  As currently
//		written, this number cannot be zero.  You can, however, set it
//		to '1' and connect all of the relevant ID inputs to zero.
//
//	These three parameters have currently been abbreviated with AW, DW, and
//	IW.  I anticipate returning them to their original meanings, I just
//	haven't done so (yet).
//
//	4) OPT_TIMEOUT		This is the number of clock periods, from
//		interconnect request to interconnect response, that the
//		slave needs to respond within.  (The actual timeout from the
//		user slave's perspective will be shorter than this.)
//
//		This timeout is part of the check that a slave core will
//		always return a response.  From the standpoint of this core,
//		it can be set arbitrarily large.  (From the standpoint of
//		formal verification, it needs to be kept short ...)
//		Feel free to set this even as large as 1ms if you would like.
//
//	5) OPT_SELF_RESET	If set, will send a reset signal to the slave
//		following any write or read fault.  This will cause the other
//		side of the link (write or read) to fault as well.  Once the
//		channel then becomes inactive, the slave will be released from
//		reset and will be able to interact with the rest of the bus
//		again.
//
//	5) OPT_EXCLUSIVE	If clear, will prohibit the slave from ever
//		receiving an exclusive access request.  This saves the logic
//		in the firewall necessary to check that an EXOKAY response
//		to a write request was truly an allowed response.  Since that
//		logic can explode with the ID width, sparing it can be quite
//		useful.  If set, provides full exclusive access checking in
//		addition to the normal bus fault checking.
//
// Performance:	As mentioned above, this core can handle one read burst and one
//		write burst at a time, no more.  Further, the core will delay
//	an input path by one clock and the output path by another clock, so that
//	the latency involved with using this core is a minimum of two extra
//	clocks beyond the latency user slave core.
//
//	Maximum write latency: N+3 clocks for a burst of N values
//	Maximum read latency:  N+3 clocks for a burst of N values
//
// Faults detected:
//
//	Write channel:
//		1. Raising BVALID prior to the last write value being sent
//			to the user/slave core.
//		2. Raising BVALID prior to accepting the write address
//		3. A BID return ID that doesn't match the request AWID
//		4. Sending too many returns, such as not dropping BVALID
//			or raising it when there is no outstanding write
//			request
//
//		While the following technically isn't a violation of the
//		AXI protocol, it is treated as such by this fault isolator.
//
//		5. Accepting write data prior to the write address
//
//		The fault isolator will guarantee that AWVALID is raised before
//		WVALID, so this shouldn't be a problem.
//
//	Read channel:
//
//		1. Raising RVALID before accepting the read address, ARVALID
//		2. A return ID that doesn't match the ID that was sent.
//		3. Raising RVALID after the last return value, and so returning
//			too many response values
//		4. Setting the RLAST value on anything but the last value from
//			the bus.
//
//
// 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 axisafety #(
	// {{{
	parameter C_S_AXI_ID_WIDTH	= 1,
	parameter C_S_AXI_DATA_WIDTH	= 32,
	parameter C_S_AXI_ADDR_WIDTH	= 16,
	// OPT_SELF_RESET: Set to true if the downstream slave should be
	// reset upon detecting an error and separate from the upstream reset
	// domain
	parameter [0:0] OPT_SELF_RESET  = 1'b0,
	// OPT_EXCLUSIVE: Set to true if the downstream slave might possibly
	// offer an exclusive access capability
	parameter [0:0] OPT_EXCLUSIVE  = 1'b0,
	//
	// I use the following abbreviations, IW, DW, and AW, to simplify
	// the code below (and to help it fit within an 80 col terminal)
	localparam	IW	= C_S_AXI_ID_WIDTH,
	localparam	DW	= C_S_AXI_DATA_WIDTH,
	localparam	AW	= C_S_AXI_ADDR_WIDTH,
	//
	// OPT_TIMEOUT references the number of clock cycles to wait
	// between raising the *VALID signal and when the respective
	// *VALID return signal must be high.  You might wish to set this
	// to a very high number, to allow your core to work its magic.
	parameter	OPT_TIMEOUT = 20
	// }}}
	) (
		// {{{
		output	reg	o_read_fault,
		output	reg	o_write_fault,
		// User ports ends
		// Do not modify the ports beyond this line

		// Global Clock Signal
		input	wire			S_AXI_ACLK,
		// Global Reset Signal. This Signal is Active LOW
		input	wire			S_AXI_ARESETN,
		output	reg			M_AXI_ARESETN,
		//
		// The input side.  This is where slave requests come into
		// the core.
		// {{{
		//
		//	Write address
		input	wire [IW-1 : 0]		S_AXI_AWID,
		input	wire [AW-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	reg			S_AXI_AWREADY,
		//	Write data
		input	wire [DW-1 : 0]		S_AXI_WDATA,
		input	wire [(DW/8)-1 : 0]	S_AXI_WSTRB,
		input	wire			S_AXI_WLAST,
		input	wire			S_AXI_WVALID,
		output	reg			S_AXI_WREADY,
		//	Write return
		output	reg [IW-1 : 0]		S_AXI_BID,
		output	reg [1 : 0]		S_AXI_BRESP,
		output	reg			S_AXI_BVALID,
		input	wire			S_AXI_BREADY,
		//	Read address
		input	wire [IW-1 : 0]		S_AXI_ARID,
		input	wire [AW-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	reg			S_AXI_ARREADY,
		//	Read data
		output	reg [IW-1 : 0]		S_AXI_RID,
		output	reg [DW-1 : 0]		S_AXI_RDATA,
		output	reg [1 : 0]		S_AXI_RRESP,
		output	reg			S_AXI_RLAST,
		output	reg			S_AXI_RVALID,
		input	wire			S_AXI_RREADY,
		// }}}
		//
		// The output side, where slave requests are forwarded to the
		// actual slave
		// {{{
		//	Write address
		// {{{
		output	reg [IW-1 : 0]		M_AXI_AWID,
		output	reg [AW-1 : 0]		M_AXI_AWADDR,
		output	reg [7 : 0]		M_AXI_AWLEN,
		output	reg [2 : 0]		M_AXI_AWSIZE,
		output	reg [1 : 0]		M_AXI_AWBURST,
		output	reg			M_AXI_AWLOCK,
		output	reg [3 : 0]		M_AXI_AWCACHE,
		output	reg [2 : 0]		M_AXI_AWPROT,
		output	reg [3 : 0]		M_AXI_AWQOS,
		output	reg			M_AXI_AWVALID,
		input	wire			M_AXI_AWREADY,
		//	Write data
		output	reg [DW-1 : 0]		M_AXI_WDATA,
		output	reg [(DW/8)-1 : 0]	M_AXI_WSTRB,
		output	reg			M_AXI_WLAST,
		output	reg			M_AXI_WVALID,
		input	wire			M_AXI_WREADY,
		//	Write return
		input	wire [IW-1 : 0]		M_AXI_BID,
		input	wire [1 : 0]		M_AXI_BRESP,
		input	wire			M_AXI_BVALID,
		output	wire			M_AXI_BREADY,
		// }}}
		//	Read address
		// {{{
		output	reg [IW-1 : 0]		M_AXI_ARID,
		output	reg [AW-1 : 0]		M_AXI_ARADDR,
		output	reg [7 : 0]		M_AXI_ARLEN,
		output	reg [2 : 0]		M_AXI_ARSIZE,
		output	reg [1 : 0]		M_AXI_ARBURST,
		output	reg			M_AXI_ARLOCK,
		output	reg [3 : 0]		M_AXI_ARCACHE,
		output	reg [2 : 0]		M_AXI_ARPROT,
		output	reg [3 : 0]		M_AXI_ARQOS,
		output	reg			M_AXI_ARVALID,
		input	wire			M_AXI_ARREADY,
		//	Read data
		input	wire [IW-1 : 0]		M_AXI_RID,
		input	wire [DW-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
		// }}}
		// }}}
		// }}}
	);

	localparam	LGTIMEOUT = $clog2(OPT_TIMEOUT+1);
	localparam [1:0]	OKAY = 2'b00, EXOKAY = 2'b01;
	localparam	SLAVE_ERROR = 2'b10;
	//
	//
	// Register declarations
	// {{{
	reg			faulty_write_return, faulty_read_return;
	reg			clear_fault;
	//
	// Timer/timeout variables
	reg	[LGTIMEOUT-1:0]	write_timer,   read_timer;
	reg			write_timeout, read_timeout;

	//
	// Double buffer the write address channel
	reg		r_awvalid, m_awvalid;
	reg	[IW-1:0] r_awid,   m_awid;
	reg	[AW-1:0] r_awaddr, m_awaddr;
	reg	[7:0]	r_awlen,   m_awlen;
	reg	[2:0]	r_awsize,  m_awsize;
	reg	[1:0]	r_awburst, m_awburst;
	reg		r_awlock,  m_awlock;
	reg	[3:0]	r_awcache, m_awcache;
	reg	[2:0]	r_awprot,  m_awprot;
	reg	[3:0]	r_awqos,   m_awqos;

	//
	// Double buffer for the write channel
	reg			r_wvalid,m_wvalid;
	reg	[DW-1:0]	r_wdata, m_wdata;
	reg	[DW/8-1:0]	r_wstrb, m_wstrb;
	reg			r_wlast, m_wlast;

	//
	// Double buffer the write response channel
	reg			m_bvalid;	// r_bvalid == 0
	reg	[IW-1:0]	m_bid;
	reg	[1:0]		m_bresp;

	//
	// Double buffer the read address channel
	reg		r_arvalid, m_arvalid;
	reg	[IW-1:0]	r_arid,    m_arid;
	reg	[AW-1:0] r_araddr, m_araddr;
	reg	[7:0]	r_arlen,   m_arlen;
	reg	[2:0]	r_arsize,  m_arsize;
	reg	[1:0]	r_arburst, m_arburst;
	reg		r_arlock,  m_arlock;
	reg	[3:0]	r_arcache, m_arcache;
	reg	[2:0]	r_arprot,  m_arprot;
	reg	[3:0]	r_arqos,   m_arqos;

	//
	// Double buffer the read data response channel
	reg			r_rvalid,m_rvalid;
	reg	[IW-1:0]	         m_rid;
	reg	[1:0]		r_rresp, m_rresp;
	reg			         m_rlast;
	reg	[DW-1:0]	r_rdata, m_rdata;

	//
	// Write FIFO data
	wire	[IW-1:0]	wfifo_id;
	wire			wfifo_lock;

	//
	// Read FIFO data
	reg	[IW-1:0]	rfifo_id;
	reg			rfifo_lock;
	reg	[8:0]		rfifo_counter;
	reg			rfifo_empty, rfifo_last, rfifo_penultimate;

	//
	//
	reg	[0:0]	s_wbursts;
	reg	[8:0]	m_wpending;
	reg		m_wempty, m_wlastctr;
	wire		waddr_valid, raddr_valid;

	wire			lock_enabled, lock_failed;
	wire	[(1<<IW)-1:0]	lock_active;
	reg			rfifo_first, exread;
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Write channel processing
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	// Write address processing
	// {{{
	// S_AXI_AWREADY
	// {{{
	initial	S_AXI_AWREADY = (OPT_SELF_RESET) ? 0:1;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_AWREADY <= !OPT_SELF_RESET;
	else if (S_AXI_AWVALID && S_AXI_AWREADY)
		S_AXI_AWREADY <= 0;
	// else if (clear_fault)
	//	S_AXI_AWREADY <= 1;
	else if (!S_AXI_AWREADY)
		S_AXI_AWREADY <= S_AXI_BVALID && S_AXI_BREADY;
	// }}}

	generate if (OPT_EXCLUSIVE)
	begin : GEN_LOCK_ENABLED
		// {{{
		reg	r_lock_enabled, r_lock_failed;

		// lock_enabled
		// {{{
		initial	r_lock_enabled = 0;
		always @(posedge S_AXI_ACLK)
		if (!S_AXI_ARESETN || !OPT_EXCLUSIVE)
			r_lock_enabled <= 0;
		else if (S_AXI_AWVALID && S_AXI_AWREADY)
			r_lock_enabled <= S_AXI_AWLOCK && lock_active[S_AXI_AWID];
		else if (S_AXI_BVALID && S_AXI_BREADY)
			r_lock_enabled <= 0;
		// }}}

		// lock_failed
		// {{{
		initial	r_lock_failed = 0;
		always @(posedge S_AXI_ACLK)
		if (!S_AXI_ARESETN || !OPT_EXCLUSIVE)
			r_lock_failed <= 0;
		else if (S_AXI_AWVALID && S_AXI_AWREADY)
			r_lock_failed <= S_AXI_AWLOCK && !lock_active[S_AXI_AWID];
		else if (S_AXI_BVALID && S_AXI_BREADY)
			r_lock_failed <= 0;
		// }}}

		assign	lock_enabled = r_lock_enabled;
		assign	lock_failed  = r_lock_failed;
		// }}}
	end else begin : NO_LOCK_ENABLE
		// {{{
		assign	lock_enabled = 0;
		assign	lock_failed  = 0;
		// }}}
	end endgenerate

	// waddr_valid
	// {{{
	generate if (OPT_SELF_RESET)
	begin : GEN_LCL_RESET
		reg	r_waddr_valid;

		initial	r_waddr_valid = 0;
		always @(posedge S_AXI_ACLK)
		if (!S_AXI_ARESETN)
			r_waddr_valid <= 0;
		else if (S_AXI_AWVALID && S_AXI_AWREADY)
			r_waddr_valid <= 1;
		else if (waddr_valid)
			r_waddr_valid <= !S_AXI_BVALID || !S_AXI_BREADY;

		assign	waddr_valid = r_waddr_valid;
	end else begin : NO_LCL_RESET
		assign	waddr_valid = !S_AXI_AWREADY;
	end endgenerate
	// }}}

	// r_aw*
	// {{{
	// Double buffer for the AW* channel
	//
	initial	r_awvalid = 0;
	always @(posedge S_AXI_ACLK)
	begin
		if (S_AXI_AWVALID && S_AXI_AWREADY)
		begin
			r_awvalid <= 1'b0;
			r_awid    <= S_AXI_AWID;
			r_awaddr  <= S_AXI_AWADDR;
			r_awlen   <= S_AXI_AWLEN;
			r_awsize  <= S_AXI_AWSIZE;
			r_awburst <= S_AXI_AWBURST;
			r_awlock  <= S_AXI_AWLOCK;
			r_awcache <= S_AXI_AWCACHE;
			r_awprot  <= S_AXI_AWPROT;
			r_awqos   <= S_AXI_AWQOS;
		end else if (M_AXI_AWREADY)
			r_awvalid <= 0;

		if (!S_AXI_ARESETN)
		begin
			r_awvalid <= 0;
			r_awlock  <= 0;
		end

		if (!OPT_EXCLUSIVE)
			r_awlock <= 1'b0;
	end
	// }}}

	// m_aw*
	// {{{
	// Second half of the AW* double-buffer.  The m_* terms reference
	// either the value in the double buffer (assuming one is in there),
	// or the incoming value (if the double buffer is empty)
	//
	always @(*)
	if (r_awvalid)
	begin
		m_awvalid = r_awvalid;
		m_awid    = r_awid;
		m_awaddr  = r_awaddr;
		m_awlen   = r_awlen;
		m_awsize  = r_awsize;
		m_awburst = r_awburst;
		m_awlock  = r_awlock;
		m_awcache = r_awcache;
		m_awprot  = r_awprot;
		m_awqos   = r_awqos;
	end else begin
		m_awvalid = S_AXI_AWVALID && S_AXI_AWREADY;
		m_awid    = S_AXI_AWID;
		m_awaddr  = S_AXI_AWADDR;
		m_awlen   = S_AXI_AWLEN;
		m_awsize  = S_AXI_AWSIZE;
		m_awburst = S_AXI_AWBURST;
		m_awlock  = S_AXI_AWLOCK && OPT_EXCLUSIVE;
		m_awcache = S_AXI_AWCACHE;
		m_awprot  = S_AXI_AWPROT;
		m_awqos   = S_AXI_AWQOS;
	end
	// }}}

	// M_AXI_AW*
	// {{{
	// Set the output AW* channel outputs--but only on no fault
	//
	initial	M_AXI_AWVALID = 0;
	always @(posedge S_AXI_ACLK)
	begin
		if (!M_AXI_AWVALID || M_AXI_AWREADY)
		begin

			if (o_write_fault)
				M_AXI_AWVALID <= 0;
			else
				M_AXI_AWVALID <= m_awvalid;

			M_AXI_AWID    <= m_awid;
			M_AXI_AWADDR  <= m_awaddr;
			M_AXI_AWLEN   <= m_awlen;
			M_AXI_AWSIZE  <= m_awsize;
			M_AXI_AWBURST <= m_awburst;
			M_AXI_AWLOCK  <= m_awlock && lock_active[m_awid];
			M_AXI_AWCACHE <= m_awcache;
			M_AXI_AWPROT  <= m_awprot;
			M_AXI_AWQOS   <= m_awqos;
		end

		if (!OPT_EXCLUSIVE)
			M_AXI_AWLOCK  <= 0;
		if (!M_AXI_ARESETN)
			M_AXI_AWVALID <= 0;
	end
	// }}}
	// }}}

	// s_wbursts
	// {{{
	// Count write bursts outstanding from the standpoint of
	// the incoming (slave) channel
	//
	// Notice that, as currently built, the count can only ever be one
	// or zero.
	//
	// We'll use this count in a moment to determine if a response
	// has taken too long, or if a response is returned when there's
	// no outstanding request
	initial	s_wbursts = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		s_wbursts <= 0;
	else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST)
		s_wbursts <= 1;
	else if (S_AXI_BVALID && S_AXI_BREADY)
		s_wbursts <= 0;
	// }}}

	// wfifo_id, wfifo_lock
	// {{{
	// Keep track of the ID of the last transaction.  Since we only
	// ever have one write transaction outstanding, this will need to be
	// the ID of the returned value.

	assign	wfifo_id = r_awid;
	assign	wfifo_lock = r_awlock;
	// }}}

	// m_wpending, m_wempty, m_wlastctr
	// {{{
	// m_wpending counts the number of (remaining) write data values that
	// need to be sent to the slave.  It counts this number with respect
	// to the *SLAVE*, not the master.  When m_wpending == 1, WLAST shall
	// be true.  To make comparisons of (m_wpending == 0) or (m_wpending>0),
	// m_wempty is assigned to (m_wpending).  Similarly, m_wlastctr is
	// assigned to (m_wpending == 1).
	//
	initial	m_wpending = 0;
	initial	m_wempty   = 1;
	initial	m_wlastctr = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_write_fault)
	begin
		// {{{
		m_wpending <= 0;
		m_wempty   <= 1;
		m_wlastctr <= 0;
		// }}}
	end else if (M_AXI_AWVALID && M_AXI_AWREADY)
	begin
		// {{{
		if (M_AXI_WVALID && M_AXI_WREADY)
		begin
			// {{{
			// Accepting AW* and W* packets on the same
			// clock
			if (m_wpending == 0)
			begin
				// The AW* and W* packets go together
				m_wpending <= {1'b0, M_AXI_AWLEN};
				m_wempty   <= (M_AXI_AWLEN == 0);
				m_wlastctr <= (M_AXI_AWLEN == 1);
			end else begin
				// The W* packet goes with the last
				// AW* command, the AW* packet with a
				// new one
				m_wpending <= M_AXI_AWLEN+1;
				m_wempty   <= 0;
				m_wlastctr <= (M_AXI_AWLEN == 0);
			end
			// }}}
		end else begin
			// {{{
			m_wpending <= M_AXI_AWLEN+1;
			m_wempty   <= 0;
			m_wlastctr <= (M_AXI_AWLEN == 0);
			// }}}
		end
		// }}}
	end else if (M_AXI_WVALID && M_AXI_WREADY && (!m_wempty))
	begin
		// {{{
		// The AW* channel is idle, and we just accepted a value
		// on the W* channel
		m_wpending <= m_wpending - 1;
		m_wempty   <= (m_wpending <= 1);
		m_wlastctr <= (m_wpending == 2);
		// }}}
	end
	// }}}

	// Write data processing
	// {{{
	// S_AXI_WREADY
	// {{{
	// The S_AXI_WREADY or write channel stall signal
	//
	// For this core, we idle at zero (stalled) until an AW* packet
	// comes through
	//
	initial	S_AXI_WREADY = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_WREADY <= 0;
	else if (S_AXI_WVALID && S_AXI_WREADY)
	begin
		// {{{
		if (S_AXI_WLAST)
			S_AXI_WREADY <= 0;
		else if (o_write_fault)
			S_AXI_WREADY <= 1;
		else if (!M_AXI_WVALID || M_AXI_WREADY)
			S_AXI_WREADY <= 1;
		else
			S_AXI_WREADY <= 0;
		// }}}
	end else if ((s_wbursts == 0)&&(waddr_valid)
				&&(o_write_fault || M_AXI_WREADY))
		S_AXI_WREADY <= 1;
	else if (S_AXI_AWVALID && S_AXI_AWREADY)
		S_AXI_WREADY <= 1;
	// }}}

	// r_w*
	// {{{
	// Double buffer for the write channel
	//
	// As before, the r_* values contain the values in the double
	// buffer itself
	//
	initial	r_wvalid = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		r_wvalid <= 0;
	else if (!r_wvalid)
	begin
		// {{{
		r_wvalid <= (S_AXI_WVALID && S_AXI_WREADY
				&& M_AXI_WVALID && !M_AXI_WREADY);
		r_wdata <= S_AXI_WDATA;
		r_wstrb <= S_AXI_WSTRB;
		r_wlast <= S_AXI_WLAST;
		// }}}
	end else if (o_write_fault || M_AXI_WREADY || !M_AXI_ARESETN)
		r_wvalid <= 0;
	// }}}

	// m_w*
	// {{{
	// Here's the result of our double buffer
	//
	// m_* references the value within the double buffer in the case that
	// something is in the double buffer.  Otherwise, it is the values
	// directly from the inputs.  In the case of a fault, neither is true.
	// Write faults override.
	//
	always @(*)
	if (o_write_fault)
	begin
		// {{{
		m_wvalid = !m_wempty;
		m_wlast  = m_wlastctr;
		m_wstrb  = 0;
		// }}}
	end else if (r_wvalid)
	begin
		// {{{
		m_wvalid = 1;
		m_wstrb  = r_wstrb;
		m_wlast  = r_wlast;
		// }}}
	end else begin
		// {{{
		m_wvalid = S_AXI_WVALID && S_AXI_WREADY;
		m_wstrb  = S_AXI_WSTRB;
		m_wlast  = S_AXI_WLAST;
		// }}}
	end
	// }}}

	// m_wdata
	// {{{
	// The logic for the DATA output of the double buffer doesn't
	// matter so much in the case of o_write_fault
	always @(*)
	if (r_wvalid)
		m_wdata = r_wdata;
	else
		m_wdata = S_AXI_WDATA;
	// }}}

	// M_AXI_W*
	// {{{
	// Set the downstream write channel values
	//
	// As per AXI spec, these values *must* be registered.  Note that our
	// source here is the m_* double buffer/incoming write data switch.
	initial	M_AXI_WVALID = 0;
	always @(posedge S_AXI_ACLK)
	begin
		if (!M_AXI_WVALID || M_AXI_WREADY)
		begin
			M_AXI_WVALID <= m_wvalid;
			M_AXI_WDATA  <= m_wdata;
			M_AXI_WSTRB  <= m_wstrb;
			if (OPT_EXCLUSIVE && lock_failed)
				M_AXI_WSTRB <= 0;
			M_AXI_WLAST  <= m_wlast;
		end

		// Override the WVALID signal (only) on reset, voiding any
		// output we might otherwise send.
		if (!M_AXI_ARESETN)
			M_AXI_WVALID <= 0;
	end
	// }}}
	// }}}

	// Write fault detection
	// {{{
	// write_timer
	// {{{
	// The write timer
	//
	// The counter counts up to saturation.  It is reset any time
	// the write channel is either clear, or a value is accepted
	// at the *MASTER* (not slave) side.  Why the master side?  Simply
	// because it makes the proof below easier.  (At one time I checked
	// both, but then couldn't prove that the faults wouldn't get hit
	// if the slave responded in time.)
	initial	write_timer = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !waddr_valid)
		write_timer <= 0;
	else if (!o_write_fault && M_AXI_BVALID)
		write_timer <= 0;
	else if (S_AXI_WREADY)
		write_timer <= 0;
	else if (!(&write_timer))
		write_timer <= write_timer + 1;
	// }}}

	// write_timeout
	// {{{
	// Write timeout detector
	//
	// If the write_timer reaches the OPT_TIMEOUT, then the write_timeout
	// will get set true.  This will force a fault, taking the write
	// channel off line.
	initial	write_timeout = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || clear_fault)
		write_timeout <= 0;
	else if (M_AXI_BVALID)
		write_timeout <= write_timeout;
	else if (S_AXI_WVALID && S_AXI_WREADY)
		write_timeout <= write_timeout;
	else if (write_timer >= OPT_TIMEOUT)
		write_timeout <= 1;
	// }}}

	// faulty_write_return
	// {{{
	// fault_write_return
	//
	// This combinational logic is used to catch an invalid return, and
	// so take the slave off-line before the return can corrupt the master
	// channel.  Reasons for taking the write return off line are listed
	// below.
	always @(*)
	begin
		faulty_write_return = 0;
		if (M_AXI_WVALID && M_AXI_WREADY
				&& M_AXI_AWVALID && !M_AXI_AWREADY)
			// Accepting the write *data* prior to the write
			// *address* is a fault
			faulty_write_return = 1;
		if (M_AXI_BVALID)
		begin
			if (M_AXI_AWVALID || M_AXI_WVALID)
				// Returning a B* acknowledgement while the
				// request remains outstanding is also a fault
				faulty_write_return = 1;
			if (!m_wempty)
				// Same as above, but this time the write
				// channel is neither complete, nor is *WVALID
				// active.  Values remain to be written,
				// and so a return is a fault.
				faulty_write_return = 1;
			if (s_wbursts <= (S_AXI_BVALID ? 1:0))
				// Too many acknowledgments
				//
				// Returning more than one BVALID&BREADY for
				// every AWVALID & AWREADY is a fault.
				faulty_write_return = 1;
			if (M_AXI_BID != wfifo_id)
				// An attempt to return the wrong ID
				faulty_write_return = 1;
			if (M_AXI_BRESP == EXOKAY && (!OPT_EXCLUSIVE
					|| !lock_enabled))
				// An attempt to return a valid lock, without
				// a prior request
				faulty_write_return = 1;
		end
	end
	// }}}

	// o_write_fault
	// {{{
	// On a write fault, we're going to disconnect the write port from
	// the slave, and return errors on each write connect.  o_write_fault
	// is our signal determining if the write channel is disconnected.
	//
	// Most of this work is determined within faulty_write_return above.
	// Here we do just a bit more:
	initial	o_write_fault = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || clear_fault)
		o_write_fault <= 0;
	else if ((!M_AXI_ARESETN&&o_read_fault) || write_timeout)
		o_write_fault <= 1;
	else if (M_AXI_BVALID && M_AXI_BREADY)
		o_write_fault <= (o_write_fault) || faulty_write_return;
	else if (M_AXI_WVALID && M_AXI_WREADY
			&& M_AXI_AWVALID && !M_AXI_AWREADY)
		// Accepting the write data prior to the write address
		// is a fault
		o_write_fault <= 1;
	// }}}
	// }}}

	// Write return generation
	// {{{
	// m_b*
	// {{{
	// Since we only ever allow a single write burst at a time, we don't
	// need to double buffer the return channel.  Hence, we'll set our
	// return channel based upon the incoming values alone.  Note that
	// we're overriding the M_AXI_BID below, in order to make certain that
	// the return goes to the right source.
	//
	always @(*)
	if (o_write_fault)
	begin
		m_bvalid = (s_wbursts > (S_AXI_BVALID ? 1:0));
		m_bid    = wfifo_id;
		m_bresp  = SLAVE_ERROR;
	end else begin
		m_bvalid = M_AXI_BVALID;
		if (faulty_write_return)
			m_bvalid = 0;
		m_bid    = wfifo_id;
		m_bresp  = M_AXI_BRESP;
	end
	// }}}

	// S_AXI_B*
	// {{{
	// We'll *never* stall the slaves BREADY channel
	//
	// If the slave returns the response we are expecting, then S_AXI_BVALID
	// will be low and it can go directly into the S_AXI_BVALID slot.  If
	// on the other hand the slave returns M_AXI_BVALID at the wrong time,
	// then we'll quietly accept it and send the write interface into
	// fault detected mode, setting o_write_fault.
	//
	// Sadly, this will create a warning in Vivado.  If/when you see it,
	// see this note and then just ignore it.
	assign M_AXI_BREADY = 1;

	//
	// Return a write acknowlegement at the end of every write
	// burst--regardless of whether or not the slave does so
	//
	initial	S_AXI_BVALID = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_BVALID <= 0;
	else if (!S_AXI_BVALID || S_AXI_BREADY)
		S_AXI_BVALID <= m_bvalid;

	//
	// Set the values associated with the response
	//
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_BVALID || S_AXI_BREADY)
	begin
		S_AXI_BID    <= m_bid;
		S_AXI_BRESP  <= m_bresp;
	end
	// }}}

	// }}}

	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Read channel processing
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

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

	// S_AXI_ARREADY
	// {{{
	initial	S_AXI_ARREADY = (OPT_SELF_RESET) ? 0:1;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_ARREADY <= !OPT_SELF_RESET;
	else if (S_AXI_ARVALID && S_AXI_ARREADY)
		S_AXI_ARREADY <= 0;
	// else if (clear_fault)
	//	S_AXI_ARREADY <= 1;
	else if (!S_AXI_ARREADY)
		S_AXI_ARREADY <= (S_AXI_RVALID && S_AXI_RLAST && S_AXI_RREADY);
	// }}}

	// raddr_valid
	// {{{
	generate if (OPT_SELF_RESET)
	begin : GEN_READ_RESET
		assign	raddr_valid = !rfifo_empty;
	end else begin : SIMPLE_RADDR_VALID
		assign	raddr_valid = !S_AXI_ARREADY;
	end endgenerate
	// }}}

	// r_ar*
	// {{{
	// Double buffer the values associated with any read address request
	//
	initial	r_arvalid = 0;
	always @(posedge S_AXI_ACLK)
	begin
		if (S_AXI_ARVALID && S_AXI_ARREADY)
		begin
			r_arvalid <= 0; // (M_AXI_ARVALID && !M_AXI_ARREADY);
			r_arid    <= S_AXI_ARID;
			r_araddr  <= S_AXI_ARADDR;
			r_arlen   <= S_AXI_ARLEN;
			r_arsize  <= S_AXI_ARSIZE;
			r_arburst <= S_AXI_ARBURST;
			r_arlock  <= S_AXI_ARLOCK;
			r_arcache <= S_AXI_ARCACHE;
			r_arprot  <= S_AXI_ARPROT;
			r_arqos   <= S_AXI_ARQOS;
		end else if (M_AXI_ARREADY)
			r_arvalid <= 0;

		if (!M_AXI_ARESETN)
			r_arvalid <= 0;
		if (!OPT_EXCLUSIVE || !S_AXI_ARESETN)
			r_arlock <= 1'b0;
	end
	// }}}

	// m_ar*
	// {{{
	always @(*)
	if (r_arvalid)
	begin
		m_arvalid = r_arvalid;
		m_arid    = r_arid;
		m_araddr  = r_araddr;
		m_arlen   = r_arlen;
		m_arsize  = r_arsize;
		m_arburst = r_arburst;
		m_arlock  = r_arlock;
		m_arcache = r_arcache;
		m_arprot  = r_arprot;
		m_arqos   = r_arqos;
	end else begin
		m_arvalid = S_AXI_ARVALID && S_AXI_ARREADY;
		m_arid    = S_AXI_ARID;
		m_araddr  = S_AXI_ARADDR;
		m_arlen   = S_AXI_ARLEN;
		m_arsize  = S_AXI_ARSIZE;
		m_arburst = S_AXI_ARBURST;
		m_arlock  = S_AXI_ARLOCK && OPT_EXCLUSIVE;
		m_arcache = S_AXI_ARCACHE;
		m_arprot  = S_AXI_ARPROT;
		m_arqos   = S_AXI_ARQOS;
	end
	// }}}

	// M_AXI_AR*
	// {{{
	// Set the downstream values according to the transaction we've just
	// received.
	//
	initial	M_AXI_ARVALID = 0;
	always @(posedge S_AXI_ACLK)
	begin
		if (!M_AXI_ARVALID || M_AXI_ARREADY)
		begin

			if (o_read_fault)
				M_AXI_ARVALID <= 0;
			else
				M_AXI_ARVALID <= m_arvalid;

			M_AXI_ARID    <= m_arid;
			M_AXI_ARADDR  <= m_araddr;
			M_AXI_ARLEN   <= m_arlen;
			M_AXI_ARSIZE  <= m_arsize;
			M_AXI_ARBURST <= m_arburst;
			M_AXI_ARLOCK  <= m_arlock && OPT_EXCLUSIVE;
			M_AXI_ARCACHE <= m_arcache;
			M_AXI_ARPROT  <= m_arprot;
			M_AXI_ARQOS   <= m_arqos;
		end

		if (!M_AXI_ARESETN)
			M_AXI_ARVALID <= 0;
	end
	// }}}

	// }}}

	//
	// Read fault detection
	// {{{

	// read_timer
	// {{{
	// First step: a timer.  The timer starts as soon as the S_AXI_ARVALID
	// is accepted.  Once that happens, rfifo_empty will no longer be true.
	// The count is reset any time the slave produces a value for us to
	// read.  Once the count saturates, it stops counting.
	initial	read_timer = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || clear_fault)
		read_timer <= 0;
	else if (rfifo_empty||(S_AXI_RVALID))
		read_timer <= 0;
	else if (M_AXI_RVALID)
		read_timer <= 0;
	else if (!(&read_timer))
		read_timer <= read_timer + 1;
	// }}}

	// read_timeout
	// {{{
	// Once the counter > OPT_TIMEOUT, we have a timeout condition.
	// We'll detect this one clock earlier below.  If we ever enter
	// a read time out condition, we'll set the read fault.  The read
	// timeout condition can only be cleared by a reset.
	initial	read_timeout = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || clear_fault)
		read_timeout <= 0;
	else if (rfifo_empty||S_AXI_RVALID)
		read_timeout <= read_timeout;
	else if (M_AXI_RVALID)
		read_timeout <= read_timeout;
	else if (read_timer == OPT_TIMEOUT)
		read_timeout <= 1;
	// }}}

	//
	// faulty_read_return
	// {{{
	// To avoid returning a fault from the slave, it is important to
	// determine within a single clock period whether or not the slaves
	// return value is at fault or not.  That's the purpose of the code
	// below.
	always @(*)
	begin
		faulty_read_return = 0;
		if (M_AXI_RVALID)
		begin
			if (M_AXI_ARVALID)
				// It is a fault to return data before the
				// request has been accepted
				faulty_read_return = 1;
			if (M_AXI_RID != rfifo_id)
				// It is a fault to return data from a
				// different ID
				faulty_read_return = 1;
			if (rfifo_last && (S_AXI_RVALID || !M_AXI_RLAST))
				faulty_read_return = 1;
			if (rfifo_penultimate && S_AXI_RVALID && (r_rvalid || !M_AXI_RLAST))
				faulty_read_return = 1;
			if (M_AXI_RRESP == EXOKAY && (!OPT_EXCLUSIVE || !rfifo_lock))
				faulty_read_return = 1;
			if (OPT_EXCLUSIVE && exread && M_AXI_RRESP == OKAY)
				// Can't switch from EXOKAY to OKAY
				faulty_read_return = 1;
			if ((!OPT_EXCLUSIVE || (!rfifo_first && !exread))
						&& M_AXI_RRESP == EXOKAY)
				// Can't switch from OKAY to EXOKAY
				faulty_read_return = 1;
		end
	end
	// }}}

	// o_read_fault
	// {{{
	initial	o_read_fault = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || clear_fault)
		o_read_fault <= 0;
	else if ((!M_AXI_ARESETN && o_write_fault) || read_timeout)
		o_read_fault <= 1;
	else if (M_AXI_RVALID)
	begin
		if (faulty_read_return)
			o_read_fault <= 1;
		if (!raddr_valid)
			// It is a fault if we haven't issued an AR* request
			// yet, and a value is returned
			o_read_fault <= 1;
	end
	// }}}

	// }}}

	//
	// Read return/acknowledgment processing
	// {{{


	// exread
	// {{{
	always @(posedge S_AXI_ACLK)
	if (!M_AXI_ARESETN || !OPT_EXCLUSIVE)
		exread <= 0;
	else if (M_AXI_RVALID && M_AXI_RREADY)
	begin
		if (!M_AXI_RRESP[1])
			exread <= (M_AXI_RRESP == EXOKAY);
	end else if (S_AXI_RVALID && S_AXI_RREADY)
	begin
		if (S_AXI_RLAST)
			exread <= 1'b0;
	end
	// }}}

	// r_rvalid
	// {{{
	// Step one, set/create the read return double buffer.  If r_rvalid
	// is true, there's a valid value in the double buffer location.
	//
	initial r_rvalid = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_read_fault)
		r_rvalid <= 0;
	else if (!r_rvalid)
	begin
		// {{{
		// Refuse to set the double-buffer valid on any fault.
		// That will also keep (below) M_AXI_RREADY high--so that
		// following the fault the slave might still (pretend) to
		// respond properly
		if (faulty_read_return)
			r_rvalid <= 0;
		else if (o_read_fault)
			r_rvalid <= 0;
		// If there's nothing in the double buffer, then we might
		// place something in there.  The double buffer only gets
		// filled under two conditions: 1) something is pending to be
		// returned, and 2) there's another return that we can't
		// stall and so need to accept here.
		r_rvalid <= M_AXI_RVALID && M_AXI_RREADY
				&& (S_AXI_RVALID && !S_AXI_RREADY);
		// }}}
	end else if (S_AXI_RREADY)
		// Once the up-stream read-channel clears, we can always
		// clear the double buffer
		r_rvalid <= 0;
	// }}}

	// r_rresp, r_rdata
	// {{{
	// Here's the actual values kept whenever r_rvalid is true.  This is
	// the double buffer.  Notice that r_rid and r_last are generated
	// locally, so not recorded here.
	//
	always @(posedge S_AXI_ACLK)
	if (!r_rvalid)
	begin
		r_rresp  <= M_AXI_RRESP;
		r_rdata  <= M_AXI_RDATA;
	end
	// }}}

	// M_AXI_RREADY
	// {{{
	// Stall the downstream channel any time there's something in the
	// double buffer.  In spite of the ! here, this is a registered value.
	assign M_AXI_RREADY = !r_rvalid;
	// }}}

	// rfifo_id, rfifo_lock
	// {{{
	// Copy the ID for later comparisons on the return
	always @(*)
		rfifo_id = r_arid;
	always @(*)
		rfifo_lock = r_arlock;
	// }}}

	// rfifo_[counter|empty|last|penultimate
	// {{{
	// Count the number of outstanding read elements.  This is the number
	// of read returns we still expect--from the upstream perspective.  The
	// downstream perspective will be off by both what's waiting for
	// S_AXI_RREADY and what's in the double buffer
	//
	initial	rfifo_counter    = 0;
	initial	rfifo_empty      = 1;
	initial	rfifo_last       = 0;
	initial	rfifo_penultimate= 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
	begin
		rfifo_counter    <= 0;
		rfifo_empty      <= 1;
		rfifo_last       <= 0;
		rfifo_penultimate<= 0;
	end else if (S_AXI_ARVALID && S_AXI_ARREADY)
	begin
		rfifo_counter <= S_AXI_ARLEN+1;
		rfifo_empty   <= 0;
		rfifo_last    <= (S_AXI_ARLEN == 0);
		rfifo_penultimate <= (S_AXI_ARLEN == 1);
	end else if (!rfifo_empty)
	begin
		if (S_AXI_RVALID && S_AXI_RREADY)
		begin
			rfifo_counter <= rfifo_counter - 1;
			rfifo_empty   <= (rfifo_counter <= 1);
			rfifo_last    <= (rfifo_counter == 2);
			rfifo_penultimate <= (rfifo_counter == 3);
		end
	end
	// }}}

	// lock_active
	// {{{
	generate if (OPT_EXCLUSIVE)
	begin : CALC_LOCK_ACTIVE
		// {{{
		genvar	gk;

		for(gk=0; gk<(1<<IW); gk=gk+1)
		begin : LOCK_PER_ID
			reg	r_lock_active;

			initial	r_lock_active = 0;
			always @(posedge S_AXI_ACLK)
			if (!S_AXI_ARESETN || !M_AXI_ARESETN
				|| faulty_read_return || faulty_write_return)
				r_lock_active <= 0;
			else if (M_AXI_RVALID && M_AXI_RREADY && rfifo_lock
					&& !S_AXI_ARREADY
					&& r_arid == gk[IW-1:0]
					&&(!faulty_read_return && !o_read_fault)
					&& M_AXI_RRESP == EXOKAY)
				r_lock_active <= 1;
			else if (M_AXI_BVALID && M_AXI_BREADY && wfifo_lock
					&& r_awid == gk[IW-1:0]
					&& (S_AXI_ARREADY
						|| r_arid != gk[IW-1:0]
						|| !r_arlock)
					&& M_AXI_BRESP == OKAY)
				r_lock_active <= 0;
			else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLOCK
					&& S_AXI_ARID == gk[IW-1:0])
				r_lock_active <= 0;

			assign	lock_active[gk] = r_lock_active;
		end
		// }}}
	end else begin : LOCK_NEVER_ACTIVE
		// {{{
		assign	lock_active = 0;

		// Keep Verilator happy
		// Verilator lint_off UNUSED
		wire	unused_lock;
		assign	unused_lock = &{ 1'b0, wfifo_lock };
		// Verilator lint_on  UNUSED
		// }}}
	end endgenerate
	// }}}

	// rfifo_first
	// {{{
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || !OPT_EXCLUSIVE)
		rfifo_first <= 1'b0;
	else if (S_AXI_ARVALID && S_AXI_ARREADY)
		rfifo_first <= 1'b1;
	else if (M_AXI_RVALID && M_AXI_RREADY)
		rfifo_first <= 1'b0;
	else if (o_read_fault)
		rfifo_first <= 1'b0;
	// }}}

	// m_rvalid, m_rresp
	// {{{
	// Determine values to send back and return
	//
	// This data set includes all the return values, even though only
	// RRESP and RVALID are set in this block.
	always @(*)
	if (o_read_fault || (!M_AXI_ARESETN && OPT_SELF_RESET))
	begin
		m_rvalid = !rfifo_empty;
		if (S_AXI_RVALID && rfifo_last)
			m_rvalid = 0;
		m_rresp  = SLAVE_ERROR;
	end else if (r_rvalid)
	begin
		m_rvalid = r_rvalid;
		m_rresp  = r_rresp;
	end else begin
		m_rvalid = M_AXI_RVALID && raddr_valid && !faulty_read_return;
		m_rresp  = M_AXI_RRESP;
	end
	// }}}

	// m_rid
	// {{{
	// We've stored the ID locally, so that our response will never be in
	// error
	always @(*)
		m_rid = rfifo_id;
	// }}}

	// m_rlast
	// {{{
	// Ideally, we'd want to say m_rlast = rfifo_last.  However, we might
	// have a value in S_AXI_RVALID already.  In that case, the last
	// value can only be true if we are one further away from the end.
	// (Remember, rfifo_last and rfifo_penultimate are both dependent upon
	// the *upstream* number of read values outstanding, not the downstream
	// number which we can't trust in all cases)
	always @(*)
	if (S_AXI_RVALID)
		m_rlast = rfifo_penultimate;
	else
		m_rlast = (rfifo_last);
	// }}}

	// m_rdata
	// {{{
	// In the case of a fault, rdata is a don't care.  Therefore we can
	// always set it based upon the values returned from the slave.
	always @(*)
	if (r_rvalid)
		m_rdata = r_rdata;
	else
		m_rdata = M_AXI_RDATA;
	// }}}

	// S_AXI_R*
	// {{{
	// Record our return data values
	//
	// These are the values from either the slave, the double buffer,
	// or an error value bypassing either as determined by the m_* values.
	// Per spec, all of these values must be registered.  First the valid
	// signal
	initial	S_AXI_RVALID = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN)
		S_AXI_RVALID <= 0;
	else if (!S_AXI_RVALID || S_AXI_RREADY)
		S_AXI_RVALID <= m_rvalid;

	// Then the various slave data channels
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_RVALID || S_AXI_RREADY)
	begin
		S_AXI_RID    <= m_rid;
		S_AXI_RRESP  <= m_rresp;
		S_AXI_RLAST  <= m_rlast;
		S_AXI_RDATA  <= m_rdata;
	end
	// }}}

	// }}}

	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Self-reset
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//
	generate if (OPT_SELF_RESET)
	begin : GEN_SELFRESET
		// {{{
		// Declarations
		// {{{
		reg	[4:0]	reset_counter;
		reg		r_clear_fault, w_clear_fault;
		wire		reset_timeout;
		// }}}

		// M_AXI_ARESETN
		// {{{
		initial	M_AXI_ARESETN = 0;
		always @(posedge S_AXI_ACLK)
		if (!S_AXI_ARESETN)
			M_AXI_ARESETN <= 0;
		else if (clear_fault)
			M_AXI_ARESETN <= 1;
		else if (o_read_fault || o_write_fault)
			M_AXI_ARESETN <= 0;
		// }}}

		// reset_counter
		// {{{
		initial	reset_counter = 0;
		always @(posedge S_AXI_ACLK)
		if (M_AXI_ARESETN)
			reset_counter <= 0;
		else if (!reset_timeout)
			reset_counter <= reset_counter+1;
		// }}}

		assign	reset_timeout = reset_counter[4];

		// r_clear_fault
		// {{{
		initial	r_clear_fault <= 1;
		always @(posedge S_AXI_ACLK)
		if (!S_AXI_ARESETN)
			r_clear_fault <= 1;
		else if (!M_AXI_ARESETN && !reset_timeout)
			r_clear_fault <= 0;
		else if (!o_read_fault && !o_write_fault)
			r_clear_fault <= 0;
		else if (raddr_valid || waddr_valid)
			r_clear_fault <= 0;
		else
			r_clear_fault <= 1;
		// }}}

		// clear_fault
		// {{{
		always @(*)
		if (S_AXI_AWVALID || S_AXI_ARVALID)
			w_clear_fault = 0;
		else if (raddr_valid || waddr_valid)
			w_clear_fault = 0;
		else
			w_clear_fault = r_clear_fault;

		assign	clear_fault = w_clear_fault;
		// }}}

		// }}}
	end else begin : NO_SELFRESET
		// {{{
		always @(*)
			M_AXI_ARESETN = S_AXI_ARESETN;
		assign	clear_fault = 0;
		// }}}
	end endgenerate
	// }}}

	// Make Verilator happy
	// {{{
	// Verilator lint_off UNUSED
	wire	unused;
	assign	unused = &{ 1'b0 };
	// Verilator lint_on  UNUSED
	// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal properties
// {{{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef	FORMAL
	// {{{
	// Below are just some of the formal properties used to verify
	// this core.  The full property set is maintained elsewhere.
	//
	parameter [0:0]	F_OPT_FAULTLESS = 1;

	//
	// ...
	// }}}

	faxi_slave	#(
		// {{{
		.C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
		.C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
		.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH)
		// ...
		// }}}
	) f_slave(
		// {{{
		.i_clk(S_AXI_ACLK),
		.i_axi_reset_n(S_AXI_ARESETN),
		//
		// Address write channel
		// {{{
		.i_axi_awid(S_AXI_AWID),
		.i_axi_awaddr(S_AXI_AWADDR),
		.i_axi_awlen(S_AXI_AWLEN),
		.i_axi_awsize(S_AXI_AWSIZE),
		.i_axi_awburst(S_AXI_AWBURST),
		.i_axi_awlock(S_AXI_AWLOCK),
		.i_axi_awcache(S_AXI_AWCACHE),
		.i_axi_awprot(S_AXI_AWPROT),
		.i_axi_awqos(S_AXI_AWQOS),
		.i_axi_awvalid(S_AXI_AWVALID),
		.i_axi_awready(S_AXI_AWREADY),
		// }}}
		// Write Data Channel
		// {{{
		.i_axi_wdata(S_AXI_WDATA),
		.i_axi_wstrb(S_AXI_WSTRB),
		.i_axi_wlast(S_AXI_WLAST),
		.i_axi_wvalid(S_AXI_WVALID),
		.i_axi_wready(S_AXI_WREADY),
		// }}}
		// Write response channel
		// {{{
		.i_axi_bid(S_AXI_BID),
		.i_axi_bresp(S_AXI_BRESP),
		.i_axi_bvalid(S_AXI_BVALID),
		.i_axi_bready(S_AXI_BREADY),
		// }}}
		// Read address channel
		// {{{
		.i_axi_arid(S_AXI_ARID),
		.i_axi_araddr(S_AXI_ARADDR),
		.i_axi_arlen(S_AXI_ARLEN),
		.i_axi_arsize(S_AXI_ARSIZE),
		.i_axi_arburst(S_AXI_ARBURST),
		.i_axi_arlock(S_AXI_ARLOCK),
		.i_axi_arcache(S_AXI_ARCACHE),
		.i_axi_arprot(S_AXI_ARPROT),
		.i_axi_arqos(S_AXI_ARQOS),
		.i_axi_arvalid(S_AXI_ARVALID),
		.i_axi_arready(S_AXI_ARREADY),
		// }}}
		// Read data return channel
		// {{{
		.i_axi_rvalid(S_AXI_RVALID),
		.i_axi_rready(S_AXI_RREADY),
		.i_axi_rid(S_AXI_RID),
		.i_axi_rdata(S_AXI_RDATA),
		.i_axi_rresp(S_AXI_RRESP),
		.i_axi_rlast(S_AXI_RLAST),
		// }}}
		// Formal induction values
		// {{{
		.f_axi_awr_nbursts(f_axi_awr_nbursts),
		.f_axi_wr_pending(f_axi_wr_pending),
		.f_axi_rd_nbursts(f_axi_rd_nbursts),
		.f_axi_rd_outstanding(f_axi_rd_outstanding)
		//
		// ...
		// }}}
		// }}}
	);

	////////////////////////////////////////////////////////////////////////
	//
	// Write induction properties
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	// 1. We will only ever handle a single burst--never any more
	always @(*)
		assert(f_axi_awr_nbursts <= 1);

	always @(*)
	if (f_axi_awr_nbursts == 1)
	begin
		assert(!S_AXI_AWREADY);
		if (S_AXI_BVALID)
			assert(f_axi_wr_pending == 0);
		if (!o_write_fault && M_AXI_AWVALID)
			assert(f_axi_wr_pending == M_AXI_AWLEN + 1
					- (M_AXI_WVALID ? 1:0)
					- (r_wvalid ? 1 : 0));
		if (!o_write_fault && f_axi_wr_pending > 0)
			assert((!M_AXI_WVALID || !M_AXI_WLAST)
					&&(!r_wvalid || !r_wlast));
		if (!o_write_fault && M_AXI_WVALID && M_AXI_WLAST)
			assert(!r_wvalid || !r_wlast);
	end else begin
		assert(s_wbursts == 0);
		assert(!S_AXI_WREADY);
		if (OPT_SELF_RESET)
		begin
			assert(1 || S_AXI_AWREADY || !M_AXI_ARESETN || !S_AXI_ARESETN);
		end else
			assert(S_AXI_AWREADY);
	end

	//
	// ...
	//

	//
	// AWREADY will always be low mid-burst
	always @(posedge S_AXI_ACLK)
	if (!f_past_valid || $past(!S_AXI_ARESETN))
	begin
		assert(S_AXI_AWREADY == !OPT_SELF_RESET);
	end else if (f_axi_wr_pending > 0)
	begin
		assert(!S_AXI_AWREADY);
	end else if (s_wbursts)
	begin
		assert(!S_AXI_AWREADY);
	end else if (!OPT_SELF_RESET)
	begin
		assert(S_AXI_AWREADY);
	end else if (!o_write_fault && !o_read_fault)
		assert(S_AXI_AWREADY || OPT_SELF_RESET);

	always @(*)
	if (f_axi_wr_pending > 0)
	begin
		assert(s_wbursts == 0);
	end else if (f_axi_awr_nbursts > 0)
	begin
		assert((s_wbursts ? 1:0) == f_axi_awr_nbursts);
	end else
		assert(s_wbursts == 0);

	always @(*)
	if (!o_write_fault && S_AXI_AWREADY)
		assert(!M_AXI_AWVALID);

	always @(*)
	if (M_AXI_ARESETN && (f_axi_awr_nbursts == 0))
	begin
		assert(o_write_fault || !M_AXI_AWVALID);
		assert(!S_AXI_BVALID);
		assert(s_wbursts == 0);
	end else if (M_AXI_ARESETN && s_wbursts == 0)
		assert(f_axi_wr_pending > 0);

	always @(*)
	if (S_AXI_WREADY)
	begin
		assert(waddr_valid);
	end else if (f_axi_wr_pending > 0)
	begin
		if (!o_write_fault)
			assert(M_AXI_WVALID && r_wvalid);
	end

	always @(*)
	if (!OPT_SELF_RESET)
	begin
		assert(waddr_valid == !S_AXI_AWREADY);
	end else begin
		// ...
		assert(waddr_valid == (f_axi_awr_nbursts > 0));
	end

	always @(*)
	if (S_AXI_ARESETN && !o_write_fault && f_axi_wr_pending > 0 && !S_AXI_WREADY)
		assert(M_AXI_WVALID);

	always @(*)
	if (S_AXI_ARESETN && !o_write_fault && m_wempty)
	begin
		assert(M_AXI_AWVALID || !M_AXI_WVALID);
		assert(M_AXI_AWVALID || f_axi_wr_pending == 0);
	end

	always @(*)
	if (S_AXI_ARESETN && M_AXI_AWVALID)
	begin
		if (!o_write_fault && !M_AXI_AWVALID)
		begin
			assert(f_axi_wr_pending + (M_AXI_WVALID ? 1:0) + (r_wvalid ? 1:0) == m_wpending);
		end else if (!o_write_fault)
		begin
			assert(f_axi_wr_pending == M_AXI_AWLEN + 1 - (M_AXI_WVALID ? 1:0) - (r_wvalid ? 1:0));
			assert(m_wpending == 0);
		end
	end

	always @(*)
		assert(m_wpending <= 9'h100);

	always @(*)
	if (M_AXI_ARESETN && (!o_write_fault)&&(f_axi_awr_nbursts == 0))
		assert(!M_AXI_AWVALID);

	always @(*)
	if (S_AXI_ARESETN && !o_write_fault)
	begin
		if (f_axi_awr_nbursts == 0)
		begin
			assert(!M_AXI_AWVALID);
			assert(!M_AXI_WVALID);
		end

		if (!M_AXI_AWVALID)
			assert(f_axi_wr_pending
					+(M_AXI_WVALID ? 1:0)
					+ (r_wvalid ? 1:0)
				== m_wpending);
		if (f_axi_awr_nbursts == (S_AXI_BVALID ? 1:0))
		begin
			assert(!M_AXI_AWVALID);
			assert(!M_AXI_WVALID);
		end

		if (S_AXI_BVALID)
			assert(f_axi_awr_nbursts == 1);

		if (M_AXI_AWVALID)
			assert(m_wpending == 0);

		if (S_AXI_AWREADY)
			assert(!M_AXI_AWVALID);
	end

	always @(*)
		assert(!r_awvalid);

	always @(*)
		assert(m_wempty == (m_wpending == 0));
	always @(*)
		assert(m_wlastctr == (m_wpending == 1));

	//
	// Verify the contents of the skid buffers
	//

	//
	// ...
	//

	always @(*)
	if (write_timer > OPT_TIMEOUT)
		assert(o_write_fault || write_timeout);

	always @(*)
	if (!OPT_SELF_RESET)
	begin
		assert(waddr_valid == !S_AXI_AWREADY);
	end else if (waddr_valid)
		assert(!S_AXI_AWREADY);

	always @(*)
	if (!o_write_fault && M_AXI_ARESETN)
		assert(waddr_valid == !S_AXI_AWREADY);

	always @(*)
	if (f_axi_wr_pending == 0)
		assert(!S_AXI_WREADY);
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Read induction properties
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//

	always @(*)
		assert(f_axi_rd_nbursts <= 1);
	always @(*)
		assert(raddr_valid == (f_axi_rd_nbursts>0));
	always @(*)
	if (f_axi_rdid_nbursts > 0)
	begin
		assert(rfifo_id == f_axi_rd_checkid);
	end else if (f_axi_rd_nbursts > 0)
		assert(rfifo_id != f_axi_rd_checkid);

	always @(*)
	if (f_axi_rd_nbursts > 0)
		assert(raddr_valid);

	always @(*)
	if (raddr_valid)
		assert(!S_AXI_ARREADY);

	always @(*)
	if (!OPT_SELF_RESET)
	begin
		assert(raddr_valid == !S_AXI_ARREADY);
	end else begin
		// ...
		assert(raddr_valid == (f_axi_rd_nbursts > 0));
	end

	//
	// ...
	//

	always @(*)
	if (f_axi_rd_outstanding == 0)
		assert(!raddr_valid || OPT_SELF_RESET);

	always @(*)
	if (!o_read_fault && S_AXI_ARREADY)
		assert(!M_AXI_ARVALID);

	// Our "FIFO" counter
	always @(*)
		assert(rfifo_counter == f_axi_rd_outstanding);

	always @(*)
	begin
		assert(rfifo_empty       == (rfifo_counter == 0));
		assert(rfifo_last        == (rfifo_counter == 1));
		assert(rfifo_penultimate == (rfifo_counter == 2));
	end

	//
	// ...
	//

	always @(*)
	if (r_arvalid)
		assert(skid_arvalid);

	always @(*)
	if (read_timer > OPT_TIMEOUT)
		assert(read_timeout);


	always @(posedge S_AXI_ACLK)
	if (OPT_SELF_RESET && (!f_past_valid || !$past(M_AXI_ARESETN)))
	begin
		assume(!M_AXI_BVALID);
		assume(!M_AXI_RVALID);
	end

	always @(*)
	if (!o_read_fault && M_AXI_ARESETN)
		assert(raddr_valid == !S_AXI_ARREADY);

	always @(*)
	if (f_axi_rd_nbursts > 0)
		assert(raddr_valid);

	always @(*)
	if (S_AXI_ARESETN && OPT_SELF_RESET)
	begin
		if (!M_AXI_ARESETN)
			assert(o_read_fault || o_write_fault /* ... */ );
	end
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Exclusive access property checking
	// {{{
	//
	////////////////////////////////////////////////////////////////////////
	//
	// ...
	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Cover properties
	//
	////////////////////////////////////////////////////////////////////////
	//
	// }}}

	////////////////////////////////////////////////////////////////////////
	//
	// Good interface check
	//
	////////////////////////////////////////////////////////////////////////
	//
	//
	generate if (F_OPT_FAULTLESS)
	begin : ASSUME_FAULTLESS
		// {{{
		//
		// ...
		//

		faxi_master #(
			// {{{
			.C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
			.C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
			.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH)
			// ...
			// }}}
		) f_master(
			// {{{
			.i_clk(S_AXI_ACLK),
			.i_axi_reset_n(M_AXI_ARESETN),
			//
			// Address write channel
			// {{{
			.i_axi_awid(M_AXI_AWID),
			.i_axi_awaddr(M_AXI_AWADDR),
			.i_axi_awlen(M_AXI_AWLEN),
			.i_axi_awsize(M_AXI_AWSIZE),
			.i_axi_awburst(M_AXI_AWBURST),
			.i_axi_awlock(M_AXI_AWLOCK),
			.i_axi_awcache(M_AXI_AWCACHE),
			.i_axi_awprot(M_AXI_AWPROT),
			.i_axi_awqos(M_AXI_AWQOS),
			.i_axi_awvalid(M_AXI_AWVALID),
			.i_axi_awready(M_AXI_AWREADY),
			// }}}
			// Write Data Channel
			// {{{
			.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_wlast(M_AXI_WLAST),
			// }}}
			// Write response channel
			// {{{
			.i_axi_bvalid(M_AXI_BVALID),
			.i_axi_bready(M_AXI_BREADY),
			.i_axi_bid(M_AXI_BID),
			.i_axi_bresp(M_AXI_BRESP),
			// }}}
			// Read address channel
			// {{{
			.i_axi_arid(M_AXI_ARID),
			.i_axi_araddr(M_AXI_ARADDR),
			.i_axi_arlen(M_AXI_ARLEN),
			.i_axi_arsize(M_AXI_ARSIZE),
			.i_axi_arburst(M_AXI_ARBURST),
			.i_axi_arlock(M_AXI_ARLOCK),
			.i_axi_arcache(M_AXI_ARCACHE),
			.i_axi_arprot(M_AXI_ARPROT),
			.i_axi_arqos(M_AXI_ARQOS),
			.i_axi_arvalid(M_AXI_ARVALID),
			.i_axi_arready(M_AXI_ARREADY),
			// }}}
			// Read data return channel
			// {{{
			.i_axi_rvalid(M_AXI_RVALID),
			.i_axi_rready(M_AXI_RREADY),
			.i_axi_rid(M_AXI_RID),
			.i_axi_rdata(M_AXI_RDATA),
			.i_axi_rresp(M_AXI_RRESP),
			.i_axi_rlast(M_AXI_RLAST),
			// }}}
			// Formal outputs
			// {{{
			.f_axi_awr_nbursts(fm_axi_awr_nbursts),
			.f_axi_wr_pending(fm_axi_wr_pending),
			.f_axi_rd_nbursts(fm_axi_rd_nbursts),
			.f_axi_rd_outstanding(fm_axi_rd_outstanding)
			//
			// ...
			// }}}
			// }}}
		);

		////////////////////////////////////////////////////////////////
		//
		// Contract: If the downstream has no faults, then we
		//	shouldn't detect any here.
		// {{{
		////////////////////////////////////////////////////////////////
		//
		//

		always @(*)
		if (OPT_SELF_RESET)
		begin
			assert(!o_write_fault || !M_AXI_ARESETN);
		end else
			assert(!o_write_fault);

		always @(*)
		if (OPT_SELF_RESET)
		begin
			assert(!o_read_fault || !M_AXI_ARESETN);
		end else
			assert(!o_read_fault);

		always @(*)
		if (OPT_SELF_RESET)
		begin
			assert(!read_timeout || !M_AXI_ARESETN);
		end else
			assert(!read_timeout);

		always @(*)
		if (OPT_SELF_RESET)
		begin
			assert(!write_timeout || !M_AXI_ARESETN);
		end else
			assert(!write_timeout);

		always @(*)
		if (S_AXI_AWREADY)
			assert(!M_AXI_AWVALID);

		//
		// ...
		//

		always @(*)
		if (M_AXI_ARESETN && f_axi_rd_nbursts > 0)
			assert(f_axi_rd_nbursts == fm_axi_rd_nbursts
				+ (M_AXI_ARVALID ? 1 : 0)
				+ (r_rvalid&&m_rlast ? 1 : 0)
				+ (S_AXI_RVALID&&S_AXI_RLAST ? 1 : 0));

		always @(*)
		if (M_AXI_ARESETN && f_axi_rd_outstanding > 0)
			assert(f_axi_rd_outstanding == fm_axi_rd_outstanding
				+ (M_AXI_ARVALID ? M_AXI_ARLEN+1 : 0)
				+ (r_rvalid ? 1 : 0)
				+ (S_AXI_RVALID ? 1 : 0));

		//
		// ...
		//
		always @(*)
		if (M_AXI_RVALID)
			assert(!M_AXI_ARVALID);

		always @(*)
		if (S_AXI_ARESETN)
			assert(m_wpending == fm_axi_wr_pending);

		always @(*)
		if (S_AXI_ARESETN && fm_axi_awr_nbursts > 0)
		begin
			assert(fm_axi_awr_nbursts== f_axi_awr_nbursts);
			assert(fm_axi_awr_nbursts == 1);
			//
			// ...
			//
		end
		// }}}
		////////////////////////////////////////////////////////////////
		//
		// Exclusive address checking
		// {{{
		////////////////////////////////////////////////////////////////
		//
		//

		//
		//
		// ...
		//

		////////////////////////////////////////////////////////////////
		//
		// Cover checks
		// {{{
		////////////////////////////////////////////////////////////////
		//
		//

		// }}}
		////////////////////////////////////////////////////////////////
		//
		// "Careless" assumptions
		// {{{
		////////////////////////////////////////////////////////////////
		//
		//
	end endgenerate

	//
	// ...
	//

	////////////////////////////////////////////////////////////////////////
	//
	// Never path check
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	//
	(* anyconst *) reg [C_S_AXI_ADDR_WIDTH-1:0]	fc_never_write_addr,
							fc_never_read_addr;
	(* anyconst *) reg [C_S_AXI_DATA_WIDTH + C_S_AXI_DATA_WIDTH/8-1:0]
							fc_never_write_data;
	(* anyconst *) reg [C_S_AXI_DATA_WIDTH-1:0]	fc_never_read_data;

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

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

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

	always @(posedge S_AXI_ACLK)
	if (S_AXI_ARESETN && !o_write_fault && M_AXI_ARESETN && M_AXI_WVALID)
	begin
		if (lock_failed)
			assert(M_AXI_WSTRB == 0);
		else
			assert({ M_AXI_WDATA, M_AXI_WSTRB } != fc_never_write_data);
	end
	// }}}

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

	always @(posedge S_AXI_ACLK)
	if (S_AXI_ARESETN && r_arvalid)
		assume(r_araddr != fc_never_read_addr);

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

	// Read data
	// {{{
	always @(posedge S_AXI_ACLK)
	if (S_AXI_ARESETN && M_AXI_ARESETN && M_AXI_RVALID)
		assume(M_AXI_RDATA != fc_never_read_data);

	always @(posedge S_AXI_ACLK)
	if (S_AXI_ARESETN && S_AXI_RVALID && S_AXI_RRESP != SLAVE_ERROR)
		assert(S_AXI_RDATA != fc_never_read_data);
	// }}}

	// }}}
	////////////////////////////////////////////////////////////////////////
	//
	// Cover properties
	// {{{
	////////////////////////////////////////////////////////////////////////
	//
	// We'll use these to determine the best performance this core
	// can achieve
	//
	reg	[4:0]	f_dbl_rd_count, f_dbl_wr_count;
	reg	[4:0]	f_rd_count, f_wr_count;

	// f_wr_count
	// {{{
	initial	f_wr_count = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_write_fault)
		f_wr_count <= 0;
	else if (S_AXI_BVALID && S_AXI_BREADY)
	begin
		if (!(&f_wr_count))
			f_wr_count <= f_wr_count + 1;
	end
	// }}}

	// f_dbl_wr_count
	// {{{
	initial	f_dbl_wr_count = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_write_fault||(S_AXI_AWVALID && S_AXI_AWLEN < 3))
		f_dbl_wr_count <= 0;
	else if (S_AXI_BVALID && S_AXI_BREADY)
	begin
		if (!(&f_dbl_wr_count))
			f_dbl_wr_count <= f_dbl_wr_count + 1;
	end
	// }}}

	// f_rd_count
	// {{{
	initial	f_rd_count = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_read_fault)
		f_rd_count <= 0;
	else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST)
	begin
		if (!(&f_rd_count))
			f_rd_count <= f_rd_count + 1;
	end
	// }}}

	// f_dbl_rd_count
	// {{{
	initial	f_dbl_rd_count = 0;
	always @(posedge S_AXI_ACLK)
	if (!S_AXI_ARESETN || o_read_fault||(S_AXI_ARVALID && S_AXI_ARLEN < 3))
		f_dbl_rd_count <= 0;
	else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST)
	begin
		if (!(&f_dbl_rd_count))
			f_dbl_rd_count <= f_dbl_rd_count + 1;
	end
	// }}}

	// Can we complete a single write burst without fault?
	// {{{
	always @(*)
	if (S_AXI_ARESETN)
		cover((f_wr_count > 1) && (!o_write_fault));

	always @(*)
	if (S_AXI_ARESETN)
		cover((f_dbl_wr_count > 1) && (!o_write_fault));
	// }}}

	// Can we complete four write bursts without fault? (and return to idle)
	// {{{
	always @(*)
	if (S_AXI_ARESETN)
		cover((f_wr_count > 3) && (!o_write_fault)
			&&(!S_AXI_AWVALID && !S_AXI_WVALID
					&& !S_AXI_BVALID)
			&& (f_axi_awr_nbursts == 0)
			&& (f_axi_wr_pending == 0));

	always @(*)
	if (S_AXI_ARESETN)
		cover((f_dbl_wr_count > 3) && (!o_write_fault)
			&&(!S_AXI_AWVALID && !S_AXI_WVALID
					&& !S_AXI_BVALID)
			&& (f_axi_awr_nbursts == 0)
			&& (f_axi_wr_pending == 0));
	// }}}

	// Can we complete a single read burst without fault?
	// {{{
	always @(*)
	if (S_AXI_ARESETN)
		cover((f_rd_count > 1) && (!o_read_fault));

	always @(*)
	if (S_AXI_ARESETN)
		cover((f_dbl_rd_count > 1) && (!o_read_fault));
	// }}}

	// Can we complete four read bursts without fault?
	// {{{
	always @(*)
	if (S_AXI_ARESETN)
		cover((f_rd_count > 3) && (f_axi_rd_nbursts == 0)
			&& !S_AXI_ARVALID && !S_AXI_RVALID);

	always @(*)
	if (S_AXI_ARESETN)
		cover((f_dbl_rd_count > 3) && (f_axi_rd_nbursts == 0)
			&& !S_AXI_ARVALID && !S_AXI_RVALID);
	// }}}
`endif
// }}}
endmodule
`ifndef	YOSYS
`default_nettype wire
`endif
