《The UVM Primer》——chapter3: Interface and BFM

在上一章中,我们创建了一个比较合理的验证平台,具有以下几个特点:

  • 功能覆盖率

  • 自检功能

  • 带约束的随机激励

但是这个验证平台将所有模块文件都放在了一个文件里,这使得后期的修改、重用和debug都变得非常的困难。随着后期项目和设计的复杂演化,验证平台也将变得越来越弱,这是一个巨大的缺陷。等到了项目的后期,甚至一个小小的改动都将导致验证平台的崩溃。这样的验证平台也无法用于下一个设计里。

因此需要使用一种标准化方法来创建模块化的验证平台,每次加入新代码后,其功能就更强大,也可以很容易地加入新功能到验证平台。SystemVerilog的interface封装了验证平台中的port信号,让其在modules间和objects间共享这些信号。interface可以让我们很方便的共享信号,用它们来创建 BFM,就可以对简单的总线访问协议进行封装。

TinyALU BFM( Bus Functional Model)

tinyalu_bfm封装了所有TinyALU验证平台用到的信号,并提供了一个时钟,一个reset_alu( ) task还有一个向DUT发送指令的send_op( ) task。用定义module的方式来定义一个SystemVerilog interface。从使用 interface 关键字开始,在interface中定义信号。

BFM 提供了两个 task: reset_alu( )和 send_op( )。

reset_alu( ) task 用来拉低 reset 信号,等待几个时钟然后再次拉高。

send_op( )  task 用来向 ALU 发送指令并返回结果,展示了BFM是如何封装DUT相关的协议。

operation_t是一个tinyalu_pkg包中定义的枚举类型,在interface的顶部引入

tinyalu_pkg包。

在这个例子中, task将指令和数据放在op总线和操作数总线上,之后拉高start 信号并根据指令的要求对其进行拉低。

interface tinyalu_bfm;
   import tinyalu_pkg::*;

   byteunsigned        A;
   byteunsigned        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;

   initialbegin
      clk = 0;
      foreverbegin
         #10;
         clk = ~clk;
      end
   end


   task reset_alu();
      reset_n = 1'b0;
      @(negedge clk);
      @(negedge clk);
      reset_n = 1'b1;
      start = 1'b0;
   endtask : reset_alu
   
  task send_op(inputbyte iA, inputbyte iB, input operation_t iop, outputshortint alu_result);
     
     op_set = iop;
     
     if (iop == rst_op) begin
         @(posedge clk);
         reset_n = 1'b0;
         start = 1'b0;
         @(posedge clk);
         #1;
         reset_n = 1'b1;
      endelsebegin
         @(negedge clk);
         A = iA;
         B = iB;
         start = 1'b1;
         if (iop == no_op) begin
            @(posedge clk);
            #1;
            start = 1'b0;           
         endelsebegin
            do
              @(negedge clk);
            while (done == 0);
            start = 1'b0;
         end
      end// else: !if(iop == rst_op)
      
   endtask : send_op

endinterface : tinyalu_bfm

对这个行为的封装有两个好处:

  • 不必再分散代码来处理协议级行为,调用这个 task 的代码比直接操作这些信号的代码要简单。

  • 可在一处修改所有协议级行为,一处修改可以传递到整个design。

通过BFM的创建,实现了我们三个验证平台操作(测试, 对比和覆盖)并将其连接至 DUT:

top

module top;
   tinyalu_bfm    bfm();
   tester     tester_i    (bfm);
   coverage   coverage_i  (bfm);
   scoreboard scoreboard_i(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));
endmodule : top

验证平台包括 4 个部分:

  • tinyalu_bfm         一个包含所有信号级行为的SystemVerilog interface

  • tester                   一个生成测试激励的模块

  • coverage             一个提供功能覆盖的模块

  • scoreboard         一个测试结果的模块

在模块例化的时候,我们将interface传入,验证平台只有在DUT里有信号级的连接。我们可以看到DUT的例化引用了BFM内部的信号。

scoreboard

module scoreboard(tinyalu_bfm bfm);
   import tinyalu_pkg::*;

   always @(posedge bfm.done) begin
      shortint predicted_result;
      #1;
      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
endmodule : scoreboard

通过用bfm的层次化的引用来访问BFM中的信号,剩余的逻辑跟之前验证平台

中的loop是一样的。

tester

module tester(tinyalu_bfm bfm);
   import tinyalu_pkg::*;

   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

   functionbyte get_data();
      bit [1:0] zero_ones;
      zero_ones = $random;
      if (zero_ones == 2'b00)
        return8'h00;
      elseif (zero_ones == 2'b11)
        return8'hFF;
      else
        return$random;
   endfunction : get_data
   
   initialbegin
      byteunsigned        iA;
      byteunsigned        iB;
      operation_t                  op_set;
      shortint     result;
      
      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
      $stop;
   end// initial begin
endmodule : tester

tester 模块现在更简单了,因为它不再需要处理信号级的协议了,而只需调用BFM中的task。

总结

在本章中, 将验证平台拆分成便于管理的module。这个验证平台现在有4个编译单元:tinyalu_bfm interface 、tester、scoreboard 和 coverage module。在后续章节,将用OOP来实现这个基本的四部分架构。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值