UVM应用指南及源码分析:第五章 sequence机制 学习笔记

sequence机制在UVM验证平台中扮演什么样的角色?

UVM验证平台中,sequence相当于子弹,sequencer相当于弹夹,driver相当于手枪。主从关系而言,当driver请求发射的时候告诉弹夹准备好子弹。sequence主要负责transaction的产生,UVM平台需要对DUT施加不同的激励,而激励的不同体现在transaction,本质上是通过不同case中不同的sequence产生不同的激励

drvier完全可以产生激励,并对DUT进行驱动,为什么还要多此一举,加入sequence机制,将激励的产生和驱动做以隔离?

类似UVM的phase机制,验证平台将运行过程隔离成了不同的phase,在特定时间完成特定工作,提高易用性,提高效率。sequence机制隔离激励的产生和驱动继承了这种设计哲学,使得驱动组件可以被重用
举个例子来说明为什么驱动组件被重用了:
当我们决定要用driver产生并驱动激励,main_phase中包括了DUT的运行,因此我们的想法是在main_phase中产生各种激励。

task driver::main_phase(uvm_phase phase);
    transaction tr;
    super.main_phase(phase);
    phase.raise_objection(tr);
    for(int i = 0; i < 10; i++) begin
        tr = new();
        assert(tr.randomize);
        drive(tr);
    end
    phase.drop_objection(tr);
endtask

这种写法使得driver产生并驱动了transaction level的激励,但是当我们需要驱动不同的激励时,我们必须对driver的main_phase任务重新写,导致重用性很差。因此自然有了把产生什么样的激励这部分隔离出去,留下可以重用的部分。
自然的想法是通过函数的方法:

task driver::main_phase(uvm_phase phase);
    transaction tr;
    super.main_phase(phase);
    phase.raise_objection(tr);
    for(int i = 0; i < 10; i++) begin
        gen_pkt(tr);
        drive(tr);
    end
    phase.drop_objection(tr);
endtask

function gen_pkt(ref transaction tr);
    tr = new;
    assert(tr.randomize);
endfunction

需要不同的激励时呢?改函数吗?很麻烦。我们需要在driver组件不改变的情况下能让函数调用不同的内容。因此引入了sequence的机制。sequence机制的大致过程为 在不同的case中,把不同的sequence设置为sequencer的main_phase中的defalut_sequence,当sequencer执行到main_phase,如果发现有default_phase,那么就会启动sequence。在一个case的env.agt.sqr中的build_phase,用config_db设置对应的sequence及启动的位置(main_phase)。

uvm_config_db#(uvm_object_wrapper)::set(this,"env.agt.sqr.main_phase","default_sequence",my_sequence::type_id::get)

sequence的执行与启动

有一个sequence如下:

class my_sequence extends uvm_sequence #(transaction);
    `uvm_object_utils(my_sequence)
    transaction tr;
    extern function new(string name = "my_sequence");
    virtual task body();
        repeat(10) begin
            `uvm_do(tr)
        end
        #100;
    endtask
end class

function my_sequence::new(string name = "my_sequence");
    super.new(name);
endfunction

启动如上的sequence:实例化并调用start任务,对于start任务传入sequencer参数,start任务中肯定执行了sequence的body任务

my_sequence my_seq;
my_seq = my_sequence::type_id::creat("my_seq");
my_seq.start(sequencer)

根据以上,sequencer中main_phase中先通过config_db得到defalut_sequence,然后实例化并调用start任务,start的参数是this。

通过sequence来控制验证平台的关闭

在激励的产生部分没有隔离出driver之前,driver通过raise_objection 和 drop_objection 控制平台的关闭,当sequence从driver中隔离出去后,driver只保留有驱动的功能,它向sequencer索要transaction,要到了就将transaction驱动到DUT,否则一直等待。因此应该将控制平台关闭的功能转移到sequence中,但 raise_objection 和 drop_objection 是 phase 的函数,而 sequence 继承于uvm_object 而不是 uvm_component。做法是在 sequence 中加入一个指向 phase 的指针,在sequencer 的 main_phase 中的 phase 赋给这个指针,这个指针的名字是 starting_phase :

task body();
	if(starting_phase != null)
		starting_phase.raise_objection(this);
	...
	if(starting_phase != null)
		starting_phase.drop_objection(this);
endtask

保险起见,先判断starting_phase这个指针不为空

