Multiple Inheritance In SystemVerilog

Multiple Inheritance In SystemVerilog

Posted by

I recently discovered that 2012 SystemVerilog standard introduced an extremely awesome feature called Interface Classes.

I’ll try to explain what it does as simple as possible:

In an interface class you can declare what functions you want a class to have.

A class can implement an interface class and when doing that it must provide an implementation for all the functions described in the interface class.

A class can implement as many interface classes as it wants.

If you don’t see yet how powerful this feature is don’t worry. In the example below I will show you how you can use this feature at its full potential.



Interface Class Usage Example

Let’s consider that we have an agent with an architecture as in the image below:

A Typical UVM Agent Architecture

A Typical UVM Agent Architecture


One common behavior that most of the components of an UVM agent must do is handle reset correctly.
Another feature more and more present in our life these days is low power. So some components inside our agent should handle this also.

Usually, the components aware of reset are: monitor, driver and sequencer.
For low power functionality let’s say that only the monitor and the driver must do something.

Low Power And Reset Features In an UVM Agent

Low Power And Reset Features In an UVM Agent

The Old (Bad) Way

A typical implementation for an agent with these requirements would be this one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class cfs_monitor extends uvm_monitor;
  ...
  virtual function void reset();
    ...
  endfunction
 
  virtual function void low_power_begin();
    ...
  endfunction
 
  virtual function void low_power_finish();
    ...
  endfunction
endclass

class cfs_driver extends uvm_driver;
  ...
  virtual function void do_reset();
    ...
  endfunction
 
  virtual function void lp_start();
    ...
  endfunction
 
  virtual function void lp_end();
    ...
  endfunction
endclass

class cfs_sequencer extends uvm_sequencer;
  ...
  virtual function void reset_started();
    ...
  endfunction
endclass

The bad thing about this approach is that the agent code must know precisely what functions are implemented in what components:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class cfs_agent extends uvm_agent;
  ...
  virtual function void handle_reset();
    //agent must know what function for handling reset is implemented in each component
    monitor.reset();
    driver.do_reset();
    sequencer.reset_started();
  endfunction
 
  virtual function void low_power_start();
    //agent must know what function for handling low power start is implemented in each component
    monitor.low_power_begin();
    driver.lp_start();
  endfunction
 
  virtual function void low_power_end();
    //agent must know what function for handling low power end is implemented in each component
    monitor.low_power_finish();
    driver.lp_end();
  endfunction
endclass

This imply that if you realize that the coverage collector should also be aware of low power then you would have to add some functions in the coverage collector component and call them in the agent.
You can run this code on EDAPlayground.

The New (Good) Way

A better approach is to use interface classes to define a common API for the components which must be aware of reset and low power:

1
2
3
4
5
6
7
8
9
10
11
12
13
interface class cfs_reset_handler;
 
  pure virtual function void  handle_reset();
 
endclass

interface class cfs_low_power_handler;
 
  pure virtual function void low_power_start();
 
  pure virtual function void low_power_end();

endclass

Next you must implement the interface classes in the appropriate classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class cfs_monitor extends uvm_monitor implements cfs_reset_handler, cfs_low_power_handler;
  ...
  virtual function void handle_reset();
    ...
  endfunction
 
  virtual function void low_power_start();
    ...
  endfunction
 
  virtual function void low_power_end();
    ...
  endfunction
endclass

class cfs_driver extends uvm_driver implements cfs_reset_handler, cfs_low_power_handler;
  ...
  virtual function void handle_reset();
    ...
  endfunction
 
  virtual function void low_power_start();
    ...
  endfunction
 
  virtual function void low_power_end();
    ...
  endfunction
endclass

class cfs_sequencer extends uvm_sequencer implements cfs_reset_handler;
  ...
  virtual function void handle_reset();
    ...
  endfunction
endclass

Now comes the awesome part!!!
The agent is not directly aware of what component must handle reset or low power.
You just have to try to cast each child to a particular interface class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class cfs_agent extends uvm_agent implements cfs_reset_handler, cfs_low_power_handler;
  ...
  virtual function void handle_reset();
    foreach(m_children[idx]) begin
      cfs_reset_handler reset_handler;
      if($cast(reset_handler, m_children[idx])) begin
        reset_handler.handle_reset();
      end
    end
  endfunction
 
  virtual function void low_power_start();
    foreach(m_children[idx]) begin
      cfs_low_power_handler low_power_handler;
      if($cast(low_power_handler, m_children[idx])) begin
        low_power_handler.low_power_start();
      end
    end
  endfunction
 
  virtual function void low_power_end();
    foreach(m_children[idx]) begin
      cfs_low_power_handler low_power_handler;
      if($cast(low_power_handler, m_children[idx])) begin
        low_power_handler.low_power_end();
      end
    end
  endfunction
endclass

In this way the agent implementation is more abstract and it will automatically take into consideration any new child which implements one of the two interface classes.

You can try out this code on EDAPlayground.

In all fairness I must say that this is not truly multiple inheritance because a class can not inherit members from an interface class or even implemented functions. At most I can say that via an interface class you inherit an API.

One last thing: I tried to run this code on all three major simulators but unfortunately only two worked (is anybody from San Jose reading this?)



Cristian Slav

9 Comments

Leave a Reply

Your email address will not be published.