Example uvm testbench for a simple rtl such as register slice

Hi,

I was looking for an example UVM testbench for simple RTL such as register slice.
I think someone should have already coded something for it.
The RTL module ports would look like below:

module register_slice ( s_data_in, s_valid_in, s_ready_out, m_data_out, m_valid_out, m_ready_in);

parameter WIDTH = 64;

input [WIDTH-1:0] s_data_in;
input s_valid_in;
output s_ready_out;
output [WIDTH-1:0] m_data_out;
output m_valid_out;
input m_ready_in;
. . .

endmodule

In reply to davidct:

It’s a simple AXI type of interface with handshake signals “valid” and “ready”.
Hope someone has good links to example uvm or systemverilog testbenches for download.

In reply to davidct:

You could use some script or a full-fledged tool to generate skeleton code. We have a tool named DVC_UVM (DVCreate - UVM) at www.verifworks.com - I will be happy to send you a sample generated code for this design offline (As I don’t find an easy way to upload a tar ball here in this forum). Contact me via email srini <> cvcblr.com

Regards
Srini

In reply to Srini @ CVCblr.com:

The code that Srini provided is at
http://SystemVerilog.us/fv/reg_slice.tgz

Many thanks Srini!
ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr

In reply to ben@SystemVerilog.us:

Thanks for providing the uvm skeleton testbench !!

Ben,
I bought your book “Systemverilog Assertions Handbook”, 4th Edition
and will start reading it next week.

David

In reply to davidct:

In reply to ben@SystemVerilog.us:
Ben,
I bought your book “Systemverilog Assertions Handbook”, 4th Edition
and will start reading it next week.
David

Thanks, I hope that you like the book; it’s the collaboration of 3 other engineers, each of us with real design and verification experience in large companies (me Raytheon, Srini Intel, Synopsis and now his own training and consulting company, Lisa Cadence; Ajeetha independent work and Entrepreneur). We were also inspired by user experiences and difficulties expressed in forums like this one, and translated those experiences into book examples/models.
Again, thanks and I hope you enjoy the book.

I strongly recommend that you read See PAPER: Understanding the SVA Engine + Simple alternate solutions - SystemVerilog - Verification Academy
Abstract: Understanding the engine behind SVA provides not only a better appreciation and limitations of SVA, but in some situations provide features that cannot be simply implemented with the current definition of SVA. This paper first explains, by example, how a relatively simple assertion example can be written without SVA with the use of SystemVerilog tasks; this provides the basis for understanding the concepts of multithreading and exit of threads upon a condition, such as an error in the assertion. The paper then provides examples that uses computational variables within threads; those variables can cause, in some cases, errors in SVA. The strictly emulation model with tasks solves this issue.
Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr

  • SVA Handbook 4th Edition, 2016 ISBN 978-1518681448
  • A Pragmatic Approach to VMM Adoption 2006 ISBN 0-9705394-9-5
  • Using PSL/SUGAR for Formal and Dynamic Verification 2nd Edition, 2004, ISBN 0-9705394-6-0
  • Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn 978-1539769712
  • Component Design by Example ", 2001 ISBN 0-9705394-0-1
  • VHDL Coding Styles and Methodologies, 2nd Edition, 1999 ISBN 0-7923-8474-1
  • VHDL Answers to Frequently Asked Questions, 2nd Edition

In reply to davidct:

Hi Ben,

I got the testbench and RTL compile.

Now there is nothing toggling because the

seq_tests/reg_slice_rand_seq.sv

has nothing being exercised except for uvm_info

task reg_slice_rand_seq::body();
`uvm_info(get_name(),$sformatf(“:Sequence is Running …”),UVM_MEDIUM)

`uvm_info(get_name(),$sformatf(“:Sequence is Complete …”),UVM_MEDIUM)
endtask : body

Need a simple example and I’ll do some research.

David

In reply to davidct:

Did you fill in your driver logic? It is your design so you need to fill the BFM part. Once done, we can take the next step.

Srini

In reply to Srini @ CVCblr.com:

Hi Srini,

