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.
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: write
endclass: 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.
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: write
endclass: 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.
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_taste
endclass: 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.
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_phase
endclass: jelly_bean_env
The next post will show the anticipated test using these components.