`uvm_do宏

一个sequence被启动后,UVM会自动执行body任务,body任务和之前的 gen_pkt function 是一样的作用,不同点在于 gen_pkt function 函数是通过 ref 引用的方式给 driver 传递 transaction ,而sequence 和 driver 之间要进行通信。

sequencer
sequence.imp
driver.export

一个transaction的产生有四步:

task body();
	transaction tr;
	tr = transaction::type_id::creat("tr");//实例化
	start_item(tr);
	assert(tr.randomize);
	finish_item(tr);
endtask

当driver向sequencer进行请求,sequencer才会启动sequence产生一个transaction,产生完成后等待driver把item取走,driver会显式调用seq_item_port.item_done(),此函数被调用后,finish_item才会返回,一个transaction的传输才算完成。而这个过程中只有第三步是变化的,因此引入了`uvm_do系列宏。以上步骤简化为:

task body();
	transaction tr;
	`uvm_do(tr)
endtask

一个`uvm_dowith的宏

task body();
	transaction tr;
	`uvm_do_with(tr, {tr.en == 1;})
endtask

以上会将第三步替换为

assert(tr.randomize() with {tr.en == 1;});

再考虑一种情况,如果我们有30个case,每个case中的sequence都要发10中transaction,但在30个case中仅限于这10种transaction,如果要分别写sequence的话,很麻烦而且代码很多都是重复的,为了解决这个问题,uvm_do宏的参数也可以为sequence类型

class seq0 extends uvm_sequence #(transaction);
    `uvm_object_utils(seq0)
    task body();
        transaction tr;
        `uvm_do_with(tr, {tr.data == 16'd0;tr.en == 1;})
    endtask
endclass
class seq1 extends uvm_sequence #(transaction);
    `uvm_object_utils(seq1)
    task body();
        transaction tr;
        `uvm_do_with(tr, {tr.data == 16'd2;tr.en == 1;})
    endtask
endclass
class seq extends uvm_sequence #(transaction);
    `uvm_object_utils(seq)
    task body();
        seq0 s1;
        seq1 s2;
        `uvm_do(s1)
        `uvm_do(s2)
    endtask
endclass

virtual sequence & virtual sequencer

考虑这样一种情况,验证平台中有两个driver,等待一个driver发送给DUT激励后另一个driver再发送激励,有先后顺序,自然的想法是通过全局变量定义一个事件,在两个sequence的body中进行触发和等待,但全局变量是危险的操作,不建议。因此引入了virtual sequence 和 virtual sequencer 的概念来调度有先后顺序的sequence
要使用virtual sequence,一般有一个virtual sequencer包含指向其它sequencer的指针。而virtual sequencer不同于虚拟类或者虚拟方法,它本质上只是一个component

class vsequencer extends uvm_sequencer;
	`uvm_component_utils(vsequnecer)
	cpu_sequencer cpu_sqr;
	mac_sequencer mac_sqr;
endclass

在test中实例化virtual sequencer 并将 sequencer 赋给virtual sequencer 的指针。

class base_test extends uvm_test;
	env env_inst;
	vsequencer vsqr;
	function bulid_phase(uvm_phase phase);
		vsqr = vsquencer::type_id::creat("vsqr", this);
	endfunction
	function connect_phase(uvm_phase phase);
		vsqr.cpu_sqr = env_inst.cpu_agt.cpu_sqr;
		vsqr.mac_sqr = env_inst.mac_agt.mac_sqr;
	endfunction
endclass

virtual sequence如何启动sequence?

class vseq extends uvm_sequence;
	`uvm_object_utils(vseq)
	task body();
		cpu_seq cseq;
		mac_seq mseq;
		`uvm_do_on(cseq, p_sequencer.cpu.sqr)
		`uvm_do_on(mseq, p_sequencer.mac.sqr)
	endtask
	`uvm_declare_p_sequencer(vsequencer)
endclass

`uvm_do_on将启动的sequence产生的transaction交给了p_sequencer指向的任意sqr,而p_sequencer是指向virtual sequencer的指针,也需要一句宏命令显示定义,整个过程中,virtual sequence 扮演了调度sequence顺序的角色,virtual sequencer 扮演了整合所有squencer的角色,他们有三个特点:

  • virtual sequencer 控制其他sequencer
  • virtual sequencer 不处理transaction
  • virtual sequencer 不连接driver

这也是为什么取名为virtual 的原因。

在以前,启动sequence时,首先在test中将sequence通过config_db设置为对应sequencer 的 defalut_sequence,然后再sequencer的main_phase中通过config_db取到sequence,再通过start任务启动。当有多个sequence时不免要进行多次config_db的操作,而通过virtual sequence,则只需要一次操作:

