zoukankan      html  css  js  c++  java
  • testbench的设计 文件读取和写入操作 源代码

    十大基本功之 testbench

    1. 激励的产生


    对于 testbench 而言,端口应当和被测试的 module 一一对应。
    端口分为 input,output 和 inout 类型产生激励信号的时候,
    input  对应的端口应当申明为 reg,
    output 对应的端口申明为 wire,
    inout  端口比较特殊,下面专门讲解。

    1)直接赋值


    一般用 initial 块给信号赋初值,initial 块执行一次,always 或者 forever 表示由事件激发反复执行。
    举例,一个 module

    [plain] view plain copy
     
    1. `timescale 1ns/1ps  
    2.   
    3. module exam();  
    4.   reg   rst_n;  
    5.   reg   clk;  
    6.   reg   data;  
    7.     
    8.   initial  
    9.   begin  
    10.     clk = 1'b0;  
    11.     rst = 1'b1;  
    12.     #10  
    13.     rst = 1'b0;  
    14.     #500  
    15.     rst = 1'b1;  
    16.   end  
    17.     
    18.   always  
    19.   begin  
    20.     #10 clk = ~clk;  
    21.   end  
    22.     
    23. endmodule  



    大家应该注意到有个#符号,该符号的意思是指延迟相应的时间单位。该时间单位由 timscale 决定.


    一般在 testbench 的开头定义时间单位和仿真精度,比如`timescale 1ns/1ps
    前面一个是代表时间单位,后面一个代表仿真时间精度。
    以上面的例子而言,一个时钟周期是 20 个单位,也就是 20ns。


    而仿真时间精度的概念就是,你能看到 1.001ns 时对应的信号值,
    而假如 timescale 1ns/1ns,1.001ns 时候的值就无法看到。
    对于一个设计而言,时间刻度应该统一,如果设计文件和 testbench 里面的时间刻度不一致,
    仿真器默认以 testbench 为准。


    一个较好的办法是写一个 global.v 文件,然后用 include 的办法,可以防止这个问题。

    对于反复执行的操作,可写成 task,然后调用,比如

    [plain] view plain copy
     
    1. task load_count;  
    2.   
    3. input [3:0] load_value;  
    4.   begin  
    5.     @(negedge clk_50);  
    6.     $display($time, " << Loading the counter with %h >>", load_value);  
    7.     load_l   = 1’b0;  
    8.     count_in = load_value;  
    9.     @(negedge clk_50);  
    10.     load_l   = 1’b1;  
    11.   end  
    12. endtask //of load_count  
    13.   
    14. initial  
    15. begin  
    16.   load_count(4’hA); // 调用 task  
    17. end  



    其他像 forever,for,function 等等语句用法类似,虽然不一定都能综合,但是用在 testbench 里面很方
    便,大家可以自行查阅参考文档

    2) 文件输入


    有时候,需要大量的数据输入,直接赋值的话比较繁琐,可以先生成数据,再将数据读入到寄存器中,
    需要时取出即可。
    用 $readmemb 系统任务从文本文件中读取二进制向量(可以包含输入激励和输出期望值)。
    $readmemh 用于读取十六进制文件。例如:


    [plain] view plain copy
     
    1. reg   [7:0]  mem[256:1] // a 8-bit, 256-word 定义存储器 mem  
    2. initial $readmemh ( "E:/readhex/mem.dat", mem ) // 将.dat 文件读入寄存器 mem 中  
    3. initial $readmemh ( "E:/readhex/mem.dat", mem, 128, 1 ) // 参数为寄存器加载数据的地址始终  


    文件调入和打印中,我们 $fread $fwrite 用的更多一些, 大家可以自行查阅参考文档


    2. 查看仿真结果


    对于简单的 module 来说,要在 modelsim 的仿真窗口里面看波形,就用 add wave ..命令
    比如, testbench 的顶层 module 名叫 tb,要看时钟信号,就用 add wave tb.clk
    要查看所有信号的时候,就用 add wave /*  

    当然,也可以在 workspace 下的 sim 窗口里面右键单击 instance 来添加波形
    对于复杂的仿真,免不了要记录波形和数据到文件里面去。

    1)波形文件记录(这部分暂时我没用到呢!)

    常见的波形文件一般有两种, vcd 和 fsdb, debussy 是个很好的工具,支持 fsdb,所以最好是 modelsim+debussy 的组
    合默认情况下, modelsim 不认识 fsdb,所以需要先装 debussy,再生成 fsdb 文件。


    $dumpfile 和$dumpvar 是 verilog 语言中的两个系统任务, 可以调用这两个系统任务来创建和将指定信息导入 VCD 文件.
    对于 fsdb 文件来说,对应的命令是 fsdbDumpfile,dumpfsdbvars


    (什么是 VCD 文件? 答: VCD 文件是在对设计进行的仿真过程中,记录各种信号取值变化情况的信息记录文件。 EDA
    工具通过读取 VCD 格式的文件,显示图形化的仿真波形,所以,可以把 VCD 文件简单地视为波形记录文件.)下面分别
    描述它们的用法并举例说明之。

    [plain] view plain copy
     
    1. $dumpfile 系统任务:为所要创建的 VCD 文件指定文件名。  
    2. 举例( "//"符号后的内容为注释文字):  
    3. initial  
    4. $dumpfile ("myfile.dump"); //指定 VCD 文件的名字为 myfile.dump,仿真信息将记录到此文件  
    5. $dumpvar 系统任务:指定需要记录到 VCD 文件中的信号,可以指定某一模块层次上的所有信号,也可以单独指定某一  
    6. 个信号。  
    7. 典型语法为$dumpvar(level, module_name); 参数 level 为一个整数, 用于指定层次数, 参数 module 则指定要记录的模块。  
    8. 整句的意思就是,对于指定的模块,包括其下各个层次(层次数由 level 指定)的信号,都需要记录到 VCD 文件中去。  
    9.   
    10.   
    11. 举例:  
    12.   initial  
    13.     $dumpvar (0, top); //指定层次数为 0,则 top 模块及其下面各层次的所有信号将被记录  
    14.   
    15.   initial  
    16.     $dumpvar (1, top); //记录模块实例 top 以下一层的信号  
    17.   //层次数为 1,即记录 top 模块这一层次的信号  
    18.   //对于 top 模块中调用的更深层次的模块实例,则不记录其信号变化  
    19.   
    20.   initial  
    21.     $dumpvar (2, top); //记录模块实例 top 以下两层的信号  
    22.   
    23.   //即 top 模块及其下一层的信号将被记录  
    24.   假设模块 top 中包含有子模块 module1,而我们希望记录 top.module1 模块以下两层的信号,则语法举例如下:  
    25.   initial  
    26.     $dumpvar (2, top.module1); //模块实例 top.module1 及其下一层的信号将被记录  
    27.   假设模块 top 包含信号 signal1 和 signal2(注意是变量而不是子模块), 如我们希望只记录这两个信号,则语法举例如下:  
    28.   
    29.   initial  
    30.     $dumpvar (0, top.signal1, top.signal2); //虽然指定了层次数,但层次数是不影响单独指定的信号的  



      //即指定层次数和单独指定的信号无关
      我们甚至可以在同一个$dumpvar 的调用中,同时指定某些层次上的所有信号和某个单独的信号,假设模块 top 包含信
      号 signal1,同时包含有子模 块 module1,如果我们不但希望记录 signal1 这个独立的信号,而且还希望记录子模块 module1
      
      以下三层的所有信号,则语法举例如下:
      

    [plain] view plain copy
     
    1. initial  
    2.     $dumpvar (3, top.signal1, top.module1); //指定层次数和单独指定的信号无关  
    3.                                             //所以层次数 3 只作用于模块 top.module1, 而与信号  
    4.   top.signal1 无关  



      
      上面这个例子和下面的语句是等效的:
      

    [plain] view plain copy
     
    1. initial  
    2.     begin  
    3.     $dumpvar (0, top.signal1);  
    4.     $dumpvar (3, top.module1);  
    5.   end  
    6.     
    7. $dumpvar 的特别用法(不带任何参数):  
    8.   initial  
    9.   $dumpvar; //无参数,表示设计中的所有信号都将被记录  


    最后,我们将$dumpfile 和$dumpvar 这两个系统任务的使用方法在下面的例子中综合说明,假设我们有一个设计实例,
    名为 i_design,此设计中包含模块 module1,模块 module1 下面还有很多层次,我们希望对这个设计进行仿真,并将仿
    真过程中模块 module1 及其以下所有层次中所有信号的变化情况,记录存储到名为 mydesign.dump 的 VCD 文件中去,
    则例示如下:

    [plain] view plain copy
     
    1. initial  
    2. begin  
    3.   $dumpfile ("mydesign.dump"); //指定 VCD 文件名为 mydesign.dump  
    4.   $dumpvar (0, i_design.module1); //记录 i_design.module1 模块及其下面层次中所有模块的所有信号  
    5. end  

      
      对于生成 fsdb 文件而言,也是类似的

    [plain] view plain copy
     
    1. initial  
    2. begin  
    3.   $fsdbDumpfile("tb_xxx.fsdb");  
    4.   $fsdbDumpvars(0,tb_xxx);  
    5. end  

    2)文件输出结果

      integer out_file; // out_file 是一个文件描述,需要定义为 integer 类型
      out_file = $fopen ( " cpu.data " ); // cpu.data 是需要打开的文件,也就是最终的输出文本
    设计中的信号值可以通过$fmonitor, $fdisplay,$fwrite
    其中$fmonitor 只要有变化就一直记录, $fdisplay 和$fwrite 需要触发条件才记录
    例子:
      

    [plain] view plain copy
     
    1. initial begin  
    2.     $fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);  
    3.     end  
    4.     always@(a or b)  
    5.     begin  
    6.     $fwrite(file_id,"At time%t a=%b b=%b",$realtime,a,b);  
    7.   end  
    8.     

    3 参考“A Verilog HDL Test Bench Primier.pdf”

    1) DUT(Design Under Test)部分

    [plain] view plain copy
     
    1. //-------------------------------------------------  
    2. // File: count16.v  
    3. // Purpose: Verilog Simulation Example  
    4. //-------------------------------------------------  
    5. `timescale 1 ns / 100 ps  
    6. module count16 (  
    7.        clk,  
    8.        rst_n,  
    9.        load_l,  
    10.        enable_l,  
    11.        cnt_in,  
    12.        oe_l,  
    13.          
    14.        count,  
    15.        count_tri  
    16.        );  
    17.         
    18.   input         clk;  
    19.   input         rst_n;  
    20.     
    21.   input         load_l;  
    22.   input         enable_l;  
    23.   input  [3:0]  cnt_in;  
    24.   input         oe_l;  
    25.                   
    26.   output [3:0]  count;  
    27.   output [3:0]  count_tri;  
    28.     
    29.   reg    [3:0]  count;  
    30.     
    31.   // tri-state buffers  
    32.   assign count_tri = (!oe_l) ? count : 4'bZZZZ;  
    33.     
    34.     
    35.   // synchronous 4 bit counter  
    36.     
    37.   always @ (posedge clk or negedge rst_n)  
    38.   if (!rst_n) begin  
    39.     count <=  4'd0;  
    40.   end  
    41.   else begin  
    42.     if (!load_l) begin  
    43.       count <=  cnt_in;  
    44.     end  
    45.     else if (!enable_l) begin  
    46.       count <=  count + 1;  
    47.     end  
    48.   end  
    49.     
    50. endmodule //of count16  

    2) Test Bench 

    [plain] view plain copy
     
    1. //-------------------------------------------------  
    2. // File: tb.v  
    3. // Purpose: Verilog Simulation Example  
    4. // Test Bench  
    5. //-----------------------------------------------------------  
    6. `timescale 1ns / 100ps  
    7. module tb ();  
    8.     
    9.   //---------------------------------------------------------  
    10.   // inputs to the DUT are reg type  
    11.   reg         clk_50;  
    12.   reg         rst_n;  
    13.   reg         load_l;   
    14.   reg         enable_l;  
    15.     
    16.   reg  [3:0]  count_in;  
    17.   reg         oe_l;  
    18.     
    19.   //--------------------------------------------------------  
    20.   // outputs from the DUT are wire type  
    21.   wire [3:0]  cnt_out;  
    22.   wire [3:0]  count_tri;  
    23.     
    24.     
    25.   //----------------------------------------------------------  
    26.   // create a 50Mhz clock  
    27.   always  #10 clk_50 = ~clk_50; // every ten nanoseconds invert  
    28.     
    29.     
    30.   //-----------------------------------------------------------  
    31.   // initial blocks are sequential and start at time 0  
    32.   initial  
    33.   begin  
    34.     $display($time, " << Starting the Simulation >>");  
    35.     clk_50 = 1'd0;  
    36.       
    37.     // at time 0  
    38.     rst_n = 0;  
    39.       
    40.     // reset is active  
    41.     enable_l = 1'd1;  
    42.       
    43.     // disabled  
    44.     load_l = 1'd1;  
    45.       
    46.     // disabled  
    47.     count_in = 4'h0;  
    48.     oe_l = 4'b0;  
    49.       
    50.     // enabled  
    51.     #20 rst_n = 1'd1;  
    52.       
    53.     // at time 20 release reset  
    54.     $display($time, " << Coming out of reset >>");  
    55.       
    56.     @(negedge clk_50); // wait till the negedge of  
    57.                        // clk_50 then continue  
    58.     load_count(4'hA);  
    59.       
    60.     // call the load_count task  
    61.       
    62.     @(negedge clk_50);  
    63.     $display($time, " << Turning ON the count enable >>");  
    64.       
    65.     enable_l = 1'b0;  
    66.     // turn ON enable  
    67.     // let the simulation run,  
    68.     // the counter should roll  
    69.     wait (cnt_out == 4'b0001); // wait until the count  
    70.       
    71.     // equals 1 then continue  
    72.     $display($time, " << count = %d - Turning OFF the count enable >>",cnt_out);  
    73.     enable_l = 1'b1;  
    74.     #40;  
    75.       
    76.     // let the simulation run for 40ns  
    77.     // the counter shouldn't count  
    78.     $display($time, " << Turning OFF the OE >>");  
    79.     oe_l = 1'b1;  
    80.       
    81.       
    82.     // disable OE, the outputs of  
    83.     // count_tri should go high Z.  
    84.     #20;  
    85.     $display($time, " << Simulation Complete >>");  
    86.     $stop;  
    87.       
    88.     // stop the simulation  
    89.   end  
    90.     
    91.     
    92.   //--------------------------------------------------------------  
    93.   // This initial block runs concurrently with the other  
    94.   // blocks in the design and starts at time 0  
    95.     
    96.   initial begin  
    97.   // $monitor will print whenever a signal changes  
    98.   // in the design  
    99.     $monitor(  
    100.       $time,   
    101.       " clk_50=%b, rst_n=%b, enable_l=%b, load_l=%b, count_in=%h, cnt_out=%h, oe_l=%b, count_tri=%h",  
    102.       clk_50, rst_n, enable_l, load_l, count_in, cnt_out, oe_l, count_tri  
    103.     );  
    104.   end  
    105.     
    106.     
    107.   //--------------------------------------------------------------  
    108.   // The load_count task loads the counter with the value passed  
    109.   task load_count;  
    110.     input [3:0] load_value;  
    111.       
    112.     begin  
    113.       @(negedge clk_50);  
    114.         $display($time, " << Loading the counter with %h >>", load_value);  
    115.         load_l = 1'b0;  
    116.         count_in = load_value;  
    117.       
    118.       @(negedge clk_50);  
    119.         load_l = 1'b1;  
    120.     end  
    121.   endtask //of load_count  
    122.     
    123.     
    124.     
    125.   //---------------------------------------------------------  
    126.   // instantiate the Device Under Test (DUT)  
    127.   // using named instantiation  
    128.   count16 count16_m0 (  
    129.     .clk       (clk_50),  
    130.     .rst_n     (rst_n),  
    131.     .load_l    (load_l),  
    132.     .cnt_in    (count_in),  
    133.     .enable_l  (enable_l),  
    134.     .oe_l      (oe_l),  
    135.       
    136.     .count     (cnt_out),  
    137.     .count_tri (count_tri)  
    138.   );  
    139.     
    140.     
    141.     
    142.   //---------------------------------------------------------  
    143.   // read and write data  
    144.   reg  [7:0] mem[10:1];//read data from file  
    145.     
    146.   initial $readmemh ("F:/IC/prj/testbench/prj0/data/mem.dat", mem ); // 将.dat 文件读入寄存器 mem 中  
    147.     
    148.     
    149.   //设计中的信号值可以通过$fmonitor, $fdisplay,$fwrite  
    150.   //其中$fmonitor 只要有变化就一直记录, $fdisplay 和$fwrite 需要触发条件才记录  
    151.     
    152.   integer file_out; // out_file 是一个文件描述,需要定义为 integer 类型  
    153.   initial file_out = $fopen("F:/IC/prj/testbench/prj0/data/wr_mem.dat", "w");  
    154.     
    155.   // wr_mem.dat 是需要打开的文件,也就是最终的输出文本  
    156.     
    157.   always @(posedge clk_50)  
    158.     if (/*tb.count16_m0.*/enable_l == 1'd0) begin  
    159.       $fwrite (file_out, "%h ", cnt_out[3:0]);  
    160. //      $fdisplay(file_out, "%h", cnt_out[3:0]);  
    161.     end  
    162.     
    163.     
    164. endmodule //of cnt16_tb  

    3) sim.do文件

    [plain] view plain copy
     
      1. #Time: 2016-07-26  
      2. #By  : times_poem  
      3.   
      4. quit -sim  
      5.   
      6. cd F:/IC/prj/testbench/prj0  
      7.   
      8. if [file exists work] {  
      9.    vdel -all  
      10. }  
      11.   
      12. vlib work   
      13.   
      14. vlog ./*.v  
      15. vlog ./src/*.v  
      16.    
      17. vsim -t ps -novopt work.tb  
      18.   
      19. log -r /*  
      20. do wave.do   
      21.   
      22. run -all  
      23. 转载:https://blog.csdn.net/times_poem/article/details/52036592
  • 相关阅读:
    谈谈 OC 中的内联函数
    Spring 新手教程(二) 生命周期和作用域
    实时竞价(RTB) 介绍(基础篇)
    oracle数据库性能优化方案精髓整理收集回想
    HNU 13411 Reverse a Road II(最大流+BFS)经典
    CSS3主要知识点复习总结+HTML5新增标签
    修改默认MYSQL数据库data存放位置
    mysql状态查看 QPS/TPS/缓存命中率查看
    Mysql5.7.10新加用户
    很靠谱linux常用命令
  • 原文地址:https://www.cnblogs.com/chengqi521/p/8819411.html
Copyright © 2011-2022 走看看