What is a scoreboard ?
UVM scoreboard is a verification component that contains checkers and verifies the functionality of a design. It usually receives transaction level objects captured from the interfaces of a DUT via TLM Analysis Ports.
For example, write and read values from a RW register should match. When a write operation is performed to the design, the scoreboard receives this packet and is the expected value. After that, the same register is read back from the design and the data is actual value which is sent to UVM scoreboard. Now the scoreboard can compare between the expected and actual values to see if they match.
What is a reference model ?
After receiving data objects, it can either perform calculations and predict the expected value or send it to a reference model to get expected values. The reference model is also called a predictor and would mimic the functionality of the design.
The final task is to compare expected results with the actual output data from DUT.
It is recommended to inherit from uvm_scoreboard
than uvm_component
so that any additions to uvm_scoreboard
class in a future release of UVM will automatically be included in the custom UVM scoreboard when you switch to the newer version.
Steps to create a UVM scoreboard
1. Create a custom class inherited fromuvm_scoreboard
, register with factory and call function new
// my_scoreboard is user-given name for this class that has been derived from "uvm_scoreboard"
class my_scoreboard extends uvm_scoreboard;
// [Recommended] Makes this scoreboard more re-usable
`uvm_component_utils (my_scoreboard)
// This is standard code for all components
function new (string name = "my_scoreboard", uvm_component parent = null);
super.new (name, parent);
endfunction
// Code for rest of the steps come here
endclass
2. Add necessary TLM exports to receive transactions from other components and instantiat them in build_phase
// Step2: Declare and create a TLM Analysis Port to receive data objects from other TB components
uvm_analysis_imp #(apb_pkt, my_scoreboard) ap_imp;
// Instantiate the analysis port, because afterall, its a class object
function void build_phase (uvm_phase phase);
ap_imp = new ("ap_imp", this);
endfunction
3. Define the action to be taken when data is received from the analysis port
// Step3: Define action to be taken when a packet is received via the declared analysis port
virtual function void write (apb_pkt data);
// What should be done with the data packet received comes here - let's display it
`uvm_info ("write", $sformatf("Data received = 0x%0h", data), UVM_MEDIUM)
endfunction
4. Perform checksIt is not required to perform checks only in the check_phase
. Real checkers can also actively check during the run_phase
.
// Step4: [Optional] Perform any remaining comparisons or checks before end of simulation
virtual function void check_phase (uvm_phase phase);
...
endfunction
5. Connect Analysis ports of scoreboard with other components in the environment
class my_env extends uvm_env;
...
// Step5: Connect the analysis port of the scoreboard with the monitor so that
// the scoreboard gets data whenever monitor broadcasts the data.
virtual function void connect_phase (uvm_phase phase);
super.connect_phase (phase);
m_apb_agent.m_apb_mon.analysis_port.connect (m_scbd.ap_imp);
endfunction
endclass
Other components in the testbench send data to the scoreboard via an analysis port by calling the port's write
method.
For example, a monitor collects data packets from the bus interface. The packet is complete when the bus operation has received or sent all the data associated with the transfer. The monitor calls the write
method of its analysis port after formulating a complete packet. The scoreboard will get the data packet since the analysis ports of the monitor and scoreboard are connected in the environment.
UVM Scoreboard Example
my_scoreboard is a class inherited from uvm_scoreboard
and registered with the factory. A UVM analysis implementation port called ap_imp is defined to accept transactions of type apb_pkt (uvm_sequence_item
).
Because ap_imp is also a class, an object has to be created using the new
method which has been done in the build_phase
. Implementation of the analysis port is only complete when we define the write
method to handle the incoming packet appropriately.
// Step1 : Create a new class that extends from uvm_scoreboard
class my_scoreboard extends uvm_scoreboard;
`uvm_component_utils (my_scoreboard)
function new (string name = "my_scoreboard", uvm_component parent);
super.new (name, parent);
endfunction
// Step2a: Declare and create a TLM Analysis Port to receive data objects from other TB components
uvm_analysis_imp #(apb_pkt, my_scoreboard) ap_imp;
// Step2b: Instantiate the analysis port, because afterall, its a class object
function void build_phase (uvm_phase phase);
ap_imp = new ("ap_imp", this);
endfunction
// Step3: Define action to be taken when a packet is received via the declared analysis port
virtual function void write (apb_pkt data);
// What should be done with the data packet received comes here - let's display it
`uvm_info ("write", $sformatf("Data received = 0x%0h", data), UVM_MEDIUM)
endfunction
// Step3: Define other functions and tasks that operate on the data and call them
// Remember, this is the main task that consumes simulation time in UVM
virtual task run_phase (uvm_phase phase);
...
endtask
// Step4: [Optional] Perform any remaining comparisons or checks before end of simulation
virtual function void check_phase (uvm_phase phase);
...
endfunction
endclass
How to connect analysis ports of UVM scoreboard ?
After a scoreboard has been defined, you also need to instantiate it in the environment and connect it with the appropriate analysis ports.
class my_env extends uvm_env;
`uvm_component_utils (my_env)
function new (string name = "my_env", uvm_component parent);
super.new (name, parent);
endfunction
// Declare a handle so that we can connect TB components to this
my_scoreboard m_scbd;
// Instantiate or Build the scoreboard using standard UVM factory create calls
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_scbd = my_scoreboard::type_id::create ("m_scbd", this);
endfunction
// Step5: Connect the analysis port of the scoreboard with the monitor so that
// the scoreboard gets data whenever monitor broadcasts the data.
// Note: This agent is assumed to be present in this environment for example purpose
virtual function void connect_phase (uvm_phase phase);
super.connect_phase (phase);
m_apb_agent.m_apb_mon.analysis_port.connect (m_scbd.ap_imp);
endfunction
endclass