Performance Degrade when calling sequencer ".start" repeatedly



Hey,
My simulation runs super-slow when I toggle interface lines with UVM based methods versus using Xilinx verilog IP to toggle the lines.
I attached the code I think is relevant below (some code was removed for easier reading).
Following the profiling process (in the two photos attached), it seems like “.start” method in uvm_sequence_base.svh, which I call a lot of times, causes that degrade (very high usage of stack).
I use Questa 2020.4 as my simulator.
Thanks.

typedef uvm_sequence #(uvm_sequence_item) uvm_virtual_sequence;
class VirtualSequence extends uvm_virtual_sequence;
	`uvm_object_utils(VirtualSequence)	
	
	typedef AxiStreamMasterBaseSequence#(AXI_STREAM_DATA_WIDTH_IN) AxiStreamMasterBaseSeq;
	typedef AxiStreamSlaveBaseSequence#(AXI_STREAM_DATA_WIDTH_OUT) AxiStreamSlaveBaseSeq;
	typedef axi_lite_item #(AXI_LITE_ADDR_WIDTH,AXI_LITE_DATA_WIDTH) axi_lite_item_t;
	operation_t axiLiteOp;
	MemoryConfig memConfig;
	GenericHandlers genericHandlers;
	rand frameBufferOps frameBufferOp;
	rand int camIDPressure;
	int camID;
	int lineCount;

	virtual AxiStreamIf#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamMasterVif;


	AxiStreamSlaveSanitySequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamSlaveSanitySeq;
	AxiStreamSlaveNormalSequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamSlaveNormalSeq;
	AxiStreamMasterSanitySequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamMasterSanitySeq;
	AxiStreamMasterValidReadyRandomSequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamMasterValidReadyRandomSeq;
	AxiStreamMasterDropValidSequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamMasterDropValidSeq;
	AxiStreamMasterResetSequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamMasterResetSeq;
	AxiStreamMasterFullRandomSequence#(AXI_STREAM_DATA_WIDTH_OUT) axiStreamMasterFullRandomSeq;
	AxiLiteGenericSequence#(AXI_LITE_ADDR_WIDTH, AXI_LITE_DATA_WIDTH) axiLiteWrSequence;
	AxiLiteGenericSequence#(AXI_LITE_ADDR_WIDTH, AXI_LITE_DATA_WIDTH) axiLiteRdSequence;
	FrameBufferEnvConfig frameBufferEnvCfg;

	uvm_sequencer#(axi_lite_item_t) axiLiteSeqrTPG;
	uvm_sequencer#(axi_lite_item_t) axiLiteSeqrDUT;
	uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) axiStreamMasterSeqr;
	uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) axiStreamSlaveSeqr;
	uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) resetSeqr;

	uvm_event MemoryConfigUpdated;
	uvm_event resetEvent;

	bit[7:0] backgroundPattern;


	extern function new(string name="VirtualSequence");
	extern function void createSequenceObjects();
	extern function void initAndUpdateReset();
	extern function logic[AXI_STREAM_DATA_WIDTH_OUT-1:0] getNextData();
	extern task sanity();
	extern task setTuser(AxiStreamMasterBaseSeq axiMasterSeq, AxiStreamSlaveBaseSeq axiSlaveSeq);
	extern task resetDUT();
	extern task triggerReset();
	extern task fullRandom(sofE isSOF = SOF_ENABLE);
	extern task transmitPixels(AxiStreamMasterBaseSeq axiMasterSeq1, AxiStreamMasterBaseSeq axiMasterSeq2, AxiStreamSlaveBaseSeq axiSlaveSeq1, AxiStreamSlaveBaseSeq axiSlaveSeq2);
	extern task startAxiLiteSequence(uvm_sequencer#(axi_lite_item_t) axiSeqr, AxiLiteGenericSequence#(AXI_LITE_ADDR_WIDTH, AXI_LITE_DATA_WIDTH) axiSeq, logic[31:0] address, logic[31:0] data, operation_t op);
	extern task startSlaveSequence(uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) slaveSeqr, AxiStreamSlaveBaseSeq slaveSeq, logic tready = 1'bz);
	extern task startMasterSequence(uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) masterSeqr, AxiStreamMasterBaseSeq masterSeq, logic tuser = 1'bz, logic tvalid = 1'bz, logic tlast = 1'bz, logic[AXI_STREAM_DATA_WIDTH_OUT-1:0] tdata = {AXI_STREAM_DATA_WIDTH_OUT{1'bz}}, logic reset = 1'bz, bit takeNewData = 1'b1);
	extern virtual task body();


endclass : VirtualSequence


function VirtualSequence::new(string name="VirtualSequence");
	super.new(name);
endfunction


function void VirtualSequence::createSequenceObjects();
	axiLiteWrSequence = AxiLiteGenericSequence#(AXI_LITE_ADDR_WIDTH, AXI_LITE_DATA_WIDTH)::type_id::create("axiLiteWrSequence");
	axiStreamSlaveSanitySeq = AxiStreamSlaveSanitySequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamSlaveSanitySeq");
	axiStreamSlaveNormalSeq = AxiStreamSlaveNormalSequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamSlaveNormalSeq");
	axiStreamMasterDropValidSeq = AxiStreamMasterDropValidSequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamMasterDropValidSeq");
	axiStreamMasterSanitySeq = AxiStreamMasterSanitySequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamMasterSanitySeq");
	axiStreamMasterValidReadyRandomSeq = AxiStreamMasterValidReadyRandomSequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamMasterValidReadyRandomSeq");
	axiStreamMasterResetSeq = AxiStreamMasterResetSequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamMasterResetSeq");
	axiStreamMasterFullRandomSeq = AxiStreamMasterFullRandomSequence#(AXI_STREAM_DATA_WIDTH_OUT)::type_id::create("axiStreamMasterFullRandomSeq");
endfunction




function logic[AXI_STREAM_DATA_WIDTH_OUT-1:0] VirtualSequence::getNextData();
	return $urandom_range(0,INPUT_MAX_VAL);
endfunction



task VirtualSequence::startSlaveSequence(uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) slaveSeqr, AxiStreamSlaveBaseSeq slaveSeq, logic tready = 1'bz);
 	if (tready !== 1'bz)
 		slaveSeq.tready = tready;
	slaveSeq.start(slaveSeqr);
endtask 



task VirtualSequence::startMasterSequence(uvm_sequencer#(AxiStreamSequenceItem#(AXI_STREAM_DATA_WIDTH_OUT)) masterSeqr, AxiStreamMasterBaseSeq masterSeq, logic tuser = 1'bz, logic tvalid = 1'bz, logic tlast = 1'bz, logic[AXI_STREAM_DATA_WIDTH_OUT-1:0] tdata = {AXI_STREAM_DATA_WIDTH_OUT{1'bz}}, logic reset = 1'bz, bit takeNewData = 1'b1);
 	if (reset !== 1'bz)
 		masterSeq.reset = reset;
 	if (tuser !== 1'bz)
 		masterSeq.tuser = tuser;
 	if (tvalid !== 1'bz)
 		masterSeq.tvalid = tvalid;
 	if (tlast !== 1'bz)
 		masterSeq.tlast = tlast;
	masterSeq.start(masterSeqr);
endtask 



task VirtualSequence::transmitPixels(AxiStreamMasterBaseSeq axiMasterSeq1, AxiStreamMasterBaseSeq axiMasterSeq2, AxiStreamSlaveBaseSeq axiSlaveSeq1, AxiStreamSlaveBaseSeq axiSlaveSeq2);
	while(!axiStreamMasterVif.tlast) begin
		fork
			begin
				startMasterSequence(axiStreamMasterSeqr, axiMasterSeq1, 0);
			end
			begin
				startSlaveSequence(axiStreamSlaveSeqr, axiSlaveSeq1);
			end
		join
		if (frameBufferEnvCfg.axiStreamMasterCfg[camID].disableEOL && axiStreamMasterVif.pixelCounterOut % IMG_WIDTH == 0 && axiStreamMasterVif.pixelCounterOut != 0) begin
			lineCount++;
			if (lineCount == IMG_HEIGHT) begin
				return;
			end
		end
	end
	lineCount++;
	while (axiStreamMasterVif.tlast) begin
		fork
			begin
				startMasterSequence(axiStreamMasterSeqr, axiMasterSeq2, 0);
			end
			begin
				if (lineCount >= IMG_HEIGHT-1)
					startSlaveSequence(axiStreamSlaveSeqr, axiStreamSlaveSanitySeq);
				else
					startSlaveSequence(axiStreamSlaveSeqr, axiSlaveSeq2);
			end
		join
	end
endtask : transmitPixels




task VirtualSequence::setTuser(AxiStreamMasterBaseSeq axiMasterSeq, AxiStreamSlaveBaseSeq axiSlaveSeq);
	fork
		begin
			startSlaveSequence(axiStreamSlaveSeqr, axiSlaveSeq);
		end
		begin
			startMasterSequence(axiStreamMasterSeqr, axiMasterSeq, 1, 1);
		end
	join
endtask



function void VirtualSequence::initAndUpdateReset();
	lineCount = 0;
	genericHandlers.finishedRandomizingMemConfig = 0;
endfunction : initAndUpdateReset


task VirtualSequence::sanity();
	int lineCount;
	// Raise tready
	startSlaveSequence(axiStreamSlaveSeqr, axiStreamSlaveSanitySeq);
	axiStreamMasterVif.clockingBlock.tdata <= getNextData();
	//Set tuser, tvalid
	startMasterSequence(axiStreamMasterSeqr, axiStreamMasterSanitySeq, 1, 1);
	// transmit IMG_HEIGHT lines with IMG_WIDTH pixels per line
	repeat(IMG_HEIGHT) begin
		transmitPixels(axiStreamMasterSanitySeq, axiStreamMasterSanitySeq, axiStreamSlaveSanitySeq, axiStreamSlaveSanitySeq);
	end
	//drop valid at end of frame
	startMasterSequence(axiStreamMasterSeqr, axiStreamMasterDropValidSeq, 1'b0, 1'b0, 1'b0,{ParametersPkg::AXI_STREAM_DATA_WIDTH_OUT{1'bz}}, 1'bz, 1'b0);
	lineCount = 0;
endtask : sanity


task VirtualSequence::fullRandom(sofE isSOF = SOF_ENABLE);
	int resetLine;
	bit isReset;
	// randomize if there is reset in this frame
	void'(std::randomize(isReset) with {isReset dist{0:= 8, 1:=2};});
	//randomize the line in which reset will be activated if isReset=1
	void'(std::randomize(resetLine) with {resetLine inside{[1:IMG_HEIGHT-1]};});
	axiStreamMasterVif.clockingBlock.tdata <= getNextData();
	//decide whether to activate SOF or not
	if (isSOF != SOF_DISABLE) begin
		setTuser(axiStreamMasterValidReadyRandomSeq, axiStreamSlaveNormalSeq);	
 	end
 	// transmit IMG_HEIGHT lines with IMG_WIDTH pixels per line
 	repeat (IMG_HEIGHT) begin
		transmitPixels(axiStreamMasterValidReadyRandomSeq, axiStreamMasterValidReadyRandomSeq, axiStreamSlaveNormalSeq, axiStreamSlaveNormalSeq);
		if (isReset && camID == 0) begin
			if (lineCount == resetLine) begin
				resetDUT();
		 		break;
			end
		end
	end
	startMasterSequence(axiStreamMasterSeqr, axiStreamMasterDropValidSeq, 1'b0, 1'b0, 1'b0,{AXI_STREAM_DATA_WIDTH_OUT{1'bz}}, 1'bz, 1'b0);
	lineCount = 0;
endtask



task VirtualSequence::triggerReset();
	fork
		forever @(posedge axiStreamMasterVif.clk) begin
			if (!axiStreamMasterVif.reset)
				resetEvent.trigger();
		end	
	join_none
endtask : triggerReset


task VirtualSequence::resetDUT();
	startMasterSequence(resetSeqr, axiStreamMasterResetSeq, , 0, 0);
	`uvm_info(get_type_name(), "resetting DUT...", UVM_LOW)
		// re-transmit frame, openImageFile() will open the same file for re-transmission
	axiStreamMasterSeqr.stop_sequences();
	axiStreamSlaveSeqr.stop_sequences();
