OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [rtl/] [core/] [dcache.v] - Rev 209

Compare with Previous | Blame | View Log

////////////////////////////////////////////////////////////////////////////////
//
// Filename:	dcache.v
//
// Project:	Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:	To provide a simple data cache for the ZipCPU.  The cache is
//		designed to be a drop in replacement for the pipememm memory
//	unit currently existing within the ZipCPU.  The goal of this unit is
//	to achieve single cycle read access to any memory in the last cache line
//	used, or two cycle access to any memory currently in the cache.
//
//	The cache separates between four types of accesses, one write and three
//	read access types.  The read accesses are split between those that are
//	not cacheable, those that are in the cache, and those that are not.
//
//	1. Write accesses always create writes to the bus.  For these reasons,
//		these may always be considered cache misses.
//
//		Writes to memory locations within the cache must also update
//		cache memory immediately, to keep the cache in synch.
//
//		It is our goal to be able to maintain single cycle write
//		accesses for memory bursts.
//
//	2. Read access to non-cacheable memory locations will also immediately
//		go to the bus, just as all write accesses go to the bus.
//
//	3. Read accesses to cacheable memory locations will immediately read
//		from the appropriate cache line.  However, since thee valid
//		line will take a second clock to read, it may take up to two
//		clocks to know if the memory was in cache.  For this reason,
//		we bypass the test for the last validly accessed cache line.
//
//		We shall design these read accesses so that reads to the cache
//		may take place concurrently with other writes to the bus.
//
//	Errors in cache reads will void the entire cache line.  For this reason,
//	cache lines must always be of a smaller in size than any associated
//	virtual page size--lest in the middle of reading a page a TLB miss
//	take place referencing only a part of the cacheable page.
//
//
//
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016-2019, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype	none
//
//
`ifdef	FORMAL
`define	ASSERT	assert
 
`ifdef DCACHE
`define	ASSUME	assume
`else
`define	ASSUME	assert
`endif
`endif
 
module	dcache(i_clk, i_reset, i_pipe_stb, i_lock,
		i_op, i_addr, i_data, i_oreg,
			o_busy, o_pipe_stalled, o_valid, o_err, o_wreg,o_data,
		o_wb_cyc_gbl, o_wb_cyc_lcl, o_wb_stb_gbl, o_wb_stb_lcl,
			o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
		i_wb_ack, i_wb_stall, i_wb_err, i_wb_data
`ifdef	FORMAL
		, f_nreqs, f_nacks, f_outstanding, f_pc
`endif
	);
	parameter	LGCACHELEN = 8,
			ADDRESS_WIDTH=30,
			LGNLINES=(LGCACHELEN-3), // Log of the number of separate cache lines
			NAUX=5;	// # of aux d-wires to keep aligned w/memops
	parameter [0:0]	OPT_LOCAL_BUS=1'b1;
	parameter [0:0]	OPT_PIPE=1'b1;
	parameter [0:0]	OPT_LOCK=1'b1;
	parameter [0:0]	OPT_DUAL_READ_PORT=1'b1;
	parameter 	OPT_FIFO_DEPTH = 4;
	localparam	AW = ADDRESS_WIDTH; // Just for ease of notation below
	localparam	CS = LGCACHELEN; // Number of bits in a cache address
	localparam	LS = CS-LGNLINES; // Bits to spec position w/in cline
	parameter	F_LGDEPTH=1 + (((!OPT_PIPE)||(LS > OPT_FIFO_DEPTH))
					? LS : OPT_FIFO_DEPTH);
	localparam	LGAUX = 3; // log_2 of the maximum number of piped data
	localparam	DW = 32; // Bus data width
	localparam	DP = OPT_FIFO_DEPTH;
	//
	localparam [1:0]	DC_IDLE  = 2'b00; // Bus is idle
	localparam [1:0]	DC_WRITE = 2'b01; // Write
	localparam [1:0]	DC_READS = 2'b10; // Read a single value(!cachd)
	localparam [1:0]	DC_READC = 2'b11; // Read a whole cache line
	//
	input	wire		i_clk, i_reset;
	// Interface from the CPU
	input	wire		i_pipe_stb, i_lock;
	input	wire [2:0]		i_op;
	input	wire [(DW-1):0]	i_addr;
	input	wire [(DW-1):0]	i_data;
	input	wire [(NAUX-1):0] i_oreg; // Aux data, such as reg to write to
	// Outputs, going back to the CPU
	output	reg		o_busy;
	output	reg		o_pipe_stalled;
	output	reg		o_valid, o_err;
	output reg [(NAUX-1):0]	o_wreg;
	output	reg [(DW-1):0]	o_data;
	// Wishbone bus master outputs
	output	wire		o_wb_cyc_gbl, o_wb_cyc_lcl;
	output	reg		o_wb_stb_gbl, o_wb_stb_lcl;
	output	reg		o_wb_we;
	output	reg [(AW-1):0]	o_wb_addr;
	output	reg [(DW-1):0]	o_wb_data;
	output	wire [(DW/8-1):0] o_wb_sel;
	// Wishbone bus slave response inputs
	input	wire			i_wb_ack, i_wb_stall, i_wb_err;
	input	wire	[(DW-1):0]	i_wb_data;
`ifdef FORMAL
	output	wire [(F_LGDEPTH-1):0]	f_nreqs, f_nacks, f_outstanding;
	output	wire			f_pc;
 
	reg	f_past_valid;
`endif
	//
	// output	reg	[31:0]		o_debug;
 
 
	reg	cyc, stb, last_ack, end_of_line, last_line_stb;
	reg	r_wb_cyc_gbl, r_wb_cyc_lcl;
	// npending is the number of pending non-cached operations, counted
	// from the i_pipe_stb to the o_wb_ack
	reg	[DP:0]	npending;
 
 
	reg	[((1<<LGNLINES)-1):0] c_v;	// One bit per cache line, is it valid?
	reg	[(AW-LS-1):0]	c_vtags	[0:((1<<LGNLINES)-1)];
	reg	[(DW-1):0]	c_mem	[0:((1<<CS)-1)];
	reg			set_vflag;
	reg	[1:0]		state;
	reg	[(CS-1):0]	wr_addr;
	reg	[(DW-1):0]	cached_idata, cached_rdata;
	reg	[DW-1:0]	pre_data;
	reg			lock_gbl, lock_lcl;
 
 
	// To simplify writing to the cache, and the job of the synthesizer to
	// recognize that a cache write needs to take place, we'll take an extra
	// clock to get there, and use these c_w... registers to capture the
	// data in the meantime.
	reg			c_wr;
	reg	[(DW-1):0]	c_wdata;
	reg	[(DW/8-1):0]	c_wsel;
	reg	[(CS-1):0]	c_waddr;
 
	reg	[(AW-LS-1):0]	last_tag;
	reg			last_tag_valid;
 
 
	wire	[(LGNLINES-1):0]	i_cline;
	wire	[(CS-1):0]	i_caddr;
 
