【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中的执行顺序是从上到下进行执行的;
相关文章:
【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和其…...
SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
这是一篇港科大学生在google research 实习期间发在ECCV2024的语义引导生成式修复的文章,港科大陈启峰也挂了名字。从首页图看效果确实很惊艳,尤其是第三行能用文本调控修复结果牌上的字。不过看起来更倾向于生成,对原图内容并不是很复原&…...
#揭秘万维网:从静态页面到智能互联网
揭秘万维网:从静态页面到智能互联网 今天刚上了学校开设的课程,于是便有了下文的思考内容。 在当今数字化时代,Web(万维网)扮演着重要的角色,成为人们获取信息、沟通交流和进行商业活动的主要平台。 1. …...
【计算机基础——数据结构——红黑树】
1. 红黑树(RBTree) 为什么HashMap不直接使用AVL树,而是选择了红黑树呢? 由于AVL树必须保证左右子树平衡,Max(最大树高-最小树高) < 1,所以在插入的时候很容易出现不平衡的情况,一旦这样&…...
Sentinel — 微服务保护
微服务架构将大型应用程序拆分为多个小而独立的服务,每个服务可以独立部署和扩展。然而,微服务系统需要面对的挑战也随之增加,例如服务之间的依赖、分布式环境下的故障传播和安全问题。因此,微服务保护措施是确保系统在高并发、资…...
Cynet:全方位一体化安全防护工具
前言 1999年,布鲁斯施奈尔曾说过:“复杂性是安全最大的敌人。”彼时还是19年前,而现在,网络安全已然变得更加繁杂。 近日我在网上冲浪过程中发现了这么一个平台性质的软件,看似具有相当强的防护能力。 根据Cynet的描…...
python中常见的8种数据结构之一数组的应用
在Python中,数组是一种常见的数据结构,用于存储一系列相同类型的元素。在实际应用中,数组可以用于解决各种问题。 以下是数组在Python中的一些常见应用: 1. 存储和访问数据:数组可以用于存储和访问一组数据。可以通过…...
安装多个低版本谷歌Chrome浏览器用于测试,适配Vue3+vite项目
安装多个低版本谷歌Chrome浏览器用于测试,适配Vue3vite项目 问题:使用vue3tsvite搭建了一个项目,在chrome新版本浏览器上无问题,但是部署到现场页面直接空白,且控制台报错: Uncaugnt SyntaxError: Unexpe…...
UI组件---如何设置el-pagination分页组件的背景色
1. 要替换 el-pagination 组件的背景色,您可以通过自定义CSS来实现。 具体的CSS规则取决于您想要更改的是哪个部分的背景色,例如普通页码、活跃页码、上下导航箭头等。以下是一些示例CSS规则,您可以根据自己的需求进行调整: /* …...
LabVIEW编程过程中为什么会出现bug?
在LabVIEW编程过程中,Bug的产生往往源自多方面原因。以下从具体的案例角度分析一些常见的Bug成因和调试方法,以便更好地理解和预防这些问题。 1. 数据流错误 案例:在一个LabVIEW程序中,多个计算节点依赖相同的输入数据&#…...
论文阅读《Structure-from-Motion Revisited》
摘要 增量式地运动结构恢复是从无序图像集合中进行三维重建的一个普遍策略。虽然增量式地重建系统在各个方面上都取得了巨大的进步,但鲁棒性、准确性、完整度和尺度仍然是构建真正通用管道的关键问题。我们提出了一种新的运动结构恢复技术,它改进了目前…...
RK android14 第三方app获取su权限
需要修改的地方如下 frameworks/base/core/jni/com_android_internal_os_Zygote.cpp kernel-6.1/security/commoncap.c system/core/init/selinux.cpp system/core/libcutils/fs_config.cpp system/extras/su/su.cpp device/rockchip/common/BoardConfig.mk device/rockchip…...
线程与进程的区别(面试)
一.进程 进程:一个程序启动起来,就会对应一个进程,进程就是系统分配资源的基本单位。 上面一部分进程是我们自己去执行应用的可执行文件, 而另一部分是操作系统自动启动的进程. 二.线程 线程:线程是进程中的一个执行单元ÿ…...
OpenDroneMap Webodm
OpenDroneMap & Webodm OpenDroneMap Webodm 开源无人机航拍系列图像及其它系列图像三维重建软件。很棒的开源无人机测绘软件OpenDroneMap,从航拍图像生成精确的地图、高程模型、3D 模型和点云。 应用领域 Mapping & Surveying 测绘和测量 从图像测量获得高精度的可…...
Could not create task ‘:shared_preferences_android:generateDebugUnitTestConfig‘
flutter项目使用shared_preferences库的时候,打开flutter项目中的android项目运行,会出现如下错误信息: A build operation failed. Could not create task :shared_preferences_android:generateDebugUnitTestConfig. Could not create…...
CSS教程(四)- 字体
1、尺寸单位 px 像素单位% 百分比,参照父元素对应属性的值进行计算em 字体尺寸单位,参照父元素的字体大小计算,1em16pxrem字体尺寸单位,参照根元素的字体大小计算,1rem16px 2、字体属性 介绍 CSS Fonts (字体)属性用于定义字体…...
深入理解Java中的Lambda表达式
在Java 8中,Lambda表达式的引入无疑是一个重大的里程碑。 Lambda表达式以其简洁的语法和强大的功能,极大地改变了Java开发者编写代码的方式。本文将深入探讨Lambda表达式的概念、语法、使用场景以及其在函数式编程中的意义。 一、Lambda表达式的基本概…...
C#里怎么样判断一个数是偶数还是奇数
一般是采用取余的做法。 程序如下: /** C# Program to Check whether the Entered Number is Even or Odd*/ using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace check1 {class Program{static void Main(string[]…...
【论文笔记】Prefix-Tuning: Optimizing Continuous Prompts for Generation
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Prefix-Tuning: Optimizin…...
GNN系统学习:消息传递图神经网络
引言 在开篇中我们介绍了,为节点生成节点表征(Node Representation)是图计算任务成功的关键,我们要利用神经网络来学习节点表征。 消息传递范式是一种聚合邻接节点信息来更新中心节点信息的范式,它将卷积算子推广到了…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
