Architecting testbench-测试平台结构

1.下图是基本测试平台的结构

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.verification harness

 Instead of a monolithic block, the testbenches should be designed with a layer of physical-level busfunctional models. This physical-level layer, common to all testbenches for the design under verification, is called the verification harness. The  test functions required to implement the testcases identified in the verification plan are built on top of the verification harness, as illustrated in Figure 6-3. The test function and the harness together form a testbench.

 

 

 

 

 

 

 

 

 

 

 

 

2.1 Encapsulate the verification harness

The design under verification, the clock generators and the top-level signals and interfaces are instantiated in a top-level module. The bus-functional model instances and their connectivity to the interface instances are encapsulated in a program or a class eventually instantiated in a program. The various test functions then instantiate the encapsulated verification harness.Figure6-4 depicts the structure of the verification harness for the ATM switch node and the location of the components in the top-level module or encapsulating program or class.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//Top-level  module for ATM switch  node
 module top; 
utopia_L1_if   tx_0(), tx_1(), tx_2(), tx_3(); 
utopia_L1_if   rx_0(), rx_1(), rx_2(), rx_3(); 
utopia_mgmt_if mgmt(); 
... 
reg            reset = 0; 
reg            clk   = 0; 
 
switch_node dut(tx_0.clk, ..., clk, reset); 
 
always #5 clk = ~clk; 
 
endmodule: top 


Bus-functional models in top- level program or  class

The bus-functional models are instantiated in a top-level program or class that will eventually be instanted in a program. This ensures that the testbench executes as program threads and can reliably react to events and assertions in the design. Sample 6-4 shows the bus-functional models instantiated in a program whereas Sample 6-5 shows them instantiated in a class. Both look very similar but I prefer to use a class as it has a few advantages over a program.      

//Sample 6-4. Top-level program for ATM switch node 
program harness; 
 
utopia_L1_bfm  atm0 = new(top.tx_0, rx_0); 
utopia_L1_bfm  atm1 = new(top.tx_1, rx_1); 
utopia_L1_bfm  atm2 = new(top.tx_2, rx_2); 
utopia_L1_bfm  atm3 = new(top.tx_3, rx_3); 
utopia_mgmt_bfm cpu = new(top.mgmt); 
 
task reset; 
   top.rst <= 1; 
   repeat (3) @(negedge top.clk); 
   top.rst <= 0; 
endtask 
 
endprogram 


 

//Sample 6-5. Top-level  class for ATM  switch node 
class harness; 
   utopia_L1_bfm   atm0 = new(top.tx_0, rx_0); 
   utopia_L1_bfm   atm1 = new(top.tx_1, rx_1); 
   utopia_L1_bfm   atm2 = new(top.tx_2, rx_2); 
   utopia_L1_bfm   atm3 = new(top.tx_3, rx_3); 
   utopia_mgmt_bfm cpu  = new(top.mgmt); 
 
   task reset; 
      top.rst <= 1; 
      repeat (3) @(negedge top.clk); 
      top.rst <= 0; 
   endtask 
 
endclass: harness 


Test functions use transaction interfaces in the verification harness

 A complete verification harness provides a transaction-level abstraction of the design to be verified. It provides a foundation on which the data generation mechanism, the self-checking structure and the functional coverage measurements are built. Test functions are implemented by using the transaction-level interface elements
in the bus-functional models and verification harness itself. These interface elements are accessed using hierarchical references in a single instance of the verification harness. Sample 6-6 shows a partial test function that configures the device then injects an ATM cell in one of the ports. 
 
 

//Sample 6-6. Test function using a verification harness 
program my_test; 
 
harness th = new; 
 
initial 
begin 
   atm_cell cell; 
th.cpu.write(16’h0001, 16’h0010); 
   ... 
th.atm0.send(cell); 
   ... 
   $finish; 
end 
 
endprogram: my_test 
 

 

3. design configuration

 it is good practice to collect all device configuration information under a single descriptor.

4. self checking testbench

5.directed stimulus

//Sample 6-22. Random-filled directed instruction sequence stimulus
instr.randomize() with { 
   opcode == CMP; 
}; 
... 
repeat (3) begin 
   instr.randomize() with { 
      opcode == NOP; 
   }; 
end 
... 
instr.randomize() with { 
   opcode == BLT; 
}; 
... 
6.random stimulus
6.1产生随机数据流很简单
generators are output-only bus-functional models. Their output is a transaction-level interface, the stream of generated random transactions. 
//Sample 6-24. Simple random generator 
class atm_gen; 
   ... 
   function new(); 
      ... 
      fork 
         this.main(); 
      join_none 
   endfunction: new 
 
   task main(); 
      atm_cell cell; 
 
      repeat (100) begin 
         cell = new; 
         if (!cell.randomize()) ... 
         ... 
      end 
   endtask: main 
endclass: atm_gen 
6.2 定义中断机制
The simple random generator in Sample 6-24 will always generate 100 cells then terminate. This number is completely arbitrary and is unlikely to satisfy the needs of all testcases. During initial design debug stage, generating just a single data item is often required. A random testbench must run for much longer to increase the likelihood that functional coverage points will be hit. Generators should have several termination mechanisms that can be armed at the start of the simulation (such as the number of objects to generate) or externally triggered by the testbench. Sample 6-25 shows a generator that, by default, will generate an infinite number of objects. It will also not start immediately, leaving time for the testbench to configure the device before starting to generate stimulus. The generator also can be suspended at anytime by calling the  stop() method. Sample 6-26 shows how a debug testcase can configure the generator to generate a single cell on a randomly selected port and no cells on the others.   
//Sample 6-25. Random generator with termination mechanisms
class atm_gen; 
   ... 
   int stop_after = -1; 
 
   function new(); 
      ... 
   endfunction: new 
 
   function void start(); 
      fork 
         this.main(); 
      join_none 
   endfunction: start 
 
   function void stop(); 
      this.stop_after = 0; 
   endfunction: stop 
   virtual task main(); 
      atm_cell cell; 
 
      while (this.stop_after != 0) begin 
         cell = new; 
         if (!cell.randomize()) ... 
         ... 
         if (this.stop_after > 0) begin 
            this.stop_after--; 
         end 
      end 
   endtask: main 
endclass: atm_gen 

6.3 adding constraints

The simplest mechanism for adding constaints is to add them to the class being randomized.The problem with this approach is that the constraint will apply to every
instance of the object in all future simulations and models. If the objective was to inject a specific condition for a specific testcase or simulation, this approach will not work.

可以打开和关闭constraint:

class atm_cell; 
   ... 
   constraint vpi_is_0 { 
      vpi == 0; 
   } 
 
   function new(); 
      this.vpi_is_0.constraint_mode(0); 
   endfunction: new 
endclass: atm_cell 


 6.4 constraint sequence

//Sample 6-40. Generating sequences using an array 
class atm_cell_seq; 
   rand atm_cell randomized_cells[]; 
endclass: atm_cell_seq 
 
class atm_gen; 
   ... 
   atm_cell_seq randomized_seq; 
 
   virtual task main(); 
      while (this.stop_after != 0) begin 
         ... 
         ok = this.randomized_seq.randomize(); 
         ... 
      end 
   endtask: main 
endclass: atm_gen 


 

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值