I see the tb_src/reg_slice_driver.sv

and the messages that get output to the log file from the code

UVM_INFO …/tb_src/reg_slice_scoreboard.sv(24) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_scoreboard_0 [reg_slice_scoreboard_0] Start of Run phase …
UVM_INFO …/tb_src/reg_slice_output_monitor.sv(27) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_output_monitor_0 [reg_slice_output_monitor_0] Run Phase is Running …
UVM_INFO …/tb_src/reg_slice_input_monitor.sv(27) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_input_monitor_0 [reg_slice_input_monitor_0] Run Phase is Running …
UVM_INFO …/tb_src/reg_slice_driver.sv(20) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_driver_0 [reg_slice_driver_0] Start of Reset Phase …
UVM_INFO …/tb_src/reg_slice_driver.sv(24) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_driver_0 [reg_slice_driver_0] End of Reset Phase …
UVM_INFO …/seq_tests/reg_slice_rand_test.sv(19) @ 0: uvm_test_top [uvm_test_top] Test is running…
UVM_INFO …/tb_src/reg_slice_driver.sv(28) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_driver_0 [reg_slice_driver_0] Start of Main Phase …
UVM_INFO …/seq_tests/reg_slice_rand_seq.sv(15) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0@@reg_slice_rand_seq_0 [reg_slice_rand_seq_0] :Sequence is Running …
UVM_INFO …/seq_tests/reg_slice_rand_seq.sv(18) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0@@reg_slice_rand_seq_0 [reg_slice_rand_seq_0] :Sequence is Complete …
UVM_INFO …/seq_tests/reg_slice_rand_test.sv(24) @ 0: uvm_test_top [uvm_test_top] End of main phase in test

So now I need to create the BFM to drive “reg_slice_if”.
Let me do some reading and understanding since UVM is still new to me.

David

In reply to davidct:
It looks to me that your issue is that the model that Srini provided is more of a template, and the body of that template needs to be complete.


// The body of that 
import reg_slice_pkg::*;
class reg_slice_xactn  extends uvm_sequence_item;   
  `uvm_object_utils_begin(reg_slice_xactn)   
  `uvm_object_utils_end
  extern function new(string name="reg_slice_xactn");
endclass : reg_slice_xactn 
// The body of that external function needs to be filled
function reg_slice_xactn::new(string name="reg_slice_xactn");
  super.new(name);
endfunction : new

Below is an example of a driver I did a few years ago for a loadable counter.
If I were to redo this, I would use the current Srini’s guidelines.
Again, this is an old model, but it may guide you in the right directions.


