1. 前言
Verilog(韋理ログ)作為一種硬體描述語言,被廣泛應用於FPGA與ASIC等電路設計,是不可或缺的工具。要利用Verilog進行高效率的設計,對陣列的理解極為重要。
透過陣列,可以更簡潔直觀地處理資料集合,並提升電路描述的可讀性與維護性。特別是在將多個訊號分組,或是表示RAM等記憶體結構時,陣列的效果非常顯著。
本文將以「Verilog 陣列」為核心關鍵字,從基礎的陣列定義方式,到實務上有用的應用技巧進行全面解析。同時涵蓋陣列的種類、SystemVerilog的擴充功能,以及常見錯誤與FAQ,幫助讀者建立完整的理解。
文章內容淺顯易懂,並搭配實用的程式範例,即使是初學者也能輕鬆上手。建議閱讀到最後,確保完整掌握。
2. Verilog的基本資料型態
在Verilog中使用陣列之前,必須先理解基本資料型態。Verilog提供了數種主要型態,用來處理電路設計中必須的邏輯訊號。
reg型與wire型的差異
Verilog中最常用的型態是「reg(暫存器)」與「wire(導線)」。需要根據邏輯訊號的行為來選擇適當型態。
- wire型
wire用作連接線,需由其他模組或電路驅動,必須透過assign
語句進行賦值,適合組合邏輯電路的輸出。例:
wire a;
assign a = b & c;
- reg型
reg作為暫存變數,能在程序區塊(如always
)中賦值,用於表示鎖存器或正反器。例:
reg q;
always @(posedge clk) begin
q <= d;
end
可用於陣列的資料型態
在Verilog中,陣列通常以reg
型態定義,但wire
在部分情境下也可使用。不過,早期的Verilog不支援多維陣列,這一點在SystemVerilog中獲得了改善。
以下為簡單的陣列宣告範例:
reg [7:0] data_array [0:15]; // 儲存16筆8位元資料的陣列
掌握這些基本概念能避免在宣告或使用陣列時的混淆。特別是reg與wire的誤用,容易導致模擬錯誤或綜合錯誤。
3. 陣列的基本概念
在Verilog中,當需要一次處理多個相同型態的訊號時,就會使用「陣列(array)」。利用陣列能夠更好地整理訊號,並提升程式碼的可讀性與可重用性。
陣列的宣告方式
Verilog主要支援一維陣列,基本語法如下:
reg [位元寬度] 陣列名稱 [索引範圍];
具體範例:
reg [7:0] data_array [0:15]; // 儲存16筆8位元資料的陣列
此範例中,data_array
擁有0到15共16個元素,每個元素皆為8位元(1位元組)。
陣列元素的存取方式
陣列的每個元素可透過索引號碼存取,與C語言相同,索引從0開始。
data_array[0] = 8'hFF; // 將十六進位FF指定給第1個元素
data_array[1] = 8'd12; // 將十進位12指定給第2個元素
同時,也可在always
區塊中使用迴圈進行初始化或操作。
integer i;
always @(posedge clk) begin
for (i = 0; i < 16; i = i + 1) begin
data_array[i] <= 8'd0;
end
end
4. 多維陣列的活用
在Verilog中,陣列能簡化設計並整理電路結構,而透過多維陣列,則可更有效率地處理複雜的資料結構。
需要注意的是,早期的Verilog(IEEE 1364-1995)並不支援多維陣列,而Verilog 2001之後才正式引入。若要進行更靈活的陣列操作,建議使用SystemVerilog。
多維陣列的宣告
自Verilog 2001起,可以對單一變數指定多個索引來定義多維陣列。基本語法如下:
reg [7:0] matrix [0:3][0:3]; // 定義4×4的8位元矩陣
此宣告使matrix
成為一個擁有16個8位元元素的二維陣列。
元素的存取與賦值
在多維陣列中,也可透過索引存取特定元素並進行賦值:
matrix[0][0] = 8'hA5;
matrix[2][3] = 8'd255;
搭配for迴圈
透過巢狀for迴圈,可以靈活操作多維陣列。以下範例為初始化操作:
integer i, j;
always @(posedge clk) begin
for (i = 0; i < 4; i = i + 1) begin
for (j = 0; j < 4; j = j + 1) begin
matrix[i][j] <= 8'd0;
end
end
end
多維陣列的應用範例
- 矩陣運算與濾波處理:適用於需要複雜資料結構的電路設計。
- 影像處理或數位訊號處理(DSP):可用於逐像素資料操作。
- ROM/RAM區塊化,以及位址與資料配對整理。
注意事項與限制
- 使用多維陣列時,需確認綜合工具的支援情況,部分工具可能不完全支援。
- 與模組實例化或介面結合時,可能產生額外限制。
- 掌握與SystemVerilog的差異,有助於避免相容性問題(後續章節將詳述)。

