使用 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 錯誤進行故障排除。