Last Updated: April 4, 2014
This post will provide a continued explanation on the rest of the verification components.
Subscribers
Functional Coverage
The functional coverage subscriber (jelly_bean_fc_sucbscriber
) identifies the generated jelly beans to take a total tally. The jelly_bean_transaction
sent from the monitor is sampled by the write
function on the line 21, and takes the cross coverage of the flavor, color, and other characteristics of the jelly bean.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class jelly_bean_fc_subscriber extends uvm_subscriber#(jelly_bean_transaction); `uvm_component_utils(jelly_bean_fc_subscriber) jelly_bean_transaction jb_tx; covergroup jelly_bean_cg; flavor_cp: coverpoint jb_tx.flavor; color_cp: coverpoint jb_tx.color; sugar_free_cp: coverpoint jb_tx.sugar_free; sour_cp: coverpoint jb_tx.sour; cross flavor_cp, color_cp, sugar_free_cp, sour_cp; endgroup: jelly_bean_cg function new(string name, uvm_component parent); super.new(name, parent); jelly_bean_cg = new; endfunction: new function void write(jelly_bean_transaction t); jb_tx = t; jelly_bean_cg.sample(); endfunction: writeendclass: jelly_bean_fc_subscriber |
Scoreboard
In the functional coverage subscriber, the jelly_bean_transaction
was sampled in the write
function. Similar to the functional coverage subscriber, focus on the write
function is the key. The scoreboard subscriber uses the write
function to call the check_jelly_bean_taste
function in the parent component (jelly_bean_scoreboard
). This check_jelly_bean_taste
function compares the DUT response against the expected response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | typedef class jelly_bean_scoreboard; class jelly_bean_sb_subscriber extends uvm_subscriber#(jelly_bean_transaction); `uvm_component_utils(jelly_bean_sb_subscriber) function new(string name, uvm_component parent); super.new(name, parent); endfunction: new function void write(jelly_bean_transaction t); jelly_bean_scoreboard jb_sb; $cast( jb_sb, m_parent ); jb_sb.check_jelly_bean_taste(t); endfunction: writeendclass: jelly_bean_sb_subscriber |
The check_jelly_bean_taste
function expects the DUT module to “respond negatively to the sour chocolate-flavor jelly bean, while reacting positively to the other combinations.” When the DUT responds properly, the jelly-bean flavor and color are printed. When the DUT is not functioning correctly, the function will print an error message.
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 37 38 39 40 41 42 | class jelly_bean_scoreboard extends uvm_scoreboard; `uvm_component_utils(jelly_bean_scoreboard) uvm_analysis_export#(jelly_bean_transaction) jb_analysis_export; local jelly_bean_sb_subscriber jb_sb_sub; function new(string name, uvm_component parent); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); super.build_phase(phase); jb_analysis_export = new( .name("jb_analysis_export"), .parent(this)); jb_sb_sub = jelly_bean_sb_subscriber::type_id::create(.name("jb_sb_sub"), .parent(this)); endfunction: build_phase function void connect_phase(uvm_phase phase); super.connect_phase(phase); jb_analysis_export.connect(jb_sb_sub.analysis_export); endfunction: connect_phase virtual function void check_jelly_bean_taste(jelly_bean_transaction jb_tx); uvm_table_printer p = new; if (jb_tx.flavor == jelly_bean_transaction::CHOCOLATE && jb_tx.sour) begin if (jb_tx.taste == jelly_bean_transaction::YUCKY) begin `uvm_info("jelly_bean_scoreboard", { "You have a good sense of taste.\n", jb_tx.sprint(p) }, UVM_LOW); end else begin `uvm_error("jelly_bean_scoreboard", { "You lost sense of taste!\n", jb_tx.sprint(p) }); end end else begin if (jb_tx.taste == jelly_bean_transaction::YUMMY) begin `uvm_info("jelly_bean_scoreboard", { "You have a good sense of taste.\n", jb_tx.sprint(p) }, UVM_LOW); end else begin `uvm_error("jelly_bean_scoreboard", { "You lost sense of taste!\n", jb_tx.sprint(p) }); end end endfunction: check_jelly_bean_tasteendclass: jelly_bean_scoreboard |
Many consider it a hassle to create a separate scoreboard class. In our case, it may be more straightforward to check expected response in the jelly_bean_sb_subscriber
, because the expected response is created from the inside. Yet, there are times when two analysis ports are necessary, one for expected data and the other for actual data. The write
function of a subscriber does not support multiple analysis ports. One solution to this problem is to develop a scoreboard class with two subscribers. Thinking about the extendability in the future, creating two layers like our scoreboard might be a good idea.
Environment
To provide a conclusion, this section will explain the verification environment that contains all the verification components. Simply stated, the environment connects the previously explained agent and the subscribers. Taking a look at the first post of the series will help better understand this concept.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class jelly_bean_env extends uvm_env; `uvm_component_utils(jelly_bean_env) jelly_bean_agent jb_agent; jelly_bean_fc_subscriber jb_fc_sub; jelly_bean_scoreboard jb_sb; function new(string name, uvm_component parent); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); super.build_phase(phase); jb_agent = jelly_bean_agent::type_id::create(.name("jb_agent"), .parent(this)); jb_fc_sub = jelly_bean_fc_subscriber::type_id::create(.name("jb_fc_sub"), .parent(this)); jb_sb = jelly_bean_scoreboard::type_id::create(.name("jb_sb"), .parent(this)); endfunction: build_phase function void connect_phase(uvm_phase phase); super.connect_phase(phase); jb_agent.jb_ap.connect(jb_fc_sub.analysis_export); jb_agent.jb_ap.connect(jb_sb.jb_analysis_export); endfunction: connect_phaseendclass: jelly_bean_env |
The next post will show the anticipated test using these components.
There are a few points I am confused on here.
What is the need for the scoreboard subscriber? You don’t create a handle to it in the env, the scoreboard already has an analysis export…..
Is it because a scoreboard class doesn’t have a built in write() method?
Also in the fc subscriber you don’t create a handle to an analysis export, nor do you reference it in the connect and build phases (the same goes for the scoreboard subscriber) is that because these are extended uvm_subscribers and have this analysis export by default ( called analysis_export)? I.e from the uvm base class
Thanks
Steve
The
jelly_bean_scoreboard
instantiates the localjelly_bean_sb_subscriber
. For this tutorial, thejelly_bean_scoreboard
class is not indispensable. I could have used thejelly_bean_sb_subscriber
only and moved thecheck_jelly_bean_taste
function from thejelly_bean_scoreboard
to thejelly_bean_sb_subscriber
. As you mentioned, the reason I had a subscriber was I wanted thewrite
method in the scoreboard. I also wanted expandability of the scoreboard so that I could add another subscriber in case I needed the secondwrite
. Another approach to have the secondwrite
would be using`uvm_analysis_imp_decl
macro.Regarding the
analysis_export
, theuvm_subscriber
class (the base class of the fc and sb subscribers) has the analysis export calledanalysis_export
.a small correction to the last line … uvm_subscriber class has analysis import called analysis export.
uvm_analysis_imp #(T, class_name) analysis_export.
Hi Keisuke,
Can you please add some sort comments whereever required in the piece of code you provide so that it is easy to grab the content.
Also, can you give me a brief idea why we reuiqre a subscriber ? or waht is its significance ?
Is it a gateway between the components in agent and outside ??
Thanks in Advance..!
-surya
A subscriber is a component typically used with a monitor. It “subscribes” the transactions the monitor sends via an
analysis_port
. Every time a transaction is sent by the monitor, thewrite
function of the subscriber is executed. You can use thewrite
function to collect functional coverage or check the validity of the transaction, for example.Hi Keisuke,
Can you please explain, why are you casting with m_parent at line no 13 in jelly_bean_sb_subscriber and also could you please explain the significance of m_parent there.
Thanks
Dheeraj
Each
uvm_component
has a property calledm_parent
, which points to the parent component that created the component. In this example, them_parent
ofjelly_bean_sb_subscriber
points to thejelly_bean_scoreboard
. Please see the line 14 ofjelly_bean_scoreboard
.The
$cast
is required because the type ofm_parent
isuvm_component
, which does not know anything about thecheck_jelly_bean_taste
function.Hello Keisuke,
In the scoreboard class uvm analysis export object is declared “uvm_analysis_export#(jelly_bean_transaction) jb_analysis_export” . Why cannot it be a uvm_analysis_imp type object since “imp” class serves as termination for the analysis port.
If you look at the Verification Components figure in Overview, you will find the
jelly_bean_sb_subscriber
serves as the termination point, not thejelly_bean_scoreboard
. That’s why the scoreboard uses auvm_analysis_export
instead of auvm_analysis_imp
.Hey Keisuke,
my question is regarding the $cast.
in the write function of jelly_bean_sb_subscriber, the jelly_bean_scoreboard is already defined.
hence the jb_sb would be aware of check_jelly_bean_taste task. then why is the cast needed.
plus when a castis done as $cast(jb_sb,m_parent). the m_parent which point to component class,will start pointing to a extended class which would be a error ,right ?
Also, thanks for the brilliant blog, its very useful. Thanks.
–Vin
The
jb_sb
is declared as thejelly_bean_scoreboard
type on the line 11, but the value ofjb_sb
isnull
because we did not assign any value yet. On the line 13, we attempted to assign the value ofjb_sb
to bem_parent
so thatjb_sb
(object handle) points to them_parent
object. Since the type ofm_parent
isuvm_component
, notjelly_bean_scorebord
, we needed to use the$cast
. This casting won’t cause any errors as long as them_parent
is a handle to ajelly_bean_scoreboard
object.Hi keisuke,
I have one small doubt, In jelly_bean_fc_subscriber we are having handle jb_tx of type jelly_bean_transaction, So why we are not using create/new method to that handle.
The
jb_tx
is an object handle that points to the same object passed by thewrite
function (see the line 20 of thejelly_bean_fc_subscriber
). Since we do not create a new object, we call neithernew
norcreate
.Hi Keisuke,
Could you please comment on the error around ‘uvm_subscriber’ shown in http://www.edaplayground.com/x/5VX ?
It seems the link is broken. Can you check?
I am not sure if Sureshkumar meant this link:
http://www.edaplayground.com/x/EVA
I somehow remembered only the uvm_analysis_imp can provide the write method, but looks here the subscriber’s analysis_export is hooked up to the scoreboard. Could you please explain why the write method is used with analysis_export?
Another thing I’m not clear is that in subscriber, the scoreboard is declared in “write” function, in scoreboard, the subscriber is declared as local and further created in the build_phase. Is there any problem with the double referencing to each other?
Thanks in advance!
analysis_export
of theuvm_subscriber
is actuallyuvm_analysis_imp
.jelly_bean_sb_subscriber
and thejelly_bean_scoreboard
each need a handle to the other. Thetypedef
(the first line) of thejelly_bean_sb_subscriber
provides a forward declaration for thejelly_bean_scoreboard
. Thetypedef
lets the compiler know the actual class definition of thejelly_bean_scoreboard
will follow.I have a confusion. I cannot see anywhere the write function of scoreboard_subscriber being called, like the functional coverage subscriber write was called in monitor. Then how is that write implemented?
The
jb_ap.write(jb_tx)
on the line 31 of thejelly_bean_monitor
class (see Agent) executes everywrite()
function connected to thejb_ap
. In other words, the line 31 executes thewrite()
function of thejelly_bean_sb_subscriber
as well as thewrite()
function of thejelly_bean_fc_subscriber
.Hey Kiesuke,
I have the same question as Ella, the scoreboard is declared in “write” function, in scoreboard, the subscriber is declared as local and further created in the build_phase. Is there any problem with the double referencing to each other?
Can you be more specific about the answer you gave to ella.
Thanks.
typedef class jelly_bean_scoreboard
declaresjelly_bean_scoreboard
is to be of typeclass
. This allows compiler to compilejelly_bean_sb_subscriber
when it encountersjelly_bean_scoreboard
in thewrite
function even though it is not defined yet.When having a scoreboard with a prediction port and a measurement port that are not generating transactions at the same rate, how would you handle that?
This is actually a typical use case for an ADC where the rate of input signals is faster than the sampling rate of the ADC.
I would use a queue or a FIFO to store the faster transactions.
Hi Keisuke,
Thanks for the nice blog. I have one question.
Let us say, in jelly_bean_scoreboard, if we have overridden any function from uvm_scoreboard. In this case, we should be able to access that overridden function in sb_subscriber just by using m_parent without casting right?
The type of
m_parent
isuvm_component
. As long as you access the function ofuvm_component
, you don’t need a cast. Otherwise you need a cast becauseuvm_component
doesn’t know the function.