【IC每日一题:IC验证面试--UVM验证-2】

IC每日一题:IC验证面试--UVM验证-2

    • 2.9 get_next_iterm()和try_next_item()的区别?
    • 2.10 一个典型的UVM验证平台,谈一下UVM验证环境结构,各个组件之间的关系?
    • 2.11 uvm组件之间通信的方式? analysis_port和其他的区别?analysis_port是否可以不连或者连接多个import?
    • 2.12 uvm_tlm_anlysis_fifo类是什么,有什么端口?
    • 2.13 UVM组件中常用的方法,各种phase关系,phase机制?
    • 2.14 phase中的domain概念
    • 2.15 run_phase和main_phase之间的关系?
    • 2.16 UVM组件的通信方式TLM的接口分类和用法,peek和get的差异;
    • 2.17 sequence和item(uvm_sequence, uvm_sequence_item)的分类;
    • 2.18 为什么会有sequence,sequencer以及driver,为什么我们分开实现,这样做的好处是什么?
    • 2.19 如何在driver中使用interface?
    • 2.20 config_db的作用以及传递其使用时的参数含义

【博客首发与微信公众号《漫谈芯片与编程》,欢迎专注一下】
本篇博客开始介绍IC验证基本功–UVM-2的相关问题;

2.9 get_next_iterm()和try_next_item()的区别?

get_next_item() 和 try_next_item() 是 uvm_sequencer 类提供的两个方法,用于从 sequencer 中获取下一个transaction。
get_next_item()–阻塞调用:
这个方法会阻塞当前的执行线程,直到 sequencer 中有可用的 item。如果 sequencer 中没有 item,调用 get_next_item() 的线程会一直等待,直到有 item 被放入 sequencer。一旦获取到 item,get_next_item() 会返回这个 item,并且调用者可以继续执行。

task run_phase(uvm_phase phase);forever beginseq_item_port.get_next_item(req);  // 阻塞调用,直到有新的事务可用drive(req);  // 处理事务seq_item_port.item_done();  // 通知序列器事务已完成end
endtask

try_next_item()–非阻塞调用
当驱动器调用 try_next_item() 时,如果当前没有可用的事务,它会立即返回,不会阻塞。try_next_item() 返回一个布尔值,表示是否成功获取到事务。

