Synthesizable constructs, logic minimization, latch-free case / if, combinational loops, priority structures, tri-state buses and resource sharing — a self-study guide可合成語法、邏輯最小化、不產生閂鎖的 case / if、組合邏輯迴路、優先權結構、三態匯流排與資源共享 — 組合邏輯合成自學指南合成可能な構文、論理最小化、ラッチを生まない case / if、組合せループ、優先順位構造、トライステート・バス、リソース共有 — 組合せ論理合成の自学ガイド
The designer writes an HDL behavioral model (design entry) and checks it with functional simulation. Physical optimization and implementation then map it to a target technology, after which timing simulation verifies the implemented design against the original intent.設計者先寫出 HDL 行為模型(design entry),再以功能模擬檢查。接著由實體最佳化與實作把它映射到目標製程,最後以時序模擬驗證實作結果是否仍符合原始設計意圖。設計者はまず HDL の動作モデル(design entry)を書き、機能シミュレーションで確認する。続いて物理最適化と実装がそれをターゲット・テクノロジへマッピングし、最後にタイミング・シミュレーションで実装結果が当初の意図どおりかを検証する。
| Target目標製程ターゲット | Implementation steps實作步驟実装の手順 |
|---|---|
| PLD | Partition, map, interconnect分割、映射、連接分割・マッピング・配線 |
| FPGA / masked gate arrayFPGA / 光罩式閘陣列FPGA / マスク・ゲートアレイ | Map, place, route映射、佈局、繞線マッピング・配置・配線 |
| Standard cells標準單元スタンダードセル | Place, route佈局、繞線配置・配線 |
One test bench drives both the Verilog behavioral description and the gate-level description produced by synthesis. A stimulus generator feeds both, a response comparator compares their outputs, and a check signal flags mismatches. This is the post-synthesis check that the netlist behaves like the RTL.同一個測試平台(test bench)同時驅動 Verilog 行為描述與合成產生的閘層描述。激勵產生器把相同輸入餵給兩者,響應比較器比對兩邊的輸出,check 訊號則標示出不一致之處。這就是合成後用來確認 netlist 行為與 RTL 相同的檢查。一つのテストベンチが、Verilog の動作記述と合成で生成されたゲートレベル記述の両方を駆動する。刺激生成器が同じ入力を両者に与え、応答比較器が出力を突き合わせ、check 信号が不一致を知らせる。これが、ネットリストが RTL と同じ振る舞いをするかを確かめる合成後のチェックである。
Logic synthesis operates on Boolean equations and produces optimized combinational logic, in three stages:邏輯合成以布林方程式為操作對象,分三個階段產生最佳化後的組合邏輯:論理合成はブール式を対象に動作し、三つの段階を経て最適化された組合せ論理を生成する。
| Engine引擎エンジン | Input輸入入力 | Output輸出出力 |
|---|---|---|
| Translation轉譯変換 | Behavioral description行為描述動作記述 | Two-level logic functions兩層邏輯函數2 段の論理関数 |
| Optimization最佳化最適化 | Two-level functions兩層函數2 段の関数 | Optimized multi-level logic (technology independent)最佳化的多層邏輯(與製程無關)最適化された多段論理(テクノロジ非依存) |
| Mapping映射マッピング | Optimized logic + technology library最佳化後的邏輯 + 製程元件庫最適化された論理 + テクノロジ・ライブラリ | Technology implementation (cells)製程實作(cell)テクノロジ実装(セル) |
input, output, inout模組宣告;埠 input、output、inoutモジュール宣言、ポート input・output・inoutwire, tri, wand, wor, supply0, supply1連線型別:wire, tri, wand, wor, supply0, supply1ネット型:wire, tri, wand, wor, supply0, supply1reg, integer暫存型別:reg、integerレジスタ型:reg・integerbegin ... end, if / else, case, casex, casez, defaultbegin ... end、if / else、case, casex, casez, defaultbegin ... end・if / else・case, casex, casez, defaultfor loops, disable of a procedural blockfor 迴圈、對程序區塊使用 disablefor ループ、手続きブロックの disableassign ... deassign (PCA)assign ... deassign(程序性連續指定 PCA)assign ... deassign(手続き連続代入 PCA)task* and functiontask* 與 functiontask* と function* No timing or event control allowed inside a synthesizable task.* 可合成的 task 內不得出現時序控制或事件控制。* 合成可能な task の中では時間制御・イベント制御は使えない。
| Group類別分類 | Constructs語法構文 |
|---|---|
| Simulation control模擬控制シミュレーション制御 | initial, event, fork ... join, forever, while, wait, repeat, force ... release |
| Timing時序タイミング | Intra-assignment timing control, delay specifications, specify ... endspecify, $time指定式內部的時序控制、延遲設定、specify ... endspecify、$time代入内の時間制御、遅延指定、specify ... endspecify、$time |
| Switch level / strength開關層級/驅動強度スイッチレベル/駆動強度 | cmos, rcmos, nmos, pmos, rnmos, rpmos, tran, tranif0, tranif1, rtran, rtranif0, rtranif1, pullup, pulldown, weak0, weak1, strong0, strong1, pull0, pull1, small, medium, large, scalared, vectored |
| Other其他その他 | Case equality === / !==, defparam, global variables, a variable used as a bit select on the LHS, sequential UDP (primitive ... table with state), system tasks $keywordcase 等號 === / !==、defparam、全域變數、左側以變數做位元選取、含狀態的序向 UDP(primitive ... table)、系統任務 $keywordケース等価 === / !==、defparam、グローバル変数、左辺で変数によるビット選択、状態をもつ順序 UDP(primitive ... table)、システムタスク $keyword |
These lists are the lecture's "generally supported" view. Modern tools accept some items (e.g. while or repeat with a constant bound, variable bit select on the LHS), but for this course and its exam treat them as listed.這些清單是課堂上「一般支援」的觀點。現代工具其實接受其中一部分(例如界限為常數的 while 或 repeat、左側以變數做位元選取),但在本課程與考試中請依清單認定。これらの一覧は講義でいう「一般にサポートされる」範囲である。最近のツールは一部を受け付ける(上限が定数の while や repeat、左辺の変数ビット選択など)が、本講義と試験ではこの一覧どおりに扱うこと。
Problem: Classify each: (a) assign y = s ? a : b; (b) always @(a) #5 y = a; (c) if (a === 1'bx) (d) a function with a complete case (e) initial q = 0; (f) for (k = 0; k < 4; k = k + 1) (g) a task containing @(posedge clk).題目:判斷下列各項:(a) assign y = s ? a : b; (b) always @(a) #5 y = a; (c) if (a === 1'bx) (d) 具有完整 case 的 function (e) initial q = 0; (f) for (k = 0; k < 4; k = k + 1) (g) 內含 @(posedge clk) 的 task。問題:次のそれぞれを分類せよ。(a) assign y = s ? a : b; (b) always @(a) #5 y = a; (c) if (a === 1'bx) (d) 完全な case をもつ function (e) initial q = 0; (f) for (k = 0; k < 4; k = k + 1) (g) @(posedge clk) を含む task。
Synthesizable: (a), (d), (f). Not synthesizable: (b) delay control, (c) case equality === (x has no hardware meaning), (e) initial, (g) task with event control. For (b) most tools ignore the #5 with a warning, which creates a simulation/synthesis mismatch — still avoid it.可合成:(a)、(d)、(f)。不可合成:(b) 延遲控制、(c) case 等號 ===(x 在硬體上沒有對應意義)、(e) initial、(g) 含事件控制的 task。至於 (b),多數工具會忽略 #5 並發出警告,這會造成模擬與合成不一致 — 還是別寫。合成可能:(a)、(d)、(f)。合成不可:(b) 遅延制御、(c) ケース等価 ===(x にはハードウェア上の意味がない)、(e) initial、(g) イベント制御を含む task。(b) については多くのツールが警告つきで #5 を無視するが、それはシミュレーションと合成の不一致を生むので、やはり書かないこと。
Synthesis target: minimize area, delay or power.合成的目標:最小化面積、延遲或功耗。合成の目標は面積・遅延・電力の最小化である。
| Operation運算操作 | Before之前変形前 | After之後変形後 |
|---|---|---|
| Decomposition one function → new sub-functions分解 Decomposition 一個函數 → 新的子函數分解 Decomposition 一つの関数 → 新しい部分関数 | $F = abc + abd + a'c'd' + b'c'd'$ | $X = ab,\ Y = c + d$ $F = XY + X'Y'$ |
| Extraction common sub-expressions of several functions抽取 Extraction 多個函數的共同子運算式抽出 Extraction 複数の関数に共通する部分式 | $F = (a+b)cd + e$ $G = (a+b)e'$ $H = cde$ | $X = a+b,\ Y = cd$ $F = XY + e,\ G = Xe',\ H = Ye$ |
| Factoring SOP → product of sums form因式分解 Factoring 積之和 → 和之積的形式因数分解 Factoring 積和形 → 和積形 | $F = ac + ad + bc + bd + e$ | $F = (a+b)(c+d) + e$ |
| Substitution reuse an existing function代換 Substitution 重用既有的函數置換 Substitution 既存の関数を再利用する | $F = a + b + c,\ G = a + b$ | $F = G + c$ |
| Elimination flatten (inverse of substitution)消去 Elimination 攤平(代換的反向操作)消去 Elimination 平坦化(置換の逆操作) | $F = Ga + G'b,\ G = c + d$ | $F = ac + ad + bc'd'$ |
Problem: (a) Factor $F = ace + ade + bce + bde + f$. (b) Eliminate $G$ from $F = Gx + G'y$ with $G = ab$. (c) Count literals before and after each.題目:(a) 對 $F = ace + ade + bce + bde + f$ 做因式分解。(b) 在 $G = ab$ 的條件下,把 $F = Gx + G'y$ 中的 $G$ 消去。(c) 分別數出兩題前後的 literal 數。問題:(a) $F = ace + ade + bce + bde + f$ を因数分解せよ。(b) $G = ab$ として $F = Gx + G'y$ から $G$ を消去せよ。(c) それぞれについて前後のリテラル数を数えよ。
(a) $F = (a+b)(c+d)e + f$. Literals: 13 → 6.(a) $F = (a+b)(c+d)e + f$。literal 數:13 → 6。(a) $F = (a+b)(c+d)e + f$。リテラル数は 13 → 6。
(b) $F = abx + (ab)'y = abx + a'y + b'y$. Literals in $F$: 4 (plus 2 in $G$) → 7.(b) $F = abx + (ab)'y = abx + a'y + b'y$。$F$ 中的 literal:4(再加上 $G$ 的 2 個)→ 7。(b) $F = abx + (ab)'y = abx + a'y + b'y$。$F$ のリテラル数は 4($G$ の 2 個を加える)→ 7。
(c) Factoring shrinks area; elimination usually grows literal count but removes a logic level, which helps delay. Synthesis applies them iteratively against the area/delay cost.(c) 因式分解縮小面積;消去通常會讓 literal 變多,但少一層邏輯,對延遲有利。合成工具會依面積/延遲的成本函數反覆交替使用這兩種操作。(c) 因数分解は面積を縮め、消去はリテラルを増やす代わりに論理段数を 1 つ減らすので遅延に効く。合成ツールは面積/遅延のコストを見ながら、これらを繰り返し適用する。
The following map successfully to circuits: a netlist of Verilog primitives, combinational UDPs, continuous assignments, behavioral always blocks, functions, tasks without delay or event control, and interconnected modules of these. All of §4.1 – §4.6 describe the same function and synthesize to the same two cells.以下幾種寫法都能順利映射成電路:Verilog 基本元件組成的 netlist、組合邏輯 UDP、連續指定、行為式 always 區塊、function、不含延遲或事件控制的 task,以及由這些互連而成的模組。§4.1 – §4.6 描述的其實是同一個函數,也合成出同樣的兩顆 cell。次のものはいずれも回路へ問題なくマッピングされる。Verilog プリミティブのネットリスト、組合せ UDP、連続代入、動作レベルの always ブロック、function、遅延やイベント制御を含まない task、そしてそれらを相互接続したモジュールである。§4.1 – §4.6 はすべて同じ関数を記述しており、合成結果も同じ 2 つのセルになる。
module or_nand_1 (enable, x1, x2, x3, x4, y);
input enable, x1, x2, x3, x4;
output y;
wire w1, w2, w3;
or (w1, x1, x2);
or (w2, x3, x4);
or (w3, x3, x4); // redundant
nand (y, w1, w2, w3, enable);
endmodule
Synthesis removes the redundant w3 gate and maps the rest to one oai22 (OR-AND-invert) cell followed by a nand2 with enable.合成會移除多餘的 w3 閘,其餘映射成一顆 oai22(OR-AND-invert)cell,後面再接一個吃 enable 的 nand2。合成は冗長な w3 のゲートを取り除き、残りを oai22(OR-AND-invert)セル 1 個と、enable を受ける nand2 にマッピングする。
Final synthesis results depend on the synthesis tool and its cell library.最終的合成結果會隨合成工具及其 cell library 而不同。最終的な合成結果は、合成ツールとそのセルライブラリに依存する。
primitive boolean_eqs (y, a, b, c);
output y;
input a, b, c;
table
// a b c : y
0 1 ? : 1;
0 0 ? : 0;
1 ? 1 : 1;
1 ? 0 : 0;
endtable
endprimitive
Reading the table: $a = 0 \Rightarrow y = b$, $a = 1 \Rightarrow y = c$, i.e. $y = a'b + ac$ — a 2:1 mux, synthesized as two ANDs and an OR.讀這張表:$a = 0 \Rightarrow y = b$、$a = 1 \Rightarrow y = c$,也就是 $y = a'b + ac$ — 一個 2:1 多工器,合成成兩個 AND 加一個 OR。表を読むと $a = 0 \Rightarrow y = b$、$a = 1 \Rightarrow y = c$、すなわち $y = a'b + ac$ である — 2:1 マルチプレクサであり、AND 2 個と OR 1 個に合成される。
module or_nand_2 (enable, x1, x2, x3, x4, y); input enable, x1, x2, x3, x4; output y; assign y = ~(enable & (x1 | x2) & (x3 | x4)); endmodule
Most modern synthesis tools actually ignore the sensitivity list: they build the combinational logic from the body of the block and issue a warning. What really creates a latch is a path with no assignment on it (see §6). An incomplete sensitivity list does still make the RTL simulation hold the old value like a latch, so it no longer matches the synthesized netlist. Since Verilog-2001 the advice is simply to write always @* and be done with it.大多數現代合成工具其實會忽略敏感列表,直接依程式內容產生組合邏輯並發出警告;真正產生 latch 的原因是「某些路徑沒有賦值」(見第 6 節)。但敏感列表不完整會讓 RTL 模擬像 latch 一樣保持舊值,與合成後的 netlist 不一致。Verilog-2001 起建議直接寫 always @*,一次解決。最近の合成ツールの多くは感度リストを無視し、ブロック本体の記述からそのまま組合せ論理を作って警告を出す。本当にラッチを生むのは「代入されない経路がある」ことである(第 6 節)。ただし感度リストが不完全だと、RTL シミュレーションはラッチのように古い値を保持し、合成後のネットリストと一致しなくなる。Verilog-2001 以降は always @* と書けば一度で片がつく。
module or_nand_3 (enable, x1, x2, x3, x4, y);
input enable, x1, x2, x3, x4;
output y;
reg y;
always @ (enable or x1 or x2 or x3 or x4)
begin
y = ~(enable & (x1 | x2) & (x3 | x4));
end
endmodule
Same oai22 + nand2 circuit as §4.1.與 §4.1 相同的 oai22 + nand2 電路。§4.1 と同じ oai22 + nand2 の回路になる。
module and4_behav (y, x_in);
parameter word_length = 4;
input [word_length - 1:0] x_in;
output y;
reg y;
integer k;
always @ x_in
begin: check_for_0
y = 1;
for (k = 0; k <= word_length - 1; k = k + 1)
if (x_in[k] == 0)
begin
y = 0;
disable check_for_0; // early exit
end
end
endmodule
The loop has a constant bound so it unrolls; the disable only shortens simulation. Result: a single 4-input AND gate.迴圈的界限是常數,所以會被展開;disable 只是縮短模擬時間。結果就是一個 4 輸入的 AND 閘。ループの上限は定数なので展開される。disable はシミュレーションを短くするだけである。結果は 4 入力 AND ゲート 1 個になる。
module comparator (a, b, a_gt_b, a_lt_b, a_eq_b);
parameter size = 2;
input [size:1] a, b;
output a_gt_b, a_lt_b, a_eq_b;
reg a_gt_b, a_lt_b, a_eq_b;
integer k;
always @ (a or b)
begin: compare_loop
for (k = size; k > 0; k = k - 1) // MSB first
begin
if (a[k] != b[k])
begin
a_gt_b = a[k];
a_lt_b = ~a[k];
a_eq_b = 0;
disable compare_loop;
end // if
end // for loop
a_gt_b = 0;
a_lt_b = 0;
a_eq_b = 1;
end // compare_loop
endmodule
Scanning from the MSB, the first differing bit decides: if a[k] = 1 then $a > b$. Synthesis builds XOR/XNOR bit comparators, an equality AND, and muxes that select the decision bit by priority.由 MSB 往下掃,第一個不相同的位元就決定結果:若 a[k] = 1 則 $a > b$。合成會產生逐位元的 XOR/XNOR 比較器、一個做相等判斷的 AND,以及依優先權挑出決定位元的多工器。MSB から順に見ていき、最初に異なるビットで結果が決まる。a[k] = 1 なら $a > b$ である。合成はビットごとの XOR/XNOR 比較器、一致判定の AND、そして優先順位で決定ビットを選ぶマルチプレクサを生成する。
module or_nand_4 (enable, x1, x2, x3, x4, y);
input enable, x1, x2, x3, x4;
output y;
assign y = or_nand(enable, x1, x2, x3, x4);
function or_nand;
input enable, x1, x2, x3, x4;
begin
or_nand = ~(enable & (x1 | x2)
& (x3 | x4));
end
endfunction
endmodulemodule or_nand_5 (enable, x1, x2, x3, x4, y);
input enable, x1, x2, x3, x4;
output y;
reg y;
always @ (enable or x1 or x2 or x3 or x4)
or_nand(enable, x1, x2, x3, x4, y);
task or_nand;
input enable, x1, x2, x3, x4;
output y;
begin
y = !(enable & (x1 | x2) & (x3 | x4));
end
endtask
endmoduleBoth synthesize to the oai22 + nand2 pair. The task uses logical ! instead of bitwise ~; for a 1-bit operand they are the same, for vectors they are not.兩者都合成成 oai22 + nand2 這一對。task 版用的是邏輯 ! 而不是位元 ~;對 1 位元運算元兩者相同,對向量則不同。どちらも oai22 + nand2 の組に合成される。task 版はビット単位の ~ ではなく論理否定の ! を使っている。1 ビットのオペランドなら同じだが、ベクタでは異なる。
| Construct語法構文 | Why原因理由 |
|---|---|
| Multiple event controls in one procedural block一個程序區塊裡有多個事件控制一つの手続きブロック内に複数のイベント制御 | Implies a multi-cycle state machine with no explicit state等於寫了一台沒有明確狀態的多週期狀態機状態を明示しない複数サイクルの状態機械を意味する |
| Named event with edge-sensitive event control具名事件搭配邊緣敏感的事件控制名前つきイベントとエッジ検出のイベント制御 | No hardware equivalent硬體上沒有對應的東西対応するハードウェアが存在しない |
| Feedback loops回授迴路帰還ループ | Combinational loop (§7)組合邏輯迴路(§7)組合せループ(§7) |
| PCA containing event or delay control含事件或延遲控制的 PCAイベント制御や遅延を含む PCA | Timing not synthesizable時序部分無法合成時間的な記述は合成できない |
fork ... join, waitfork ... join、waitfork ... join・wait | Simulation-only只能用於模擬シミュレーション専用 |
External disable從外部 disable 其他區塊外部からの disable | Only disabling the enclosing block is supported只支援停用自己所在的那個區塊自分を囲むブロックの無効化しかサポートされない |
| Procedural loops with timing controls含時序控制的程序迴圈時間制御を含む手続きループ | Cannot be unrolled無法展開展開できない |
| Data-dependent loops界限取決於資料的迴圈データに依存するループ | Bound unknown at compile time編譯期無從得知界限上限がコンパイル時に分からない |
| Tasks with timing controls; sequential UDPs含時序控制的 task;序向 UDP時間制御を含む task、順序 UDP | Not mapped by the tool工具不會把它映射成電路ツールがマッピングしない |
module syn1_mux_4bits (y, sel, a, b, c, d);
input [3:0] a, b, c, d;
input [1:0] sel;
output [3:0] y;
assign y = (sel == 0) ? a :
(sel == 1) ? b :
(sel == 2) ? c :
(sel == 3) ? d : 4'bx;
endmodulemodule syn2_mux_4bits (y, sel, a, b, c, d);
input [3:0] a, b, c, d;
input [1:0] sel;
output [3:0] y;
reg [3:0] y;
always @ (sel or a or b or c or d)
case (sel)
0: y = a;
1: y = b;
2: y = c;
3: y = d;
default: y = 4'bx;
endcase
endmodulemodule syn3_mux_4bits (y, sel, a, b, c, d);
input [3:0] a, b, c, d;
input [1:0] sel;
output [3:0] y;
reg [3:0] y;
always @ (sel or a or b or c or d)
if (sel == 0) y = a;
else if (sel == 1) y = b;
else if (sel == 2) y = c;
else if (sel == 3) y = d;
else y = 4'bx;
endmoduleAll three are "simulation and synthesis friendly". Because the sel values are mutually exclusive, the if chain synthesizes to the same mux as the case version — no priority logic. The 4'bx default lets the tool treat the impossible branch as a don't care.三種寫法都屬於「模擬與合成都友善」。由於 sel 的各個值互斥,if 串接合成出來的多工器與 case 版完全相同,不會多出優先邏輯。4'bx 的 default 則讓工具把不可能發生的分支當成 don't care。三つとも「シミュレーションにも合成にも適した」書き方である。sel の各値は互いに排他なので、if チェーンも case 版と同じマルチプレクサに合成され、優先順位論理は生じない。4'bx の default は、起こりえない分岐をドントケアとして扱わせる。
always @ (sel) // only sel case (sel) 0: assign y = a; // procedural continuous assignment 1: assign y = b; 2: assign y = c; 3: assign y = d; default: assign y = 4'bx; endcase
Using assign (PCA) inside the block lets y follow a–d continuously while the block wakes only on sel, so it simulates fast. The synthesis result is the same mux, but PCA support varies by tool, so the full-sensitivity version is preferred.在區塊內用 assign(PCA),y 會持續跟著 a–d 變動,而區塊本身只在 sel 改變時被喚醒,所以模擬很快。合成結果是同一個多工器,但各家工具對 PCA 的支援不一,因此還是建議用完整敏感列表的版本。ブロック内で assign(PCA)を使うと、ブロックは sel でしか起動しないのに y は a–d に追従し続けるため、シミュレーションが速い。合成結果は同じマルチプレクサだが、PCA のサポートはツールによって差があるので、感度リストを完全に書いた版のほうが望ましい。
?:, case and if styles all synthesize to the same multiplexer, as long as the conditions are mutually exclusive and cover every value.?:、case、if 三種寫法,只要條件互斥且完整,都合成出相同的多工器。?:・case・if の三つの書き方は、条件が互いに排他ですべての値を網羅してさえいれば、同じマルチプレクサに合成される。sel only; the "simulation and synthesis friendly" style puts every input in the sensitivity list.「模擬有效率」寫法用 PCA,只對 sel 敏感;「模擬與合成都友善」寫法則把所有輸入放進敏感列表。「シミュレーション効率型」は PCA を使い sel にだけ感度をもつ。「シミュレーションにも合成にも適した」書き方は、すべての入力を感度リストに入れる。A case or if that does not cover all possible values is incompletely specified. On the uncovered paths the register must keep its old value, so synthesis inserts a latch. Avoid it.沒有涵蓋所有可能值的 case 或 if 就是未完整指定。在沒涵蓋到的路徑上,變數必須保持舊值,於是合成工具會插入一個閂鎖。請避免。取りうる値をすべて網羅していない case や if は不完全指定である。網羅されていない経路では変数が古い値を保持しなければならないので、合成はそこにラッチを挿入する。避けること。
module mux_latch (y_out, sel_a, sel_b, data_a, data_b);
input sel_a, sel_b, data_a, data_b;
output y_out;
reg y_out;
always @ (sel_a or sel_b or data_a or data_b)
case ({sel_a, sel_b})
2'b10: y_out = data_a;
2'b01: y_out = data_b; // incomplete case list!!
endcase
endmodule
module alu_incomplete1a (alu_out, data_a,
data_b, enable, opcode);
input [2:0] opcode;
input [3:0] data_a, data_b;
input enable;
output alu_out; // scalar
reg [3:0] alu_reg;
assign alu_out = (enable == 1) ? alu_reg : 4'b0;
always @ (opcode)
case (opcode)
3'b001: alu_reg = data_a | data_b;
3'b010: alu_reg = data_a ^ data_b;
3'b110: alu_reg = ~data_b;
endcase
endmodulemodule alu_incomplete2a (alu_out, data_a,
data_b, enable, opcode);
...
assign alu_out = (enable == 1) ? alu_reg : 4'b0;
always @ (opcode or data_a or data_b)
case (opcode)
3'b001: alu_reg = data_a | data_b;
3'b010: alu_reg = data_a ^ data_b;
3'b110: alu_reg = ~data_b;
endcase
endmoduleBoth synthesize a latch (latrnb) between the opcode-selected datapath and alu_out: for the five opcodes not listed, alu_reg must hold its value. Fixing the sensitivity list alone does not remove it.兩者都會在由 opcode 選出的資料路徑與 alu_out 之間合成出一個閂鎖(latrnb):對於沒列出的那五個 opcode,alu_reg 必須保持原值。只修敏感列表並不能把它消掉。どちらも、opcode で選ばれたデータパスと alu_out の間にラッチ(latrnb)を合成してしまう。列挙されていない 5 つの opcode では alu_reg が値を保持しなければならないからである。感度リストだけを直してもラッチは消えない。
module alu_complete (alu_out, data_a, data_b, enable, opcode);
...
always @ (opcode or data_a or data_b)
case (opcode)
3'b001: alu_reg = data_a | data_b;
3'b010: alu_reg = data_a ^ data_b;
3'b110: alu_reg = ~data_b;
default: alu_reg = 4'b0; // makes the case list complete
endcase
endmodule
With default the result is pure gates plus a mux — no latch.加上 default 之後,結果只剩純邏輯閘加一個多工器 — 沒有閂鎖。default を加えれば、結果は純粋なゲートとマルチプレクサだけになり、ラッチは生じない。
alu_out is a 1-bit port ("scalar for illustration"), so alu_reg is truncated to alu_reg[0] on assignment. That is why the synthesized schematic shows only one bit of datapath.alu_out 是 1 位元的埠(投影片寫「為了示意而用純量」),所以指定時 alu_reg 會被截成 alu_reg[0]。這就是合成出來的電路圖只看得到一個位元資料路徑的原因。alu_out は 1 ビットのポート(講義では「説明のためのスカラ」)なので、代入時に alu_reg は alu_reg[0] に切り詰められる。合成後の回路図にデータパスが 1 ビットしか現れないのはこのためである。
module incomplete_and (y, a1, a2);
input a1, a2;
output y;
reg y;
always @ (a1 or a2)
begin
if ({a2, a1} == 2'b11) y = 1;
else if ({a2, a1} == 2'b01) y = 0;
else if ({a2, a1} == 2'b10) y = 0; // the last statement should be "else"
end
endmodule
The case {a2, a1} = 00 is missing, so the tool builds inverters, a NOR/NAND enable and a latch (latrnb). Ending with a plain else y = 0; gives one AND gate.少了 {a2, a1} = 00 這個情況,工具就造出反相器、一組 NOR/NAND 致能邏輯與一個閂鎖(latrnb)。只要最後改成單純的 else y = 0;,就只剩一個 AND 閘。{a2, a1} = 00 の場合が抜けているため、ツールはインバータ、NOR/NAND のイネーブル論理、そしてラッチ(latrnb)を作ってしまう。最後を単純な else y = 0; にすれば AND ゲート 1 個で済む。
Problem: Which blocks infer a latch?題目:下列哪些區塊會推論出閂鎖?問題:ラッチが推論されるのはどのブロックか。
// (a) always @ (a or b or s) if (s) y = a; else y = b; // (b) always @ (en or d) if (en) q = d; // (c) always @ (s or a or b) begin y = b; if (s) y = a; end // (d) always @ (op or a or b) case (op) 2'b00: y = a; 2'b01: y = b; 2'b10: y = a & b; endcase // (e) op is 2 bits always @ (op or a or b) case (op) 2'b00: y = a; 2'b01: y = b; 2'b10: y = a & b; 2'b11: y = a | b; endcase
(a) No — every path assigns y.(a) 不會 — 每條路徑都有指定 y。(a) いいえ — どの経路でも y に代入される。
(b) Yes — no else; this is the standard way to write an intentional D-latch.(b) 會 — 沒有 else;這正是刻意寫出 D 型閂鎖的標準寫法。(b) はい — else がない。意図的に D ラッチを書くときの標準的な形である。
(c) No — the default assignment at the top covers the missing else.(c) 不會 — 開頭的預設指定已經補上了缺少的 else。(c) いいえ — 先頭の既定代入が、欠けている else を補っている。
(d) Yes — op = 2'b11 is not covered.(d) 會 — op = 2'b11 沒有被涵蓋。(d) はい — op = 2'b11 が網羅されていない。
(e) No — all four values of a 2-bit op are listed. (In simulation op = x would hold y, but synthesis only considers 0/1, so no latch; adding default is still good style.)(e) 不會 — 2 位元 op 的四個值都列出來了。(模擬時 op = x 會讓 y 保持舊值,但合成只考慮 0/1,所以不會有閂鎖;不過補上 default 仍是好習慣。)(e) いいえ — 2 ビットの op の 4 値がすべて列挙されている。(シミュレーションでは op = x のとき y が保持されるが、合成は 0/1 しか考えないのでラッチは生じない。とはいえ default を足しておくのは良い作法である。)
A case or if that is "completed" by assigning the variable to itself in a level-sensitive behavior synthesizes to a mux whose output feeds back to its input. This combinational loop cannot be mapped to proper gates — avoid it.在位準敏感的行為區塊裡,用把變數指定給自己的方式來「補完」case 或 if,合成出來會是一個輸出回授到自己輸入的多工器。這種組合邏輯迴路無法對應成正常的邏輯閘 — 請避免。レベル検出の記述の中で、変数に自分自身を代入して case や if を「完全」にすると、出力が自分の入力へ戻るマルチプレクサに合成される。この組合せループはまともなゲートにマッピングできない — 避けること。
module latch_case1 (latch_out, latch_in,
set, clear, enable);
input latch_in, set, clear, enable;
output latch_out;
reg latch_out;
always @ (enable or set or clear or latch_in)
case ({enable, set, clear})
3'b000: latch_out = latch_in; // transparent
3'b110: latch_out = 1'b1; // set
3'b010: latch_out = 1'b1; // set
3'b101: latch_out = 1'b0; // clear
3'b001: latch_out = 1'b0; // clear
default: latch_out = latch_out; // holds value
endcase
endmodulemodule latch_if1 (data_out, data_in,
latch_enable);
input [3:0] data_in;
output [3:0] data_out;
input latch_enable;
reg [3:0] data_out;
always @ (latch_enable or data_in)
if (latch_enable) data_out = data_in;
else data_out = data_out;
endmoduleProblem: Rewrite latch_if1 two ways: (a) as an intentional latch the tool will map to a latch cell, (b) as pure combinational logic that outputs 0 when disabled.題目:用兩種方式改寫 latch_if1:(a) 寫成工具會映射到閂鎖 cell 的刻意閂鎖,(b) 寫成純組合邏輯,未致能時輸出 0。問題:latch_if1 を二通りに書き直せ。(a) ツールがラッチセルにマッピングする意図的なラッチとして、(b) 無効時に 0 を出力する純粋な組合せ論理として。
// (a) intentional latch: no else, no self-assignment always @ (latch_enable or data_in) if (latch_enable) data_out = data_in; // (b) combinational: every path gets a new value always @ (latch_enable or data_in) if (latch_enable) data_out = data_in; else data_out = 4'b0;
(a) is recognized as a latch template and mapped to latch cells; (b) becomes four AND gates. The self-assignment x = x is what makes the tool build an explicit feedback mux instead.(a) 會被辨識成閂鎖樣板,映射到閂鎖 cell;(b) 則變成四個 AND 閘。真正讓工具去造出明確回授多工器的,就是 x = x 這種自我指定。(a) はラッチのテンプレートとして認識され、ラッチセルにマッピングされる。(b) は AND ゲート 4 個になる。ツールにわざわざ明示的な帰還マルチプレクサを作らせてしまうのは、x = x という自己代入である。
if statement also synthesizes to a mux when its branch conditions are mutually exclusive.if 敘述只要分支條件互斥,同樣會合成成多工器。if 文も、分岐条件が互いに排他であれば同じくマルチプレクサに合成される。module mux_4pri (y, a, b, c, d, sel_a, sel_b, sel_c);
input a, b, c, d, sel_a, sel_b, sel_c;
output y;
reg y;
always @ (sel_a or sel_b or sel_c or a or b or c or d)
begin // not mutually exclusive
if (sel_a == 1) y = a;
else if (sel_b == 0) y = b;
else if (sel_c == 1) y = c;
else y = d;
end
endmodule
module encoder (Data, Code);
input [7:0] Data;
output [2:0] Code;
reg [2:0] Code;
always @ (Data)
begin
if (Data == 8'b00000001) Code = 0;
else if (Data == 8'b00000010) Code = 1;
else if (Data == 8'b00000100) Code = 2;
else if (Data == 8'b00001000) Code = 3;
else if (Data == 8'b00010000) Code = 4;
else if (Data == 8'b00100000) Code = 5;
else if (Data == 8'b01000000) Code = 6;
else if (Data == 8'b10000000) Code = 7;
else Code = 3'bx;
end
endmodulemodule encoder (Data, Code);
input [7:0] Data;
output [2:0] Code;
reg [2:0] Code;
always @ (Data)
case (Data)
8'b00000001 : Code = 0;
8'b00000010 : Code = 1;
8'b00000100 : Code = 2;
8'b00001000 : Code = 3;
8'b00010000 : Code = 4;
8'b00100000 : Code = 5;
8'b01000000 : Code = 6;
8'b10000000 : Code = 7;
default : Code = 3'bx;
endcase
endmoduleThe one-hot patterns are mutually exclusive and the default is a don't care, so the tool reduces each output bit to a 4-input OR:one-hot 的樣式彼此互斥,default 又是 don't care,所以工具把每個輸出位元化簡成一個 4 輸入 OR:ワンホットのパターンは互いに排他で、default はドントケアなので、ツールは各出力ビットを 4 入力 OR に簡単化する。
module priority (Data, Code, valid_data);
input [7:0] Data;
output [2:0] Code;
output valid_data;
reg [2:0] Code;
assign valid_data = |Data; // reduction or
always @ (Data)
begin
if (Data[7]) Code = 7;
else if (Data[6]) Code = 6;
else if (Data[5]) Code = 5;
else if (Data[4]) Code = 4;
else if (Data[3]) Code = 3;
else if (Data[2]) Code = 2;
else if (Data[1]) Code = 1;
else if (Data[0]) Code = 0;
else Code = 3'bx;
end
endmodulemodule priority (Data, Code, valid_data);
...
assign valid_data = |Data;
always @ (Data)
casex (Data)
8'b1xxxxxxx : Code = 7;
8'b01xxxxxx : Code = 6;
8'b001xxxxx : Code = 5;
8'b0001xxxx : Code = 4;
8'b00001xxx : Code = 3;
8'b000001xx : Code = 2;
8'b0000001x : Code = 1;
8'b00000001 : Code = 0;
default : Code = 3'bx;
endcase
endmoduleNow several bits may be 1 at once, so the conditions overlap and the highest index wins. The synthesized netlist adds inverters and AND/NOR terms that mask lower bits, e.g.現在可能同時有好幾個位元是 1,條件因此重疊,由索引最高的那個勝出。合成出的 netlist 會多出反相器與遮蔽低位元的 AND/NOR 項,例如:今度は複数のビットが同時に 1 になりうるため条件が重なり、添字の大きいほうが勝つ。合成されたネットリストには、下位ビットをマスクするインバータと AND/NOR 項が加わる。例えば次のとおり。
module decoder (Code, Data);
output [7:0] Data;
input [2:0] Code;
reg [7:0] Data;
always @ (Code)
begin
if (Code == 0) Data = 8'b00000001;
else if (Code == 1) Data = 8'b00000010;
else if (Code == 2) Data = 8'b00000100;
else if (Code == 3) Data = 8'b00001000;
else if (Code == 4) Data = 8'b00010000;
else if (Code == 5) Data = 8'b00100000;
else if (Code == 6) Data = 8'b01000000;
else if (Code == 7) Data = 8'b10000000;
else Data = 8'bx;
end
endmodule always @ (Code)
case (Code)
0 : Data = 8'b00000001;
1 : Data = 8'b00000010;
2 : Data = 8'b00000100;
3 : Data = 8'b00001000;
4 : Data = 8'b00010000;
5 : Data = 8'b00100000;
6 : Data = 8'b01000000;
7 : Data = 8'b10000000;
default: Data = 8'bx;
endcase
Each Data[i] is a 3-input minterm of Code; the netlist uses inverters, nand2/and2 pre-decoding and nor/and3 cells. HW: write a mux the same way.每個 Data[i] 都是 Code 的 3 輸入最小項;netlist 會用到反相器、nand2/and2 做預解碼,以及 nor/and3 等 cell。作業:用同樣的方式寫一個多工器。各 Data[i] は Code の 3 入力最小項である。ネットリストはインバータ、nand2/and2 によるプリデコード、nor/and3 などのセルを使う。宿題:同じやり方でマルチプレクサを書くこと。
Problem: For Data = 8'b0010_0100, give Code from (a) the non-priority encoder in simulation, (b) the same encoder's synthesized OR netlist, (c) the priority encoder. (d) What does valid_data mean when Data = 0?題目:當 Data = 8'b0010_0100 時,分別給出 (a) 無優先權的 encoder 在模擬中的 Code、(b) 同一個編碼器合成後 OR netlist 的輸出、(c) 優先編碼器的輸出。(d) 當 Data = 0 時,valid_data 代表什麼?問題:Data = 8'b0010_0100 のとき、(a) 優先順位なしの encoder のシミュレーション上の Code、(b) 同じエンコーダを合成した OR ネットリストの出力、(c) プライオリティエンコーダの出力をそれぞれ示せ。(d) Data = 0 のとき valid_data は何を意味するか。
(a) Not one-hot → default → Code = 3'bxxx.(a) 不是 one-hot → 走 default → Code = 3'bxxx。(a) ワンホットではない → default → Code = 3'bxxx。
(b) $D_5 = D_2 = 1$: Code[2] = 1 ($D_5$), Code[1] = 1 ($D_2$), Code[0] = 1 ($D_5$) → 3'b111. The x in RTL became a concrete (and wrong-looking) value: a simulation/synthesis mismatch caused by the don't care.(b) $D_5 = D_2 = 1$:Code[2] = 1(來自 $D_5$)、Code[1] = 1(來自 $D_2$)、Code[0] = 1(來自 $D_5$)→ 3'b111。RTL 裡的 x 變成了具體(而且看起來不對)的值:這正是 don't care 造成的模擬/合成不一致。(b) $D_5 = D_2 = 1$ なので Code[2] = 1($D_5$)、Code[1] = 1($D_2$)、Code[0] = 1($D_5$)→ 3'b111。RTL の x が具体的な、しかも一見おかしな値になった。ドントケアが生むシミュレーションと合成の不一致である。
(c) Highest set bit is 5 → Code = 3'b101.(c) 最高的 1 在第 5 位 → Code = 3'b101。(c) 立っている最上位ビットは 5 → Code = 3'b101。
(d) valid_data = 0 flags that Code is meaningless; downstream logic must ignore Code then.(d) valid_data = 0 表示 Code 沒有意義;此時下游邏輯必須忽略 Code。(d) valid_data = 0 は Code が無意味であることを示す。このとき後段の論理は Code を無視しなければならない。
Buses transport multi-bit data; buffers store or drive data with or without control signals. Four implementation concerns: tri-state buffers, bidirectional buses, bus loading, and tri-state outputs with don't cares.匯流排負責搬運多位元資料;緩衝器則在有或沒有控制訊號的情況下儲存或驅動資料。實作上有四個重點:三態緩衝器、雙向匯流排、匯流排負載,以及帶 don't care 的三態輸出。バスは多ビットのデータを運び、バッファは制御信号の有無に応じてデータを保持または駆動する。実装上の論点は四つある。トライステート・バッファ、双方向バス、バスの負荷、そしてドントケアを伴うトライステート出力である。
module stuff_to_bus1 (data_to_bus, bus_enabled, clk); input bus_enabled, clk; output [31:0] data_to_bus; reg [31:0] ckt_output_to_bus; assign data_to_bus = (bus_enabled) ? ckt_output_to_bus : 32'bz; // Description of core circuit goes here to drive ckt_output_to_bus endmodule
A conditional operator whose other branch is z synthesizes to a 32-bit tri-state buffer controlled by bus_enabled.條件運算子的另一個分支給 z,就會合成成一個由 bus_enabled 控制的 32 位元三態緩衝器。条件演算子のもう一方の分岐を z にすると、bus_enabled で制御される 32 ビットのトライステート・バッファに合成される。
module stuff_to_bus2 (data_to_from_bus, clk, send_data, rcv_data); input clk, send_data, rcv_data; inout [31:0] data_to_from_bus; reg [31:0] reg_to_bus; wire [31:0] data_to_from_bus, inbound_data; assign inbound_data = (rcv_data) ? data_to_from_bus : 32'bz; assign data_to_from_bus = (send_data) ? reg_to_bus : 32'bz; // Behavior using inbound_data goes here endmodule
module stuff_to_bus3 (data_to_from_bus, enab_a, enab_b, clk, rcv_data);
input enab_a, enab_b, rcv_data, clk;
inout [31:0] data_to_from_bus;
reg [31:0] reg_a_to_bus, reg_b_to_bus;
assign data_to_from_bus = (enab_a) ? reg_a_to_bus :
(enab_b) ? reg_b_to_bus : 32'bz;
endmodule // not showing other logic
Rather than two tri-state drivers on the bus, one nested conditional gives a 2:1 mux (select enab_a) followed by a single tri-state driver enabled by enab_a | enab_b. Only one driver loads the bus, and contention is impossible.與其在匯流排上掛兩個三態驅動器,用一個巢狀條件式就能得到一個 2:1 多工器(以 enab_a 選擇),後面再接單一由 enab_a | enab_b 致能的三態驅動器。匯流排上只有一個驅動器,也就不可能發生競爭。バスにトライステート・ドライバを 2 個ぶら下げる代わりに、入れ子の条件式を使えば、2:1 マルチプレクサ(選択は enab_a)の後ろに enab_a | enab_b でイネーブルされる単一のトライステート・ドライバが置かれる。バスを駆動するのは 1 個だけなので、競合は起こりえない。
module alu_with_z1 (alu_out, data_a, data_b, enable, opcode); input [2:0] opcode; input [3:0] data_a, data_b; input enable; output alu_out; // scalar for illustration reg [3:0] alu_reg; assign alu_out = (enable == 1) ? alu_reg : 4'bz; always @ (opcode or data_a or data_b) case (opcode) 3'b001: alu_reg = data_a | data_b; 3'b010: alu_reg = data_a ^ data_b; 3'b110: alu_reg = ~data_b; default: alu_reg = 4'b0; // alu_with_z2: alu_reg = 4'bx; (don't cares) endcase endmodule
| Version版本バージョン | default | Synthesized circuit合成出的電路合成される回路 |
|---|---|---|
alu_with_z1 | 4'b0 | Must force 0 for 5 unused opcodes: two muxes, several gates, tri-state output5 個未使用的 opcode 都必須強制為 0:兩個多工器、數個邏輯閘、一個三態輸出未使用の 5 つの opcode で 0 を強制する必要がある:マルチプレクサ 2 個、ゲート数個、トライステート出力 |
alu_with_z2 | 4'bx | Unused opcodes are free: one mux, fewer gates, tri-state output未使用的 opcode 可以隨意:一個多工器、較少的邏輯閘、一個三態輸出未使用の opcode は自由なので、マルチプレクサ 1 個、より少ないゲート、トライステート出力で済む |
Assigning x in a default both prevents a latch (the case is complete) and gives the optimizer freedom. Use it only when those input values truly never occur, because the hardware output for them is unpredictable.在 default 裡指定 x,既能避免閂鎖(case 變完整),又給了最佳化器自由。但只有在那些輸入值真的不可能出現時才可以這樣寫,因為硬體在那些情況下的輸出是無法預期的。default で x を代入すると、case が完全になるのでラッチを防げるうえに、最適化器に自由度を与えられる。ただし、その入力値が本当に起こらない場合にのみ使うこと。起きたときのハードウェア出力は予測できないからである。
Problem: Instead of §9.3, a designer writes題目:有人沒照 §9.3 的寫法,而是寫成問題:§9.3 の代わりに、ある設計者は次のように書いた。
assign data_to_from_bus = enab_a ? reg_a_to_bus : 32'bz; assign data_to_from_bus = enab_b ? reg_b_to_bus : 32'bz;
With reg_a_to_bus = 32'h0000_00FF, reg_b_to_bus = 32'h0000_0F0F and enab_a = enab_b = 1, what does simulation show for the low byte? What does §9.3 show?若 reg_a_to_bus = 32'h0000_00FF、reg_b_to_bus = 32'h0000_0F0F,且 enab_a = enab_b = 1,模擬中最低位元組會是什麼?改用 §9.3 的寫法又會是什麼?reg_a_to_bus = 32'h0000_00FF、reg_b_to_bus = 32'h0000_0F0F、enab_a = enab_b = 1 のとき、シミュレーションで下位バイトはどうなるか。§9.3 の書き方ならどうなるか。
Two drivers on a wire: bits that agree keep their value, bits that differ become x. Low byte: a = 1111_1111, b = 0000_1111 → xxxx_1111. In silicon this is a short between the two drivers.同一條 wire 上有兩個驅動器:相同的位元維持原值,不同的位元變成 x。最低位元組:a = 1111_1111、b = 0000_1111 → xxxx_1111。在晶片上這就是兩個驅動器之間的短路。一本の wire を二つのドライバが駆動する。一致するビットは値を保ち、異なるビットは x になる。下位バイトは a = 1111_1111、b = 0000_1111 → xxxx_1111。シリコン上ではこれは二つのドライバ間の短絡である。
§9.3 gives enab_a priority: the bus carries 8'hFF, no contention.§9.3 的寫法讓 enab_a 有優先權:匯流排上是 8'hFF,不會發生競爭。§9.3 では enab_a が優先される。バスには 8'hFF が乗り、競合は起きない。
Do the resource sharing before RTL coding — it is what gives hardware its low-cost property.資源共享要在寫 RTL 之前就想好 — 硬體之所以能低成本,靠的就是這件事。リソース共有はRTL を書く前に済ませておく — ハードウェアが低コストでいられるのはこれによる。
module res_share (y_out, sel, data_a, data_b, accum); input [3:0] data_a, data_b, accum; input sel; output [4:0] y_out; // two adders + mux // assign y_out = sel ? (data_a + accum) : (data_a + data_b); // one mux + one adder assign y_out = data_a + (sel ? accum : data_b); endmodule
Problem: Rewrite each with one arithmetic unit. (a) y = sel ? a * b : a * c; (b) y = sel ? a + b : c + d; (c) Is (b) always a win?題目:把下列各式改寫成只用一個算術單元。(a) y = sel ? a * b : a * c; (b) y = sel ? a + b : c + d; (c) (b) 一定划算嗎?問題:それぞれを演算器 1 個で書き直せ。(a) y = sel ? a * b : a * c; (b) y = sel ? a + b : c + d; (c) (b) は必ず得になるか。
(a) y = a * (sel ? b : c); — one multiplier + one mux.(a) y = a * (sel ? b : c); — 一個乘法器加一個多工器。(a) y = a * (sel ? b : c); — 乗算器 1 個とマルチプレクサ 1 個。
(b) y = (sel ? a : c) + (sel ? b : d); — one adder + two muxes.(b) y = (sel ? a : c) + (sel ? b : d); — 一個加法器加兩個多工器。(b) y = (sel ? a : c) + (sel ? b : d); — 加算器 1 個とマルチプレクサ 2 個。
(c) For narrow adders two muxes may cost as much as the saved adder, and the mux now sits in front of the adder, lengthening the critical path. Sharing pays off for large units (multipliers, wide adders) and when timing has slack.(c) 對位元數少的加法器而言,兩個多工器的成本可能和省下的那個加法器差不多;而且多工器現在擋在加法器前面,會拉長關鍵路徑。只有在運算單元很大(乘法器、寬加法器)且時序還有餘裕時,共享才划算。(c) ビット幅の小さい加算器では、マルチプレクサ 2 個のコストが節約した加算器と同程度になりうる。しかもマルチプレクサが加算器の前に入るため、クリティカルパスが延びる。共有が得になるのは、演算器が大きい場合(乗算器や幅の広い加算器)と、タイミングに余裕がある場合である。
initial, delays, ===, fork, wait.不可用 initial、延遲、===、fork、wait。initial・遅延・===・fork・wait は使わない。@*).所有輸入都要列進事件列表(@*)。すべての入力をイベントリストに入れる(@*)。default / final else.用 default 或最後一個 else 補起來。default か最後の else で補う。x = x feedback → combinational loop.x = x 的回授 → 組合邏輯迴路。x = x の帰還 → 組合せループ。if chain or casex.優先編碼器:if 串接或 casex。プライオリティエンコーダ:if チェーンか casex。cond ? v : 'bz → tri-state.cond ? v : 'bz → 三態。cond ? v : 'bz → トライステート。?:.用巢狀 ?: 讓每條匯流排只有一個驅動器。入れ子の ?: でバスごとにドライバを 1 個にする。default x = don't care; share adders.default x 就是 don't care;加法器要共用。default x はドントケア。加算器は共有する。always @* // complete sensitivity begin y = DEFAULT_VALUE; // every path assigned case (sel) ... default: y = 'bx; // complete list, don't care endcase end