`ifdef	FORMAL
	reg	[F_LGDEPTH-1:0]	f_fill;
	reg	[AW:0]		f_return_address;
	reg	[AW:0]		f_pending_addr;
`endif
 
	assign	i_cline = i_addr[(CS+1):LS+2];
	assign	i_caddr = i_addr[(CS+1):2];
 
	wire	cache_miss_inow, w_cachable;
	assign	cache_miss_inow = (!last_tag_valid)
					||(last_tag != i_addr[(AW+1):LS+2])
					||(!c_v[i_cline]);
 
	wire	raw_cachable_address;
 
	iscachable chkaddress(i_addr[AW+1:2], raw_cachable_address);
 
	assign	w_cachable = ((!OPT_LOCAL_BUS)||(i_addr[(DW-1):(DW-8)]!=8'hff))
		&&((!i_lock)||(!OPT_LOCK))&&(raw_cachable_address);
 
	reg	r_cachable, r_svalid, r_dvalid, r_rd, r_cache_miss,
		r_rd_pending;
	reg	[(AW-1):0]		r_addr;
	wire	[(LGNLINES-1):0]	r_cline;
	wire	[(CS-1):0]		r_caddr;
	wire	[(AW-LS-1):0]		r_ctag;
 
	assign	r_cline = r_addr[(CS-1):LS];
	assign	r_caddr = r_addr[(CS-1):0];
	assign	r_ctag  = r_addr[(AW-1):LS];
 
 
	reg	wr_cstb, r_iv, in_cache;
	reg	[(AW-LS-1):0]	r_itag;
	reg	[DW/8-1:0]	r_sel;
	reg	[(NAUX+4-1):0]	req_data;
	reg			gie;
 
 
 
	//
	// The one-clock delayed read values from the cache.
	//
	initial	r_rd = 1'b0;
	initial	r_cachable = 1'b0;
	initial	r_svalid = 1'b0;
	initial	r_dvalid = 1'b0;
	initial	r_cache_miss = 1'b0;
	initial	r_addr = 0;
	initial	last_tag_valid = 0;
	initial	r_rd_pending = 0;
	always @(posedge i_clk)
	if (i_reset)
	begin
		r_rd <= 1'b0;
		r_cachable <= 1'b0;
		r_svalid <= 1'b0;
		r_dvalid <= 1'b0;
		r_cache_miss <= 1'b0;
		r_addr <= 0;
		r_rd_pending <= 0;
		last_tag_valid <= 0;
	end else begin
		// The single clock path
		// The valid for the single clock path
		//	Only ... we need to wait if we are currently writing
		//	to our cache.
		r_svalid<= (i_pipe_stb)&&(!i_op[0])&&(w_cachable)
				&&(!cache_miss_inow)&&(!c_wr)&&(!wr_cstb);
 
		//
		// The two clock in-cache path
		//
		// Some preliminaries that needed to be calculated on the first
		// clock
		if ((!o_pipe_stalled)&&(!r_rd_pending))
			r_addr <= i_addr[(AW+1):2];
		if ((!o_pipe_stalled)&&(!r_rd_pending))
		begin
			r_iv   <= c_v[i_cline];
			r_itag <= c_vtags[i_cline];
			r_cachable <= (!i_op[0])&&(w_cachable)&&(i_pipe_stb);
			r_rd_pending <= (i_pipe_stb)&&(!i_op[0])&&(w_cachable)
				&&((cache_miss_inow)||(c_wr)||(wr_cstb));
				// &&((!c_wr)||(!wr_cstb));
		end else begin
			r_iv   <= c_v[r_cline];
			r_itag <= c_vtags[r_cline];
			r_rd_pending <= (r_rd_pending)
				&&((!cyc)||(!i_wb_err))
				&&((r_itag != r_ctag)||(!r_iv));
		end
		r_rd <= (i_pipe_stb)&&(!i_op[0]);
		// r_itag contains the tag we didn't have available to us on the
		// last clock, r_ctag is a bit select from r_addr containing a
		// one clock delayed address.
		r_dvalid <= (!r_svalid)&&(!r_dvalid)&&(r_itag == r_ctag)&&(r_iv)
						&&(r_cachable)&&(r_rd_pending);
		if ((r_itag == r_ctag)&&(r_iv)&&(r_cachable)&&(r_rd_pending))
		begin
			last_tag_valid <= 1'b1;
			last_tag <= r_ctag;
		end else if ((state == DC_READC)
				&&(last_tag[CS-LS-1:0]==o_wb_addr[CS-1:LS])
				&&((i_wb_ack)||(i_wb_err)))
			last_tag_valid <= 1'b0;
 
		// r_cache miss takes a clock cycle.  It is only ever true for
		// something that should be cachable, but isn't in the cache.
		// A cache miss is only true _if_
		// 1. A read was requested
		// 2. It is for a cachable address, AND
		// 3. It isn't in the cache on the first read
		//	or the second read
		// 4. The read hasn't yet started to get this address
		r_cache_miss <= ((!cyc)||(o_wb_we))&&(r_cachable)
				// One clock path -- miss
				&&(!r_svalid)
				// Two clock path -- misses as well
				&&(r_rd)&&(!r_svalid)
				&&((r_itag != r_ctag)||(!r_iv));
	end
 
	initial	r_sel = 4'hf;
	always @(posedge i_clk)
	if (i_reset)
		r_sel <= 4'hf;
	else if (!o_pipe_stalled)
	begin
		casez({i_op[2:1], i_addr[1:0]})
		4'b0???: r_sel <= 4'b1111;
		4'b100?: r_sel <= 4'b1100;
		4'b101?: r_sel <= 4'b0011;
		4'b1100: r_sel <= 4'b1000;
		4'b1101: r_sel <= 4'b0100;
		4'b1110: r_sel <= 4'b0010;
		4'b1111: r_sel <= 4'b0001;
		endcase
	end
 
	assign	o_wb_sel = (state == DC_READC) ? 4'hf : r_sel;
 
	initial	o_wb_data = 0;
	always @(posedge i_clk)
	if (i_reset)
		o_wb_data <= 0;
	else if ((!o_busy)||((stb)&&(!i_wb_stall)))
	begin
		casez(i_op[2:1])
		2'b0?: o_wb_data <= i_data;
		2'b10: o_wb_data <= { (2){i_data[15:0]} };
		2'b11: o_wb_data <= { (4){i_data[ 7:0]} };
		endcase
	end
 
	generate if (OPT_PIPE)
	begin : OPT_PIPE_FIFO
		reg	[NAUX+4-2:0]	fifo_data [0:((1<<OPT_FIFO_DEPTH)-1)];
 
		reg	[DP:0]		wraddr, rdaddr;
 
		always @(posedge i_clk)
		if (i_pipe_stb)
			fifo_data[wraddr[DP-1:0]]
				<= { i_oreg[NAUX-2:0], i_op[2:1], i_addr[1:0] };
 
		always @(posedge i_clk)
		if (i_pipe_stb)
			gie <= i_oreg[NAUX-1];
 
`ifdef	NO_BKRAM
		reg	[NAUX+4-2:0]	r_req_data, r_last_data;
		reg			single_write;
 
		always @(posedge i_clk)
			r_req_data <= fifo_data[rdaddr[DP-1:0]];
 
		always @(posedge i_clk)
			single_write <= (rdaddr == wraddr)&&(i_pipe_stb);
 
		always @(posedge i_clk)
		if (i_pipe_stb)
			r_last_data <= { i_oreg[NAUX-2:0],
						i_op[2:1], i_addr[1:0] };
 
		always @(*)
		begin
			req_data[NAUX+4-1] = gie;
			// if ((r_svalid)||(state == DC_READ))
			if (single_write)
				req_data[NAUX+4-2:0] = r_last_data;
			else
				req_data[NAUX+4-2:0] = r_req_data;
		end
 
		always @(*)
			`ASSERT(req_data == fifo_data[rdaddr[DP-1:0]]);
`else
		always @(*)
			req_data[NAUX+4-2:0] = fifo_data[rdaddr[DP-1:0]];
		always @(*)
			req_data[NAUX+4-1] = gie;
`endif
 
		initial	wraddr = 0;
		always @(posedge i_clk)
		if ((i_reset)||((cyc)&&(i_wb_err)))
			wraddr <= 0;
		else if (i_pipe_stb)
			wraddr <= wraddr + 1'b1;
 
		initial	rdaddr = 0;
		always @(posedge i_clk)
		if ((i_reset)||((cyc)&&(i_wb_err)))
			rdaddr <= 0;
		else if ((r_dvalid)||(r_svalid))
			rdaddr <= rdaddr + 1'b1;
		else if ((state == DC_WRITE)&&(i_wb_ack))
			rdaddr <= rdaddr + 1'b1;
		else if ((state == DC_READS)&&(i_wb_ack))
			rdaddr <= rdaddr + 1'b1;
 
`ifdef	FORMAL
		reg	[AW-1:0]	f_fifo_addr [0:((1<<OPT_FIFO_DEPTH)-1)];
		reg	[F_LGDEPTH-1:0]	f_last_wraddr;
		reg	f_pc_pending;
 
		always @(*)
		begin
			f_fill = 0;
			f_fill[DP:0] = wraddr - rdaddr;
		end
 
		always @(*)
			`ASSERT(f_fill <= { 1'b1, {(DP){1'b0}} });
 
		always @(*)
		if ((r_dvalid)||(r_svalid))
		begin
			if (r_svalid)
				`ASSERT(f_fill == 1);
			else if (r_dvalid)
				`ASSERT(f_fill == 1);
			else
				`ASSERT(f_fill == 0);
		end else if (r_rd_pending)
			`ASSERT(f_fill == 1);
		else
			`ASSERT(f_fill == npending);
 
 
		initial	f_pc_pending = 0;
		always @(posedge i_clk)
		if (i_reset)
			f_pc_pending <= 1'b0;
		else if (i_pipe_stb)
			f_pc_pending <= (!i_op[0])&&(i_oreg[3:1] == 3'h7);
		else if (f_fill == 0)
			f_pc_pending <= 1'b0;
		//else if ((o_valid)&&(o_wreg[3:1] == 3'h7)&&(f_fill == 0))
		//	f_pc_pending <= 1'b0;
 
		always @(posedge i_clk)
		if (f_pc_pending)
			`ASSUME(!i_pipe_stb);
 
		always @(posedge i_clk)
		if (state == DC_WRITE)
			`ASSERT(!f_pc_pending);
 
		always @(*)
		begin
			f_last_wraddr = 0;
			f_last_wraddr[DP:0] = wraddr - 1'b1;
		end
 
		always @(posedge i_clk)
		if (r_rd_pending)
			`ASSERT(f_pc_pending == (fifo_data[f_last_wraddr][7:5] == 3'h7));
 
`define	INSPECT_FIFO
		reg	[((1<<(DP+1))-1):0]	f_valid_fifo_entry;
 
		genvar	k;
		for(k=0; k<(1<<(DP+1)); k=k+1)
		begin
 
			always @(*)
			begin
			f_valid_fifo_entry[k] = 1'b0;
			/*
			if ((rdaddr[DP] != wraddr[DP])
					&&(rdaddr[DP-1:0] == wraddr[DP-1:0]))
				f_valid_fifo_entry[k] = 1'b1;
			else */
			if ((rdaddr < wraddr)&&(k < wraddr)
					&&(k >= rdaddr))
				f_valid_fifo_entry[k] = 1'b1;
			else if ((rdaddr > wraddr)&&(k >= rdaddr))
				f_valid_fifo_entry[k] = 1'b1;
			else if ((rdaddr > wraddr)&&(k <  wraddr))
				f_valid_fifo_entry[k] = 1'b1;
			end
 
`ifdef	INSPECT_FIFO
			wire	[NAUX+4-2:0]	fifo_data_k;
 
			assign	fifo_data_k = fifo_data[k[DP-1:0]];
			always @(*)
			if (f_valid_fifo_entry[k])
			begin
				if (!f_pc_pending)
					`ASSERT((o_wb_we)||(fifo_data_k[7:5] != 3'h7));
				else if (k != f_last_wraddr)
					`ASSERT(fifo_data_k[7:5] != 3'h7);
			end
`endif // INSPECT_FIFO
 
		end
 
`ifndef	INSPECT_FIFO
		always @(posedge i_clk)
		if ((r_rd_pending)&&(rdaddr[DP:0] != f_last_wraddr[DP-1]))
			assume(fifo_data[rdaddr][7:5] != 3'h7);
`endif // INSPECT_FIFO
 
		assign	f_pc = f_pc_pending;
 
		//
		//
		//
		always @(*)
			f_pending_addr = f_fifo_addr[rdaddr];
 
		//
		//
		//
		always @(posedge i_clk)
		if (i_pipe_stb)
			f_fifo_addr[wraddr[DP-1:0]] <= i_addr[AW+1:2];
 
		always @(*)
		begin
			f_return_address[AW] = (o_wb_cyc_lcl);
			f_return_address[AW-1:0] = f_fifo_addr[rdaddr];
			if (state == DC_READC)
				f_return_address[LS-1:0]
				= (o_wb_addr[LS-1:0] - f_outstanding[LS-1:0]);
		end
 
`define	TWIN_WRITE_TEST
`ifdef	TWIN_WRITE_TEST
		(* anyconst *)	reg	[DP:0]		f_twin_base;
				reg	[DP:0]		f_twin_next;
		(* anyconst *)	reg	[AW+NAUX+4-2-1:0]	f_twin_first,
							f_twin_second;
		// reg	[AW-1:0]	f_fifo_addr [0:((1<<OPT_FIFO_DEPTH)-1)];
		// reg	[NAUX+4-2:0]	fifo_data [0:((1<<OPT_FIFO_DEPTH)-1)];
 
		always @(*)	f_twin_next = f_twin_base+1;
 
		reg	f_twin_none, f_twin_single, f_twin_double, f_twin_last;
		reg	f_twin_valid_one, f_twin_valid_two;
		always @(*)
		begin
			f_twin_valid_one = ((f_valid_fifo_entry[f_twin_base])
				&&(f_twin_first == { f_fifo_addr[f_twin_base],
						fifo_data[f_twin_base] }));
			f_twin_valid_two = ((f_valid_fifo_entry[f_twin_next])
				&&(f_twin_second == { f_fifo_addr[f_twin_next],
						fifo_data[f_twin_next] }));
		end
 
		always @(*)
		begin
			f_twin_none   =(!f_twin_valid_one)&&(!f_twin_valid_two);
			f_twin_single =( f_twin_valid_one)&&(!f_twin_valid_two);
			f_twin_double =( f_twin_valid_one)&&( f_twin_valid_two);
			f_twin_last   =(!f_twin_valid_one)&&( f_twin_valid_two);
		end
 
		always @(posedge i_clk)
		if ((!f_past_valid)||($past(i_reset))||($past(cyc && i_wb_err)))
			`ASSERT(f_twin_none);
		else if ($past(f_twin_none))
			`ASSERT(f_twin_none || f_twin_single || f_twin_last);
		else if ($past(f_twin_single))
			`ASSERT(f_twin_none || f_twin_single || f_twin_double || f_twin_last);
		else if ($past(f_twin_double))
			`ASSERT(f_twin_double || f_twin_last);
		else if ($past(f_twin_last))
			`ASSERT(f_twin_none || f_twin_single || f_twin_last);
 
`endif // TWIN_WRITE_TEST
 
		always @(*)
			`ASSERT(req_data == { gie, fifo_data[rdaddr[DP-1:0]] });
 
		always @(posedge i_clk)
		if (r_svalid||r_dvalid || r_rd_pending)
			`ASSERT(f_fill == 1);
		else if (f_fill > 0)
			`ASSERT(cyc);
 
		always @(posedge i_clk)
		if (state != 0)
			`ASSERT(f_fill > 0);
		else if (!r_svalid && !r_dvalid && !r_rd_pending)
			`ASSERT(f_fill == 0);
 
`endif // FORMAL
 
		always @(posedge i_clk)
			o_wreg <= req_data[(NAUX+4-1):4];
 
		/*
		reg	fifo_err;
		always @(posedge i_clk)
		begin
			fifo_err <= 1'b0;
			if ((!o_busy)&&(rdaddr != wraddr))
				fifo_err <= 1'b1;
			if ((!r_dvalid)&&(!r_svalid)&&(!r_rd_pending))
				fifo_err <= (npending != (wraddr-rdaddr));
		end
 
		always @(*)
		o_debug = { i_pipe_stb, state, cyc, stb,	//  5b
				fifo_err, i_oreg[3:0], o_wreg, 		// 10b
				rdaddr, wraddr, 		// 10b
				i_wb_ack, i_wb_err, o_pipe_stalled, o_busy,//4b
				r_svalid, r_dvalid, r_rd_pending };
		*/
	end else begin : NO_FIFO
 
		always @(posedge i_clk)
		if (i_pipe_stb)
			req_data <= { i_oreg, i_op[2:1], i_addr[1:0] };
 
		always @(*)
			o_wreg = req_data[(NAUX+4-1):4];
 
		always @(*)
			gie = i_oreg[NAUX-1];
 
`ifdef	FORMAL
		assign	f_pc = ((r_rd_pending)||(o_valid))&&(o_wreg[3:1] == 3'h7);
 
		//
		//
		//
		initial	f_pending_addr = 0;
		always @(posedge i_clk)
		if (i_reset)
			f_pending_addr <= 0;
		else if (i_pipe_stb)
		begin
			f_pending_addr <= { (OPT_LOCAL_BUS)&&(&i_addr[DW-1:DW-8]),
						i_addr[(AW+1):2] };
		end
 
		//
		//
		always @(*)
		begin
			f_return_address[AW]      = o_wb_cyc_lcl;
			f_return_address[AW-1:LS] = o_wb_addr[AW-1:LS];
		end
		always @(*)
		if (state == DC_READS)
			f_return_address[LS-1:0] = o_wb_addr[LS-1:0];
		else
			f_return_address[LS-1:0]
				= (o_wb_addr[LS-1:0] - f_outstanding[LS-1:0]);
 
`endif
		/*
		always @(*)
		o_debug = { i_pipe_stb, state, cyc, stb,	//  5b
				i_oreg, o_wreg, 		// 10b
				10'hb,		 		// 10b
				i_wb_ack, i_wb_err, o_pipe_stalled, o_busy,//4b
				r_svalid, r_dvalid, r_rd_pending };
		*/
 
		// verilator lint_off UNUSED
		wire	unused_no_fifo;
		assign	unused_no_fifo = gie;
		// verilator lint_on  UNUSED
	end endgenerate
 
 
	initial	r_wb_cyc_gbl = 0;
	initial	r_wb_cyc_lcl = 0;
	initial	o_wb_stb_gbl = 0;
	initial	o_wb_stb_lcl = 0;
	initial	c_v = 0;
	initial	cyc = 0;
	initial	stb = 0;
	initial	c_wr = 0;
	initial	wr_cstb = 0;
	initial	state = DC_IDLE;
	initial	set_vflag = 1'b0;
	always @(posedge i_clk)
	if (i_reset)
	begin
		c_v <= 0;
		c_wr   <= 1'b0;
		c_wsel <= 4'hf;
		r_wb_cyc_gbl <= 1'b0;
		r_wb_cyc_lcl <= 1'b0;
		o_wb_stb_gbl <= 0;
		o_wb_stb_lcl <= 0;
		wr_cstb <= 1'b0;
		last_line_stb <= 1'b0;
		end_of_line <= 1'b0;
		state <= DC_IDLE;
		cyc <= 1'b0;
		stb <= 1'b0;
		state <= DC_IDLE;
		set_vflag <= 1'b0;
	end else begin
		// By default, update the cache from the write 1-clock ago
		// c_wr <= (wr_cstb)&&(wr_wtag == wr_vtag);
		// c_waddr <= wr_addr[(CS-1):0];
		c_wr <= 0;
 
		set_vflag <= 1'b0;
		if ((!cyc)&&(set_vflag))
			c_v[c_waddr[(CS-1):LS]] <= 1'b1;
 
		wr_cstb <= 1'b0;
 
		if (!cyc)
			wr_addr <= r_addr[(CS-1):0];
		else if (i_wb_ack)
			wr_addr <= wr_addr + 1'b1;
		else
			wr_addr <= wr_addr;
 
		if (LS <= 0)
			end_of_line <= 1'b1;
		else if (!cyc)
			end_of_line <= 1'b0;
		else if (!end_of_line)
		begin
			if (i_wb_ack)
				end_of_line
				<= (c_waddr[(LS-1):0] == {{(LS-2){1'b1}},2'b01});
			else
				end_of_line
				<= (c_waddr[(LS-1):0]=={{(LS-1){1'b1}}, 1'b0});
		end
 
		if (!cyc)
			last_line_stb <= (LS <= 0);
		else if ((stb)&&(!i_wb_stall)&&(LS <= 1))
			last_line_stb <= 1'b1;
		else if ((stb)&&(!i_wb_stall))
			last_line_stb <= (o_wb_addr[(LS-1):1]=={(LS-1){1'b1}});
		else if (stb)
			last_line_stb <= (o_wb_addr[(LS-1):0]=={(LS){1'b1}});
 
		//
		//
		if (state == DC_IDLE)
		begin
			o_wb_we <= 1'b0;
 
			cyc <= 1'b0;
			stb <= 1'b0;
 
			r_wb_cyc_gbl <= 1'b0;
			r_wb_cyc_lcl <= 1'b0;
			o_wb_stb_gbl <= 1'b0;
			o_wb_stb_lcl <= 1'b0;
 
			in_cache <= (i_op[0])&&(w_cachable);
			if ((i_pipe_stb)&&(i_op[0]))
			begin // Write  operation
				state <= DC_WRITE;
				o_wb_addr <= i_addr[(AW+1):2];
				o_wb_we <= 1'b1;
 
				cyc <= 1'b1;
				stb <= 1'b1;
 
				if (OPT_LOCAL_BUS)
				begin
				r_wb_cyc_gbl <= (i_addr[DW-1:DW-8]!=8'hff);
				r_wb_cyc_lcl <= (i_addr[DW-1:DW-8]==8'hff);
				o_wb_stb_gbl <= (i_addr[DW-1:DW-8]!=8'hff);
				o_wb_stb_lcl <= (i_addr[DW-1:DW-8]==8'hff);
				end else begin
					r_wb_cyc_gbl <= 1'b1;
					o_wb_stb_gbl <= 1'b1;
				end
 
			end else if (r_cache_miss)
			begin
				state <= DC_READC;
				o_wb_addr <= { r_ctag, {(LS){1'b0}} };
 
				c_waddr <= { r_ctag[CS-LS-1:0], {(LS){1'b0}} }-1'b1;
				cyc <= 1'b1;
				stb <= 1'b1;
				r_wb_cyc_gbl <= 1'b1;
				o_wb_stb_gbl <= 1'b1;
				wr_addr[LS-1:0] <= 0;
			end else if ((i_pipe_stb)&&(!w_cachable))
			begin // Read non-cachable memory area
				state <= DC_READS;
				o_wb_addr <= i_addr[(AW+1):2];
 
				cyc <= 1'b1;
				stb <= 1'b1;
				if (OPT_LOCAL_BUS)
				begin
				r_wb_cyc_gbl <= (i_addr[DW-1:DW-8]!=8'hff);
				r_wb_cyc_lcl <= (i_addr[DW-1:DW-8]==8'hff);
				o_wb_stb_gbl <= (i_addr[DW-1:DW-8]!=8'hff);
				o_wb_stb_lcl <= (i_addr[DW-1:DW-8]==8'hff);
				end else begin
				r_wb_cyc_gbl <= 1'b1;
				o_wb_stb_gbl <= 1'b1;
				end
			end // else we stay idle
 
		end else if (state == DC_READC)
		begin
			// We enter here once we have committed to reading
			// data into a cache line.
			if ((stb)&&(!i_wb_stall))
			begin
				stb <= (!last_line_stb);
				o_wb_stb_gbl <= (!last_line_stb);
				o_wb_addr[(LS-1):0] <= o_wb_addr[(LS-1):0]+1'b1;
			end
 
			if ((i_wb_ack)&&(!end_of_line))
				c_v[o_wb_addr[(CS-1):LS]] <= 1'b0;
 
			c_wr    <= (i_wb_ack);
			c_wdata <= i_wb_data;
			c_waddr <= ((i_wb_ack)?(c_waddr+1'b1):c_waddr);
			c_wsel  <= 4'hf;
 
			set_vflag <= !i_wb_err;
			if (i_wb_ack)
				c_vtags[r_addr[(CS-1):LS]]
						<= r_addr[(AW-1):LS];
 
			if (((i_wb_ack)&&(end_of_line))||(i_wb_err))
			begin
				state          <= DC_IDLE;
				cyc <= 1'b0;
				stb <= 1'b0;
				r_wb_cyc_gbl <= 1'b0;
				r_wb_cyc_lcl <= 1'b0;
				o_wb_stb_gbl <= 1'b0;
				o_wb_stb_lcl <= 1'b0;
				//
			end
		end else if (state == DC_READS)
		begin
			// We enter here once we have committed to reading
			// data that cannot go into a cache line
			if ((!i_wb_stall)&&(!i_pipe_stb))
			begin
				stb <= 1'b0;
				o_wb_stb_gbl <= 1'b0;
				o_wb_stb_lcl <= 1'b0;
			end
 
			if ((!i_wb_stall)&&(i_pipe_stb))
				o_wb_addr <= i_addr[(AW+1):2];
 
			c_wr <= 1'b0;
 
			if (((i_wb_ack)&&(last_ack))||(i_wb_err))
			begin
				state        <= DC_IDLE;
				cyc          <= 1'b0;
				stb          <= 1'b0;
				r_wb_cyc_gbl <= 1'b0;
				r_wb_cyc_lcl <= 1'b0;
				o_wb_stb_gbl <= 1'b0;
				o_wb_stb_lcl <= 1'b0;
			end
		end else if (state == DC_WRITE)
		begin
			c_wr    <= (stb)&&(c_v[o_wb_addr[CS-1:LS]])
				&&(c_vtags[o_wb_addr[CS-1:LS]]==o_wb_addr[AW-1:LS])
				&&(stb);
			c_wdata <= o_wb_data;
			c_waddr <= r_addr[CS-1:0];
			c_wsel  <= o_wb_sel;
 
			if ((!i_wb_stall)&&(!i_pipe_stb))
			begin
				stb          <= 1'b0;
				o_wb_stb_gbl <= 1'b0;
				o_wb_stb_lcl <= 1'b0;
			end
 
			wr_cstb  <= (stb)&&(!i_wb_stall)&&(in_cache);
 
			if ((stb)&&(!i_wb_stall))
				o_wb_addr <= i_addr[(AW+1):2];
 
			if (((i_wb_ack)&&(last_ack)
						&&((!OPT_PIPE)||(!i_pipe_stb)))
				||(i_wb_err))
			begin
				state        <= DC_IDLE;
				cyc          <= 1'b0;
				stb          <= 1'b0;
				r_wb_cyc_gbl <= 1'b0;
				r_wb_cyc_lcl <= 1'b0;
				o_wb_stb_gbl <= 1'b0;
				o_wb_stb_lcl <= 1'b0;
			end
		end
	end
 
	//
	// npending is the number of outstanding (non-cached) read or write
	// requests
	initial	npending = 0;
	always @(posedge i_clk)
	if ((i_reset)||(!OPT_PIPE)
			||((cyc)&&(i_wb_err))
			||((!cyc)&&(!i_pipe_stb))
			||(state == DC_READC))
		npending <= 0;
	else if (r_svalid)
		npending <= (i_pipe_stb) ? 1:0;
	else case({ (i_pipe_stb), (cyc)&&(i_wb_ack) })
	2'b01: npending <= npending - 1'b1;
	2'b10: npending <= npending + 1'b1;
	default: begin end
	endcase
 
	initial	last_ack = 1'b0;
	always @(posedge i_clk)
	if (i_reset)
		last_ack <= 1'b0;
	else if (state == DC_IDLE)
	begin
		last_ack <= 1'b0;
		if ((i_pipe_stb)&&(i_op[0]))
			last_ack <= 1'b1;
		else if (r_cache_miss)
			last_ack <= (LS == 0);
		else if ((i_pipe_stb)&&(!w_cachable))
			last_ack <= 1'b1;
	end else if (state == DC_READC)
	begin
		if (i_wb_ack)
			last_ack <= last_ack || (&wr_addr[LS-1:1]);
		else
			last_ack <= last_ack || (&wr_addr[LS-1:0]);
	end else case({ (i_pipe_stb), (i_wb_ack) })
	2'b01: last_ack <= (npending <= 2);
	2'b10: last_ack <= (!cyc)||(npending == 0);
	default: begin end
	endcase
 
`ifdef	FORMAL
always @(*)
`ASSERT(npending <= { 1'b1, {(DP){1'b0}} });
 
`endif
 
 
	//
	// Writes to the cache
	//
	// These have been made as simple as possible.  Note that the c_wr
	// line has already been determined, as have the write value and address
	// on the last clock.  Further, this structure is defined to match the
	// block RAM design of as many architectures as possible.
	//
	always @(posedge i_clk)
	if (c_wr)
	begin
		if (c_wsel[0])
			c_mem[c_waddr][7:0] <= c_wdata[7:0];
		if (c_wsel[1])
			c_mem[c_waddr][15:8] <= c_wdata[15:8];
		if (c_wsel[2])
			c_mem[c_waddr][23:16] <= c_wdata[23:16];
		if (c_wsel[3])
			c_mem[c_waddr][31:24] <= c_wdata[31:24];
	end
 
	//
	// Reads from the cache
	//
	// Some architectures require that all reads be registered.  We
	// accomplish that here.  Whether or not the result of this read is
	// going to be our output will need to be determined with combinatorial
	// logic on the output.
	//
	generate if (OPT_DUAL_READ_PORT)
	begin
 
		always @(posedge i_clk)
			cached_idata <= c_mem[i_caddr];
 
		always @(posedge i_clk)
			cached_rdata <= c_mem[r_caddr];
 
	end else begin
 
		always @(posedge i_clk)
			cached_rdata <= c_mem[(o_busy) ? r_caddr : i_caddr];
 
		always @(*)
			cached_idata = cached_rdata;
 
	end endgenerate
 
// o_data can come from one of three places:
// 1. The cache, assuming the data was in the last cache line
// 2. The cache, second clock, assuming the data was in the cache at all
// 3. The cache, after filling the cache
// 4. The wishbone state machine, upon reading the value desired.
	always @(*)
		if (r_svalid)
			pre_data = cached_idata;
		else if (state == DC_READS)
			pre_data = i_wb_data;
		else
			pre_data = cached_rdata;
 
	always @(posedge i_clk)
	casez(req_data[3:0])
	4'b100?: o_data <= { 16'h0, pre_data[31:16] };
	4'b101?: o_data <= { 16'h0, pre_data[15: 0] };
	4'b1100: o_data <= { 24'h0, pre_data[31:24] };
	4'b1101: o_data <= { 24'h0, pre_data[23:16] };
	4'b1110: o_data <= { 24'h0, pre_data[15: 8] };
	4'b1111: o_data <= { 24'h0, pre_data[ 7: 0] };
	default	o_data <= pre_data;
	endcase
 
	initial	o_valid = 1'b0;
	always @(posedge i_clk)
	if (i_reset)
		o_valid <= 1'b0;
	else if (state == DC_READS)
		o_valid <= i_wb_ack;
	else
		o_valid <= (r_svalid)||(r_dvalid);
 
	initial	o_err = 1'b0;
	always @(posedge i_clk)
	if (i_reset)
		o_err <= 1'b0;
	else
		o_err <= (cyc)&&(i_wb_err);
 
	initial	o_busy = 0;
	always @(posedge i_clk)
	if ((i_reset)||((cyc)&&(i_wb_err)))
		o_busy <= 1'b0;
	else if (i_pipe_stb)
		o_busy <= 1'b1;
	else if ((state == DC_READS)&&(i_wb_ack))
		o_busy <= 1'b0;
	else if ((r_rd_pending)&&(!r_dvalid))
		o_busy <= 1'b1;
	else if ((state == DC_WRITE)
			&&(i_wb_ack)&&(last_ack)&&(!i_pipe_stb))
		o_busy <= 1'b0;
	else if (cyc)
		o_busy <= 1'b1;
	else // if ((r_dvalid)||(r_svalid))
		o_busy <= 1'b0;
 
	//
	// We can use our FIFO addresses to pre-calculate when an ACK is going
	// to be the last_noncachable_ack.
 
 
	always @(*)
	if (OPT_PIPE)
		o_pipe_stalled = (cyc)&&((!o_wb_we)||(i_wb_stall)||(!stb))
				||(r_rd_pending)||(npending[DP]);
	else
		o_pipe_stalled = o_busy;
 
	initial	lock_gbl = 0;
	initial	lock_lcl = 0;
	always @(posedge i_clk)
	if (i_reset)
	begin
		lock_gbl <= 1'b0;
		lock_lcl<= 1'b0;
	end else begin
		lock_gbl <= (OPT_LOCK)&&(i_lock)&&((r_wb_cyc_gbl)||(lock_gbl));
		lock_lcl <= (OPT_LOCK)&&(i_lock)&&((r_wb_cyc_lcl)||(lock_lcl));
	end
 
	assign	o_wb_cyc_gbl = (r_wb_cyc_gbl)||(lock_gbl);
	assign	o_wb_cyc_lcl = (r_wb_cyc_lcl)||(lock_lcl);
 
	generate if (AW+2 < DW)
	begin : UNUSED_BITS
 
		// Verilator lint_off UNUSED
		wire	[DW-AW-2:0]	unused;
		assign	unused = i_addr[DW-1:AW+1];
		// Verilator lint_on  UNUSED
	end endgenerate
 
