verilog开始使用verilog


备注

Verilog是一种硬件描述语言(HDL),用于在行为或寄存器传输级别设计,模拟和验证数字电路。值得注意的是,将其与“传统”编程语言区分开来:

  • 有两种类型的赋值,阻塞和非阻塞,每种都有自己的用法和语义。
  • 必须将变量声明为单位宽或显式宽度。
  • 设计是分层的,能够实例化具有所需行为的模块。
  • 在模拟中(通常不在合成中), wire变量可以处于四种状态之一:0,1,浮动( z )和未定义( x )。

版本

发布日期
Verilog IEEE-1364-1995 1995-01-01
Verilog IEEE-1364-2001 2001-09-28
Verilog IEEE-1364.1-2002 2002-12-18
Verilog IEEE-1364-2005 2006-04-07
SystemVerilog IEEE-1800-2009 2009-12-11
SystemVerilog IEEE-1800-2012 2013年2月21日

介绍

Verilog是一种用于模拟电子系统的硬件描述语言(HDL)。它最常描述的是抽象的寄存器传输级(RTL)的电子系统。它还用于验证模拟电路和混合信号电路。其结构和主要原则(如下所述)旨在描述和成功实施电子系统。

  • 刚性
    电子电路是具有固定结构的物理实体,Ve​​rilog适用于此。模块(模块),端口(输入/输出/输入),连接(电线),块(@always),寄存器(reg)都在编译时固定。实体和互连的数量不会动态变化。顶层始终有一个“模块”代表芯片结构(用于合成),一个在系统级用于验证。
  • 排比
    物理芯片中固有的同时操作通过始终(大多数通用),初始和fork / join块在语言中模仿。
  module top();
  reg r1,r2,r3,r4; // 1-bit registers
    initial
    begin
      r1 <= 0 ;
    end
    initial
    begin
      fork
         r2 <= 0 ;
         r3 <= 0 ;
      join
    end
     always @(r4)
        r4 <= 0 ;
 endmodule
 

所有上述语句在同一时间单元内并行执行。

  • 定时和同步
    Verilog支持各种结构来描述电路的时间特性。电路中的时序和延迟可以在Verilog中实现,例如#delay结构。类似地,Verilog还适用于同步和异步电路以及使用各种结构的触发器,锁存器和组合逻辑等组件,例如“始终”模块。还可以通过公共时钟信号同步一组块,或者可以基于特定的输入集触发块。

    #10   ;                 // delay for 10 time units
    always @(posedge clk )  // synchronous 
    always @(sig1 or sig2 ) // combinatorial logic  
    @(posedge event1)       // wait for post edge transition of event1
    wait (signal  == 1)     // wait for signal to be 1
     
  • 不确定
    Verilog支持电子电路中固有的一些不确定性。 “X”用于表示电路的未知状态。 “Z”用于表示电路的未驱动状态。

    reg1 = 1'bx;
    reg2 = 1'bz;
     
  • 抽象化
    Verilog支持在不同抽象级别进行设计。设计的最高抽象级别是Resister传输级别(RTL),下一个是门级别,最低级别是单元级别(User Define Primitives),RTL抽象是最常用的。 Verilog还支持行为抽象级别,而不考虑主要用于验证的设计的结构实现。

 // Example of a D flip flop at RTL abstraction
module dff (
 clk    , // Clock Input
 reset  , // Reset input
 d       , // Data Input
 q        // Q output
 );
 //-----------Input Ports---------------
 input d, clk, reset ;

 //-----------Output Ports---------------
 output q;

 reg q;

 always @ ( posedge clk)
 if (~reset) begin
   q <= 1'b0;
 end  else begin
   q <= d;
 end

endmodule


// And gate model based at Gate level abstraction 
module and(input x,input y,output o);

wire  w;
// Two instantiations of the module NAND
nand U1(w,x, y); 
nand U2(o, w, w); 

endmodule

// Gate modeled at Cell-level Abstraction
primitive udp_and(
a, // declare three ports
b,
c 
);
output a;   // Outputs
input b,c;  // Inputs 

