uvm_primer ch17 communication between threads

Communication between verilog threads

The communication between producer and consumer
uses put_it and get_it for communication coordination;

module producer(output byte shared, input bit put_it, output bit get_it);
   initial
     repeat(3) begin 
        $display("Sent %0d", ++shared);
        get_it = ~get_it;
        @(put_it);
     end
endmodule : producer

module consumer(input byte shared,  output bit put_it, input bit get_it);
   initial
      forever begin
         @(get_it);
         $display("Received: %0d", shared);
         put_it = ~put_it;
      end
endmodule : consumer

module top; 
   byte shared;
   producer p (shared, put_it, get_it);
   consumer c (shared, put_it, get_it);
endmodule : top

oop's inter-thread communication coordination

Generally use semaphores or mailboxs; to proceed;

Communication coordination between uvm threads

Use two components to hide details

  • ports The ports object constructed in uvm_component allows us to communicate with other threads in run_phase, use put port to send data to other threads, and use get port to obtain data from other threads;
  • TLM fifo This TLM fifo object is used to connect put port and get port; transaction-level modeling; this fifo can not only transfer transactions, but also any type of data;
    TLM fifo only saves one data element;

blocking mode

The producer generates a piece of data and puts it into the fifo, but the fifo can only store one piece of data; when the loop comes to put again, it is blocked; until the consumer uses get to fetch the data; also when the consumer gets a piece of data, the fifo is empty , Can only block, wait for the next data;

class producer extends uvm_component;
   `uvm_component_utils(producer);
   int shared;
   uvm_put_port #(int) put_port_h;
   function void build_phase(uvm_phase phase);
      put_port_h = new("put_port_h", this);
   endfunction : build_phase
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction : new
   task run_phase(uvm_phase phase);
      phase.raise_objection(this);
      repeat (3) begin
         put_port_h.put(++shared);
         $display("Sent %0d", shared);
      end
      phase.drop_objection(this);
   endtask : run_phase
endclass : producer

class consumer extends uvm_component;
   `uvm_component_utils(consumer);

   uvm_get_port #(int) get_port_h;
   int shared;
   function void build_phase(uvm_phase phase);
      get_port_h = new("get_port_h", this);
   endfunction : build_phase
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction : new
   task run_phase(uvm_phase phase);
      forever begin
         get_port_h.get(shared);
         $display("Received: %0d", shared);
      end
   endtask : run_phase
endclass : consumer

Connect using fifo

class communication_test extends uvm_test;
   `uvm_component_utils(communication_test)
   
   producer producer_h;
   consumer consumer_h;
   uvm_tlm_fifo #(int) fifo_h;
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction : new
   function void build_phase(uvm_phase phase);
      producer_h = new("producer_h", this);
      consumer_h = new("consumer_h", this);
      fifo_h = new("fifo_h",this);
   endfunction : build_phase
   function void connect_phase(uvm_phase phase);
      producer_h.put_port_h.connect(fifo_h.put_export);
      consumer_h.get_port_h.connect(fifo_h.get_export);
   endfunction : connect_phase
endclass : communication_test

The difference between uvm_tlm_fifo and uvm_analysis_fifo

Non-blocking mode

The blocking mode is suitable for the communication coordination between the threads where the producer and the consumer are both time-free;
when it comes to the clocking edge, you need to use try_put() and try_get();
try_put() and try_get() return a bit to tell you to put /get is successful;

try_get returns 1 to print; returns 0 to skip to the next clock edge;

class producer extends uvm_component;
   `uvm_component_utils(producer);
   int shared;
   uvm_put_port #(int) put_port_h;

   function void build_phase(uvm_phase phase);
      
      put_port_h = new("put_port_h", this);
   endfunction : build_phase
   task run_phase(uvm_phase phase);
      phase.raise_objection(this);
      repeat (3) begin
         #17;
         put_port_h.put(++shared);
         $display("%0tns  Sent %0d", $time, shared);
      end
      #17;
      phase.drop_objection(this);
   endtask : run_phase
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction : new

endclass : producer

class consumer extends uvm_component;
   `uvm_component_utils(consumer);

   uvm_get_port #(int) get_port_h;
   virtual clk_bfm clk_bfm_i;
   int shared;
   function void build_phase(uvm_phase phase);
      get_port_h = new("get_port_h", this);
      clk_bfm_i = example_pkg::clk_bfm_i;
   endfunction : build_phase
   task run_phase(uvm_phase phase);
      forever begin
         @(posedge clk_bfm_i.clk);
         if(get_port_h.try_get(shared))  //重点
           $display("%0tns  Received: %0d", $time,shared);
      end
   endtask : run_phase
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction : new
endclass : consumer

Insert picture description here

problem

This chapter uses producer and consumer to explain the communication coordination mechanism between threads;
but it does not explain why the monitor and scb in ch16 are the same thread;
the producer and consumer here are different threads;

Guess you like

Origin blog.csdn.net/weixin_39060517/article/details/113093319