使用 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 语句在我看来实际上更容易阅读,并且更清楚它的作用。但我不想在设计和测试中使用相同的 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; 改为 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 错误进行故障排除。