task run_phase(uvm_phase phase);forever beginif (seq_item_port.try_next_item(req)) {  // 非阻塞调用drive(req);  // 处理事务seq_item_port.item_done();  // 通知序列器事务已完成} else {// 没有事务时执行其他任务do_something_else();}end
endtask

典型应用场景:

  • get_next_item():当你希望驱动器总是等待事务并按顺序处理时,使用 get_next_item()。这是最常见的用法,特别是在简单的驱动器实现中。
  • try_next_item():当你希望驱动器在没有事务时能够执行其他任务,或者在多事务流场景下需要灵活处理时,使用 try_next_item()。这在需要更高的响应性和灵活性的场景中非常有用

2.10 一个典型的UVM验证平台,谈一下UVM验证环境结构,各个组件之间的关系?

UVM验证环境的基本组成:
环境(uvm_env):包含所有验证组件。
代理(uvm_agent):包含驱动器、监视器和序列器,与DUT进行交互。
驱动器(uvm_driver):将事务转换为信号,驱动到DUT。
监视器(uvm_monitor):监控DUT的输入和输出,并将信号转换为事务。
序列器(uvm_sequencer):从序列中获取事务并传递给驱动器。
序列(uvm_sequence):生成事务。
参考模型 (reference_model): 参考模型是一个功能性的模型,它独立于DUT实现同样的功能,参考模型的输出可以用来与DUT的实际输出进行比较,从而判断DUT的功能是否正确。
记分板(uvm_scoreboard):检查DUT的输出是否符合预期。
虚拟接口(virtual interface):连接UVM组件与DUT。
寄存器模型(uvm_reg_block):描述DUT中的寄存器和寄存器块。

在这里重点介绍一下参考模型的Demo:

class my_reference_model extends uvm_component;`uvm_component_utils(my_reference_model)uvm_analysis_imp #(my_transaction, my_reference_model) imp;function new(string name, uvm_component parent);super.new(name, parent);imp = new("imp", this);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctionfunction void write(my_transaction tr);// 执行与DUT相同的操作// 例如:计算期望的结果my_transaction exp_tr = tr.clone();exp_tr.data = perform_function(tr.data);  // 假设有一个函数 perform_function// 将期望的结果发送到记分板`uvm_info("REF_MODEL", $sformatf("Expected data: %h", exp_tr.data), UVM_HIGH)// 这里假设记分板已经连接到了参考模型的分析端口endfunction// 假设这是一个简单的函数,模拟DUT的功能function bit [7:0] perform_function(bit [7:0] input_data);// 实现一些功能,例如简单的加法return input_data + 1;endfunctionendclassclass my_scoreboard extends uvm_scoreboard;`uvm_component_utils(my_scoreboard)uvm_analysis_imp #(my_transaction, my_scoreboard) imp;uvm_tlm_analysis_fifo #(my_transaction) exp_fifo;function new(string name, uvm_component parent);super.new(name, parent);imp = new("imp", this);exp_fifo = new("exp_fifo", this);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctionfunction void write(my_transaction tr);// 将DUT的实际输出放入FIFOimp.write(tr);endfunctionfunction void check_phase(uvm_phase phase);my_transaction act_tr, exp_tr;while (exp_fifo.try_get(exp_tr)) beginif (!imp.get(act_tr)) begin`uvm_error("SB", "No actual transaction to compare with expected")continue;endif (act_tr.data !== exp_tr.data) begin`uvm_error("SB", $sformatf("Data mismatch: Expected %h, Actual %h", exp_tr.data, act_tr.data))end else begin`uvm_info("SB", $sformatf("Data match: %h", act_tr.data), UVM_HIGH)endendendfunction
endclassclass my_env extends uvm_env;`uvm_component_utils(my_env)my_agent agent;my_scoreboard scoreboard;my_reference_model ref_model;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);agent = my_agent::type_id::create("agent", this);scoreboard = my_scoreboard::type_id::create("scoreboard", this);ref_model = my_reference_model::type_id::create("ref_model", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);agent.monitor.ap.connect(scoreboard.imp);agent.monitor.ap.connect(ref_model.imp);endfunctionendclass

2.11 uvm组件之间通信的方式? analysis_port和其他的区别?analysis_port是否可以不连或者连接多个import?

UVM组件之间的通信方式:
1.TLM ports and exports:
uvm_port 和 uvm_export: 用于请求-响应式的通信。例如,uvm_blocking_put_port 和 uvm_blocking_get_port。
uvm_analysis_port 和 uvm_analysis_imp: 用于单向数据流的通信,主要用于监控和收集数据。

2.Phases and Callbacks
通过 UVM 的 phase 机制,可以在特定的 phase 中进行组件间的通信。回调(callbacks)也可以用于在特定事件发生时进行通信。

3.uvm_config_db
通过 uvm_config_db 机制,可以在组件之间传递配置信息;

uvm_analysis_port可以不连接任何uvm_analysis_imp–这种情况下,发送的数据将被忽略
uvm_analysis_port可以连接多个uvm_analysis_imp,允许多个组件同时接收相同的数据;是通过uvm_analysis_port::connect方法来实现的

uvm_analysis_port和uvm_analysis_imp的实现示例:


// 定义一个简单的事务类
class my_transaction extends uvm_sequence_item;rand int data;`uvm_object_utils(my_transaction)function new(string name = "my_transaction");super.new(name);endfunction
endclass// 定义一个产生事务的组件
class producer extends uvm_component;`uvm_component_utils(producer)uvm_analysis_port #(my_transaction) ap;function new(string name, uvm_component parent);super.new(name, parent);ap = new("ap", this);endfunctiontask run_phase(uvm_phase phase);my_transaction tr;tr = my_transaction::type_id::create("tr");tr.randomize();ap.write(tr);  // 将事务发送到分析端口endtask
endclass// 定义一个接收事务的组件
class consumer extends uvm_component;`uvm_component_utils(consumer)uvm_analysis_imp #(my_transaction, consumer) imp;function new(string name, uvm_component parent);super.new(name, parent);imp = new("imp", this);endfunctionfunction void write(my_transaction t);`uvm_info("CONSUMER", $sformatf("Received data: %0d", t.data), UVM_HIGH)endfunction
endclass// 定义顶层环境
class env extends uvm_env;`uvm_component_utils(env)producer prod;consumer cons1, cons2;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);prod = producer::type_id::create("prod", this);cons1 = consumer::type_id::create("cons1", this);cons2 = consumer::type_id::create("cons2", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);prod.ap.connect(cons1.imp);  // 连接到第一个消费者prod.ap.connect(cons2.imp);  // 连接到第二个消费者endfunction
endclass// 测试用例
module top;initial beginrun_test();end
endmodule

2.12 uvm_tlm_anlysis_fifo类是什么,有什么端口?

uvm_tlm_analysis_fifo 是 UVM(Universal Verification Methodology)提供的一个类,它结合了 TLM(Transaction Level Modeling)和 FIFO(First-In-First-Out)的功能,用于在验证环境中存储和转发事务。这个类特别适用于需要缓存事务数据的场景,例如在监控器和记分板之间传递数据。
uvm_tlm_analysis_fifo的主要端口:

  • uvm_analysis_imp:
    用于接收事务数据。这是一个单向的数据流,通常用于监控器将数据发送到 FIFO。
  • uvm_get_port:
    用于从 FIFO 中取出事务数据。这是一个请求-响应式的端口,通常用于记分板或其他组件从 FIFO 中获取数据

使用uvm_tlm_analysis_fifo的端口:

//==transaction
class my_transaction extends uvm_sequence_item;rand int data;`uvm_object_utils(my_transaction)function new(string name = "my_transaction");super.new(name);endfunction
endclass//==monitor
class my_monitor extends uvm_monitor;`uvm_component_utils(my_monitor)uvm_analysis_port #(my_transaction) ap;virtual my_if vif;function new(string name, uvm_component parent);super.new(name, parent);ap = new("ap", this);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("NOVIF", "Failed to get vif")endfunctiontask run_phase(uvm_phase phase);my_transaction tr;forever begin@(posedge vif.clk);if (vif.valid && vif.ready) begintr = my_transaction::type_id::create("tr");tr.data = vif.data;ap.write(tr);  // 将事务发送到分析端口endendendtask
endclass//==scoreboard
class my_scoreboard extends uvm_scoreboard;`uvm_component_utils(my_scoreboard)uvm_tlm_analysis_fifo #(my_transaction) fifo;function new(string name, uvm_component parent);super.new(name, parent);fifo = new("fifo", this);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctiontask run_phase(uvm_phase phase);my_transaction tr;forever beginfifo.get(tr);  // 从 FIFO 中取出事务`uvm_info("SCOREBOARD", $sformatf("Received data: %0d", tr.data), UVM_HIGH)endendtask
endclass//==env
class my_env extends uvm_env;`uvm_component_utils(my_env)my_monitor monitor;my_scoreboard scoreboard;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);monitor = my_monitor::type_id::create("monitor", this);scoreboard = my_scoreboard::type_id::create("scoreboard", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);monitor.ap.connect(scoreboard.fifo.analysis_export);  // 连接监控器和 FIFOendfunction
endclass//==test
class my_test extends uvm_test;`uvm_component_utils(my_test)my_env env;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);env = my_env::type_id::create("env", this);endfunction
endclass//==module
module top;initial beginrun_test("my_test");end
endmodule

