Comparison at scoreboard?

Hi Sir, after 3 weeks of learning UVM through various sites. I started writing my own testbench for small design as shown below. I have worked till the monitor without any obstacles. when i started writing scoreboard. i dont know how to compare the transactions(which i got from monitor) with predicted data(i dont know where do i get this data from). please some one guide me in complete my first uvm testbench (scoreboard). how and with what(transaction items coming from sequencer or driver ??) should i compare?? I am providing my eda url link for below code : design done(1) - EDA Playground

I have half written scoreboard component below…

///////////////////////////////////////////dut///////////////////////////////////////

module dut(clk,rst,sel,in,op1,op2,op3);
  input clk,rst;
  input [1:0]sel;
  input [3:0]in;
  output reg [3:0] op1,op2,op3;
  
  always@(posedge clk)
    begin
      if(rst || (sel==2'b11)) begin
        op1<=4'b0;
        op2<=4'b0;
        op3<=4'b0;
      end
      else begin
        case(sel)
          2'b00: begin
            op1<=in;
            op2<=4'b0;
            op3<=4'b0;
          end
           2'b01: begin
            op1<=4'b0;
            op2<=in;
            op3<=4'b0;
          end
           2'b10: begin
            op1<=4'b0;
            op2<=4'b0;
            op3<=in;
          end           
        endcase
      end   
      end
          endmodule

///////////////////////////interface///////////////////////////////

interface intf(input logic clk);
  logic rst;
  logic [3:0]in;
  logic [1:0]sel;
  logic [3:0]op1,op2,op3;
  
  clocking cb@(posedge clk);
    default input #1 output #3;
    input op1,op2,op3;
    output in,sel;
  endclocking
 
    clocking mcb@(posedge clk);
    default input #1 output #3;
    input op1,op2,op3;
    input in,sel;
  endclocking
  
endinterface

 /////////////////////////transaction//////////////////////////

class dut_seq_item extends uvm_sequence_item;

  rand bit [1:0]sel;
  rand bit [3:0]in;
       bit [3:0]op1,op2,op3;
  
  `uvm_object_utils_begin(dut_seq_item)
     `uvm_field_int(sel, UVM_DEFAULT)
     `uvm_field_int(in, UVM_DEFAULT)
     `uvm_field_int(op1, UVM_DEFAULT)
     `uvm_field_int(op2, UVM_DEFAULT)
     `uvm_field_int(op3, UVM_DEFAULT)
  `uvm_object_utils_end
  
  function new(string name= "seq_item");
    super.new(name);
  endfunction
  
   virtual function string convert2str();
     return $sformatf("sel=%b in=0x%0d op1=0x%0d op2=0x%0d op3=0x%0d", sel, in, op1, op2, op3);
  endfunction
  
endclass

//////////////////////////sequence//////////////////////////////////
class dut_sequence extends uvm_sequence#(dut_seq_item);
  
  `uvm_object_utils(dut_sequence)
  
  function new(string name= "dut_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_info ("Dut_Sequence", $sformatf ("Starting body of %s", this.get_name()), UVM_MEDIUM)
     
    for(int i=0; i<8; i++) begin
dut_seq_item  trans= dut_seq_item::type_id::create("trans");
      start_item(trans);
      assert(trans.randomize());                          
      `uvm_info("Dut_sequence", $sformatf("Generating new items: %s", trans.convert2str()), UVM_MEDIUM)
      finish_item(trans);
        
    end
    `uvm_info ("Dut_Sequence", $sformatf ("Sequence Items over %s", this.get_name()), UVM_MEDIUM)
  endtask
  
endclass

//////////////////////////sequencer//////////////////////////////////

typedef uvm_sequencer#(dut_seq_item) dut_sequencer;

//////////////////////////driver////////////////////////////////////

class dut_driver extends uvm_driver#(dut_seq_item);

  `uvm_component_utils(dut_driver)
  virtual intf vif;
  
  function new(string name="dut_driver", uvm_component parent=null);
    super.new(name,parent);
  endfunction
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
   if(!uvm_config_db#(virtual intf)::get(this, "", "vif",vif))
      `uvm_error("vif","vif not found at driver")
      endfunction
      
   virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);
    forever begin
      dut_seq_item trans;
      seq_item_port.get_next_item(trans);
   //   `uvm_info("[DRIVER]", $sformatf("Driver recieved Trans: %s", trans.convert2str()), UVM_MEDIUM)
      drive(trans);
      seq_item_port.item_done();
      `uvm_info("[DRIVER]", $sformatf("Driver Item done: %s", trans.convert2str()), UVM_MEDIUM)
    end
    endtask
    
 virtual task drive(dut_seq_item trans);
   @(vif.cb);
   if(trans.sel!= 2'b11) begin
        vif.cb.sel <= trans.sel;
        vif.cb.in <= trans.in;
        trans.op1<= vif.cb.op1;
        trans.op2<= vif.cb.op2;
        trans.op3<= vif.cb.op3;
        `uvm_info("Diver_trans_vif", $sformatf("AT DRIVER VALUES: %s", trans.convert2str()), UVM_MEDIUM)
      end
   if(trans.sel== 2'b11) begin
        vif.cb.sel <= trans.sel;
        vif.cb.in <= trans.in;
        trans.op1<= vif.cb.op1;
        trans.op2<= vif.cb.op2;
        trans.op3<= vif.cb.op3;
        `uvm_info("Diver_trans_vif", $sformatf("AT DRIVER VALUES: %s", trans.convert2str()), UVM_MEDIUM)
      end   
    endtask
    endclass 
   
 //////////////////////monitor//////////////////////////////////////
   
  class dut_monitor extends uvm_monitor;
  uvm_analysis_port#(dut_seq_item) mon_analysis_port;
  virtual intf vif;
    
    dut_seq_item trans;
    `uvm_component_utils(dut_monitor)
    
    function new(string name="dut_monitor", uvm_component parent=null);
    super.new(name, parent);
      trans=new();
      mon_analysis_port = new ("mon_analysis_port", this);
  endfunction

   function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual intf)::get(this, "", "vif", vif))
      `uvm_fatal("MON", "Could not get vif")
  endfunction

  virtual task run_phase(uvm_phase phase);
    forever  begin
      @ (vif.mcb);
      if(vif.mcb.sel != 2'b11)begin
        trans.sel = vif.mcb.sel;
        trans.in = vif.mcb.in;
        trans.op1 = vif.mcb.op1;
        trans.op2 = vif.mcb.op2;
        trans.op3 = vif.mcb.op3;
        @(vif.mcb);
      end
      if(vif.mcb.sel == 2'b11)begin
        trans.sel = vif.mcb.sel;
        trans.in = vif.mcb.in;
        trans.op1 = vif.mcb.op1;
        trans.op2 = vif.mcb.op2;
        trans.op3 = vif.mcb.op3;
        @(vif.mcb);
      end
      `uvm_info("Monitor",$sformatf("Monitor got VALUES: %s",trans.convert2str()), UVM_MEDIUM)
        mon_analysis_port.write(trans);   
      end
  endtask
endclass
   
 /////////////////////////agent////////////////////////////////////  
    
  class dut_agent extends uvm_agent;
  
    `uvm_component_utils(dut_agent)
 
  function new(string name="dut_agent", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  dut_driver 	    d0; 	
  dut_sequencer	    s0;
  dut_monitor       m0;

   function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    s0 = dut_sequencer::type_id::create("s0", this);
    m0 = dut_monitor::type_id::create("m0", this); 
    d0 = dut_driver::type_id::create("d0", this);
   endfunction

   function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    d0.seq_item_port.connect(s0.seq_item_export);
  endfunction
endclass

   ////////////////////////scoreboard/////////////////////////////////
   
 class dut_scoreboard extends uvm_scoreboard;
 
   `uvm_component_utils(dut_scoreboard)
  
   function new(string name="dut_scoreboard", uvm_component parent=null);
    super.new(name, parent);
  endfunction
   
   dut_seq_item queue[$];
   
// bit [3:0]chk_op1,chk_op2,chk_op3;
   
  uvm_analysis_imp #(dut_seq_item, dut_scoreboard) m_analysis_imp;
   

   function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    m_analysis_imp = new("m_analysis_imp", this);
  endfunction

  virtual  function void write(dut_seq_item trans);
    queue.push_back(trans)
    endfunction
     
   virtual task run_phase(uvm_phase phase)
   dut_seq_item pkt;
     forever begin
       ---
       ---
       ---
       ---
       
endclass  
   
  
///////////////////////environment///////////////////////////////////
   
 class dut_env extends uvm_env;
   `uvm_component_utils(dut_env)
   function new(string name="dut_env", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  dut_agent 		a0; 		// Agent handle
  dut_scoreboard	sb0; 		// Scoreboard handle

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    a0 = dut_agent::type_id::create("a0", this);
    sb0 = dut_scoreboard::type_id::create("sb0", this);
  endfunction

   function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    a0.m0.mon_analysis_port.connect(sb0.m_analysis_imp);
  endfunction
endclass
   
   
//////////////////////////test///////////////////////////////////////
   
  class test extends uvm_test;
  `uvm_component_utils(test)
  function new(string name = "test", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  dut_env env;
  virtual intf vif;

   function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = dut_env::type_id::create("env", this);
    if (!uvm_config_db#(virtual intf)::get(this, "", "vif", vif))
      `uvm_fatal("TEST", "Did not get vif")
      uvm_config_db#(virtual intf)::set(this, "env.a0.*", "vif", vif);
  endfunction

  virtual task run_phase(uvm_phase phase);
    dut_sequence seq = dut_sequence::type_id::create("seq");
    phase.raise_objection(this);
    apply_reset();
    seq.start(env.a0.s0);
    #50;
    phase.drop_objection(this);
  endtask

  virtual task apply_reset();
    vif.rst <= 1;
    repeat(10) @ (vif.cb);
    vif.rst <= 0;
    repeat(10) @ (vif.cb);
  endtask
endclass
      
///////////////////////////////top//////////////////////////////////////
  
  module tb;
  reg clk;  
  always #5 clk =~ clk;

   intf i_intf (clk);
     dut u0 ( .clk (clk),
               .rst(i_intf.rst),
               .sel(i_intf.sel),
               .in (i_intf.in),
               .op1 (i_intf.op1),
               .op2 (i_intf.op2),
               .op3 (i_intf.op3));
  
  initial begin
    clk = 1;
    uvm_config_db#(virtual intf)::set(null, "*", "vif", i_intf);
    run_test("test");
  end

  initial begin
    $dumpvars;
    $dumpfile ("dump.vcd");
  end
   
endmodule

In reply to subbarao:

A scoreboard needs always at least to tarnsactions to compare. One transaction you get from the monitor collecting the outputs of your design. The 2nd transaction will come out of a reference model instantiated in the scorboard, egtting the input transactions to the design.

BTW do not use a queue in your scorboards as data storage use instead a uvm_tlm_analysis_fifo.

In reply to chr_sue:

sir, if i use uvm_tlm_analysis_fifo in scoreboard it just gets the transactions from the fifo (it has inbuilt write method and analysis_imp)right?? In monitor i have used analysis port with write method(so here all the transactions received from virtual interface are broadcasted using analysis_port) So these are expected values right?? (…i have done till here…)

To get reference values do i need to instantiate my dut_seq_item trans in scoreboard (trans is handle/variable)??? And how should i compare with this reference model values with expected values ??(using compare method)…

In reply to subbarao:

The reference model in your scoreboard is a transaction-level model of your DUT. This converts on the TL the input tarsnactions into the output transactions. These output transactions are the expected values and the transactions from the monitor are the actual transaction.

In reply to chr_sue:

hi sir, i have created 2 monitors, one for carrying inputs to scoreboard(for expected result) and other to carry actual result values to scoreboard for comparing both. My both monitors getting both inputs and outputs values. But where as my scoreboard is not displaying my values even after am using tlmfifo ports with get method.

///////////////////seq_item/////////////////////////////////////

class dut_seq_item extends uvm_sequence_item;

rand bit [1:0]sel;
rand bit [3:0]in;
bit clk,rst;
bit [3:0]op1,op2,op3;

uvm_object_utils_begin(dut_seq_item) uvm_field_int(sel, UVM_DEFAULT)
uvm_field_int(in, UVM_DEFAULT) uvm_field_int(op1, UVM_DEFAULT)
uvm_field_int(op2, UVM_DEFAULT) uvm_field_int(op3, UVM_DEFAULT)
`uvm_object_utils_end

function new(string name= “seq_item”);
super.new(name);
endfunction

virtual function string convert2str();
return $sformatf(“sel=%b in=0x%0d op1=0x%0d op2=0x%0d op3=0x%0d”, sel, in, op1, op2, op3);
endfunction

endclass

//////////////////////////sequence//////////////////////////////////

class dut_sequence extends uvm_sequence#(dut_seq_item);

`uvm_object_utils(dut_sequence)

function new(string name= “dut_sequence”);
super.new(name);
endfunction

virtual task body();
for(int i=0; i<5; i++) begin
dut_seq_item trans= dut_seq_item::type_id::create(“trans”);
start_item(trans);
assert(trans.randomize());
`uvm_info(“Dut_sequence”, $sformatf(“Generating new items: %s”, trans.convert2str()), UVM_MEDIUM)
finish_item(trans);

end
`uvm_info ("Dut_Sequence", $sformatf ("Sequence Items over %s", this.get_name()), UVM_MEDIUM)

endtask

endclass

//////////////////////////sequencer//////////////////////////////////

typedef uvm_sequencer#(dut_seq_item) dut_sequencer;

//////////////////////////driver////////////////////////////////////

class dut_driver extends uvm_driver#(dut_seq_item);

`uvm_component_utils(dut_driver)

virtual intf vif;

function new(string name=“dut_driver”, uvm_component parent=null);
super.new(name,parent);
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual intf)::get(this, “”, “vif”,vif))
`uvm_error(“vif”,“vif not found at driver”)
endfunction

virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
dut_seq_item trans;
seq_item_port.get_next_item(trans);
drive(trans);
seq_item_port.item_done();
`uvm_info(“[DRIVER]”, $sformatf(“Driver Item done: %s”, trans.convert2str()), UVM_MEDIUM)
end
endtask

virtual task drive(dut_seq_item trans);
@(vif.cb);
if(trans.sel!= 2’b11) begin
vif.cb.sel <= trans.sel;
vif.cb.in <= trans.in;
trans.op1<= vif.cb.op1;
trans.op2<= vif.cb.op2;
trans.op3<= vif.cb.op3;
uvm_info("Diver_trans_vif", $sformatf("AT DRIVER VALUES: %s", trans.convert2str()), UVM_MEDIUM) end if(trans.sel== 2'b11) begin vif.cb.sel <= trans.sel; vif.cb.in <= trans.in; trans.op1<= vif.cb.op1; trans.op2<= vif.cb.op2; trans.op3<= vif.cb.op3; uvm_info(“Diver_trans_vif”, $sformatf(“AT DRIVER VALUES: %s”, trans.convert2str()), UVM_MEDIUM)
end
endtask
endclass

//////////////////////monitor_before_ap//////////////////////////////

class dut_monitor_before extends uvm_monitor;

uvm_analysis_port #(dut_seq_item) mon_ap_before;

virtual intf vif;

dut_seq_item trans;

`uvm_component_utils(dut_monitor_before)

function new(string name="dut_monitor_before", uvm_component parent=null);
super.new(name, parent);
  trans=new();
  mon_ap_before = new("mon_ap_before", this);
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual intf)::get(this, “”, “vif”, vif))
`uvm_fatal(“MON”, “Could not get vif”)
endfunction

virtual task run_phase(uvm_phase phase);
forever begin
@ (vif.mcb);
if(vif.sel != 2’b11)begin
trans.op1 = vif.op1;
trans.op2 = vif.op2;
trans.op3 = vif.op3;
end
if(vif.sel == 2’b11)begin
trans.op1 = vif.op1;
trans.op2 = vif.op2;
trans.op3 = vif.op3;

  end
  `uvm_info("Monitor1",$sformatf("Monitor got output VALUES: %s",trans.convert2str()), UVM_MEDIUM)
  mon_ap_before.write(trans);   
  end

endtask
endclass
///////////////////////monitor_after_ap////////////////////////////

class dut_monitor_after extends uvm_monitor;

 uvm_analysis_port #(dut_seq_item) mon_ap_after;

 virtual intf vif;

dut_seq_item trans;

 `uvm_component_utils(dut_monitor_after)

 function new(string name="dut_monitor_after", uvm_component parent=null);
super.new(name, parent);
  trans=new();
  mon_ap_after = new("mon_ap_after", this);

endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual intf)::get(this, “”, “vif”, vif))
`uvm_fatal(“MON”, “Could not get vif”)
endfunction

virtual task run_phase(uvm_phase phase);
forever begin
@ (vif.mcb);
if(vif.sel != 2’b11)begin
trans.sel = vif.sel;
trans.in = vif.in;
end
if(vif.sel == 2’b11)begin
trans.sel = vif.sel;
trans.in = vif.in;
end
`uvm_info(“Monitor2”,$sformatf(“Monitor got input VALUES: %s”,trans.convert2str()), UVM_MEDIUM)
mon_ap_after.write(trans);
end
endtask
endclass

