2

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?

Ashutosh Rawal
  • 301
  • 1
  • 4
  • 16

1 Answers1

3

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
sharvil111
  • 4,301
  • 1
  • 14
  • 29
Ashutosh Rawal
  • 301
  • 1
  • 4
  • 16
  • Why Semi-Colon(;) in `uvm_component_utils(driver);` and all others? I think it is not a single consumer, but it is one-to-one connection between different ports of different producers and different (imp-)ports of single class. So, it might be still a one-to-one connection. (Total No. of Producer Ports = Total No. of consumer ports) – sharvil111 Jul 07 '16 at 12:11
  • 1
    Semi-Colon(;) does not make any difference while declaring a macro. – Ashutosh Rawal Jul 08 '16 at 17:17
  • 1
    Yes, it is one to one connection(of monitor and driver) with a single consumer(scoreboard). Driver and Monitor are connected with a single scoreboard.Why it is not a single consumer? Scoreboard receives(consumes) data from two different components. (Total No. of Producer Ports = Total No. of consumer ports) But still Two different components (Monitor and driver) and a single component(scoreboard). – Ashutosh Rawal Jul 08 '16 at 17:31