uvm_tlm_analysis_fifo 可以有效地在监控器和记分板之间传递和缓存事务数据。

2.13 UVM组件中常用的方法,各种phase关系,phase机制?

组件的生命周期是通过一系列的phase来管理的。这些phase包括构建阶段(Build Phase)、连接阶段(Connect Phase)、运行阶段(Run Phase)等。
new():构造函数,用于创建组件实例。
build_phase():构建阶段,用于创建和配置组件的子组件。
connect_phase():连接阶段,用于连接组件之间的端口和接口。
pre_run_phase():在仿真运行之前的一些配置准备阶段;
run_phase():运行阶段,执行组件的主要功能,如发送事务、接收事务等。
report_phase():仿真结束后,报告阶段,用于生成验证结果的报告。

Phase机制:UVM的phase机制是通过一个全局的phase控制器来管理的。这个控制器负责调度和执行各个phase。在每个phase开始时,控制器会调用所有组件的相应phase方法。组件可以通过重载这些方法来实现自定义的行为。

function new(string name, uvm_component parent);super.new(name, parent);
endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);// 创建子组件my_child = my_child::type_id::create("my_child", this);
endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);// 连接端口my_child.my_port.connect(my_other_child.my_export);
endfunctionfunction void start_of_simulation_phase(uvm_phase phase);super.start_of_simulation_phase(phase);// 初始化某些全局变量global_var = 0;
endfunctiontask run_phase(uvm_phase phase);super.run_phase(phase);// 生成激励repeat (10) beginmy_transaction tr = my_transaction::type_id::create("tr");tr.randomize();my_sequencer.starting_sequence.put(tr);end
endtaskfunction void report_phase(uvm_phase phase);super.report_phase(phase);// 生成报告uvm_report_server::get_server().write_report_messages();
endfunction