`ifndef COUNTER_DRIVER
`define COUNTER_DRIVER
//  /UVM_counter_with_resp0/tb_src/counter_driver.sv
class counter_driver extends uvm_driver #(counter_xactn, counter_xactn);
	string tID;
	virtual interface counter_if.drvr_if_mp vif;
	//counter_xactn req; is already in uvm_driver 
	counter_xactn item_copy; // for debug
	bit[3:0] ct; // used as a test case in the response

	function new(string name, uvm_component parent);
		super.new(name,parent);
		enable_stop_interrupt = 1;
		tID=get_type_name();
		tID=tID.toupper();
		// item_copy=new();
		item_copy=counter_xactn::type_id::create("item_copy", this);	
	endfunction : new

	`uvm_component_utils_begin(counter_driver)
	`uvm_field_object(req, UVM_ALL_ON)
	`uvm_component_utils_end
	
	task get_and_drive();
		counter_xactn t;  // to hold gotten item as a copy, keeping original pristine
		// rsp=new(); 
		rsp=counter_xactn::type_id::create("rsp", this); // not needed in this case
		forever
		begin
			//wait(vif.reset==0);  //block until reset released
			seq_item_port.get_next_item(req); // New item at every call, cannot view this
			$cast(t, req);
			$display("--****************--"); 
			send_to_dut(t);
			rsp.set_id_info(req);   // Copies the sequence_id and transaction_id 
			// from the referenced item (req) into the calling item (rsp)  
			rsp.data = ct+1'b1; //   
			ct++; 
			seq_item_port.put_response(rsp);
			seq_item_port.item_done();
		end
	endtask : get_and_drive
    
	// copy elements of item into item_copy
	function void copy_items(counter_xactn dest, counter_xactn src);
		dest.kind=src.kind;
		dest.data=src.data;
		dest.ld=src.ld; 
		dest.rst_n=src.rst_n;
		dest.reset_cycles=src.reset_cycles; 
		dest.idle_cycles=src.idle_cycles;
	endfunction : copy_items
     
	task send_to_dut(input counter_xactn item);
		uvm_report_info(tID,$psprintf("%s : item sent is %0s",tID,item.sprint()),UVM_MEDIUM);
		copy_items(item_copy, item); // Do this for viewing in waveform view
		this.vif.driver_cb.kind_cp<=item.kind; // put into interface for debug 
		case(item.kind)
			CT_LOAD : begin 
				this.load_task(item.data); 
			end
			CT_RESET : begin 
				this.reset_task(1, item); 
			end 
			CT_WAIT : begin 
				this.idle_task(item.data); 
			end
			CT_DONE : begin 
				this.done_task(item); 
			end 
		endcase 
	endtask : send_to_dut

	task run();
		fork
			begin
				// uvm_default_printer = uvm_default_line_printer;  
				// uvm_default_printer=new(); // << error 
				uvm_report_info(tID,$psprintf(" %s : running",tID),UVM_MEDIUM);
			end
			begin
				//reset_dut(); //fill in "reset_dut()" if needed
				get_and_drive();
			end
		join	
	endtask : run

	virtual function void report();
		//fill in any reporting code if needed
		logic dummy;
	endfunction : report
  
	task load_task(int data);
		this.vif.driver_cb.data_in <= data;
		this.vif.driver_cb.rst_n <= 1'b1;
		this.vif.driver_cb.ld <= 1'b1; 
		@(this.vif.driver_cb)this.vif.driver_cb.ld <= 1'b0; 
        
	endtask : load_task
    
	// reset
	task reset_task(int r,counter_xactn req);
		automatic logic[3:0] v;
		this.vif.driver_cb.ld <= 1'b0; 
		// Line below not working in NC
		// if (!randomize(v)) `uvm_error("MYERR", "This is a randomize error");
		// ap_rand01: assert(randomize(v)); 
		// this.vif.driver_cb.data_in <= v;  //  for random numbers in data_in
		this.vif.driver_cb.data_in <= req.data;
		repeat(r) this.vif.driver_cb.rst_n <= 1'b0; 
		// @(this.vif.driver_cb); 
		@(this.vif.driver_cb)this.vif.driver_cb.rst_n <= 1'b1;
		// @(this.vif.driver_cb); 
	endtask : reset_task
    
	// IDLE
	task idle_task(int data);// for now, make idle for 4 cycles 
		logic[3:0] v=data; 
		this.vif.driver_cb.rst_n <= 1'b1;
		this.vif.driver_cb.ld <= 1'b0;
		this.vif.driver_cb.data_in <= data;
		@(this.vif.driver_cb); 
        
		//        for (int i=0; i<1; i++) begin
		//            this.vif.driver_cb.ld <= 1'b0; 
		//            ap_rand01: assert(randomize(v)); 
		//            this.vif.driver_cb.data_in <= v;
		//            @(this.vif.driver_cb); 
		//        end
	endtask : idle_task
    
	// DONE, for now, a do nothing 
	task done_task(counter_xactn req);
		this.vif.driver_cb.data_in <= req.data;
		this.vif.driver_cb.rst_n <= 1'b1;
		this.vif.driver_cb.ld <= 1'b0; 
		@(this.vif.driver_cb); 
        
	endtask : done_task
  
