UVM——layer sequence

0. 介绍

sequence中有多个不同的transaction的时候,为了将不同transaction的生成过程分离,分成更小的粒度,便于后面的复用和管理,可以采用Layer sequence,或者说多层sequence。它将一个sequenceA中产生的transactionA交付给另一个sequenceB,transactionA作为sequenceB中transactionB的一部分。

1. 例子

比如有个ip包,ip的内容作为mac包里的pload。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ip_transaction extends uvm_sequence_item;

//ip header
rand bit [3:0] version;//protocol version
rand bit [3:0] ihl;// ip header length
rand bit [7:0] diff_service; // service type, tos(type of service)
rand bit [15:0] total_len;// ip telecom length, include payload, byte
rand bit [15:0] iden;//identification
rand bit [2:0] flags;//flags
rand bit [12:0] frag_offset;//fragment offset
rand bit [7:0] ttl;// time to live
rand bit [7:0] protocol;//protocol of data in payload
rand bit [15:0] header_cks;//header checksum
rand bit [31:0] src_ip; //source ip address
rand bit [31:0] dest_ip;//destination ip address
rand bit [31:0] other_opt[];//other options and padding
rand bit [7:0] payload[];//data
....
endclass
1
2
3
4
5
6
7
8
9
class mac_transaction extends uvm_sequence_item;

rand bit[47:0] dmac;
rand bit[47:0] smac;
rand bit[15:0] ether_type;
rand byte pload[];
rand bit[31:0] crc;
...
endclass

将ip包的内容打包为ma包中pload[]。

1. 关键

layer sequence的实现,关键是如何将ip_transaction交给mac_sequence。

可以借鉴driver和sequencer的通信,在mac_sequencer中设置一个port,让它链接到ip_sequencer中的seq_item_export,这样ip_sequencer产生的ip_transaction就可以传送给mac_sequencer,在mac_sequence中拿到发送来ip_transaction.

2. 实现步骤

2.1 在mac_sequencer中增加ip_tr_port

1
2
3
4
5
6
7
8
9
10
class mac_sequencer extends uvm_sequencer#(mac_transaction);
`uvm_component_utils(mac_sequencer);

uvm_seq_item_pull_port#(ip_transaction) ip_tr_port;//定义ip_tr_port

function new(string name="mac_sequencer",uvm_component parent=null);
super.new(name,parent);
ip_tr_port=new("ip_tr_port",this);
endfunction
endclass

driver中的seq_item_port就是uvm_seq_item_pull_port类型的。

2.2 在env中将ip_tr_port和ip_sqr的seq_item_export连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class enviroment extends uvm_env;

`uvm_component_utils(enviroment);

ip_sequencer ip_sqr;
mac_sequencer sqr;
driver drv;
...
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
sqr.ip_tr_port.connect(ip_sqr.seq_item_export); //连接mac_sqr和ip_sqr间的port
endfunction

endclass

将port连接起来才能用get_next_item获取item。

2.3 mac_sequence中获取ip_transaction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
typedef class ip_sequence;

class mac_sequence extends uvm_sequence#(mac_transaction);

`uvm_object_utils(mac_sequence);
`uvm_declare_p_sequencer(mac_sequencer);//生命p_sequencer

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

task body();
ip_transaction ip_tr;
byte unsigned data_q[];
int data_size;
forever begin
p_sequencer.ip_tr_port.get_next_item(ip_tr);//从ip_sqr中获取ip_tr
`uvm_info(get_type_name(),"get a ip_tr",UVM_LOW);
data_size = ip_tr.pack_bytes(data_q)/8;
req=new("req");
assert(req.randomize() with {req.pload.size()==data_size;});
foreach(data_q[i]) begin
req.pload[i] = data_q[i];
end
`uvm_send(req);
`uvm_info(get_type_name(),"mac_sequence send a item",UVM_LOW);
p_sequencer.ip_tr_port.item_done();//使用完ip_tr,调用item_done()
end
endtask

task pre_body();
// reference to Synopsys UVM LAB
if(get_parent_sequence()==null && starting_phase!=null) begin
starting_phase.raise_objection(this);
`uvm_info(get_type_name(),$sformatf("%s starting phase raise %s phase",get_sequence_path(),starting_phase.get_name()),UVM_LOW);
end
endtask
task post_body();
if(get_parent_sequence()==null && starting_phase!=null) begin
starting_phase.drop_objection(this);
`uvm_info(get_type_name(),$sformatf("%s starting phase drop %s phase",get_sequence_path(),starting_phase.get_name()),UVM_LOW);
end
endtask

endclass

2.4 启动sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class case0 extends base_case;

`uvm_component_utils(case0);

function new(string name="case0",uvm_component parent=null);
super.new(name,parent);
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(uvm_object_wrapper)::set(this,"env.ip_sqr.run_phase","default_sequence",ip_sequence::get_type());
uvm_config_db#(uvm_object_wrapper)::set(this,"env.sqr.run_phase","default_sequence",mac_sequence::get_type());
endfunction

endclass

3. 注意

我们在上面采用的是get_next_item来获取ip_transaction中,《UVM实战》第10.2.3节中建议使用try_next_item,具体原因有点复杂,还没搞明白。

4. 代码示例

代码示例


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!