Welcome ! This website will help YOU (recent graduates/professionals) learn verification languages like SystemVerilog and UVM. Register for free and access more content !
3 minutes reading time (687 words)

Remove redundant register sequences with this neat trick

Remove redundant register sequences with this neat trick

I was sipping green tea sitting in front of my desk trying to figure a way to avoid having to write redundant sequences and register model method calls. That's when I got this idea to check upon existing methods in the UVM register layer. Well, good that I did ! I saved quite a lot of time writing sequences by the effective use of uvm_reg_block and uvm_reg methods.

To give you a bit of a background on what I am talking about here, I had this design which had multiple register blocks with the same set of registers within each block that had to be written with random values.

The problem

I would normally write a sequence to program each flower which would look something like what's below.

// Defines for path to register model
`define RM_DAISY_A001   reg_model.m_daisy_reg_block.m_daisy_Main_CfgGen_A001
`define RM_DAISY_B001   reg_model.m_daisy_reg_block.m_daisy_Main_CfgGen_B001
`define RM_LILLY_A001   reg_model.m_daisy_reg_block.m_daisy_Main_CfgGen_A001
`define RM_TULIP     reg_model.m_tulip_reg_block
class m_daisy_seq extends uvm_sequence;
  task body ();
    `RM_DAISY_A001.write (status, value);
    `RM_DAISY_B001.write (status, value);
class m_lilly_seq extends uvm_sequence;
  task body ();
    `RM_LILLY.randomize ();
    `RM_LILLY.update (status);
class m_tulip_seq extends uvm_sequence;
  task body ();
    `RM_TULIP_A001.set (value);
    `RM_TULIP_B001.set (value);

But this would require quite a lot of code to be written for each flower, and all these sequences do the same functionality with the same set of values to be written to the same set of registers within multiple register blocks.

The solution

As far as readability goes, this is a good way but little difficult to scale if the number of flowers change. Instead we can use some really useful methods within uvm_reg_block class to make our code really concise.

First I created a generic sequence that will accept the flower name and it's register block so that you can write configurations into that particular flower. Because we are using a parent class handle of type uvm_reg_block to access any m_*_reg_block, we will not be able to reference its registers directly using . operator. So we need to loop through the available registers within the block and select the one we require. Luckily there is a standard method called get_reg_by_name() inside uvm_reg class that will return the handle to the register if we provide it with a name. I have done this in my custom function set_value_for_reg. After all the register configurations are done, I can call update() to update the design with new values all in one go.

// The main sequence to configure registers - replaces all the m_*_seq we saw above
class gen_seq extends uvm_sequence;
  string      flowerName;
  uvm_reg_block    tmp_blk;
  virtual function void set_value_for_reg (uvm_reg my_reg, string name, int val);
    uvm_reg tmp = tmp_blk.get_reg_by_name (name);
    tmp.set (val);
  virtual function void set_reference (uvm_reg_block tmp_blk, string name);
    this.tmp_blk = tmp_blk;
    this.flowerName = name;
  task body ();
    uvm_reg   tmp_reg;
    set_value_for_reg ({flowerName, "_Main_CfgGen_A001"}, val);
    set_value_for_reg ({flowerName, "_Main_CfgGen_B001"}, val);
    tmp_blk.update (status);

Now that my generic sequence is ready, I need to invoke it from another sequence or a virtual sequence. We have to provide a register block and name before this sequence is started with the start() method which is done using a custom function set_reference(). In this example a string array of flowers is created and looped through.

// Virtual sequencer where you can start gen_seq for a particular flower

class virtual_seq extends uvm_env;
	string 	flower [4];
	task body();
		foreach (flower[i]) begin
			gen_seq   m_gen_seq = gen_seq::type_id::create ({flower[i], "_seq"});
			uvm_reg_block tmp_blk = getRegBlockForFlower (name);
			m_gen_seq.set_reference (tmp, name);
			m_gen_seq.start (p_sequencer);

The final step is to provide a definition for the custom function getRegBlockForFlower() which should return the correct reference to the register block for a particular flower.

// Function to return the correct register block for a particular name

function uvm_reg_block getRegBlockForFlower (string name);
	if (! uvm_config_db #(reg_model_class)::get (null, "uvm_test_top", "reg_model", reg_model))
		`uvm_fatal ("FATAL", "OOPS ! Did not get a register model")
	case (name)
		"daisy" 	: return `RM_DAISY;
		"tulip" 	: return `RM_TULIP;
		"lilly" 	: return `RM_LILLY;

Feel free to comment below and maybe share how you might have used something similar !

that you have to reset your register model ?
how to create a singleton object

Comments 1

Nayan Naware on Monday, 24 July 2017 01:14

Can you please include the basics of RAL and its implementation. So that one who is starting with RAL can understand it more clearly.

Can you please include the basics of RAL and its implementation. So that one who is starting with RAL can understand it more clearly.
Already Registered? Login Here
Monday, 18 June 2018

We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. You consent to our cookies if you continue to use our website. To find out more about the cookies we use and how to delete them, see our privacy policy.

  I accept cookies from this site.
EU Cookie Directive plugin by www.channeldigital.co.uk