JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

從邏輯圖到 Verilog

工程師不會一個閘一個閘地畫出現代晶片——單是一個區塊就能容納數十億個電晶體,遠遠超出任何筆或電路圖所能排布的極限。他們改用文字來描述硬體,再讓工具把圖畫出來。在本指南裡,你會認識 Verilog 這門負責描述的語言,以及那個讓每個新手都栽跟頭的關鍵觀念:它不是一門程式語言。把這個觀念想通,其餘的便會水到渠成。

為什麼要用文字描述硬體?

想像一下,要畫出一座城市,得親手擺好每一塊磚。當一個設計超過幾千個閘之後,逐個閘去畫的電路圖就是這種感覺——而真正的晶片有數十億個閘。畫到某個程度,畫圖這件事就再也撐不下去了。你需要一種辦法,把*你想要什麼*說清楚,再讓機器去算每一塊磚。

這正是 HDL(硬體描述語言)的用武之地。你寫下一段精煉的文字描述——「這個區塊把兩個 8 位元數相加」「那個區塊在兩路輸入之間切換」——再由合成工具把你的話變成一張真正的閘級網路。文字才是真理之源;電路圖成了工具*替*你畫出來的東西,而不是你*親手*去畫的東西。

HDL 不是程式語言

這就是那個讓每個新手都栽跟頭的觀念。在軟體裡,程式碼是一行接一行執行的。而在 Verilog 這樣的 HDL 裡,每一行描述的是同時存在的硬體——更像一支管弦樂團裡各個聲部,而不像食譜裡的一步步操作。寫下 assign y = a & b; 並不是做一次「及」運算;它鋪下的是一根永久的導線,時時刻刻都在算這個結果。

module and_gate(input a, b, output y);
  assign y = a & b;   // a permanent wire: y is ALWAYS (a AND b)
endmodule
一個二輸入「及」閘。module 為一塊硬體命名;連接埠就是它的接腳。

這一點一旦想通,你的 assign 敘述的先後順序基本就不再重要了。兩行 assign 描述的是兩根導線;先寫哪一行都沒差別,因為兩根線是同時通電的。這正是「描述硬體」與「寫程式」之間最深的區別——也是值得從第一天就養成的習慣。

你的第一個模組:一個閘

一個 Verilog 設計是由一個個模組搭起來的。模組就是一個貼了標籤的硬體盒子:它有一個名字、一組連接埠(也就是它的接腳,標著 input 或 output),還有一段說明接腳之間關係的主體。你把模組拼接起來的方式,就像把晶片插到電路板上——小盒子裝進大盒子裡。

module inverter(input  a,      // one pin in
                output y);     // one pin out
  assign y = ~a;               // y is always NOT a
endmodule
一個反相器(「非」閘)。~ 把這一位元取反;y 永遠跟著 a 翻轉。

把它讀成對一個零件的描述,而不是一連串動作:「這裡有個叫 inverter 的盒子;有一個進來的接腳 a 和一個出去的接腳 y;y 永遠是 a 的反面。」一通電,它就保持這個關係——沒有哪一行會「執行」。你將來會用到的每一個閘(及、或、非、互斥或)都只差一個運算子和一句 assign。

導線、訊號與匯流排

在模組內部、模組之間,數值都在導線上傳輸。一根導線只承載一個位元——一個 0 或一個 1。但你很少只搬一個位元;一個 8 位元數、一種顏色、一個位址,都需要好幾根導線綁在一起。這一捆就叫匯流排,在 Verilog 裡你用方括號寫出它的位元寬度。

wire        ready;        // 1 bit
wire [7:0]  data;         // an 8-bit bus: data[7] down to data[0]
wire [7:0]  sum;          // an 8-bit bus carrying the result of a + b
assign      sum = a + b;  // (a and b are 8-bit wires declared elsewhere)
[7:0] 的意思是「8 根線,從 7 編到 0」——一條排線,八股線芯。

把匯流排想像成一條排線:許多股線芯並排黏在一起,作為一個有名字的整體一起移動。data[0] 是最低位那一股,data[7] 是最高位那一股。位元寬度不是裝飾——它是實打實的物理量。一個存放 data[7:0] 的暫存器就是八個正反器那麼寬,而更寬的匯流排,字面意義上就是晶片上更多的金屬線。

行為級與結構級

描述同一塊硬體有兩種寫法,好的設計者能在兩者之間自如切換。結構級是由下而上的:你點出各個零件,再親手把它們連起來,像一張裝配圖。行為級是由上而下的:你說出*你想要的行為*,讓合成去想出該用哪些閘。同一顆晶片,兩種高度的描述。

拿一個 2 選 1 多工器來說——它是一個開關,根據一根選擇線 sel 來挑選輸入 a 還是輸入 b。用行為級的寫法,你只要說出這個選擇,再讓工具去把它搭出來。

module mux2(input a, b, sel, output y);
  assign y = sel ? b : a;   // sel=1 -> y=b, sel=0 -> y=a
endmodule
一個 2 選 1 多工器,行為級寫法。你描述的是「選擇」,而不是那些閘。

*同一個*多工器的結構級版本,會把那些閘一個個寫出來——一個反相器、兩個「及」閘、一個「或」閘——再一股一股地連起來。兩種描述合成出來的是同一套硬體。這給我們的啟示是:從行為級起步,先描述意圖,只有在你需要對具體用哪些閘做精確控制時,才下沉到結構級。先站在高處;只在划得來的地方才放大細看。