[UVMC]UVM Connect基础教程

发布于:2022-12-16 ⋅ 阅读:(622) ⋅ 点赞:(0)

UVM Connect基础教程

--- Integrating SystemC into UVM

       前言:尽管 UVM 为构建参考模型提供了高级抽象,但 SystemC 在用于设计和验证的高级模型方面具有传统。 为了允许在 UVM 测试平台中重用使用 SystemC 编写的参考模型,UVMC 在 SystemC 和 SystemVerilog UVM 模型和组件之间提供 TLM1 和 TLM2 连接(参见图 1)。

               

Figure 1 - UVMC: SystemC and SystemVerilog sides

       对于 TLM 通信,验证组件必须同意它们正在交换的数据。 使用事务参数化这些组件使它们能够建立 UVMC 连接 [1]。 

一、一个例子

       为了说明 UVM Connect 的使用,将使用图 2 的测试平台作为示例。 与简单的加法器测试台不同,这个测试台没有监视器,也没有驱动程序,一旦检查的是模块refmod_low(用SystemC编写)的操作,在refmod(用SystemC编写的另一个模块)的操作中。

       两个 refmod 的操作都非常简单:它们只是获取来自 uvm_tlm_analysis_fifo 的 from_refmod 和 from_refmod_low 的事务(带有消息的字符串),并将这些事务分别放入 uvm_tlm_fifo 的 to_refmod 和 to_refmod_low 中。

       序列读取图 3 的树的文件,并且定序器将事务发送到 path_tr,其中使用 analysis_port 将其传输到 uvm_tlm_analysis_fifo 的 from_refmod 和 from_refmod_low。

 Figure 3 - Tree containing transactions for the sequence

       测试平台的代码及其 refmods 可以在下面看到。

  • The class packet_in that defines the input transaction
class packet_in extends uvm_sequence_item;
    string message;

    `uvm_object_utils_begin(packet_in)
        `uvm_field_string(message, UVM_DEFAULT|UVM_HEX)
    `uvm_object_utils_end

    function new(string name="packet_in");
        super.new(name);
    endfunction: new
endclass: packet_in
  •  The class packet_out that defines the output transaction
class packet_out extends uvm_sequence_item;
    string message;

    `uvm_object_utils_begin(packet_out)
        `uvm_field_string(message, UVM_DEFAULT|UVM_HEX)
    `uvm_object_utils_end

    function new(string name="packet_in");
        super.new(name);
    endfunction: new
endclass: packet_out
  •  The sequence_in that generates the transactions withe the DPI function read_message()
import "DPI-C" context function string read_message(string msg);

class sequence_in extends uvm_sequence #(packet_in);
    `uvm_object_utils(sequence_in)

    function new(string name="sequence_in");
        super.new(name);
    endfunction: new
    
    int data_file, scan_file;
    string filename;
    
    function void open_file();
      data_file = $fopen("myfile.txt", "r");
      if(data_file == 0)begin
         $display("file could not be open!!!");
      end
     endfunction: open_file
  
    task body();
        packet_in tr;
        open_file();
        while(1)begin
            scan_file = $fscanf(data_file, "%s", filename);
            tr = packet_in::type_id::create("tr");
            start_item(tr);
            tr.message = read_message(filename);
            finish_item(tr);
            if($feof(data_file))
                break;
        end
        $finish();
    endtask: body
endclass: sequence_in
  •  The DPI function called in the sequence_in
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

extern "C" const char* read_message(const char* message){
   string msg;
   ifstream myfile(message);
   if(myfile.is_open()){
      getline(myfile, msg);
      return msg.c_str();
   }
   else
     cout << "unable to open file";
}
  •  The sequencer that sends the transaction to the class path_tr
class sequencer extends uvm_sequencer #(packet_in);
    `uvm_component_utils(sequencer)

    function new (string name = "sequencer", uvm_component parent = null);
        super.new(name, parent);
    endfunction
endclass: sequencer
  • The class path_tr that trasmits the transaction to the uvm_tlm_analysis_fifo's from_refmod and from_refmod_low using an analysis_port
