cpu_mon.v 4.07 KB
// cpu_mon.v v1 Frank Berndt
// cpu sysad bus monitor;
// :set tabstop=4

module cpu_mon (
	sysclk,
	divmode, coldrst_l, warmrst_l,
	eok_l,
	sysad_out, syscmd_out, pvalid_l,
	sysad_in, syscmd_in, evalid_l,
	int_l, nmi_l,
	secure,
);
	input sysclk;
	input [2:0] divmode;
	input coldrst_l;
	input warmrst_l;
	input eok_l;
	input [31:0] sysad_out;		// from cpu;
	input [4:0] syscmd_out;
	input pvalid_l;
	input [31:0] sysad_in;		// to cpu;
	input [4:0] syscmd_in;
	input evalid_l;
	input [4:0] int_l;
	input nmi_l;
	input secure;

	// monitor cpu activity;

	reg cpu_mon;		// monitor enable flag;
	reg ready;			// cpu is ready;

	initial
	begin
		cpu_mon = $test$plusargs("cpu_mon");
		$display("%M: enabled %b", cpu_mon);
		ready = 0;
		#1;
		ready = 0;
	end

	// monitor pll divmode;

	always @(divmode)
	begin
		$display("%t: %M: divmode %b", $time, divmode);
	end

	// monitor cpu resets;

	always @(coldrst_l or warmrst_l)
	begin
		$display("%t: %M: cpu coldrst %b warmrst %b", $time, coldrst_l, warmrst_l);
	end

	always @(negedge coldrst_l or negedge warmrst_l)
		ready = 0;
	always @(posedge warmrst_l)
		ready = 1;

	// monitor secure mode;

	always @(secure)
	begin
		$display("%t: %M: secure mode %b", $time, secure);
	end

	// monitor sysad bus activity;
	// always report fatal errors;

	reg issue;			// issue cycle;
	reg sout_x;			// address issue phase has Xs;
	reg cout_x;			// write data phase has Xs;
	reg [31:0] ad;		// address/data word;
	integer size;		// request size in bytes;
	integer wdi;		// write data word index;
	integer rdi;		// response data word index;
	integer nwords;		// # of expected data words;
	reg slave;			// bus interface in slave;

	initial 
	begin
		slave = 0;
		nwords = 0;
	end

	// monitor request issue and write protocol;

	always @(posedge sysclk)
	begin
		issue <= ~eok_l;
		if(ready) begin
			if((eok_l === 1'bx) | (eok_l === 1'bz))
				$display("ERROR: %t: %M: eok_l %b", $time, eok_l);
			if(pvalid_l === 1'b0) begin
				sout_x = ^sysad_out;
				cout_x = ^syscmd_out;
				if(cout_x === 1'bx)
					$display("ERROR: %t: %M: syscmd_out 0x%h", $time, syscmd_out);
				ad = sysad_out;
				if(syscmd_out[4] === 1'b0) begin
					if(sout_x === 1'bx)
						$display("ERROR: %t: %M: sysad_out 0x%h", $time, sysad_out);
					size = syscmd_out[2]? (8 << syscmd_out[1:0]) : (syscmd_out[1:0] + 1);
					nwords = syscmd_out[2]? (2 << syscmd_out[1:0]) : 1;
					if(size > 32)
						$display("ERROR: %t: %M: syscmd_out size %0d", $time, size);
					if(issue) begin
						if(cpu_mon) begin
							$display("%t: %M: addr 0x%h, %s %0d",
								$time, ad, syscmd_out[3]? "write" : "read ", size);
						end
						slave = ~syscmd_out[3];
					end
					wdi = 0;
					rdi = 0;
				end else if(syscmd_out[4] === 1'b1) begin
					if(cpu_mon)
						$display("%t: %M: data[%0d] 0x%h", $time, wdi, ad);
					if(wdi >= nwords)
						$display("ERROR: %t: %M: excessive write data", $time);
					wdi = wdi + 1;
				end
			end else if(pvalid_l !== 1'b1) begin
				$display("ERROR: %t: %M: pvalid_l %b", $time, pvalid_l);
				repeat(50) @(posedge sysclk);
				$finish;
			end
		end
	end

	// monitor response protocol;

	always @(posedge sysclk)
	begin
		if(ready) begin
			if(evalid_l === 1'b0) begin
				if( !slave)
					$display("ERROR: %t: %M: evalid_l when not in slave state", $time);
				casex(syscmd_in)
					5'b1000x,
					5'b1100x,
					5'b1001x,
					5'b1101x: begin
						if(rdi >= nwords)
							$display("ERROR: %t: %M: excessive read response data", $time);
						if(cpu_mon) begin
							$display("%t: %M: rsp[%0d] 0x%h last %b err %b",
								$time, rdi, sysad_in, ~syscmd_in[3], syscmd_in[1]);
						if(syscmd_in[3] === 1'b0)
							slave = 0;
						rdi = rdi + 1;
						end
					end
					default:
						$display("ERROR: %t: %M: syscmd_in %b", $time, syscmd_in);
				endcase
			end else if(evalid_l !== 1'b1)
				$display("ERROR: %t: %M: evalid_l %b", $time, evalid_l);
		end
	end

	// detect and log cpu interrupts and nmi;

	always @(int_l)
	begin
		if(ready & cpu_mon)
			$display("%t: %M: int_l %b", $time, int_l);
	end

	always @(nmi_l)
	begin
		if(ready & cpu_mon)
			$display("%t: %M: nmi_l %b", $time, nmi_l);
	end

endmodule