uvm_primer ch16は、テストベンチでanalysis_portを使用します-シングルスレッド通信

uvm_primer ch16は、テストベンチでanalysis_portを使用します

この章では、analysis_portを使用して、異なるオブジェクト間の内部通信をシングルスレッドの一例である
観察モードは、モニタ接続の使用に適している
ここに画像の説明を挿入
インターフェースのハンドルを追加し、この使用前に使用されていない;
界面にimport tinyalu_pkg::*;

interface tinyalu_bfm;
   import tinyalu_pkg::*;
   command_monitor command_monitor_h;  //定义句柄
   result_monitor  result_monitor_h;
   byte         unsigned        A;
   byte         unsigned        B;
   bit          clk;
   bit          reset_n;
   wire [2:0]   op;
   bit          start;
   wire         done;
   wire [15:0]  result;
   operation_t  op_set;
   
   assign op = op_set;

   task reset_alu();
      reset_n = 1'b0;
      @(negedge clk);
      @(negedge clk);
      reset_n = 1'b1;
      start = 1'b0;
   endtask : reset_alu
  ...
   always @(posedge clk) begin : cmd_monitor
      bit new_command;
      if (!start) 
        new_command = 1;
      else
        if (new_command) begin 
           command_monitor_h.write_to_monitor(A, B, op);   //重点
           new_command = (op == 3'b000); // handle no_op
        end 
   end : cmd_monitor

   always @(negedge reset_n) begin : rst_monitor
      command_monitor_h.write_to_monitor(A, B, rst_op);
   end : rst_monitor
   
   always @(posedge clk) begin : rslt_monitor
         if (done) 
           result_monitor_h.write_to_monitor(result);
   end : rslt_monitor
....
  endinterface 

pkgにすべてのコンポーネントを含めます。

package tinyalu_pkg;
   import uvm_pkg::*;
`include "uvm_macros.svh"
   
      typedef enum bit[2:0] {
    
    no_op  = 3'b000,
                          add_op = 3'b001, 
                          and_op = 3'b010,
                          xor_op = 3'b011,
                          mul_op = 3'b100,
                          rst_op = 3'b111} operation_t;
   typedef struct {
    
    
      byte unsigned        A;
      byte unsigned        B;
      operation_t op;
   } command_s;
`include "coverage.svh"
`include "base_tester.svh"
`include  "random_tester.svh"
`include "add_tester.svh"   
`include "scoreboard.svh"
`include "command_monitor.svh"
`include "result_monitor.svh"
   
`include "env.svh"

`include "random_test.svh"
`include "add_test.svh"
   
endpackage : tinyalu_pkg

モニターのインターフェースのハンドルにオブジェクトを割り当てます

class command_monitor extends uvm_component;
   `uvm_component_utils(command_monitor);
  uvm_analysis_port #(command_s) ap;//重点
 
  function void build_phase(uvm_phase phase);
    virtual tinyalu_bfm bfm;
    if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
       $fatal("Failed to get BFM");
    bfm.command_monitor_h = this;  //连接句柄和对象
    ap  = new("ap",this);//重点
  endfunction : build_phase

  function void write_to_monitor(byte A, byte B, bit[2:0] op);
    command_s cmd;
    cmd.A = A;
    cmd.B = B;
    cmd.op = op2enum(op);
    $display("COMMAND MONITOR: A:0x%2h B:0x%2h op: %s", A, B, cmd.op.name());
    ap.write(cmd);  //重点
  endfunction : write_to_monitor
   function operation_t op2enum(bit[2:0] op);
      case(op)
        3'b000 : return no_op;
        3'b001 : return add_op;
        3'b010 : return and_op;
        3'b011 : return xor_op;
        3'b100 : return mul_op;
        3'b111 : return rst_op;
        default : $fatal($sformatf("Illegal operation on op bus: %3b",op));
      endcase // case (op)
   endfunction : op2enum
   function new (string name, uvm_component parent);
      super.new(name,parent);
   endfunction
endclass : command_monitor

カバレッジ

class coverage extends uvm_subscriber #(command_s);//重点
   `uvm_component_utils(coverage)
   byte         unsigned        A;
   byte         unsigned        B;
   operation_t  op_set;
   covergroup op_cov;
      coverpoint op_set {
    
    
         bins single_cycle[] = {
    
    [add_op : xor_op], rst_op,no_op};
         bins multi_cycle = {
    
    mul_op};
         bins opn_rst[] = ([add_op:no_op] => rst_op);
         bins rst_opn[] = (rst_op => [add_op:no_op]);
         bins sngl_mul[] = ([add_op:xor_op],no_op => mul_op);
         bins mul_sngl[] = (mul_op => [add_op:xor_op], no_op);
         bins twoops[] = ([add_op:no_op] [* 2]);
         bins manymult = (mul_op [* 3:5]);
         bins rstmulrst   = (rst_op => mul_op [=  2] => rst_op);
         bins rstmulrstim = (rst_op => mul_op [-> 2] => rst_op);
      }
   endgroup
   function new (string name, uvm_component parent);
      super.new(name, parent);
      op_cov = new();
      zeros_or_ones_on_ops = new();
   endfunction : new
//因为extend uvm_subscriber, 包含了analysis_export
   function void write(command_s t);//重点  通过write函数得到A B op
         A = t.A;
         B = t.B;
         op_set = t.op;
         op_cov.sample();
         zeros_or_ones_on_ops.sample();
   endfunction : write

endclass : coverage

複数のanalysis_portsにサブスクライブする必要があります

この問題を解決するには、uvm_tlm_analysis_fifoを使用します

uvm_tlm_analysis_fifoの一方の端にはanalysis_exportがあり、もう一方の端にはtry_get()メソッドがあります。try_get()を使用してfifoからデータをフェッチします。fifoが空の場合は0を返します。

class scoreboard extends uvm_subscriber #(shortint);
   `uvm_component_utils(scoreboard);
   uvm_tlm_analysis_fifo #(command_s) cmd_f;
   function void build_phase(uvm_phase phase);
      cmd_f = new ("cmd_f", this);
   endfunction : build_phase
   function void write(shortint t);  //重点  取shortint
      shortint predicted_result;
      command_s cmd; 
      cmd.op = no_op;
      do
      //重点  取 command_s
       if (!cmd_f.try_get(cmd)) $fatal(1, "No command in self checker");  
      while ((cmd.op == no_op) || (cmd.op == rst_op));
      case (cmd.op)
        add_op: predicted_result = cmd.A + cmd.B;
        and_op: predicted_result = cmd.A & cmd.B;
        xor_op: predicted_result = cmd.A ^ cmd.B;
        mul_op: predicted_result = cmd.A * cmd.B;
      endcase // case (op_set)

      if (predicted_result != t)
       $error (
     "FAILED: A: %2h  B: %2h  op: %s actual result: %4h   expected: %4h",
         cmd.A, cmd.B, cmd.op.name(), t,  predicted_result);
   endfunction : write         
   function new (string name, uvm_component parent);
      super.new(name, parent);
   endfunction : new
endclass : scoreboard

モニターを接続する

class env extends uvm_env;
   `uvm_component_utils(env);
   function void connect_phase(uvm_phase phase);
      
      result_monitor_h.ap.connect(scoreboard_h.analysis_export);
      command_monitor_h.ap.connect(scoreboard_h.cmd_f.analysis_export);  //连接fifo
      command_monitor_h.ap.connect(coverage_h.analysis_export);

   endfunction : connect_phase
   endclass

uvm_analysis_portを使用して、さまざまなオブジェクトを接続します。これは、スレッド内の通信メカニズム(トレッド内)です。
関数呼び出しはスレッド内で発生します。cmd_monitorが常にwrite_to_monitor()を呼び出す場合、呼び出しは同じスレッドのサブスクライバーへの書き込みです( )関数;

おすすめ

転載: blog.csdn.net/weixin_39060517/article/details/113091878