The scoreboardis a crucial element in a self-checking environment, it verifies the properoperation of a design at a functional level. This component is the mostdifficult one to write, it varies from project to project and from designer todesigner.
In our case, wedecided to make the prediction of the DUT functionality in the monitors and letthe scoreboard compare the prediction with the DUT’s response. But there aredesigners who prefer to leave the prediction to the scoreboard. So thefunctionality of the scoreboard is very subjective.
In the agent, wecreated two monitors, as a result, we will have to create two analysis exportsin the scoreboard that are going to be used to retrieve transactions from bothmonitors. After that, a method compare() is going to beexecuted in the run phase and compare both transactions. If they match, itmeans that the testbench and the DUT both agree in the functionality and itwill return an “OK” message.
But we have aproblem: we have two transaction streams coming from two monitors and we needto make sure they are synchronized. This could be done manually by writingappropriatedwrite() functions but there is an easier and cleanerway of doing this: by using UVM FIFO.
These FIFO willwork as it’s represented in Figure 8.1.
Figure 8.1– Usage of FIFO in the scoreboard
The FIFO areinstantiated similarly to ports/exports, with uvm_tlm_analysis_fifo#(generic_transaction) generic_fifo and they already implement therespective write() functions that are called from the monitors.To access their data we just execute the get() method fromeach FIFO.
The code fromthe scoreboard follows in Code 8.1.
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 43 44 45 46 47 48 | class simpleadder_scoreboard extends uvm_scoreboard; `uvm_component_utils(simpleadder_scoreboard)
uvm_analysis_export #(simpleadder_transaction) sb_export_before; uvm_analysis_export #(simpleadder_transaction) sb_export_after;
uvm_tlm_analysis_fifo #(simpleadder_transaction) before_fifo; uvm_tlm_analysis_fifo #(simpleadder_transaction) after_fifo;
simpleadder_transaction transaction_before; simpleadder_transaction transaction_after;
function new(string name, uvm_component parent); super.new(name, parent); transaction_before = new("transaction_before"); transaction_after = new("transaction_after"); endfunction: new
function void build_phase(uvm_phase phase); super.build_phase(phase); sb_export_before = new("sb_export_before", this); sb_export_after = new("sb_export_after", this);
before_fifo = new("before_fifo", this); after_fifo = new("after_fifo", this); endfunction: build_phase
function void connect_phase(uvm_phase phase); sb_export_before.connect(before_fifo.analysis_export); sb_export_after.connect(after_fifo.analysis_export); endfunction: connect_phase
task run(); foreverbegin before_fifo.get(transaction_before); after_fifo.get(transaction_after); compare(); end endtask: run
virtual function void compare(); if(transaction_before.out== transaction_after.out)begin `uvm_info("compare",{"Test: OK!"}, UVM_LOW); endelsebegin `uvm_info("compare",{"Test: Fail!"}, UVM_LOW); end endfunction: compare endclass: simpleadder_scoreboard |
Code 8.1 – Code for thescoreboard
In Figure 8.2,it’s represented the current state of our testbench.