/////////////////////////agent////////////////////////////////////

class dut_agent extends uvm_agent;

`uvm_component_utils(dut_agent)

function new(string name=“dut_agent”, uvm_component parent=null);
super.new(name, parent);
endfunction

uvm_analysis_port #(dut_seq_item) agent_ap_before;
uvm_analysis_port #(dut_seq_item) agent_ap_after;

dut_driver d0;
dut_sequencer s0;
dut_monitor_before m0_before;
dut_monitor_after m0_after;

function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent_ap_before=new(“agent_ap_before”,this);
agent_ap_after=new(“agent_ap_after”,this);
s0 = dut_sequencer::type_id::create(“s0”, this);
m0_before = dut_monitor_before::type_id::create(“m0_before”, this);
m0_after = dut_monitor_after::type_id::create(“m0_after”, this);
d0 = dut_driver::type_id::create(“d0”, this);
endfunction

function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
d0.seq_item_port.connect(s0.seq_item_export);
m0_before.mon_ap_before.connect(agent_ap_before);
m0_before.mon_ap_before.connect(agent_ap_before);
endfunction
endclass

////////////////////////scoreboard/////////////////////////////////

class dut_scoreboard extends uvm_scoreboard;

`uvm_component_utils(dut_scoreboard)

uvm_analysis_export #(dut_seq_item) sb_export_before;
uvm_analysis_export #(dut_seq_item) sb_export_after;

