精华内容
下载资源
问答
  • 自从Xilinx官方从ISE升级为Xilinx后,无法再用软件自动生成testbench文件了,给FPGA工程师带来不少麻烦。 不过Xilinx官方提供了tcl商店以丰富Xilinx软件功能,其中就有生成testbench的tcl脚本提供下载。但是使用...

           自从Xilinx官方从ISE升级为Xilinx后,无法再用软件自动生成testbench文件了,给FPGA工程师带来不少麻烦。

           不过Xilinx官方提供了tcl商店以丰富Xilinx软件功能,其中就有生成testbench的tcl脚本提供下载。但是使用起来还是比较麻烦,必须让那个模块成为顶层并进入Elaborate, Synthesize或者implement界面,然后用tcl指令生成。

           网上也有生成testbench的Perl或者Python的脚本代码,但是使用起来还是有点麻烦,因为需要在命令行敲指令才能完成testbench的生成。

           不过后来发现Vim,Sublime,Notepad++这几种比较主流的编辑器都有生成testbench的功能,直接按快捷键就可以生成了,只是自动生成的testbench比较简单,又无法自己修改插件而已。

           后来本人发现VSCode是个颜值很高的编辑器,于是转投VSCode,而且VSCode具有snippets的功能,可以提高效率,Vivado也可以调用VSCode,在Tools->Setting->Text Editor选择Custom Editor,指令为"...(自己电脑的地址)//Microsoft VS Code//Code.exe" -g [file name]:[line number]。

           很遗憾的是VSCode只有基础语法的插件,没有testbench自动生成插件,于是本人结合网上他人python生成testbench的脚本写了一个VSCode生成testbench的插件。由于VSCode目前只支持typescript和Javascript语言开发,但本人并不熟悉,而且官网提供的文档也并不完善,所以使用typescript建立一个命令行窗口调用python脚本生成testbench和模块例化代码。

           在编写插件代码时,当前的窗口可以用下面语句获取:

    let editor = vscode.window.activeTextEditor;
           选取的内容为editor.selection; let text = editor.document.getText(selection);
           其中文本长度text.length
           当前操作的文件名为editor.document.fileName

           工程目录的out目录绝对值为__dirname

           创建命令行窗口并输入命令行指令
    let terminal1 = vscode.window.createTerminal({name:'new'});
    terminal1.show(true);
    terminal1.sendText(`...`);

           该插件的源代码可以在github上下载:https://github.com/truecrab/VSCode_Extension_Verilog。

           现在该插件已经在VSCode的应用市场上架了,名字是Verilog_Testbench,欢迎大家下载使用,有问题可以在博客留言。

           关于Vivado的其他技巧,可参考:Vivado工程经验与时序收敛技巧

    展开全文
  • vivado testbench 注意事项

    千次阅读 2018-09-27 11:32:52
    对于一个设计而言,时间刻度应该统一,如果设计文件和testbench里面的时间刻度不一致,仿真 器默认以testbench为准。一个较好的办法是写一个global.v文件,然后用include的办法,可以防止这个问题。 对于反复执行的...


        wire对应于连续赋值,如assign;wire型变量综合出来一般情况下是一根导线。
        reg对应于过程赋值,如always,initial;
        reg变量在always中有两种情况:
      (1)always @(a or b or c)形式的,即不带时钟边沿的,综合出来还是组合逻辑;
      (2)always @(posedge clk)形式的,即带有边沿的,综合出来一般是时序逻辑,会包含触发器(Flip-Flop)
        top设计中,输入信号一般wire型。而输出信号wire和reg型都可以。reg输出比较稳定。
       testbench元件实例化时必须用wire型,assign语句用wire型,input、output、inout预设值都是wire型

     


    1. 激励的产生

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

    1)直接赋值。

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

    举例,一个module

    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 

    大家应该注意到有个#符号,该符号的意思是指延迟相应的时间单位。该时间单位由timscale决定.一般在testbench的开头定义时间单位和仿真 精度,比如`timescale 1ns/1ps,前面一个是代表时间单位,后面一个代表仿真时间精度。以上面的例子而言,一个时钟周期是20个单位,也就是20ns。而仿真时间精度的概 念就是,你能看到1.001ns时对应的信号值,而假如timescale 1ns/1ns,1.001ns时候的值就无法看到。对于一个设计而言,时间刻度应该统一,如果设计文件和testbench里面的时间刻度不一致,仿真 器默认以testbench为准。一个较好的办法是写一个global.v文件,然后用include的办法,可以防止这个问题。

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

    task load_count;
           input [3:0] load_value;
           begin
                @(negedge clk_50);
                         $display($time, " << Loading the counter with %h >>", 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 用于读取十六进制文件。例如:

    reg [7:0]   mem[1:256]   //   a 8-bit, 256-word 定义存储器mem

    initial   $readmemh ( "E:/readhex/mem.dat", mem ) // 将.dat文件读入寄存器mem中

    initial   $readmemh ( "E:/readhex/mem.dat", mem, 128, 1 ) // 参数为寄存器加载数据的地址始终

    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文件简单地视为波形记录文件.)下面分别描述它们的用法并举例说明之。

    $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以下三层的所有信号,则语法举例如下:
    initial
    $dumpvar (3, top.signal1, top.module1); //指定层次数和单独指定的信号无关
    //所以层次数3只作用于模块top.module1, 而与信号

    top.signal1无关

    上面这个例子和下面的语句是等效的:
    initial
    begin
    $dumpvar (0, top.signal1);
    $dumpvar (3, top.module1);
    end

    $dumpvar的特别用法(不带任何参数):
    initial
    $dumpvar; //无参数,表示设计中的所有信号都将被记录


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


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

    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需要触发条件才记录


    例子:
    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 testbench的技巧

    1).如果激励中有一些重复的项目,可以考虑将这些语句编写成一个task,这样会给书写和仿真带来很大方便。例如,一个存储器的testbench的激励可以包含write,read等task。

    2).如果DUT中包含双向信号(inout),在编写testbench时要注意。需要一个reg变量来表示其输入,还需要一个wire变量表示其输出。

    3).如果initial块语句过于复杂,可以考虑将其分为互补相干的几个部分,用数个initial块来描述。在仿真时,这些initial块会并发运行。这样方便阅读和修改。

    4).每个testbench都最好包含$stop语句,用以指明仿真何时结束。
    5).加载测试向量时,避免在时钟的上下沿变化,比如数据最好在时钟上升沿之前变化,这也符合建立时间的要求。


    4.一个简单的例子

    module counter (clk, reset, enable, count);

    input clk, reset, enable;
    output [3:0] count;
    reg [3:0] count;                                  
      
    always @ (posedge clk)
    if (reset == 1'b1) begin
    count <= 0;
    end else if ( enable == 1'b1) begin
    count <= count + 1;
    end
      
    endmodule 



    testbench

    module counter_tb; 
    reg clk, reset, enable; 
    wire [3:0] count; 
       
    counter U0 ( 
    .clk (clk), 
    .reset   (reset), 
    .enable (enable), 
    .count   (count) 
    ); 
       
    initial begin
       clk = 0; 
       reset = 0; 
       enable = 0; 
    end 
       
    always  
       #5   clk =   ! clk; 
       
    initial   begin
       $dumpfile ("counter.vcd"); 
       $dumpvars; 
    end 
       
    initial   begin
       $display("\t\ttime,\tclk,\treset,\tenable,\tcount"); 
       $monitor("‰d,\t‰b,\t‰b,\t‰b,\t‰d",$time, clk,reset,enable,count); 
    end 
       
    initial 
        #100   $finish; 
       
    //Rest of testbench code after this line 
       
       endmodule

    5   双向端口
    这个我没用过,完全是从网上google的,如果有问题,大家再讨论吧


    芯片外部引脚很多都使用inout类型的,为的是节省管腿。一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。就是一个端口同时做输入和 输出。 inout在具体实现上一般用三态门来实现。三态门的第三个状态就是高阻'Z'。当inout端口不输出时,将三态门置高阻。这样信号就不会因为两端同时 输出而出错了,更详细的内容可以搜索一下三态门tri-state的资料.
    1 使用inout类型数据,可以用如下写法:
    inout data_inout;
    input data_in;
    reg data_reg;//data_inout的映象寄存器
    reg link_data;
    assign data_inout=link_data?data_reg:1’bz;//link_data控制三态门
    //对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data的高低电平,从而设置data_inout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data可以通过相关电路来控制.
    2 编写测试模块时,对于inout类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.
    当上面例子中的data_inout用作输入时,需要赋值给data_inout,其余情况可以断开.此时可以用assign语句实现:assign data_inout=link?data_in_t:1’bz;其中的link ,data_in_t是reg类型变量,在测试模块中赋值.
    另外,可以设置一个输出端口观察data_inout用作输出的情况:
    Wire data_out;
    Assign data_out_t=(!link)?data_inout:1’bz;

    else,in RTL
    inout use in top module(PAD)
    dont use inout(tri) in sub module
    也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port实现,到顶层的时候再用三态实现。理由是:在非顶层模块用双向口的话,该 双向口必然有它的上层跟它相连。既然是双向口,则上层至少有一个输入口和一个输出口联到该双向口上,则发生两个内部输出单元连接到一起的情况出现,这样在 综合时往往会出错。

    对双向口,我们可以将其理解为2个分量:一个输入分量,一个输出分量。另外还需要一个控制信号控制输出分量何时输出。此时,我们就可以很容易地对双向端口建模。

    例子:
    CODE:
    module dual_port (
    ....
    inout_pin,
    ....
    );

    inout inout_pin;

    wire inout_pin;

    wire input_of_inout;
    wire output_of_inout;
    wire out_en;

    assign input_of_inout = inout_pin;

    assign inout_pin = out_en ? output_of_inout : 高阻;

    endmodule

    可见,此时input_of_inout和output_of_inout就可以当作普通信号使用了。

    在仿真的时候,需要注意双向口的处理。如果是直接与另外一个模块的双向口连接,那么只要保证一个模块在输出的时候,另外一个模块没有输出(处于高阻态)就可以了。
    如果是在ModelSim中作为单独的模块仿真,那么在模块输出的时候,不能使用force命令将其设为高阻态,而是使用release命令将总线释放掉

    很多初学者在写testbench进行仿真和验证的时候,被inout双向口难住了。仿真器老是提示错误不能进行。下面是我个人对inout端口写 testbench仿真的一些总结,并举例进行说明。在这里先要说明一下inout口在testbench中要定义为wire型变量。

    先假设有一源代码为:

    module xx(data_inout , ........);

    inout data_inout;

    ........................

    assign data_inout=(! link)?datareg:1'bz;

    endmodule

    方法一:使用相反控制信号inout口,等于两个模块之间用inout双向口互连。这种方法要注意assign 语句只能放在initial和always块内。

    module test();

    wire data_inout;

    reg data_reg;

    reg link;

    initial begin

    ..........

    end

    assign data_inout=link?data_reg:1'bz;

    endmodule

    方法二:使用force和release语句,但这种方法不能准确反映双向端口的信号变化,但这种方法可以反在块内。

    module test();

    wire data_inout;

    reg data_reg;

    reg link;

    #xx;        //延时

    force data_inout=1'bx;           //强制作为输入端口

    ...............

    #xx;

    release data_inout;       //释放输入端口

    endmodule

    很多读者反映仿真双向端口的时候遇到困难,这里介绍一下双向端口的仿真方法。一个典型的双向端口如图1所示。

    其中inner_port与芯片内部其他逻辑相连,outer_port为芯片外部管脚,out_en用于控制双向端口的方向,out_en为1时,端口为输出方向,out_en为0时,端口为输入方向。

    用Verilog语言描述如下:
    module bidirection_io(inner_port,out_en,outer_port);
    input out_en;
    inout[7:0] inner_port;
    inout[7:0] outer_port;
    assign outer_port=(out_en==1)?inner_port:8'hzz;
    assign inner_port=(out_en==0)?outer_port:8'hzz;
    endmodule

    用VHDL语言描述双向端口如下:
    library ieee;
    use IEEE.STD_LOGIC_1164.ALL;
    entity bidirection_io is
    port ( inner_port : inout std_logic_vector(7 downto 0);
    out_en : in std_logic;
    outer_port : inout std_logic_vector(7 downto 0) );
    end bidirection_io;
    architecture behavioral of bidirection_io is
    begin
    outer_port<=inner_port when out_en='1' else (OTHERS=>'Z');
    inner_port<=outer_port when out_en='0' else (OTHERS=>'Z');
    end behavioral;

    仿真时需要验证双向端口能正确输出数据,以及正确读入数据,因此需要驱动out_en端口,当out_en端口为1时,testbench驱动 inner_port端口,然后检查outer_port端口输出的数据是否正确;当out_en端口为0时,testbench驱动 outer_port端口,然后检查inner_port端口读入的数据是否正确。由于inner_port和outer_port端口都是双向端口(在 VHDL和Verilog语言中都用inout定义),因此驱动方法与单向端口有所不同。
    验证该双向端口的testbench结构如图2所示。

    这是一个self-checking testbench,可以自动检查仿真结果是否正确,并在Modelsim控制台上打印出提示信息。图中Monitor完成信号采样、结果自动比较的功能。
    testbench的工作过程为
    1)out_en=1时,双向端口处于输出状态,testbench给inner_port_tb_reg信号赋值,然后读取outer_port_tb_wire的值,如果两者一致,双向端口工作正常。
    2)out_en=0时,双向端口处于输如状态,testbench给outer_port_tb_reg信号赋值,然后读取inner_port_tb_wire的值,如果两者一致,双向端口工作正常。

    用Verilog代码编写的testbench如下,其中使用了自动结果比较,随机化激励产生等技术。

    `timescale 1ns/10ps
    module tb();
    reg[7:0] inner_port_tb_reg;
    wire[7:0] inner_port_tb_wire;
    reg[7:0] outer_port_tb_reg;
    wire[7:0] outer_port_tb_wire;
    reg out_en_tb;
    integer i;

    initial
    begin
    out_en_tb=0;
    inner_port_tb_reg=0;
    outer_port_tb_reg=0;
    i=0;
    repeat(20)
    begin
    #50
    i=$random;
    out_en_tb=i[0]; //randomize out_en_tb
    inner_port_tb_reg=$random; //randomize data
    outer_port_tb_reg=$random;
    end
    end

    //**** drive the ports connecting to bidirction_io
    assign inner_port_tb_wire=(out_en_tb==1)?inner_port_tb_reg:8'hzz;
    assign outer_port_tb_wire=(out_en_tb==0)?outer_port_tb_reg:8'hzz;

    //instatiate the bidirction_io module
    bidirection_io bidirection_io_inst(.inner_port(inner_port_tb_wire),
    .out_en(out_en_tb),
    .outer_port(outer_port_tb_wire));

    //***** monitor ******
    always@(out_en_tb,inner_port_tb_wire,outer_port_tb_wire)
    begin
    #1;
    if(outer_port_tb_wire===inner_port_tb_wire)
    begin
    $display("\n **** time=%t ****",$time);
    $display("OK! out_en=%d",out_en_tb);
    $display("OK! outer_port_tb_wire=%d,inner_port_tb_wire=%d",
    outer_port_tb_wire,inner_port_tb_wire);
    end
    else
    begin
    $display("\n **** time=%t ****",$time);
    $display("ERROR! out_en=%d",out_en_tb);
    $display("ERROR! outer_port_tb_wire != inner_port_tb_wire" );
    $display("ERROR! outer_port_tb_wire=%d, inner_port_tb_wire=%d",
    outer_port_tb_wire,inner_port_tb_wire);
    end
    end
    endmodule


    6. 高级用法
    比如pli之类的东西,我也没用过。。。有需要的,大家再讨论

       总体感觉,testbench是个很难的事情,这里讨论的只是一些最基本的东西。真正有技术含量的是testcase的设计,设计阶段合理层次设计以及模 块划分等等,我没有做过很大的项目,所以这方面也没有办法提供更多的帮助。经验丰富的大牛不妨出来讲讲经验,^_^

    --------------------- 本文来自 长弓的坚持 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/wordwarwordwar/article/details/53885209?utm_source=copy

    展开全文
  • 编写高效Vivado HLS工程testbench的三个要素
  • Vivado中IP Catalog内的大多数IP核都提供了一个TestBench,用于单独仿真该IP核。在设计中可以使用这个TestBench来仿真测试IP核的功能是否正确。在产生IP核的输出文件时,可以看到该IP核是否包含TestBench: 相关...

    Vivado中IP Catalog内的大多数IP核都提供了一个TestBench,用于单独仿真该IP核。在设计中可以使用这个TestBench来仿真测试IP核的功能是否正确。在产生IP核的输出文件时,可以看到该IP核是否包含TestBench:
    这里写图片描述
    相关文件输出完毕后,在Sources窗口的IP Sources中可以看到该TestBench文件,查阅该文件可以学习不少TestBench的设计编写方法。
    这里写图片描述
    在Sources窗口的Hierarchy标签下,在Simulation Sources文件夹中打开IP核的层次结构(点击前面的小箭头,或右键->IP Hierarchy->Show IP Hierarchy),TestBench文件名格式为tb_ipname。
    这里写图片描述
    将该Testbench设置为顶层仿真模块,右键->Set as Top:
    这里写图片描述
    注意,通常顶层模块会显示为加粗字体,但IP核的TestBench设置为Top模块时不会显示加粗(不清楚是否为Vivado版本bug),但在设置中看到仿真顶层模块为对应TestBench即可。
    这里写图片描述
    以DDS Compiler IP核为例,使用自带的TestBench进行行为仿真结果如下:
    这里写图片描述

    展开全文
  • 文章目录背景一、米联客verilog篇笔记1、为什么要推出vivado2、状态机,软核的理解3、always @的含义与 @()4、条件运算符5、阻塞逻辑和非阻塞逻辑混用二、xilinx ug910三、常用TestBench模板 背景 一件事情,...

    背景

    一件事情,只有迈出了第一步,才会有第二步,永远迈不出第一步,那么就永远停留在原点,毕竟距离毕业还有一年时间,我觉得明年这个时候,我应该已经掌握了常用的XILINX IP使用,以及仿真等使用了,此外对verilog这种语言也会有更深一步的认识。
    本篇文章是对verilog语言的全新认识,适用于有了基础后,想从语法联系到电路,这样才能对verilog有一个比较深刻的认识。

    一、米联客verilog篇笔记

    1、为什么要推出vivado

    推出Vivado 是为了提高设计者的效率,硬件进入了28nm时代,软件的设计也要提升,它能够显著增加Xilinx的28nm工艺的可编程逻辑器件的设计、
    综合与实现效率,所以,vivado目前只支持xilinx的28nm工艺的7系列FPGA,包括V7,K7,A7,ZYNQ。另外值得注意的是ISE 14.7是支持全系列的Xilinx family的。
    在这里插入图片描述

    2、状态机,软核的理解

    我们可以把一些逻辑控制顺序复杂的事情用C代码来实现,让FPGA中运行CPU(由于逻辑控制顺序
    复杂,不适合用状态机)而实时处理的部分仍然用Verilog来实现。并且那部分Verilog可以被C代码
    控制。米联客的第三段,状态输出,写的是当前状态CS,而不是NS。

    3、always @的含义与 @()

    always @() 括号里面是敏感信号。这里的always @ (posedge clk),敏感信号是posedge clk含义是上升沿的时候有效,敏感信号还可以negedge clk含义是下降沿的时候有效,这种形式一般时序逻辑都会用到。
    在这里插入图片描述
    @代表的是在什么什么时刻,代表的是一种沿触发。

    4、条件运算符

    A=B?C:D 是一个条件运算符,含义是如果B为TRUE,则把C连线A,否则把D连线A,通常B是一个条件判断,用小括弧括起来:
    assign c1_clk =(c1==25’d24999999)?1:0;

    5、阻塞逻辑和非阻塞逻辑混用

    always @ (posedge clk)
    begin
    A=1’b1; //阻塞逻辑
    B<=1’b1; //非阻塞逻辑
    end
    看到上面这个程序是阻塞与非阻塞的混合使用,一般教材是极力反对这种写法的,但有时候这种用法还能帮上大忙,只不过,不理解的话乱用会导致时序违规。当时钟上升沿来临的时刻,首先A会被置1,然后B寄存器再置1.区别就是A和B不再同时置位1。A要比B提前零点几纳秒,这样就出现了先后顺序。这个过程还是在一个时钟内完成的,但是数据到达B寄存器相比非阻塞逻辑,晚了那么零点几纳秒。
    在这里插入图片描述

    在这里插入图片描述

    二、xilinx官方DOC

    三、常用TestBench模板

    1、如何产生外部触发信号

    很多时候我们需要外部触发信号来产生激励,我们可以采用forever语句来产生占空比非50%的脉冲。

    • 产生任意占空比的外部触发信号
    initial                                                
    begin                                                  
    	#0 clk=0;
    	#0 extriger=0;
    	forever
    	begin
    		#10000 extriger=0;
    		#60000 extriger=1;
    	end
    end    
    

    在这里插入图片描述
    上图中产生了10us的高电平,60us的低电平。
    先产生60us的低电平,然后产生10us的高电平。
    在这里插入图片描述

    • 产生脉冲个数固定的脉冲信号
      repeat函数。将程序执行n次
    initial                                                
    begin                                                  
    	#0 clk=0;
    	#0 extriger=0;
    	repeat(10)
    	begin
    		#2000 extriger=0;	
    	   #80000 extriger=1;
    	end
    end   
    

    在这里插入图片描述

    2、task的用法

    在这里插入图片描述
    task 就把它当做module模块来写即可,不过module是可以综合的,而task是不能综合的而已。

    3、wait与@

    在这里插入图片描述

    四、EDA先锋工作室笔记

    1、define

    在一个文件中出现‘define可以被多个文件使用,也就是说‘defibe是一种全局性定义,这是‘define与parameter定义的最大区别。
    ‘define指令被编译以后,将在整个编译过程中有效,直到遇到‘undef指令为止,比如说:‘undef BUS_width

    2、逻辑值

    在Verilog语言中,为了对电路进行精确建模,又增加了两种逻辑状态,即“X”和“Z”。
    当“X”用作信号状态时表示未知,当用作条件判断时(在casex或casez中)表示不关心;
    “Z”表示高阻状态,也就是没有任何驱动,通常用来对三态总线进行建模。
    但是在综合工具眼里,或者说在实际实现的电路中并没有什么X值,只存在0,1和Z 3种状态。但是在实际电路中还可能出现亚稳态,它既不是0,也不是1,而是一种不稳定状态。

    3、常量

    Verilog中的常量有三中类型:整数型、实数型、字符串型
    这里就说一下字符串型吧。
    字符串是指双引号中的字符序列,是8位ASCII码值的序列,例如“Hello World” ,该字符串包含11个ASCII符号(两个单词一共10个符号,单词之间的空格为一个符号,共11个ASCII符号),因此需要11个字节存储,方法如下:

    reg [8*11:1] Message;
    ...
    Message= “Hello World”;
    这样就可以将字符串常量存入到Message变量。
    

    4、寄存器与存储器

    reg是最常用的寄存器类型数据,可以使一位、多位或者二维数组(存储器)
    reg [3:0] ABC;//定义一个名字为ABC的4位存储器
    在多位寄存器中可以进行位选择或者部分选择,例如:
    ABC [3]=1; //将ABC的第三位赋值为1;
    ABC [0]=0; //将ABC的第0位赋值为 0
    ABC [2:1]=2’b01; //将ABC的第1、2位赋值为1和0

    使用reg类型还可以定义二维寄存器数组,这种结构通常用于描述存储器(Memory结构)
    reg [3:0] MEM [0:7]; //定义一个存储器,地址为0~7,每个存储单元都是4bit
    与一维的reg变量不同的是,不能再对存储器中的存储单元进行位选择或部分选择,但是可以为每个单元单独赋值,比如:
    MEM 【1】=4b‘0101; //为MEM中的第一个存储单元赋值4’b0101.
    在verilog中,不存在一条语句对整个存储器赋值。必须对每个单元单独赋值。

    5、线网与寄存器

    线网是被驱动的,该值不被存储,在任意一个仿真步进上都需要重新计算。
    寄存器是被赋值的,且该值将在仿真过程中被保存,直到再次对该变量进行赋值。

    6、verilog中的三种描述方式

    数据流描述:采用assign连续赋值语句
    行为描述:使用always语句或initial语句块中的过程赋值语句
    结构化描述:实例化已有的功能模块或原语

    7、begin end与fork join

    begin end在测试文件中是顺序执行出现在initial中
    在fork join语句组中语句是并行执行的。代码改写为:

    initial
    fork
    databin=0;
    #6 databin=0;
    #4 databin=1;
    #2 databin=0;
    join
    

    由于所有语句是并行执行的,也就是说以上4条语句都是从0时刻开始执行的,因此产生的波形将和begin end的initial就不一样了。
    在这里插入图片描述

    8、if else 与case

    if else语句是有优先顺序的,如果第一级是关键路径的话,就可以利用这样的优先级编码提高设计性能。
    case语句中,所有被判断的分之条件都具有一样的优先级。
    在always模块内,逻辑是按照指定的顺序执行的。always块中的语句称为顺序语句,因为他们是顺序执行的,请注意,两个或多个的always模块也是同事执行的,但是模块内部的语句是顺序执行的,看一下always内的语句,你就会明白它是如何实现功能的。if,,,else,,,if必须顺序执行,否则其功能就没有任何意义。如果else语句在if语句之前执行,功能就不符合要求。

    五、vivado的基本使用

    1、创建工程

    在这里插入图片描述
    选择RTL工程
    在这里插入图片描述
    选择器件
    在这里插入图片描述
    界面介绍
    在这里插入图片描述
    在这里插入图片描述

    2、语法参考language templates与IP catalog

    在这里插入图片描述
    上面要介绍的这个Language Templates。包含了我们所有的语法,IP例化等等,真的是非常方便,而且,我们可以经常查阅这个模板,从而掌握更多的语法结构。
    在这里插入图片描述
    在上图中synthesis constructs包含了可综合的常见的语法结构
    在这里插入图片描述
    如上图所示,coding example包含了很多例子,包括乘法器,ram移位,状态机等等,简直可以称得上一本完美的教科书。

    对于vivado FPGA工程师来说,这些代码永远值得参考学习,永远值得敬畏,永远值得温习,学习,从而改进自己的代码风格。
    下图的IP catalog也是一个非常有用的工具,包含了所有的IP,我们可以根据这个目录去学习一些常用的IP核。

    在这里插入图片描述
    在这里插入图片描述

    3、RTL详细描述和分析

    详细描述(Elaboration)是指将RTL优化到FPGA技术。在基于RTL的设计中,详细描述是第一步,当设计者打开一个详细描述的RTL,设计者可以查看RTL结构、语法和逻辑定义。分析和报告能力包括:
    RTL编译有效性和语法检查;
    网表和原理图研究;
    设计规则检查;
    使用一个RTL端口列表的早期IO引脚规划;
    在RTL视图中,选择一个对象,右击,出现浮动菜单。在浮动菜单内,选择go to source 选项,将自动跳转到定义该对象源代码的位置。
    在这里插入图片描述
    如下图所所示,可进行IO管脚分配。
    在这里插入图片描述
    在这里插入图片描述
    从上图所示,选定了RTL的对象过后,右键点击go to source,可以跳转到代码位置。所以关于RTL的所有对象,我们也有必要学习,这样才能更深刻理解数字电路。关于RTL的所有对象,我以后会专门写一篇文章,这里暂时放一放。(无力吐糟感,处女座强迫症)
    在这里插入图片描述
    RTL Netlists里面,在该标签窗口中,查看RTL级网表。

    上面箭头的Nets代表连线
    leaf cells代表对象

    4、综合及资源报告

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    添加verilog文件过后,我们可以看到
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    上面两张图是进行综合后的总结报告。
    要比较X和A的FPGA,就要清楚两个大厂的FPGA的结构,但是,两家公司都可以统一到LUT(Look_UP_Table)查找表上。A家的片子,用的是LE这个术语。
    在这里插入图片描述
    而X家用的是CLB这个术语,作为基本单元
    在这里插入图片描述
    再来看看两家的基本单元有何不同:
    在这里插入图片描述
    A家就是一个4输入LUT+FF构成

    而X家的CLB如下:
    在这里插入图片描述
    一个CLB由2个SLICE构成,一个SLICE含有4个6输入的LUT,所以LUT=8*CLB
    在这里插入图片描述
    这样的话,可以较比一下。EP4CE6基本就和XC6SLX9一个级别。。。。当然A家的片子是4输入LUT远比不上X家的6输入LUT。而X家的S-6片子,一个Slice内部有4个lut,8个FF。简而言之,一个Slice=四个LE。要注意的是A家C5以下的片子是4输入LUT而X家的是6输入LUT,差别也较大。如果不考虑FF,那么一个X家的slice=4个A家的LE。例如XC6SLX16含有2278个slices=EP4CE10(9000LE)的样子。当然,S-6的FF多一倍,达到了18224个。
    在Virtex-5中(我们的设计大部分是Virtex,V5V6V7),一个Slice包含了4个LUT和4个FF。所以单纯从逻辑资源来看,S-6一个Slice比V-5的Slice强。当然V5的GTPGTX等等还有IO数量是S-6赶不上的。当然,A家的Cyclone V系列的片子,内部和前几代完全不同,采用了从高端的Stratix系列下放的技术,在新设计时,值得推荐~!
    上述介绍参考:https://www.cnblogs.com/lifan3a/articles/4682471.html
    说了这么多,那么综合究竟是干嘛呢?综合就是将RTL级的设计描述转换成门级的描述,比如说触发器,我们知道触发器也是由门电路组成的。在综合过程中,将进行逻辑优化,并且映射到Xilinx器件原语。该综合工具支持xilinx设计约束XDC。
    在综合的过程中,综合工具使用XDC约束来驱动综合优化,因此必须存在XDC文件。

    在这里插入图片描述
    当执行完综合后,可以展开synthesis design。在synthesis designed分组中听过了下列选项:
    1、constraints wizard(约束向导)
    2、Edit Tiing Constraints(编辑时序约束):该选项用于启动时序约束标签。
    3、set up debug (设置调试):该选项用于启动标记网络视图界面,这些标记过的网络视图将用于调试目的。
    4、report timing summary(报告时序总结):该选项生成一个默认的时序报告。
    5、report clock networks(报告时钟网络):该选项生成该设计的时钟树。
    6、report clock interaction(报告时钟相互作用):该选项用于在时钟域之间,验证路径上的约束收敛。
    7、report DRC(报告DRC):该选项用于对整个设计执行设计规则检查。
    8、report noise(报告噪声):该选项用于对设计中的输出和双向引脚执行一个SSO分析。
    9、report utilization(报告利用率):该选项生成一个图形化的利用率报告
    10、report power(报告功耗):该选项用于生成一个详细的功耗分析报告。
    11、schematic(原理图):该选项用于打开原理图视图界面。

    4、实现implement

    在这里插入图片描述
    在这里插入图片描述
    可以看到经过实现后的资源有所变化,LUT减少
    解决办法:
    https://blog.csdn.net/xinxulsq/article/details/80926720

    5、时序约束

    参考视频:https://china.xilinx.com/video/hardware/using-vivado-timing-constraint-wizard.html
    参考视频:中文配音:http://xilinx.eetrend.com/d6-xilinx/webinar/2016-08/10388.html
    vivado中约束文件名字的后缀名是.xdc,用于取代ISE集成设计环境中的.ucf文件

    6、IO管脚分配

    在这里插入图片描述
    在layout下,可以切换至IO规划器。
    可以通过IO规划器来实现约束引脚位置。IO规划器允许设计者查看晶圆和封装视图,这样设计者就可以理解IO组合逻辑之间的关系。
    在器件视图中,引脚之间的不同颜色区域标识了IO组,同时显示了差分对。从图中可以看到时钟使能引脚、VCC、GND,以及没有连接的引脚,这些引脚通过不同的形状来标识。
    在这里插入图片描述
    在这里插入图片描述
    采用此工具还可以自动分配管脚。

    7、仿真

    1、vivado simulator以及操作技巧

    通过点击add sources,可以增加仿真文件
    在这里插入图片描述
    如下图,添加tb文件添加成功。可以看到在我们添加了tb文件,然后编写tb文件代码后,原来的顶层模块也自动加入到sim中来了。

    在这里插入图片描述
    顶层代码:

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2019/05/15 14:13:04
    // Design Name: 
    // Module Name: led_top
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    module led_top(
    input clk,
    input rst,
    output led
        );
    
    reg [28:0] time_cnt;
    reg led_reg;
    
    always @ (posedge clk or negedge rst)
    	begin
    		if(!rst)
    		time_cnt<=0;
    		else if (time_cnt=='d50000000)
    		time_cnt<=0;
    		else
    		time_cnt<=time_cnt+1'b1;
    	end
    
    always @ (posedge clk or negedge rst)
    	begin
    		if(!rst)
    		led_reg<=0;
    		else if(time_cnt=='d50000000)
    		led_reg<=~led_reg;
    		else
    		led_reg<=led_reg;
    	end
    assign led=led_reg;
    endmodule
    
    
    

    仿真文件

    `timescale 1ns / 1ns
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2019/05/15 14:06:03
    // Design Name: 
    // Module Name: led_top_tb
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module led_top_tb(
    reg clk,
    reg rst,
    wire led
        );
     parameter PERIOD = 20;
    led_top led_top_inst(
            .clk(clk),
            .rst(rst),
            .led(led)
                );
    initial 
    begin
    #0 clk=0;
    #0 rst=0;
    #100 rst=1;
       forever
          #(PERIOD/2) clk = ~clk;
    end
    endmodule
    
    

    点击run simulation,第一个是行为仿真,后面还有4种仿真,一般来说,我们进行功能仿真,如果跑时序仿真,往往比较慢。

    在这里插入图片描述
    下图为运行综合function仿真后的结果
    在这里插入图片描述
    我们可以从左边的scope里面拖动要观察的信号到右边,然后run all即可
    在这里插入图片描述
    这里实现后,仿真就不介绍了,操作步骤都是一样的。
    我们来看一下经过实现后的仿真,每个time_cnt累加已经变化了,也就是说,它不是一下就变化的,而是一位一位的变化的。
    在这里插入图片描述

    至此,我们的自带vivado simulator仿真实验就已经讲解完毕了。下面,我再针对仿真实验,做一些额外的补充。
    补充参考视频资源:
    https://www.bilibili.com/video/av44305906/?p=3基于Xsim的仿真
    在这里插入图片描述
    如上图所示,我们要将仿真工具设置为vivado simulator。
    此外,仿真的语言,我们选择为verilog,如果我们选择vivado simulator就不需要再对仿真编译库进行额外的编译,但是如果选择第三方平台如modelsim等工具,我们是需要额外对仿真编译库进行编译的。
    此外,如果我们针对多个模块进行仿真,写了多个模块的多个TB,那么我们需要制定要仿真顶层文件。
    在这里插入图片描述
    此外,我们还可以保存我们的波形文件,波形文件类型为wcfg
    在这里插入图片描述
    如上图所示,我们可以将选择option,从而设置默认的波形选项。
    此外,我们还可以将波形信号进行分组,这样有个好处是将暂时不看的波形折叠到一起,挪出屏幕空间观察别的信号。
    在这里插入图片描述
    如何精准测量时间间隔
    在这里插入图片描述
    如上图所示,我们是怎么测量时钟之间的间隔的呢,首先,我们点击需要将光标落到某个要观察的信号,这样,这个信号就保持高亮状态了,然后点击如下图所示的两个transition按钮,这两个按钮的意思是数据变化的时间点。然后进行add maker。最后出现两条蓝色线后,点击
    在这里插入图片描述
    在这里插入图片描述
    此外,如果我们需要观察的信号更多的话,还可以添加另一个波形窗口。
    在这里插入图片描述

    如何保存一个波形呢,然后下次直接打开保存的波形
    在这里插入图片描述
    首先是要进行保存波形文件,文件类型为wcfg文件。
    下次打开这个波形文件的时候,要开启一个新的waveform configuration,然后再点击open waveform configuration。

    2、基于modelsim的仿真(避免重复Xilinx编译库)

    参考视频:https://www.bilibili.com/video/av44305906/?p=4 基于modelsim的仿真
    值得注意的是,采用modelsim的仿真,是基于第三方平台,所以我们需要编译xilinx的库,如果我们使用vivado自带的就不需要
    在这里插入图片描述
    采用如上图所示的命令compile_smlib来编译
    在这里插入图片描述
    在这里插入图片描述
    上图是编译库后的路径,那么现在问题来了,我们是不是需要每一次工程都让vivado编译整个xilinx的库呢?答案显示是不需要的,我只要指定编译好的文件为公共文件即可,这样就能实现每次共享了,除非是新版本的vivado的软件刚安装好,新的modelsim文件刚刚安装好。否则,我们只需要每次调用这个公共的xilinx的库即可。
    在这里插入图片描述
    在这里插入图片描述
    上图是option里面modelsim的安装路径。
    通过上面简单的介绍,下面我们就开始以真正的实际例子来说吧。
    参考文章:
    https://blog.csdn.net/gooyin/article/details/82769643
    在这里插入图片描述
    如上图所示,在tools–>compile simlation library -->设置编译选项并指定编译路径,如下图所示,我们将指定编译库的位置放在modelsim的安装路径,并且新建了一个文件夹叫做 vivado_simib
    在这里插入图片描述
    执行的命令为:

    compile_simlib -language all -dir {D:/modism_10.4/vivado_simlib} -simulator_exec_path {D:/modism_10.4/win64} -library all -family  all
    

    通过命令,我们应该可以看出来之前讲的理论了,这是编译了xilinx所有的器件库。
    设置好后,点击compile即可,整个时间比较长,大概好几分钟的左右(i7 8核处理器)

    此时我打开编译库的文件夹
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    编译的整个库文件大小为2.37GB
    在编译的库文件里面有一个modelsim.ini文件
    在这里插入图片描述
    用notepad++打开并找到mvc_lib = $MODEL_TECH/…/mvc_lib
    下面都是编译好的IP所处的路径,将这些全部复制,然后打开modelsim安装路径下的modelsim.ini文件并完成粘贴。

    在这里插入图片描述
    下面我们运行vivado run simulation就可以了,这样modelsim就可以运行了,并且我们可以看到modelsim中添加了大量的Xilinx库
    在这里插入图片描述
    如下图所示,成功调用了modelsim,并运行仿真。
    在这里插入图片描述
    其实在这里,我又在开始思考一个问题了,Alteral 是不是也可以这样避免每次重复编译库呢?这个问题,以后我亲自实践,研究研究后,会再写一篇文章。

    8、烧写下载、固化程序

    烧写程序有两种,一种是不保存的,一种是能够保存到flash中的。下面就开始分别介绍。

    1、生成bit文件

    在这里插入图片描述
    上图是产生bitstream
    然后给开发板通电,并且连接下载器,单击open target 然后单击auto connect
    在这里插入图片描述
    连接成功后vivado会自动识别到芯片

    在这里插入图片描述
    然后单击program device
    在这里插入图片描述
    下载过程
    在这里插入图片描述

    2、固化程序

    对于纯粹的verilog工程的固化
    在这里插入图片描述
    在这里插入图片描述
    然后选择一个flash类型,设置生成mcs文件名,选择生成的bit流文件
    在这里插入图片描述
    1、选择好flash存储器件
    2、自动填充flash的存储大小,注意单位是MB,所以是原本flash大小再除以8
    3、命名mcs文件
    4、选择烧写接口
    5、选择bit文件
    6、全部勾选

    在这里插入图片描述
    最终我们可以看到生成了mcs文件和prm文件
    在这里插入图片描述
    最后我们来看如何将烧写后的程序固化到flash中。
    在这里插入图片描述
    接下来就是要连接到器件。这里由于我目前身边没有,我就直接粘贴一下外协给的步骤吧。
    在这里插入图片描述
    在这里插入图片描述
    如上图,是识别到了三个FPGA,我们分别给每一个FPGA配置flash。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    选中FLASH芯片,右键选择“Program Configuration Memory Device”。
    在这里插入图片描述
    添加待配置的.MCS和.prm文件,如下图所示,其它默认或按需求更改。注意不要选错文件。
    在这里插入图片描述
    然后静待固化完成,完成后会弹窗提示。最后断电、断开JTAG,再上电。

    福利链接

    认识FPGA已经有2年了,我可能以后不会从事FPGA开发了,但FPGA依然是相关的,所以FPGA我会慢慢学,而不是主打了,这里我总结了一些适合初学者以及想进阶的FPGA视频,
    包含了USB 3.0 DDR2 sobel边缘检测、图像处理、千兆以太网的详细文档代码讲解,另外包含了xilinx 锆石的文档讲解,以及明德扬的信号处理文档(不含视频),此外还有Intel的官方视频。
    都是良心推荐的。需要可以Q1183699227 5元

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 工程文件虽然部分基于xilinx的官方例程,但官方例程没有testbench,这部分是自己编写的,并对不同的配置进行了分析,完整的工程文件见 如果没有分数下载,认真看本篇,也能做出来。 第一部分参考以下文章,表示感谢...
  • Test bench是一个用来验证逻辑功能是否正确的虚拟坏境,由Driver/Stimulus(输入激励)、Reference Model(参考模型,其输出结果是正确结果)、DUT(待测模型,Design Under Test,我们需要综合的C函数)、Monitor...
  • C/C++ Test bench的基本架构 Test bench是一个用来验证逻辑功能是否正确的虚拟坏境,由Driver/Stimulus(输入激励)、Reference Model(参考模型,其输出结果是正确结果)、DUT(待测模型,Design Under Test...
  • 参见 玩转Zynq连载17——新建Vivado工程,这里不再另行说明。 更改编辑器 Tools→settings→TextEditor→CurrentEditorTools\rightarrow settings\rightarrow Text Editor \rightarrow Current EditorTools→...
  • 首先要明白测试代码的作用,这点其实很重要!...8、 结束testbench程序的运行  用$stop 或$finish结束程序的运行,另起一个initial。例如 initial begin #(1000000*CYCLE); $ stop; end  
  • test bench是FPGA开发中很关键的一个部分,可以给大型FPGA项目开发节约大量的时间,进行逻辑仿真是非常有必要的一步,希望初学者重视起来。使用编译软件quartus或者vivado等等和modelsim进行关联仿真,这种调用方法...
  • VIM插件 -- 自动生成verilog module的testbench@(VIM)1. 动机软件语言都有各自好用的IDE,各种自动补全,高亮,语法检查。而苦逼的ICer大多还操着远古时期的VIM写着verilog。也是,硬件语言本身就小众,即使是xilinx...
  • module testbench ; reg clk ; wire ddp ; wire gdp ; wire out ; wire add ; wire [ 3 : 0 ] m ; wire [ 3 : 0 ] n ; test test ( . clk ( clk ) , . out ( out ) , . gdp ...
  • 新建工程打开Vivado软件,直接在欢迎界面点击Create New Project,或在开始菜单中选择File - New Project即可新建工程。点击Next输入工程名称和路径。选择RTL Project,勾选Do not specify......(这样可以跳过添加...
  • 这个是vivado写的Verilog代码,主要是实现FIFO的功能,还有一些是自己的测试testbench
  • 记录testbench编写使用过程中的问题,作为笔记不定时更新。 FPGA开发过程中,编写的模块如果直接使用硬件仿真,开发会特别费时费力,一般编写完一个逻辑模块后可以使用时序...vivado软件没有自动生成TestBench文件的
  • 如何写一个仿真文件——testbench

    千次阅读 2020-04-29 17:25:08
    任何设计都是有输入输出的,testbench的作用就是给这个设计输入,然后观察输出是否符合我们的预期,这就是testbench的功能。运行环境一般是ise或者vivado自带的仿真工具,或者如modelsim一样的第三方仿真工具。 如下...
  • Vivado中IP Catalog内的大多数IP核都提供了一个TestBench,用于单独仿真该IP核。在设计中可以使用这个TestBench来仿真测试IP核的功...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 143
精华内容 57
关键字:

testbenchvivado