2.14 phase中的domain概念

domain 是一个用于管理和同步不同时钟域之间的信号和事件的概念。在不同的模块可能运行在不同的时钟频率上,这就需要一种机制来确保跨时钟域的信号传输和事件处理是正确和可靠的;
domain 通常与 clocking block 一起使用,clocking block 是一种特殊的代码块,用于描述信号在时钟边沿上的行为。通过将信号声明在 clocking block 中,可以确保信号的采样和驱动是同步的,并且符合特定的时钟约束。

// 定义一个时钟域
clocking cb @(posedge clk);input  data;output ack;
endclocking// 在组件中使用时钟域
class MyComponent extends uvm_component;virtual clocking cb;function new(string name, uvm_component parent);super.new(name, parent);// 初始化时钟域cb = new("cb", this);endfunctiontask run_phase(uvm_phase phase);forever begin// 在时钟上升沿采样输入数据@(cb);data = cb.data;// 处理数据//...// 在时钟上升沿驱动输出信号cb.ack <= 1'b1;@(cb);cb.ack <= 1'b0;endendtask
endclass

在这个示例中,clocking block cb 定义了一个时钟域,其中包含一个输入信号 data 和一个输出信号 ack。在 MyComponent 类中,run_phase 任务使用 @(cb) 来等待时钟上升沿,然后采样输入数据并驱动输出信号。

2.15 run_phase和main_phase之间的关系?

run_phase和main phase(动态运行)都是task phase,且是并行运行的,后者称为动态运行(run-time)的phase。
如果想执行一些耗费时间的代码,那么要在此phase下任意一个component中至少提起一次objection,这个结论只适用于12个run-time的phase。对于run_phase则不适用,由于run_phase与动态运行的phase是并行运行的,如果12个动态运行的phase有objection被提起,那么run_phase根本不需要raise_objection就可以自动执行。

2.16 UVM组件的通信方式TLM的接口分类和用法,peek和get的差异;

事务级建模(Transaction Level Modeling,TLM)是一种用于在验证环境中进行组件间通信的方法。TLM 接口和方法提供了一种标准化的方式来实现组件之间的通信。
UVM提供的TLM接口分类:put/get 接口和 analysis 接口;

put/get 接口:
uvm_put_port/uvm_put_imp:
用于将数据从一个组件传递到另一个组件,发送方不需要接收方的响应。
uvm_get_port/uvm_get_imp:
用于从另一个组件请求数据,发送方需要接收方的响应。
uvm_peek_port/uvm_peek_imp:
用于查看另一个组件中的数据,但不移除数据。类似于 get,但不会消耗数据。
uvm_transport_port/uvm_transport_imp:
用于双向通信,发送方发送数据并接收响应。
analysis 接口:
uvm_analysis_port/uvm_analysis_imp:
用于单向数据流,通常用于监控和收集数据。发送方不需要接收方的响应。

