CH02 FPGA设计Verilog基础笔记(三)

 

 

1、一个完整的设计,除了好的功能描述代码,对于程序的仿真验证是必不可少的。学会如何去验证自己所写的程序,即如何调试自己的程序是一件非常重要的事。而RTL逻辑设计中,学会根据硬件逻辑来写测试程序,即Testbench显得尤其重要。

编写Testbench的目的是为了对使用硬件描述语言设计的电路进行仿真验证,测试设计电路的功能、性能与设计的预期是否符合。通常过程如下:

*产生模拟激励(波形);

*将产生的激励加入到被测试模块中并观察其响应;

*将输出相应与预期值相比较。

2、Testbench文件结构为:

module Test_bench();  //通常无输入无输出

信号或变量声明定义

逻辑设计中输入对应reg型

逻辑设计中输出对应wire型

使用initial或always语句产生激励

例化待测试模块

监控和比较输出响应

endmodule

1、  时钟激励设计

/*************时钟激励产生方法一:50%占空比时钟************/

parameter ClockPeriod=10;

initial

           begin

                    clk_i=0;

                    forever

                             #(ClockPeriod/2) clk_i=~clk_i;

           end

/*****************时钟激励产生方法二:50%占空比时钟*************/

initial

           begin

                    clk_i=0;

                    always #(ClockPeriod/2) clk_i=~clk_i;

           end

/*****************时钟激励产生方法三:产生固定数量的时钟脉冲*************/

initial

           begin

                    clk_i=0;

                    repeat(6)

                             #(ClockPeriod/2) clk_i=~clk_i;

           end

/*****************时钟激励产生方法四:产生非占空比为50%的时钟*************/

initial

           begin

                    clk_i=0;

                    forever

                             begin

                                       #((ClockPeriod/2)-2) clk_i=0;

                                       #((ClockPeriod/2)+2) clk_i=1;

                             end

           end

2、  复位信号设计

/*****************复位信号产生方法一:异步复位*************/

initial

           begin

                    rst_n_i=1;

#100;

         rst_n_i=0;

         #100;

         rst_n_i=1;

end

/*****************复位信号产生方法二:同步复位*************/

         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

/*****************复位信号产生方法三:复位任务封装*************/

task reset;

           input [31:0] reset_time;       //复位时间可调,输入复位时间

         RST_ING=0;                          //复位方式可调,低电平或高电平

           begin

                    rst_n=RST_ING;           //复位中

                    #reset_time;                //复位时间

                    rst_n_i=~RST_ING;     //撤销复位,复位结束

           end

endtask

3、  双向信号设计

/*****************双向信号描述一:inout在testbench中定义为wire型变量*************/

//为双向端口设置中间变量inout_reg作为inout的输出寄存,

//其中inout变量定义为wire型,使用输出使能控制传输方向

//inout bir_port;

wire bir_port;

reg bir_port_reg;

reg bi_port_oe;

assign bi_port=bi_port_oe?bir_port_reg:1’bz;

/*****************双向信号描述二:强制force**************/

//当双向端口作为输出口时,不需要对其初始化,只需要开通三态门

//当双向端口作为输入口时,只需要对其初始化并关闭三态门,初始化赋值

//需要使用wire型数据,通过force命令来对双向端口进行输入赋值

//assign dinout=(!en) din: 16’hz;  完成双向赋值

initial

           begin

                    force dinout=20;

                    #200;

                    force dinout=dinout-1;

           end

4、  特殊信号设计

/*****************特殊激励信号产生描述一:输入信号任务封装**************/

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;

end

endtask

//调用方法: i_data(8’hXX);

/*****************特殊激励信号产生描述二:多输入信号任务封装**************/

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

entask

 

/*****************特殊激励信号产生描述三:输入信号产生,一次SRAM写信号产生**************/

initial

           begin

                    cs_n=1;               //片选无效

wr_n=1;              //写使能无效    

rd_n=1;              //读使能无效

addr=8’hxx;       //地址无效

data=8’hzz;       //数据无效

#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’hzz;

         end

/****************Testbench中@与wait**************/

//@使用沿触发

//wait语句使用电平触发

initial

         begin

                   start=1’b1;

                   wait(en=1’b1);

                   #10;

                   start=1’b0;

         end

5、  仿真控制语句及系统任务描述

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位整型时间

         $realtime   //实行实型模拟时间

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

         //激励复杂的数据结构

         //verilog提供了读入文本的系统函数

         $readmemb/$readmemh(“<数据文件名>”<存储器名>);

         $readmemb/$readmemh(“<数据文件名>”<存储器名>,<起始地址>);

         $readmemb/$readmemh(“<数据文件名>”<存储器名>,<起始地址>,<结束地址>);

         readmemb:/*

                                     读取二进制数据,读取文件内容只能包含:空白位置,注释行,二进制数。

                                     数据中不能包含位宽说明和格式说明,每个数字必须是二进制数字。

                                     当地址出现在数据文件中,格式为@hh...h。地址与数字间不允许空白位置,

                                     可出现多个地址。

*/

         module

                   reg [7:0] memory[0:3];        //定义了4个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文件内容

         @001

AB  CD

         @003

A1    

*/

//仿真输出为:

Memory[0]=xx;

Memory[1]=AB;

Memory[2]=CD;

Memory[3]=A1;

9、  加法器的仿真测试文件编写

/*******************Design Source文件*****************************/

module add(a,b,c,d,e);//模块端口

input [5:0] a;  //输入信号a

input [5:0] b;

input [5:0] c;

input [5:0] d;

output [7:0] e; //求和信号

wire [6:0] outa1,outa2; //定义输出线网型

assign e=outa1+outa2;  

/*

    通常,我们模块调用写法如下:

    被调用的模块名字-自定义名字-括号内信号

    这里比如括号内的信号, .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));

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   //模块结束

 

/*******************Simulation Sources文件*****************************/

`timescale 1ns/1ps

module add_tv();

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   

/*******************仿真时序图如下*****************************/

posted @ 2019-12-03 16:51  烟火流沙  阅读(539)  评论(0编辑  收藏  举报