日常记录(57)vseqr与vseq。AHB2
AHB2项目虽然有不少错误,但是从整体架构上比较规范。
https://gitee.com/bai-mengwei/AHB2
RTL
可能由于只是一个VIP,只有一个interface。在interface里具有断言的写法。
比如:其中的disable iff等表示需要系统不在复位状态,即rst=1时进行断言。
property size7_addr_p;
@(posedge HCLK) disable iff(!HRESETn)
HSIZE == 7 |-> HADDR[6:0] == 0;
endproperty
SIZE7_ADDR_BOUD: assert property(size7_addr_p);

SIM
一共6个代码。在sim文件夹中,有Makefile文件。文件中用vcs先把一些文件夹添加为搜索路径,然后编译文件总的pkg、top。这两个文件都在env文件夹中。

ENV
1. 一共6个代码。env文件夹中,top是顶层用于调用run_test函数,然后调用对应的test_case.
2. 在调用前,实例化interface,include 总的pkg(ahb_test_pkg,在test目录下),而test_case也在test目录里
注意这里的top是module,而整个项目没有program。一般时候,用top进行实例化interface后,是将program再次实例化,然后整个验证在program里。


TEST
1. ahb_test_pkg是总的pkg,包括了各种svh文件,也包括了uvm的头部
`include uvm_macros.svh import uvm_pkg::*
2. ahb_test.svh包括了所有的test_case,继承了uvm_test并注册到工厂中,因此可以调用。

3. 在每个 test_case调用过程中,基本类定义了env、和env_cfg,以及各种各类的vseq。
vseq来自于env文件夹中。
vseq从本质上是普通的seq,但是它的行为是调用真实的seq(在 task body中实现。)
vseqr本质上也是普通的seqr,但是它的内部包括了各种seqr的声明。并在env中进行了实例化连接(vseqr被各种agent的seqr进行赋值)。

传输过程
传输
在test_case中的run_phase,创建一个vseq,然后启动。
当一个特定的vseq启动,并使用env下的vseqr作为发送装置。可惜该发送装置没有接drv,不能让vseq在task_body中调用start_item, uvm_do等。而是进行了一些赋值操作。

1.基类vseqr:
首先调用base_vseq,将env的vseqr中的内容分别取出(m_sequencer),并进行赋值。
class ahb_base_vseq extends uvm_sequence#(uvm_sequence_item);
`uvm_object_utils(ahb_base_vseq)
ahb_vseqr vseqr_h;
ahb_mseqr mseqr_h;
ahb_sseqr sseqr_h;
reset_seqr reset_seqr_h;
reset_seq reset_seq_h;
set_seq set_seq_h;
ahb_idle_mseq idle_mseq_h;
ahb_incrx_mseq incrx_mseq_h;
ahb_wrapx_mseq wrapx_mseq_h;
ahb_crt_mseq crt_mseq_h;
ahb_incrbusy_mseq incrbusy_mseq_h;
ahb_reset_sseq reset_sseq_h;
ahb_ready_sseq ready_sseq_h;
ahb_err_sseq err_sseq_h;
extern function new(string name = "ahb_base_vseq");
extern task body();
endclass: ahb_base_vseq
//Constructor
function ahb_base_vseq::new(string name = "ahb_base_vseq");
super.new(name);
endfunction
//Body
task ahb_base_vseq::body();
if(!$cast(vseqr_h, m_sequencer))
begin
`uvm_fatal(get_full_name(), "Virtual Sequencer cast failed!")
end
reset_seqr_h = vseqr_h.reset_seqr_h;
mseqr_h = vseqr_h.mseqr_h;
sseqr_h = vseqr_h.sseqr_h;
endtask
2. 对应类vseqr:
然后通过子类,对实际的seq进行创建和启动。实际的seq需要使用其对应的实际的seqr,而这些seqr在agent中声明后,已经接入了agent对应的drv中了,因此可以发出去。
class ahb_reset_vseq extends ahb_base_vseq;
`uvm_object_utils(ahb_reset_vseq)
extern function new(string name = "ahb_reset_vseq");
extern task body();
endclass: ahb_reset_vseq
//Constructor
function ahb_reset_vseq::new(string name = "ahb_reset_vseq");
super.new(name);
endfunction
//Body
task ahb_reset_vseq::body();
super.body();
reset_seq_h = reset_seq::type_id::create("reset_seq_h");
reset_sseq_h = ahb_reset_sseq::type_id::create("reset_sseq_h");
fork
reset_sseq_h.start(sseqr_h);
join_none
reset_seq_h.start(reset_seqr_h);
endtask
3. 对应的seq
就使用了创建、开始、随机化以及修改,发送。然后被agent对应的drv拿到,开始驱动。
class reset_seq extends reset_base_seq;
`uvm_object_utils(reset_seq)
extern function new(string name = "reset_seq");
extern task body();
endclass: reset_seq
//Constructor
function reset_seq::new(string name = "reset_seq");
super.new(name);
endfunction
//Body
task reset_seq::body();
req = ahb_mxtn::type_id::create("req");
start_item(req);
assert(req.randomize() with {burst_mode == SINGLE;});
req.reset = 0;
finish_item(req);
endtask
说明总结
(1.vseq是临时创建并启动的,它需要一个对应的seqr)
(2.这个seqr是一个vseqr,它不是让对应的seq发送到drv的,而是存储真实的seqr的,因此在vseq基类的task body中,没有send,而是进行赋值)
RESET_AGENT
1. 这里的seqr和seq就很普通了。seqr只有一个注册过程,seqs包括了几个对应的类。
2. agent中对drv和seqr进行了连接

Le vent se lève! . . . il faut tenter de vivre!
Le vent se lève! . . . il faut tenter de vivre!

浙公网安备 33010602011771号