Search code examples
system-verilogverificationuvm

What to do in case of multiple producer and single consumer?


While developing test bench you might face a situation of multiple producers and a single consumer.

e.g. Single Scoreboard (consumer) receives data from the driver and monitor (multiple producers).

How to send data from multiple producers to consumer with the help of port connection?


Solution

  • Verification engineer often come across such situation when there are multiple producers and a single consumer.

    If the port connection is used, then for all the producers there must be a different method in single consumer. But there is only one "write" method (for analysis port).

    How to achieve this thing !!

    UVM support such functionality with to help of that you can do this. This is possible with help of analysis port.

    Let's consider following scenario: There are three producers and a single consumer. Now all three producers called write method of consumer. For that you have to follow following steps:

    You have to declare macro before consumer class.

    e.g.`uvm_analysis_imp_decl( _name )

    Port declaration is like:

    e.g.uvm_analysis_imp_name#(transaction,consumer_1) write_imp_1;

    Now you can modify name of write method as write_name.

    e.g.function void write_name(transaction tr_inst);

    $display("Function called");

    endfunction

    Here is sample code for multiple producers and a single consumer to give you more clarity.

    Multiple producers and a single consumer

    CODE

    class transaction extends uvm_sequence_item;
      `uvm_object_utils(transaction);
      rand int unsigned a;
      rand int unsigned b;
    
      function new(string name ="");
        super.new(name);
      endfunction
    
    endclass
    
    
    class producer_1 extends uvm_component;
      `uvm_component_utils(producer_1);
      transaction tr_inst;
      uvm_analysis_port #(transaction) producer_1_to_consumer_p;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        producer_1_to_consumer_p = new("producer_1_to_consumer_p",this);
        tr_inst = new("tr_inst");
      endfunction
    
    
      task run_phase(uvm_phase phase) ;
        super.run_phase(phase);
        phase.raise_objection(this);    
        tr_inst.randomize with {{b < 20};{a < 20};};
        $display("Write the data");
        tr_inst.a = 10; tr_inst.b = 20;
        producer_1_to_consumer_p.write(tr_inst);
        phase.drop_objection(this);
      endtask
    
    endclass
    
    class producer_2 extends uvm_component;
      `uvm_component_utils(producer_2);
      transaction tr_inst;
      uvm_analysis_port #(transaction) producer_2_to_consumer_p;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        producer_2_to_consumer_p = new("producer_2_to_consumer_p",this);
        tr_inst = new("tr_inst");
      endfunction
    
    
      task run_phase(uvm_phase phase) ;
        super.run_phase(phase);
        phase.raise_objection(this);
    
        tr_inst.randomize with {{b < 20};{a < 20};};
        $display("Write the data");
        tr_inst.a = 10; tr_inst.b = 20;
        producer_2_to_consumer_p.write(tr_inst);
        phase.drop_objection(this);
      endtask
    
    endclass
    
    class producer_3 extends uvm_component;
      `uvm_component_utils(producer_3);
      transaction tr_inst;
      uvm_analysis_port #(transaction) producer_3_to_consumer_p;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        producer_3_to_consumer_p = new("producer_3_to_consumer_p",this);
        tr_inst = new("tr_inst");
      endfunction
    
    
      task run_phase(uvm_phase phase) ;
        super.run_phase(phase);
        phase.raise_objection(this);
    
        tr_inst.randomize with {{b < 20};{a < 20};};
        $display("Write the data");
        tr_inst.a = 10; tr_inst.b = 20;
        producer_3_to_consumer_p.write(tr_inst);
        phase.drop_objection(this);
      endtask
    
    endclass
    
    `uvm_analysis_imp_decl( _pro_1 )
    `uvm_analysis_imp_decl( _pro_2 )
    `uvm_analysis_imp_decl( _pro_3 )
    
    class consumer_1 extends uvm_component;
      `uvm_component_utils(consumer_1);
    
      uvm_analysis_imp_pro_1#(transaction,consumer_1) write_imp_1;
      uvm_analysis_imp_pro_2#(transaction,consumer_1) write_imp_2;
      uvm_analysis_imp_pro_3#(transaction,consumer_1) write_imp_3;
      //transaction tr_inst;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        write_imp_1 = new("write_imp_1",this);
        write_imp_2 = new("write_imp_2",this);
        write_imp_3 = new("write_imp_3",this);
      endfunction
    
      function void write_pro_1(transaction tr_inst);
        $display("Got the data");
        `uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
      endfunction
    
      function void write_pro_2(transaction tr_inst);
        $display("Got the data");
        `uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
      endfunction
    
      function void write_pro_3(transaction tr_inst);
        $display("Got the data");
        `uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
      endfunction
    
    endclass
    
    
    
    class env extends uvm_component;
      `uvm_component_utils(env);
    
      producer_1 p_inst_1;
      producer_2 p_inst_2;
      producer_3 p_inst_3;
      consumer_1 c_inst_1;
    
      function new(string name="",uvm_component parent);
        super.new(name,parent);
        p_inst_1 = new("p_inst_1",this);
        p_inst_2 = new("p_inst_2",this);
        p_inst_3 = new("p_inst_3",this);
        c_inst_1 = new("c_inst_1",this);
    
      endfunction
    
      function void connect();
        p_inst_1.producer_1_to_consumer_p.connect(c_inst_1.write_imp_1);
        p_inst_2.producer_2_to_consumer_p.connect(c_inst_1.write_imp_2);
        p_inst_3.producer_3_to_consumer_p.connect(c_inst_1.write_imp_3);
      endfunction
    
    endclass
    
    module main();
    
      env env_inst;
      initial 
      begin
        env_inst = new("env_inst",null);
        run_test();
      end
    
    endmodule
    

    Here I also provides sample code for a scoreboard (a single consumer) and driver, monitor(multiple producers).

    Driver, Monitor and Scoreboard connection

    CODE

    class transaction extends uvm_sequence_item;
      `uvm_object_utils(transaction);
      rand int unsigned a;
      rand int unsigned b;
      rand int unsigned sum;
    
      function new(string name ="");
        super.new(name);
      endfunction
    
    endclass
    
    class driver extends uvm_driver;
      `uvm_component_utils(driver);
      transaction tr_inst;
      uvm_analysis_port #(transaction) driver_to_sb_p;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        driver_to_sb_p = new("driver_to_sb_p",this);
        tr_inst = new("tr_inst");
      endfunction
    
    
      task run_phase(uvm_phase phase) ;
        super.run_phase(phase);
        phase.raise_objection(this);    
        `uvm_info("DRIVER","driver drive the data to scoreboard",UVM_LOW)
        tr_inst.a = 10; tr_inst.b = 20;
        tr_inst.sum = tr_inst.a + tr_inst.b;
        driver_to_sb_p.write(tr_inst);
        phase.drop_objection(this);
      endtask
    
    endclass
    
    class monitor extends uvm_monitor;
      `uvm_component_utils(monitor);
      transaction tr_inst;
      uvm_analysis_port #(transaction) monitor_to_sb_p;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        monitor_to_sb_p = new("monitor_to_sb_p",this);
        tr_inst = new("tr_inst");
      endfunction
    
    
      task run_phase(uvm_phase phase) ;
        super.run_phase(phase);
        phase.raise_objection(this);
        `uvm_info("MONITOR","monitor drive the data to scoreboard",UVM_LOW)
        tr_inst.a = 10; tr_inst.b = 20;
        tr_inst.sum = tr_inst.a + tr_inst.b;
        monitor_to_sb_p.write(tr_inst);
        phase.drop_objection(this);
      endtask
    
    endclass
    
    `uvm_analysis_imp_decl( _dri )
    `uvm_analysis_imp_decl( _mon )
    
    class scoreboard extends uvm_scoreboard;
      `uvm_component_utils(scoreboard);
      int dri_sum,mon_sum;
      uvm_analysis_imp_dri#(transaction,scoreboard) write_imp_1;
      uvm_analysis_imp_mon#(transaction,scoreboard) write_imp_2;
      //transaction tr_inst;
    
      function new(string name ="",uvm_component parent);
        super.new(name,parent);
        write_imp_1 = new("write_imp_1",this);
        write_imp_2 = new("write_imp_2",this);
      endfunction
    
        function void write_dri(transaction tr_inst);
        `uvm_info("SCORE BOARD","Receive data form driver",UVM_LOW)
          `uvm_info("SCORE BOARD",$sformatf("the value of a = %0d and b = %0d sum = %0d",tr_inst.a,tr_inst.b,tr_inst.sum),UVM_LOW);
        dri_sum = tr_inst.sum;
      endfunction
    
      function void write_mon(transaction tr_inst);
        `uvm_info("SCORE BOARD","Receive data form monitor",UVM_LOW)
        `uvm_info("SCORE BOARD",$sformatf("the value of a = %0d and b = %0d sum = %0d",tr_inst.a,tr_inst.b,tr_inst.sum),UVM_LOW);
        mon_sum = tr_inst.sum;
      endfunction
    
      task compare_data();
        if (mon_sum == dri_sum)
          begin
            `uvm_info("SCORE BOARD","---------  data is matched  ----------",UVM_LOW)
          end
        else
          begin
            `uvm_info("SCORE BOARD","data is not matched",UVM_LOW)
          end
      endtask
    
      task run_phase(uvm_phase phase) ;
        super.run_phase(phase);
        phase.raise_objection(this);
        compare_data();
        phase.drop_objection(this);
      endtask
    
    endclass
    
    class env extends uvm_component;
      `uvm_component_utils(env);
    
      driver dri_inst;
      monitor mon_inst;
      scoreboard sb_inst;
    
      function new(string name="",uvm_component parent);
        super.new(name,parent);
        dri_inst = new("dri_inst",this);
        mon_inst = new("mon_inst",this);
        sb_inst  = new("sb_inst",this);
    
      endfunction
    
      function void connect();
        dri_inst.driver_to_sb_p.connect(sb_inst.write_imp_1);
        mon_inst.monitor_to_sb_p.connect(sb_inst.write_imp_2);
      endfunction
    
    endclass
    
    
    module main();
    
      env env_inst;
      initial 
      begin
        env_inst = new("env_inst",null);
        run_test();
      end
    
    endmodule