uvm_tlm_analysis_fifo #(dut_seq_item) before_fifo;
uvm_tlm_analysis_fifo #(dut_seq_item) after_fifo;

dut_seq_item transaction_before;
dut_seq_item transaction_after;

function new(string name="dut_scoreboard", uvm_component parent=null);
   super.new(name, parent);
 transaction_before = new();
 transaction_after = new(); 
endfunction  

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

function void connect_phase(uvm_phase phase);
sb_export_before.connect(before_fifo.analysis_export);
sb_export_after.connect(after_fifo.analysis_export);
endfunction

task run();
forever begin

before_fifo.get(transaction_before);
  `uvm_info("scoreboard2",$sformatf("scoreboard2 got input VALUES: %s",transaction_before.convert2str()), UVM_MEDIUM)
after_fifo.get(transaction_after);
  `uvm_info("scoreboard1",$sformatf("scoreboard1 got input VALUES: %s",transaction_after.convert2str()), UVM_MEDIUM)
end

endtask

endclass

///////////////////////environment///////////////////////////////////

class dut_env extends uvm_env;
`uvm_component_utils(dut_env)
function new(string name=“dut_env”, uvm_component parent=null);
super.new(name, parent);
endfunction

dut_agent a0;
dut_scoreboard sb0;

function void build_phase(uvm_phase phase);
super.build_phase(phase);
a0 = dut_agent::type_id::create(“a0”, this);
sb0 = dut_scoreboard::type_id::create(“sb0”, this);
endfunction

function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
a0.agent_ap_before.connect(sb0.sb_export_before);
a0.agent_ap_after.connect(sb0.sb_export_after);
endfunction

endclass

//////////////////////////test///////////////////////////////////////

class test extends uvm_test;

`uvm_component_utils(test)

