National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 72 24°C PM2.5 13
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 14

讀懂 Verilog

工程師怎麼描述電路:把接線圖寫成文字
Interaction 30 minute(s)

Learning Objectives

  • 說明硬體描述語言與一般程式的差別:每一行同時存在
  • 讀懂 module、input、output、wire、閘實例與 assign
  • 讀懂 always @(posedge clk)、非阻塞賦值與 reg,分辨它們變成正反器還是組合電路
  • 認得計數器與有限狀態機的固定寫法,知道合成與模擬的差別

工程師不會一條一條接線

前面的課你一條一條接過線。十幾個閘還可以,一顆真實處理器的閘多到不可能用手接,也沒辦法檢查。工程師改成用文字描述電路,再交給工具轉成閘,這種語言叫硬體描述語言(hardware description language,HDL)。

Verilog 是其中之一,1983 到 1984 年間在 Gateway Design Automation 公司由 Prabhu Goel、Phil Moorby 與 Chi-Lai Huang 開發,後來成為 IEEE 1364 標準(1995、2001、2005 年版)。2009 年它併入 SystemVerilog 的標準 IEEE 1800,目前最新版是 IEEE 1800-2023。另一個常見的硬體描述語言是 VHDL。這一課只教讀,因為你之後看到別人的設計、或請 AI 助教產生 Verilog 時,要看得懂它描述的是什麼電路。

它看起來像程式,但有一個最重要的差別:

一般程式描述「依序做什麼」;Verilog 描述「有什麼東西、怎麼接」。每一行都同時存在。

一塊電路叫做 module。最短的例子是半加器,它只有兩個閘:

module half_adder(
  input  wire a,
  input  wire b,
  output wire sum,
  output wire carry
);
  assign sum   = a ^ b;
  assign carry = a & b;
endmodule

assign 不是「執行一次賦值」,而是「sum 這條線永遠接著 a ^ b 的結果」。把這兩行對調,電路完全一樣。

閘也可以直接放:and g2 (t0, ns, d0); 的意思是放一個 AND 閘,名字叫 g2,第一個是輸出,後面是輸入。元件之間的內部連線用 wire 宣告。下面的多工器兩種寫法都有。

互動練習:一行程式對應一個閘

按任何一行,電路圖標出它對應的元件與線;按圖上的元件,左邊標出對應的行。還沒填的空格,對應的元件是虛線,也還沒有接上電路。

always、reg 與非阻塞賦值

有記憶的電路要用 always:

always @(posedge clk) begin
  q1 <= d;
  q2 <= q1;
end

@(posedge clk) 是「每次 clk 上升緣」,所以裡面被指定的東西會變成 D 正反器。左邊被指定的變數要宣告成 reg。

這裡的 <= 是非阻塞賦值(nonblocking assignment):上升緣到的時候,所有右邊先讀舊值,這一拍結束才一起更新。這正好就是正反器的行為:大家同時取樣、同時改變。所以 q2 拿到的是舊的 q1,兩個正反器串起來,q2 比 q1 晚一拍。

如果寫成 =(阻塞賦值,blocking assignment),就是一行一行立刻改,下一行讀到的是新值:q1 = d; q2 = q1; 的 q2 拿到的是 d,等於少了一級,只是兩個正反器存同一個值。

慣用的規則是:描述正反器的 always 用 <=,描述組合電路的 always 用 =。

reg 這個字會騙人。它只表示「這個變數在 always 裡被指定」,不代表一定是暫存器。always @(*) 裡被指定的 reg 是組合電路的輸出。判斷方法是看 always 的條件有沒有 posedge。

用 Python 看兩種賦值的差別

這不是 Verilog,是把兩種賦值的語意用 Python 寫出來。看 q2 的值是怎麼來的。

互動練習:非阻塞賦值接出兩級正反器

這是兩級移位暫存器。選錯選項時,下面會把「照那樣寫」接成電路真的模擬一次,和目標並排比較。

計數器與有限狀態機的固定寫法

第 8 課接過計數器,2 位元的版本寫成 Verilog 只有幾行。[1:0] 是 2 個位元,2'b00 是 2 位元、二進位、值是 00,posedge rst 表示重設不用等時脈:

