目录
一 问题代码
二 解决方法
2.1 调换代码顺序
2.2 #0 Delay
2.3 uvm class 执行移到re-avtive
2.4 搭建完备的UVM 验证平台
三 预期波形
经过之前文章的学习,想必大家对systemverilog 仿真调度的理解,应该八九不离十了。今天,我们结合实际中的例子,来实战一下,对之前的理解,做一个考核。
我们拿《UVM实战》中的2.2.1章节的例子,来讲解。
一 问题代码
(1)RTL 的设计实现
文件:src/ch2/dut/dut.sv[2]
1 module dut(clk,
2 rst_n,
3 rxd,
4 rx_dv,
5 txd,
6 tx_en);
7 input clk;
8 input rst_n;
9 input[7:0] rxd;
10 input rx_dv;
11 output [7:0] txd;
12 output tx_en;
13
14 reg[7:0] txd;
15 reg tx_en;
16
17 always @(posedge clk) begin
18 if(!rst_n) begin
19 txd <= 8'b0;
20 tx_en <= 1'b0;
21 end
22 else begin
23 txd <= rxd;
24 tx_en <= rx_dv;
25 end
26 end
27 endmodule
(2)my_driver uvm component 的实现
文件:src/ch2/section2.2/2.2.1/my_driver.sv
3 class my_driver extends uvm_driver;
4
5 function new(string name = "my_driver", uvm_component parent = null);
6 super.new(name, parent);
7 endfunction
8 extern virtual task main_phase(uvm_phase phase);
9 endclass
10
11 task my_driver::main_phase(uvm_phase phase);
12 top_tb.rxd <= 8'b0;
13 top_tb.rx_dv <= 1'b0;
14 while(!top_tb.rst_n)
15 @(posedge top_tb.clk);
16 for(int i = 0; i < 256; i++)begin
17 @(posedge top_tb.clk);
18 top_tb.rxd <= $urandom_range(0, 255);
19 top_tb.rx_dv <= 1'b1;
20 `uvm_info("my_driver", "data is drived", UVM_LOW)
21 end
22 @(posedge top_tb.clk);
23 top_tb.rx_dv <= 1'b0;
24 endtask
(3)顶层TB的实现
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "my_driver.sv"
module top_tb;
reg clk;
reg rst_n;
reg[7:0] rxd;
reg rx_dv;
wire[7:0] txd;
wire tx_en;
dut my_dut(.clk(clk),
.rst_n(rst_n),
.rxd(rxd),
.rx_dv(rx_dv),
.txd(txd),
.tx_en(tx_en));
initial begin
my_driver drv;
drv = new("drv", null);
fork
drv.main_phase(null);
join
$finish();
end
initial begin
clk = 0;
forever begin
#100 clk = ~clk;
end
end
initial begin
rst_n = 1'b0;
#1000;
rst_n = 1'b1;
end
initial begin
$fsdbDumpfile("test.fsdb");
$fsdbDumpvars(0,top_tb);
$fsdbDumpMDA();
$fsdbDumpSVA();
end
endmodule
我们将上述代码,经VCS编译仿真运行,得到结果如下:
我们发现:此仿真结果和实际DUT 行为不符合:在rst 复位期间,rxd[7:0] 竟然随机出来数据。这显然是不正确的。问题究竟出在哪里?
对了,此问题映照了今天的主题,是SV仿真调度机制的原因。
如上图所示:总体来看,右图显示,drv.main_phase(null)的执行是放在module:top_tb......endmodule:top_tb 中的 initial begin......end 之间,执行的。并且,driver 中的top_tb.rst_n 的采样,也是发生在 active 区域,而不是发生在re-active 调度区域,所有top_tb.rst_n 的采样执行 vs rst_n = 0 阻塞赋值执行,是在同一个区域,都是在active 域。那么,此时执行的顺序,是代码的位置顺序。所以,
while(!top_tb.rst_n) @(poasedge top_tb.clk);
执行的时候,rst_n =0 还未执行,while loop 跳过执行。
二 解决方法
2.1 调换代码顺序
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "my_driver.sv"
module top_tb;
reg clk;
reg rst_n;
reg[7:0] rxd;
reg rx_dv;
wire[7:0] txd;
wire tx_en;
initial begin
clk = 0;
forever begin
#100 clk = ~clk;
end
end
initial begin
rst_n = 1'b0;
#1000;
rst_n = 1'b1;
end
dut my_dut(.clk(clk),
.rst_n(rst_n),
.rxd(rxd),
.rx_dv(rx_dv),
.txd(txd),
.tx_en(tx_en));
initial begin
my_driver drv;
drv = new("drv", null);
fork
drv.main_phase(null);
join
$finish();
end
initial begin
$fsdbDumpfile("test.fsdb");
$fsdbDumpvars(0,top_tb);
$fsdbDumpMDA();
$fsdbDumpSVA();
end
endmodule
2.2 #0 Delay
这里来看,uvm class 中的 task 是顺序执行的。但是也遵守调度规则。
2.3 uvm class 执行移到re-avtive
2.4 搭建完备的UVM 验证平台
预期波形