`ifdef	FORMAL
 
	initial	f_past_valid = 1'b0;
	always @(posedge i_clk)
		f_past_valid <= 1'b1;
 
	////////////////////////////////////////////////
	//
	// Reset properties
	//
	////////////////////////////////////////////////
	//
	//
	always @(*)
	if(!f_past_valid)
		`ASSUME(i_reset);
 
	always @(posedge i_clk)
	if ((!f_past_valid)||($past(i_reset)))
	begin
		// Insist on initial statements matching reset values
		`ASSERT(r_rd == 1'b0);
		`ASSERT(r_cachable == 1'b0);
		`ASSERT(r_svalid == 1'b0);
		`ASSERT(r_dvalid == 1'b0);
		`ASSERT(r_cache_miss == 1'b0);
		`ASSERT(r_addr == 0);
		//
		`ASSERT(c_wr == 0);
		`ASSERT(c_v  == 0);
		//
		// assert(aux_head == 0);
		// assert(aux_tail == 0);
		//
		`ASSERT(lock_gbl == 0);
		`ASSERT(lock_lcl == 0);
	end
 
	////////////////////////////////////////////////
	//
	// Assumptions about our inputs
	//
	////////////////////////////////////////////////
	//
	//
	always @(*)
	if (o_pipe_stalled)
		`ASSUME(!i_pipe_stb);
 
	always @(*)
	if (!f_past_valid)
		`ASSUME(!i_pipe_stb);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(i_reset))
		&&($past(i_pipe_stb))&&($past(o_pipe_stalled)))
	begin
		`ASSUME($stable(i_pipe_stb));
		`ASSUME($stable(i_op[0]));
		`ASSUME($stable(i_addr));
		if (i_op[0])
			`ASSUME($stable(i_data));
	end
 
	always @(posedge i_clk)
	if (o_err)
		`ASSUME(!i_pipe_stb);
 
	////////////////////////////////////////////////
	//
	// Wishbone properties
	//
	////////////////////////////////////////////////
	//
	//
	wire	f_cyc, f_stb;
 
	assign	f_cyc = (o_wb_cyc_gbl)|(o_wb_cyc_lcl);
	assign	f_stb = (o_wb_stb_gbl)|(o_wb_stb_lcl);
 
	always @(*)
	begin
		// Only one interface can be active at once
		`ASSERT((!o_wb_cyc_gbl)||(!o_wb_cyc_lcl));
		// Strobe may only be active on the active interface
		`ASSERT((r_wb_cyc_gbl)||(!o_wb_stb_gbl));
		`ASSERT((r_wb_cyc_lcl)||(!o_wb_stb_lcl));
		if (o_wb_stb_lcl)
		begin
			if (o_wb_we)
				assert(state == DC_WRITE);
			else
				assert(state == DC_READS);
		end
 
		if (cyc)
			assert(o_wb_we == (state == DC_WRITE));
	end
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(cyc)&&($past(cyc)))
	begin
		`ASSERT($stable(r_wb_cyc_gbl));
		`ASSERT($stable(r_wb_cyc_lcl));
	end
 
 