class my_transaction extends uvm_sequence_item;rand int data;`uvm_object_utils(my_transaction)function new(string name = "my_transaction");super.new(name);endfunction
endclassclass producer extends uvm_component;`uvm_component_utils(producer)uvm_put_port #(my_transaction) put_port;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);put_port = new("put_port", this);endfunctiontask run_phase(uvm_phase phase);my_transaction tr;tr = my_transaction::type_id::create("tr");tr.randomize();put_port.put(tr);  // 将事务发送到 put_portendtask
endclassclass consumer extends uvm_component;`uvm_component_utils(consumer)uvm_get_imp #(my_transaction, consumer) get_imp;function new(string name, uvm_component parent);super.new(name, parent);get_imp = new("get_imp", this);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctionfunction void get(my_transaction tr);`uvm_info("CONSUMER", $sformatf("Received data: %0d", tr.data), UVM_HIGH)endfunction
endclassclass my_env extends uvm_env;`uvm_component_utils(my_env)producer prod;consumer cons;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);prod = producer::type_id::create("prod", this);cons = consumer::type_id::create("cons", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);prod.put_port.connect(cons.get_imp);  // 连接 put_port 和 get_impendfunction
endclassclass my_test extends uvm_test;`uvm_component_utils(my_test)my_env env;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);env = my_env::type_id::create("env", this);endfunction
endclassmodule top;initial beginrun_test("my_test");end
endmodule

【总结】
put/get 接口:用于组件之间的数据传递。put 用于发送数据,get 用于接收数据并消耗数据。peek 用于查看数据但不消耗数据。
analysis 接口:用于单向数据流,通常用于监控和收集数据。uvm_analysis_port 用于发送数据,uvm_analysis_imp 用于接收数据。

2.17 sequence和item(uvm_sequence, uvm_sequence_item)的分类;

uvm_sequence_item(transaction)

uvm_sequence_item 是 UVM 中表示单个事务的基本类。uvm_sequence_item 类通常包含事务的数据字段,如地址、数据、命令类型等。事务类可以包含随机化约束,用于生成符合特定条件的事务。

class my_transaction extends uvm_sequence_item;rand bit [31:0] address;rand bit [⅛:0] data;rand bit [2:0] command;constraint c_address {address inside { [0:1023] };}constraint c_data {data dist { [0:255] := 7, [256:511] := ˜3 };}constraint c_command {command inside { READ, WRITE, NOP };}`uvm_object_utils_begin(my_transaction)`uvm_field_int(address, UVM_DEFAULT)`uvm_field_int(data, UVM_DEFAULT)`uvm_field_int(command, UVM_DEFAULT)`uvm_object_utils_endfunction new(string name = "my_transaction");super.new(name);endfunction
endclass

uvm_sequence
uvm_sequence 是 UVM 中用于控制事务生成和发送的类。它负责创建事务并将其发送到 uvm_sequencer,后者再将事务传递给 uvm_driver。

class read_sequence extends uvm_sequence #(read_transaction);`uvm_object_utils(read_sequence)function new(string name = "read_sequence");super.new(name);endfunctionvirtual task body();read_transaction tr;repeat (10) begin`uvm_do(tr)  // 生成并发送读事务endendtask
endclassclass write_sequence extends uvm_sequence #(write_transaction);`uvm_object_utils(write_sequence)function new(string name = "write_sequence");super.new(name);endfunctionvirtual task body();write_transaction tr;repeat (10) begin`uvm_do(tr)  // 生成并发送写事务endendtask
endclassclass mixed_sequence extends uvm_sequence #(read_transaction, write_transaction);`uvm_object_utils(mixed_sequence)function new(string name = "mixed_sequence");super.new(name);endfunctionvirtual task body();read_transaction read_tr;write_transaction write_tr;repeat (5) begin`uvm_do(read_tr)  // 生成并发送读事务`uvm_do(write_tr)  // 生成并发送写事务endendtask
endclass

【总结】
item 是事务的基本单元,包含了验证环境中事务的最小信息。
sequence 是一系列 item 的集合,用于构建和管理验证环境中的测试场景。
通过合理地分类和设计 uvm_sequence 和 uvm_sequence_item,从而可以构建灵活且高效的激励生成机制,提高验证平台的可重用性和可维护性;

2.18 为什么会有sequence,sequencer以及driver,为什么我们分开实现,这样做的好处是什么?

首先介绍一下各自的职责:
sequence:负责生成事务(transaction),并将其发送到sequencer。sequence可以包含复杂的逻辑,如随机化、条件分支等,以生成多样化的测试场景。
sequencer:作为sequence和driver之间的桥梁,负责接收sequence发送的事务,并将其转发给driver。sequencer还可以对事务进行仲裁和调度,确保事务按照正确的顺序和时间发送给driver。
driver:负责将接收到的事务转换为实际的信号电平,并驱动到DUT(Device Under Test)的接口上。driver通常与DUT的接口协议紧密相关,需要实现具体的信号驱动逻辑。