endtask : resetDUT


task VirtualSequence::body();
	int randomDelayBetweenFrames;
	if(!uvm_config_db #(virtual AxiStreamIf#(AXI_STREAM_DATA_WIDTH_OUT))::get(.cntxt(null), .inst_name(""), .field_name($sformatf("axiStreamMasterVif_%0d", camID)), .value(axiStreamMasterVif))) begin
    	`uvm_fatal(get_name(), "NO VIF::interface not found")
  	end
	resetEvent = uvm_event_pool::get_global("resetEvent");
	createSequenceObjects();
	triggerReset();
	configDUT();
	wait(axiStreamMasterVif.reset);
	case (frameBufferOp) 
		USE_TPG : begin
			`uvm_info(get_type_name(), $sformatf("Running operation %0s..", frameBufferOp.name()), UVM_LOW)
			configAndStartTestPatternGenerator();
		end
		RANDOM_AXI_STREAM : begin
			`uvm_info(get_type_name(), $sformatf("Running operation %0s..", frameBufferOp.name()), UVM_LOW)
			repeat(13) begin
				fullRandom();
				void'(std::randomize(randomDelayBetweenFrames) with {randomDelayBetweenFrames inside {[10:100]};});
				repeat(randomDelayBetweenFrames) @(posedge axiStreamMasterVif.clk);
			end
		end
	endcase
	
	
endtask : body



class AxiStreamMasterBaseSequence#(parameter DATA_WIDTH) extends uvm_sequence #(AxiStreamSequenceItem#(DATA_WIDTH));
	
	`uvm_object_param_utils(AxiStreamMasterBaseSequence#(DATA_WIDTH))
	
	//Environment Config
	AxiStreamSequenceItem#(DATA_WIDTH) req;

	
	bit tuser;
	bit tvalid;
	bit tready;
	bit tlast;
	bit reset;
	bit imageFromFile;
	logic[DATA_WIDTH-1:0] tdata;
	
	function new(string name="AxiStreamMasterBaseSequence");
		super.new(name);
		req = AxiStreamSequenceItem#(DATA_WIDTH)::type_id::create("req");
	endfunction

	task body();
		
	endtask
endclass


class AxiStreamMasterBaseSequence#(parameter DATA_WIDTH) extends uvm_sequence #(AxiStreamSequenceItem#(DATA_WIDTH));
	
	`uvm_object_param_utils(AxiStreamMasterBaseSequence#(DATA_WIDTH))
	
	//Environment Config
	AxiStreamSequenceItem#(DATA_WIDTH) req;

	
	bit tuser;
	bit tvalid;
	bit tready;
	bit tlast;
	bit reset;
	bit imageFromFile;
	logic[DATA_WIDTH-1:0] tdata;
	
	function new(string name="AxiStreamMasterBaseSequence");
		super.new(name);
		req = AxiStreamSequenceItem#(DATA_WIDTH)::type_id::create("req");
	endfunction

	task body();
		
	endtask
endclass


class AxiStreamMasterFullRandomSequence#(parameter DATA_WIDTH) extends AxiStreamMasterBaseSequence#(DATA_WIDTH);
	
	`uvm_object_param_utils(AxiStreamMasterFullRandomSequence#(DATA_WIDTH))


	function new(string name="AxiStreamMasterFullRandomSequence");
		super.new(name);
	endfunction
	
	
	task body();
		super.body();
		start_item(req);
		//`uvm_info(get_type_name(), $psprintf("body started"), UVM_DEBUG)
		if (imageFromFile) begin
			req.tdata.rand_mode(0);		
			req.tdata = this.tdata;
		end
		void'(std::randomize(reset) with {reset dist {0:=1, 1:=10000};});

		if(!req.randomize() with {
				req.tvalid dist {1:=99, 0:=1};
				req.tvalidNumOfCyclesDelay inside {[0:2]};
				req.tuser == local::tuser;
				req.tlast == local::tlast;
				req.reset == local::reset;
				(req.reset == 0) -> req.resetNumOfCyclesDelay inside {[50:100]};
			})	`uvm_fatal(get_type_name(), "inline randomization error")
		finish_item(req);
		//`uvm_info(get_type_name(), $psprintf("body finished"), UVM_DEBUG)
	endtask

endclass


class AxiStreamSlaveNormalSequence#(parameter DATA_WIDTH) extends AxiStreamSlaveBaseSequence#(DATA_WIDTH);
	
	`uvm_object_param_utils(AxiStreamSlaveNormalSequence#(DATA_WIDTH))
	
	bit treadySwitch;

	function new(string name="AxiStreamSlaveNormalSequence");
		super.new(name);
	endfunction
	

	task body();
		super.body();
		start_item(req);
		//`uvm_info(get_type_name(), $psprintf("body started"), UVM_DEBUG)
		if (treadySwitch) begin
			req.tready = 1;
		end
		else begin
			// Only tready is interesting here
			if(!(req.randomize() with {
					req.treadyNumOfCyclesDelay inside {[0:2]};
					req.tready dist {1:=95, 0:=5};
				}))	`uvm_fatal(get_type_name(), "inline randomization error")
		end
		treadySwitch = (req.tready == 0) ? 1 : 0;
		finish_item(req);
		
		//`uvm_info(get_type_name(), $psprintf("body finished"), UVM_DEBUG)
	endtask

Although your problem might not be tool specific, debugging it might be. You may need to contact your vendor for guidance. This forum is not for discussion of tool specific usage or problems.

There is nothing in the code shown that indicates an issue. But we don’t have all the code to run and re-create the problem. Also, we would need to see what you are comparing it to. Are there any differences in randomization that could make this appear to be a problem (i.e. the length and size of transactions)?

I don’t think it is tool specific either. specified that merely for completion of details.
What i’m comparing it to is an IP provided by xilinx, generated in Vivado tpg which toggles axi-stream lines instead of me.
I’m attaching the axi-stream driver and monitor code as well.

class AxiStreamSequenceItem#(parameter DATA_WIDTH) extends uvm_sequence_item;

	rand logic reset;
	rand logic tready;
	rand logic tvalid;
	rand logic tuser;
	rand logic tlast;
	rand logic [DATA_WIDTH-1:0] tdata;
	rand int treadyNumOfCyclesDelay;
	rand int tlastNumOfCyclesDelay;
	rand int tuserNumOfCyclesDelay;
	rand int tvalidNumOfCyclesDelay;
	rand int tdataNumOfCyclesDelay;
	rand int resetNumOfCyclesDelay;
	
	
	function new(string name="AxiStreamSequenceItem");
		super.new(name);
	endfunction
	
	
	constraint NumOfCyclesDelayC {
		soft treadyNumOfCyclesDelay == 0;
		soft tlastNumOfCyclesDelay == 0;
		soft tuserNumOfCyclesDelay == 0;
		soft tvalidNumOfCyclesDelay == 0;
		soft tdataNumOfCyclesDelay == 0;
		soft resetNumOfCyclesDelay == 0;
	}
	
	
	constraint ResetC {
		soft reset == 1;
	}
	
	`uvm_object_param_utils_begin(AxiStreamSequenceItem#(DATA_WIDTH))
		`uvm_field_int(tready, UVM_DEFAULT)
		`uvm_field_int(tvalid, UVM_DEFAULT)
		`uvm_field_int(tuser, UVM_DEFAULT)
		`uvm_field_int(reset, UVM_DEFAULT)
		`uvm_field_int(tlast, UVM_DEFAULT)
		`uvm_field_int(tdata, UVM_DEFAULT)
	`uvm_object_utils_end
endclass





class AxiStreamMasterDriver#(parameter DATA_WIDTH) extends uvm_driver#(AxiStreamSequenceItem#(DATA_WIDTH));

	`uvm_component_param_utils(AxiStreamMasterDriver#(DATA_WIDTH))


	//Class Instances
	
	// Class Variables
	bit detectedSOF;
	bit disableEOL;
	bit disableValid;
	bit anotherEOL;
	bit[DATA_WIDTH-1:0] dataFIFO[$];
	int resetNumOfCyclesDelay;
	int lineLength;
	int cameraId;
	uvm_event frameEnded;
	uvm_event anotherEOLEv;
	uvm_event EOLTooLateEv;
	uvm_event EOLTooSoonEv;
	uvm_event noEOLEv;
	
	//Driver Modport Interface
	virtual AxiStreamIf#(DATA_WIDTH) axiStreamMasterDriverVif;

	//Default Constructor
	extern function new(string name="AxiStreamMasterDriver", uvm_component parent);

	// UVM Phase functions/tasks
	extern function void build_phase(uvm_phase phase);
	extern task reset_phase(uvm_phase phase);
	extern task run_phase(uvm_phase phase);


	// Class related functions
	extern task resetDefault();
	extern function void detectSOF();
	extern task driveUser(AxiStreamSequenceItem#(DATA_WIDTH) req);
	extern task updatePixelCounter();
	extern task driveValid(AxiStreamSequenceItem#(DATA_WIDTH) req);
	extern task driveData(AxiStreamSequenceItem#(DATA_WIDTH) req);
	extern task driveLast();

endclass : AxiStreamMasterDriver


function AxiStreamMasterDriver::new(string name="AxiStreamMasterDriver", uvm_component parent);
	super.new(name, parent);
endfunction


function void AxiStreamMasterDriver::build_phase(uvm_phase phase);
	super.build_phase(phase);
endfunction

task AxiStreamMasterDriver::reset_phase(uvm_phase phase);
	phase.raise_objection(this);
	resetDefault();
	@(posedge axiStreamMasterDriverVif.reset);
	phase.drop_objection(this);
endtask



task AxiStreamMasterDriver::run_phase(uvm_phase phase);
	`uvm_info(get_type_name(), $psprintf("run_phase - %m Starting"), UVM_LOW)
	frameEnded = uvm_event_pool::get_global($sformatf("frameEnded_%0d", cameraId));
	anotherEOLEv = uvm_event_pool::get_global($sformatf("anotherEOLEv_%0d", cameraId));
	EOLTooLateEv = uvm_event_pool::get_global($sformatf("EOLTooLateEv_%0d", cameraId));
	EOLTooSoonEv = uvm_event_pool::get_global($sformatf("EOLTooSoonEv_%0d", cameraId));
	noEOLEv = uvm_event_pool::get_global($sformatf("noEOLEv_%0d", cameraId));

	fork
		begin: driverSignalsProc
			forever @(axiStreamMasterDriverVif.clockingBlock) begin
				if(axiStreamMasterDriverVif.reset) begin
					detectSOF();
					seq_item_port.try_next_item(req);
					fork
						driveData(req);
						driveValid(req);
						driveUser(req);
					join
					if (req != null) seq_item_port.item_done(req);	
				end
				else begin
					resetDefault();
				end	
			end
		end
		begin: driveTlastProc
			forever @(axiStreamMasterDriverVif.clockingBlock) begin
				driveLast();
			end
		end
		begin: countPixelsProc
			forever @(axiStreamMasterDriverVif.clockingBlock) begin
				updatePixelCounter();
			end
		end
		begin: waitFrameEndProc
			forever begin
				frameEnded.wait_trigger();
				resetDefault();
			end
		end
		begin: anotherEOLProc
			forever begin
				anotherEOLEv.wait_trigger();
				anotherEOL = 1;
			end
		end
		begin: EOLTooLateProc
			forever begin
				EOLTooLateEv.wait_trigger();
				lineLength = IMG_WIDTH + 32;
			end
		end
		begin: EOLTooSoonProc
			forever begin
				EOLTooSoonEv.wait_trigger();
				lineLength = IMG_WIDTH - 32;
			end
		end
		begin: NoEOL
			forever begin
				noEOLEv.wait_trigger();
				disableEOL = 1;
			end
		end
	join
	
	`uvm_info(get_type_name(), $psprintf("run_phase - %m Finished"), UVM_LOW)
endtask


task AxiStreamMasterDriver::resetDefault();
	`uvm_info(get_type_name(), $psprintf("resetDefault Starting"), UVM_DEBUG)
	axiStreamMasterDriverVif.clockingBlock.tvalid <= 1'b0;
	axiStreamMasterDriverVif.clockingBlock.tuser <= 1'b0;
	axiStreamMasterDriverVif.clockingBlock.tlast <= 1'b0;
	axiStreamMasterDriverVif.clockingBlock.tdata <= 0;
	axiStreamMasterDriverVif.clockingBlock.pixelCounterOut <= 1;
	detectedSOF = 1'b0;
	dataFIFO.delete();
	`uvm_info(get_type_name(), $psprintf("resetDefault Finished"), UVM_DEBUG)
endtask

function void AxiStreamMasterDriver::detectSOF();
	if (axiStreamMasterDriverVif.tuser)
		detectedSOF = 1'b1;
endfunction // sofDetected

task AxiStreamMasterDriver::updatePixelCounter();
	axiStreamMasterDriverVif.clockingBlock.pixelCounterOut <= (axiStreamMasterDriverVif.clockingBlock.tready && axiStreamMasterDriverVif.tvalid && detectedSOF) ? ((axiStreamMasterDriverVif.pixelCounterOut % lineLength == 0) && axiStreamMasterDriverVif.pixelCounterOut != 0) ? 1 : axiStreamMasterDriverVif.pixelCounterOut + 1 : axiStreamMasterDriverVif.pixelCounterOut;
endtask

task AxiStreamMasterDriver::driveLast();
	if (disableEOL) axiStreamMasterDriverVif.clockingBlock.tlast <= 0;
	else if (axiStreamMasterDriverVif.tvalid && axiStreamMasterDriverVif.clockingBlock.tready && detectedSOF) begin
		if (((axiStreamMasterDriverVif.pixelCounterOut % (lineLength-1) == 0) && axiStreamMasterDriverVif.pixelCounterOut != 0) || anotherEOL) begin
			// clean event
			if (anotherEOL) anotherEOL = 0;
			axiStreamMasterDriverVif.clockingBlock.tlast <= 1;
		end
		else
			axiStreamMasterDriverVif.clockingBlock.tlast <= 0;
	end
endtask : driveLast	

task AxiStreamMasterDriver::driveValid(AxiStreamSequenceItem#(DATA_WIDTH) req);
	if (axiStreamMasterDriverVif.tlast && axiStreamMasterDriverVif.clockingBlock.tready && axiStreamMasterDriverVif.tvalid) axiStreamMasterDriverVif.clockingBlock.tvalid <= 0;
	else begin
		if (req != null)
			axiStreamMasterDriverVif.clockingBlock.tvalid <= req.tvalid;
	end
endtask : driveValid


task AxiStreamMasterDriver::driveData(AxiStreamSequenceItem#(DATA_WIDTH) req);
	if (req != null) begin
		if (req.tdata !== {DATA_WIDTH{1'bz}})
			dataFIFO.push_front(req.tdata);
	end
	if (axiStreamMasterDriverVif.tvalid && axiStreamMasterDriverVif.clockingBlock.tready && detectedSOF) begin
		if (dataFIFO.size() != 0)
			axiStreamMasterDriverVif.clockingBlock.tdata <= dataFIFO.pop_back();
	end
endtask : driveData


task AxiStreamMasterDriver::driveUser(AxiStreamSequenceItem#(DATA_WIDTH) req);
	if (!detectedSOF) axiStreamMasterDriverVif.clockingBlock.tuser <= 1'b1;
	else axiStreamMasterDriverVif.clockingBlock.tuser <= (axiStreamMasterDriverVif.tvalid && axiStreamMasterDriverVif.clockingBlock.tready) ? 1'b0 : axiStreamMasterDriverVif.clockingBlock.tuser;
endtask




class AxiStreamSlaveDriver#(parameter DATA_WIDTH) extends uvm_driver#(AxiStreamSequenceItem#(DATA_WIDTH));

	`uvm_component_param_utils(AxiStreamSlaveDriver#(DATA_WIDTH))

	//Class Instances

	//Driver Modport Interface
	virtual interface AxiStreamIf#(DATA_WIDTH) axiStreamSlaveDriverVif;
	bit detectedSOF;
	int cameraId;

	
	//Default Constructor
	extern function new(string name="AxiStreamSlaveDriver", uvm_component parent);

	// UVM Phase functions/tasks
	extern function void build_phase(uvm_phase phase);
	extern task reset_phase(uvm_phase phase);
	extern task run_phase(uvm_phase phase);


	// Class related functions
	extern task resetDefault();
	extern task driveSignals(AxiStreamSequenceItem#(DATA_WIDTH) req);
	extern task updatePixelCounter();
endclass : AxiStreamSlaveDriver

function AxiStreamSlaveDriver::new(string name="AxiStreamSlaveDriver", uvm_component parent);
	super.new(name, parent);
endfunction



function void AxiStreamSlaveDriver::build_phase(uvm_phase phase);
	super.build_phase(phase);
endfunction

task AxiStreamSlaveDriver::reset_phase(uvm_phase phase);
	phase.raise_objection(this);
	
	resetDefault();
	@(posedge axiStreamSlaveDriverVif.reset);
	phase.drop_objection(this);
	
endtask

task AxiStreamSlaveDriver::run_phase(uvm_phase phase);
	`uvm_info(get_type_name(), $psprintf("run_phase - %m Starting"), UVM_LOW)
	fork
		begin
			forever @(axiStreamSlaveDriverVif.clockingBlockSlave) begin
				updatePixelCounter();
			end
		end
		begin
			forever @(axiStreamSlaveDriverVif.clockingBlockSlave) begin
				if(!axiStreamSlaveDriverVif.reset)
					resetDefault();
				else begin
					if (axiStreamSlaveDriverVif.tuser)
						detectedSOF = 1;
					seq_item_port.try_next_item(req);
					if (req != null) begin
						driveSignals(req);
						seq_item_port.item_done(req);
					end
				end
			end
		end
	join
	
	`uvm_info(get_type_name(), $psprintf("run_phase - %m Finished"), UVM_LOW)
endtask

task AxiStreamSlaveDriver::updatePixelCounter();
	axiStreamSlaveDriverVif.clockingBlockSlave.pixelCounterIn <= (axiStreamSlaveDriverVif.tready && axiStreamSlaveDriverVif.clockingBlockSlave.tvalid && detectedSOF) ? (((axiStreamSlaveDriverVif.pixelCounterIn % ParametersPkg::IMG_WIDTH == 0) && axiStreamSlaveDriverVif.pixelCounterIn != 0) ? 1 : axiStreamSlaveDriverVif.pixelCounterIn + 1) : axiStreamSlaveDriverVif.pixelCounterIn;
endtask

task AxiStreamSlaveDriver::resetDefault();
	`uvm_info(get_type_name(), $psprintf("resetDefault Starting"), UVM_DEBUG)
	axiStreamSlaveDriverVif.clockingBlockSlave.tready <= 1'b0;
	axiStreamSlaveDriverVif.clockingBlockSlave.pixelCounterIn <= 1;
	`uvm_info(get_type_name(), $psprintf("resetDefault Finished"), UVM_DEBUG)
endtask


task AxiStreamSlaveDriver::driveSignals(AxiStreamSequenceItem#(DATA_WIDTH) req);
	axiStreamSlaveDriverVif.clockingBlockSlave.tready<=req.tready;
endtask



class AxiStreamMonitor#(parameter DATA_WIDTH_IN, parameter DATA_WIDTH_OUT) extends uvm_monitor;

	`uvm_component_param_utils(AxiStreamMonitor#(DATA_WIDTH_IN, DATA_WIDTH_OUT))

	virtual interface AxiStreamIf#(DATA_WIDTH_OUT) axiStreamMonitorVif;


	AxiStreamSequenceItem#(DATA_WIDTH_OUT) monitorTrans;


	uvm_analysis_port #(AxiStreamSequenceItem#(DATA_WIDTH_OUT)) AxiStreamAnalysisPort;

	//Default Constructor
	extern function new(string name="AxiStreamMonitor", uvm_component parent);

	// UVM Phase functions/tasks
	extern virtual function void build_phase(uvm_phase phase);
	extern task run_phase(uvm_phase phase);
	extern task reset_phase(uvm_phase phase);
	extern task collectMasterSignals();


endclass : AxiStreamMonitor

function AxiStreamMonitor::new(string name="AxiStreamMonitor", uvm_component parent);
	super.new(name,parent);
endfunction


function void AxiStreamMonitor::build_phase(uvm_phase phase);
	AxiStreamAnalysisPort = new("AxiStreamAnalysisPort", this);
	monitorTrans = AxiStreamSequenceItem#(DATA_WIDTH_OUT)::type_id::create("monitorTrans", this);
endfunction


task AxiStreamMonitor::reset_phase(uvm_phase phase);
	phase.raise_objection(this);
	@(posedge axiStreamMonitorVif.reset); 
	phase.drop_objection(this);
endtask



task AxiStreamMonitor::run_phase(uvm_phase phase);
	forever @(negedge axiStreamMonitorVif.clk) begin
		collectMasterSignals();
	end
endtask


task AxiStreamMonitor::collectMasterSignals();
	if (axiStreamMonitorVif.reset) begin
		monitorTrans.tdata=axiStreamMonitorVif.tdata;
		monitorTrans.tvalid=axiStreamMonitorVif.tvalid;
		monitorTrans.tready=axiStreamMonitorVif.tready;
		monitorTrans.tuser=axiStreamMonitorVif.tuser;
		monitorTrans.tlast=axiStreamMonitorVif.tlast;
		AxiStreamAnalysisPort.write(monitorTrans);
	end
endtask

This is too much code to go through on this forum, yet not enough to be able to recreate your issue. At least from my point of view given the time I have to look at it.

1 Like

I appreciate it.