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