精华内容
下载资源
问答
  • Lattice 公司的基于FPGA的PCI接口源代码及Testbench Verilog程序代码,很详细 Lattice 公司的基于FPGA的PCI接口源代码及Testbench Verilog程序代码,很详细
  • Plug ' kdurant/verilog-testbench ' 用法 运行:Testbench生成testbench模板 运行:VerilogInstance生成组件实例 运行:VerilogInterface生成接口(SystemVerilog)模板 运行:VerilogClass生成类(SystemVerilog)模板...
  • USB verilog 源码 testbench

    2021-09-16 16:33:52
    USB verilog 源码 testbench
  • verilog小工具,包括格式化,轻量级编译,testbench自动生成等,均经过测试可用。
  • verilog testbench

    2017-06-30 22:11:59
    verilog testbench 的寫法入門
  • 适合新手学习verilog HDL语言。并附有testbench文件,共新手学习使用。 适合新手学习verilog HDL语言。并附有testbench文件,共新手学习使用。
  • Verilog测试:TestBench结构

    万次阅读 多人点赞 2019-07-18 09:18:55
    1. 完整的TESTBENCH文件结构 2.时钟激励产生 3.复位信号设计 4.双向信号设计 5. 特殊信号设计 6.仿真控制语句以及系统任务描述 7.加法器的仿真测试文件编写   Verilog功能模块HDL设计完成后,并不代表设计...

    目录

    1. 完整的TESTBENCH文件结构

    2.时钟激励产生

    3.复位信号设计

    4.双向信号设计

    5. 特殊信号设计

    6.仿真控制语句以及系统任务描述

    7.加法器的仿真测试文件编写


      

    Verilog功能模块HDL设计完成后,并不代表设计工作的结束,还需要对设计进行进一步的仿真验证。掌握验证的方法,即如何调试自己的程序非常重要。在RTL逻辑设计中,要学会根据硬件逻辑来写测试程序即写Testbench。Verilog测试平台是一个例化的待测(MUT)模块,重要的是给它施加激励并观测其输出。逻辑块与其对应的测试平台共同组成仿真模型,应用这个模型就可以测试该模块能否符合自己的设计要求。

      编写TESTBENCH的目的就是为了测试使用HDL设计的电路,对其进行仿真验证、测试设计电路的功能、性能与设计的 预期是否相符。通常,编写测试文件的过程如下:

    •        产生模拟激励(波形)
    •       将产生的激励加入到被测试模块中并观察其响应;
    •       将输出响应与期望值比较。

    1. 完整的TESTBENCH文件结构

     

    module Test_bench()//一般简单的测试文件无输入输出
    
    信号或变量声明定义
    
    逻辑设计中输入信号在这里对应reg型变量
    
    逻辑设计中的输出信号在这里对应wire型
    
    使用initial或always语句块产生激励
    
    例化猜测是模块UT
    
    监控和比较输出响应
    
    endmodule

    2.时钟激励产生

     下面列举一些常用的生成时钟激励的方法:

    方法一: forever

    //*========================================================
                   50%占空比时钟
    ==========================================================*//
    parameter ClockPeriod = 10 ;
    
    initial
      beign
       clk_i = 0;
      forever 
        # (ClockPeriod/2) clk_i = ~clk_i ;
      
     end

    方法2: always块

    //=========================================================
                         50%时钟占空比
    ==============================================================*/
    Parameter ClockPeriod = 10 ;
    
    initial
       begin
    
        clk_i =0 ;
        always #(ClockPeriod/2) clk_i =~clk_i ;
      end

    方法3:产生固定数量的时钟脉冲

    parameter CloclPeriod = 10 ;
    
    initial
      begin
         clk_i = 0 ;
        repeat(6)
          #(ClockPeriod/2) clk_i =~ clk_i;
    
       end

    方法4:产生占空比非 50%的时钟

    parameter ClockPeriod  =  10 ;
    
    initial
       begin
    
          clk_i = 0 ;
          forever
             begin
               #((ClockPeriod/2)-2) clk_i = 0 ;
              #((ClockPeriod/2)+2) clk_i = 1;
             end
       end
    

    3.复位信号设计

    方法1:异步复位

    initial
       begin
         rst_n_i = 1 ;
         #100 ;
        rst_n_i = 0 ;
        #100 ;
        rst_n_i = 1;
      
       end

    方法2:同步复位

    initial
       begin
        rst_n_i = 1;
        @(negedge clk_i)  
            rst_n_i = 0;
        #100 ;    //这里给的是固定时间复位
       
        repeat(10) @(negedge clk_i) ;  //这里可以设置 固定数量的时钟周期
        @(negedge clk_i)
          rst_n_i = 1;
        end 
       

    方法3:对复位进行任务封装

    task reset ;
       input[31:0] reset_timer  ; //将复位的时间作为输入,达到复位时间可调的目的
       RST_ING = 0              ;//复位的方式可调,低电平有效或高电平有效
       begin
          rst_n = RST_ING ;   //复位中 
          #reset_time         //设置的复位时间
          rst_n_i = ~ RST_ING ;
       end
    endtask
    

    4.双向信号设计

    双向信号的描述方式并不唯一,常用的方法如下:

    描述方式1: inout在testbench中定义为wire型变量

    //为双向端口设置中间变量inout_reg作为intou的输出寄存,其中inout变量定义为wire型,使用输出使能控制
    //传输的方向
    //inout bir_port;
    
    wire birport      ;  //将双向接口变量定义为wire型
    reg  bir_port_reg ;  //定义一个reg型的中间变量,作为双向口的输出寄存
    reg  bi_port_oe   ;  //定义输出使能,用于控制传输的方向
    
    assign birport = (bir_port_oe)?bir_port_reg:1'bz;
    

    描述方式2:强制force

    当双向端口作为输出端口时,不需要对其进行初始化,而只需开通三态门;当双向接口作为输入时,只需要对其初始化,并关闭三态门,初始化赋值需要使用wire数据,通过force命令来对双向端口进行输入赋值

    //assign dinout = (!en)din: 16'hz ; 完成双向赋值
    
    initial
      begin
        for dinout = 20 ;
        #200 
        force dinout = dinout -1 ;
      
      end

    5. 特殊信号设计

    1.输入信号任务的封装

    方便产生激励数据。

    task i_data  ;
    input[7:0] dut_data;
    begin
    
       @(posedge data_en) ;send_data = 0;
       @(posedge data_en) ;send_data = dut_data[0];
       @(posedge data_en) ;send_data = dut_data[1];
       @(posedge data_en) ;send_data = dut_data[2];
       @(posedge data_en) ;send_data = dut_data[3];
       @(posedge data_en) ;send_data = dut_data[4];
       @(posedge data_en) ;send_data = dut_data[5];
       @(posedge data_en) ;send_data = dut_data[6];
       @(posedge data_en) ;send_data = dut_data[7];
       @(posedge data_en) ;send_data = 1;
    #100  ;
    end
    
    endtask
    
    //调用该task的方法: i_data(8'hXX) ;

    2.多输入信号任务封装

    task more_input;
    
    input [7:0] a;
    input [7:0] b;
    input [31:0] times ;
    output[8:0] c;
    
    begin
       repeat(times)                //等待times个时钟上升沿
        @(posedge clk_i)    
             c= a+b ;//时钟上升沿, a和b相加
    end
    
    endtask
    
    //调用方法: more_input(x,y,t,z);

    3.输入信号产生,一次SRAM写信号产生

    initial
        begin
            cs_n = 1 ;     //片选无效
            wr_n = 1 ;     //写使能无效
            rd_n =1  ;     //读使能无效
            addr = 8'hxx;  //地址无效
            data = 8'hxx;  //数据无效
            #100 ;
    
            cs_n = 0 ;
            wr_n = 0 ;
            addr = 8'hF1 ;
            data = 8'h2C ;
            #100  ;
            
            cs_n = 1;
            wr_n = 1 ;
            #10  ;
    
            addr = 8'hxx;
            data = 8'hxx;
        end

    Testbench中的 和 wait

    //wait都是使用电平触发

    intial
      begin
         start = 1'b1    ;
         wait(en = 1'b1) ;
         #10;
         start = 1'b0    ;
    
    end

     

    6.仿真控制语句以及系统任务描述

    仿真控制语句以及系统能够任务描述: 

    $stop        //停止运行仿真,modelsim中可以继续仿真
    $stop(n)     //带参数系统任务,根据参数0,1,或2不同,输出仿真信息
    $finish      //结束运行仿真,不可继续仿真
    $finish(n)   //带参数系统任务,根据参数的不同:0,1或2,输出仿真信息
                     // 0: 不输出任何信息
                    // 1: 输出当前仿真时刻和位置
                   // 2:输出房前仿真时刻、位置和仿真过程中用到的memory以及cpu时间的统计
    $random        //产生随机数
    $random%n     //产生范围-n到n之间的随机数
    {$random}%n    //产生范围0到n之间的随机数
    

    仿真终端显示描述

    $monitor    //仿真打印输出,打印出仿真过程中的变量,使其终端显示
                /*  $monitor($time,,,"clk = %d reset = %d out = %d",clk,reset,out); */
    
    $display   //终端打印字符串,显示仿真结果等
               /*  $display("Simulation start !");
                   $display("At time %t,input is %b %b %b,output is %b",$time,a,b,en,z);
            
               */
    $time      //返回64位整型时间
    $stime     //返回32位整型时间
    $realtiime //实行实型模拟时间

    文本输入方式:$readmemb /$readmemh

    //激励具有复杂的数据结构 
    
    //verilog提供了读入文本的系统函数 
    $readmemb/$readmemh("<数据文件名>",<存储器名>); 
    $readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>); 
    $readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>,<结束地址>); 
    
    $readmemb:
         /*读取二进制数据,读取文件内容只能包含:空白位置,注释行,二进制数 
    数据中不能包含位宽说明和格式说明,每个数字必须是二进制数字。*/ 
    
    $readmemh: /*读取十六进制数据,读取文件内容只能包含:空白位置,注释行,十六进制数数据中不能包含位宽说明和格式说明,每个数字必须是十六进制数字。*/ 
    
     /*当地址出现在数据文件中,格式为@hh...h,地址与数字之间不允许空白位置, 可出现多个地址*/
    module ;
    
    reg [7:0] memory[0:3];//声明8个8位存储单元
    integer i; 
    
    initial 
      begin
        $readmemh("mem.dat",memory);//读取系统文件到存储器中的给定地址 //显示此时存储器内容 
       for(i=0;i<4;i=i+1)  
           $display("Memory[%d]=%h",i,memory[i]); 
      end
    endmodule

    mem.dat的文件内容格式:

    //mem.dat文件内容
    @001
    AB CD
    @003
    A1 
     
    //仿真输出为
    // Memory[0] = xx;
    // Memory[1] = AB; 
    //Memory[2] = CD; 
    //Memory[3] = A1; 

     

     

    7.加法器的仿真测试文件编写

         上面只例举了常用的 testbench 写法,在工程应用中基本能够满足我们需求,至于其他更为复杂的 testbench写法,大家可参考其他书籍或资料。 

         这里提出以下几点建议供大家参考: 

    •               封装有用且常用的 testbench,testbench 中可以使用 task 或 function 对代码进行封装,下次利用时灵活调用即可;
    •              如果待测试文件中存在双向信号(inout)需要注意,需要一个 reg 变量来表示输入,一个 wire 变量表示输出; 
    •              单个 initial 语句不要太复杂,可分开写成多个 initial 语句,便于阅读和修改;
    •              Testbench 说到底是依赖 PC 软件平台,必须与自身设计的硬件功能相搭配。

    下面具体看一段程序:

    module add(a,b,c,d,e);// 模块接口 
    input [5:0] a; // 输入信号a 
    input [5:0] b; // 输入信号b 
    input [5:0] c; // 输入信号a 
    input [5:0] d; // 输入信号b 
    
    output[7:0] e; // 求和输出信号 
    
    wire [6:0]outa1,outa2; // 定义输出网线型 
    assign e = outa2+outa1; // 把两部分输出结果合并 
    
    /* 
    通常,我们模块的调用写法如下: 
    被调用的模块名字- 自定义的名字- 括号内信号 
    这里比如括号内的信号,.ina(ina1) 
    这种写法最常用,信号的顺序可以调换 
    另外还有一种写法没可以直接这样写 
    adder u1 (ina1,inb1,outa1); 
    这种写法必须确保信号的顺序一致,这种写法几乎没有人采用 */ 
    
    adder u1 (.ina(a),.inb(b),.outa(outa1)); // 调用adder 模块,自定义名字为u1 
    adder u2 (.ina(c),.inb(d),.outa(outa2)); // 调用adder 模块,自定义名字为u2
    endmodule 
    //adder 子模块 
    
    module adder(ina,inb,outa );// 模块接口 
    input [5:0] ina; // ina-输入信号 
    input [5:0] inb; // inb-输入信号 
    output [6:0] outa; // outa-输入信号 
    assign outa = ina + inb; // 求和 
    endmodule // 模块结束 

    仿真文件:

    `timescale 1ns / 1ps 
    module add_tb(); 
    
    reg [5:0] a;
    reg [5:0] b; 
    reg [5:0] c; 
    reg [5:0] d; 
    wire[7:0] e; 
    reg [5:0] i; //中间变量 
    
    // 调用被仿真模块模块 
    add uut (
    .a(a), 
    .b(b),
    .c(c),
    .d(d),
    .e(e)); 
    
    initial 
         begin    // initial 是仿真用的初始化关键词 
           a=0 ;  // 必须初始化输入信号 
           b=0 ;
           c=0 ;
           d=0  
              for(i=1;i<31;i=i+1)
                 begin 
                  #10 ; a = i; b = i; c = i; d = i; 
                 end
          end 
    initial 
        begin 
           $monitor($time,,,"%d + %d + %d + %d ={%d}",a,b,c,d,e); // 信号打印输出
           #500 
           $finish; 
        end 
    endmodule 
            
    

     

    仿真波形:

    终端显示:

     

     

     

     

     

    展开全文
  • 针对VerilogTestbench 例程,需要写Testbench 可以参考……
  •   楼主在初学verilog的时候就一直对testbench该怎么写感到困惑,之后的学习过程中也陆陆续续地看过一些testbench文件,其中有一些其实相当于就在testbench里重写了一下要验证地模块,个人感觉这有点”鸡生蛋“和”...

      楼主在初学verilog的时候就一直对testbench该怎么写感到困惑,之后的学习过程中也陆陆续续地看过一些testbench文件,其中有一些其实相当于就在testbench里重写了一下要验证地模块,个人感觉这有点”鸡生蛋“和”蛋生鸡“那味儿了。虽说在testbench里写不用考虑能否综合的问题,可以用一些更为方便的写法,但是终归还是用的Verilog体系内的语法,描述待测试模块预期的功能时很有可能会犯类似的错误,因此楼主觉得这种testbench的写法应付比较简单的模块可能还行,比较简单直接,但是应对复杂点的模块则出错的可能性偏大,不太可取。
      除了前述testbench的写法外,遍历穷举应该是常见的testbench写法之一,即借由高级语言穷举生成所有的输入和对应的输出,来比对模块的输出以达到验证的目的,因此本文就分享一个适用于这种穷举遍历思路的testbench模板,下面就借由一个原码输入原码输出的带饱和处理的减法器模块进行这一模板的写法说明。

    原码减法器

      选取被减数 A A A和减数 B B B的数据位宽为 4 4 4,输出结果 r e s res res的数据位宽也为4,设计框图如下
    在这里插入图片描述

    设计说明如下:

    1. 输入为原码(Sign-magnitude,SM)表示,而加减法一般习惯用二的补码(2’s compliment,2’s),因此先将 A A A B B B转换为补码形式,其中 B B B为被减数,可以考虑直接对(-B)进行补码转换,即上图中的红色减号,此时后续”减法“则转为加法进行;
    2. 二的补码加法比较简单,直接相加即可,本设计并不需要用到进位,因此可以只在模块内声明一下作为连线即可;
    3. 最后再进行溢出时的饱和处理,即溢出时符号位不变,幅值取最大值。具体到溢出的判断,本设计就不考虑最高位进位和次高位进位的溢出判断了,而是直接用输入和输出的符号位作为判断依据,比较直观。

    Verilog模块

      代码如下所示

    /**
     * @function:
     *   compute res = A - B and get sign-magnitude representation result
     * @input:
     *   A, B -> sign-magnitude representation
     * @output:
     *   res  -> sign-magnitude representation
    **/
    module SmSub #(
      parameter WIDTH = 4
    ) (
      input  [(WIDTH - 1) : 0] A,
      input  [(WIDTH - 1) : 0] B,
      output [(WIDTH - 1) : 0] res
    );
      
    
      wire [(WIDTH - 1) : 0] tmpA;         // magnitude part of A
      wire [(WIDTH - 1) : 0] complA;       // 2's complement representation of A
      wire [(WIDTH - 1) : 0] complB;       // 2's complement representation of B
      wire [(WIDTH - 1) : 0] complRes;     // 2's complement representation of res
      reg  [(WIDTH - 1) : 0] tmpRes;       // for negative result
      wire                   carry;
      reg  [(WIDTH - 1) : 0] satcomplRes;  // saturated complRes
      wire [(WIDTH - 1) : 0] negMax;       // maximum negative value using 2's complement representation
    
    
      // sign-magnitude -> 2's complement for A
      assign tmpA   = {1'b0, A[(WIDTH - 2):0]};
      assign complA = (1'b1 == A[(WIDTH - 1)]) ? ((~tmpA[(WIDTH - 1):0]) + 1) : A[(WIDTH - 1):0];
    
      // sign-magnitude -> 2's complement for (-B)
      assign complB = (1'b1 == B[(WIDTH - 1)]) ? {1'b0, B[(WIDTH - 2):0]} : ((~B[(WIDTH - 1):0]) + 1);
    
      // get result
      assign {carry, complRes} = complA + complB;
    
      // overflow process
      always @(*) begin
        case ({complA[(WIDTH - 1)], complB[(WIDTH - 1)], complRes[(WIDTH - 1)]})
          // postive spillover
          3'b001: begin
            satcomplRes = {1'b0, {(WIDTH - 1){1'b1}}};
          end
          // negtive spillover
          3'b110: begin
            satcomplRes = {1'b1, {(WIDTH - 1){1'b1}}};
          end
          // no spillover
          default: begin
            // 2's complement -> sign-magnitude for complRes
            tmpRes      = (~complRes[(WIDTH - 1):0]) + 1;
            satcomplRes = (1'b1 == complRes[(WIDTH - 1)]) ? {1'b1, tmpRes[(WIDTH - 2):0]} : complRes[(WIDTH - 1):0];
          end
        endcase
      end
    
      // handle special case N'b1000…000
      assign negMax = {1'b1, {(WIDTH - 1){1'b0}}};
      assign res    = (negMax[(WIDTH - 1):0] == satcomplRes[(WIDTH - 1):0]) ? {1'b1, {(WIDTH - 1){1'b1}}} : satcomplRes[(WIDTH - 1):0];
    
    endmodule
    

    matlab生成数据

      matlab代码如下所示,即穷举所有输入的情况,一共 2 4 × 2 4 = 256 2^4\times 2^4=256 24×24=256种,算出对应的输出,借由dec2bin()函数转为二进制形式写入到result.txt文件中,以供testbench读入。

    注:下列代码整体风格其实与C很像,之所以不用C而是用matlab只是图matlab里有现成的十进制转二进制函数罢了……

    dataWidth = 4;
    fileName = "../result.txt";
    fileID = fopen(fileName, "w");
    
    dataNum = power(2, dataWidth);
    magnitudeMax = power(2, dataWidth - 1) - 1;
    result = zeros(dataNum, dataNum);
    for i = 1 : dataNum
        for j = 1 : dataNum
            % convert to sign-magnitude representation
            if (i <= power(2, dataWidth - 1)) 
                tmpI = i - 1;
            else
                tmpI = power(2, dataWidth - 1) + 1 - i;
            end
            if (j <= power(2, dataWidth - 1)) 
                tmpJ = j - 1;
            else
                tmpJ = power(2, dataWidth - 1) + 1 - j;
            end
            tmpRes = tmpI - tmpJ;
    
            % saturated the results and convert to binary representation
            if tmpRes < 0
                if abs(tmpRes) >= magnitudeMax      % saturated
                    fprintf(fileID, "%s\n", dec2bin(magnitudeMax + power(2, dataWidth - 1), dataWidth));        % sign-magnitude representation
                else
                    fprintf(fileID, "%s\n", dec2bin(abs(tmpRes) + power(2, dataWidth - 1), dataWidth));
                end
            else
                if tmpRes >= magnitudeMax           % saturated
                    fprintf(fileID, "%s\n", dec2bin(magnitudeMax, dataWidth));
                else
                    fprintf(fileID, "%s\n", dec2bin(tmpRes, dataWidth));
                end
            end
        end
    end
    
    fclose(fileID);
    

    testbench编写

      本文的重头戏来了,先放代码

    `timescale 1 ns/ 10 ps
    `define period	10
    
    module SmSub_tb();
    /********** 1. ports and signal declaration **********/
      reg  [3:0] A;
      reg  [3:0] B;
      wire [3:0] res;
    
      reg [3:0] refResMem[0:(16 * 16 - 1)];
    
      integer i;
      integer j;
      integer tmpIdx;
      integer errCnt;
      
    /********** 2. module instantiation and assignment **********/
      SmSub #( 
        .WIDTH(4) 
      ) uut0 (
         .A(A),
         .B(B),
         .res(res)
        );
    	
    /********** 3. Initialization **********/
      initial begin
        errCnt = 0;
        $readmemb("./sim/result.txt", refResMem);
    
        for (i = 0; i < 16; i = i + 1) begin
          for (j = 0; j < 16; j = j + 1) begin
            A = i;  B = j;
            #(`period / 2) checkOutputs;
            #(`period / 2);
          end
        end
    
        if (errCnt) begin
          $display("***************** Total Errors: %d *****************\n", errCnt);
        end
        else begin
          $display("***************** No Errors! *****************\n");
        end
        #(`period*10) $stop;
    	end           
    
      /********** 4. check part **********/
      task checkOutputs;
        begin
          tmpIdx = (i * 16) + j;
          if (res != refResMem[tmpIdx]) begin
            error;
          end
        end
      endtask
    
      task error;
        begin
          errCnt = errCnt + 1;
          $display("ERROR AT %d: expected -> %h, get -> %h", tmpIdx, refResMem[tmpIdx], res);
        end
      endtask
    
    endmodule
    

    说明如下:

    • 第一部分就是testbench都有的端口和接下来要用的信号声明;
    • 第二部分是测试模块的实例化,较为复杂点的模块可能还需要在testbench里额外添加一些连线;
    • 第三部分为初始化,先将错误计数变量初始化为0,再用系统函数$readmemb/$readmemh将前一步用matlab生成的参考输出读入,而考虑到本模块中的输入比较有规律,所以输入用整型变量ij产生,若数据量较大或不规律,可以参照前一步,用高级语言生成对应的输入文件读入。再之后,每产生一个输入,就调用对应的checkOutputs任务进行输出对比,如果存在错误则调用error任务进行错误处理即打印出错信息到终端,并对错误进行计数。最后则是检查错误个数,打印对应的输出信息,并调用$stop中止仿真。
    • 第四部分即输出对比函数和错误处理函数,本设计并不复杂,所以只是简单的比对仅有的一个输出,错误处理也只是单纯地打印,并不算复杂;

    总结

      这一模板是楼主学Verilog以来感觉比较好用的一个,当然了,这种遍历穷举的验证方式在实际工程中还是有不小局限性的,输入比特数较大时往往就只能随机生成众多输入情况的一部分进行验证了,最终还是要借助于系统的验证方法学。尽管如此,个人感觉这一模板还是对初学Verilog的人来说还是比较友好的!

    展开全文
  • 使用Verilog语言编写的二分频testbench的源代码,可以直接加入仿真软件中进行仿真测试。
  • python自动生成Verilogtestbench脚本。python自动生成Verilogtestbench脚本。python自动生成Verilogtestbench脚本。
  • 修改了原code中不合理的地方:1、不符合I2C标准的端口处理方式 2、增加io_pad接口模块 3、testbench中增加I2C协议上拉电路 4、修改了原设计中sda信号输出方式不完善的地方 5、修改了远设计中SDA,SCL初始状态
  • 这是个串口通信的Verilog代码,代码简单明了。在顶层收到PC一个字节然后再发给PC。适合初学者使用
  • 因此,还是需要testbench测试下仿真的波形,通过波形来看,是不是真的完全表达了设计的初衷。 本文目录: 1.编写测试文件的思路 2.怎么写 正文: 1.编写测试文件的思路 我们编写 2.怎么写 THE END~ ...

    写作时间:2021-03-12
    使用的FPGA开发板:xilinx KC705
    开发环境: vivado2019.1

    Readme:
    昨天在流水灯的代码中添加了“按键消抖”功能。上板也进行了测试,测试结果OK。
    但是对于有些上板测试,有时候还不能完全反应出逻辑设计时的意思。
    因此,还是需要testbench测试下仿真的波形,通过波形来看,是不是真的完全表达了设计的初衷。
    本文以按键消抖为例

    本文目录:
    1.编写测试文件的思路
    2.怎么写以及文件结构
    3.仿真结果

    正文:
    1.编写测试文件的思路
    通常,编写测试文件的过程如下:
    1)产生模拟激励(波形);
    2)将产生的激励加入到被测试模块中并观察其响应;
    3) 将输出响应与期望值相比较

    2.怎么写
    1)建立仿真文件
    在这里插入图片描述

    文件命名:文件命名保持一致,后边加一个尾缀“tb”,表示testbench.
    在这里插入图片描述
    此时,出来一个空文件:
    在这里插入图片描述

    1. 编写内容
      了解下testbench 的基本架构
    module Test_bench();//通常无输入无输出
    //信号或变量声明定义
    //逻辑设计中输入对应 reg 型
    //逻辑设计中输出对应 wire 型
        reg  key_in;//逻辑设计中输入对应 reg 型
        reg  rst_n;
        reg  clk;
        reg [7:0] cnt;
        wire key_out;//逻辑设计中输出对应 wire 型
    //1.使用 initial 或 always 语句产生激励
    // 一般包括:时钟,复位,以及(模拟)产生测试的输入信号
    //2.例化待测试模块
     key_noshake
    #(
        .cnt_max(8'd100)
    )
    key_noshake_inst
    (
        .key_in(key_in),
        .rst_n(rst_n),
        .clk(clk),
        .key_out(key_out)
    );  
    
    
    //3.监控和比较输出响应
    
    //观察仿真后的输出波形即可
    endmodule
    

    3)完整代码如下:

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2021/03/12 10:58:46
    // Design Name: 
    // Module Name: key_noshake_tb
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module key_noshake_tb();//通常无输入无输出
    
    //信号或变量声明定义
        reg  key_in;//逻辑设计中输入对应 reg 型
        reg  rst_n;
        reg  clk;
        reg [7:0] cnt;
        wire key_out;//逻辑设计中输出对应 wire 型
    //1.使用 initial 或 always 语句产生激励    
    initial 
        begin
            clk=1'b1;
            rst_n=1'b0;
            #50
            rst_n=1'b1;
        end
    
    always #10  clk=~clk;//生成(模拟)时钟信号
    
    always@(posedge clk or negedge rst_n)
        if( rst_n==1'b0)
            cnt<=8'b0;
        else if(cnt==8'd249)
            cnt<=8'b0;
        else
             cnt<=cnt+8'b1;
                    
    always@(posedge clk or negedge rst_n)//模拟按键key_in的前抖动,后抖动,以及稳定段
        if( rst_n==1'b0)
            key_in<=1'b1;
        else  if (cnt>=8'd02 &&  cnt<=8'd19)
            key_in<={$random} %2;
        else  if (cnt>=8'd129 &&  cnt<=8'd149)
            key_in<={$random} %2;
        else
            key_in<=1'b0;
    
    // 2.例化待测试模块  
    
     key_noshake
    #(
        .cnt_max(8'd100)
    )
    key_noshake_inst
    (
        .key_in(key_in),
        .rst_n(rst_n),
        .clk(clk),
        .key_out(key_out)
    );     
    //3.监控和比较输出响应
        
    endmodule
    
    

    注:
    在这里插入图片描述

    3.仿真结果

    在这里插入图片描述

    在这里插入图片描述
    放大(局部特写)
    在这里插入图片描述

    OK~ 大功告成~


    THE END~

    展开全文
  • verilog 写的单个与门以及testbench
  • 简单verilog testbench

    2014-01-25 23:32:16
    简单verilog testbench `timescale 1ns/1ns module tb_jet_ctrl_top(); parameter U_DLY = 1; integer i; reg rst_n; reg clk; reg [ 7:0] cpu_dat; reg [11:8] cpu_addr; reg cpu_cs; reg cpu_wr_n; reg prt_...
  • verilog语言实现的流水灯代码,已在FPGA开发板上实践过
  • verilogtestbench仿真时钟的生成

    千次阅读 2020-09-23 10:57:56
    一、普通时钟信号: 1、基于initial语句的方法: parameter clk_period = 10; reg clk; initial begin clk = 0; forever #(clk_period/2) clk = ~clk; end 2、基于always语句的方法: ...always #(clk_per

    一、普通时钟信号:

    1、基于initial语句的方法:

    parameter clk_period = 10;  
    reg clk;  
    initial begin  
        clk = 0;  
        forever  
            #(clk_period/2) clk = ~clk;  
    end  
    

    2、基于always语句的方法:

    parameter clk_period = 10;  
    reg clk;  
    initial  
        clk = 0;  
    always #(clk_period/2) clk = ~clk;  
    

    二、自定义占空比的时钟信号:

    parameter High_time = 5,Low_time = 20;  
    // 占空比为High_time/(High_time+Low_time)  
    reg clk;  
    always begin  
        clk = 1;  
        #High_time;  
        clk = 0;  
        #Low_time;  
    end  
    

    三、相位偏移的时钟信号:

    parameter High_time = 5,Low_time = 20,pshift_time = 2;  
    // 相位偏移为360*pshift_time/(High_time+Low_time)  
    reg clk_a;  
    wire clk_b;  
    always begin  
        clk_a = 1;  
        #High_time;  
        clk_a = 0;  
        #Low_time;  
    end  
    assign #pshift_time clk_b = clk_a;  
    

    四、固定数目的时钟信号:

    parameter clk_cnt = 5, clk_period = 2;  
    reg clk;  
    initial begin  
        clk = 0;  
        repeat(clk_cnt)  
            #(clk_period/2) clk = ~clk;  
    end  
    

    参考链接:https://www.cnblogs.com/Edam-IC/p/9054278.html

    展开全文
  • 以后不需要再手写Testbech了,直接用这个就可以,输入你的verilog源码,直接就生成了可以测试的Testbench了。
  • Verilog testbench总结(一)

    千次阅读 2018-07-11 10:34:51
    1. 激励的产生对于testbench而言,端口应当和被测试的module一一对应。端口分为input,output和inout类型产生激励信号的时候,input对应的端口应当申明为reg, output对应的端口申明为wire,inout端口比较特殊,下面...
  • verilog实现的交通灯,用状态机实现,七段数码管显示,包含详细讲解,注释,testbench,波形图以及实验报告!内部只写了单方向的交通灯,可以根据自己需要进行修改。
  • verilog testbench的写法

    2014-12-18 21:44:19
    介绍硬件设计过程中编写测试平台,全面仿真测试设计的RTL电路
  • 一、Testbench基本结构 通常,Testbench没有输入与输出端口,应包括信号或变量定义、产生激励波形语句、例化设计模块以及监控和比较响应输出语句。 module test_bench; //信号或变量定义声明 //使用initial或...
  • Verilog testbench总结

    千次阅读 2019-01-20 16:23:06
    对于testbench而言,端口应当和被测试的module一一对应。端口分为input,output和inout类型产生激励信号的时候,input对应的端口应当申明为reg, output对应的端口申明为wire,inout端口比较特殊,下面专门讲解。 1)...
  • 借鉴UVM的测试方法,在tb中将初始数据和结果数据写入txt文件,处理完成后,读出来,进行逐一对比,并打印结果。无需肉眼一一对比,将结果用计算机自动对比,减少人工工作量,提高了准确率。
  • 本文阐述了 Verilog 中 task 的语法,并使用 task 完成了样例模块 testbench 的编写。 ...
  • 该代码实现的锁相环电路,其精度根据testbench中设置的reference_signal的频率,可以达到皮秒级。代码层次为2级,主module调用了鉴相器模块和振荡器模块。目前testbench中设置的锁定频率为333MHz,锁定后相位差3ps。...
  • 简单的uart verilog源码,没有奇偶校验位,1bit停止位,8bit数据位,MSB先。实际测试通过。可在此基础上修改自己需要的uart源码

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,717
精华内容 2,286
关键字:

testbenchverilog