首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >我眼中的UVM|只有driver的验证平台

我眼中的UVM|只有driver的验证平台

作者头像
用户10108023
发布2022-10-28 16:12:19
发布2022-10-28 16:12:19
56000
代码可运行
举报
运行总次数:0
代码可运行

嗨,屏幕前的你还好吗?我是不二鱼,一个不喜欢写技术博客的IC验证工程师,写这个系列,是需要很大的勇气的,因为,写得人很多,但写得好的不多,我也是如此。我一个菜鸡,敢写UVM(应该也不止UVM,我尽量把其他知识杂糅进去),我是疯了吗?至今能有比张强老师写得好的估计也没有,我之所以写,是为了促进自己进步,换了一个新的环境,使用UVM也是日常必备,所以,以写促学,写一写我眼中的UVM,也希望能和大家一起学习,相互成就,如有错误,欢迎私信我批评指正。

一个技术帖为什么选这么个小清新的模板,是因为,想让你看完如沐春风,没有压力感,哈哈哈。

更新频率:暂定一周一更。

01

UVM小剧场

大家好,我是一个漂洋过海来到中国的外国萌妹子,我叫UVM,大家可以加我幽梦。我的职业是灵魂注入师,是不是有一点玄幻?由于业务扩张,我已经开了自己的工作室,我已经退居幕后。

成立初期的时候,我其实只招募到一个成员,他就是“driver”。“driver”是一名出色的灵魂注入工程师,他任劳任怨负责了工作室大部分的工作,包括和客户直接对接,下面再介绍一下我们真正的客户-DUT。

“大家好,我叫DUT,我是一团行尸走肉的verilg代码,我是躺平一族的代表性人物。”

有一天,我按照惯例游荡在人世间,和形形色色的擦肩而过,但没有一个人感受到了我的存在,直到,我遇到一个人。这个人,他告诉我,他的英文名字叫做“driver”,洋里洋气的。谁还没个英文名,我也告诉他,我叫DUT,我没有灵魂。

他说,“好巧啊,我的职业是,灵魂注入师,来自幽梦工作室,快让我拯救你!”说着,他拿出来一个超大型的注射器,准备往我身体里,注入灵魂。

“雅蠛蝶,住手!!滚你丫的,第一次面,你就要扎我,你的灵魂,是通用的吗?注入我的身体里面,会不会有排斥反应啊!我害怕!”

他说,“别怕,谁都会有第一次,不疼,我的灵魂药剂叫做激励,在遇见你的那一刻,我量身为你定制的,相信我,我是专业的,快趴下。”

哈哈哈哈哈,小剧场结束啦~~

02

只有driver的验证平台

对于一个验证平台而言,最重要的角色是激励的产生,最开始,driver是集合了数据的产生、发送于一体这么一个重要的角色(后面到进入真正UVM会将功能分离)。对于整个验证平台而言,产生激励,将激励送到DUT,收集DUT产生的数据,进行对比,这是最基本的功能。后面一系列的UVM机制,都只是为了能够更好的实现这个基本功能。

这里也强调一点,学习UVM,我个人觉得最重要的是搞清楚,what,where,how。你应该产生什么样的激励数据(what),你的激励是在哪里产生(where),能各个组件之间是怎么连接,数据怎么发送,怎么收集,怎么对比,这就是how的问题。数据在哪里对比,这又是where的问题。能够从数据产生的源头,一路追,追到数据在各个组件里头的流转。就像你找到了一条小溪的源头,你能够沿着这条小溪,一路追下去,直到你明白这条小溪会流经那些村庄,目的地是哪里。

学过verilog的应该知道,verilog里面进行验证,只有两个部分,一个是DUT,一个是tb,这两个组件,组成了最最基本的验证平台,其中,它包含了激励部分,以及代码部分。在UVM中,最基本的验证平台也是由这两部分组成,但是多了一个top_tb.sv的组件。下面,先认识一下这个简单的平台,从代码进行剖析,代码全部来自张强老师的《UVM》实战的源码,张强老师如果觉得我侵权了,请联系我。

