Verilog 中的 always
語句塊,這是行為級建模的核心結構之一,在 RTL 級設計中廣泛用于時序邏輯和組合邏輯的建模。
一、什么是 always
語句?
? 定義:
always
語句用于描述可綜合的硬件行為邏輯,表示一個**“事件驅動”的過程塊**,當敏感列表中某個信號發生變化時,always
塊會立即觸發執行。
二、基本語法格式
always @(sensitivity_list)begin// 過程性代碼end
sensitivity_list
是觸發該塊執行的信號列表。
三、分類:三種常見 always
使用方式
類型 | 敏感列表 | 用途 | 典型應用 |
---|---|---|---|
時序邏輯 | posedge clk / negedge rst_n | 同步邏輯 | 寄存器建模、狀態機 |
組合邏輯 | (*) 或所有組合信號列出 | 無時序行為 | 算術邏輯單元(ALU) |
異步邏輯 | posedge clk or negedge rst | 異步復位結構 | 上電初始化控制 |
四、時序邏輯建模(推薦使用方式)
4.1 同步復位寄存器建模:
always @(posedge clk) beginif (!rst_n)q <= 0;elseq <= d;
end
? 非阻塞賦值
<=
,確保“并行硬件”的表達。
4.2 異步復位建模:
always @(posedge clk or negedge rst_n) beginif (!rst_n)q <= 0;elseq <= d;
end
?
posedge clk or negedge rst_n
:表示rst_n
變化時立即響應。
五、組合邏輯建模
推薦使用 always @(*)
always @(*) begincase (sel)2'b00: y = a;2'b01: y = b;default: y = 0;endcase
end
? 使用
=
阻塞賦值。
? 確保對每個輸出都完全賦值,否則綜合工具會推斷出 latch(鎖存器)!
六、敏感列表詳解
? 常見寫法對比:
寫法 | 解釋 | 建議 |
---|---|---|
always @(a or b or c) | 顯式列出每個信號 | ? 可控但冗長 |
always @(*) | 隱式敏感列表,表示所有用到的組合信號 | ? 推薦用于組合邏輯 |
always @(posedge clk) | 上升沿觸發(時序邏輯) | ? 推薦用于寄存器 |
七、阻塞/非阻塞賦值回顧(重點)
場景 | 使用賦值類型 | 示例 |
---|---|---|
時序邏輯(同步時鐘) | 非阻塞 <= | q <= d; |
組合邏輯 | 阻塞 = | y = a + b; |
?? 錯誤示例:混用賦值類型
always @(posedge clk) begina = b; // ? 錯誤:阻塞賦值在時序邏輯中易引發競態c <= a; // 實際 c 得到的是舊值,不是當前周期的 b
end
八、綜合注意事項(總結)
誤用 | 影響 | 修正建議 |
---|---|---|
@(*) 中漏掉信號 | 可能漏更新,綜合錯誤 | 使用 @(*) 自動推導 |
混用 = 與 <= | 引起競態與不符合意圖 | 遵循賦值語義規則 |
不完全賦值 | 可能推斷 latch | 加默認路徑 / default 分支 |
變量多處被賦值 | 沖突或競態 | 避免變量在多個 always 中賦值 |
九、典型設計范式:分離時序與組合邏輯
// 狀態寄存器
always @(posedge clk or negedge rst_n)if (!rst_n) state <= IDLE;else state <= next_state;// 下一狀態邏輯
always @(*) begincase (state)IDLE: if (start) next_state = RUN;RUN: if (done) next_state = IDLE;default: next_state = IDLE;endcase
end
? 這是 FSM 設計的推薦結構:組合邏輯決定 next_state,時序邏輯更新 state。
十、仿真輔助結構(testbench 中的 always
)
always #5 clk = ~clk; // 每 5ns 翻轉一次
- 通常用于生成仿真用時鐘;
- 非綜合代碼,僅用于
initial
或 testbench。
十一、拓展:SystemVerilog 中的 always_ff
/ always_comb
類型 | SystemVerilog 替代 | 特點 |
---|---|---|
時序邏輯 | always_ff | 自動檢查敏感列表,防止誤用 |
組合邏輯 | always_comb | 自動推導敏感列表 |
? 更強語義檢查,更安全可維護,但需要 SystemVerilog 工具支持。
十二、實戰示例總結:組合 + 寄存器 + 狀態機
// 組合邏輯:計數器是否達到最大值
always @(*) begindone = (cnt == 15);
end// 時序邏輯:計數器累加
always @(posedge clk or negedge rst_n) beginif (!rst_n)cnt <= 0;else if (en)cnt <= cnt + 1;
end
小結
內容 | 核心要點 |
---|---|
語義 | always 塊是硬件中的過程行為 |
時序建模 | 使用 posedge clk + 非阻塞賦值 |
組合建模 | 使用 @(*) + 阻塞賦值,完整賦值 |
綜合約束 | 不可在綜合邏輯中使用 #延遲 等 |
推薦實踐 | 將時序邏輯與組合邏輯分離建模,提高可讀性與綜合效果 |