好处:
1.职责单一:
事务生成与硬件驱动分离:sequence 专注于事务生成,而 driver 专注于硬件驱动。这种分离使得事务生成逻辑和硬件驱动逻辑可以独立开发和调试。
仲裁与调度:sequencer 负责事务的仲裁和调度,使得 sequence 和 driver 不必关心这些细节。这种分离使得 sequence 和 driver 可以专注于各自的核心功能。
2.灵活性和可拓展性:
可以轻松地添加新的 sequence 来生成不同的激励模式。
可以通过配置 sequencer 来改变事务的调度策略。
可以通过嵌套 sequence 来构建复杂的激励模式。
可以通过添加新的 driver 来支持不同的 DUT 接口。
3.易于调试和维护:
隔离问题:
如果某个组件出现问题,可以单独调试该组件,而不影响其他组件。
清晰的责任划分:
每个组件都有明确的职责,使得问题定位更加容易。
代码简洁:
每个组件的代码量相对较少,使得代码更加简洁和易于阅读。

//====transaction
class my_transaction extends uvm_sequence_item;rand bit [31:0] address;rand bit [⅛:0] data;rand bit [2:0] command;`uvm_object_utils_begin(my_transaction)`uvm_field_int(address, UVM_DEFAULT)`uvm_field_int(data, UVM_DEFAULT)`uvm_field_int(command, UVM_DEFAULT)`uvm_object_utils_endfunction new(string name = "my_transaction");super.new(name);endfunction
endclass//==sequence
class my_sequence extends uvm_sequence #(my_transaction);`uvm_object_utils(my_sequence)function new(string name = "my_sequence");super.new(name);endfunctionvirtual task body();my_transaction tr;repeat (10) begintr = my_transaction::type_id::create("tr");start_item(tr);assert(tr.randomize() with { address inside {[0:1023]}; });finish_item(tr);endendtask
endclass//==driver
class my_driver extends uvm_driver #(my_transaction);`uvm_component_utils(my_driver)virtual my_if vif;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("NOVIF", "Failed to get vif")endfunctiontask run_phase(uvm_phase phase);my_transaction tr;forever beginseq_item_port.get_next_item(tr);drive_transaction(tr);seq_item_port.item_done();endendtasktask drive_transaction(my_transaction tr);vif.cb.address <= tr.address;vif.cb.data <= tr.data;vif.cb.command <= tr.command;@(vif.cb);endtask
endclass//==sequencer
class my_sequencer extends uvm_sequencer #(my_transaction);`uvm_component_utils(my_sequencer)function new(string name, uvm_component parent);super.new(name, parent);endfunction
endclass//==env
class my_env extends uvm_env;`uvm_component_utils(my_env)my_sequencer seqr;my_driver drv;function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);seqr = my_sequencer::type_id::create("seqr", this);drv = my_driver::type_id::create("drv", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);drv.seq_item_port.connect(seqr.seq_item_export);endfunction
endclass

通过这种分离的设计,UVM验证环境可以更加灵活、高效地进行事务级验证,同时提高代码的可维护性和可重用性。

2.19 如何在driver中使用interface?

在driver中进行virtual interface声明,并接收来自顶层通过config_db传递的interface。

// 定义一个简单的interface
interface my_interface (input clk, input rst_n);logic [7:0] data;logic       valid;logic       ready;
endinterface// driver的实现
class my_driver extends uvm_driver #(my_transaction);// 实例化interfacevirtual my_interface vif;function new(string name, uvm_component parent);super.new(name, parent);endfunction// 在build_phase中获取interface的句柄function void build_phase(uvm_phase phase);super.build_phase(phase);if (!uvm_config_db#(virtual my_interface)::get(this, "", "vif", vif)) begin`uvm_error("my_driver", "Failed to get vif handle")endendfunction// 在run_phase中使用interface与DUT通信task run_phase(uvm_phase phase);my_transaction tr;forever beginseq_item_port.get_next_item(tr);// 使用interface中的信号驱动DUTvif.data <= tr.data;vif.valid <= 1'b1;@(posedge vif.clk);while (!vif.ready) @(posedge vif.clk);vif.valid <= 1'b0;seq_item_port.item_done();endendtask
endclass

2.20 config_db的作用以及传递其使用时的参数含义

