前言:尽管 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 可以在下面看到。
- 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
- 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
- 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
- #include
- #include
- #include
- #include
-
- 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";
- }
- 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
- 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
- #include "systemc.h"
- #include "tlm.h"
- #include
-
- 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
> in; - sc_port
> out; -
- void p() {
-
- tr tr;
- while(1){
- tr = in->get();
- cout <<"refmod: " <
"\n"; - out->put(tr);
- }
- }
- SC_CTOR(refmod): in("in"), out("out") { SC_THREAD(p); }
- };
- SC_MODULE(refmod_low){
- sc_port
> in; - sc_port
> out; -
- void p() {
-
- tr tr;
- while(1){
- tr = in->get();
- cout <<"refmod_low: " <
"\n"; - out->put(tr);
- }
- }
- SC_CTOR(refmod_low): in("in"), out("out") { SC_THREAD(p); }
- };
- #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);
- }
- 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
- `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
- 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
- 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

- uvmc_connect(refmod_i.out, "refmod_i.out");
- uvmc_connect(refmod_low_i.out, "refmod_low_i.out");
- 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