UVM——ALU生成fabonacci数列

0. 介绍

之前的这篇文章——UVM——tb0-alu验证平台是居于一个ALU搭建的验证平台,现在希望让这个验证平台能够输出斐波那契数列数列(1,1,2,3,5,8…),利用一种特殊的响应,写一个能够生成斐波那契数列的sequence。

1. 思路

特殊的响应

`uvm_do语句会将transaction通过sequencer发送给driver,`uvm_do执行完之后,它的第一个参数,也就是刚才发送的transaction指针,它不是null,它指向刚才发送的transaction。我们可以在driver驱动接口的时候,把计算的结果保存在transaction中,返回给sequence,这算是一种另类的响应。

2. 实现方法

​ 这样的话,我们可以在transaction类中增加一个变量来保存计算结果,如下:

1
2
3
4
5
6
7
8
class transaction extends uvm_sequence_item;

rand bit[7:0] A;
rand bit[7:0] B;
rand operation_t op;
shortint unsigned result;//增加的变量,用来保存结果
.....
endclass

在driver驱动接口之后,等待加法命令执行完了,我们将计算结果返回给driver驱动的transaction,这个transaction就会传给sequence中的transaction。

在driver中:

1
2
3
4
5
6
7
8
9
10
11
task driver::run_phase(uvm_phase phase);
22 super.run_phase(phase);
23 `uvm_info("driver","run_phase",UVM_LOW);
24 bfm.reset_alu();
25 while(1) begin
26 seq_item_port.get_next_item(req);
27 //req.print();
28 bfm.drive_one_pkg(req);//接口中的任务
29 seq_item_port.item_done();
30 end
31 endtask

上面的driver的run phase中,先从sequencer中拿到一个transaction——req;然后调用接口中的任务,将transaction的数据按照一定的时序驱动到接口中;驱动完,调用item_done()。

接口中的任务:

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
interface alu_bfm;
...
task drive_one_pkg(transaction tr); //驱动driver拿到的transaction
if(tr.op == rst_op) begin
@(posedge clk);
reset_n = 1'b0;
start = 1'b0;
@(posedge clk);
#1;
reset_n = 1'b1;
end
else begin
@(negedge clk);
op = tr.op;
A = tr.A;
B = tr.B;
start = 1'b1;
if(tr.op == no_op) begin
@(posedge clk);
#1;
start = 1'b0;
end
else begin
do
@(negedge clk);//this is negedge
while(done==0); //在这里判断运算执行完
tr.result = result; //将结果返回到transaction
start = 1'b0;
end
end
endtask
...
endinterface

3. fabonacci sequence

所以我们就可以写一个fabonacci sequence,写法如下:

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
task pre_body();
if(starting_phase != null)
starting_phase.raise_objection(this);
`uvm_info("sequence0","pre_body",UVM_LOW)
endtask

transaction fab_tr;
task body();
shortint unsigned tmp1,tmp2;
// 先发送前两个数,A=1,B=1,约束命令为加法运算。
`uvm_do_with(fab_tr,{fab_tr.A==1;fab_tr.B==1;fab_tr.op==add_op;});
tmp1=1;
tmp2=fab_tr.result;//计算结果存在变量里,为了在下一次发送sequence时使用。
repeat(20) begin
`uvm_do_with(fab_tr,{fab_tr.A==tmp1;fab_tr.B==tmp2;fab_tr.op==add_op;});
tmp1=fab_tr.B;//这一次发送的B的值,会是下一次发送的A的值
tmp2=fab_tr.result;
end
endtask

task post_body();
`uvm_info("sequence0","post_body",UVM_LOW)
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask

4. 打印结果

结果如下,这个log是处理过的,只把需要的信息拿出来了,实际中比较乱。

1
2
3
4
5
6
7
8
9
10
11
12
33:@ 90000 fabonacci sequence is     2
39:@ 130000 fabonacci sequence is 3
45:@ 170000 fabonacci sequence is 5
51:@ 210000 fabonacci sequence is 8
57:@ 250000 fabonacci sequence is 13
63:@ 290000 fabonacci sequence is 21
69:@ 330000 fabonacci sequence is 34
75:@ 370000 fabonacci sequence is 55
81:@ 410000 fabonacci sequence is 89
87:@ 450000 fabonacci sequence is 144
93:@ 490000 fabonacci sequence is 233
143:@ 530000 fabonacci sequence is 377