// UDP function code here
// A = B & C;
table
 // B  C    : A 
    1  1    : 1;
    0  1    : 0;
    1  0    : 0;
    0  0    : 0;
endtable

endprimitive
 

Verilog有三个主要用例。它们确定代码的结构及其解释,并确定使用的工具集。所有这三个应用程序都是成功实现任何Verilog设计所必需的。

  1. 物理设计/后端
    这里,Verilog主要将设计视为实现逻辑设计的互连门矩阵。 RTL / logic / Design经历了从综合 - >布局 - >时钟树构造 - >路由 - > DRC - > LVS - >到tapeout的各个步骤。精确的步骤和顺序根据实施的确切性质而有所不同。
  2. 模拟
    在该用例中,主要目的是生成测试向量以根据规范验证设计。在这个用例中编写的代码不需要是可综合的,它仍然在验证范围内。这里的代码更像是for / while / do循环等通用软件结构。
  3. 设计
    设计涉及通常在RTL抽象级别实现电路规范。然后给出用于验证的Verilog代码,并且为物理实现提供完全验证的代码。代码只使用Verilog的可合成结构编写。某些RTL编码风格可能导致模拟与合成不匹配,必须注意避免这些。

有两个主要的实施流程。它们还会影响Verilog代码的编写和实现方式。某些样式的编码和某些结构更适合于一个流程而不是另一个流程。

  • ASIC流程(专用集成电路)
  • FPGA流程(现场可编程门阵列) - 包括FPGA和CPLD

你好,世界

此示例使用icarus verilog编译器。

第1步:创建一个名为hello.v的文件

module myModule();

initial
  begin
    $display("Hello World!");   // This will display a message
    $finish ; // This causes the simulation to end.  Without, it would go on..and on.
  end

endmodule
 

第2步。我们使用icarus编译.v文件:

>iverilog -o hello.vvp hello.v
 

-o开关为输出对象文件指定名称。如果没有此开关,输出文件将被称为a.out。 hello.v表示要编译的源文件。编译此源代码时,实际上应该没有输出,除非有错误。

第3步。您已准备好模拟此Hello World verilog程序。为此,请调用:

>vvp hello.vvp 
Hello World!
>
 

在Mac OSx Sierra上安装GTKWave以模拟数据的图形显示