代码语言:javascript
代码运行次数:0
运行
复制
module dut(clk,
           rst_n, 
           rxd,
           rx_dv,
           txd,
           tx_en);
input clk;
input rst_n;
input[7:0] rxd;
input rx_dv;
output [7:0] txd;
output tx_en;

reg[7:0] txd;
reg tx_en;

always @(posedge clk) begin
   if(!rst_n) begin
      txd <= 8'b0;
      tx_en <= 1'b0;
   end
   else begin
      txd <= rxd;
      tx_en <= rx_dv;
   end
end
endmodule

这个dut确实是很简单。当复位也就是rst_n=0时,将输出数据(txd)和使能(tx_en)都设置为0,否则,将输入给输出。

看到这个DUT,如果让你自己写一个Tb.v,你会怎么写呢?不妨自己写一个,然后再对照下面这个。其实思路也很简答,就是产生相应的数据给四根输入信号,经过dut,看输出的数据。产生时钟给clk,产生复位信号给rst_n,产生数据给rxd,产生使能信号给rx_dv。下面我们来看看driver和tb。

代码语言:javascript
代码运行次数:0
运行
复制
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SV
//这个`ifndef和`define其实就是相当于一个判断条件,便于调用
class my_driver extends uvm_driver;
   function new(string name = "my_driver", uvm_component parent = null);
      super.new(name, parent);
   endfunction
   extern virtual task main_phase(uvm_phase phase);
endclass
//这里出现了extern,你翻翻SV的书就知道,只是因为把代码全部写在这个类里面显得臃肿
//所以,在这里用extern留下了一个索引,具体的内容放到class外面
task my_driver::main_phase(uvm_phase phase);//::作用域符号,这个写法就是个规则,记住就行
   top_tb.rxd <= 8'b0; 
   top_tb.rx_dv <= 1'b0;
//这两句相当于初始化
   while(!top_tb.rst_n)//这里其实是等待复位结束,否则一直在这里循环
      @(posedge top_tb.clk);
   for(int i = 0; i < 256; i++)begin// 复位结束之后开始for循环,产生256个数据
      @(posedge top_tb.clk);
      top_tb.rxd <= $urandom_range(0, 255);//产生随机数,赋值给rxd
      top_tb.rx_dv <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW)
   end
   @(posedge top_tb.clk);//赋值结束以后,等待时钟上升沿,将rx_dv,重新归零
   top_tb.rx_dv <= 1'b0;
endtask
`endif
代码语言:javascript
代码运行次数:0
运行
复制
`timescale 1ns/1ps //时钟精度
`include "uvm_macros.svh"//导入uvm的库文件,才能识别定义的宏变量

import uvm_pkg::*; // 导入uvm的包
`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));
//这是信号的例化,相当于把这个文件中的信号,和DUT的输入信号连接起来
initial begin
   my_driver drv;//指定一个类的指针,你可以理解为用drv代替了driver.
   drv = new("drv", null);//实例化一个driver,不实例化的driver相当于一张图纸
   drv.main_phase(null);
   $finish();
end

initial begin
   clk = 0;
   forever begin  // forever,永远发生,你还能想到其他方法吗?
      #100 clk = ~clk; //这是产生时钟的地方,#是延迟,意思是每隔100个时钟单位,clk进行翻转
   end
end

initial begin
   rst_n = 1'b0;
   #1000; //复位持续了1000个时钟单位
   rst_n = 1'b1;
end

endmodule

用vcs进行仿真,如果不会配置,参照下面的链接:

如何跑通《UVM实战》书上的例子?

看一下波形:

从波形图中,我们怎么看呢?看复位,是不是在1000个时间单位以前在复位;看采样,复位之后的时钟上升沿是否开始采样,采的样是不是复位之后的有效数据,看数据,数据个数,对照输入输出的数据是否一致;我们就基本可以判定,DUT的功能有没有实现。

这一次分享就到此结束了,希望对你的学习有帮助,最后,希望能点个赞支持一下,你的鼓励是我最大的动力!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 不二鱼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档