endclass : counter_driver 
`endif 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to ben@SystemVerilog.us:

Thanks Ben for pointing out the file

tb_src/reg_slice_xactn.svh

and some example driver code.

To start with understanding BFM driver,
I’m reading this website that shows 4 use models of a driver
and some simple UVM driver code.

http://www.learnuvmverification.com/index.php/2015/10/03/uvm-driver-use-models-part-2/

In reply to davidct:

Hi Srini,

If I put simple uvm code in

tb_src/reg_slice_xactn.sv

to check that it is executing something, nothing is echoed out to the display

function reg_slice_xactn::new(string name=“reg_slice_xactn”);
super.new(name);

`uvm_info(get_name(),$sformatf(“reg_slice_xactn is Running …”),UVM_MEDIUM)

endfunction : new

Is this function reg_slice_xactn even working ?

In the links above, the author uses

task body; // in class extended from uvm_sequence
. . .

but you use “function”.

I’m confused about this.

Need some explanation
on why do you want me to modify “function reg_slice_xactn” (reg_slice_xactn.sv) versus
the other author who modifies “task body;” in the class extended from uvm_sequence ?

Thanks,

David

In reply to davidct:

FYI, I put “task pre_body” and “task post_body” in seq_tests/reg_slice_rand_seq.sv

task pre_body();
uvm_report_info(get_full_name(),“pre_body() callback”, UVM_MEDIUM);
endtask: pre_body
task post_body();
uvm_report_info(get_full_name(),“post_body() callback”, UVM_MEDIUM);
endtask: post_body

and I can see the uvm report display the text :

UVM_INFO …/tb_src/reg_slice_scoreboard.sv(24) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_scoreboard_0 [reg_slice_scoreboard_0] Start of Run phase …
UVM_INFO …/tb_src/reg_slice_output_monitor.sv(27) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_output_monitor_0 [reg_slice_output_monitor_0] Run Phase is Running …
UVM_INFO …/tb_src/reg_slice_input_monitor.sv(27) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_input_monitor_0 [reg_slice_input_monitor_0] Run Phase is Running …
UVM_INFO …/tb_src/reg_slice_driver.sv(30) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_driver_0 [reg_slice_driver_0] Start of Reset Phase …
UVM_INFO …/tb_src/reg_slice_driver.sv(34) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_driver_0 [reg_slice_driver_0] End of Reset Phase …
UVM_INFO …/seq_tests/reg_slice_rand_test.sv(19) @ 0: uvm_test_top [uvm_test_top] Test is running…
UVM_INFO …/tb_src/reg_slice_driver.sv(38) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_driver_0 [reg_slice_driver_0] Start of Main Phase …
UVM_INFO @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0@@reg_slice_rand_seq_0 [uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0.reg_slice_rand_seq_0] pre_body() callback
UVM_INFO …/seq_tests/reg_slice_rand_seq.sv(41) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0@@reg_slice_rand_seq_0 [reg_slice_rand_seq_0] :Sequence is Running …
UVM_INFO …/seq_tests/reg_slice_rand_seq.sv(44) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0@@reg_slice_rand_seq_0 [reg_slice_rand_seq_0] :Sequence is Complete …
UVM_INFO @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0@@reg_slice_rand_seq_0 [uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_sequencer_0.reg_slice_rand_seq_0] post_body() callback
UVM_INFO …/seq_tests/reg_slice_rand_test.sv(24) @ 0: uvm_test_top [uvm_test_top] End of main phase in test
UVM_INFO …/tb_src/reg_slice_fcov.sv(36) @ 0: uvm_test_top.reg_slice_env_0.reg_slice_agent_0.reg_slice_fcov_0 [reg_slice_fcov_0] Test achieved functional coverage: 0.00%

In reply to davidct:

David, pleasee believe me. It is useless what you are doing. This way you’ll never understand the UVM.
My recommendation is to start with an education step. The Verification Academy is offering great material. See here
https://verificationacademy.com/courses/introduction-to-the-uvm and
Basic UVM | Universal Verification Methodology | Verification Academy

You can use the code template to experience your Knowledge.

In reply to chr_sue:

Thanks for the tips.
I watching the UVM videos now.
I’m hoping Srini or Ben can reply to my question to clarify my confusion.

David