config_db 在 UVM(Universal Verification Methodology)是一个配置数据库,用于在验证环境中的不同组件之间传递配置信息–来配置和共享参数;
uvm_config_db 提供了两种主要的方法来设置和获取配置信息:uvm_config_db#(T)::set uvm_config_db#(T)::get;

// 在测试用例中设置配置信息
class my_test extends uvm_test;my_agent my_agent_inst;function void build_phase(uvm_phase phase);super.build_phase(phase);my_agent_inst = my_agent::type_id::create("my_agent_inst", this);// 设置配置信息uvm_config_db#(int)::set(this, "my_agent_inst", "num_transactions", 100);endfunction
endclass// 在代理(agent)中获取配置信息
class my_agent extends uvm_agent;int num_transactions;function void build_phase(uvm_phase phase);super.build_phase(phase);// 获取配置信息if (!uvm_config_db#(int)::get(this, "", "num_transactions", num_transactions)) begin`uvm_error("my_agent", "Failed to get num_transactions config")end// 使用配置信息`uvm_info("my_agent", $sformatf("Number of transactions: %0d", num_transactions), UVM_LOW)endfunction
endclass

在build_phase中的执行顺序是从上到下进行执行的;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/468808.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity 插件 - Project窗口资源大小显示

Unity 插件 - Project窗口资源大小显示 &#x1f354;功能&#x1f32d;安装 &#x1f354;功能 &#x1f4a1;.显示Project Assets 和Packages下所有文件的大小&#xff08;右侧显示&#xff09; &#x1f4a1;.统计选中文件夹及其子文件夹下所有文件的大小并显示&#xff08…