class path_tr extends uvm_driver #(packet_in);
    packet_in tr;
   
    `uvm_component_utils(path_tr)
    uvm_analysis_port #(packet_in) item_collected_port;
    
   function new(string name, uvm_component parent);
        super.new(name, parent);
        item_collected_port = new ("item_collected_port", this);
    endfunction
    
    virtual task run_phase(uvm_phase phase);
      forever begin
        seq_item_port.get_next_item(tr);
        begin_tr(tr, "path_tr");
          item_collected_port.write(tr);
        end_tr(tr);
        seq_item_port.item_done();
      end
    endtask
endclass: path_tr
  •  The refmod (written in SystemC)
#include "systemc.h"
#include "tlm.h"
#include <string>

using namespace std;

using namespace tlm;

struct tr {
  string message;
};

#include "uvmc.h"
using namespace uvmc;
UVMC_UTILS_1(tr, message)


SC_MODULE(refmod) {
  sc_port<tlm_get_peek_if<tr> > in;
  sc_port<tlm_put_if<tr> > out;

  void p() {
    
    tr tr;
    while(1){
      tr = in->get();
      cout <<"refmod: " <<tr.message <<"\n";
      out->put(tr);
    }
  }
  SC_CTOR(refmod): in("in"), out("out") { SC_THREAD(p); }
};
  • The refmod_low (written in SystemC)
SC_MODULE(refmod_low){
  sc_port<tlm_get_peek_if<tr> > in;
  sc_port<tlm_put_if<tr> > out;

  void p() {
    
    tr tr;
    while(1){
      tr = in->get();
      cout <<"refmod_low: " <<tr.message <<"\n";
      out->put(tr);
    }
  }
  SC_CTOR(refmod_low): in("in"), out("out") { SC_THREAD(p); }
};
  •  The sc_main (file top.cpp) for making connections on the SystemC side
#include "refmod.cpp"
#include "refmod_low.cpp"

int sc_main(int argc, char* argv[]) {
 
  refmod  refmod_i("refmod_i");
  refmod_low refmod_low_i("refmod_low_i");
  
  uvmc_connect(refmod_i.in, "refmod_i.in");
  uvmc_connect(refmod_low_i.in, "refmod_low_i.in");
  uvmc_connect(refmod_i.out, "refmod_i.out");
  uvmc_connect(refmod_low_i.out, "refmod_low_i.out");

  sc_start();
  return(0);
}
  •  The class comparator that expects transactions from the outputs of the refmod and refmod_low in order to compare them
class comparator #(type T = packet_in) extends uvm_scoreboard;
   typedef comparator #(T) this_type;
   `uvm_component_utils(this_type)
    
    uvm_tlm_fifo #(T) from_refmod;
    uvm_tlm_fifo#(T) from_refmod_low;    
    
     T tr1, tr2;
     int match, mismatch;

    function new(string name, uvm_component parent);
      super.new(name, parent);
      from_refmod = new("from_refmod", null, 1); 
      from_refmod_low = new("from_refmod_low", null, 1);
      tr1 = new("tr1");
      tr2 = new("tr2");
    endfunction
 
    function void connect_phase(uvm_phase phase);
        uvmc_tlm1 #(T)::connect(from_refmod.put_export, "refmod_i.out");
        uvmc_tlm1#(T)::connect(from_refmod_low.put_export, "refmod_low_i.out");
    endfunction: connect_phase
   
    task run_phase(uvm_phase phase);
      forever begin
        from_refmod.get(tr1);
        from_refmod_low.get(tr2);
        compare();
      end
    endtask: run_phase

    virtual function void compare();
      if(tr1.message == tr2.message) begin
        $display("Comparator MATCH");
        match++;
      end
      else begin
        $display("Comparator MISMATCH");
        mismatch++;
      end
    endfunction: compare
   
endclass: comparator
  •  The environment class
`include "comparator.sv"
 
class env extends uvm_env;
    sequencer sqr;
    path_tr path;
    comparator #(packet_out) comp;

    uvm_tlm_analysis_fifo #(packet_in) to_refmod;
    uvm_tlm_analysis_fifo #(packet_in) to_refmod_low;

    `uvm_component_utils(env)

    function new(string name, uvm_component parent = null);
        super.new(name, parent);       
        to_refmod = new("to_refmod", this);
        to_refmod_low = new("to_refmod_low", this);
    endfunction

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        sqr = sequencer::type_id::create("sqr", this);
        path = path_tr::type_id::create("path", this);
        comp = comparator #(packet_out)::type_id::create("comp", this);
    endfunction

    virtual function void connect_phase(uvm_phase phase);
        path.seq_item_port.connect(sqr.seq_item_export);
        path.item_collected_port.connect(to_refmod.analysis_export);
        uvmc_tlm1 #(packet_in)::connect(to_refmod.get_export, "refmod_i.in");

        path.item_collected_port.connect(to_refmod_low.analysis_export);
        uvmc_tlm1 #(packet_in)::connect(to_refmod_low.get_export, "refmod_low_i.in");
    endfunction

    virtual function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
    endfunction
  
endclass
  •  The test class
class test extends uvm_test;
  env env_h;
  sequence_in seq;

  `uvm_component_utils(test)

  function new(string name, uvm_component parent = null);
    super.new(name, parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env_h = env::type_id::create("env_h", this);
    seq = sequence_in::type_id::create("seq", this);
  endfunction
 
  task run_phase(uvm_phase phase);
    seq.start(env_h.sqr);
  endtask: run_phase

endclass: test
  •  The top module(top.sv)
import uvm_pkg::*;
import uvmc_pkg::*;

`include "uvm_macros.svh"
`include "packet_in.sv"
`include "packet_out.sv"
`include "sequence_in.sv"
`include "sequencer.sv"
`include "path_tr.sv"
`include "env.sv"
`include "test.sv"

//Top
module top;
  
  initial begin
    `ifdef INCA
       $recordvars();
    `endif
    `ifdef VCS
       $vcdpluson;
    `endif
    `ifdef QUESTA
       $wlfdumpvars();
       set_config_int("*", "recording_detail", 1);
    `endif
    
    run_test("test");
  end
endmodule
  •  在顶部模块中,应导入 uvm 连接包(import uvmc_pkg::*;)。 图 4 显示了 refmod 和 refmod_low(SystemC 端)与比较器(SystemVerilog 端)之间的连接。

  • SystemC端的连接可以在sc_main的以下几行中看到:
uvmc_connect(refmod_i.out, "refmod_i.out");
uvmc_connect(refmod_low_i.out, "refmod_low_i.out");
  •  SystemVerilog 端的连接可以在比较器的以下行中看到:
function void connect_phase(uvm_phase phase);
        uvmc_tlm1 #(T)::connect(from_refmod.put_export, "refmod_i.out");
        uvmc_tlm1#(T)::connect(from_refmod_low.put_export, "refmod_low_i.out");
endfunction: connect_phase

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到