Monday, October 24, 2016

UVM / System Verilog - Threads and Synchronization.


  • In SystemVerilog, when you instantiate static modules, you create multiple threads running the procedures within each instances.
  • Synchronization
    • Mailbox
    • Streams
    • Semaphore
    • Use Ports, Exports and TLM_FIFOs
      • uvm_put_port # (int) p1;
        p1 = new("put_port", this);
      • uvm_get_port #(int) p2;
      • uvm_tlm_fifl #(int) p3;
      • m1.p1.connect (p3.put_export);
        m2.p2.connect (p3.get_export);
      • // in f1.svh, for class c1
           uvm_put_port # (int) p1;
           p1 = new("put_port", this);
        // in f2.svh, for class c2
           uvm_get_port #(int) p2;
           p2 = new("p2", this);
        // in f3.svh, which contains the 
        //     test env for c1 and c2
           uvm_tlm_fifo #(int) p3;
           p3 = new("p3", this);
           c1.p1.connect (p3.put_export);
           c2.p2.connect (p3.get_export0;
        
        // c1.p1 -> (put_export of env)
        //               ->(p3)->
        //          (get_export of env) -> c2.p2
        
           
        endtask : run
        
    • Put shared variable in a package, together with all the classes that share that variable (using `include);
    • virtual task run();
         integer i;
         for (i = 1; i < cnt; i++) begin : loop
            uvm_report_info ("run", $psprintf(...));
            my_pkg::shared = i; // used by other classes 
                                // for synchronization
            // i = my_pkg::shared; // to read from the shared
         end : loop
      endtask : run
      
      
    • Blocking Methods vs Non-Blocking Methods
      • blocking method
        • myport.put(<data>);
        • myport.get(<data>);
      • non-blocking method (returns 0 if failed)
        • myport.try_put();
        • myport.try_get();

Example
class c1 extends uvm_agent;
   uvm_put_port #(int)p1;
   `uvm_component_utils(c1)

   function new...

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

   virtual task run_phase (uvm_phase phase);
      phase.raise_objection(this);
      for (int i = 0; i < cnt; i++) begin
         p1.put(i);
         uvm_report_info("run_phase",...);
      end : loop
      phase.drop_objection(this);
   endtask : run_phase
endclass : c1

class c2 extends uvm_agent;
   uvm_put_port #(int)p2;
   `uvm_component_utils(c2)

   function new...

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

   virtual task run_phase (uvm_phase phase);
      int i;
      forever begin : loop
         p2.get(i);
         uvm_report_info("run_phase",...);
      end : loop
   endtask : run_phase
endclass : c2

class c3 extends uvm_agent;

   `uvm_component_utils(c3)

   c1 p1;
   c2 p2;
   uvm_tlm_fifo #(int) p3;

   function new...

   virtual function void build_phase (uvm_phase phase);
      super.build_phase(phase);
      p1 = c1::type_id::create("p1", this);
      p2 = c2::type_id::create("p2", this);
      p3 = new("p3", this);
   endfunction : build_phase

   virtual function void connect_phase (uvm_phase phase);
      super.connect_phase(phase);
      c1.p1.connect(p3.put_export);
      c2.p2.connect(p3.get_export);
   endfunction : connect_phase

   virtual task run_phase (uvm_phase phase);
   endtask : run_phase

endclass : c3


Example : Blocking Communication vs Non-blocking Communication
// blocking
// @(posedge clk); // this could be missed 
//                   and block the following
// my_port.get(data);
// bus <= data; 

// non-blocking
// @(posedge clk)
// my_port.try_get(data); // won't suspend
// bus <= data;
//

class c1 extends uvm_agent;

   `uvm_component_utils(c1)
   uvm_put_port #(int)p1;

   function new...

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

   virtual task run_phase (uvm_phase phase);
      phase.raise_objection(this);
      for (int i = 0; i < cnt; i++) begin
         // p1.put(i);
         // uvm_report_info("run_phase",...);
         #UNIT_DELAY; // to delay this thread so the following
                      // is always slower than p2 and 
                      // should never fail
         assert (p1.try_put(i)) else
            uvm_report_info("run_phase: p1 not connected");
         uvm_report_info("run_phase", $psprintf("put: %0d",i));
      end : loop
      phase.drop_objection(this);
   endtask : run_phase
endclass : c1

class c2 extends uvm_agent;

   `uvm_component_utils(c2)
   uvm_put_port #(int)p2;

   function new...

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

   virtual task run_phase (uvm_phase phase);
      int i;
      forever begin : loop
         // p2.get(i);
         // uvm_report_info("run_phase",...);
         if (p2.try_get(i))
            uvm_report_info ("run",
               $psprintf ("got: %0d",i));
         else
            uvm_report_info ("run","got nothing");
      end : loop
   endtask : run_phase
endclass : c2



No comments:

Post a Comment