If you feel doing repetitive coding is a boring task, then this blog is for you! UVM provides many inbuilt features which can be easily plugged in to our testbench with little modification. So, we can reduce our coding time and achieve our goal of verification. In this post, we will see how the UVM is useful for building a scoreboard quickly.
Generally, scoreboard has a function for creating analysis ports (expected transaction and actual transaction) which is connected with transmitter's analysis port and receiver's analysis port, a function which converts a transaction class into another transaction class, FIFOs for storing transactions and methods for getting transaction and compare them. In most of the projects, we are using the same kind of scoreboard structure and mostly transaction conversion method differs from project to project.
UVM provides all these features in "uvm_algorithmic_comparator" class and you can easily plug-n-play the scoreboard component in your environment. Just, you need to concentrate on writing a method which translates a transaction class into another type of transaction class. So, you can easily save your time in terms of coding and compiling the scoreboard code.
Below is the example of "uvm_algorithmic_comparator".
Step (1): Create a transformer class and overwrite "transform" method which converts an input transaction class into another type of (output) transaction class.
In this example, "m_transformer" class is created and "a_item" transaction class is converted into "b_item" transaction using "transform" method in it.
function b_item transform(a_item a_i);
b_i = new("b_i");
b_i.b = a_i.a;
b_i.bb = a_i.aa;
endclass : m_transformer
Step (2): Instantiate the transformer class into "environment" class along with other agents in "uvm_algorithmic_comparator" class.
"uvm_algorithmic_comparator" has three parameters:
BEFORE: A transaction class which needs to be converted
AFTER: A transaction class which needs to be compared
TRANSFORMER: A component which contains "transform" method
Note that, you must have to implement "convert2string" and "do_compare" method in ~AFTER~ transaction class.
Step (3): Connect analysis port having ~BEFORE~ transaction class with "before_export" port of algorithmic comparator and analysis port having ~AFTER~ transaction class with "after_export" port.
// Agent class handle
// STEP - 2
uvm_algorithmic_comparator #(a_item, b_item, m_transformer) algo;
function void build_phase(uvm_phase phase);
transf = new("transf",this);
algo = new("algo",this, transf);
a_ag = a_agent::type_id::create("a_ag", this);
b_ag = b_agent::type_id::create("b_ag", this);
endfunction : build_phase
// STEP - 3
function void connect_phase(uvm_phase phase);
endfunction : connect_phase
Alright, you are done with the scoreboard and good to go for simulation!!!
Here, when "a_ag.drv" broadcast any transaction on "a_ap" analysis port, it will be converted in to "b_item" transaction class and stored in "m_before_fifo" tlm analysis fifo of "uvm_in_order_comparator" class. Similarly, when "b_ag.drv" broadcast any transaction on "b_ap" analysis port, it will be stored in "m_after_fifo" tlm analysis fifo of "uvm_in_order_comparator" class. In run phase, when any transaction available in "m_before_fifo" and "m_after_fifo", they will be compared.
Now, when any transaction mismatch, this scoreboard will give a warning (UVM_WARNING) message "Comparator Mismatch" that you can override to error (UVM_ERROR) message based on your project need.