1. 前言:Verilog 中「display」的重要性與目的
什麼是 Verilog 中的「display」?
Verilog 中使用的 $display
是系統任務之一,用於在模擬過程中「顯示」程式的內部狀態。就像 C 語言的 printf
一樣,它可以將訊號或變數的值、字串等輸出到終端機或控制台,是非常方便的功能,在除錯與動作確認中扮演核心角色。
為什麼 $display
在 Verilog 開發中不可或缺
- 提升除錯效率:在複雜的電路設計中,將內部訊號可視化是非常重要的。透過
$display
,能在模擬中立即檢查關鍵訊號的值。 - 模擬可視化:在追蹤特定時序的值變化時,僅靠波形可能不足,顯示日誌能清楚呈現關鍵時刻。
- 文件化用途:在將設計意圖或操作規則傳達給其他工程師時,於輸出日誌中加入註解或提示能提升程式碼的理解度。
本文的目的與架構
本文將依序解說以下內容:
- 基本寫法與用法:詳細介紹
$display
的基本語法與使用方式。 - 與其他系統任務比較:整理
$write
、$strobe
、$monitor
等相關顯示任務的差異。 - 格式指定符與應用技巧:介紹
%d
、%b
、%h
、%s
等格式化輸出的使用方法。 - 實用範例:搭配程式碼展示測試平台與模組中的應用,提供即戰力技巧。
- 顯示控制的應用:涵蓋 LCD 與螢幕控制,說明文字與圖片輸出的實際應用。
透過這樣的架構,從初學者到中階使用者都能正確理解並實際運用 Verilog 中的 $display
。接下來的各章節將盡可能搭配範例與圖解,使內容更容易理解。
2. $display
的基礎:寫法・用途・注意事項
$display
的基本語法
在 Verilog 中使用 $display
時,其基本語法如下:
$display("字串或格式指定符", 訊號1, 訊號2, ...);
- 字串部分:可填入任意文字或格式指定符(例如:
%d
,%b
,%h
)。 - 引數:可列出訊號名稱或變數,並依照對應格式輸出。
範例:顯示時脈計數與訊號值
$display("Time=%0t : clk=%b, reset=%b", $time, clk, reset);
此範例會在模擬過程中輸出模擬時間、時脈與重置信號的值。
$display
的用途
- 掌握模擬進度
在程式特定區段插入$display
,即可確認程式執行進度。 - 檢查訊號值
僅靠波形檢視難以理解的條件判斷或狀態轉換,可以透過文字輸出更直觀地理解。 - 條件式訊息輸出
可搭配if
語句,僅在符合特定條件時輸出日誌。if (reset) $display("Reset asserted at %0t", $time);
$display
與 $write
的差異
$display
會在輸出結尾自動加上換行符號;而 $write
則不會換行,可連續輸出。
範例:
$display("Hello");
$display("World");
輸出結果:
Hello
World
$write("Hello");
$write("World");
輸出結果:
HelloWorld
→ 當需要有條理的一行一筆輸出時,選擇 $display
;若要將多筆資料排在同一行,則使用 $write
。
注意事項
- 避免過量輸出
若在每個時脈週期都使用$display
,日誌會過於龐大並降低可讀性。
→ 建議加入條件控制輸出。 - 善用時間輸出
透過$time
或$realtime
,可精確掌握動作發生的時刻。 - 僅限模擬使用
$display
無法用於合成(FPGA/ASIC 實作),僅能在模擬環境中用於除錯。
3. 日誌輸出系統任務比較:$display・$write・$strobe・$monitor
Verilog 除了 $display
,還有其他系統任務可用於輸出。由於用途與輸出時機不同,理解並正確選用能大幅提升除錯效率。
$display
:標準顯示任務
- 特點
輸出後自動換行,每一筆輸出各占一行。 - 用途
最常用的基本除錯方式,可在任意時間點輸出一次訊息。
$write
:不換行的顯示
- 特點
輸出後不換行,可連續顯示字串。 - 用途
適合將多個值橫向排列顯示。 - 範例
$write("A=%d, ", a); $write("B=%d\n", b);
→ 輸出結果:A=5, B=10
$strobe
:模擬週期結束時輸出
- 特點
在當前模擬步驟的所有評估完成後,輸出最終確定的值。 - 用途
適合避免競爭條件(多個訊號同時變化)時使用。 - 範例
$strobe("Time=%0t, signal=%b", $time, sig);
→ 可確保輸出的是穩定值。
$monitor
:自動追蹤輸出
- 特點
指定的訊號只要有變化,就會自動輸出。 - 用途
適合持續監控訊號。 - 範例
$monitor("At %0t: a=%b, b=%b", $time, a, b);
→ 每當a
或b
改變時,自動輸出。
比較表整理
任務 | 換行 | 輸出時機 | 主要用途 |
---|---|---|---|
$display | 有 | 呼叫瞬間 | 基本日誌輸出 |
$write | 無 | 呼叫瞬間 | 橫向排列、日誌整形 |
$strobe | 有 | 模擬週期結束後 | 確認穩定值 |
$monitor | 有 | 訊號變化時自動輸出 | 訊號持續監視 |
使用技巧
- 基本選擇
$display
:可讀性高,初學者易於理解。 - 需要多值同列時選
$write
。 - 要確認穩定值時選
$strobe
。 - 要長期追蹤訊號時選
$monitor
。
4. 格式指定符與特殊顯示技巧
在 $display
與 $write
中,可以在字串中使用「格式指定符」,讓訊號或變數以指定格式輸出。由於其用法與 C 語言的 printf
類似,只要正確選用,就能大幅提升除錯效率。
基本格式指定符
指定符 | 內容 | 輸出範例 |
---|---|---|
%b | 二進位 (binary) | 1010 |
%d | 十進位 (decimal) | 10 |
%h | 十六進位 (hexadecimal) | A |
%o | 八進位 (octal) | 12 |
%c | 以 ASCII 字元顯示 | A |
%s | 字串 | Hello |
%t | 輸出模擬時間 | #100 |
%m | 輸出階層名稱(模組名稱) | top.u1.u2 |
實用範例
- 以多種格式顯示訊號
reg [7:0] data = 8'b10101010; $display("data = %b (bin), %d (dec), %h (hex)", data, data, data);
→ 輸出:data = 10101010 (bin), 170 (dec), AA (hex)
- 確認階層名稱
$display("目前的模組階層是 %m");
→ 輸出:目前的模組階層是 top.u1.counter
- 顯示模擬時間
$display("Time=%0t: clk=%b", $time, clk);
→ 輸出:Time=100: clk=1
特殊顯示技巧
- 零補齊與位數指定
%0d
可指定補零與位數,例如$display("Count=%04d", count);
→ 輸出:Count=0012
- 有號 / 無號區分
%d
視為有號整數,%u
視為無號整數,若輸出負數不如預期,請檢查指定符。 - 多行訊息
可用\n
換行:$display("Start of test\nSignal A=%b\nSignal B=%b", A, B);
注意事項
- 注意位元寬度:不同寬度的訊號,使用
%d
可能出現截斷或符號延伸。 - 未定義值 (X, Z):若訊號包含未知值,
%b
會顯示為x
或z
。
5. 實戰範例:在測試平台與模組中使用 $display
以下透過實際的 Verilog 程式碼範例,展示如何有效利用 $display
,從基礎測試平台到條件式除錯。
基礎範例:在測試平台中輸出
在測試平台加入 $display
,可於模擬過程中檢查運作狀態。
module tb_counter;
reg clk;
reg reset;
wire [3:0] count;
// DUT(Device Under Test)
counter uut (
.clk(clk),
.reset(reset),
.count(count)
);
// 產生時脈
initial begin
clk = 0;
forever #5 clk = ~clk; // 每5單位反轉一次
end
// 測試情境
initial begin
reset = 1;
#10 reset = 0;
#50 $finish;
end
// 顯示狀態
always @(posedge clk) begin
$display("Time=%0t | reset=%b | count=%d", $time, reset, count);
end
endmodule
在此範例中,每逢時脈上升沿,會輸出 reset
與 count
的值。這讓工程師除了檢視波形外,也能透過文字日誌追蹤行為。
條件式輸出範例
若搭配 if
語句,可以僅在特定條件成立時輸出。
always @(posedge clk) begin
if (count == 4'd10) begin
$display("計數器已達 10 (Time=%0t)", $time);
end
end
→ 可避免冗長日誌,只保留關鍵事件。
除錯訊息
在調查設計錯誤時,能即時偵測「異常狀態」。
always @(posedge clk) begin
if (count > 4'd12) begin
$display("WARNING: count overflow detected! Time=%0t, value=%d", $time, count);
end
end
→ 可快速發現設計問題或非預期行為。
同時監控多個訊號
當需要輸出多個訊號時,將其集中於一行能提升可讀性。
$display("Time=%0t | clk=%b | reset=%b | A=%h | B=%h | SUM=%h",
$time, clk, reset, A, B, SUM);

實戰重點整理
- 在測試平台中顯示執行進度
- 利用條件判斷縮小輸出範圍
- 加入警告訊息偵測異常
- 將多個訊號整合在單行輸出
6. 顯示控制的應用(像素/文字/影像顯示)
前面介紹的 $display
,主要用於模擬日誌與除錯訊息的「文字顯示」。
另一方面,Verilog 也廣泛應用於「顯示控制」(如 LCD、VGA、HDMI 輸出)。以下簡單介紹如何在硬體層面進行畫面顯示。
顯示控制的基本概念
要在螢幕上顯示文字或影像,不能使用 $display
,而是要產生視訊訊號。典型控制訊號如下:
- HSYNC(水平同步訊號):表示每一行的邊界。
- VSYNC(垂直同步訊號):表示每一個畫面的邊界。
- RGB 資料:每個像素的顏色(例如 8bit × 3 = 24bit 色彩)。
在 Verilog 中,這些訊號會透過計數器或狀態機控制,依時序輸出,進而實現「畫面顯示」。
範例1:顯示彩條
最基礎的範例是輸出彩條:
always @(posedge clk) begin
if (h_counter < 100) rgb <= 24'hFF0000; // 紅色
else if (h_counter < 200) rgb <= 24'h00FF00; // 綠色
else if (h_counter < 300) rgb <= 24'h0000FF; // 藍色
else rgb <= 24'h000000; // 黑色
end
→ 畫面會呈現水平排列的紅、綠、藍彩條。
範例2:文字顯示
文字顯示需要字型 ROM,將每個字元的點陣轉換為像素輸出。
// 依照 'A' 的字型點陣輸出
if (font_rom[char_code][y][x] == 1'b1)
rgb <= 24'hFFFFFF; // 白色
else
rgb <= 24'h000000; // 黑色背景
→ 可在畫面上繪製特定字元(如「A」)。
範例3:影像顯示
顯示影像時,需預先將位圖資料存入 ROM 或外部記憶體,再轉換為像素輸出。
rgb <= image_rom[addr]; // 從 ROM 取出顏色資料
在 FPGA 的嵌入式系統中,這種方法常用於顯示圖示或 Logo。
與除錯用 $display
的差異
$display
:文字輸出(僅模擬用)- 顯示控制:視訊訊號產生(可於硬體實作)
兩者用途完全不同,但常被初學者混淆。
- 「模擬中檢查運作」 → 使用
$display
- 「FPGA 輸出到螢幕」 → 設計視訊訊號控制電路
應用延伸
- 學習用 FPGA 板常使用七段顯示器或小型 LCD。
- 進一步可實作VGA/HDMI 輸出,應用於遊戲或 GUI。
- 若同時掌握
$display
與顯示控制,能在模擬與實機中靈活處理「顯示」問題。
7. 根據應用場景的使用方式與技巧
在 Verilog 中,「顯示」可分為兩種:模擬用的 $display
系統任務 與 硬體上的顯示控制。依場景正確選用,能提升開發與除錯效率。
模擬中的應用
- 以
$display
作為除錯日誌- 輸出重要變數或訊號,確認設計是否正確。
- 特別適合檢查「特定條件」或「計數器到達點」。
- 避免過量輸出
- 若每個時脈都輸出,日誌會爆量。建議加條件。
- 例如:
if (state == ERROR) $display("錯誤發生 at %0t", $time);
- 搭配其他系統任務
$monitor
→ 持續監視訊號$strobe
→ 輸出穩定值$write
→ 排版整齊的單行輸出
實機顯示控制的應用
- 七段顯示器學習
- FPGA 入門常用計數器數值顯示。
- 搭配
$display
模擬,可雙重驗證。
- LCD / VGA 顯示
- 透過字型 ROM 或影像 ROM 顯示文字與影像。
- 可與
$display
搭配,用於驗證訊號正確性。
- 除錯疊加層
- 將「計數值」「座標」「訊息」疊加在影像上。
- FPGA 開發常利用「畫面」作為除錯工具。
實務技巧
- 注意「模擬 → 實機」的流程
先用$display
確認,再實作顯示控制。 - 結合日誌與波形
$display
適合檢查事件時刻,波形適合檢查細節轉換。 - 團隊開發時統一訊息格式
如加前綴或時間,方便多人解析日誌。
小結
$display
:模擬用觀察工具- 顯示控制:硬體實現的輸出方式
- 兩者結合,能大幅提升開發效率
8. FAQ(常見問題與回答)
Q1. $display
與 $monitor
有何不同?
A. $display
是「呼叫當下只輸出一次」,而 $monitor
則是在指定訊號發生變化時「自動持續輸出」。
- 單次除錯 →
$display
- 持續監控 →
$monitor
Q2. 什麼時候需要使用 $strobe
?
A. $strobe
會在模擬週期結束時輸出,確保顯示的是「最終穩定值」。
例如在時脈上升沿後有多個訊號同時變化時,$display
可能輸出暫時值,此時用 $strobe
能得到穩定結果。
Q3. 格式指定符 %m
有什麼用途?
A. %m
可輸出當前模組階層名稱。在大型設計中,可快速確認訊息來自哪個階層。
$display("目前模組: %m");
輸出範例:
目前模組: top.u1.counter
Q4. 如果寫了太多 $display
,日誌變得非常龐大怎麼辦?
A. 可採取以下方法:
- 使用
if
條件限制輸出 - 只輸出錯誤或關鍵事件
- 用
$monitor
監控必要訊號 - 將輸出導入檔案,再過濾分析
Q5. $display
可以在合成(FPGA/ASIC)中使用嗎?
A. 不行。$display
只在模擬環境下有效,合成工具會忽略它,無法用於實機。
若要在實機輸出,需要設計「七段顯示器」「LCD」「VGA 控制電路」等。
Q6. 如果要在實機顯示文字或影像,該怎麼做?
A. 必須產生視訊訊號,而不是使用 $display
。
- 七段顯示器 → 用於數字或簡單字元
- VGA/LCD → 產生 HSYNC、VSYNC、RGB 訊號
- 文字 → 透過字型 ROM 轉換為像素
- 影像 → 將位圖存入 ROM 或外部記憶體並輸出像素
9. 總結與下一步
本文總結
本文以 Verilog 的「display」為主題,從基礎到進階完整解說。重點如下:
$display
的基礎- 在模擬中輸出訊號與變數,類似 C 語言的
printf
。
- 在模擬中輸出訊號與變數,類似 C 語言的
- 與其他任務的比較
$write
→ 不換行輸出$strobe
→ 輸出穩定值$monitor
→ 自動監控訊號
- 格式指定符的應用
- 使用
%b
、%d
、%h
、%m
、%t
等,提升日誌可讀性。
- 使用
- 實戰範例
- 在測試平台中輸出進度
- 搭配條件判斷提升除錯效率
- 顯示控制的應用
$display
僅限模擬,但可在 FPGA 上實作 HSYNC、VSYNC、RGB 以輸出文字或影像。- 從七段顯示器到 VGA/HDMI,皆可逐步延伸。
下一步
- 學習 SystemVerilog
→ SystemVerilog 提供更進階的除錯工具(如 assertion、加強版$display
)。 - 結合波形檢視
→ 將$display
輸出與波形檢視結合,可從數值與時序兩面向分析。 - 實機顯示專案
→ 在 FPGA 上嘗試七段顯示器或 LCD 專案,體驗「模擬輸出」與「實機顯示」的差異。 - 團隊開發應用
→ 統一$display
日誌格式,方便多人協作分析。
結語
$display
不只是單純的「文字輸出」,更是強大的模擬除錯工具。若再進一步學習顯示控制,還能利用 FPGA 將圖形實際輸出到螢幕。
希望本文能幫助學習 Verilog 的讀者,掌握「模擬除錯」與「實機顯示」的完整技巧。