zoukankan      html  css  js  c++  java
  • UVM Primer

    在本章, 我们会把验证平台的结构跟功能进行分离。我们要添加另外一个用于搭建验证平台的类 uvm_env。然后我们会看到测试用例怎么跟这个类通过 factory来通信

    tinyalu_pkg.sv

    package tinyalu_pkg;
       import uvm_pkg::*;
    `include "uvm_macros.svh"
       
          typedef enum bit[2:0] {no_op  = 3'b000,
                              add_op = 3'b001, 
                              and_op = 3'b010,
                              xor_op = 3'b011,
                              mul_op = 3'b100,
                              rst_op = 3'b111} operation_t;
    
    
    `include "coverage.svh"
    `include "base_tester.svh"
    `include "random_tester.svh"
    `include "add_tester.svh"   
    `include "scoreboard.svh"
    `include "env.svh"
    `include "random_test.svh"
    `include "add_test.svh"
       
       
    endpackage : tinyalu_pkg

    tinyalu_bfm.sv

    interface tinyalu_bfm;
       import tinyalu_pkg::*;
    
       byte         unsigned        A;
       byte         unsigned        B;
       bit          clk;
       bit          reset_n;
       wire [2:0]   op;
       bit          start;
       wire         done;
       wire [15:0]  result;
       operation_t  op_set;
    
       assign op = op_set;
    
       task reset_alu();
          reset_n = 1'b0;
          @(negedge clk);
          @(negedge clk);
          reset_n = 1'b1;
          start = 1'b0;
       endtask : reset_alu
       
    
    
       task send_op(input byte iA, input byte iB, input operation_t iop, shortint alu_result);
          if (iop == rst_op) begin
             @(negedge clk);
             op_set = iop;
             @(posedge clk);
             reset_n = 1'b0;
             start = 1'b0;
             @(posedge clk);
             #1;
             reset_n = 1'b1;
          end else begin
             @(negedge clk);
             op_set = iop;
             A = iA;
             B = iB;
             start = 1'b1;
             if (iop == no_op) begin
                @(posedge clk);
                #1;
                start = 1'b0;           
             end else begin
                do
                  @(negedge clk);
                while (done == 0);
                alu_result = result;
                start = 1'b0;
             end
          end // else: !if(iop == rst_op)
          
       endtask : send_op
    
       initial begin
          clk = 0;
          forever begin
             #10;
             clk = ~clk;
          end
       end
    
    
    endinterface : tinyalu_bfm

    coverage.svh

    class coverage extends uvm_component;
       `uvm_component_utils(coverage)
    
       virtual tinyalu_bfm bfm;
    
       byte         unsigned        A;
       byte         unsigned        B;
       operation_t  op_set;
    
       covergroup op_cov;
    
          coverpoint op_set {
             bins single_cycle[] = {[add_op : xor_op], rst_op,no_op};
             bins multi_cycle = {mul_op};
    
             bins opn_rst[] = ([add_op:no_op] => rst_op);
             bins rst_opn[] = (rst_op => [add_op:no_op]);
    
             bins sngl_mul[] = ([add_op:xor_op],no_op => mul_op);
             bins mul_sngl[] = (mul_op => [add_op:xor_op], no_op);
    
             bins twoops[] = ([add_op:no_op] [* 2]);
             bins manymult = (mul_op [* 3:5]);
    
    
          }
    
       endgroup
    
       covergroup zeros_or_ones_on_ops;
    
          all_ops : coverpoint op_set {
             ignore_bins null_ops = {rst_op, no_op};}
    
          a_leg: coverpoint A {
             bins zeros = {'h00};
             bins others= {['h01:'hFE]};
             bins ones  = {'hFF};
          }
    
          b_leg: coverpoint B {
             bins zeros = {'h00};
             bins others= {['h01:'hFE]};
             bins ones  = {'hFF};
          }
    
          op_00_FF:  cross a_leg, b_leg, all_ops {
             bins add_00 = binsof (all_ops) intersect {add_op} &&
                           (binsof (a_leg.zeros) || binsof (b_leg.zeros));
    
             bins add_FF = binsof (all_ops) intersect {add_op} &&
                           (binsof (a_leg.ones) || binsof (b_leg.ones));
    
             bins and_00 = binsof (all_ops) intersect {and_op} &&
                           (binsof (a_leg.zeros) || binsof (b_leg.zeros));
    
             bins and_FF = binsof (all_ops) intersect {and_op} &&
                           (binsof (a_leg.ones) || binsof (b_leg.ones));
    
             bins xor_00 = binsof (all_ops) intersect {xor_op} &&
                           (binsof (a_leg.zeros) || binsof (b_leg.zeros));
    
             bins xor_FF = binsof (all_ops) intersect {xor_op} &&
                           (binsof (a_leg.ones) || binsof (b_leg.ones));
    
             bins mul_00 = binsof (all_ops) intersect {mul_op} &&
                           (binsof (a_leg.zeros) || binsof (b_leg.zeros));
    
             bins mul_FF = binsof (all_ops) intersect {mul_op} &&
                           (binsof (a_leg.ones) || binsof (b_leg.ones));
    
             bins mul_max = binsof (all_ops) intersect {mul_op} &&
                            (binsof (a_leg.ones) && binsof (b_leg.ones));
    
             ignore_bins others_only =
                                      binsof(a_leg.others) && binsof(b_leg.others);
    
          }
    
    endgroup
       
    
       function new (string name, uvm_component parent);
          super.new(name, parent);
          op_cov = new();
          zeros_or_ones_on_ops = new();
       endfunction : new
    
       function void build_phase(uvm_phase phase);
          if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
        $fatal("Failed to get BFM");
       endfunction : build_phase
       
       task run_phase(uvm_phase phase);
          forever begin  : sampling_block
             @(negedge bfm.clk);
             A = bfm.A;
             B = bfm.B;
             op_set = bfm.op_set;
             op_cov.sample();
             zeros_or_ones_on_ops.sample();
          end : sampling_block
       endtask : run_phase
          
    endclass : coverage

    scoreboard.svh

    class scoreboard extends uvm_component;
       `uvm_component_utils(scoreboard);
    
       virtual tinyalu_bfm bfm;
    
       function new (string name, uvm_component parent);
          super.new(name, parent);
       endfunction : new
    
       function void build_phase(uvm_phase phase);
          if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
            $fatal("Failed to get BFM");
       endfunction : build_phase
    
       task run_phase(uvm_phase phase);
          shortint predicted_result;
          ;
          forever begin : self_checker
             @(posedge bfm.done) 
               case (bfm.op_set)
                 add_op: predicted_result = bfm.A + bfm.B;
                 and_op: predicted_result = bfm.A & bfm.B;
                 xor_op: predicted_result = bfm.A ^ bfm.B;
                 mul_op: predicted_result = bfm.A * bfm.B;
               endcase // case (op_set)
             
             if ((bfm.op_set != no_op) && (bfm.op_set != rst_op))
               if (predicted_result != bfm.result)
                 $error ("FAILED: A: %0h  B: %0h  op: %s result: %0h",
                         bfm.A, bfm.B, bfm.op_set.name(), bfm.result);
          end : self_checker
       endtask : run_phase
    endclass : scoreboard

    base_tester.svh

    我们创建了base_tester 类,它提供了run_phase()方法。这个run_phase()方法用get_op()和get_data()方法进行1000次指令。base_tester是一个虚类,不能例化,不过可以继承base_tester来创建其他Test类
    run_phase()方法假定所有的base_tester子类都重载get_op()和get_data()方法,用pure virtual关键字来强制random_tester和add_tester来完成

    virtual class base_tester extends uvm_component;
    `uvm_component_utils(base_tester)
       virtual tinyalu_bfm bfm;
    
       function void build_phase(uvm_phase phase);
          if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
            $fatal("Failed to get BFM");
       endfunction : build_phase
    
       pure virtual function operation_t get_op();
    
       pure virtual function byte get_data();
    
       task run_phase(uvm_phase phase);
          byte         unsigned        iA;
          byte         unsigned        iB;
          operation_t                  op_set;
          shortint     result;
          
          phase.raise_objection(this);
          bfm.reset_alu();
          repeat (1000) begin : random_loop
             op_set = get_op();
             iA = get_data();
             iB = get_data();
             bfm.send_op(iA, iB, op_set, result);
          end : random_loop
          #500;
          phase.drop_objection(this);
       endtask : run_phase
       
    
       function new (string name, uvm_component parent);
          super.new(name, parent);
       endfunction : new
    
    endclass : base_tester

    random_tester.svh继承自base_tester并重载了get_op()和get_data()方法

    class random_tester extends base_tester;
       `uvm_component_utils (random_tester)
       
       function byte get_data();
          bit [1:0] zero_ones;
          zero_ones = $random;
          if (zero_ones == 2'b00)
            return 8'h00;
          else if (zero_ones == 2'b11)
            return 8'hFF;
          else
            return $random;
       endfunction : get_data
    
       function operation_t get_op();
          bit [2:0] op_choice;
          op_choice = $random;
          case (op_choice)
            3'b000 : return no_op;
            3'b001 : return add_op;
            3'b010 : return and_op;
            3'b011 : return xor_op;
            3'b100 : return mul_op;
            3'b101 : return no_op;
            3'b110 : return rst_op;
            3'b111 : return rst_op;
          endcase // case (op_choice)
       endfunction : get_op
    
       function new (string name, uvm_component parent);
          super.new(name, parent);
       endfunction : new
    
    endclass : random_tester

    add_tester.svh继承自random_tester并重载了get_op()函数

    class add_tester extends random_tester;
       `uvm_component_utils(add_tester)
    
       function operation_t get_op();
          bit [2:0] op_choice;
          return add_op;
       endfunction : get_op
             
       function new (string name, uvm_component parent);
          super.new(name, parent);
       endfunction : new
    
    endclass : add_tester

    Separating Structure from stimulus

    • base_tester是测试平台架构中关键的一环,通过base_tester可以派生出一系列的tester,然后我么可以像前两节所述,在uvm_test中例化这些tester开始仿真,这样可以正常工作但是却不利于代码维护。
    • 原因: testbench中的stimulus和structure都被封装在uvm_test中,每一个扩展自uvm_tester的都包含了,tester,coverage,scoreboard的对象,如果我们需要修改测试平台的结构,此时工作就会变得相当复杂。
    • 这样的测试平台,违背了“每个类只做一件事情”的原则,因此我们需要将平台中的structure(uvm_componnet及其子类组件)和stimulus(uvm_test及其子类)分成两个不同的功能类。UVM定义了uvm_env(扩展自uvm_component),用于存放测试平台的各个组件,uvm_env通常只包含build_phase和connect_phase两个方法。
    • 使用uvm_component将测试平台的各个组件封装起来,然后使用uvm_test将各个组件填充起来。我们首先在uvm_env中例化各个uvm_component,然后在uvm_test中例化uvm_env,此时测试平台的结构如下所示:

    版权声明:本文为CSDN博主「我不是悍跳狼丶」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_39556143/article/details/88377144

    env.svh

    env类定义了验证平台的结构。它例化了验证平台中的对象

    class env extends uvm_env;
       `uvm_component_utils(env);
    
       base_tester   tester_h;
       coverage      coverage_h;
       scoreboard    scoreboard_h;
    //下面的代码用Factory格式创建三个对象
    function void build_phase(uvm_phase phase); tester_h = base_tester::type_id::create("tester_h",this); //创建了base_tester类(抽象类)的对象,需要重载Factory coverage_h = coverage::type_id::create ("coverage_h",this); scoreboard_h = scoreboard::type_id::create("scoreboard_h",this); endfunction : build_phase function new (string name, uvm_component parent); super.new(name,parent); endfunction : new endclass

    random_test.svh

    class random_test extends uvm_test;
       `uvm_component_utils(random_test);
    
       env       env_h;
    
       function void build_phase(uvm_phase phase);
          base_tester::type_id::set_type_override(random_tester::get_type());  //重载Factory,静态方法set_type_override()告诉Factory,在看到base_class_name的请求时,返回child_class_name类型的对象
          env_h = env::type_id::create("env_h",this);  //例化env类
       endfunction : build_phase
       
       function new (string name, uvm_component parent);
          super.new(name,parent);
       endfunction : new
       
    endclass

    add_test.svh

    class add_test extends uvm_test;
       `uvm_component_utils(add_test);
    
       env       env_h;
    
       function void build_phase(uvm_phase phase);
          base_tester::type_id::set_type_override(add_tester::get_type());  //重载Factory,静态方法set_type_override()告诉Factory,在看到base_class_name的请求时,返回child_class_name类型的对象
          env_h = env::type_id::create("env_h",this);
       endfunction : build_phase
       
       function new (string name, uvm_component parent);
          super.new(name,parent);
       endfunction : new
    
    endclass

    这一节我们介绍了uvm_env,env将测试平台分割成structure和stimulus两个功能模块;
    通过定义虚类base_tester和factory override使得uvm_env (stucture)和uvm_test (stimulus) 可以通信;

    top.sv

    module top;
       import uvm_pkg::*;
       import   tinyalu_pkg::*;
    `include "tinyalu_macros.svh"
    `include "uvm_macros.svh"
       
       tinyalu_bfm       bfm();
       tinyalu DUT (.A(bfm.A), .B(bfm.B), .op(bfm.op), 
                    .clk(bfm.clk), .reset_n(bfm.reset_n), 
                    .start(bfm.start), .done(bfm.done), .result(bfm.result));
    
    
    initial begin
       uvm_config_db #(virtual tinyalu_bfm)::set(null, "*", "bfm", bfm);
       run_test();
    end
    
    endmodule : top
  • 相关阅读:
    mp4v2 基本知识
    iperf3.0 hisi uclib 交叉编译
    几个性能测试工具
    单元测试和测试驱动开发的一些常见问题总结
    线程上下文切换的性能损耗测试
    TDD中的单元测试写多少才够?
    AOP学习总结
    ATDD和TDD的区别是什么?
    [转帖]双剑合璧:CPU+GPU异构计算完全解析
    推荐《程序员的四种类型》
  • 原文地址:https://www.cnblogs.com/yiyedada/p/12376120.html
Copyright © 2011-2022 走看看