`uvm_config_db#(uvm_object_wrapper)::set("this", "env.vsqr.main_phase", "default sequence", type_id_get());
env
cpu_agt
mac_agt
vsqr
mac_sqr
cpu_sqr
vseq
mac_seq
cpu_seq
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Table of Contents Articles Introduction 0 Cookbook/Introduction 0 Cookbook/Acknowledgements 1 Testbench Architecture 2 Testbench 2 Testbench/Build 9 Testbench/Blocklevel 19 Testbench/IntegrationLevel 29 Component 39 Agent 42 Phasing 48 Factory 53 UsingFactoryOverrides 56 SystemVerilogPackages 62 Connections to DUT Interfaces 65 Connections 65 SVCreationOrder 71 Connect/SystemVerilogTechniques 73 ParameterizedTests 75 Connect/Virtual Interface 78 Config/VirtInterfaceConfigDb 86 Connect/VirtInterfacePackage 90 Connect/VirtInterfaceConfigPkg 93 Connect/TwoKingdomsFactory 97 DualTop 103 VirtInterfaceFunctionCallChain 106 BusFunctionalModels 108 ProtocolModules 111 Connect/AbstractConcrete 115 Connect/AbstractConcreteConfigDB 118 Configuring a Test Environment 126 Configuration 126 Resources/config db 131 Config/Params Package 134 Config/ConfiguringSequences 139 ResourceAccessForSequences 142 MacroCostBenefit 145 Analysis Components & Techniques 146 Analysis 146 AnalysisPort 149 AnalysisConnections 152 MonitorComponent 158 Predictors 161 Scoreboards 163 MetricAnalyzers 170 PostRunPhases 172 Matlab/Integration 175 End Of Test Mechanisms 183 EndOfTest 183 Objections 185 Sequences 188 Sequences 188 Sequences/Items 193 Transaction/Methods 195 Sequences/API 200 Connect/Sequencer 204 Driver/Sequence API 206 Sequences/Generation 213 Sequences/Overrides 221 Sequences/Virtual 223 Sequences/VirtualSequencer 231 Sequences/Hierarchy 237 Sequences/SequenceLibrary 242 Driver/Use Models 246 Driver/Unidirectional 247 Driver/Bidirectional 250 Driver/Pipelined 255 Sequences/Arbitration 267 Sequences/Priority 276 Sequences/LockGrab 277 Sequences/Slave 284 Stimulus/Signal Wait 290 Stimulus/Interrupts 294 Sequences/Stopping 301 Sequences/Layering 302 Register Abstraction Layer 308 Registers 308 Registers/Specification 315 Registers/Adapter 317 Registers/Integrating 321 Registers/Integration 327 Registers/RegisterModelOverview 332 Registers/ModelStructure 334 Registers/QuirkyRegisters 344 Registers/ModelCoverage 349 Registers/BackdoorAccess 354 Registers/Generation 357 Registers/StimulusAbstraction 358 Registers/MemoryStimulus 370 Registers/SequenceExamples 375 Registers/BuiltInSequences 382 Registers/Configuration 386 Registers/Scoreboarding 389 Registers/FunctionalCoverage 395 Testbench Acceleration through Co-Emulation 401 Emulation 401 Emulation/SeparateTopLevels 404 Emulation/SplitTransactors 410 Emulation/BackPointers 415 Emulation/DefiningAPI 419 Emulation/Example 422 Emulation/Example/APBDriver 430 Emulation/Example/SPIAgent 435 Emulation/Example/TopLevel 441 Debug of SV and UVM 444 BuiltInDebug 444 Reporting/Verbosity 455 UVM/CommandLineProcessor 460 UVM Connect - SV-SystemC interoperability 464 UvmConnect 464 UvmConnect/Connections 466 UvmConnect/Conversion 468 UvmConnect/CommandAPI 472 UVM Express - step by step improvement 476 UvmExpress 476 UvmExpress/DUT 481 UvmExpress/BFM 485 UvmExpress/WritingBfmTests 490 UvmExpress/FunctionalCoverage 498 UvmExpress/ConstrainedRandom 503 Appendix - Deployment 516 OVM2UVM 516 OVM2UVM/DeprecatedCode 527 OVM2UVM/SequenceLibrary 528 OVM2UVM/Phasing 530 OVM2UVM/ConvertPhaseMethods 535 UVC/UvmVerificationComponent 537 Package/Organization 548 Appendix - Coding Guidelines 555 SV/Guidelines 555 UVM/Guidelines 569 Appendix - Glossary of Terms 579 Doc/Glossary 579

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值