• uvm白皮书练习_ch2_ch221只有driver的验证平台之*2.2.1 最简单的验证平台


    uvm白皮书练习
    ch221


    dut.sv
    这个DUT的功能非常简单,通过rxd接收数据,再通过txd发送出去。其中rx_dv是接收的数据有效指示,tx_en是发送的数据有效指示。

    module dut (
        clk,
        rst_n,
        rxd,
        rx_dv,
        txd,
        tx_en
    );
        input clk    ;   
        input rst_n  ;   
        input rxd    ; 
        input rx_dv  ;   
        output txd   ;  
        output tx_en ; 
    
    reg [7:0]   txd;
    reg         tx_en;    
    
    always @(posedge clk) begin
        if(!rst_n)begin
            txd     <=  8'h00;
            tx_en   <=  1'b0;
        end
        else begin
            txd     <=  rxd;
            tx_en   <=  rx_dv;
        end
    end
    endmodule
    
    • 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

    my_driver.sv
    所有派生自uvm_driver的类的new函数有两个参数,一个是string类型的name,一个是uvm_component类型的parent。关于name参数,比较好理解,就是名字而已;至于parent则比较难以理解,读者可暂且放在一边,下文会有介绍。事实上,这两个参数是由uvm_component要求的,每一个派生自uvm_component或其派生类的类在其new函数中要指明两个参数:name和parent,这是uvm_component类的一大特征。而uvm_driver是一个派生自uvm_component的类,所以也会有这两个参数。
    driver所做的事情几乎都在main_phase中完成。UVM由phase来管理验证平台的运行,这些phase统一以xxxx_phase来命名,且都有一个类型为uvm_phase、名字为phase的参数。main_phase是uvm_driver中预先定义好的一个任务。因此几乎可以简单地认为,实现一个driver等于实现其main_phase。上述代码中还出现了uvm_info宏。这个宏的功能与Verilog中display语句的功能类似,但是它比display语句更加强大。它有三个参数,第一个参数是字符串,用于把打印的信息归类;第二个参数也是字符串,是具体需要打印的信息;第三个参数则是冗余级别。在验证平台中,某些信息是非常关键的,这样的信息可以设置为UVM_LOW,而有些信息可有可无,就可以设置为UVM_HIGH,介于两者之间的就是UVM_MEDIUM。UVM默认只显示UVM_MEDIUM或者UVM_LOW的信息
    uvm_info宏非常强大,它包含了打印信息的物理文件来源、逻辑结点信息(在UVM树中的路径索引)、打印时间、对信息的分类组织及打印的信息。读者在搭建验证平台时应该尽量使用uvm_info宏取代display语句。
    类的定义类似于在纸上写下一纸条文,然后把这些条文通知给SystemVerilog的仿真器:验证平台可能会用到这样的一个类,请做好准备工作。而类的实例化在于通过new()来通知SystemVerilog的仿真器:请创建一个A的实例。仿真器接到new的指令后,就会在内存中划分一块空间,在划分前,会首先检查是否已经预先定义过这个类,在已经定义过的情况下,按照定义中所指定的“条文”分配空间,并且把这块空间的指针返回给a_inst,之后就可以通过a_inst来查看类中的各个成员变量,调用成员函数/任务等。对大部分的类来说,如果只定义而不实例化,是没有任何意义的(这里的例外是一些静态类,其成员变量都是静态的,不实例化也可以正常使用。);而如果不定义就直接实例化,仿真器将会报错。
    第2行把uvm_macros.svh文件通过include语句包含进来。这是UVM中的一个文件,里面包含了众多的宏定义,只需要包含一次。
    第4行通过import语句将整个uvm_pkg导入验证平台中。只有导入了这个库,编译器在编译my_driver.sv文件时才会认识其中的uvm_driver等类名。
    第24和25行定义一个my_driver的实例并将其实例化。注意这里调用new函数时,其传入的名字参数为drv,前文介绍uvm_info宏的打印信息时出现的代表路径索引的drv就是在这里传入的参数drv。另外传入的parent参数为null,在真正的验证平台中,这个参数一般不是null,这里暂且使用null。
    第26行显式地调用my_driver的main_phase。在main_phase的声明中,有一个uvm_ phase类型的参数phase,在真正的验证平台中,这个参数是不需要用户理会的。本节的验证平台还算不上一个完整的UVM验证平台,所以暂且传入null。
    第27行调用finish函数结束整个仿真,这是一个Verilog中提供的函数。
    (行数不一定一一对应,需要自己判断)

    `ifndef MY_DRIVER_SV
    `define MY_DRIVER_SV
    
    class my_driver  extends uvm_driver;
        function new(string name="my_driver",uvm_component parent =null);
            super.new(name,parent);
        endfunction //new()
        extern  virtual task main_phase(uvm_phase phase);//调用附近的代码
    endclass //my_driver  extends uvm_driver
    
    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<25;i++)begin
            @(posedge top_tb.clk);//等个时钟
            top_tb.rxd <= i[7:0];
            // top_tb.rxd <= $urand_range(0.255);
            top_tb.rx_dv    <= 1'b1;
            `uvm_info("my_driver","data is driver",UVM_LOW);
        end
        @(posedge top_tb.clk);
        top_tb.rx_dv    <=  1'b0;
    endtask //my_driver::main_phase
    `endif
    
    • 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

    top_tb.sv

    `timescale 1ns/1ns
    `include "uvm_macros.sv"
    
    import uvm_pkg::*;
    `include "my_driver.sv"
    
    module top_tb ;
    reg         clk     ;    //时钟
    reg         rst_n   ;   //复位
    reg [7:0]   rxd     ;   //接受数据
    reg         rx_dv   ;   //接受数据
    reg [7:0]   txd     ;   //发送数据
    reg         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);//传入数据
        drv.main_phase(null);
        $finish;
    end
    /*时钟模块*/
    initial begin
        clk = 0;
        forever begin
            #100ns clk = ~clk;
        end
    end
    /*复位模块*/
    initial begin
        rst_n = 1'b0;
        #1000;
        rst_n = 1'b1;
    end
    
    /*fsdb*/
    initial begin
        $fsdbDumpfile("verilog.fsdb");
        $fsdbDumpvars(0);
        $display("fsdbDumpfilrs is start at %d",$time);
        // #1e7;
        // $finish;
    end
    endmodule
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    仿真结果
    激励本来是256次,发送随机数,这里为了方便直观,改25次,升序

    fsdbDumpfilrs is start at                    0
    UVM_INFO my_driver.sv(22) @ 1000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 3000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 5000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 7000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 9000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 11000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 13000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 15000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 17000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 19000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 21000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 23000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 25000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 27000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 29000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 31000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 33000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 35000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 37000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 39000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 41000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 43000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 45000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 47000: drv [my_driver] data is driver
    UVM_INFO my_driver.sv(22) @ 49000: drv [my_driver] data is driver
    $finish called from file "top_tb.sv", line 28.
    $finish at simulation time                51000
    
    
    • 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
  • 相关阅读:
    【HCIE】11.EVPN路由
    上传百度文库有什么技巧吗?百度文库上传怎样才能成功
    Nexus存储库管理器搭建-Maven私服
    getchar函数设置为非阻塞
    《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(19)-Fiddler精选插件扩展安装,将你的Fiddler武装到牙齿
    基于SpringBoot的在线点餐系统【附源码】
    【数据湖架构】在 Azure Data Lake Storage (ADLS)二代上构建数据湖
    大语言模型(LLM)技术名词表(一)
    聊聊 MQTT 和 WebSocket
    提供一个springboot使用h2数据库是无法使用脚本并报错的处理方案
  • 原文地址:https://blog.csdn.net/qq_36683398/article/details/132999920