module counter2(
  input  wire clk,
  input  wire rst,
  output reg  [1:0] count
);
  always @(posedge clk or posedge rst) begin
    if (rst) count <= 2'b00;
    else     count <= count + 2'b01;
  end
endmodule

count + 2'b01 這一行不用自己想 XOR 怎麼接,工具會轉成加法電路。這就是用 HDL 的理由:寫要做什麼,細節交給工具,所以你讀的時候要能反過來想「這大概是什麼電路」。

有限狀態機通常寫成兩段,正好對應第 9 課的三塊電路:always @(*) 裡用 case 寫次態邏輯(就是狀態表),always @(posedge clk ...) 寫狀態暫存器,assign 寫輸出邏輯。

互動練習:把第 9 課的紅綠燈讀一遍

這個紅綠燈的電路你在第 9 課接過。這裡下方的電路是手動化簡後的對照:工具實際產生的閘不一定長得一樣,但行為要相同。

模擬、合成與 SystemVerilog

同一段 Verilog 有兩種用法:

  • 模擬(simulation):在電腦上算出每個訊號隨時間的變化,用來檢查設計。測試用的程式也用 Verilog 寫,裡面可以有 #10(等 10 個時間單位)、印訊息這些動作。
  • 合成(synthesis):把描述轉成實際的閘與正反器。只有一部分的語法能合成:#10 這種延遲,合成工具會忽略,因為閘的延遲是製程決定的,不是你寫了就算。

合成的結果可以放到 FPGA(出廠之後還能重新設定的可程式晶片),或做成 ASIC(為特定用途製造、電路固定的晶片)。

一個常見的陷阱:模擬結果正確,不代表合成出來的電路一樣。例如阻塞賦值的順序、case 沒有寫全,都可能讓模擬與硬體不一致。所以上面那些慣用規則不是風格問題。

現況:Verilog 的標準 2009 年已經併入 SystemVerilog,SystemVerilog 廣泛用於晶片設計與驗證。它是 Verilog 的延伸,舊的寫法大多還能用,並補上比較不會騙人的語法:logic 取代 reg、always_ff 明說這是正反器、always_comb 明說這是組合電路:

always_ff @(posedge clk) begin
  q1 <= d;
  q2 <= q1;
end

這一課的 Verilog 範例用的是 IEEE 1364-2001 的標準語法,電路是依程式手動對照,不是工具編譯的結果。

確認一下

1.

assign y = a & b; 和 assign z = y | c; 兩行對調,電路會怎樣?

2.

nand g5 (x, a, b); 這一行,哪一個是輸出?

3.

reg y; 在 always @(*) 裡被指定,always 的條件沒有 posedge。y 是什麼?

4.

always @(posedge clk) 裡面寫 q2 <= q1; 再寫 q1 <= d;(和前面的順序相反)。電路會怎樣?

5.

always @(posedge clk) 裡面寫 q1 = d; 再寫 q2 = q1;,d 的變化會怎麼傳到 q2?

6.

程式裡寫了 #10 y = a;,模擬時 y 晚 10 個時間單位才變。合成之後的電路呢?

第 1 次作答

重點整理

  • HDL 描述硬體,不是依序執行的程式:每一行同時存在,順序不影響電路。
  • module 是一塊電路;input、output 是接腳;wire 是線;閘實例的第一個接腳是輸出;assign 是永遠成立的接線。
  • always @(posedge clk) 產生正反器,裡面用 <=;always @(*) 產生組合電路,裡面用 =。reg 不等於暫存器。
  • 有限狀態機的固定寫法:case 寫次態、posedge 寫暫存器、assign 寫輸出,一定要有重設。
  • 模擬檢查設計,合成產生閘;只有部分語法能合成。SystemVerilog 是 Verilog 的延伸,廣泛用於晶片設計與驗證。

這條軌道走到這裡,你從一個邏輯閘接到一顆簡單的 CPU,也看得懂工程師實際用的語言了。想繼續往下,可以學計算機組織(管線、快取),或是拿一塊 FPGA 開發板,把這些 Verilog 真的放進晶片。

這一課完成了!
看我的學習進度
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。