5. 使用陣列建構記憶體模型
在Verilog中,可以利用陣列建構簡易的記憶體模型。這樣能夠簡潔且靈活地描述RAM或ROM等儲存電路,並用於模擬與設計。
其中,一維陣列的記憶體模型特別常見,應用於CPU設計或通訊系統。
記憶體模型的基本語法
以下範例表示一個每字32位元、1024個位址(0〜1023)的簡單RAM:
reg [31:0] memory [0:1023]; // 32位元 × 1024字的記憶體
此宣告建立了一個名為memory
的陣列,每個索引(位址)可存放32位元資料。
記憶體的寫入與讀出
透過陣列來進行記憶體的讀寫操作,可如下撰寫:
// 寫入
always @(posedge clk) begin
if (we) begin
memory[addr] <= data_in;
end
end
// 讀出
assign data_out = memory[addr];
重點說明:
- 寫入於
posedge clk
下同步執行,並受we
(write enable)控制。 - 讀出通常以組合邏輯方式(
assign
)實現,屬於非同步讀取。
記憶體初始化方式
在測試平台或初始狀態設定中,可以使用initial
區塊初始化陣列:
integer i;
initial begin
for (i = 0; i < 1024; i = i + 1) begin
memory[i] = 32'd0;
end
end
此外,利用$readmemh
或$readmemb
可從外部檔案讀入初始值:
initial begin
$readmemh("rom_init.hex", memory); // 以16進位格式初始化
end
實務應用範例
- CPU或微控制器的暫存器檔案
- FPGA內部區塊RAM(BRAM)的行為模擬
- 快取記憶體(Cache)的動作驗證
- ROM資料的讀取模擬
注意事項
- 當陣列規模過大時,會增加模擬時間與綜合資源。
- 讀取方式(同步或非同步)需依設計規格與工具支援審慎選擇。
- 若考慮綜合,應遵循記憶體推論規則,以確保合成工具能正確識別為實體RAM。
6. SystemVerilog中的陣列擴充
在Verilog 2001以前,陣列功能有限,設計常顯得繁瑣。為此,後繼的SystemVerilog大幅擴充了陣列功能,提供更靈活且強大的描述方式。
本章將介紹SystemVerilog中的三種代表性陣列:「動態陣列」、「關聯陣列」、「佇列(Queue)」,並說明其特點與應用情境。
動態陣列(Dynamic Arrays)
特點
- 可在執行時改變大小。
- 適合大小不固定或需彈性變動的資料集合。
宣告與使用範例
int dyn_array[]; // 宣告動態陣列
dyn_array = new[10]; // 初始化為10個元素
dyn_array[0] = 100;
應用情境
- 測試平台中暫存資料。
- 管理大小可變的緩衝區。
關聯陣列(Associative Arrays)
特點
- 索引可使用任意值(整數、字串等)。
- 可扮演雜湊表(hash table)的角色。
宣告與使用範例
int assoc_array[string]; // 使用字串作為索引的關聯陣列
assoc_array["id_001"] = 42;
應用情境
- 儲存不同參數的設定值。
- 以ID或名稱檢索資料。
佇列(Queues)
特點
- 接近FIFO(先進先出)結構。
- 元素可動態新增或刪除,適合變動頻繁的資料序列。
宣告與使用範例
int queue_array[$]; // 宣告佇列型陣列
queue_array.push_back(10); // 在尾端新增
queue_array.push_front(5); // 在前端新增
int val = queue_array.pop_front(); // 從前端取出
應用情境
- 資料暫存(FIFO緩衝區)。
- 事件處理或交易管理。
比較與使用策略
陣列類型 | 大小變更 | 索引型態 | 適用情境 |
---|---|---|---|
動態陣列 | 可變 | 整數 | 大小不固定時 |
關聯陣列 | 可變 | 任意(int, string等) | 需要雜湊結構時 |
佇列 | 可變 | 自動(前端/尾端) | 頻繁新增刪除資料時 |
注意事項
- 這些擴充功能屬於SystemVerilog,在Verilog中不可用。
- 可綜合範圍依工具而異,但多數情況僅用於測試平台。
- 若目標為FPGA或ASIC,必須事先確認是否支援。
7. 陣列操作的最佳實踐
在Verilog或SystemVerilog中使用陣列時,若能兼顧效率與可讀性,將直接影響硬體設計品質。本章將介紹一些安全且有效的使用技巧。
透過註解與命名明確表達意圖
雖然陣列具備高可擴展性,但元素代表意義可能不直觀,因此建議:
- 陣列名稱使用具意義的單詞:
reg [7:0] sensor_data [0:7];
- 透過註解標明用途與單位:
// 儲存來自8個感測器的8位元資料
reg [7:0] sensor_data [0:7];
for迴圈需注意邊界條件
使用for
迴圈進行批次操作時,必須正確設定索引範圍:
- 若上限錯誤 → 可能造成陣列越界。
- 注意
<
與<=
的差別。
範例:
integer i;
always @(posedge clk) begin
for (i = 0; i < 8; i = i + 1) begin
sensor_data[i] <= 8'd0;
end
end
明確初始化
若陣列未初始化就使用,可能影響模擬結果。尤其在RAM或暫存器組的情境,建議明確初始化:
initial begin
for (i = 0; i < 256; i = i + 1)
mem[i] = 32'd0;
end
在SystemVerilog中,也可透過建構子或foreach
迴圈更簡潔地初始化。
設計具備可重用性的模組
利用陣列可讓設計更具彈性,例如元素數量或位元寬度變化時仍能適應:
- 使用
parameter
控制陣列大小:
parameter DEPTH = 16;
reg [7:0] buffer [0:DEPTH-1];
- 允許從外部指定大小,可提升模組的可重用性。
考慮可綜合性
設計時需留意合成工具支援:
- Verilog的一維
reg
陣列:一般可安全綜合。 - SystemVerilog的動態/關聯/佇列:不可綜合(僅限模擬)。
陣列與模組分割的取捨
雖然陣列可減少程式碼量,但過於複雜時,建議以模組分割設計:
- 處理內容單純且數量不大 → 陣列 + for迴圈。
- 功能差異大或規模龐大 → 採模組化與階層設計。
8. 常見問題(FAQ)
在使用Verilog或SystemVerilog的陣列時,初學者到中階工程師都常會遇到一些共通的問題。以下整理了有關「Verilog 陣列」的三個常見問題,並結合實務經驗加以解釋。
Q1. 在Verilog中使用多維陣列會出錯,為什麼?
A1.
在Verilog 1995或Verilog 2001之前的版本,多維陣列要嘛不支援,要嘛僅在有限情況下支援,因此會出現編譯錯誤。
例如,下列程式在Verilog 1995會發生錯誤:
reg [7:0] matrix [0:3][0:3]; // 僅Verilog 2001之後支援
解決方式:
- 確認所使用的工具是否支援Verilog 2001或更新版本。
- 若受限於工具,可改以一維陣列模擬,透過運算公式存取索引:
reg [7:0] matrix_1d [0:15];
// 存取時以 (i*4 + j) 代表二維索引
Q2. 若用陣列描述RAM,是否能在實際硬體中運作?
A2.
可以,多數綜合工具已經支援使用Verilog陣列來描述RAM。例如:
reg [31:0] mem [0:255]; // 32位元 × 256字的RAM
但需要注意:
- 綜合工具必須能推論為Block RAM,條件需符合該工具的模板。
- 讀寫方式(同步/非同步)若不符合規範,可能無法正確映射為實體RAM。
建議:
- 參考各晶片廠商的「記憶體推論指南」。
- 若模擬與實機行為不同,建議檢查Log並依照官方模板修改。
Q3. SystemVerilog的動態陣列、關聯陣列、佇列能否在實機中使用?
A3.
基本上,動態陣列、關聯陣列、佇列都不可綜合(僅限模擬)。這些結構雖然靈活,但無法直接映射為硬體電路。
因此,常見用途為:
- 測試平台的暫存資料。
- 驗證環境中的隨機化、scoreboard實作。
- 描述複雜交易或事件。
實作上的提醒:
- 若設計中使用動態/關聯陣列,綜合工具會忽略或直接報錯。
- 要實際部署於硬體,必須改寫為固定長度的一維
reg
陣列。
9. 總結
本文以「Verilog 陣列」為主題,從基礎到應用進行全面解析。正確使用陣列,能有效提升設計效率、程式可讀性、維護性。
本文回顧重點
- 理解Verilog基本資料型態(reg與wire),可避免陣列使用錯誤。
- 一維陣列是資料集合與記憶體模型的重要結構。
- 多維陣列在Verilog 2001後支援,可處理矩陣等進階結構。
- 使用SystemVerilog可引入動態陣列、關聯陣列、佇列(主要用於模擬)。
- 遵循最佳實踐(初始化、命名、可重用性、合成考量),能撰寫更高品質程式。
實務上的提示
雖然陣列非常方便,但並非所有情況都適合用陣列。若要考慮綜合與協作,需配合設計規範與團隊風格。
SystemVerilog的進階陣列功能,若將其定位於模擬用途,才能發揮最大效益。根據目標靈活切換,才是優秀設計者的條件。
延伸閱讀建議
若已掌握本文內容,建議進一步學習以下主題:
- 利用
generate
語句進行動態電路生成。 - 結合
interface
與陣列的匯流排設計。 - 利用陣列最佳化FIFO、環形緩衝區、ROM設計。
熟練掌握陣列,是成為專業Verilog設計工程師的重要第一步。