HTB:Photobomb[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行端口开放扫描 再次使用nmap对靶机开放端口进行脚本、服务扫描 使用ffuf进行简单的子域名扫描 使用浏览器直接访问该域名 选取一个照片进行下载&#xff0c;使用Yakit进行抓包 USER_FLAG&#xff1a;a9afd9220ae2b5731…

ssm教室信息管理系统+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码看文章最下面 需要定制看文章最下面 目 录 目 录 III 1 绪论 1 1.1 研究背景 1 1.2目的和意义 1 1.3 论文结构安排 2 2 相关技术 3 …

详解Java之Spring MVC篇二

目录 获取Cookie/Session 理解Cookie 理解Session Cookie和Session的区别 获取Cookie 获取Session 获取Header 获取User-Agent 获取Cookie/Session 理解Cookie HTTP协议自身是“无状态”协议&#xff0c;但是在实际开发中&#xff0c;我们很多时候是需要知道请求之间的…

量子计算及其在密码学中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 量子计算及其在密码学中的应用 量子计算及其在密码学中的应用 量子计算及其在密码学中的应用 引言 量子计算概述 定义与原理 发展…

当财政支持减弱时,国有企业如何实现降本增效?

当财政支持减弱时&#xff0c;国有企业如何实现降本增效&#xff1f; 随着市场环境的不断变化和上级市场化政策要求的不断推进&#xff0c;部分国有企业面临着双重压力&#xff0c;一方面&#xff0c;市场的快速变革要求企业不断创新、提升竞争力&#xff1b;另一方面&#xff…

引入 axios,根据 api 文档生成调用接口

起步 | Axios Docs 安装 axios npm install axios 生成 api 调用接口【可选】 https://github.com/ferdikoomen/openapi-typescript-codegen 安装 npm install openapi-typescript-codegen --save-dev 然后执行生成代码 # http://localhost:8805/api/user/v3/api-docs&a…

ElasticSearch的Python Client测试

一、Python环境准备 1、下载Python安装包并安装 https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe 2、安装 SDK 参考ES官方文档: https://www.elastic.co/guide/en/elasticsearch/client/index.html python -m pip install elasticsearch一、Client 代…

在双显示器环境中利用Sunshine与Moonlight实现游戏串流的同时与电脑其他任务互不干扰

我和老婆经常会同时需要操作家里的电脑&#xff0c;在周末老婆有时要用电脑加班上网办公&#xff0c;而我想在难得的周末好好地Game一下&#xff08;在客厅用电视机或者平板串流&#xff09;&#xff0c;但是电脑只有一个&#xff0c;以往我一直都是把电脑让给老婆&#xff0c;…

【第六节】windows汇编开发工具-RadAsm与Masm

一、介绍RadAsm和Masm相关概念 1.1 什么是Win32Asm&#xff1f; Win32Asm是一种基于32位汇编语言的编程语言&#xff0c;专门用于在Windows操作系统下进行开发。Win32Asm的全称是“Windows下的32位汇编语言编程”&#xff0c;它使用微软的MASM&#xff08;Microsoft Macro Ass…

EHOME视频平台EasyCVR视频融合平台支持哪些摄像机接入?监控摄像头镜头的种类有哪些?

在现代安防监控领域&#xff0c;视频融合平台扮演着至关重要的角色&#xff0c;它们不仅能够整合不同品牌和型号的摄像机&#xff0c;还能提供稳定可靠的视频流传输和高效的视频管理功能。EasyCVR视频融合平台以其卓越的兼容性和灵活性&#xff0c;逐渐成为构建复杂监控网络的首…

从pg_depend和pg_class开始了解MogDB/openGauss/postgresql的系统元数据设计

前言 学习任何一种数据库&#xff0c;必须要了解它的数据字典&#xff0c;这样有利于了解数据库的结构、解读部分日志、定位一些问题。PG/OG系数据库的系统元数据遵从一个统一的设计规则&#xff0c;可以让初学者快速入门。本文以MogDB为例&#xff0c;剖析一下PG/OG系数据库的…

[译] APT分析报告:13.Trellix对Iran网络空间能力评估

这是作者新开的一个专栏&#xff0c;主要翻译国外知名安全厂商的技术报告和安全技术&#xff0c;了解它们的前沿技术&#xff0c;学习它们威胁溯源和恶意代码分析的方法&#xff0c;希望对您有所帮助。当然&#xff0c;由于作者英语有限&#xff0c;会借助LLM进行校验和润色&am…

vue2,vue3,uniapp,小程序实现前端url生成二维码

最近遇到一个项目&#xff0c;api返回url地址&#xff0c;前端通过地址生成二维码。 话不多说直接上代码&#xff0c;亲测有效&#xff0c;希望能帮助大家&#xff0c;同时如果有更好的方法希望大家能够分享 1、第一步&#xff0c;在项目的utils文件夹下面创建一个weapp-qrco…

Python的函数(补充浅拷贝和深拷贝)

一、定义 函数的定义&#xff1a;实现【特定功能】的代码块。 形参&#xff1a;函数定义时的参数&#xff0c;没有实际意义 实参&#xff1a;函数调用/使用时的参数&#xff0c;有实际意义 函数的作用&#xff1a; 简化代码提高代码重用性便于维护和修改提高代码的可扩展性…

FPGA学习笔记#4 Vitis HLS 入门的第一个工程

本笔记使用的Vitis HLS版本为2022.2&#xff0c;在windows11下运行&#xff0c;仿真part为xcku15p_CIV-ffva1156-2LV-e&#xff0c;这一篇终于没有再大量使用别人的内容&#xff0c;是我自己从头捋到尾的结果&#xff0c;不过之后的笔记还是要参照别人的教程就是了。 学习笔记&…

Linux中给普通账户一次性提权

我在以前文章中Linux常见指令大全&#xff08;必要知识点&#xff09;-CSDN博客 写过sudo的概念与用法。其实本质就是提权用的但是在某些场景下就算提权了也不能使用。 例如&#xff1a;打开主工作目录 他不相信你这个用户&#xff0c;虽然你是erman 解决方法 使用root账号打开…

A027-基于Spring Boot的农事管理系统

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

linux命令详解,存储管理相关

存储管理 一、内存使用量&#xff0c;free free 命令是一个用于显示系统中物理内存&#xff08;RAM&#xff09;和交换空间&#xff08;swap&#xff09;使用情况的工具 free -m free -m -s 5参数 -b 功能: 以字节&#xff08;bytes&#xff09;为单位显示内存使用情况。说…

关于若依500验证码问题的求助

关于若依框架中验证码出现500错误的问题&#xff0c;这通常表示服务器内部错误。以下是一些可能的原因及解决方案&#xff1a; 一、配置文件问题 .env.production文件&#xff1a; 确保.env.production文件中的VUE_APP_BASE_API已经修改成服务器上的域名地址&#xff0c;而不…