`ifdef	DCACHE
`define	FWB_MASTER	fwb_master
`else
`define	FWB_MASTER	fwb_counter
`endif
 
	`FWB_MASTER #(
		.AW(AW), .DW(DW),
			.F_MAX_STALL(2),
			.F_MAX_ACK_DELAY(3),
			// If you need the proof to run faster, use these
			// lines instead of the two that follow
			// .F_MAX_STALL(1),
			// .F_MAX_ACK_DELAY(1),
			.F_LGDEPTH(F_LGDEPTH),
			.F_MAX_REQUESTS((OPT_PIPE) ? 0 : (1<<LS)),
`ifdef	DCACHE
			.F_OPT_SOURCE(1'b1),
`endif
			.F_OPT_DISCONTINUOUS(0)
		) fwb(i_clk, i_reset,
			cyc, f_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
				i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
		f_nreqs, f_nacks, f_outstanding);
 
`ifdef	DCACHE	// Arbitrary access is specific to local dcache implementation
	////////////////////////////////////////////////
	//
	// Arbitrary address properties
	//
	////////////////////////////////////////////////
	//
	//
	(* anyconst *)	reg	[AW:0]		f_const_addr;
	(* anyconst *)	reg			f_const_buserr;
	wire	[AW-LS-1:0]	f_const_tag, f_ctag_here, f_wb_tag;
	wire	[CS-LS-1:0]	f_const_tag_addr;
	reg	[DW-1:0]	f_const_data;
	wire	[DW-1:0]	f_cmem_here;
	reg			f_pending_rd;
	wire			f_cval_in_cache;
 
	assign	f_const_tag    = f_const_addr[AW-1:LS];
	assign	f_const_tag_addr = f_const_addr[CS-1:LS];
	assign	f_cmem_here    = c_mem[f_const_addr[CS-1:0]];
	assign	f_ctag_here    = c_vtags[f_const_addr[CS-1:LS]];
	assign	f_wb_tag       = o_wb_addr[AW-1:LS];
 
	assign	f_cval_in_cache= (c_v[f_const_addr[CS-1:LS]])
					&&(f_ctag_here == f_const_tag);
 
	generate if ((AW > DW - 8)&&(OPT_LOCAL_BUS))
	begin : UPPER_CONST_ADDR_BITS
 
		always @(*)
		if (f_const_addr[AW])
			assume(&f_const_addr[(AW-1):(DW-8)]);
		else
			assume(!(&f_const_addr[(AW-1):(DW-8)]));
	end endgenerate
 
	wire	[AW-1:0]	wb_start;
	assign	wb_start = (f_stb) ? (o_wb_addr - f_nreqs) : o_wb_addr;
 
	// Data changes upon request
	always @(posedge i_clk)
	begin
		if ((i_pipe_stb)&&(i_addr[(AW+1):2] == f_const_addr[AW-1:0])
			&&(f_const_addr[AW] == ((OPT_LOCAL_BUS)
						&&(&i_addr[(DW-1):(DW-8)])))
			&&(i_op[0]))
		begin
			casez({ i_op[2:1], i_addr[1:0] })
			4'b0???: f_const_data <= i_data;
			4'b100?: f_const_data[31:16] <= i_data[15:0];
			4'b101?: f_const_data[15: 0] <= i_data[15:0];
			4'b1100: f_const_data[31:24] <= i_data[ 7:0];
			4'b1101: f_const_data[23:16] <= i_data[ 7:0];
			4'b1110: f_const_data[15: 8] <= i_data[ 7:0];
			4'b1111: f_const_data[ 7: 0] <= i_data[ 7:0];
			endcase
		end
 
		if (f_cval_in_cache)
			assume((!i_wb_err)
				||(!i_pipe_stb)
				||(f_const_addr[AW-1:0] != i_addr[AW+1:2]));
	end
 
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!i_reset)&&(!f_const_buserr))
	begin
		if ((cyc)&&(o_wb_we)&&(f_stb)
				&&(o_wb_addr[AW-1:0] == f_const_addr[AW-1:0])
				&&( o_wb_stb_lcl == f_const_addr[AW]))
		begin
 
			//
			// Changing our data
			//
			if (o_wb_sel[0])
				`ASSERT(o_wb_data[ 7: 0]==f_const_data[ 7: 0]);
			if (o_wb_sel[1])
				`ASSERT(o_wb_data[15: 8]==f_const_data[15: 8]);
			if (o_wb_sel[2])
				`ASSERT(o_wb_data[23:16]==f_const_data[23:16]);
			if (o_wb_sel[3])
				`ASSERT(o_wb_data[31:24]==f_const_data[31:24]);
 
			// Check the data in the cache
			if ((!f_const_addr[AW])&&(c_v[f_const_tag_addr])
				&&(f_ctag_here == o_wb_addr[AW-1:LS]))
			begin
			if ((!c_wsel[0])&&(!o_wb_sel[0]))
				`ASSERT(f_cmem_here[ 7: 0]==f_const_data[ 7: 0]);
			if ((!c_wsel[1])&&(!o_wb_sel[1]))
				`ASSERT(f_cmem_here[15: 8]==f_const_data[15: 8]);
			if ((!c_wsel[2])&&(!o_wb_sel[2]))
				`ASSERT(f_cmem_here[23:16]==f_const_data[23:16]);
			if ((!c_wsel[3])&&(!o_wb_sel[3]))
				`ASSERT(f_cmem_here[31:24]==f_const_data[31:24]);
 
			end
		end else if ((!f_const_addr[AW])&&(c_v[f_const_tag_addr])
			&&(f_ctag_here ==f_const_addr[AW-1:LS]))
		begin
			// If ...
			//   1. Our magic address is cachable
			//   2. Our magic address is associated with a valid
			//		cache line
			//   3. The cache tag matches our magic address
 
 
			// if ($past(cyc && i_wb_err))
			// begin
				// Ignore what happens on an error, the result
				// becomes undefined anyway
			// end else
			if ((c_wr)
				&&(c_waddr[CS-1:0] == f_const_addr[CS-1:0]))
			begin
				//
				// If we are writing to this valid cache line
				//
				if (c_wsel[3])
					`ASSERT(c_wdata[31:24]
							== f_const_data[31:24]);
				else
					`ASSERT(f_cmem_here[31:24]
							== f_const_data[31:24]);
				if (c_wsel[2])
					`ASSERT(c_wdata[23:16]
							== f_const_data[23:16]);
				else
					`ASSERT(f_cmem_here[23:16] == f_const_data[23:16]);
				if (c_wsel[1])
					`ASSERT(c_wdata[15:8]
							== f_const_data[15:8]);
				else
					`ASSERT(f_cmem_here[15:8] == f_const_data[15:8]);
				if (c_wsel[0])
					`ASSERT(c_wdata[7:0]
							== f_const_data[7:0]);
				else
					`ASSERT(f_cmem_here[7:0] == f_const_data[7:0]);
			end else
				`ASSERT(f_cmem_here == f_const_data);
		end
	end
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(state == DC_READC))
	begin
		`ASSERT(f_wb_tag == r_ctag);
		if ((wb_start[AW-1:LS] == f_const_tag)
			&&(!c_v[f_const_tag_addr])
			&&(f_const_addr[AW] == r_wb_cyc_lcl)
			&&(f_nacks > f_const_addr[LS-1:0]))
		begin
			// We are reading the cache line containing our
			// constant address f_const_addr.  Make sure the data
			// is correct.
			if ((c_wr)&&(c_waddr[CS-1:0] == f_const_addr[CS-1:0]))
				`ASSERT(c_wdata == f_const_data);
			else
				`ASSERT(f_cmem_here == f_const_data);
		end
 
		if (f_nacks > 0)
			`ASSERT(!c_v[wb_start[CS-1:LS]]);
	end
 
	always @(posedge i_clk)
	if ((state == DC_READC)&&(f_nacks > 0))
	begin
		`ASSERT(c_vtags[wb_start[(CS-1):LS]] <= wb_start[(AW-1):LS]);
		`ASSERT(c_vtags[wb_start[(CS-1):LS]] <= r_addr[AW-1:LS]);
	end
 
	reg	[AW-1:0]	f_cache_waddr;
	wire			f_this_cache_waddr;
 
	always @(*)
	begin
		// f_cache_waddr[AW-1:LS] = c_vtags[c_waddr[CS-1:CS-LS]];
		f_cache_waddr[AW-1:LS] = wb_start[AW-1:LS];
		f_cache_waddr[CS-1: 0] = c_waddr[CS-1:0];
	end
 
	assign	f_this_cache_waddr = (!f_const_addr[AW])
				&&(f_cache_waddr == f_const_addr[AW-1:0]);
	always @(posedge i_clk)
	if ((f_past_valid)&&(state == DC_READC))
	begin
		if ((c_wr)&&(c_waddr[LS-1:0] != 0)&&(f_this_cache_waddr))
			`ASSERT(c_wdata == f_const_data);
	end
 
	always @(posedge i_clk)
	if ((OPT_PIPE)&&(o_busy)&&(i_pipe_stb))
	begin
		`ASSUME(i_op[0] == o_wb_we);
		if (o_wb_cyc_lcl)
			assume(&i_addr[DW-1:DW-8]);
		else
			assume(!(&i_addr[DW-1:DW-8]));
	end
 
	initial	f_pending_rd = 0;
	always @(posedge i_clk)
	if (i_reset)
		f_pending_rd <= 0;
	else if (i_pipe_stb)
		f_pending_rd <= (!i_op[0]);
	else if ((o_valid)&&((!OPT_PIPE)
		||((state != DC_READS)&&(!r_svalid)&&(!$past(i_pipe_stb)))))
		f_pending_rd <= 1'b0;
 
	always @(*)
	if ((state == DC_READC)&&(!f_stb))
		`ASSERT(f_nreqs == (1<<LS));
 
	always @(*)
	if ((state == DC_READC)&&(f_stb))
		`ASSERT(f_nreqs == { 1'b0, o_wb_addr[LS-1:0] });
 
	always @(posedge i_clk)
	if (state == DC_READC)
	begin
		if (($past(i_wb_ack))&&(!$past(f_stb)))
			`ASSERT(f_nacks-1 == { 1'b0, c_waddr[LS-1:0] });
		else if (f_nacks > 0)
		begin
			`ASSERT(f_nacks-1 == { 1'b0, c_waddr[LS-1:0] });
			`ASSERT(c_waddr[CS-1:LS] == o_wb_addr[CS-1:LS]);
		end else begin
			`ASSERT(c_waddr[CS-1:LS] == o_wb_addr[CS-1:LS]-1'b1);
			`ASSERT(&c_waddr[LS-1:0]);
		end
	end
 
	always @(*)
	if (r_rd_pending)
		`ASSERT(r_addr == f_pending_addr[AW-1:0]);
 
	always @(*)
	if (f_pending_addr[AW])
	begin
		`ASSERT(state != DC_READC);
		`ASSERT((!o_wb_we)||(!o_wb_cyc_gbl));
	end
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(o_valid)&&($past(f_pending_addr) == f_const_addr))
	begin
		if (f_const_buserr)
			`ASSERT(o_err);
		else if (f_pending_rd)
		begin
			casez($past(req_data[3:0]))
			4'b0???: `ASSERT(o_data ==f_const_data);
			4'b101?: `ASSERT(o_data =={16'h00,f_const_data[15: 0]});
			4'b100?: `ASSERT(o_data =={16'h00,f_const_data[31:16]});
			4'b1100: `ASSERT(o_data =={24'h00,f_const_data[31:24]});
			4'b1101: `ASSERT(o_data =={24'h00,f_const_data[23:16]});
			4'b1110: `ASSERT(o_data =={24'h00,f_const_data[15: 8]});
			4'b1111: `ASSERT(o_data =={24'h00,f_const_data[ 7: 0]});
			endcase
		end
	end
 
	wire			f_this_return;
 
	assign	f_this_return = (f_return_address == f_const_addr);
	always @(*)
	if ((f_cyc)&&(
		((state == DC_READC)
			&&(f_return_address[AW-1:LS] == f_const_addr[AW-1:LS]))
		||(f_this_return))&&(f_cyc))
	begin
		if (f_const_buserr)
			assume(!i_wb_ack);
		else begin
			assume(!i_wb_err);
			assume(i_wb_data == f_const_data);
		end
	end
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(last_tag == f_const_tag)&&(f_const_buserr)
			&&(!f_const_addr[AW]))
		`ASSERT(!last_tag_valid);
 
	always @(*)
	if (f_const_buserr)
	begin
		`ASSERT((!c_v[f_const_tag_addr])||(f_const_addr[AW])
			||(f_ctag_here != f_const_tag));
 
		if ((state == DC_READC)&&(wb_start[AW-1:LS] == f_const_tag))
		begin
			`ASSERT(f_nacks <= f_const_tag[LS-1:0]);
			if (f_nacks == f_const_tag[LS-1:0])
				assume(!i_wb_ack);
		end
	end
 
`endif	// DCACHE
 
	////////////////////////////////////////////////
	//
	// Checking the lock
	//
	////////////////////////////////////////////////
	//
	//
 
	always @(*)
		`ASSERT((!lock_gbl)||(!lock_lcl));
	always @(*)
	if (!OPT_LOCK)
		`ASSERT((!lock_gbl)&&(!lock_lcl));
 
	////////////////////////////////////////////////
	//
	// State based properties
	//
	////////////////////////////////////////////////
	//
	//
	reg	[F_LGDEPTH-1:0]	f_rdpending;
 
	initial	f_rdpending = 0;
	always @(posedge i_clk)
	if ((i_reset)||(o_err))
		f_rdpending <= 0;
	else case({ (i_pipe_stb)&&(!i_op[0]), o_valid })
	2'b01: f_rdpending <= f_rdpending - 1'b1;
	2'b10: f_rdpending <= f_rdpending + 1'b1;
	default: begin end
	endcase
 
	wire	f_wb_cachable;
	iscachable #(.ADDRESS_WIDTH(AW))
		f_chkwb_addr(o_wb_addr, f_wb_cachable);
 
 
	always @(*)
	if (state == DC_IDLE)
	begin
		`ASSERT(!r_wb_cyc_gbl);
		`ASSERT(!r_wb_cyc_lcl);
 
		`ASSERT(!cyc);
 
		if ((r_rd_pending)||(r_dvalid)||(r_svalid))
			`ASSERT(o_busy);
 
		if (!OPT_PIPE)
		begin
			if (r_rd_pending)
				`ASSERT(o_busy);
			else if (r_svalid)
				`ASSERT(o_busy);
			else if (o_valid)
				`ASSERT(!o_busy);
			else if (o_err)
				`ASSERT(!o_busy);
		end
	end else begin
		`ASSERT(o_busy);
		`ASSERT(cyc);
	end
 
 
 
	always @(posedge i_clk)
	if (state == DC_IDLE)
	begin
		if (r_svalid)
		begin
			`ASSERT(!r_dvalid);
			`ASSERT(!r_rd_pending);
			if (!OPT_PIPE)
				`ASSERT(!o_valid);
			else if (o_valid)
				`ASSERT(f_rdpending == 2);
		end
 
		if (r_dvalid)
		begin
			`ASSERT(!r_rd_pending);
			`ASSERT(npending == 0);
			`ASSERT(f_rdpending == 1);
		end
 
		if (r_rd_pending)
		begin
			if ((OPT_PIPE)&&(o_valid))
				`ASSERT(f_rdpending <= 2);
			else
				`ASSERT(f_rdpending == 1);
 
		end else if ((OPT_PIPE)&&(o_valid)&&($past(r_dvalid|r_svalid)))
				`ASSERT(f_rdpending <= 2);
		else
			`ASSERT(f_rdpending <= 1);
	end
 
	always @(posedge i_clk)
	if (state == DC_READC)
	begin
		`ASSERT( o_wb_cyc_gbl);
		`ASSERT(!o_wb_cyc_lcl);
		`ASSERT(!o_wb_we);
		`ASSERT(f_wb_cachable);
 
		`ASSERT(r_rd_pending);
		`ASSERT(r_cachable);
		if (($past(cyc))&&(!$past(o_wb_stb_gbl)))
			`ASSERT(!o_wb_stb_gbl);
 
		if ((OPT_PIPE)&&(o_valid))
			`ASSERT(f_rdpending == 2);
		else
			`ASSERT(f_rdpending == 1);
	end
 
	always @(*)
	if (state == DC_READS)
	begin
		`ASSERT(!o_wb_we);
 
		if (OPT_PIPE)
		begin
			if (o_valid)
				`ASSERT((f_rdpending == npending + 1)
					||(f_rdpending == npending));
			else
				`ASSERT(f_rdpending == npending);
		end
	end else if (state == DC_WRITE)
		`ASSERT(o_wb_we);
 
	always @(posedge i_clk)
	if ((state == DC_READS)||(state == DC_WRITE))
	begin
		`ASSERT(o_wb_we == (state == DC_WRITE));
		`ASSERT(!r_rd_pending);
		if (o_wb_we)
			`ASSERT(f_rdpending == 0);
 
		if (OPT_PIPE)
		begin
			casez({ $past(i_pipe_stb), f_stb })
			2'b00: `ASSERT(npending == f_outstanding);
			2'b1?: `ASSERT(npending == f_outstanding + 1);
			2'b01: `ASSERT(npending == f_outstanding + 1);
			endcase
 
			if (state == DC_WRITE)
				`ASSERT(!o_valid);
		end else
			`ASSERT(f_outstanding <= 1);
	end
 
	always @(*)
	if (OPT_PIPE)
		`ASSERT(f_rdpending <= 2);
	else
		`ASSERT(f_rdpending <= 1);
 
	always @(posedge i_clk)
	if ((!OPT_PIPE)&&(o_valid))
		`ASSERT(f_rdpending == 1);
	else if (o_valid)
		`ASSERT(f_rdpending >= 1);
 
 
	always @(*)
	if ((!o_busy)&&(!o_err)&&(!o_valid))
		`ASSERT(f_rdpending == 0);
 
	always @(*)
		`ASSERT(cyc == ((r_wb_cyc_gbl)||(r_wb_cyc_lcl)));
 
	always @(*)
	if ((!i_reset)&&(f_nreqs == f_nacks)&&(!f_stb))
		`ASSERT(!cyc);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&($past(o_err)))
		`ASSUME(!i_lock);
	else if ((f_past_valid)&&(OPT_LOCK)&&($past(i_lock))
			&&((!$past(o_valid)) || ($past(i_pipe_stb))))
		`ASSUME($stable(i_lock));
 
 
	////////////////////////////////////////////////
	//
	// Ad-hoc properties
	//
	////////////////////////////////////////////////
	//
	//
	always @(*)
	if ((OPT_PIPE)&&(state == DC_WRITE)&&(!i_wb_stall)&&(stb)
			&&(!npending[DP]))
		`ASSERT(!o_pipe_stalled);
 
	always @(posedge i_clk)
	if (state == DC_WRITE)
		`ASSERT(o_wb_we);
	else if ((state == DC_READS)||(state == DC_READC))
		`ASSERT(!o_wb_we);
 
	always @(*)
	if (cyc)
		`ASSERT(f_cyc);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(cyc))&&(!c_wr)&&(last_tag_valid)
			&&(!r_rd_pending))
		`ASSERT((c_v[last_tag[(CS-LS-1):0]])
			&&(c_vtags[last_tag[(CS-LS-1):0]] == last_tag));
 
	always @(*)
	if (!OPT_LOCAL_BUS)
	begin
		`ASSERT(r_wb_cyc_lcl == 1'b0);
		`ASSERT(o_wb_stb_lcl == 1'b0);
		`ASSERT(lock_lcl == 1'b0);
	end
 
	always @(posedge i_clk)
	if ((state == DC_READC)&&(!stb))
	begin
		`ASSERT(o_wb_addr[LS-1:0] == 0);
		`ASSERT(o_wb_addr[AW-1:CS] == r_addr[AW-1:CS]);
	end else if ((state == DC_READC)&&(stb))
	begin
		`ASSERT(o_wb_addr[AW-1:CS] == r_addr[AW-1:CS]);
		`ASSERT(o_wb_addr[LS-1:0] == f_nreqs[LS-1:0]);
	end
 
	wire	[CS-1:0]	f_expected_caddr;
	assign	f_expected_caddr = { r_ctag[CS-LS-1:0], {(LS){1'b0}} }-1
					+ f_nacks;
	always @(posedge i_clk)
	if (state == DC_READC)
	begin
		if (LS == 0)
			`ASSERT(end_of_line);
		else if (f_nacks < (1<<LS)-1)
			`ASSERT(!end_of_line);
		else if (f_nacks == (1<<LS)-1)
			`ASSERT(end_of_line);
		`ASSERT(f_nacks <= (1<<LS));
		`ASSERT(f_nreqs <= (1<<LS));
		if (f_nreqs < (1<<LS))
		begin
			`ASSERT(o_wb_stb_gbl);
			`ASSERT(o_wb_addr[(LS-1):0] == f_nreqs[LS-1:0]);
		end else
			`ASSERT(!f_stb);
		`ASSERT((f_nreqs == 0)||(f_nacks <= f_nreqs));
		`ASSERT(c_waddr == f_expected_caddr);
	end
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(r_rd)&&(!$past(i_reset)))
	begin
		`ASSERT((o_busy)||(r_svalid));
	end
 
	always @(posedge i_clk)
	if (!$past(o_busy))
		`ASSERT(!r_dvalid);
 
	always @(posedge i_clk)
	if ((state == DC_READC)&&(c_wr))
		`ASSERT(c_wsel == 4'hf);
 
	always @(*)
	if (c_wr)
		`ASSERT((c_wsel == 4'hf)
			||(c_wsel == 4'hc)
			||(c_wsel == 4'h3)
			||(c_wsel == 4'h8)
			||(c_wsel == 4'h4)
			||(c_wsel == 4'h2)
			||(c_wsel == 4'h1));
 
	always @(*)
	if (!OPT_PIPE)
		`ASSERT(o_pipe_stalled == o_busy);
	else if (o_pipe_stalled)
		`ASSERT(o_busy);
 
	//
	// Only ever abort on reset
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(i_reset))&&($past(cyc))&&(!$past(i_wb_err)))
	begin
		if (($past(i_pipe_stb))&&(!$past(o_pipe_stalled)))
			`ASSERT(cyc);
		else if ($past(f_outstanding > 1))
			`ASSERT(cyc);
		else if (($past(f_outstanding == 1))
				&&((!$past(i_wb_ack))
					||(($past(f_stb))
						&&(!$past(i_wb_stall)))))
			`ASSERT(cyc);
		else if (($past(f_outstanding == 0))
				&&($past(f_stb)&&(!$past(i_wb_ack))))
			`ASSERT(cyc);
	end
 
	always @(posedge i_clk)
	if ((OPT_PIPE)&&(f_past_valid)&&(!$past(i_reset))&&(state != DC_READC))
	begin
		if ($past(cyc && i_wb_err))
		begin
			`ASSERT(npending == 0);
		end else if (($past(i_pipe_stb))||($past(i_wb_stall && stb)))
			`ASSERT((npending == f_outstanding+1)
				||(npending == f_outstanding+2));
		else
			`ASSERT(npending == f_outstanding);
	end
 
	always @(posedge i_clk)
	if ((OPT_PIPE)&&(state != DC_READC)&&(state != DC_IDLE))
		`ASSERT(last_ack == (npending <= 1));
 
	always @(*)
	`ASSERT(stb == f_stb);
 
	always @(*)
	if (r_rd_pending)
		`ASSERT(!r_svalid);
 
	always @(*)
	if (o_err)
		`ASSUME(!i_pipe_stb);
 
	always @(*)
	if (last_tag_valid)
		`ASSERT(|c_v);
 
	always @(posedge i_clk)
	if ((cyc)&&(state == DC_READC)&&($past(f_nacks > 0)))
		`ASSERT(!c_v[o_wb_addr[CS-1:LS]]);
 
	always @(*)
	if (last_tag_valid)
	begin
		`ASSERT((!cyc)||(o_wb_we)||(state == DC_READS)
					||(o_wb_addr[AW-1:LS] != last_tag));
	end
 
	wire	f_cachable_last_tag, f_cachable_r_addr;
 
	iscachable #(.ADDRESS_WIDTH(AW))
		fccheck_last_tag({last_tag, {(LS){1'b0}}}, f_cachable_last_tag);
 
	iscachable #(.ADDRESS_WIDTH(AW))
		fccheck_r_cachable(r_addr, f_cachable_r_addr);
 
	always @(*)
	if ((r_cachable)&&(r_rd_pending))
	begin
		`ASSERT(state != DC_WRITE);
		// `ASSERT(state != DC_READS);
		`ASSERT(f_cachable_r_addr);
		if (cyc)
			`ASSERT(o_wb_addr[AW-1:LS] == r_addr[AW-1:LS]);
	end
 
	always @(*)
	if (last_tag_valid)
	begin
		`ASSERT(f_cachable_last_tag);
		`ASSERT(c_v[last_tag[CS-LS-1:0]]);
		`ASSERT(c_vtags[last_tag[CS-LS-1:0]]==last_tag);
		`ASSERT((state != DC_READC)||(last_tag != o_wb_addr[AW-1:LS]));
	end
 
 
	////////////////////////////////////////////////
	//
	// Cover statements
	//
	////////////////////////////////////////////////
	//
	//
 
	always @(posedge i_clk)
		cover(o_valid);
 
	always @(posedge i_clk)
	if (f_past_valid)
		cover($past(r_svalid));
 
	generate if (OPT_PIPE)
	begin : PIPE_COVER
 
		wire		recent_reset;
		reg	[2:0]	recent_reset_sreg;
		initial	recent_reset_sreg = -1;
		always @(posedge i_clk)
		if (i_reset)
			recent_reset_sreg <= -1;
		else
			recent_reset_sreg <= { recent_reset_sreg[1:0], 1'b0 };
 
		assign recent_reset = (i_reset)||(|recent_reset_sreg);
 
		//
		//
		wire	f_cvr_cread = (!recent_reset)&&(i_pipe_stb)&&(!i_op[0])
					&&(w_cachable);
 
		wire	f_cvr_cwrite = (!recent_reset)&&(i_pipe_stb)&&(i_op[0])
				&&(!cache_miss_inow);
 
		wire	f_cvr_writes = (!recent_reset)&&(i_pipe_stb)&&(i_op[0])
					&&(!w_cachable);
		wire	f_cvr_reads  = (!recent_reset)&&(i_pipe_stb)&&(!i_op[0])
					&&(!w_cachable);
		wire	f_cvr_test  = (!recent_reset)&&(cyc);
 
		always @(posedge i_clk)
		if ((f_past_valid)&&($past(o_valid)))
			cover(o_valid);		// !
 
		always @(posedge i_clk)
		if ((f_past_valid)&&(!$past(i_reset))&&($past(i_pipe_stb)))
			cover(i_pipe_stb);
 
		always @(posedge i_clk)
		if ((f_past_valid)&&($past(o_valid))&&($past(o_valid,2)))
			cover(o_valid);
 
		always @(posedge i_clk)
			cover(($past(f_cvr_cread))&&(f_cvr_cread));
 
		always @(posedge i_clk)
			cover(($past(f_cvr_cwrite))&&(f_cvr_cwrite));
 
		always @(posedge i_clk)
			cover(($past(f_cvr_writes))&&(f_cvr_writes));
 
		/*
		* This cover statement will never pass.  Why not?  Because
		* cache reads must be separated from non-cache reads.  Hence,
		* we can only allow a single non-cache read at a time, otherwise
		* we'd bypass the cache read logic.
		*
		always @(posedge i_clk)
			cover(($past(f_cvr_reads))&&(f_cvr_reads));
		*/
 
		//
		// This is unrealistic, as it depends upon the Wishbone
		// acknoledging the request on the same cycle
		always @(posedge i_clk)
			cover(($past(f_cvr_reads,2))&&(f_cvr_reads));
 
		always @(posedge i_clk)
			cover(($past(r_dvalid))&&(r_svalid));
 
		//
		// A minimum of one clock must separate two dvalid's.
		// This option is rather difficult to cover, since it means
		// we must first load two separate cache lines before
		// this can even be tried.
		always @(posedge i_clk)
			cover(($past(r_dvalid,2))&&(r_dvalid));
 
		//
		// This is the optimal configuration we want:
		//	i_pipe_stb
		// 	##1 i_pipe_stb && r_svalid
		//	##1 r_svalid && o_valid
		//	##1 o_valid
		// It proves that we can handle a 2 clock delay, but that
		// we can also pipelin these cache accesses, so this
		// 2-clock delay becomes a 1-clock delay between pipelined
		// memory reads.
		//
		always @(posedge i_clk)
			cover(($past(r_svalid))&&(r_svalid));
 
		//
		// While we'd never do this (it breaks the ZipCPU's pipeline
		// rules), it's nice to know we could.
		//	i_pipe_stb && (!i_op[0]) // a read
		//	##1 i_pipe_stb && (i_op[0]) && r_svalid // a write
		//	##1 o_valid
		always @(posedge i_clk)
			cover(($past(r_svalid))&&(f_cvr_writes));
 
		/* Unreachable
		*
		always @(posedge i_clk)
			cover(($past(f_cvr_writes))&&(o_valid));
 
		always @(posedge i_clk)
			cover(($past(f_cvr_writes,2))&&(o_valid));
 
		always @(posedge i_clk)
			cover(($past(f_cvr_writes,3))&&(o_valid));
 
		always @(posedge i_clk)
			cover(($past(r_dvalid,3))&&(r_dvalid));
 
		*/
 
		always @(posedge i_clk)
			cover(($past(f_cvr_writes,4))&&(o_valid));
 
	end endgenerate
 
	////////////////////////////////////////////////
	//
	// Carelesss assumption section
	//
	////////////////////////////////////////////////
	//
	//
 
	//
	// Can't jump from local to global mid lock
	always @(*)
	if((OPT_LOCK)&&(OPT_LOCAL_BUS))
	begin
		if ((i_lock)&&(o_wb_cyc_gbl)&&(i_pipe_stb))
			assume(!(&i_addr[(DW-1):(DW-8)]));
		else if ((i_lock)&&(o_wb_cyc_lcl)&&(i_pipe_stb))
			assume(&i_addr[(DW-1):(DW-8)]);
	end
 
	always @(*)
	if ((OPT_PIPE)&&(o_busy || i_lock)&&(!o_pipe_stalled))
	begin
		if (i_pipe_stb)
			assume((!OPT_LOCAL_BUS)
				||(f_pending_addr[AW]==(&i_addr[DW-1:DW-8])));
	end
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(cyc))&&(!cyc))
		assume((!i_wb_err)&&(!i_wb_ack));
 
`endif
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2021 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.