Verilog十大基本功 您所在的位置:网站首页 vivado读取txt文件 Verilog十大基本功

Verilog十大基本功

2024-07-04 04:29| 来源: 网络整理| 查看: 265

内容       :testbench的设计 读取文件 写入文件

来自       :时间的诗

十大基本功之 testbench

1. 激励的产生 对于 testbench 而言,端口应当和被测试的 module 一一对应。端口分为 input,output 和 inout 类型产生激励信号的时候,input  对应的端口应当申明为 reg,output 对应的端口申明为 wire,inout  端口比较特殊,下面专门讲解。 1)直接赋值 一般用 initial 块给信号赋初值,initial 块执行一次,always 或者 forever 表示由事件激发反复执行。举例,一个 module [plain]  view plain  copy `timescale 1ns/1ps    module exam();    reg   rst_n;    reg   clk;    reg   data;        initial    begin      clk = 1'b0;      rst = 1'b1;      #10      rst = 1'b0;      #500      rst = 1'b1;    end        always    begin      #10 clk = ~clk;    end      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 task load_count;    input [3:0] load_value;    begin      @(negedge clk_50);      $display($time, " ", load_value);      load_l   = 1’b0;      count_in = load_value;      @(negedge clk_50);      load_l   = 1’b1;    end  endtask //of load_count    initial  begin    load_count(4’hA); // 调用 task  end   其他像 forever,for,function 等等语句用法类似,虽然不一定都能综合,但是用在 testbench 里面很方 便,大家可以自行查阅参考文档 2) 文件输入 有时候,需要大量的数据输入,直接赋值的话比较繁琐,可以先生成数据,再将数据读入到寄存器中,需要时取出即可。用 $readmemb 系统任务从文本文件中读取二进制向量(可以包含输入激励和输出期望值)。$readmemh 用于读取十六进制文件。例如: [plain]  view plain  copy reg   [7:0]  mem[256:1] // a 8-bit, 256-word 定义存储器 mem  initial $readmemh ( "E:/readhex/mem.dat", mem ) // 将.dat 文件读入寄存器 mem 中  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 $dumpfile 系统任务:为所要创建的 VCD 文件指定文件名。  举例( "//"符号后的内容为注释文字):  initial  $dumpfile ("myfile.dump"); //指定 VCD 文件的名字为 myfile.dump,仿真信息将记录到此文件  $dumpvar 系统任务:指定需要记录到 VCD 文件中的信号,可以指定某一模块层次上的所有信号,也可以单独指定某一  个信号。  典型语法为$dumpvar(level, module_name); 参数 level 为一个整数, 用于指定层次数, 参数 module 则指定要记录的模块。  整句的意思就是,对于指定的模块,包括其下各个层次(层次数由 level 指定)的信号,都需要记录到 VCD 文件中去。      举例:    initial      $dumpvar (0, top); //指定层次数为 0,则 top 模块及其下面各层次的所有信号将被记录      initial      $dumpvar (1, top); //记录模块实例 top 以下一层的信号    //层次数为 1,即记录 top 模块这一层次的信号    //对于 top 模块中调用的更深层次的模块实例,则不记录其信号变化      initial      $dumpvar (2, top); //记录模块实例 top 以下两层的信号      //即 top 模块及其下一层的信号将被记录    假设模块 top 中包含有子模块 module1,而我们希望记录 top.module1 模块以下两层的信号,则语法举例如下:    initial      $dumpvar (2, top.module1); //模块实例 top.module1 及其下一层的信号将被记录    假设模块 top 包含信号 signal1 和 signal2(注意是变量而不是子模块), 如我们希望只记录这两个信号,则语法举例如下:      initial      $dumpvar (0, top.signal1, top.signal2); //虽然指定了层次数,但层次数是不影响单独指定的信号的  

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

[plain]  view plain  copy initial      $dumpvar (3, top.signal1, top.module1); //指定层次数和单独指定的信号无关                                              //所以层次数 3 只作用于模块 top.module1, 而与信号    top.signal1 无关        上面这个例子和下面的语句是等效的:    [plain]  view plain  copy initial      begin      $dumpvar (0, top.signal1);      $dumpvar (3, top.module1);    end      $dumpvar 的特别用法(不带任何参数):    initial    $dumpvar; //无参数,表示设计中的所有信号都将被记录  

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

[plain]  view plain  copy initial  begin    $dumpfile ("mydesign.dump"); //指定 VCD 文件名为 mydesign.dump    $dumpvar (0, i_design.module1); //记录 i_design.module1 模块及其下面层次中所有模块的所有信号  end        对于生成 fsdb 文件而言,也是类似的 [plain]  view plain  copy initial  begin    $fsdbDumpfile("tb_xxx.fsdb");    $fsdbDumpvars(0,tb_xxx);  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 initial begin      $fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);      end      always@(a or b)      begin      $fwrite(file_id,"At time%t a=%b b=%b",$realtime,a,b);    end      

3 参考“A Verilog HDL Test Bench Primier.pdf” 1) DUT(Design Under Test)部分

[plain]  view plain  copy //-------------------------------------------------  // File: count16.v  // Purpose: Verilog Simulation Example  //-------------------------------------------------  `timescale 1 ns / 100 ps  module count16 (         clk,         rst_n,         load_l,         enable_l,         cnt_in,         oe_l,                  count,         count_tri         );            input         clk;    input         rst_n;        input         load_l;    input         enable_l;    input  [3:0]  cnt_in;    input         oe_l;                      output [3:0]  count;    output [3:0]  count_tri;        reg    [3:0]  count;        // tri-state buffers    assign count_tri = (!oe_l) ? count : 4'bZZZZ;            // synchronous 4 bit counter        always @ (posedge clk or negedge rst_n)    if (!rst_n) begin      count 


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有