function new(string name = “test”, uvm_component parent=null);
super.new(name, parent);
endfunction

dut_env env;

virtual intf vif;

function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = dut_env::type_id::create(“env”, this);
if (!uvm_config_db#(virtual intf)::get(this, “”, “vif”, vif))
`uvm_fatal(“TEST”, “Did not get vif”)
uvm_config_db#(virtual intf)::set(this, “env.a0.*”, “vif”, vif);
endfunction

virtual task run_phase(uvm_phase phase);
dut_sequence seq = dut_sequence::type_id::create(“seq”);
phase.raise_objection(this);
apply_reset();
seq.start(env.a0.s0);
#20;
phase.drop_objection(this);
endtask

virtual task apply_reset();
vif.rst <= 1;
repeat(5) @ (vif.cb);
vif.rst <= 0;
endtask

endclass

///////////////////////////////top//////////////////////////////////////

module tb;
reg clk;

always #5 clk =~ clk;

intf i_intf (clk);

dut u0 ( .clk (clk),
.rst(i_intf.rst),
.sel(i_intf.sel),
.in (i_intf.in),
.op1 (i_intf.op1),
.op2 (i_intf.op2),
.op3 (i_intf.op3));

initial begin
clk = 1;
uvm_config_db#(virtual intf)::set(null, “*”, “vif”, i_intf);
run_test(“test”);
end

initial begin
$dumpvars;
$dumpfile (“dump.vcd”);
end

endmodule

In reply to subbarao:

solved by just adding fork and join… now am able to get values in scoreboard