GTKWave是一个功能齐全的图形查看包,支持多种图形数据存储标准,但它也支持VCD,这是vvp 将输出的格式。所以,要选择GTKWave,你有几个选择

  1. 转到http://gtkwave.sourceforge.net/gtkwave.zip并下载它。此版本通常是最新版本。
  2. 如果您已经安装了MacPorts( https://www.macports.org/ ),只需运行sudo port install gtkwave 。这可能要安装在依赖项上。请注意,此方法通常会为您提供旧版本。如果您没有安装MacPorts,则可以在此页面上执行此操作的安装设置示例。是!您将需要所有xcode开发人员工具,因为此方法将从源“构建”您的GTKWave。

安装完成后,可能会要求您选择python版本。我已经安装了2.7.10,所以我从未“选择”新的。

此时,您可以使用gtkwave 从命令行启动gtkwave 。启动时,可能会要求您安装或更新XQuarts。这样做。在我的例子中安装了XQuarts 2.7.11。

注意:我实际上需要重新启动以正确获取XQuarts,然后我再次键入gtkwave 并启动应用程序。

在下一个示例中,我将创建两个独立的文件,一个测试平台和要测试的模块,我们将使用gtkwave来查看设计。

为Mac OSX Sierra安装Icarus Verilog编译器

  1. 从App Store安装Xcode。
  2. 安装Xcode开发人员工具
> xcode-select --install
 

这将提供基本的命令行工具,如gccmake

  1. 安装Mac端口https://www.macports.org/install.php

OSX Sierra安装包将提供在Mac平台上安装和升级其他软件包的开源方法。为Mac考虑yumapt-get

  1. 使用Mac端口安装icarus
> sudo port install iverilog
 
  1. 从命令行验证安装
$ iverilog
iverilog: no source files.

Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
                [-g1995|-g2001|-g2005] [-g<feature>]
                [-D macro[=defn]] [-I includedir] [-M depfile] [-m module]
                [-N file] [-o filename] [-p flag=value]
                [-s topmodule] [-t target] [-T min|typ|max]
                [-W class] [-y dir] [-Y suf] source_file(s)

See the man page for details.
$
 

您现在可以在Mac上编译和模拟您的第一个Verilog文件。

安装或设置

有关设置或安装Verilog的详细说明取决于您使用的工具,因为有许多Verilog工具。

使用Icarus Verilog和GTKWaves以图形方式模拟和查看设计

这个例子使用了Icarus和GTKWave。 OSx上这些工具的安装说明在本页的其他地方提供。

让我们从模块设计开始。该模块是BCD到7段显示器。我已经用一种钝的方式对设计进行编码,只是为了给我们一些容易打破的东西,我们可以花一些时间以图形方式进行修复。所以我们有一个时钟,复位,一个表示BCD值的4数据输入,以及一个代表七段显示的7位输出。创建一个名为bcd_to_7seg.v的文件,并将源代码放在其中。

module bcd_to_7seg (
   input clk,
   input reset,
   input [3:0] bcd,
   output [6:0] seven_seg_display

);
   parameter TP = 1;
   reg seg_a;
   reg seg_b;
   reg seg_c;
   reg seg_d;
   reg seg_e;
   reg seg_f;
   reg seg_g;

   
   always @ (posedge clk or posedge reset)
      begin
      if (reset)
         begin
            seg_a <= #TP 1'b0;
            seg_b <= #TP 1'b0;
            seg_c <= #TP 1'b0;
            seg_d <= #TP 1'b0;
            seg_e <= #TP 1'b0;
            seg_f <= #TP 1'b0;
            seg_g <= #TP 1'b0;
         end
      else
         begin
            seg_a <= #TP  ~(bcd == 4'h1 || bcd == 4'h4);
            seg_b <= #TP  bcd < 4'h5 || bcd > 6;
            seg_c <= #TP   bcd != 2;
            seg_d <= #TP   bcd == 0 || bcd[3:1] == 3'b001 || bcd == 5 || bcd == 6 || bcd == 8;
            seg_e <= #TP  bcd == 0 || bcd == 2 || bcd == 6 || bcd == 8;
            seg_f <= #TP  bcd == 0 || bcd == 4 || bcd == 5 || bcd == 6 || bcd > 7;
            seg_g <= #TP  (bcd > 1 && bcd < 7) || (bcd > 7);
         end
    end
 
    assign seven_seg_display = {seg_g,seg_f,seg_e,seg_d,seg_c,seg_b,seg_a};
endmodule
 

接下来,我们需要一个测试来检查该模块是否正常工作。测试平台中的case语句在我看来实际上更容易阅读,并且更清楚它的作用。但我不想在设计和测试中使用相同的案例陈述。这是不好的做法。相反,两个独立的设计被用于相互验证。

使用下面的代码,你会注意到两行$dumpfile("testbench.vcd");$dumpvars(0,testbench); 。这些行是创建将用于执行设计图形分析的VCD输出文件的行。如果你将它们遗漏,你将无法生成VCD文件。创建一个名为testbench.v的文件,并将源代码放在其中。

`timescale 1ns/100ps
module testbench;
reg clk;
reg reset;
reg [31:0] ii;
reg [31:0] error_count;
reg [3:0] bcd;
wire [6:0] seven_seg_display; 
parameter TP = 1;
parameter CLK_HALF_PERIOD = 5;
 
   // assign clk = #CLK_HALF_PERIOD ~clk;  // Create a clock with a period of ten ns
   initial
   begin
     clk = 0;
     #5;
     forever clk = #( CLK_HALF_PERIOD )  ~clk;
   end

   initial
     begin
       $dumpfile("testbench.vcd");
       $dumpvars(0,testbench);
       // clk  = #CLK_HALF_PERIOD ~clk; 
       $display("%0t, Reseting system", $time);
       error_count = 0;
       bcd  = 4'h0;
       reset = #TP 1'b1;
       repeat (30) @ (posedge clk);
       reset  = #TP 1'b0;
       repeat (30) @ (posedge clk);
       $display("%0t, Begin BCD test", $time); // This displays a message


       for (ii = 0; ii < 10; ii = ii + 1)
          begin
          repeat (1) @ (posedge clk);
          bcd  = ii[3:0];
          repeat (1) @ (posedge clk); 
          if (seven_seg_display !== seven_seg_prediction(bcd)) 
             begin
                $display("%0t, ERROR: For BCD %d, module output 0b%07b does not match prediction logic value of 0b%07b.",$time,bcd, seven_seg_display,seven_seg_prediction(bcd));
                error_count = error_count + 1;
             end
          end
       $display("%0t, Test Complete with %d errors", $time, error_count);
       $display("%0t, Test %s", $time, ~|error_count ? "pass." : "fail.");
       $finish ; // This causes the simulation to end.
     end


parameter SEG_A = 7'b0000001;
parameter SEG_B = 7'b0000010;
parameter SEG_C = 7'b0000100;
parameter SEG_D = 7'b0001000;
parameter SEG_E = 7'b0010000;
parameter SEG_F = 7'b0100000;
parameter SEG_G = 7'b1000000;

function [6:0] seven_seg_prediction;
   input [3:0] bcd_in;

   //    +--- A ---+
   //    |         |
   //    F         B
   //    |         |
   //    +--- G ---+
   //    |         |
   //    E         C
   //    |         |
   //    +--- D ---+

   begin
      case (bcd_in)
         4'h0: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
         4'h1: seven_seg_prediction = SEG_B | SEG_C;
         4'h2: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
         4'h3: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D;
         4'h4: seven_seg_prediction = SEG_F | SEG_G | SEG_B | SEG_C;
         4'h5: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
         4'h6: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_E | SEG_C | SEG_D;
         4'h7: seven_seg_prediction = SEG_A | SEG_B | SEG_C;
         4'h8: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
         4'h9: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_B | SEG_C;
         default: seven_seg_prediction = 7'h0;
      endcase
   end
endfunction


bcd_to_7seg u0_bcd_to_7seg (
.clk               (clk),
.reset             (reset),
.bcd               (bcd),
.seven_seg_display (seven_seg_display)
);


endmodule
 

现在我们有两个文件,一个是testbench.v和bcd_to_7seg.v,我们需要编译,详细说明使用Icarus。去做这个:

$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
 

接下来我们需要模拟

$ vvp testbench.vvp 
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
8000, Test Complete with          0 errors
8000, Test pass. 
 

此时,如果要验证文件是否正在测试中,请转到bcd_2_7seg.v文件并移动一些逻辑并重复前两个步骤。

作为一个例子,我改变了行seg_c <= #TP bcd != 2; to seg_c <= #TP bcd != 4; 。重新编译和模拟执行以下操作:

$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
$ vvp testbench.vvp 
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
6600, ERROR: For BCD  2, module output 0b1011111 does not match prediction logic value of 0b1011011.
7000, ERROR: For BCD  4, module output 0b1100010 does not match prediction logic value of 0b1100110.
8000, Test Complete with          2 errors
8000, Test fail.
$
 

现在,让我们使用GTKWave查看模拟。从命令行发出一个

gtkwave testbench.vcd &

出现GTKWave窗口时,您将在左上角的框中看到模块名称testbench。点击它。这将揭示与该文件关联的子模块,任务和功能。电线和寄存器也将出现在左下方的框中。

现在将,clk,bcd,error_count和seven_seg_display拖动到波形窗口旁边的信号框中。现在将绘制信号。 Error_count将显示哪个特定的BCD输入生成了错误的seven_seg_display输出。

您现在已准备好以图形方式对Verilog错误进行故障排除。