A consolidated study companion for Lectures 1–8 — design flow, Verilog syntax and semantics, simulation, delay modelling, behavioral description, synthesis rules, and the two capstone design examples.涵蓋第 1–8 講的整合式學習手冊 — 設計流程、Verilog 語法與語意、 模擬、延遲模型、行為描述、合成規則,以及兩個總結性的設計範例。第 1–8 講をまとめた学習ガイド — 設計フロー、Verilog の構文と意味、 シミュレーション、遅延モデル、動作記述、合成規則、そして 2 つの総仕上げの設計例。
Each section states the rule first, then shows the minimum code that demonstrates it, then flags the
trap that the rule exists to prevent. Where the lecture slides asked a question ("what is the difference between
always and forever?"), the answer is given in a collapsible box.每一節都先講規則,接著給出能說明該規則的最小程式碼,最後點出這條規則存在是為了避免哪個陷阱。凡是課堂投影片提出過的問題(例如「always 和 forever 有什麼不同?」),答案都放在可展開的方塊裡。各節はまず規則を述べ、次にそれを示す最小限のコードを挙げ、最後にその規則が防ごうとしている落とし穴を指摘します。講義スライドが問いかけていた点(たとえば「always と forever の違いは?」)については、答えを折りたたみボックスに収めてあります。
The single highest-yield idea in the whole course: Verilog is not a programming language, it is a notation for hardware. Every construct has three separate answers — what it simulates as, what it synthesizes to, and whether it synthesizes at all. Keep those three columns separate in your head and most of the exam becomes bookkeeping.整門課投報率最高的一個觀念:Verilog 不是程式語言,它是描述硬體的記法。每一個語法結構都有三個各自獨立的答案 — 它模擬出什麼行為、它合成成什麼電路,以及它到底能不能合成。把這三欄在腦中分清楚,大部分考題就只剩查表的功夫。この科目で最も費用対効果の高い一点:Verilog はプログラミング言語ではなく、ハードウェアを表す記法である。どの構文にも独立した 3 つの答えがあります — シミュレーションではどう振る舞うか、合成すると何になるか、そもそも合成できるのか。この 3 つの列を頭の中で分けておけば、試験の大半は表を引く作業になります。
The course places Verilog inside a larger industrial flow. Knowing where each tool sits is worth easy exam marks.本課程把 Verilog 放在一條更大的產業流程裡。知道每個工具落在哪個位置,是很好拿的考試分數。この講義は Verilog をより大きな産業フローの中に位置づけます。どのツールがどこに入るかを知っておくと、試験で確実に点が取れます。
The research-level loop the lecture draws is: choose a direction → pick a topic → simulate the algorithm (MATLAB/C) → write Verilog → verify the IC design → layout → fabrication → board assembly → chip measurement → compare against reference ICs. Verilog sits in the middle, and the algorithm simulation before it produces the golden pattern the testbench will later compare against.投影片畫出的研究層級循環是:選定方向 → 決定題目 → 模擬演算法(MATLAB/C)→ 撰寫 Verilog → 驗證 IC 設計 → 佈局 → 下線製造 → 電路板組裝 → 晶片量測 → 與參考 IC 比較。Verilog 位在中間,而在它之前的演算法模擬會產生測試平台日後要拿來比對的 golden pattern。講義が描く研究レベルのループは、方向を選ぶ → テーマを決める → アルゴリズムを(MATLAB/C で)シミュレーションする → Verilog を書く → IC 設計を検証する → レイアウト → 製造 → ボード実装 → チップ測定 → 参照 IC と比較、という流れです。Verilog はその中間にあり、その手前のアルゴリズムシミュレーションが、後でテストベンチが比較に使う golden pattern を生み出します。
| Level層次レベル | What the model describes模型描述的內容モデルが記述するもの | Typical artefact典型產出典型的な成果物 |
|---|---|---|
| Architectural / Algorithmic架構級/演算法級アーキテクチャ級/アルゴリズム級 | the algorithm, in high-level language constructs以高階語言結構表達的演算法高水準言語の構文で表したアルゴリズム | C / MATLAB, behavioral VerilogC/MATLAB、行為級 VerilogC/MATLAB、動作レベルの Verilog |
| RTLRTLRTL | flow of data between registers and how the design processes it資料在暫存器之間的流動,以及設計如何處理它レジスタ間のデータの流れと、その処理のしかた | synthesizable Verilog可合成的 Verilog合成可能な Verilog |
| Gate閘級ゲート級 | logic gates and their interconnections邏輯閘與它們之間的連接論理ゲートとその相互接続 | netlist from synthesis合成產生的網表合成が出力するネットリスト |
| Transistor電晶體級トランジスタ級 | transistors and their interconnections電晶體與它們之間的連接トランジスタとその相互接続 | SPICE, standard-cell layoutSPICE、標準單元佈局SPICE、スタンダードセル・レイアウト |
The same design can be viewed in three domains at each level: abstract (behavior), structural (connectivity), and physical (geometry). Moving down the abstract column is design; moving rightwards from abstract to structural is synthesis; comparing the two is verification.同一份設計在每一層都可以從三個領域來看:抽象(行為)、結構(連接關係)與實體(幾何形狀)。沿著抽象那一欄往下走是設計;從抽象往右走到結構是合成;把兩者互相比對則是驗證。同じ設計は、どのレベルでも 3 つの領域から眺められます:抽象(動作)、構造(接続関係)、物理(幾何形状)。抽象の列を下に降りるのが設計、抽象から構造へ右に移るのが合成、両者を突き合わせるのが検証です。
The module is the basic building block — Verilog's design entity. Three facts about modules carry most of the exam weight:module 是最基本的組成單位 — Verilog 的設計實體。關於模組有三件事佔了大部分的考試分數:module は最も基本的な構成単位、すなわち Verilog の設計エンティティです。モジュールについて試験の配点の大半を占めるのは次の 3 点です。
input, output, inout; every port defaults to
wire unless you declare otherwise.埠的方向有 input、output、inout;除非另行宣告,每個埠預設都是 wire。ポートの方向は input、output、inout の 3 つで、明示しない限りすべてのポートは既定で wire です。module test (a, b, c, d); input a, b; // default net type: wire output c, d; wire c, d; // explicit, but redundant here assign c = a | b; // continuous assignment, drives a net assign d = a & b; endmodule
Verilog splits every signal into one of two families. Almost every "why does this not compile?" question in the course reduces to putting a signal in the wrong family.Verilog 把每個訊號分成兩大家族。這門課裡幾乎所有「為什麼這段編不過?」的問題,追根究柢都是把訊號放錯了家族。Verilog はすべての信号をこの 2 つの系統のいずれかに分類します。この講義で出てくる「なぜコンパイルが通らないのか」という疑問は、ほぼすべて信号を誤った系統に置いたことに帰着します。
| NetNetNet | RegisterRegisterRegister | |
|---|---|---|
| Keywords關鍵字キーワード | wire, wand, wor, tri, triand,
trior, supply0, supply1wire、wand、wor、tri、triand、
trior、supply0、supply1wire、wand、wor、tri、triand、
trior、supply0、supply1 |
reg, integer, time, real, realtimereg、integer、time、real、realtimereg、integer、time、real、realtime |
| Meaning意義意味 | structural connectivity — a wire, stores nothing結構上的連接 — 一條線,本身不儲存任何東西構造的な接続 — ただの配線であり、何も保持しない | abstraction of storage — holds a value between events儲存的抽象 — 在事件之間保住一個值記憶の抽象 — イベントとイベントの間、値を保持する |
| Assigned by由什麼賦值何によって代入されるか | assign (continuous), or by being driven by a primitive or module outputassign(連續賦值),或被原件、模組輸出所驅動assign(連続代入)、またはプリミティブやモジュール出力に駆動されること |
procedural statement inside always/initial, a task, a function, or a sequential UDPalways/initial、task、function 或序向 UDP 內的程序式敘述always/initial、task、function、順序回路 UDP の中の手続き文 |
| May NOT be不可以是次にはできない | the target of a procedural assignment inside alwaysalways 內程序式賦值的目標always 内の手続き型代入の左辺 |
the output of a primitive gate; the target of a continuous assign原件閘的輸出;連續 assign 的目標プリミティブゲートの出力、および連続 assign の左辺 |
| Initial value at time 0時間 0 的初始值時刻 0 での初期値 | x if driven, z if undriven被驅動時為 x,未被驅動時為 z駆動されていれば x、駆動されていなければ z |
x |
Declaring a signal reg does not mean a flip-flop will be
synthesized. reg is only a simulation-time storage abstraction: it says "this variable must hold its value
between procedural assignments". Whether real hardware storage appears depends entirely on the sensitivity list and
whether the value is fully assigned in every branch.把訊號宣告成 reg 並不代表就會合成出正反器。reg 只是模擬時的儲存抽象:它表示「這個變數必須在兩次程序式賦值之間保住自己的值」。真正的硬體儲存元件會不會出現,完全取決於敏感度列表,以及這個值是否在每個分支中都被賦值。信号を reg と宣言しても、フリップフロップが合成されるという意味ではありません。reg はシミュレーション上の記憶の抽象にすぎず、「この変数は手続き型代入と代入の間で値を保持しなければならない」ことを表すだけです。実際のハードウェア記憶素子ができるかどうかは、センシティビティリストと、すべての分岐で値が代入されているかどうかで決まります。
module test (a, b, c, d); input a, b; output c, d; reg c, d; // required because they are assigned procedurally always @ (a or b) begin // sensitivity list c = a | b; d = a & b; end endmodule
This synthesizes to exactly the same two gates as the assign version above — no latches, no
flip-flops — because the sensitivity list is complete and both targets are assigned unconditionally.這段合成出來的結果,和上面用 assign 的版本完全相同 — 就是那兩個閘,沒有鎖存器、也沒有正反器 — 因為敏感度列表是完整的,而且兩個目標都被無條件賦值。これは上の assign 版とまったく同じ 2 つのゲートに合成されます — ラッチもフリップフロップも生じません — センシティビティリストが完全で、両方の対象が無条件に代入されているからです。
The scope of a variable is the module, task, function, or named begin…end block in
which it is declared. To reach inside an instantiated module from a testbench, use a
hierarchical path name: X.w, or X.Y.Z.w. This is legal in testbenches and is
how force reaches internal nodes; it is not synthesizable.一個變數的作用範圍是宣告它的那個 module、task、function,或具名的 begin…end 區塊。若要從測試平台伸進被實體化的模組內部,要用階層路徑名稱:X.w 或 X.Y.Z.w。這在測試平台中是合法的,也是 force 能碰到內部節點的方式;但它不可合成。変数のスコープは、それを宣言した module・task・function、または名前付きの begin…end ブロックです。テストベンチからインスタンス化したモジュールの内部に手を伸ばすには、階層パス名(X.w や X.Y.Z.w)を使います。テストベンチでは合法で、force が内部ノードに届くのもこの仕組みですが、合成はできません。
| Value值値 | Meaning意義意味 |
|---|---|
0 | logic zero / FALSE邏輯零/FALSE論理ゼロ/FALSE |
1 | logic one / TRUE邏輯一/TRUE論理イチ/TRUE |
x or Xx 或 Xx または X | unknown, ambiguous — the simulator cannot decide未知、無法判定 — 模擬器決定不了不定・あいまい — シミュレータが決められない |
z or Zz 或 Zz または Z | high impedance, open circuit, undriven高阻抗、開路、無人驅動ハイインピーダンス、開放、無駆動 |
Logic values are not case-sensitive (x and X are the same); identifiers
and keywords are.邏輯值不分大小寫(x 和 X 相同);識別字與關鍵字則會分。論理値は大文字・小文字を区別しません(x と X は同じ)。一方、識別子とキーワードは区別します。
The AND truth table over four values is the one to memorise, because it shows the asymmetry that makes
x propagation tolerable:四值下的 AND 真值表最該背起來,因為它呈現出讓 x 的傳播不至於失控的那種不對稱性:4 値の AND 真理値表は覚えておくべきものです。x の伝播が許容できるものになる非対称性が、そこに現れているからです。
& | 0 | 1 | x | z |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | x | x |
| x | 0 | x | x | x |
| z | 0 | x | x | x |
A controlling value dominates. 0 & anything = 0 even if the other input is
unknown, because no value of the unknown input can change the answer. Likewise 1 | x = 1. Everywhere else
the unknown leaks through and the output becomes x. Note that z on the input of a logic gate
behaves like x, never like a third logic level.控制值會壓過一切。即使另一個輸入是未知的,0 & anything = 0 仍然成立,因為未知輸入不論取什麼值都改變不了答案。同理 1 | x = 1。其他地方未知就會滲出來,輸出變成 x。注意邏輯閘輸入端的 z 行為等同於 x,絕不是第三種邏輯準位。支配値がすべてに優先します。もう一方の入力が不定でも 0 & anything = 0 は成り立ちます。不定の入力がどんな値であっても答えは変わらないからです。同様に 1 | x = 1 です。それ以外の場所では不定が漏れ出て、出力は x になります。論理ゲートの入力の z は x と同じ扱いであり、第 3 の論理レベルではない点に注意してください。
<[size]> <'base_format> <number><[位元數]> <'底數格式> <數值><[サイズ]> <'基数> <数値>
d/D decimal, h/H hex, o/O octal, b/B binarybase_format — d/D 十進、h/H 十六進、o/O 八進、b/B 二進base_format — d/D 十進、h/H 十六進、o/O 八進、b/B 二進Two rules govern what happens when size and value disagree:位元數與數值不吻合時,由兩條規則決定結果:サイズと値が食い違うときは、次の 2 つの規則が結果を決めます。
0, except that a leading
x or z extends itself.數值太短 → 左邊補 0,但是開頭若為 x 或 z 則會自我延伸。値が短すぎる → 左を 0 で埋める。ただし先頭が x または z の場合はそれ自身が拡張されます。| Literal常量リテラル | Expands to展開成展開結果 | Note說明備考 |
|---|---|---|
8'b1010 | 0000_1010 | decimal 10十進位 10十進の 10 |
6'b010111 | 01_0111 | exact fit剛好放得下ちょうど収まる |
8'b0110 | 0000_0110 | zero-padded左邊補零ゼロ埋め |
4'bx014'bx014'bx01 | xx01xx01xx01 | leading x extends開頭的 x 會延伸先頭の x が拡張される |
16'H3AB16'H3AB16'H3AB | 0000_0011_1010_1011 | |
12'd24 | 0000_0001_1000 | |
5'O36 | 11110 | octal 36 is 6 bits, truncated to 5八進位 36 佔 6 位元,被截成 5 位元八進の 36 は 6 ビットなので 5 ビットに切り詰められる |
16'Hx16'Hx16'Hx | xxxx_xxxx_xxxx_xxxxxxxx_xxxx_xxxx_xxxxxxxx_xxxx_xxxx_xxxx | x extends across all 16 bitsx 延伸填滿全部 16 個位元x が 16 ビット全体に拡張される |
8'hz8'hz8'hz | zzzz_zzzzzzzz_zzzzzzzz_zzzz | z extends tooz 也會延伸z も拡張される |
3'b5 | illegal — digit 5 is not valid in base 2不合法 — 數字 5 在二進位裡不成立不正 — 数字の 5 は 2 進では使えない | |
Verilog lets you mix all three freely inside one module. The exam habitually asks you to write the same circuit in all three.Verilog 允許在同一個模組裡自由混用這三種風格。考試很習慣要你把同一個電路用三種風格各寫一次。Verilog では 1 つのモジュール内で 3 つのスタイルを自由に混ぜられます。試験では同じ回路を 3 つのスタイルすべてで書かせるのが定番です。
| Style風格スタイル | Mechanism機制仕組み | Abstraction抽象程度抽象度 |
|---|---|---|
| 1. Behavioral1. 行為描述1. 動作記述 | procedural assignments in always/initial, with if, case, loops, timing control在 always/initial 裡的程序式賦值,搭配 if、case、迴圈與時序控制always/initial の中の手続き型代入。if、case、ループ、タイミング制御を伴う | highest最高最も高い |
| 2. RTL / dataflow2. RTL/資料流2. RTL/データフロー | continuous assign statements; combinational logic plus registers連續 assign 敘述;組合邏輯加上暫存器連続 assign 文。組合せ論理とレジスタ | middle中間中間 |
| 3. Structural3. 結構描述3. 構造記述 | instantiation of primitives, UDPs, and modules實體化原件、UDP 與模組プリミティブ・UDP・モジュールのインスタンス化 | lowest (gate and transistor)最低(閘級與電晶體級)最も低い(ゲート級・トランジスタ級) |
Problem: Write a 1-bit full adder (S, CO, A, B, CI) in behavioral, RTL, and structural
style. For the structural version, build it from two half adders and an OR gate.題目:用行為、RTL 與結構三種風格各寫一次 1 位元全加器 (S, CO, A, B, CI)。結構版請用兩個半加器加一個 OR 閘組成。問題:1 ビット全加算器 (S, CO, A, B, CI) を、動作記述・RTL・構造記述の 3 つのスタイルで書きなさい。構造記述版は半加算器 2 個と OR ゲート 1 個で構成すること。
Style 1 — Behavioral風格 1 — 行為描述スタイル 1 — 動作記述
module fa_bhv (S, CO, A, B, CI); output S, CO; input A, B, CI; reg S, CO; // required to hold values between events always @ (A or B or CI) begin S = A ^ B ^ CI; // procedural assignment CO = A & B | A & CI | B & CI; end endmodule
Style 2 — RTL / dataflow風格 2 — RTL/資料流スタイル 2 — RTL/データフロー
module fa_rtl (S, CO, A, B, CI);
output S, CO;
input A, B, CI;
assign S = A ^ B ^ CI; // continuous assignment
assign CO = A & B | A & CI | B & CI;
endmodule
Style 3 — Structural風格 3 — 結構描述スタイル 3 — 構造記述
module half_add (S, C, X, Y); output S, C; input X, Y; xor (S, X, Y); // primitive: output first, then inputs and (C, X, Y); endmodule module full_add (S, CO, A, B, CI); output S, CO; input A, B, CI; wire N1, N2, N3; or P1 (CO, N3, N2); // primitive with instance name P1 half_add HA1 (N1, N2, A, B), // module instances HA2 (S, N3, N1, CI); endmodule
Points to note. In fa_bhv, S and CO must be
reg; in fa_rtl they stay nets. All three synthesize to the same logic. In the structural
version the primitive port order is outputs first, then inputs — always. The instance name on a
primitive (P1) is optional; on a module instance it is mandatory.要注意的地方。在 fa_bhv 裡,S 與 CO 必須是 reg;在 fa_rtl 裡它們仍是 net。三者合成出來的邏輯完全相同。結構版中原件的埠順序永遠是輸出在前、輸入在後。原件實體的名稱(P1)可以省略;模組實體的名稱則是必要的。注意点。fa_bhv では S と CO を reg にしなければなりませんが、fa_rtl ではネットのままです。3 つとも同じ論理に合成されます。構造記述版では、プリミティブのポート順序は必ず出力が先、入力が後です。プリミティブのインスタンス名(P1)は省略できますが、モジュールのインスタンス名は必須です。
Hierarchy is created by module instantiation. Rules:階層是由模組實體化建立的。規則如下:階層はモジュールのインスタンス化によって作られます。規則は次のとおりです。
// by position — order must match the declaration exactly full_add FA0 (sum[0], c1, a[0], b[0], cin); // by name — order is irrelevant, far safer for wide port lists full_add FA0 (.S(sum[0]), .CO(c1), .A(a[0]), .B(b[0]), .CI(cin)); // empty port — leave an output unconnected full_add FA0 (.S(sum[0]), .CO(), .A(a[0]), .B(b[0]), .CI(cin));
When the same bit-wise operation repeats across a vector, an array of instances is more compact than writing each one out:當同一個位元運算要在整個向量上重複時,用實體陣列會比一個一個寫出來簡潔得多:同じビット単位の演算がベクタ全体で繰り返されるときは、1 つずつ書き下すよりインスタンス配列のほうがはるかに簡潔です。
wire [3:0] a, b, y;
and A[3:0] (y, a, b); // four AND gates: y[i] = a[i] & b[i]
A 16-bit ripple-carry adder built this way chains the carry through a wire vector:用這種寫法做出的 16 位元漣波進位加法器,會透過一條線向量把進位串起來:この書き方で作る 16 ビットのリップルキャリー加算器は、配線ベクタを通してキャリーを連結します。
module rca16 (sum, cout, a, b, cin); output [15:0] sum; output cout; input [15:0] a, b; input cin; wire [16:0] c; assign c[0] = cin; assign cout = c[16]; full_add FA [15:0] (sum, c[16:1], a, b, c[15:0]); endmodule
$; up to 1024 characters; the
first character must not be a digit or $.識別字可以使用字母、數字、底線與 $,最長 1024 個字元;第一個字元不可以是數字或 $。識別子には英字・数字・アンダースコア・$ が使え、長さは 1024 文字までです。先頭の文字を数字や $ にすることはできません。// to end of line, /* ... */ for blocks.註解:// 到行尾,/* ... */ 為區塊註解。コメント:// は行末まで、/* ... */ はブロックコメントです。`define state0 3'b001. That is a backtick, not an apostrophe.編譯器指令以重音符開頭 — 例如 `define state0 3'b001。那是反引號,不是單引號。コンパイラディレクティブはグレイヴアクセントで始まります — たとえば `define state0 3'b001。アポストロフィではなくバッククォートです。$ are built-in system tasks and functions —
$monitor, $time, $finish. They never synthesize.以 $ 開頭的名稱是內建的系統任務與系統函式 — $monitor、$time、$finish。它們一律不可合成。$ で始まる名前は組み込みのシステムタスク・システム関数です — $monitor、$time、$finish。いずれも合成されません。Problem: Given word = 8'b1100_0100, evaluate
(a) word[3:0], (b) word[5:1], (c) word[7:5], (d) word[9:4].
Then state the bit pattern of (e) 4'bx01 and (f) 5'O36.題目:已知 word = 8'b1100_0100,求
(a) word[3:0]、(b) word[5:1]、(c) word[7:5]、(d) word[9:4]。
再寫出 (e) 4'bx01 與 (f) 5'O36 的位元樣式。問題:word = 8'b1100_0100 のとき、
(a) word[3:0]、(b) word[5:1]、(c) word[7:5]、(d) word[9:4] を求めなさい。
さらに (e) 4'bx01 と (f) 5'O36 のビットパターンを答えなさい。
Index the vector using the declared range. With [7:0], bit 7 is the leftmost bit of
1100_0100.用宣告時的範圍去索引向量。宣告為 [7:0] 時,第 7 位元是 1100_0100 最左邊那一位。宣言した範囲に従ってベクタを添字付けします。[7:0] と宣言した場合、ビット 7 は 1100_0100 の左端のビットです。
word[3:0] = 4'b0100(a) word[3:0] = 4'b0100(a) word[3:0] = 4'b0100word[5:1] = 5'b00010 — bits 5,4,3,2,1 are 0,0,0,1,0(b) word[5:1] = 5'b00010 — 第 5,4,3,2,1 位元依序是 0,0,0,1,0(b) word[5:1] = 5'b00010 — ビット 5,4,3,2,1 は順に 0,0,0,1,0word[7:5] = 3'b110(c) word[7:5] = 3'b110(c) word[7:5] = 3'b110word[9:4] is an illegal select — index out of bounds.
Verilog returns x rather than erroring, which is exactly why you should never write it: the bug
is silent.(d) word[9:4] 是不合法的選取 — 索引超出範圍。Verilog 會回傳 x 而不是報錯,這正是絕對不該這樣寫的理由:錯誤是無聲的。(d) word[9:4] は不正な選択です — 添字が範囲外だからです。Verilog はエラーを出さずに x を返します。これこそ、こう書いてはいけない理由です。バグが表に出ません。4'bx01 = xx01 — the leading x extends to fill.(e) 4'bx01 = xx01 — 開頭的 x 會延伸填滿。(e) 4'bx01 = xx01 — 先頭の x が拡張して埋めます。5'O36: octal 3 is 011, octal 6 is 110, giving
011110, truncated from the left to 5 bits, so 11110.(f) 5'O36:八進位的 3 是 011、6 是 110,合起來是 011110,從左截成 5 位元後得到 11110。(f) 5'O36:八進の 3 は 011、6 は 110 なので 011110 となり、左から切り詰めて 5 ビットにすると 11110 です。Rule to remember: the MSB of a part-select is the leftmost index, the LSB is the rightmost.
Out of bounds returns x — avoid.要記住的規則:部分選取的 MSB 是最左邊的索引、LSB 是最右邊的。超出範圍會回傳 x — 避免這樣寫。覚えておく規則:部分選択の MSB は左端の添字、LSB は右端の添字です。範囲外は x を返すので、書かないこと。
A change in the value of a signal during simulation is an event. Simulation is event-driven if new values are computed only for signals affected by events that have already occurred, and only at those times when a change can occur.模擬過程中訊號值的一次改變稱為一個事件。若新值只為那些受已發生事件影響的訊號計算,而且只在可能發生變化的那些時刻計算,這樣的模擬就是事件驅動的。シミュレーション中に信号の値が変化することをイベントといいます。すでに発生したイベントの影響を受ける信号だけについて、しかも変化が起こりうる時刻だけで新しい値を計算するとき、そのシミュレーションはイベント駆動であるといいます。
The simulator maintains a time-ordered event list. Initial events are the input changes in the
testbench; executing them schedules further events at later times. Simulation stops when the event list
becomes empty — or when $finish is executed, whichever comes first.模擬器維護一份依時間排序的事件清單。最初的事件是測試平台中的輸入變化;執行它們會排程更晚時刻的後續事件。當事件清單變空時模擬就停止 — 或是執行到 $finish,以先發生者為準。シミュレータは時刻順のイベントリストを保持します。最初のイベントはテストベンチでの入力変化であり、それを実行するとより後の時刻に新たなイベントが登録されます。イベントリストが空になるとシミュレーションは停止します — あるいは $finish が実行されたときで、どちらか早いほうです。
With no delay specified, a gate produces its result immediately (zero response time). With a gate delay, the output is scheduled delay time units later. But Verilog gate delay is inertial, not transport, and that has a consequence that is a perennial exam question.沒有指定延遲時,閘會立即產生結果(反應時間為零)。有閘延遲時,輸出會被排程在延遲個時間單位之後。但 Verilog 的閘延遲是慣性延遲而非傳輸延遲,這件事帶來的後果是歷年必考題。遅延を指定しなければ、ゲートは即座に結果を出します(応答時間ゼロ)。ゲート遅延がある場合、出力は遅延時間単位だけ後に登録されます。ただし Verilog のゲート遅延は伝送遅延ではなく慣性遅延であり、その帰結は毎年のように試験に出ます。
Inertial delay is the amount of time an input pulse must endure for the output to respond. Verilog uses the propagation delay as the inertial delay. Consequently, multiple events cannot occur on the output in a time period shorter than the inertial delay — an input pulse narrower than the gate delay is swallowed entirely and never appears at the output.慣性延遲是輸入脈衝必須持續多久,輸出才會有反應。Verilog 直接把傳播延遲當成慣性延遲。因此,輸出上不可能在短於慣性延遲的時間內發生兩個以上的事件 — 比閘延遲還窄的輸入脈衝會被整個吞掉,根本不會出現在輸出端。慣性遅延とは、出力が反応するために入力パルスが持続していなければならない時間のことです。Verilog は伝搬遅延をそのまま慣性遅延として使います。したがって、慣性遅延より短い間隔で出力に複数のイベントが起こることはありません — ゲート遅延より狭い入力パルスは丸ごと飲み込まれ、出力には現れません。
Problem: An AND gate has 3 ns delay and an inverter has 2 ns delay. Signal
a rises at $t=0$. It feeds both an inverter and, together with the inverter's output, an AND gate, so
y = a & ~a. (a) What does the simulator produce? (b) What would the same circuit produce with zero
delay? (c) What real phenomenon does this model?題目:AND 閘延遲 3 ns,反相器延遲 2 ns。訊號 a 在 $t=0$ 上升,它同時接到反相器,並與反相器輸出一起接到 AND 閘,因此 y = a & ~a。(a) 模擬器會得到什麼?(b) 若延遲全為零,同一電路會得到什麼?(c) 這個模型對應到現實中的什麼現象?問題:AND ゲートの遅延は 3 ns、インバータの遅延は 2 ns とします。信号 a は $t=0$ で立ち上がり、インバータに入るとともに、インバータ出力と一緒に AND ゲートへ入ります。つまり y = a & ~a です。(a) シミュレータは何を出力しますか。(b) 遅延がすべてゼロなら同じ回路は何を出しますか。(c) これは現実のどんな現象のモデルですか。
(a) At $t=0$, a goes 0→1. The AND gate sees a=1 immediately, but
~a is still 1 until $t=2$ ns. So the AND input pair is (1,1) during
$0 \le t \lt 2$ ns — a 2 ns wide glitch at the AND's input. The AND has 3 ns of inertial delay.
Since $2 \lt 3$, the glitch is swallowed and y stays 0.(a) 在 $t=0$,a 由 0→1。AND 閘立刻看到 a=1,但 ~a 要到 $t=2$ ns 才變,在那之前仍是 1。所以在 $0 \le t \lt 2$ ns 期間 AND 的兩個輸入是 (1,1) — 也就是 AND 輸入端一個 2 ns 寬的突波。AND 的慣性延遲是 3 ns,因為 $2 \lt 3$,這個突波被吞掉,y 維持 0。(a) $t=0$ で a が 0→1 に変わります。AND ゲートは即座に a=1 を見ますが、~a は $t=2$ ns までまだ 1 のままです。したがって $0 \le t \lt 2$ ns の間、AND の入力対は (1,1) — AND の入力に幅 2 ns のグリッチが立ちます。AND の慣性遅延は 3 ns で $2 \lt 3$ なので、グリッチは飲み込まれ、y は 0 のままです。
(b) With zero delay, ~a updates in the same time step, the AND never sees
(1,1), and y is identically 0. Same final answer, different reason.(b) 延遲為零時,~a 在同一個時間步就更新,AND 從來不會看到 (1,1),y 恆為 0。答案相同,理由不同。(b) 遅延がゼロなら ~a は同じ時間ステップで更新されるので、AND が (1,1) を見ることはなく、y は恒等的に 0 です。答えは同じでも理由が違います。
(c) This models a static hazard (glitch) caused by unequal path delays. The
inertial-delay rule decides whether a real gate is fast enough to pass the glitch on. If the inverter delay had been
4 ns instead of 2 ns, the glitch would be 4 ns wide, exceed the AND's 3 ns inertia, and a spurious
pulse would appear on y from $t=4$ to $t=7$ ns.(c) 這是路徑延遲不相等所造成的靜態危障(突波)模型。慣性延遲規則決定了真實的閘是否快到足以把這個突波傳下去。如果反相器延遲是 4 ns 而不是 2 ns,突波就會有 4 ns 寬,超過 AND 的 3 ns 慣性,於是 y 上真的會在 $t=4$ 到 $t=7$ ns 之間出現一個假脈衝。(c) これは経路遅延の不一致による静的ハザード(グリッチ)のモデルです。慣性遅延の規則が、実際のゲートがそのグリッチを通すほど速いかどうかを決めます。インバータの遅延が 2 ns ではなく 4 ns なら、グリッチ幅は 4 ns となって AND の 3 ns の慣性を超え、y には $t=4$ から $t=7$ ns にかけて偽のパルスが実際に現れます。
| Construct語法結構構文 | Purpose用途用途 |
|---|---|
initialinitialinitial | declares a one-shot behavior — runs once, starting at time 0宣告一次性的 behavior — 從時間 0 開始,只跑一次一度だけ実行される behavior を宣言する — 時刻 0 から 1 回だけ動く |
$monitor$monitor$monitor | continuously watches its arguments; prints whenever any of them changes持續監看其引數;只要其中任何一個改變就印出引数を監視し続け、そのうちいずれかが変化するたびに出力する |
$display$display$display | prints once, immediately, when encountered被執行到時立刻印一次実行された時点で直ちに 1 回出力する |
$time$time$time | current simulation time as a 64-bit integer ($realtime for floating point)以 64 位元整數表示的目前模擬時間(浮點版為 $realtime)現在のシミュレーション時刻を 64 ビット整数で返す(浮動小数点版は $realtime) |
$stop$stop$stop | halts the simulator into interactive mode — you can still resume讓模擬器停進互動模式 — 仍可繼續執行シミュレータを対話モードで停止させる — 再開できる |
$finish$finish$finish | ends the simulation and returns control to the operating system結束模擬並把控制權交還作業系統シミュレーションを終了し、制御をオペレーティングシステムに返す |
`timescale 1ns/10ps module tb_fa; reg A, B, CI; wire S, CO; fa_rtl DUT (.S(S), .CO(CO), .A(A), .B(B), .CI(CI)); // connect by name initial $monitor("t=%0d A=%b B=%b CI=%b -> CO=%b S=%b", $time, A, B, CI, CO, S); initial begin {A,B,CI} = 3'b000; repeat (7) #10 {A,B,CI} = {A,B,CI} + 1'b1; // sweep all 8 cases #10 $finish; end endmodule
$display prints once, at the moment it is executed, and then forgets about it. $monitor needs to be called only once; after that it prints automatically whenever any signal in its argument list changes, until it is switched off or the simulation ends.$display 在被執行到的當下印一次,之後不再管。$monitor 只需要
呼叫一次,之後只要參數清單中任何一個訊號改變就自動印出,直到被關閉或模擬結束。$display は実行された瞬間に 1 回だけ出力し、その後は何もしません。$monitor は一度呼び出せば十分で、以後は引数リストのいずれかの信号が変化するたびに自動的に出力し、それが解除されるかシミュレーションが終わるまで続きます。
One subtlety of scheduling is worth remembering: within the same time step, $display executes before the non-blocking assignments complete, whereas $monitor executes at the end of that time step. The two can therefore print different values from the same piece of code — a favourite exam trap.排程上的細微差異值得記住:在同一個時間步內,$display 會在
non-blocking assignment 完成之前執行,而 $monitor 在該時間步的
最後才執行。因此同一段程式裡兩者印出的值可能不同 — 這是常考的陷阱。スケジューリング上の細かな違いを覚えておく価値があります。同じ時間ステップ内で、$display はノンブロッキング代入が完了する前に実行されるのに対し、$monitor はその時間ステップの最後に実行されます。そのため同じコードでも両者が異なる値を表示することがあり、試験で好んで問われる落とし穴です。
$fopen, $fclose, $fdisplay — behave like their C counterparts.$fopen、$fclose、$fdisplay — 行為與 C 的同名函式相同。$fopen、$fclose、$fdisplay — C の対応する関数と同じ振る舞いをします。$readmemh / $readmemb — read a text file into a 2-D array (hex or binary).
Verilog supports only 2-D arrays, so a 1024×16 RAM is
reg [15:0] RAM_1 [0:1023]; and the file has 1024 lines of 16 bits.$readmemh/$readmemb — 把文字檔讀進二維陣列(十六進位或二進位)。Verilog 只支援二維陣列,所以 1024×16 的 RAM 要寫成 reg [15:0] RAM_1 [0:1023];,而檔案有 1024 行、每行 16 個位元。$readmemh/$readmemb — テキストファイルを 2 次元配列に読み込みます(16 進または 2 進)。Verilog は2 次元配列しかサポートしないので、1024×16 の RAM は reg [15:0] RAM_1 [0:1023]; と書き、ファイルは 16 ビット 1024 行になります。| Directive指令ディレクティブ | Example範例例 | Effect作用効果 |
|---|---|---|
`timescale`timescale`timescale | `timescale 1ns/10ps`timescale 1ns/10ps`timescale 1ns/10ps | time unit / precision時間單位/精度時間単位/精度 |
`include`include`include | `include "testbench.v"`include "testbench.v"`include "testbench.v" | textual inclusion文字層級的檔案引入テキストとしての取り込み |
`default_nettype`default_nettype`default_nettype | `default_nettype wor`default_nettype wor`default_nettype wor | change the implicit net type改變隱含的 net 型別暗黙のネット型を変更する |
`define / `undef`define/`undef`define/`undef | `define wait_state 3'b010`define wait_state 3'b010`define wait_state 3'b010 | macro definition, referenced as `wait_state巨集定義,引用時寫成 `wait_stateマクロ定義。参照するときは `wait_state と書く |
Design: real hardware; every module instance exists all the time; every
module has an architecture figure — draw the figure before writing the code.
Testbench: not hardware; behavioral level; feeds input patterns and compares outputs versus time.設計端:真實硬體;每個模組實體隨時都存在;每個模組都有一張架構圖 — 先畫圖,再寫程式。
測試平台端:不是硬體;屬於行為層級;負責餵入輸入圖樣,並隨時間比對輸出。設計側:本物のハードウェア。モジュールのインスタンスは常に存在し、どのモジュールにもアーキテクチャ図がある — コードを書く前に図を描くこと。
テストベンチ側:ハードウェアではなく動作レベル。入力パターンを与え、時間に沿って出力を比較します。
| Keyword關鍵字キーワード | Meaning意義意味 |
|---|---|
wirewirewire | the default; establishes connectivity預設型別;建立連接關係既定の型。接続関係を作る |
tritritri | identical to wire, but explicitly states the net is tri-stated與 wire 完全相同,只是明確表示這條 net 會進入三態wire と同一だが、そのネットがトライステートであることを明示する |
wand / worwand/worwand/wor | wired-AND / wired-OR resolution when a net has multiple drivers當一條 net 有多個驅動源時,以 wired-AND/wired-OR 決議ネットに複数のドライバがあるとき、ワイヤード AND/ワイヤード OR で解決する |
triand / triortriand/triortriand/trior | tri-stated wired-AND / wired-OR with multiple drivers多驅動源下可進入三態的 wired-AND/wired-OR複数ドライバをもつトライステートのワイヤード AND/ワイヤード OR |
supply0 / supply1supply0/supply1supply0/supply1 | permanently connected to GND / VDD永久接到 GND/VDDGND/VDD に恒久的に接続される |
A classic tri use: O = A when E = 1, otherwise O = z. That is
exactly what the built-in primitive bufif1 does.tri 的經典用法:E = 1 時 O = A,否則 O = z。這正是內建原件 bufif1 在做的事。tri の典型的な使い方:E = 1 のとき O = A、そうでなければ O = z。これは組み込みプリミティブ bufif1 がまさに行うことです。
wire x; // scalar wand y; // wired-AND resolution wire [15:0] data; // vector; data[5] bit-select, data[5:3] part-select wire [0:7] array_a; // little-endian declaration; array_a[0:3] is the left half wire [7:0] array_2d_p [0:31]; // 32 entries of 8 bits; array_2d_p[2] is an 8-bit vector wire a = b + c; // declaration with an implicit continuous assignment
Explicitly by a continuous assignment (assign).
Implicitly by being connected to the output terminal of a primitive, or to the output port of a
module. At time 0, a driven net takes the value its drivers give it (defaulting to x); an
undriven net is z. An undeclared net defaults to type wire.顯式:由連續賦值(assign)給值。隱式:被接到某個原件的輸出端,或某個模組的輸出埠。在時間 0,有被驅動的 net 取得驅動源給的值(預設為 x);未被驅動的 net 則是 z。未宣告的 net 預設型別為 wire。明示的には連続代入(assign)によって、暗黙的にはプリミティブの出力端子やモジュールの出力ポートに接続されることによって値を得ます。時刻 0 では、駆動されているネットはドライバが与える値(既定では x)を取り、駆動されていないネットは z です。宣言されていないネットは既定で wire 型になります。
| Keyword關鍵字キーワード | Stores儲存的內容保持するもの |
|---|---|
regregreg | a logic value (4-state)一個邏輯值(四值)論理値(4 値) |
integerintegerinteger | signed integers in two's complement — 32 bits by default二補數表示的有號整數 — 預設 32 位元2 の補数表現の符号付き整数 — 既定で 32 ビット |
realrealreal | double-precision floating point倍精度浮點數倍精度浮動小数点数 |
timetimetime | 64-bit unsigned time value64 位元無號時間值64 ビット符号なしの時刻値 |
realtimerealtimerealtime | time stored as a real number以實數儲存的時間実数として保持される時刻 |
reg a, b;
reg [15:0] counter;
reg [7:0] shift_reg [0:15]; // 16-deep memory of 8-bit words
integer c;
A memory is a collection of registers — a 2-D array. Individual bits cannot be addressed directly: you must read a whole word out first.記憶體就是一群暫存器 — 一個二維陣列。不能直接定址到單一位元:必須先把整個字讀出來。メモリはレジスタの集まり、すなわち 2 次元配列です。個々のビットを直接アドレス指定することはできません。まずワード全体を読み出す必要があります。
reg [31:0] cache [0:1023]; // 1K x 32-bit memory reg [31:0] one_word; reg one_bit; one_word = cache[1022]; // legal: word select one_bit = one_word[31]; // legal: bit select on a plain reg // one_bit = cache[1022][31]; // NOT legal in Verilog-1995/2001 memories
x.在模擬中,register 變數的初值是 x。シミュレーションでは、レジスタ変数の初期値は x です。wire), which is
illegal inside a behavior — a frequent cause of "cannot assign to wire" errors.未宣告的識別字會被當成 net(wire),而這在 behavior 內是不合法的 — 這是「cannot assign to wire」錯誤的常見原因。宣言されていない識別子はネット(wire)とみなされますが、それは behavior の中では不正です — 「cannot assign to wire」エラーのよくある原因です。reg object may never be the output of a primitive gate, nor the target of a
continuous assignment.reg 物件絕對不可以是原件閘的輸出,也不可以是連續賦值的目標。reg オブジェクトは決してプリミティブゲートの出力にも、連続代入の左辺にもできません。x — silently. Avoid it.超出範圍的部分選取會無聲地回傳 x。不要這樣寫。範囲外の部分選択は何も言わずに x を返します。書かないこと。parameter size = 16; reg [size-1:0] a; // parameterised width parameter num_b = 2'b01; parameter av_delay = (min_delay + max_delay) / 2; // expression of other parameters
A parameter's value cannot change during simulation, but it can be changed at compile time by substitution:參數的值在模擬期間不能改變,但可以在編譯期以替換的方式改掉:パラメータの値はシミュレーション中に変えられませんが、コンパイル時に置き換えることはできます。
Direct substitution — defparam直接替換 — defparam直接の置き換え — defparam
module top;
adder #(.WIDTH(8)) A1 (...);
// or, the older form:
defparam A2.WIDTH = 12;
adder A2 (...);
endmodule
Indirect substitution — at instantiation間接替換 — 在實體化時指定間接的な置き換え — インスタンス化のとき
module adder (sum, a, b);
parameter WIDTH = 4;
output [WIDTH-1:0] sum;
input [WIDTH-1:0] a, b;
assign sum = a + b;
endmodule
adder #(16) A3 (s, x, y); // WIDTH = 16
They make hardware flexible (design once, reuse at many widths), make the code easier to maintain, and make it readable. In a communication IC, where the same FIR or interleaver is instantiated at several word widths, this is not a stylistic nicety — it is the difference between one module and six.參數讓硬體有彈性(設計一次,就能在多種位元寬度下重用)、讓程式好維護,也讓它易讀。在通訊 IC 裡,同一個 FIR 或交錯器常常要以好幾種字寬實體化,這時參數就不只是寫法好看的問題 — 它決定你是寫一個模組還是六個。パラメータはハードウェアに柔軟性を与え(一度設計すれば複数のビット幅で再利用できる)、コードを保守しやすく、読みやすくします。同じ FIR やインタリーバを複数のワード幅でインスタンス化する通信 IC では、これは書き方の good taste の問題ではありません — モジュールが 1 つで済むか 6 つ必要かの違いです。
Binary + - * / %; unary + -.二元 + - * / %;一元 + -。2 項 + - * / %、単項 + -。
~ & | ^ ~^ ^~. The shorter operand is zero-extended to the width of the longer.~ & | ^ ~^ ^~。較短的運算元會被補零延伸到較長者的寬度。~ & | ^ ~^ ^~。短いほうのオペランドは長いほうの幅までゼロ拡張されます。
| Expression運算式式 | Result結果結果 |
|---|---|
~(1010) | 0101 |
(01) & (11) | 01 |
(01) | (11) | 11 |
(01) ^ (11) | 10 |
(01) ~^ (11) | 01 |
Unary operators & ~& | ~| ^ ~^ ^~ that collapse a vector to a single bit.一元運算子 & ~& | ~| ^ ~^ ^~,把一個向量收縮成單一位元。単項演算子 & ~& | ~| ^ ~^ ^~ は、ベクタを1 ビットに畳み込みます。
| Expression運算式式 | Result結果結果 | Why原因理由 |
|---|---|---|
&(0101) | 0 | not all bits are 1並非所有位元都是 1すべてのビットが 1 ではない |
|(0101) | 1 | at least one bit is 1至少有一個位元是 1少なくとも 1 ビットが 1 である |
&(01xx)&(01xx)&(01xx) | 0 | a 0 is present — controlling value settles it出現了 0 — 控制值直接定案0 があるので — 支配値で決着する |
|(01xx)|(01xx)|(01xx) | 1 | a 1 is present — controlling value settles it出現了 1 — 控制值直接定案1 があるので — 支配値で決着する |
& with two operands is bitwise and returns a vector.
& with one operand is reduction and returns one bit. Same symbol, completely
different operation. &(01xx) is 0 while (01xx) & (1111) is 01xx.& 帶兩個運算元是位元運算,回傳一個向量。& 帶一個運算元是縮減運算,回傳一個位元。同一個符號,完全不同的運算。&(01xx) 是 0,而 (01xx) & (1111) 是 01xx。& はオペランドが2 つならビット演算でベクタを返し、1 つならリダクションで 1 ビットを返します。同じ記号でまったく別の演算です。&(01xx) は 0 ですが、(01xx) & (1111) は 01xx です。
! && || == != === !==. These return a single-bit truth value.! && || == != === !==。這些回傳單一位元的真假值。! && || == != === !==。いずれも 1 ビットの真偽値を返します。
| Operator運算子演算子 | Behaviour with x / z遇到 x/z 時的行為x/z があるときの振る舞い |
|---|---|
== / != | logical equality — result is x if either operand contains x or z邏輯相等 — 只要有一邊含 x 或 z,結果就是 x論理等価 — どちらかのオペランドに x や z が含まれると結果は x |
=== / !== | case equality — compares x and z literally; always returns 0 or 1, never xcase 相等 — 把 x 與 z 照字面比較;一律回傳 0 或 1,絕不會是 xケース等価 — x と z を文字どおり比較する。常に 0 か 1 を返し、x にはならない |
Only === and !== can ask "is this signal exactly x?" — and neither is
synthesizable, because real hardware has no x.只有 === 與 !== 能問「這個訊號是不是剛好等於 x?」— 而且兩者都不可合成,因為真實硬體沒有 x。「この信号はちょうど x か」と問えるのは === と !== だけです — そしてどちらも合成できません。実際のハードウェアに x は存在しないからです。
| Class類別分類 | Operators運算子演算子 | Example範例例 |
|---|---|---|
| Relational關係関係 | < <= > >= | if ((a < size-1) || (b >= 3))if ((a < size-1) || (b >= 3))if ((a < size-1) || (b >= 3)) |
| Shift位移シフト | << >> | result = (a << 3);result = (a << 3);result = (a << 3); |
| Conditional條件条件 | ? : | y = (a == b) ? a : b; |
| Concatenation串接連結 | { , } | {a,b} |
| Replication複製繰り返し | {n{ }} | {4{a}} gives {a,a,a,a}{4{a}} 得到 {a,a,a,a}{4{a}} は {a,a,a,a} になる |
{3{a}, 2{b}, 4{c}} // -> {a,a,a, b,b, c,c,c,c}
signal = (cond) ? true_expr : false_expr;
z is not allowed in the conditional expression. If the condition is
ambiguous (evaluates to x), the simulator evaluates both branches and combines
them bitwise: a bit position where both branches agree keeps that value; a position where they
disagree becomes x. It does not simply return all-x.signal = (cond) ? true_expr : false_expr;
條件運算式中不允許出現 z。若條件無法判定(求值為 x),模擬器會把兩個分支都算出來,再逐位元合併:兩個分支一致的位元保留該值,不一致的位元變成 x。它並不是直接回傳全 x。signal = (cond) ? true_expr : false_expr;
条件式に z を書くことはできません。条件があいまい(評価結果が x)の場合、シミュレータは両方の分岐を評価し、ビットごとに合成します。両分岐が一致するビットはその値を保ち、食い違うビットは x になります。単純に全ビット x を返すわけではありません。
| Precedence優先順序優先順位 | Operators運算子演算子 |
|---|---|
| Highest最高最高 | unary ! ~ + - and reduction一元 ! ~ + - 與縮減運算単項 ! ~ + - とリダクション |
* / % | |
+ - (binary)+ -(二元)+ -(2 項) | |
<< >> | |
< <= > >= | |
== != === !== | |
&, then ^ ~^, then |先 &,再 ^ ~^,最後 |まず &、次に ^ ~^、最後に | | |
&&, then ||先 &&,再 ||まず &&、次に || | |
| Lowest最低最低 | ? : |
"If unsure, use parentheses." This is not laziness — parenthesised RTL also reads better in code review and produces identical synthesis results.「不確定就加括號。」這不是偷懶 — 加了括號的 RTL 在程式審查時也更好讀,而且合成結果完全相同。「迷ったら括弧を付けよ。」これは手抜きではありません — 括弧を付けた RTL はコードレビューでも読みやすく、合成結果はまったく同じです。
Problem: Let a = 4'b1010, b = 4'b0110, c = 4'b01x0.
Evaluate:
(a) a & b, (b) &a, (c) |c, (d) a == c,
(e) a === a, (f) {2{b[1:0]}}, (g) a >> 2,
(h) (a > b) ? a : b.題目:設 a = 4'b1010、b = 4'b0110、c = 4'b01x0。求:
(a) a & b、(b) &a、(c) |c、(d) a == c、
(e) a === a、(f) {2{b[1:0]}}、(g) a >> 2、
(h) (a > b) ? a : b。問題:a = 4'b1010、b = 4'b0110、c = 4'b01x0 とします。次を評価しなさい。
(a) a & b、(b) &a、(c) |c、(d) a == c、
(e) a === a、(f) {2{b[1:0]}}、(g) a >> 2、
(h) (a > b) ? a : b。
1010 & 0110 = 4'b0010(a) 位元 AND:1010 & 0110 = 4'b0010(a) ビット単位 AND:1010 & 0110 = 4'b00101010: a 0 is present, so 1'b0(b) 1010 的縮減 AND:存在 0,所以是 1'b0(b) 1010 のリダクション AND:0 があるので 1'b001x0: a 1 is present, so 1'b1 — the
x is irrelevant because 1 is the controlling value for OR(c) 01x0 的縮減 OR:存在 1,所以是 1'b1 — x 無關緊要,因為 1 是 OR 的控制值(c) 01x0 のリダクション OR:1 があるので 1'b1 — 1 は OR の支配値なので x は影響しません== is logical equality and c contains an x, so the
result is 1'bx — not 0(d) == 是邏輯相等,而 c 含有 x,所以結果是 1'bx — 不是 0(d) == は論理等価で、c に x が含まれるため結果は 1'bx です — 0 ではありません=== is case equality: 1'b1(e) === 是 case 相等:1'b1(e) === はケース等価なので 1'b1b[1:0] = 2'b10, replicated twice: 4'b1010(f) b[1:0] = 2'b10,複製兩次:4'b1010(f) b[1:0] = 2'b10 を 2 回繰り返して 4'b10104'b0010(g) 邏輯右移,左邊補零:4'b0010(g) 論理右シフトでゼロ埋め:4'b0010a = 10, b = 6, so the condition is true and the result is
a = 4'b1010(h) a = 10、b = 6,條件成立,結果為 a = 4'b1010(h) a = 10、b = 6 なので条件は真となり、結果は a = 4'b1010The trap is (d). Comparing against a vector containing x with == gives
x, and if (x) takes the false branch. Every if whose condition can go
unknown silently falls through — this is why reset must be applied before any comparison-driven logic runs.陷阱在 (d)。用 == 去和含 x 的向量比較會得到 x,而 if (x) 走的是假分支。任何條件可能變成未知的 if 都會無聲地掉進 else — 這正是為什麼任何由比較驅動的邏輯開始運作之前,必須先做好重置。落とし穴は (d) です。x を含むベクタと == で比較すると結果は x になり、if (x) は偽の分岐を通ります。条件が不定になりうる if はすべて黙って else に落ちます — 比較で駆動される論理が動き出す前に必ずリセットをかけなければならない理由がこれです。
A primitive is a built-in logic model: and, or, nand,
nor, buf, not, xor, xnor, and the tri-state buffers
bufif0/1, notif0/1. Because the predefined set is limited, Verilog lets you define your own
with primitive … endprimitive.原件是內建的邏輯模型:and、or、nand、nor、buf、not、xor、xnor,以及三態緩衝器 bufif0/1、notif0/1。由於預先定義的種類有限,Verilog 讓你用 primitive … endprimitive 自己定義。プリミティブは組み込みの論理モデルで、and、or、nand、nor、buf、not、xor、xnor、およびトライステートバッファ bufif0/1、notif0/1 があります。定義済みの種類は限られているため、Verilog では primitive … endprimitive で自分のプリミティブを定義できます。
inout.可以有多個輸入(2、3、4、…);不可以有 inout。入力は複数(2、3、4、…)でもかまいませんが、inout は使えません。reg in a
sequential UDP.組合邏輯 UDP 的輸出埠必須是 net,序向 UDP 的輸出埠則必須是 reg。出力ポートは、組合せ論理 UDP では net、順序回路 UDP では reg でなければなりません。x.表格中沒有指定到的組合一律視為 x。テーブルで指定されていない組合せはすべて x として扱われます。and (d, a, b, c); // no instance name — legal and M1 (z2, x2, y2); // with instance name — also legal my_udp (c2, a2, b2); my_udp N1 (c1, a1, b1);
| Symbol符號記号 | Means意義意味 |
|---|---|
0 1 x | the literal logic values (note: z is not a table value)字面上的邏輯值(注意:z 不是表格值)そのままの論理値(注意:z はテーブル値ではありません) |
? | any of {0, 1, x} — a don't-care input{0, 1, x} 中的任何一個 — 代表輸入的 don't-care{0, 1, x} のいずれか — 入力のドントケア |
b | either of {0, 1}{0, 1} 中的任一個{0, 1} のいずれか |
(vw)(vw)(vw) | an input transition from v to w輸入由 v 變成 w 的轉態入力が v から w へ遷移すること |
- | no change (used in the output column of a sequential UDP)不改變(用在序向 UDP 的輸出欄)変化なし(順序回路 UDP の出力欄で使う) |
* | shorthand for (??) — any transition on that input(??) 的簡寫 — 該輸入的任意轉態(??) の略記 — その入力の任意の遷移 |
r | shorthand for (01) — rising edge(01) 的簡寫 — 上升邊緣(01) の略記 — 立ち上がりエッジ |
f | shorthand for (10) — falling edge(10) 的簡寫 — 下降邊緣(10) の略記 — 立ち下がりエッジ |
Structure: $n$ inputs, 1 output, and therefore $n+1$ columns in the table — the first $n$ are inputs, the last is the output.結構:$n$ 個輸入、1 個輸出,因此表格有 $n+1$ 欄 — 前 $n$ 欄是輸入,最後一欄是輸出。構成:入力 $n$ 個と出力 1 個なので、テーブルは $n+1$ 列になります — 先頭の $n$ 列が入力、最後の 1 列が出力です。
Boolean function out = ab + ac + bc (majority of three)布林函數 out = ab + ac + bc(三者多數決)ブール関数 out = ab + ac + bc(3 入力の多数決)
primitive boolean_func (out, a, b, c);
output out;
input a, b, c;
table
// a b c : out
0 0 ? : 0;
0 ? 0 : 0;
? 0 0 : 0;
1 1 ? : 1;
1 ? 1 : 1;
? 1 1 : 1;
endtable
endprimitive
A full 3-input table over {0,1,x} would need 27 rows. Using ?
covers the majority function in 6. The remaining combinations — those with a genuine x that
actually matters, such as (1, 0, x) — are unspecified and therefore evaluate to x,
which is the correct answer.在 {0,1,x} 上寫完整的三輸入表格需要 27 列。用 ? 只要 6 列就能涵蓋多數決函數。剩下的組合 — 那些真的有 x 且會影響結果的,例如 (1, 0, x) — 因為未指定而求值為 x,而那正是正確答案。{0,1,x} 上で 3 入力の完全なテーブルを書くと 27 行になります。? を使えば多数決関数は 6 行で表せます。残りの組合せ — (1, 0, x) のように x が実際に効いてくるもの — は未指定なので x と評価され、それがまさに正しい答えです。
Structure: $n$ inputs, plus a state and an output — so $n+2$ columns:
<n inputs> : <state> : <output = next state>. The output port must be declared
reg, and an initial statement inside the primitive may set its power-up value.結構:$n$ 個輸入,再加上一個狀態與一個輸出 — 所以有 $n+2$ 欄:<n 個輸入> : <狀態> : <輸出=次態>。輸出埠必須宣告為 reg,而原件內部的 initial 敘述可以設定它的上電初值。構成:入力 $n$ 個に状態と出力が加わるので $n+2$ 列になります:<n 個の入力> : <状態> : <出力=次状態>。出力ポートは reg と宣言する必要があり、プリミティブ内の initial 文で電源投入時の値を設定できます。
Two flavours:有兩種:2 つの種類があります。
Level-sensitive — transparent latch準位敏感 — 透通鎖存器レベルセンシティブ — 透過ラッチ
primitive latch (q, clk, d); output q; reg q; input clk, d; table // clk d : state : q(next) 0 1 : ? : 1; 0 0 : ? : 0; 1 ? : ? : -; // hold endtable endprimitive
Edge-sensitive — rising-edge D flip-flop邊緣敏感 — 上升邊緣觸發的 D 正反器エッジセンシティブ — 立ち上がりエッジ D フリップフロップ
primitive dff (q, clk, d); output q; reg q; input clk, d; table // clk d : state : q(next) (01) 0 : ? : 0; (01) 1 : ? : 1; (0x) 1 : 1 : 1; (0x) 0 : 0 : 0; (?0) ? : ? : -; // ignore falling ? (??): ? : -; // ignore data change endtable endprimitive
Combinational UDPs are synthesizable. Sequential UDPs are not — they appear in the lecture's explicit list of unsupported constructs. Use them for modelling library cells and for teaching, never in RTL you intend to hand to Design Compiler.組合邏輯 UDP 是可以合成的。序向 UDP 則不行 — 它明確列在投影片的不支援結構清單裡。序向 UDP 適合用來建立函式庫單元模型和教學,絕不要寫進打算交給 Design Compiler 的 RTL。組合せ論理 UDP は合成できます。順序回路 UDP はできません — 講義がサポート対象外として明示的に挙げている構文です。ライブラリセルのモデリングや教育目的には使えますが、Design Compiler に渡すつもりの RTL に書いてはいけません。
Problem: Write primitive mux2 (out, sel, a, b) where out = a when
sel = 0 and out = b when sel = 1. Make it handle the case where
sel is x but both data inputs agree.題目:寫出 primitive mux2 (out, sel, a, b),使 sel = 0 時 out = a、sel = 1 時 out = b。並讓它能處理 sel 為 x 但兩個資料輸入相同的情況。問題:primitive mux2 (out, sel, a, b) を書きなさい。sel = 0 のとき out = a、sel = 1 のとき out = b とします。さらに sel が x でも 2 つのデータ入力が一致する場合を扱えるようにしなさい。
primitive mux2 (out, sel, a, b); output out; input sel, a, b; table // sel a b : out 0 1 ? : 1; 0 0 ? : 0; 1 ? 1 : 1; 1 ? 0 : 0; x 0 0 : 0; // both agree — selector does not matter x 1 1 : 1; endtable endprimitive
Why the last two rows matter. Without them, sel = x falls through to "unspecified",
and the output becomes x even though both data inputs are 1. Real hardware would output 1 regardless of
the selector. Adding those rows makes the model less pessimistic and prevents spurious x
propagation through a long datapath — the practical reason UDPs exist in cell libraries.最後兩列為什麼重要。少了它們,sel = x 就會掉進「未指定」,即使兩個資料輸入都是 1,輸出仍會變成 x。真實硬體不管選擇訊號如何都會輸出 1。加上那兩列可以讓模型不那麼悲觀,避免 x 沿著長長的資料路徑虛假地傳播 — 這正是函式庫單元裡會有 UDP 的實務理由。最後の 2 行が重要な理由。これがないと sel = x は「未指定」に落ち、両方のデータ入力が 1 でも出力は x になります。実際のハードウェアはセレクタがどうであれ 1 を出します。この 2 行を加えるとモデルは過度に悲観的でなくなり、長いデータパスを通じた偽の x 伝播を防げます — セルライブラリに UDP が存在する実務上の理由です。
Note the column count: 3 inputs + 1 output = 4 columns, consistent with the $n+1$ rule for a
combinational UDP. The output is a net (no reg), as required.注意欄數:3 個輸入 + 1 個輸出 = 4 欄,符合組合邏輯 UDP 的 $n+1$ 規則。輸出依規定是 net(不是 reg)。列数に注目:入力 3 + 出力 1 = 4 列で、組合せ論理 UDP の $n+1$ の規則どおりです。出力は規定どおりネット(reg ではない)です。
specify block; describes input-to-output
paths without reference to internal structure.模組路徑延遲 — 宣告在 specify 區塊裡;描述輸入到輸出的路徑,不牽涉內部結構。モジュールパス遅延 — specify ブロックで宣言します。内部構造に触れずに入力から出力への経路を記述します。| Delay延遲遅延 | Applies to transitions適用的轉態対象となる遷移 |
|---|---|
| Rising上升立ち上がり | anything except 1 → 1, i.e. 0->1, x->1, z->1除了 1 → 1 以外的任何轉態,也就是 0->1、x->1、z->11 → 1 以外のすべて、すなわち 0->1、x->1、z->1 |
| Falling下降立ち下がり | anything except 0 → 0, i.e. 1->0, x->0, z->0除了 0 → 0 以外的任何轉態,也就是 1->0、x->0、z->00 → 0 以外のすべて、すなわち 1->0、x->0、z->0 |
| Turn-off關斷ターンオフ | anything except z → z, i.e. 0->z, 1->z, x->z除了 z → z 以外的任何轉態,也就是 0->z、1->z、x->zz → z 以外のすべて、すなわち 0->z、1->z、x->z |
and (y, x1, x2); // no delay — zero and #2 (y, x1, x2); // all transitions: 2 and #1.45 (y, x1, x2); // fractional, scaled by `timescale and #(2,3) (y, x1, x2); // rise = 2, fall = 3 bufif1 #(3,4,1) (out, in, ctrl); // rise = 3, fall = 4, turn-off = 1 bufif1 #(3:4:5, 6:7:8, 5:8:9) (out, in, ctrl); // min:typ:max for each
| Number of delays given給定的延遲個數指定した遅延の個数 | Rise上升立ち上がり | Fall下降立ち下がり | Turn-off關斷ターンオフ |
|---|---|---|---|
#d | d | d | d |
#(d1,d2) | d1 | d2 | min(d1,d2)min(d1,d2)min(d1,d2) |
#(d1,d2,d3) | d1 | d2 | d3 |
The bufif1 truth table — worth knowing because it is the basis of every tri-state bus:bufif1 的真值表 — 值得記住,因為每一條三態匯流排都建立在它之上:bufif1 の真理値表 — あらゆるトライステートバスの土台なので覚えておく価値があります。
bufif1bufif1bufif1 | ctrl=0ctrl=0ctrl=0 | ctrl=1ctrl=1ctrl=1 | ctrl=xctrl=xctrl=x | ctrl=zctrl=zctrl=z |
|---|---|---|---|---|
| in=0in=0in=0 | z | 0 | L | L |
| in=1in=1in=1 | z | 1 | H | H |
| in=xin=xin=x | z | x | x | x |
| in=zin=zin=z | z | x | x | x |
L means "0 or z", H means "1 or z" — the simulator's way of saying the output is
either driven or floating but definitely not the opposite polarity.L 代表「0 或 z」,H 代表「1 或 z」— 這是模擬器在說:輸出不是被驅動就是浮接,但絕不會是相反的極性。L は「0 または z」、H は「1 または z」を表します — 出力は駆動されているかフローティングかのどちらかであって、逆の極性には決してならない、というシミュレータの言い方です。
Delay may be attached to a net, and it adds to the gate delay of whatever drives it.延遲可以掛在 net 上,而且它會疊加到驅動它的那個閘的延遲之上。遅延はネットにも付けられ、それを駆動するもののゲート遅延に加算されます。
Gate delay only — total 5只有閘延遲 — 合計 5ゲート遅延のみ — 合計 5
module my_xor1 (y_out, a, b); output y_out; input a, b; xor #5 (y_out, a, b); endmodule
Gate + net delay — total 8閘延遲+net 延遲 — 合計 8ゲート遅延+ネット遅延 — 合計 8
module my_xor2 (y_out, a, b); output y_out; input a, b; wire #3 y_int; // net delay = 3 xor #5 (y_int, a, b); // gate delay = 5 assign y_out = y_int; endmodule
specify blocks6.3 模組路徑延遲與 specify 區塊6.3 モジュールパス遅延と specify ブロックIn a structural description, the module delay can be traced through gate and net delays. In a
behavioral description there are no gates to trace, so paths are described separately inside
specify … endspecify.在結構描述中,模組延遲可以沿著閘延遲與 net 延遲一路追蹤。但行為描述裡沒有閘可以追,所以路徑要另外寫在 specify … endspecify 之中。構造記述では、モジュールの遅延をゲート遅延とネット遅延をたどって求められます。しかし動作記述にはたどるべきゲートがないため、経路は specify … endspecify の中に別途記述します。
| Path kind路徑種類パスの種類 | Meaning意義意味 | Models對應的模型モデル対象 |
|---|---|---|
| Simple簡單路徑単純パス | unconditional direct input-to-output path無條件的輸入到輸出直達路徑条件なしで入力から出力へ直結する経路 | combinational blocks組合邏輯區塊組合せ論理ブロック |
| State-dependent狀態相依路徑状態依存パス | path exists only when a condition holds只有在某個條件成立時才存在的路徑ある条件が成り立つときだけ存在する経路 | transparent latches透通鎖存器透過ラッチ |
| Edge-dependent邊緣相依路徑エッジ依存パス | source is an edge transition of a synchronising signal起點是某個同步訊號的邊緣轉態起点が同期信号のエッジ遷移である経路 | edge-triggered flip-flops邊緣觸發正反器エッジトリガ・フリップフロップ |
specify // simple path, parallel connection (bit i to bit i) (a => y) = (3, 4); // rise = 3, fall = 4 // full connection: every bit of a to every bit of y (a *> y) = (3, 4); // named delay values specparam t_rise = 3, t_fall = 4; (b => y) = (t_rise, t_fall); // state-dependent: only while enable is high (a latch) if (enable) (data *> q) = (3, 4); // edge-sensitive: clock edge to register output (posedge clock => (q +: data)) = (5, 6); endspecify
=> versus *>, and path polarity=> 與 *>,以及路徑極性=> と *>、そしてパスの極性=> is a parallel connection: source bit $i$ to
destination bit $i$; the two must be the same width. *> is a full connection: every
source bit to every destination bit; widths may differ.=> 是平行連接:來源的第 $i$ 位元對應目的的第 $i$ 位元,兩者寬度必須相同。*> 是全連接:來源每一個位元都連到目的的每一個位元,寬度可以不同。=> は並列接続で、ソースのビット $i$ をデスティネーションのビット $i$ に対応させます。両者の幅は同じでなければなりません。*> は全結合で、ソースの全ビットをデスティネーションの全ビットに結びます。幅は異なっていてもかまいません。
Polarity operators +: and -: tell the timing engine whether the
path is non-inverting or inverting, so that a rising input maps to the correct rise/fall delay at the output.極性運算子 +: 與 -: 告訴時序引擎這條路徑是同相還是反相,這樣輸入上升時才會對應到輸出端正確的上升/下降延遲。極性演算子 +: と -: は、その経路が非反転か反転かをタイミングエンジンに伝えます。これにより入力の立ち上がりが出力側の正しい立ち上がり/立ち下がり遅延に対応づけられます。
Module paths obey inertial-delay rules too. A pulse narrower than the path delay is rejected. The
PATHPULSE$ specparam lets you separate two thresholds:模組路徑同樣遵守慣性延遲規則。比路徑延遲窄的脈衝會被排除。PATHPULSE$ 這個 specparam 讓你把兩個門檻分開:モジュールパスも慣性遅延の規則に従います。パス遅延より狭いパルスは除去されます。specparam の PATHPULSE$ を使うと、2 つのしきい値を分けて指定できます。
x,
flagging "this might be a real glitch, I cannot tell".錯誤門檻(error limit) — 介於排除門檻與錯誤門檻之間的脈衝會以 x 傳播,等於標示「這也許是真的突波,我判斷不了」。エラー限界 — リジェクト限界とエラー限界の間にあるパルスは x として伝搬し、「本物のグリッチかもしれないが判断できない」と示します。`timescale6.4 時間單位與 `timescale6.4 時間単位と `timescale`timescale <time_unit> / <precision>`timescale <時間單位> / <精度>`timescale <時間単位> / <精度>
With `timescale 10ps/1ps: one time unit is 10 ps, and all times are rounded to 1 ps
precision. So nor #3.57 (z, x1, x2) gives a delay of
$3.57 \times 10\,\text{ps} = 35.7\,\text{ps}$, rounded to 36 ps.用 `timescale 10ps/1ps 時:一個時間單位是 10 ps,所有時間都四捨五入到 1 ps 的精度。因此 nor #3.57 (z, x1, x2) 的延遲是 $3.57 \times 10\,\text{ps} = 35.7\,\text{ps}$,取整為 36 ps。`timescale 10ps/1ps の場合、1 時間単位は 10 ps で、すべての時刻は 1 ps の精度に丸められます。したがって nor #3.57 (z, x1, x2) の遅延は $3.57 \times 10\,\text{ps} = 35.7\,\text{ps}$ となり、丸めて 36 ps です。
The simulator's actual time resolution is the smallest precision declared
anywhere in the design. A single file with `timescale 1ns/1fs forces femtosecond resolution on the whole
simulation and can slow it down by orders of magnitude. Keep the timescale consistent across files.模擬器實際的時間解析度,是整個設計中任何一處宣告過的最小精度。只要有一個檔案寫了 `timescale 1ns/1fs,整個模擬就被迫用飛秒解析度,速度可能慢上好幾個數量級。請讓各檔案的 timescale 保持一致。シミュレータの実際の時間分解能は、設計中のどこかで宣言された最小の精度になります。1 つのファイルに `timescale 1ns/1fs と書いてあるだけで、シミュレーション全体がフェムト秒分解能を強いられ、速度が桁違いに落ちることがあります。ファイル間でタイムスケールをそろえてください。
Problem: Under `timescale 10ns/1ns, consider題目:在 `timescale 10ns/1ns 之下,考慮問題:`timescale 10ns/1ns のもとで次を考えます。
wire #2.5 w; and #(1.24, 3.66) G1 (w, a, b); assign y = w;
(a) What rise and fall delays does G1 use, in ns? (b) What is the net delay in ns?
(c) What is the total a-to-y rise delay? (d) If a 30 ns pulse appears at the AND
inputs, does it reach y?(a) G1 使用的上升與下降延遲各是多少 ns?(b) net 延遲是多少 ns?(c) 從 a 到 y 的總上升延遲是多少?(d) 若 AND 輸入端出現一個 30 ns 的脈衝,它會傳到 y 嗎?(a) G1 の立ち上がり遅延と立ち下がり遅延はそれぞれ何 ns ですか。(b) ネット遅延は何 ns ですか。(c) a から y までの立ち上がり遅延の合計は何 ns ですか。(d) AND の入力に 30 ns のパルスが現れたとき、それは y に届きますか。
(a) One time unit = 10 ns, precision 1 ns.
Rise: $1.24 \times 10 = 12.4$ ns, rounded to precision → 12 ns.
Fall: $3.66 \times 10 = 36.6$ ns → 37 ns.(a) 一個時間單位 = 10 ns,精度 1 ns。
上升:$1.24 \times 10 = 12.4$ ns,依精度取整 → 12 ns。
下降:$3.66 \times 10 = 36.6$ ns → 37 ns。(a) 1 時間単位 = 10 ns、精度は 1 ns です。
立ち上がり:$1.24 \times 10 = 12.4$ ns を精度に丸めて → 12 ns。
立ち下がり:$3.66 \times 10 = 36.6$ ns → 37 ns。
(b) $2.5 \times 10 = 25$ ns exactly → 25 ns.(b) $2.5 \times 10 = 25$ ns 剛好整除 → 25 ns。(b) $2.5 \times 10 = 25$ ns でちょうど割り切れます → 25 ns。
(c) Net delay adds to gate delay: $12 + 25 = $ 37 ns total rise delay from
a to y.(c) net 延遲與閘延遲相加:$12 + 25 = $ 37 ns,即 a 到 y 的總上升延遲。(c) ネット遅延はゲート遅延に加算されます:$12 + 25 = $ 37 ns が a から y までの立ち上がり遅延の合計です。
(d) Yes, but think about which delay gates it. The gate's inertial delay for a pulse is governed by
the transitions involved: the pulse must survive the rise delay of 12 ns to start, and the output pulse
then has to last long enough to fall. A 30 ns input pulse exceeds the 12 ns rise delay, so the output
begins to rise. The subsequent falling edge is scheduled 37 ns after the input falls. Since the gate is inertial,
the key comparison is pulse width (30 ns) against the delay that would suppress it — here 30 > 12, so the
pulse is not swallowed and does appear at w, then at y 25 ns later
(net delay is transport, so it never rejects anything).(d) 會,但要想清楚是哪一個延遲在把關。閘對脈衝的慣性延遲由所涉及的轉態決定:脈衝必須撐過 12 ns 的上升延遲才開始,接著輸出脈衝還要持續夠久才能落下。30 ns 的輸入脈衝超過 12 ns 的上升延遲,所以輸出開始上升。後續的下降邊緣則排程在輸入下降後的 37 ns。既然閘是慣性的,關鍵比較就是脈衝寬度(30 ns)對上會抑制它的那個延遲 — 這裡 30 > 12,所以脈衝不會被吞掉,會出現在 w,再過 25 ns 出現在 y(net 延遲是傳輸型的,永遠不排除任何東西)。(d) 届きます。ただし、どの遅延が関門になるかを考えてください。パルスに対するゲートの慣性遅延は、関係する遷移で決まります。パルスはまず 12 ns の立ち上がり遅延を生き延びる必要があり、その後、出力パルスは立ち下がれるだけの長さを保たなければなりません。30 ns の入力パルスは 12 ns の立ち上がり遅延を超えるので、出力は立ち上がり始めます。続く立ち下がりエッジは入力が立ち下がってから 37 ns 後に登録されます。ゲートは慣性的なので、鍵となる比較はパルス幅(30 ns)と、それを抑制しうる遅延との比較です — ここでは 30 > 12 なのでパルスは飲み込まれず、w に現れ、その 25 ns 後に y にも現れます(ネット遅延は伝送型なので何も除去しません)。
The point of (d): gate delay can swallow pulses; net delay never can. That is the practical difference between inertial and transport delay.(d) 的重點:閘延遲會吞掉脈衝,net 延遲永遠不會。這就是慣性延遲與傳輸延遲在實務上的差別。(d) の要点:ゲート遅延はパルスを飲み込みますが、ネット遅延は決して飲み込みません。これが慣性遅延と伝送遅延の実務上の違いです。
The IEEE Verilog standard describes syntax in Backus-Naur Form. You need to read it, not write it:IEEE Verilog 標準用 Backus-Naur Form 描述語法。你需要會讀它,不需要會寫它:IEEE Verilog 規格は構文を Backus-Naur Form で記述しています。読めれば十分で、書けるようになる必要はありません。
| Symbol符號記号 | Means意義意味 |
|---|---|
::= | is defined as定義為~と定義される |
| | alternative擇一選択肢 |
[ ... ] | appears once or not at all出現一次或完全不出現1 回現れるか、まったく現れない |
{ ... } | appears any number of times, or not at all出現任意次,或完全不出現任意の回数現れるか、まったく現れない |
For example conditional_expression ::= expression1 ? expression2 : expression3.例如 conditional_expression ::= expression1 ? expression2 : expression3。たとえば conditional_expression ::= expression1 ? expression2 : expression3 です。
Everything from the preceding sections can coexist in one module:前面各節提到的一切,都可以共存在同一個模組裡:ここまでの節で扱ったものは、すべて 1 つのモジュールの中に共存できます。
module my_module (...); assign ...; // continuous assignment and (...); // instantiation of a primitive my_udp (...); // instantiation of a UDP adder_16bits M1 (...); // instantiation of a module always @ (...) begin // behavior ... end endmodule
initial and always7.1 initial 與 always7.1 initial と alwaysinitialinitialinitial | alwaysalwaysalways | |
|---|---|---|
| Activity活動方式動作 | one-shot — runs once from time 0一次性 — 從時間 0 開始跑一次1 回限り — 時刻 0 から 1 度だけ実行する | cyclic — an infinite loop until simulation stops週期性 — 無窮迴圈,直到模擬結束繰り返し — シミュレーションが終わるまでの無限ループ |
| Triggered by觸發來源起動のきっかけ | simulation start模擬開始シミュレーションの開始 | its event control (sensitivity list)它的事件控制(敏感度列表)そのイベント制御(センシティビティリスト) |
| Synthesizable可否合成合成可否 | No — testbench only不可以 — 只用於測試平台不可 — テストベンチ専用 | Yes可以可 |
The body may be a single statement or a block statement delimited by begin …
end. Procedural statements assign values to register variables — the one exception
being force…release, which can also target nets.本體可以是單一敘述,也可以是以 begin … end 括起來的區塊敘述。程序式敘述賦值給的是register 變數 — 唯一的例外是 force…release,它也可以作用在 net 上。本体は単一の文でも、begin … end で囲んだブロック文でもかまいません。手続き文が値を代入する相手はレジスタ変数です — 唯一の例外が force…release で、これはネットも対象にできます。
initialinitialinitial
initial begin sig_a = 0; // procedural assignments sig_b = 1; // execute sequentially sig_c = 0; end
alwaysalwaysalways
always @ (b or c or d) begin
if (b == 1'b1)
a = c;
else
a = d;
end
Blocking =: an assignment completes before the next one starts.
Non-blocking <=: all right-hand sides are evaluated first, then all assignments
happen together.阻擋式 =:一個賦值完成之後,下一個才開始。
非阻擋式 <=:先把所有右式算完,然後所有賦值一起發生。ブロッキング =:1 つの代入が完了してから次が始まります。
ノンブロッキング <=:まずすべての右辺を評価し、その後すべての代入が同時に起こります。
Blocking阻擋式ブロッキング
a = 0;
a = 1;
c = a; // c = 1
Non-blocking非阻擋式ノンブロッキング
a = 0;
a <= 1;
c = a; // c = 0
In the non-blocking case, a <= 1 schedules the update for the end of the time step, so
c = a still reads the old value 0.在非阻擋式的情況下,a <= 1 把更新排到時間步的最後,所以 c = a 讀到的仍是舊值 0。ノンブロッキングの場合、a <= 1 は更新を時間ステップの最後に登録するため、c = a が読むのは古い値 0 のままです。
d <= 0; d <= 1; — is d 0 or 1? The result is
ambiguous, and therefore illegal as a modelling practice. Never assign the same variable twice
non-blockingly in one time step, and never mix = and <= on the same variable inside the
same behavior.d <= 0; d <= 1; — d 到底是 0 還是 1?結果無法確定,因此在建模實務上是不合法的。絕對不要在一個時間步內對同一個變數做兩次非阻擋式賦值,也絕對不要在同一個 behavior 裡對同一個變數混用 = 與 <=。d <= 0; d <= 1; — d は 0 でしょうか 1 でしょうか。結果はあいまいであり、モデリングの作法として不正です。1 つの時間ステップで同じ変数に 2 度ノンブロッキング代入してはいけませんし、同じ behavior の中で同じ変数に = と <= を混ぜてもいけません。
<= for sequential logic序向邏輯用 <=順序論理には <= を使うAnything inside always @ (posedge clk). Non-blocking assignments are
order-independent, which is exactly the semantics of a bank of flip-flops all clocked together.凡是寫在 always @ (posedge clk) 裡的東西都用它。非阻擋式賦值與順序無關,而這正是一整排同時被時脈打到的正反器的語意。always @ (posedge clk) の中身はすべてこれです。ノンブロッキング代入は順序に依存しないので、同じクロックで一斉に叩かれるフリップフロップ群の意味そのものになります。
= for combinational logic組合邏輯用 =組合せ論理には = を使うAnything inside always @(*). Blocking assignments let you build up an
intermediate result across several lines, which is how combinational logic reads.凡是寫在 always @(*) 裡的東西都用它。阻擋式賦值讓你可以分好幾行逐步堆出中間結果,而組合邏輯本來就該這樣讀。always @(*) の中身はすべてこれです。ブロッキング代入なら数行かけて中間結果を積み上げられ、それが組合せ論理の読み方に合っています。
A delay before the statement (#5 a = b;) suspends the activity flow,
then evaluates and assigns. A delay inside the statement (a = #5 b;) evaluates the right-hand
side now and assigns the captured value 5 units later.寫在敘述之前的延遲(#5 a = b;)會先暫停活動流程,然後才求值與賦值。寫在敘述裡面的延遲(a = #5 b;)則是現在就把右式算好,5 個單位之後才把擷取到的值寫進去。文の前に置いた遅延(#5 a = b;)は実行フローを一旦止め、それから評価して代入します。文の中に置いた遅延(a = #5 b;)は右辺を今評価し、取り込んだ値を 5 単位後に書き込みます。
Blocking, intra-assignment阻擋式、賦值內延遲ブロッキング・代入内遅延
a = #5 b; // b captured now, written at t+5; // flow resumes at t+5 c = d; // executes at t+5
Event-controlled intra-assignment以事件控制的賦值內延遲イベント制御による代入内遅延
e = @(bus) f; // f captured now, written when // bus next changes g = h; // executes after that event
With non-blocking assignment the difference becomes dramatic, because the activity flow is not suspended at all:改用非阻擋式賦值後差別更明顯,因為活動流程完全不會被暫停:ノンブロッキング代入にすると違いは劇的になります。実行フローがまったく止まらないからです。
initial begin d <= #10 0; // evaluated at t=0, scheduled for t=10 d <= #11 1; // evaluated at t=0, scheduled for t=11 d <= #12 0; // evaluated at t=0, scheduled for t=12 d <= #13 1; // evaluated at t=0, scheduled for t=13 end // all four lines execute at t=0
repeat may appear in the intra-assignment position to wait for $n$ occurrences of an event —
the idiomatic way to say "capture this now, deliver it three clocks later":repeat 可以出現在賦值內的位置,用來等待某事件發生 $n$ 次 — 這是「現在就把值抓起來,三個時脈之後再送出去」的慣用寫法:repeat は代入内の位置に書いて、あるイベントが $n$ 回起こるのを待てます — 「今の値を取り込んで、3 クロック後に出す」という定型表現です。
a = repeat (3) @(posedge clk) b; // b captured now, written on the 3rd rising edge
Not synthesizable; useful in testbenches.不可合成;在測試平台裡很好用。合成はできませんが、テストベンチでは便利です。
Two mechanisms that override normal assignment. Both are dynamic bindings, both are testbench and debugging tools, and synthesis tools might not support either.有兩種機制可以覆蓋一般的賦值。兩者都是動態繫結,都是測試平台與除錯用的工具,而且合成工具可能兩者都不支援。通常の代入を上書きする仕組みが 2 つあります。どちらも動的な束縛であり、テストベンチとデバッグのための道具で、合成ツールはどちらもサポートしない可能性があります。
assign … deassignassign … deassignassign … deassign | force … releaseforce … releaseforce … release | |
|---|---|---|
| Target作用對象対象 | register variables only只能是 register 變數レジスタ変数のみ | nets or registersnet 或 registerネットまたはレジスタ |
| Overrides覆蓋什麼何を上書きするか | all procedural assignments to that register對該 register 的所有程序式賦值そのレジスタへのすべての手続き型代入 | primitives and continuous assignments on a net; procedural assignments on a registernet 上的原件與連續賦值;register 上的程序式賦值ネット上のプリミティブと連続代入、レジスタ上の手続き型代入 |
| Released by如何解除解除の方法 | deassign, or a new PCA (deassign is optional)deassign,或另一個 PCA(deassign 可省略)deassign、または別の PCA(deassign は省略可) | release — and only releaserelease — 而且只能用 releaserelease — そして release のみ |
| Typical use典型用途典型的な用途 | level-sensitive combinational behavior, transparent latches, asynchronous control of sequential logic準位敏感的組合行為、透通鎖存器、序向邏輯的非同步控制レベルセンシティブな組合せ動作、透過ラッチ、順序論理の非同期制御 | code debugging in the testbench; works with hierarchical de-referencing測試平台中的程式除錯;可搭配階層路徑取用テストベンチでのコードデバッグ。階層パスによる参照と組み合わせられる |
assigns不要把兩種 assign 搞混2 つの assign を混同しないことA continuous assignment assign y = a & b; at module level
drives a net and is core synthesizable RTL. A procedural continuous assignment
assign inside an always block targets a register and is a simulation override.
Same keyword, different construct, opposite synthesizability.模組層級的連續賦值 assign y = a & b; 驅動的是一條 net,是核心的可合成 RTL。而 always 區塊內的程序式連續賦值 assign 作用在 register 上,是模擬時的覆蓋手段。同一個關鍵字,不同的語法結構,可合成性完全相反。モジュールレベルの連続代入 assign y = a & b; は ネットを駆動する、合成可能な RTL の中核です。一方 always ブロック内の手続き型連続代入 assign は レジスタを対象とするシミュレーション上の上書きです。同じキーワードでも別の構文であり、合成可否は正反対です。
// force/release reaching into the DUT from a testbench initial begin #100 force DUT.sig_a = 1'b1; // hierarchical de-reference to an internal node #50 force DUT.sig_b = 1'b0; #50 release DUT.sig_a; release DUT.sig_b; end // non-synthesizable
| Target對象対象 | Continuous assign連續 assign連続 assign | Procedural (always/initial)程序式(always/initial)手続き型(always/initial) | PCA assignPCA assignPCA assign | PCA forcePCA forcePCA force |
|---|---|---|---|---|
| NetNetネット | yes可以可 | no不可以不可 | no不可以不可 | yes可以可 |
| RegisterRegisterレジスタ | no不可以不可 | yes可以可 | yes可以可 | yes可以可 |
| Mechanism機制仕組み | Syntax語法構文 | Synthesizable?可合成?合成可能か |
|---|---|---|
| Delay control延遲控制遅延制御 | #10 a = b; | no不可以不可 |
| Event control事件控制イベント制御 | @(posedge clk) a = b;@(posedge clk) a = b;@(posedge clk) a = b; | yes (as a clocked behavior)可以(作為時脈驅動的 behavior)可(クロック同期の behavior として) |
Event or事件 orイベントの or | @(posedge clk or negedge rst)@(posedge clk or negedge rst)@(posedge clk or negedge rst) | yes可以可 |
| Named event具名事件名前付きイベント | event e; -> e; @(e) ...event e; -> e; @(e) ...event e; -> e; @(e) ... | no不可以不可 |
waitwaitwait | wait (enable) data_out = data_in;wait (enable) data_out = data_in;wait (enable) data_out = data_in; | no不可以不可 |
posedge and negedge — exact definitionsposedge 與 negedge — 精確定義posedge と negedge — 正確な定義posedge: 0->1, 0->x, x->1
negedge: 1->0, 1->x, x->0posedge:0->1、0->x、x->1
negedge:1->0、1->x、x->0posedge:0->1、0->x、x->1
negedge:1->0、1->x、x->0
The transitions through x are the reason a simulation can appear to clock itself during the
unknown-value startup phase before reset is applied.會經過 x 的那些轉態,正是為什麼在重置生效之前那段值都未知的啟動階段,模擬看起來像是會自己打時脈。x を経由する遷移があるからこそ、リセットがかかる前の値が不定な起動段階では、シミュレーションが勝手にクロックを刻んでいるように見えるのです。
or — a D flip-flop with asynchronous active-low set and reset事件 or — 帶非同步低態有效 set 與 reset 的 D 正反器イベントの or — 非同期・負論理のセットとリセットを持つ D フリップフロップalways @ (posedge clk or negedge set or negedge rst) begin
if (rst == 0)
q = 1'b0; // asynchronous reset — highest priority
else if (set == 0)
q = 1'b1; // asynchronous set
else if (clk == 1)
q = data_in; // synchronous branch — must be last
else
q = q;
end
When the event control is sensitive to the edge of more than one signal, an
if statement must be the first statement in the behavior, and the synchronizing signal is not
tested explicitly — by default the last branch describes the synchronous activity. This
ordering is how the synthesis tool knows which signals are asynchronous controls (which map to the flip-flop's
set/reset pins) and which is the clock. Get the order wrong and you get either a synthesis error or an unintended
priority structure.當事件控制對一個以上訊號的邊緣敏感時,if 敘述必須是 behavior 的第一個敘述,而且不能顯式地測試同步訊號 — 依慣例由最後一個分支來描述同步行為。這個順序正是合成工具用來判斷哪些訊號是非同步控制(對應到正反器的 set/reset 接腳)、哪一個才是時脈的依據。順序寫錯,得到的不是合成錯誤,就是一個你沒打算要的優先權結構。イベント制御が複数の信号のエッジに反応する場合、if 文は behavior の最初の文でなければならず、同期信号を明示的に判定してはいけません — 既定では最後の分岐が同期動作を表します。この順序こそ、合成ツールがどの信号を非同期制御(フリップフロップの set/reset ピンに対応)とみなし、どれをクロックとみなすかの手がかりです。順序を間違えると、合成エラーになるか、意図しない優先順位構造ができます。
waitwaitwaitdata_out = 0;
wait (enable) data_out = data_in; // suspend until enable is true
wait is level-sensitive (unlike @, which is edge/change sensitive) and is
not synthesizable.wait 是準位敏感的(不像 @ 是邊緣/變化敏感),而且不可合成。wait はレベルセンシティブで(エッジ・変化に反応する @ とは異なります)、合成できません。
event trigger; // declared only within a module always @ (posedge clk) -> trigger; // event-trigger operator always @ (trigger) $display("fired at %0d", $time);
Named events synchronize activity within and between modules; they can be referenced from other modules by hierarchical de-referencing. Not synthesizable.具名事件用來在模組內部與模組之間同步活動;可以由其他模組透過階層路徑引用。不可合成。名前付きイベントは、モジュール内およびモジュール間で動作を同期させるために使い、他のモジュールから階層パスで参照できます。合成はできません。
Available constructs: the conditional operator ?:; case, casex,
casez; if…else; loops repeat, for,
while, forever; disable; and fork…join.可用的語法結構:條件運算子 ?:;case、casex、casez;if…else;迴圈 repeat、for、while、forever;disable;以及 fork…join。使える構文:条件演算子 ?:、case・casex・casez、if…else、ループの repeat・for・while・forever、disable、そして fork…join。
case and its variantscase 及其變體case とその派生| Statement敘述文 | Matching behavior比對行為照合の振る舞い |
|---|---|
casecasecase | requires a complete bitwise match; expression and case item must have the same bit length; x and z must match literally要求逐位元完全相符;運算式與 case 項目的位元長度必須相同;x 與 z 必須照字面相符ビットごとの完全一致を要求する。式と case 項のビット長は同じでなければならず、x と z は文字どおり一致する必要がある |
casezcasezcasez | ignores bit positions that contain z; ? may be used as a don't-care忽略含 z 的位元位置;可以用 ? 當作 don't-carez を含むビット位置を無視する。? をドントケアとして使える |
casexcasexcasex | ignores bit positions that contain x or z; ? may also be used忽略含 x 或 z 的位元位置;同樣可以用 ?x または z を含むビット位置を無視する。? も使える |
If the case list is incomplete, synthesis infers a latch to hold the
unassigned value — an uncontrollable element that breaks static timing analysis and scan test. Always finish with
default. Section 10.3 shows the synthesized result.如果 case 清單不完整,合成會推論出一個鎖存器來保住沒被賦值的那個值 — 那是個無法控制的元件,會破壞靜態時序分析與掃描測試。一律用 default 收尾。10.3 節會給出合成結果。case のリストが不完全だと、合成は代入されなかった値を保持するためにラッチを推論します — 制御できない素子であり、静的タイミング解析とスキャンテストを壊します。必ず default で締めてください。合成結果は 10.3 節に示します。
if…elseif…elseif…else{0, x, z}.真就是數值 1。假則是 {0, x, z} 中的任何一個。真は数値の 1 です。偽は {0, x, z} のいずれかです。else pairs with the nearest if. Use
begin…end when nesting to make the intent explicit.懸空的 else 會配給最近的 if。巢狀時請用 begin…end 把意圖寫清楚。宙に浮いた else はいちばん近い if と結び付きます。入れ子にするときは begin…end で意図を明示してください。repeat — fixed countrepeat — 固定次數repeat — 回数固定
parameter memory_size = 1024;
integer i;
initial begin
i = 0;
repeat (memory_size) begin
mem[i] = 0;
i = i + 1;
end
end
for — the synthesizable workhorsefor — 可合成的主力for — 合成できる主力
integer k;
always @ (a or b) begin
for (k = 0; k < 8; k = k + 1)
y[k] = a[k] & b[k];
end
// unrolls into 8 AND gates
whilewhilewhile
while (count < limit) begin ... count = count + 1; end
forever — clock generatorforever — 時脈產生器forever — クロック発生器
initial begin
clk = 0;
forever #5 clk = ~clk; // 10-unit period
end
always is a module-level behavior. It runs in parallel with the other always/initial blocks as a thread of its own, and it is synthesizable.always 是模組層級的 behavior,和其他 always/initial
平行執行,自己就是一個執行緒;可以合成。always はモジュールレベルの behavior で、他の always/initial と並行に動く独立したスレッドです。合成できます。forever is a statement-level loop. It must sit inside an initial or always block and cannot stand alone, and it is not synthesizable.forever 是敘述層級的迴圈,必須寫在 initial 或 always
裡面,不能單獨存在;不可合成。forever は文レベルのループで、initial か always の中に書く必要があり、単独では存在できません。合成はできません。forever contains no timing control (# or @), the simulation loops forever at the same instant and hangs. The same is true of always — always a = ~a; locks the simulator up.關鍵陷阱:forever 內若沒有任何時間控制(# 或 @),模擬會在同一個時間點
無限迴圈而卡死。always 也一樣 — always a = ~a; 會鎖死模擬器。重要な落とし穴:forever の中にタイミング制御(# や @)がないと、シミュレーションは同じ時刻で無限にループしてハングします。always も同様で、always a = ~a; はシミュレータを固めます。disable terminates only the named block or task you point it at. The rest of the behavior keeps running and simulation time keeps advancing — the equivalent of C's break or an early return. $finish ends the whole simulation and returns control to the operating system. $stop merely pauses into interactive mode, and you can resume afterwards.disable 只終止指定的具名區塊或 task,其餘的
behavior 繼續跑,模擬時間繼續前進 — 相當於 C 的 break/提早 return。
$finish 結束整個模擬並把控制權交回作業系統。
$stop 則是暫停進入互動模式,之後還能繼續。disable は指定した名前付きブロックまたは task だけを終了させます。behavior の残りは動き続け、シミュレーション時間も進みます — C の break や早期 return に相当します。$finish はシミュレーション全体を終了し、制御をオペレーティングシステムに返します。$stop は対話モードで一時停止するだけで、後から再開できます。
begin : search_block // named block for (i = 0; i < 16; i = i + 1) if (mem[i] == target) begin found = 1; disable search_block; // break out early end end
fork…join and race conditions7.7 fork…join 與競爭條件7.7 fork…join と競合状態begin…endbegin…endbegin…end | fork…joinfork…joinfork…join |
|---|---|
| statements execute sequentially敘述依序執行文は順番に実行される | statements execute in parallel, as independent threads敘述平行執行,各自是獨立的執行緒文は独立したスレッドとして並行に実行される |
| finishes when the last statement finishes最後一個敘述結束時就結束最後の文が終わった時点で終了する | finishes when all threads have completed所有執行緒都完成時才結束すべてのスレッドが完了した時点で終了する |
| synthesizable可合成合成可能 | not supported by synthesis tools合成工具不支援合成ツールは非対応 |
There is no ordering among the threads, so interaction between them can create ambiguity.執行緒之間沒有先後順序,所以它們一旦互動就可能產生無法確定的結果。スレッド間に順序関係がないため、互いに影響し合うとあいまいさが生じ得ます。
Race condition有競爭條件競合状態あり
fork
a = 1;
b = a; // is b 1 or the old a?
join
No race condition沒有競爭條件競合状態なし
fork
a = 1;
#1 b = a; // ordering is now explicit
join
The target signal becomes ambiguous when different assignment statements occur simultaneously and the language does not define their order. The two classic cures: impose a delay, or use non-blocking assignments so that all reads happen before all writes.當不同的賦值敘述同時發生,而語言又沒有定義它們的先後順序時,目標訊號就變得無法確定。兩種經典解法:加上延遲,或改用非阻擋式賦值,讓所有讀取都發生在所有寫入之前。異なる代入文が同時に起こり、言語がその順序を定義していないとき、対象の信号はあいまいになります。古典的な対処は 2 つ:遅延を入れるか、ノンブロッキング代入を使ってすべての読み出しをすべての書き込みより先に済ませるかです。
Within one simulation time step, the simulator performs these steps in this order:在一個模擬時間步之內,模擬器依照這個順序執行下列步驟:1 つのシミュレーション時間ステップの中で、シミュレータはこの順序で次の処理を行います。
$monitor.
($display executes when it is encountered — that is, before the non-blocking
assignments.)執行 $monitor。($display 是在被執行到的當下就跑 — 也就是在非阻擋式賦值之前。)$monitor を実行する。($display は出会った時点で実行される — つまりノンブロッキング代入より前です。)When an exam asks "what does $display print, and what does
$monitor print, at time 10?", the answer is always read off this ordering: $display sees the
pre-non-blocking values, $monitor sees the settled end-of-step values.當考題問「在時間 10 時 $display 印什麼、$monitor 又印什麼?」,答案永遠是照這個順序讀出來的:$display 看到的是非阻擋式賦值之前的值,$monitor 看到的是時間步結束後穩定下來的值。試験で「時刻 10 で $display は何を表示し、$monitor は何を表示するか」と問われたら、答えは常にこの順序から読み取れます。$display が見るのはノンブロッキング代入前の値、$monitor が見るのはステップ終了時の確定値です。
Problem: Work out the $monitor output of this module.題目:推導出這個模組的 $monitor 輸出。問題:このモジュールの $monitor の出力を求めなさい。
module blocking_nonblocking ();
reg a, b, c, d;
initial begin initial begin
#10 a = 0; c = #10 0;
#11 a = 1; c = #11 1;
#12 a = 0; c = #12 0;
#13 a = 1; c = #13 1;
end end
initial begin initial begin
#10 b <= 0; d <= #10 0;
#11 b <= 1; d <= #11 1;
#12 b <= 0; d <= #12 0;
#13 b <= 1; d <= #13 1;
end end
initial begin
$monitor("TIME = %d A = %b B = %b C = %b D = %b", $time, a, b, c, d);
#50 $finish;
end
endmodule
Analyse each block separately.逐個區塊分析。ブロックごとに分析します。
a — delay control before a blocking assignment. Each #n suspends the flow, so
the delays accumulate: assignments land at
$t = 10,\; 21,\; 33,\; 46$.a — 阻擋式賦值前的延遲控制。每個 #n 都會暫停流程,所以延遲會累加:賦值分別落在 $t = 10,\; 21,\; 33,\; 46$。a — ブロッキング代入の前の遅延制御。それぞれの #n が実行フローを止めるので、遅延は累積します。代入は $t = 10,\; 21,\; 33,\; 46$ に着地します。
b — delay control before a non-blocking assignment. The #n is still a delay
control on the activity flow, so the flow is suspended exactly as for a. Once the flow resumes, the
non-blocking assignment lands at the end of that same time step. Times are therefore identical to
a: $10, 21, 33, 46$.b — 非阻擋式賦值前的延遲控制。#n 仍然是作用在活動流程上的延遲控制,所以流程暫停的方式和 a 完全一樣。流程恢復後,非阻擋式賦值落在同一個時間步的末尾。因此時間點與 a 完全相同:$10, 21, 33, 46$。b — ノンブロッキング代入の前の遅延制御。#n は依然として実行フローに対する遅延制御なので、フローの停止のしかたは a とまったく同じです。フローが再開すると、ノンブロッキング代入はその同じ時間ステップの終わりに着地します。したがって時刻は a と同一で $10, 21, 33, 46$ です。
c — intra-assignment delay with blocking assignment. The RHS is evaluated immediately, but
the statement still blocks for n units before assigning and before the next statement starts.
So the delays accumulate again: $10, 21, 33, 46$. Same as a and b.c — 阻擋式賦值搭配賦值內延遲。右式立刻求值,但敘述仍會阻擋 n 個單位之後才賦值,也才輪到下一個敘述。所以延遲又累加起來:$10, 21, 33, 46$。與 a、b 相同。c — ブロッキング代入と代入内遅延。右辺は直ちに評価されますが、文は依然として n 単位だけブロックしてから代入し、その後に次の文へ進みます。よって遅延はまた累積し、$10, 21, 33, 46$ です。a・b と同じになります。
d — intra-assignment delay with non-blocking assignment. Non-blocking does not suspend the activity flow. All four statements execute at $t = 0$, each capturing its RHS immediately and scheduling the write independently. Assignments therefore land at $t = 10,\; 11,\; 12,\; 13$ — not accumulated.d — 非阻擋式賦值搭配賦值內延遲。非阻擋式不會暫停活動流程。四個敘述全都在 $t = 0$ 執行,各自立刻擷取自己的右式,並各自獨立地排程寫入。因此賦值落在 $t = 10,\; 11,\; 12,\; 13$ — 不會累加。d — ノンブロッキング代入と代入内遅延。ノンブロッキングは実行フローを止めません。4 つの文はすべて $t = 0$ で実行され、それぞれ直ちに右辺を取り込み、独立に書き込みを登録します。したがって代入は $t = 10,\; 11,\; 12,\; 13$ に着地し、累積しません。
| Time時間時刻 | A | B | C | D | What happened發生了什麼起きたこと |
|---|---|---|---|---|---|
| 0 | x | x | x | x | registers power up unknown暫存器上電時為未知レジスタは電源投入時に不定 |
| 10 | 0 | 0 | 0 | 0 | all four first assignments coincide四個區塊的第一次賦值同時發生4 ブロックの最初の代入が同時に起こる |
| 11 | 0 | 0 | 0 | 1 | only d's second assignment只有 d 的第二次賦值d の 2 回目の代入だけ |
| 12 | 0 | 0 | 0 | 0 | only d只有 dd だけ |
| 13 | 0 | 0 | 0 | 1 | only d — d is now finished只有 d — d 到此結束d だけ — d はこれで終わり |
| 21 | 1 | 1 | 1 | 1 | a, b, c second assignments (10+11)a、b、c 的第二次賦值(10+11)a・b・c の 2 回目の代入(10+11) |
| 33 | 0 | 0 | 0 | 1 | third assignments (21+12)第三次賦值(21+12)3 回目の代入(21+12) |
| 46 | 1 | 1 | 1 | 1 | fourth assignments (33+13)第四次賦值(33+13)4 回目の代入(33+13) |
The lesson. Three of the four blocks behave identically. Only the combination of
non-blocking assignment and intra-assignment delay decouples the schedule from the activity flow —
because that is the only case where the statement does not suspend the thread. This is why
d <= #5 x; is the correct idiom for modelling clock-to-Q delay in a flip-flop, and
#5 d <= x; is not.教訓。四個區塊裡有三個行為完全相同。唯有非阻擋式賦值加上賦值內延遲的組合,才能把排程與活動流程脫鉤 — 因為那是唯一一種敘述不會暫停執行緒的情況。這正是為什麼模擬正反器的 clock-to-Q 延遲時,d <= #5 x; 才是正確的寫法,#5 d <= x; 不是。教訓。4 つのブロックのうち 3 つはまったく同じ振る舞いをします。スケジュールを実行フローから切り離せるのは、ノンブロッキング代入と代入内遅延の組合せだけです — 文がスレッドを止めない唯一の場合だからです。フリップフロップのクロック-Q 遅延をモデル化するとき d <= #5 x; が正しい書き方で、#5 d <= x; がそうでない理由がこれです。
Problem: You want to swap a and b on every rising clock edge.
Consider three attempts. Which work, and what does each synthesize to?題目:你想在每個時脈上升邊緣交換 a 與 b。考慮以下三種寫法。哪些行得通?各自又會合成出什麼?問題:クロックの立ち上がりごとに a と b を入れ替えたいとします。3 つの書き方を考えます。どれが正しく、それぞれ何に合成されますか。
// Attempt 1 // Attempt 2 // Attempt 3 always @(posedge clk) begin always @(posedge clk) begin always @(posedge clk) a = b; a <= b; a <= b; b = a; b <= a; always @(posedge clk) end end b <= a;
Attempt 1 — broken. Blocking assignments complete in order. After a = b,
a already holds b's value, so b = a writes b's own value back. Both registers end up
holding the old b. Synthesis produces two flip-flops both fed from b — a copy, not a
swap.寫法 1 — 錯誤。阻擋式賦值會依序完成。a = b 之後 a 已經是 b 的值,所以 b = a 只是把 b 自己的值寫回去。兩個暫存器最後都拿到舊的 b。合成出來是兩個都由 b 餵入的正反器 — 這是複製,不是交換。書き方 1 — 誤り。ブロッキング代入は順番に完了します。a = b の後 a はすでに b の値なので、b = a は b 自身の値を書き戻すだけです。両方のレジスタが古い b を保持して終わります。合成すると、どちらも b から入力される 2 つのフリップフロップになります — 入れ替えではなく複製です。
Attempt 2 — correct. Both right-hand sides are evaluated first (capturing the old
a and old b), then both assignments occur. This is exactly the behavior of two flip-flops
whose D inputs are cross-connected to each other's Q. The swap works.寫法 2 — 正確。兩個右式先被求值(擷取舊的 a 與舊的 b),然後兩個賦值一起發生。這正是兩個 D 輸入互相交叉接到對方 Q 的正反器的行為。交換成功。書き方 2 — 正しい。まず両方の右辺が評価され(古い a と古い b を取り込み)、その後で両方の代入が起こります。これは D 入力を互いの Q に交差接続した 2 つのフリップフロップの動作そのものです。入れ替えは成功します。
Attempt 3 — also correct. Two separate behaviors, each non-blocking. Because non-blocking
assignments are order-independent, it does not matter which always block the simulator
happens to evaluate first. This is precisely why the lecture recommends non-blocking assignments for FSM and
sequential code: it removes the dependence on evaluation order between behaviors.寫法 3 — 同樣正確。兩個獨立的 behavior,各自用非阻擋式。因為非阻擋式賦值與順序無關,模擬器先算哪一個 always 區塊都無所謂。這正是投影片建議 FSM 與序向程式碼一律使用非阻擋式賦值的理由:它消除了 behavior 之間對求值順序的依賴。書き方 3 — これも正しい。独立した 2 つの behavior が、それぞれノンブロッキング代入を使っています。ノンブロッキング代入は順序に依存しないので、シミュレータがどちらの always を先に評価しても関係ありません。FSM や順序回路のコードにノンブロッキング代入が推奨される理由はまさにこれで、behavior 間の評価順序への依存がなくなるからです。
The general rule. If two registers are updated in the same clock domain and either depends on the other, blocking assignment makes the result depend on textual order — a race. Non-blocking assignment makes the result match the hardware.通則。如果兩個暫存器在同一個時脈域內更新,而且其中一個依賴另一個,那麼阻擋式賦值會讓結果取決於文字順序 — 這就是競爭。非阻擋式賦值則讓結果與硬體一致。一般則。同じクロックドメインで更新される 2 つのレジスタが互いに依存している場合、ブロッキング代入では結果が記述順に左右されます — それが競合です。ノンブロッキング代入なら結果はハードウェアと一致します。
Both let you call a common procedure from several places and both improve readability. The differences are mechanical and heavily examined:兩者都讓你從多個地方呼叫同一段共用流程,也都能改善可讀性。差別是機械式的,而且是考試重點:どちらも共通の処理を複数の場所から呼び出せるようにし、可読性も高めます。違いは形式的なものですが、試験で頻出です。
task … endtasktask … endtasktask … endtask | function … endfunctionfunction … endfunctionfunction … endfunction | |
|---|---|---|
| Arguments引數引数 | zero or more, of type input, output, or inout零個或多個,型別可為 input、output 或 inout0 個以上。型は input、output、inout のいずれか | at least one input; no output or inout至少一個 input;不可以有 output 或 inoutinput が少なくとも 1 つ必要。output と inout は不可 |
| Returns回傳值戻り値 | nothing — passes values back through output/inout沒有 — 透過 output/inout 把值帶回去なし — output/inout を通して値を返す | always a single value, through its own name永遠是單一個值,透過自己的名稱回傳常に 1 つの値を、自分自身の名前を通して返す |
| Timing control時序控制タイミング制御 | may contain # and @可以包含 # 與 @# と @ を含められる | must not contain any一律不可包含一切含めてはならない |
| Simulation time模擬時間シミュレーション時間 | may consume non-zero time可以耗掉非零的時間ゼロでない時間を消費してよい | always executes in zero time永遠在零時間內執行完常にゼロ時間で実行される |
| Called from從哪裡呼叫呼び出し元 | a procedural statement程序式敘述手続き文 | an expression — e.g. the RHS of a continuous assignment運算式 — 例如連續賦值的右式式 — たとえば連続代入の右辺 |
| Models可建模的對象モデル化できるもの | anything任何東西何でも | combinational behavior only只有組合行為組合せ動作のみ |
Task — can have multiple outputstask — 可以有多個輸出task — 出力を複数持てる
task full_adder;
input a, b, cin;
output sum, cout;
begin
sum = a ^ b ^ cin;
cout = (a & b) | (a & cin) | (b & cin);
end
endtask
always @ (a or b or cin)
full_adder (a, b, cin, s, co);
Function — returns one valuefunction — 回傳一個值function — 値を 1 つ返す
function [3:0] add4;
input [3:0] x, y;
begin
add4 = x + y; // assign to the function name
end
endfunction
assign sum = add4(a, b); // called in an expression
A Linear Feedback Shift Register is the standard binary pattern generator for self-testing circuits, and in a communication IC it is also the scrambler and the PRBS source. The lecture's structure:線性回授移位暫存器是自我測試電路的標準二元圖樣產生器,在通訊 IC 裡它同時也是擾碼器與 PRBS 源。投影片給的結構是:線形帰還シフトレジスタは自己テスト回路の標準的な 2 値パターン発生器であり、通信 IC ではスクランブラや PRBS 源でもあります。講義が示す構成は次のとおりです。
module lfsr (Y, clk, rst); parameter N = 8; parameter TAPS = 8'b1000_1110; // C[N-1:0], the characteristic polynomial output [N-1:0] Y; input clk, rst; reg [N-1:0] Y; function [N-1:0] next_state; input [N-1:0] y; integer j; begin next_state[N-1] = y[0]; // C_N = 1 always for (j = 1; j <= N-1; j = j + 1) next_state[j-1] = TAPS[j] ? (y[j] ^ y[0]) : y[j]; end endfunction always @ (posedge clk or posedge rst) if (rst) Y <= {N{1'b1}}; // must never be all-zero else Y <= next_state(Y); endmodule
The next-state computation is pure combinational logic returning one value, evaluated in
zero time, and it is used on the right-hand side of an assignment. That is the exact profile of a function. Writing it
as a task would force it into a procedural statement and lose the ability to write
Y <= next_state(Y); in one line.次態的計算是純組合邏輯,回傳單一個值,在零時間內完成,而且用在賦值的右式。這完全符合 function 的輪廓。如果寫成 task,就會被迫變成程序式敘述,也就寫不出 Y <= next_state(Y); 這樣的一行了。次状態の計算は純粋な組合せ論理で、値を 1 つ返し、ゼロ時間で評価され、代入の右辺で使われます。これはまさに function の輪郭です。task として書くと手続き文に押し込められ、Y <= next_state(Y); と 1 行で書けなくなります。
| Static timing analysis (STA)靜態時序分析(STA)静的タイミング解析(STA) | Dynamic timing analysis動態時序分析動的タイミング解析 | |
|---|---|---|
| Method方法手法 | no simulation — analyses the netlist graph不做模擬 — 直接分析網表構成的圖シミュレーションせず、ネットリストのグラフを解析する | simulation-based以模擬為基礎シミュレーションに基づく |
| Coverage涵蓋範圍カバレッジ | considers all paths, including false paths that can never be exercised考慮所有路徑,包括永遠不可能被觸發的偽路徑すべての経路を考慮する。決して活性化されない false path も含む | only paths the input stimulus actually exercises只有輸入激勵實際走到的路徑入力刺激が実際に通した経路だけ |
| Risk風險リスク | pessimistic — reports violations on paths that do not matter偏悲觀 — 會在無關緊要的路徑上報違規悲観的 — 問題にならない経路でも違反を報告する | optimistic — can miss violations if the stimulus is incomplete偏樂觀 — 激勵不完整時可能漏掉違規楽観的 — 刺激が不十分だと違反を見逃しうる |
| False paths偽路徑false path | reported; must be excluded manually會被報出來;必須手動排除報告される。手動で除外する必要がある | not reported不會被報出來報告されない |
Slack $\ge 0$: the path meets its timing budget — good.
Slack $< 0$: the path violates the budget — bad. This is the single number synthesis is
optimising, and the reason the tool restructures your logic.Slack $\ge 0$:這條路徑符合時序預算 — 好。
Slack $< 0$:這條路徑違反預算 — 不好。這就是合成在最佳化的那一個數字,也是工具會去重構你的邏輯的原因。スラック $\ge 0$:その経路はタイミング予算を満たしています — 良好。
スラック $< 0$:予算を超過しています — 不良。合成が最適化しているのはこの 1 つの数字であり、ツールがあなたの論理を作り替える理由でもあります。
Problem: A combinational path runs from a launching flip-flop through three gates with delays 1.2 ns, 0.8 ns, and 1.5 ns to a capturing flip-flop. Clock-to-Q of the launching FF is 0.4 ns; the setup time of the capturing FF is 0.3 ns. The clock period is 4 ns with zero skew. (a) Compute the arrival time, required arrival time, and slack. (b) What is the maximum clock frequency? (c) If synthesis reports slack of $-0.6$ ns, name two things you could change in the RTL.題目:有一條組合路徑,從發射端正反器出發,經過延遲 1.2 ns、0.8 ns、1.5 ns 的三個閘,到達接收端正反器。發射端正反器的 clock-to-Q 為 0.4 ns;接收端正反器的 setup 時間為 0.3 ns。時脈週期 4 ns,skew 為零。 (a) 求 arrival time、required arrival time 與 slack。(b) 最高時脈頻率是多少?(c) 若合成回報 slack 為 $-0.6$ ns,請舉出兩個你可以在 RTL 層改動的地方。問題:ある組合せ経路が、送出側フリップフロップから遅延 1.2 ns・0.8 ns・1.5 ns の 3 つのゲートを通って受け側フリップフロップに至ります。送出側のクロック-Q は 0.4 ns、受け側のセットアップ時間は 0.3 ns、クロック周期は 4 ns でスキューはゼロです。 (a) 到達時刻・要求到達時刻・スラックを求めなさい。(b) 最大クロック周波数はいくらですか。(c) 合成がスラック $-0.6$ ns を報告した場合、RTL で変えられることを 2 つ挙げなさい。
(a) Arrival time at the D pin of the capturing flip-flop:(a) 資料抵達接收端正反器 D 腳的時刻:(a) 受け側フリップフロップの D ピンへの到達時刻:
$$t_{\text{arrival}} = t_{\text{CQ}} + \sum t_{\text{gate}} = 0.4 + (1.2 + 0.8 + 1.5) = 3.9\ \text{ns}$$$$t_{\text{arrival}} = t_{\text{CQ}} + \sum t_{\text{gate}} = 0.4 + (1.2 + 0.8 + 1.5) = 3.9\ \text{ns}$$$$t_{\text{arrival}} = t_{\text{CQ}} + \sum t_{\text{gate}} = 0.4 + (1.2 + 0.8 + 1.5) = 3.9\ \text{ns}$$Required arrival time, i.e. the latest the data may arrive and still be captured:required arrival time,也就是資料最晚可以在什麼時候抵達而仍能被擷取:要求到達時刻、すなわちデータが到着してもまだ取り込める最も遅い時刻:
$$t_{\text{required}} = T_{\text{clk}} - t_{\text{setup}} = 4.0 - 0.3 = 3.7\ \text{ns}$$ $$\text{slack} = 3.7 - 3.9 = -0.2\ \text{ns} \quad \Rightarrow \quad \textbf{violation}$$$$t_{\text{required}} = T_{\text{clk}} - t_{\text{setup}} = 4.0 - 0.3 = 3.7\ \text{ns}$$ $$\text{slack} = 3.7 - 3.9 = -0.2\ \text{ns} \quad \Rightarrow \quad \textbf{violation}$$$$t_{\text{required}} = T_{\text{clk}} - t_{\text{setup}} = 4.0 - 0.3 = 3.7\ \text{ns}$$ $$\text{slack} = 3.7 - 3.9 = -0.2\ \text{ns} \quad \Rightarrow \quad \textbf{violation}$$(b) The minimum feasible period is $t_{\text{CQ}} + t_{\text{logic}} + t_{\text{setup}} = 0.4 + 3.5 + 0.3 = 4.2$ ns, so(b) 可行的最小週期是 $t_{\text{CQ}} + t_{\text{logic}} + t_{\text{setup}} = 0.4 + 3.5 + 0.3 = 4.2$ ns,所以(b) 実現できる最小周期は $t_{\text{CQ}} + t_{\text{logic}} + t_{\text{setup}} = 0.4 + 3.5 + 0.3 = 4.2$ ns なので、
$$f_{\max} = \frac{1}{4.2\ \text{ns}} \approx 238\ \text{MHz}$$$$f_{\max} = \frac{1}{4.2\ \text{ns}} \approx 238\ \text{MHz}$$$$f_{\max} = \frac{1}{4.2\ \text{ns}} \approx 238\ \text{MHz}$$(c) Two RTL-level fixes, both taught in this course:(c) 兩個 RTL 層級的解法,都是本課程教過的:(c) RTL レベルの対策を 2 つ。どちらもこの講義で扱ったものです。
if…else if chain as a case with mutually
exclusive items so that it synthesizes to a balanced mux instead of a serial priority structure
(Section 10.5).重構邏輯 — 把漣波進位加法器換成超前進位加法器,或把一長串優先權式的 if…else if 改寫成項目互斥的 case,讓它合成出平衡的多工器而不是串列的優先權結構(10.5 節)。論理の作り替え — リップルキャリー加算器をキャリー先見加算器に置き換える、あるいは長い優先順位付きの if…else if 連鎖を、項目が互いに排他的な case に書き換えて、直列の優先順位構造ではなくバランスの取れたマルチプレクサに合成させます(10.5 節)。A third, non-RTL option is to let the synthesis tool retime or upsize cells — but 0.2 ns on a 4 ns period is usually recoverable by constraint tuning alone.第三個非 RTL 的選項,是讓合成工具做 retiming 或把單元加大 — 不過 4 ns 週期上差 0.2 ns,通常光靠調整約束就能救回來。RTL 以外の第 3 の選択肢として、合成ツールにリタイミングやセルのサイズアップをさせる手もあります — ただし 4 ns 周期で 0.2 ns の不足なら、たいていは制約の調整だけで取り戻せます。
These may be invoked inside a testbench behavior or inside a module's specify block.這些可以在測試平台的 behavior 內呼叫,也可以寫在模組的 specify 區塊裡。これらはテストベンチの behavior の中でも、モジュールの specify ブロックの中でも呼び出せます。
| Task任務タスク | Violation is reported when…在什麼情況下回報違規…違反が報告される条件… | Example範例例 |
|---|---|---|
$setup(data_event, ref_event, limit)$setup(data_event, ref_event, limit)$setup(data_event, ref_event, limit) | the time from data_event to ref_event is less than limit從 data_event 到 ref_event 的時間小於 limitdata_event から ref_event までの時間が limit 未満のとき | $setup(data, posedge clk, 5);$setup(data, posedge clk, 5);$setup(data, posedge clk, 5); |
$hold(ref_event, data_event, limit)$hold(ref_event, data_event, limit)$hold(ref_event, data_event, limit) | data is stable for less than limit after ref_eventref_event 之後資料維持穩定的時間小於 limitref_event の後にデータが安定している時間が limit 未満のとき | $hold(posedge clk, data, 2);$hold(posedge clk, data, 2);$hold(posedge clk, data, 2); |
$setuphold(data, ref, s_limit, h_limit)$setuphold(data, ref, s_limit, h_limit)$setuphold(data, ref, s_limit, h_limit) | combination of both上述兩者的組合上記 2 つの組合せ | $setuphold(data, posedge clk, 5, 2);$setuphold(data, posedge clk, 5, 2);$setuphold(data, posedge clk, 5, 2); |
$period(ref_event, limit)$period(ref_event, limit)$period(ref_event, limit) | two consecutive ref_events are closer than limit連續兩個 ref_event 的間隔比 limit 還短連続する 2 つの ref_event の間隔が limit より短いとき | $period(posedge clk, 16);$period(posedge clk, 16);$period(posedge clk, 16); |
$width(ref_event, limit)$width(ref_event, limit)$width(ref_event, limit) | the interval from ref_event to the next opposite transition is less than limit從 ref_event 到下一次反向轉態的間隔小於 limitref_event から次の逆向きの遷移までの間隔が limit より短いとき | $width(posedge clk, 8);$width(posedge clk, 8);$width(posedge clk, 8); |
$skew(event_1, event_2, limit)$skew(event_1, event_2, limit)$skew(event_1, event_2, limit) | the time between the two events exceeds limit兩個事件之間的時間超過 limit2 つのイベント間の時間が limit を超えるとき | $skew(posedge clk1, posedge clk2, 3);$skew(posedge clk1, posedge clk2, 3);$skew(posedge clk1, posedge clk2, 3); |
$nochange(ref, data, start, end)$nochange(ref, data, start, end)$nochange(ref, data, start, end) | data changes inside the window relative to ref_event資料在相對於 ref_event 的視窗內發生變化ref_event を基準とする窓の中でデータが変化したとき | $nochange(posedge clk, data, -1, 2);$nochange(posedge clk, data, -1, 2);$nochange(posedge clk, data, -1, 2); |
Note that $setup takes (data, reference) while $hold
takes (reference, data). The order mirrors the physical ordering in time: setup measures data
before the clock, hold measures data after the clock. Getting this backwards is a
guaranteed lost mark.注意 $setup 收的是 (data, reference),而 $hold 收的是 (reference, data)。這個順序對應著時間上的物理順序:setup 量的是時脈之前的資料,hold 量的是時脈之後的資料。寫反必定丟分。$setup は (data, reference) を取り、$hold は (reference, data) を取ることに注意してください。この順序は時間軸上の物理的な順序を映しています。セットアップはクロックの前のデータを、ホールドはクロックの後のデータを測ります。逆にすれば確実に失点します。
edge specifieredge 指定子edge 指定子The transitions {01, 10, 0x, x1, 1x, x0} can be named explicitly:轉態 {01, 10, 0x, x1, 1x, x0} 可以被明確指名:遷移 {01, 10, 0x, x1, 1x, x0} は明示的に名指しできます。
$setuphold (data, edge 01 clk, 5, 2);
When a timing check is violated, Verilog reports the violation but the output still takes its new value —
which hides the fact that real silicon might have gone metastable. A notifier fixes this: an extra
port on a sequential UDP that forces the output to x whenever the notifier register toggles.時序檢查被違反時,Verilog 會回報違規,但輸出仍然會取得新值 — 這就掩蓋了真實矽晶片可能已經進入介穩態的事實。notifier 解決了這件事:在序向 UDP 上多加一個埠,只要 notifier 暫存器翻轉就把輸出強制成 x。タイミングチェックに違反すると、Verilog は違反を報告しますが出力は新しい値を取ってしまいます — 実際のシリコンならメタステーブルになっていたかもしれない事実が隠れてしまうのです。ノーティファイアがこれを解決します。順序回路 UDP に追加のポートを設け、ノーティファイア・レジスタがトグルするたびに出力を x に強制します。
reg notifier;
specify
$setuphold (posedge clk, data, 5, 2, notifier);
endspecify
// the UDP has an extra input port bound to `notifier`;
// toggling it drives q to x, propagating the uncertainty
| MealyMealyMealy | MooreMooreMoore | |
|---|---|---|
| Output depends on輸出取決於出力が依存するもの | current state and inputs現態與輸入現在の状態と入力 | current state only只有現態現在の状態のみ |
| Labelled on the state graph在狀態圖上標在状態遷移図での表示位置 | each arc (transition)每一條弧(轉移)上各アーク(遷移) | each node (state)每一個節點(狀態)上各ノード(状態) |
| States needed需要的狀態數必要な状態数 | generally fewer通常較少一般に少ない | generally more通常較多一般に多い |
| Output timing輸出時序出力のタイミング | responds in the same cycle as the input; can glitch與輸入同一個週期就反應;可能出現突波入力と同じサイクルで応答する。グリッチが出うる | changes only after a clock edge; glitch-free只在時脈邊緣之後才改變;無突波クロックエッジの後にのみ変化する。グリッチなし |
| Lecture's verdict投影片的結論講義の結論 | Better較佳こちらが良い |
Because the output is a pure function of registered state, it is stable for the whole cycle and cannot pass an input glitch straight through to the output. That matters enormously when the FSM output drives another clock domain or an off-chip pin. The cost is an extra state and one cycle of latency.因為輸出是已暫存狀態的純函數,它整個週期都穩定,也不可能把輸入的突波直接傳到輸出。當 FSM 的輸出要驅動另一個時脈域或晶片外的接腳時,這件事非常重要。代價是多一個狀態和一個週期的延遲。出力がレジスタに取り込まれた状態の純粋な関数なので、1 サイクルを通じて安定し、入力のグリッチをそのまま出力へ通すことがありません。FSM の出力が別のクロックドメインやチップ外のピンを駆動する場合、この点は決定的に重要です。代償は状態が 1 つ増えることと 1 サイクルのレイテンシです。
| Explicit style — better顯式風格 — 較佳明示的スタイル — こちらが良い | Implicit style隱式風格暗黙的スタイル | |
|---|---|---|
| Mechanism機制仕組み | declare a state register that encodes the state宣告一個把狀態編碼起來的狀態暫存器状態を符号化する状態レジスタを宣言する | use multiple event controls to describe an evolution of states用多個事件控制描述狀態的演進複数のイベント制御で状態の推移を記述する |
| Code volume程式量コード量 | more較多多い | less, more abstract較少,較抽象少なく、より抽象的 |
| Reset重置リセット | straightforward直截了當素直に書ける | can be considerably more complicated可能複雜得多かなり複雑になりうる |
| Applicability適用範圍適用範囲 | any FSM任何 FSMあらゆる FSM | only when a given state can be reached from exactly one other state只有當某個狀態恰好只能由另一個狀態抵達時ある状態にちょうど 1 つの状態からしか到達しない場合のみ |
| Synthesis合成合成 | reliable可靠確実 | frequently un-synthesizable經常無法合成しばしば合成できない |
Implicit style — avoid隱式風格 — 避免使用暗黙的スタイル — 避けること
always begin
@(posedge clk) y = 0;
@(posedge clk) y = 1;
@(posedge clk) y = 1;
end
// no state register; reset is awkward;
// only works for a simple ring
Explicit style — use顯式風格 — 建議使用明示的スタイル — こちらを使う
always @(posedge clk or posedge rst)
if (rst) state <= S0;
else state <= next_state;
always @(*)
case (state)
S0: next_state = S1;
S1: next_state = S2;
S2: next_state = S0;
default: next_state = S0;
endcase
The resulting three-block template is the one to reproduce under exam conditions:由此得到的三區塊樣板,就是考試時要能默寫出來的那一個:こうして得られる 3 ブロックのテンプレートが、試験で再現できるようにしておくべきものです。
module seq_detect (out, in_bit, clk, rst); output out; input in_bit, clk, rst; parameter S0 = 2'b00, // no history S1 = 2'b01, // last bit was 0 S2 = 2'b10, // last bit was 1 S3 = 2'b11; // two successive equal bits seen reg [1:0] state, next_state; // ---- Block 1: state register (sequential) ---- always @ (posedge clk or posedge rst) if (rst) state <= S0; else state <= next_state; // ---- Block 2: next-state logic (combinational) ---- always @ (state or in_bit) case (state) S0: next_state = in_bit ? S2 : S1; S1: next_state = in_bit ? S2 : S3; S2: next_state = in_bit ? S3 : S1; S3: next_state = in_bit ? S3 : S1; default: next_state = S0; // completes the case — no latch endcase // ---- Block 3: output logic (Moore: state only) ---- assign out = (state == S3); endmodule
default (or a fully-enumerated case) in block 2 — otherwise an unwanted latch.第 2 個區塊要有 default(或把 case 完全列舉)— 否則會生出非預期的鎖存器。ブロック 2 に default(または完全に列挙した case)を置く — さもないと意図しないラッチができます。<= in block 1, blocking = in block 2.第 1 個區塊用非阻擋式 <=,第 2 個區塊用阻擋式 =。ブロック 1 ではノンブロッキング <=、ブロック 2 ではブロッキング = を使う。x and never
recovers, because case (2'bxx) matches no item.要有把機器帶到已知狀態的重置 — 否則 FSM 會從 x 起步而且永遠回不來,因為 case (2'bxx) 比對不到任何項目。機械を既知の状態に置くリセットを用意する — さもないと FSM は x から始まり、case (2'bxx) はどの項目にも一致しないため二度と復帰できません。| Encoding編碼方式エンコーディング | 4 states as4 個狀態編成4 状態の表し方 | FF count正反器數FF の数 | Next-state logic次態邏輯次状態論理 | Best for最適合適した用途 |
|---|---|---|---|---|
| Binary二進位バイナリ | 00, 01, 10, 11 | $\lceil \log_2 N \rceil$ — minimum$\lceil \log_2 N \rceil$ — 最少$\lceil \log_2 N \rceil$ — 最小 | widest / deepest最寬/最深最も広く・深い | area-critical, many states面積吃緊、狀態很多的情況面積が厳しく状態数が多い場合 |
| Gray格雷碼グレイ | 00, 01, 11, 10 | $\lceil \log_2 N \rceil$$\lceil \log_2 N \rceil$$\lceil \log_2 N \rceil$ | moderate中等中程度 | counters, async FIFO pointers — only one bit changes per step計數器、非同步 FIFO 指標 — 每步只變一個位元カウンタ、非同期 FIFO のポインタ — 1 ステップで 1 ビットしか変わらない |
| One-hotOne-hotワンホット | 0001, 0010, 0100, 1000 | $N$ — maximum$N$ — 最多$N$ — 最大 | shallowest, often a single AND-OR level最淺,往往只需一層 AND-OR最も浅く、多くの場合 AND-OR 1 段で済む | speed-critical FSMs, FPGAs (flip-flops are free)速度吃緊的 FSM、FPGA(正反器不用錢)速度が厳しい FSM、FPGA(フリップフロップはただ同然) |
| JohnsonJohnsonジョンソン | 000, 001, 011, 111, 110, 100 | $N/2$ | simple簡單単純 | ring-type sequencers, glitch-free decode環狀定序器、無突波解碼リング型シーケンサ、グリッチのないデコード |
With one-hot encoding, the vast majority of the $2^N$ codes are illegal states. A
default branch that returns to the reset state is therefore not just a latch-prevention measure —
it is the FSM's recovery path after a single-event upset. In a communication IC that matters.採用 one-hot 編碼時,$2^N$ 個碼中絕大多數都是不合法狀態。因此一個會回到重置狀態的 default 分支,就不只是防鎖存器的措施 — 它是 FSM 在單一事件翻轉之後的復原路徑。在通訊 IC 裡,這件事很重要。ワンホット符号化では、$2^N$ 個の符号のほとんどが不正な状態です。したがってリセット状態に戻る default 分岐は、単なるラッチ防止策ではありません — シングルイベント・アップセット後の FSM の復帰経路です。通信 IC ではこれが効いてきます。
Problem: Design an FSM that synchronously reads a serial bit stream and asserts its output after
two successive equal bits (two 0s or two 1s) are detected. It is active on the rising clock edge.
(a) Draw the Moore state graph. (b) For the input stream 0 0 1 1 1 0 0 0 1, give the output sequence.
(c) How would a Mealy version differ?題目:設計一個 FSM,同步讀取序列位元流,在偵測到連續兩個相同的位元(兩個 0 或兩個 1)之後令輸出成立。它在時脈上升邊緣作用。
(a) 畫出 Moore 狀態圖。(b) 對輸入串 0 0 1 1 1 0 0 0 1,寫出輸出序列。(c) Mealy 版本會有什麼不同?問題:シリアルビット列を同期的に読み取り、連続する 2 つの等しいビット(0 が 2 つ、または 1 が 2 つ)を検出したら出力をアサートする FSM を設計しなさい。クロックの立ち上がりで動作します。
(a) Moore 型の状態遷移図を描きなさい。(b) 入力列 0 0 1 1 1 0 0 0 1 に対する出力列を示しなさい。(c) Mealy 版はどう違いますか。
(a) Four states suffice. Let $S_1$ = "last bit was 0, no pair yet", $S_2$ = "last bit was 1, no pair yet", $S_3$ = "a pair has just been completed". Because the output must be a function of state alone, the pair detection has to be captured in the state.(a) 四個狀態就夠了。令 $S_1$ =「上一個位元是 0,尚未成對」、$S_2$ =「上一個位元是 1,尚未成對」、$S_3$ =「剛剛湊成一對」。由於輸出必須只是狀態的函數,成對這件事就必須被記進狀態裡。(a) 状態は 4 つで足ります。$S_1$ =「直前のビットは 0、まだ対になっていない」、$S_2$ =「直前のビットは 1、まだ対になっていない」、$S_3$ =「たった今対が成立した」とします。出力は状態だけの関数でなければならないので、対の検出そのものを状態の中に取り込む必要があります。
| State狀態状態 | Meaning意義意味 | Output輸出出力 | on in=0in=0 時in=0 のとき | on in=1in=1 時in=1 のとき |
|---|---|---|---|---|
| S0 | reset, no history重置,沒有歷史リセット、履歴なし | 0 | S1 | S2 |
| S1 | last bit 0上一個位元為 0直前のビットが 0 | 0 | S3 | S2 |
| S2 | last bit 1上一個位元為 1直前のビットが 1 | 0 | S1 | S3 |
| S3 | pair detected偵測到一對対を検出 | 1 | S1 or S3S1 或 S3S1 または S3 | S2 or S3S2 或 S3S2 または S3 |
From S3 the machine must remember which bit ended the pair. Using the template in 9.3, S3 goes to S1 on a 0 and S3 on a 1 if the pair was of 1s — which is why a strict Moore version usually splits S3 into S3a ("pair of 0s") and S3b ("pair of 1s"), giving five states. This is the standard Moore penalty: more states, cleaner output.從 S3 出發時,機器必須記得是哪個位元結束了這一對。依照 9.3 的樣板,若這對是兩個 1,S3 遇 0 走到 S1、遇 1 留在 S3 — 這正是為什麼嚴格的 Moore 版本通常會把 S3 拆成 S3a(「一對 0」)與 S3b(「一對 1」),變成五個狀態。這就是 Moore 一貫的代價:狀態較多,輸出較乾淨。S3 からは、どちらのビットで対が成立したのかを機械が覚えていなければなりません。9.3 のテンプレートに従うと、対が 1 のペアだった場合、S3 は 0 で S1 へ、1 で S3 に留まります — 厳密な Moore 版では S3 を S3a(「0 の対」)と S3b(「1 の対」)に分け、5 状態にするのが普通である理由がこれです。これが Moore の定番の代償、状態は増えるが出力はきれいです。
(b) Tracing 0 0 1 1 1 0 0 0 1 with the 5-state Moore machine, where the output
is asserted in the cycle after the pair completes:(b) 用 5 狀態的 Moore 機器追蹤 0 0 1 1 1 0 0 0 1,輸出在成對之後的那個週期成立:(b) 5 状態の Moore 機械で 0 0 1 1 1 0 0 0 1 を追います。出力は対が成立した次のサイクルでアサートされます。
| bit位元ビット | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 |
|---|---|---|---|---|---|---|---|---|---|
| pair?成對?対? | – | yes是はい | no否いいえ | yes是はい | yes是はい | no否いいえ | yes是はい | yes是はい | no否いいえ |
| Moore outMoore 輸出Moore の出力 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
The Moore output is the "pair?" row delayed by one clock cycle, because the output is decoded from the registered state.Moore 的輸出就是「成對?」那一列延後一個時脈週期,因為輸出是從已暫存的狀態解碼出來的。Moore の出力は「対?」の行を1 クロック遅らせたものです。出力がレジスタに取り込まれた状態からデコードされるからです。
(c) A Mealy version needs only the two states S1 and S2 (last bit 0 / last bit 1) and asserts the
output combinationally whenever the incoming bit equals the remembered one:
out = (state == S1 && in == 0) || (state == S2 && in == 1). Fewer states, and the output
appears one cycle earlier — but it follows in asynchronously within the cycle and will show every
glitch on in.(c) Mealy 版本只需要 S1 與 S2 兩個狀態(上一個位元是 0/是 1),並在進來的位元與記住的那個相同時以組合邏輯令輸出成立:out = (state == S1 && in == 0) || (state == S2 && in == 1)。狀態較少,輸出也早一個週期出現 — 但它在週期之內非同步地跟隨 in,in 上的每一個突波都會照單全收。(c) Mealy 版に必要な状態は S1 と S2(直前のビットが 0 か 1 か)の 2 つだけで、入ってきたビットが記憶しているビットと等しいときに組合せ論理で出力をアサートします:out = (state == S1 && in == 0) || (state == S2 && in == 1)。状態は少なく、出力も 1 サイクル早く出ます — ただしサイクル内で in に非同期に追従するため、in のグリッチをすべて拾います。
Testbench note from the lecture: drive the input data stream on the falling edge of the clock. That guarantees the data is stable well before the rising edge the FSM samples on, so the simulation never races.投影片的測試平台提醒:輸入資料流請在時脈的下降邊緣驅動。這樣可以保證資料在 FSM 取樣的上升邊緣之前就已經穩定很久,模擬永遠不會發生競爭。講義のテストベンチに関する注意:入力データ列はクロックの立ち下がりエッジで与えてください。そうすれば FSM がサンプルする立ち上がりエッジのはるか前にデータが安定し、シミュレーションで競合が起きません。
always block)行為敘述(always 區塊)動作記述文(always ブロック)fork…joinfork…joinfork…joinwaitwaitwaitdisable statement外部的 disable 敘述外部からの disable 文initial, $system tasks, specify blocksinitial、$ 系統任務、specify 區塊initial、$ システムタスク、specify ブロックThe synthesis target is to minimize area, delay, or power. Two families of technique:合成的目標是把面積、延遲或功耗最小化。技術分成兩大家族:合成の目標は面積・遅延・消費電力のいずれかを最小化することです。手法は大きく 2 系統あります。
Sum-of-products (SOP) form — Karnaugh maps and Quine-McCluskey. Fast, but the resulting AND-OR network can be very wide.積項和(SOP)形式 — 卡諾圖與 Quine-McCluskey。速度快,但得到的 AND-OR 網路可能非常寬。積和(SOP)形式 — カルノー図と Quine-McCluskey 法。高速ですが、得られる AND-OR 網は非常に広くなりがちです。
| Operation操作操作 | Before之前変換前 | After之後変換後 |
|---|---|---|
| Decomposition分解分解 | $F = abc + abd + a'c'd' + b'c'd'$$F = abc + abd + a'c'd' + b'c'd'$$F = abc + abd + a'c'd' + b'c'd'$ | with $X = ab$, $Y = c+d$: $F = XY + X'Y'$取 $X = ab$、$Y = c+d$: $F = XY + X'Y'$$X = ab$、$Y = c+d$ とおくと: $F = XY + X'Y'$ |
| Extraction提取共用項抽出 | $F = (a{+}b)cd + e$, $G = (a{+}b)e'$, $H = cde$$F = (a{+}b)cd + e$、$G = (a{+}b)e'$、$H = cde$$F = (a{+}b)cd + e$、$G = (a{+}b)e'$、$H = cde$ | with $X = a+b$, $Y = cd$: $F = XY + e$, $G = Xe'$, $H = Ye$取 $X = a+b$、$Y = cd$: $F = XY + e$、$G = Xe'$、$H = Ye$$X = a+b$、$Y = cd$ とおくと: $F = XY + e$、$G = Xe'$、$H = Ye$ |
| Factoring因式分解因数分解 | $F = ac + ad + bc + bd + e$$F = ac + ad + bc + bd + e$$F = ac + ad + bc + bd + e$ | $F = (a+b)(c+d) + e$ |
| Substitution代入代入 | $F = a + b + c$, $G = a + b$ | $F = G + c$ |
| Elimination展開(反代入)消去(逆代入) | $F = Ga + G'b$, $G = c + d$$F = Ga + G'b$、$G = c + d$$F = Ga + G'b$、$G = c + d$ | $F = ac + ad + bc'd'$$F = ac + ad + bc'd'$$F = ac + ad + bc'd'$ |
Decomposition introduces new intermediate variables inside one function. Extraction finds a sub-expression shared by several functions and factors it out once. Elimination is the inverse of substitution — you would apply it to flatten logic when the extra level costs more delay than the shared gate saves area.分解是在一個函數內部引入新的中間變數。提取則是找出多個函數共用的子運算式,一次把它提出來。展開是代入的反操作 — 當多出來的那一層造成的延遲,比共用閘省下的面積還貴時,你就會用它來攤平邏輯。分解は1 つの関数の内部に新しい中間変数を導入します。抽出は複数の関数が共有する部分式を見つけ、一度だけ括り出します。消去は代入の逆操作で、余分な段が増やす遅延のほうが共有ゲートで節約できる面積より高くつくときに、論理を平坦化するために使います。
All inputs to a behavior that implements combinational logic must be
included in the event control expression — where "inputs" means operands on the RHS of assignments plus all
control signals whose transitions affect the assignment. Failure to do so produces
unwanted latches. Equally, a case or if that does not cover all
possibilities is incompletely specified and also produces latches.凡是實作組合邏輯的 behavior,其所有輸入都必須列在事件控制運算式裡 — 這裡的「輸入」指的是賦值右式的運算元,加上所有轉態會影響該賦值的控制訊號。沒做到就會產生非預期的鎖存器。同樣地,沒有涵蓋所有可能性的 case 或 if 屬於規格不完整,一樣會產生鎖存器。組合せ論理を実装する behavior では、その入力をすべてイベント制御式に含めなければなりません — ここでいう「入力」とは、代入の右辺のオペランドと、その遷移が代入に影響するすべての制御信号のことです。これを怠ると意図しないラッチが生じます。同様に、すべての可能性を網羅していない case や if は記述が不完全であり、やはりラッチを生みます。
Bad — incomplete case list不好 — case 清單不完整悪い例 — case のリストが不完全
always @ (sel or a or b or c)
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
endcase
// sel = 2'b11 not covered
// -> y must hold -> LATCH
Good — completed with default好 — 用 default 補完良い例 — default で補完
always @ (sel or a or b or c)
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
default: y = 1'b0;
endcase
// pure 4-to-1 mux, no storage
Bad — if-chain with no final else不好 — if 串沒有最後的 else悪い例 — if 連鎖に最後の else がない
always @ (a or b or sel)
if (sel == 2'b00) y = a;
else if (sel == 2'b01) y = b;
else if (sel == 2'b10) y = a & b;
// the last statement should be "else"
Good好良い例
always @ (a or b or sel) if (sel == 2'b00) y = a; else if (sel == 2'b01) y = b; else y = a & b;
A case or if that is complete but assigns the variable to itself in a
level-sensitive behavior synthesizes to a mux with feedback. Unlike the latch above, this one
cannot be synthesized to gates at all.一個確實完整、但在準位敏感的 behavior 裡把變數指派給它自己的 case 或 if,會合成出帶回授的多工器。與上面的鎖存器不同,這一個根本無法合成成閘。記述としては完全でも、レベルセンシティブな behavior の中で変数を自分自身に代入する case や if は、帰還付きのマルチプレクサに合成されます。上のラッチと違い、こちらはそもそもゲートに合成できません。
always @ (sel or a or b or c)
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
default: y = y; // explicit self-assignment -> combinational loop
endcase
The target of an assignment must not be an operand on the RHS of any assignment in the same combinational behavior — that produces an infinite loop in simulation and an unsynthesizable structure in hardware. Continuous assignments carry the same restriction: no structural feedback.賦值的目標,不可以同時是同一個組合 behavior 中任何賦值右式的運算元 — 那會在模擬中造成無窮迴圈,在硬體上則是無法合成的結構。連續賦值也受同樣的限制:不可以有結構性回授。代入の対象を、同じ組合せ behavior 内のどの代入の右辺のオペランドにもしてはいけません — シミュレーションでは無限ループになり、ハードウェアでは合成不能な構造になります。連続代入にも同じ制限があります:構造的な帰還は不可です。
Are the branch conditions mutually exclusive?
Yes → the tool synthesizes a multiplexer (all branches equal priority, balanced delay).
No → the tool synthesizes a priority structure (a chain, delay grows with depth).各分支的條件是否互斥?
是 → 工具合成出多工器(所有分支優先權相同,延遲平衡)。
否 → 工具合成出優先權結構(一條鏈,延遲隨深度增加)。分岐の条件は互いに排他的ですか。
はい → ツールはマルチプレクサを合成します(全分岐が同じ優先度、遅延は均等)。
いいえ → ツールは優先順位構造を合成します(直列の連鎖で、深さとともに遅延が増えます)。
This holds for both case and if. It is not about which keyword you use — a
common misconception. An if…else if chain with mutually exclusive conditions
synthesizes to a mux; a case whose items overlap (possible with casex/casez)
synthesizes to a priority structure.這對 case 與 if 都成立。重點不在你用了哪個關鍵字 — 這是常見的誤解。條件互斥的 if…else if 串會合成出多工器;項目重疊的 case(用 casex/casez 時有可能)則會合成出優先權結構。これは case にも if にも当てはまります。どちらのキーワードを使ったかは関係ありません — よくある誤解です。条件が互いに排他的な if…else if 連鎖はマルチプレクサに合成され、項目が重なる case(casex/casez ではあり得ます)は優先順位構造に合成されます。
8-to-3 encoder — no priority8 對 3 編碼器 — 無優先權8 対 3 エンコーダ — 優先順位なし
always @ (d)
case (d)
8'b0000_0001: code = 3'd0;
8'b0000_0010: code = 3'd1;
8'b0000_0100: code = 3'd2;
8'b0000_1000: code = 3'd3;
8'b0001_0000: code = 3'd4;
8'b0010_0000: code = 3'd5;
8'b0100_0000: code = 3'd6;
8'b1000_0000: code = 3'd7;
default: code = 3'bx;
endcase
// items mutually exclusive -> MUX
8-to-3 priority encoder8 對 3 優先權編碼器8 対 3 プライオリティエンコーダ
always @ (d)
casex (d)
8'b1xxx_xxxx: code = 3'd7;
8'b01xx_xxxx: code = 3'd6;
8'b001x_xxxx: code = 3'd5;
8'b0001_xxxx: code = 3'd4;
8'b0000_1xxx: code = 3'd3;
8'b0000_01xx: code = 3'd2;
8'b0000_001x: code = 3'd1;
8'b0000_0001: code = 3'd0;
default: code = 3'bx;
endcase
// items overlap -> PRIORITY chain
The equivalent if forms produce identical hardware:等價的 if 寫法會產生完全相同的硬體:等価な if の書き方でも、まったく同じハードウェアになります。
if (d[7]) code = 3'd7;
else if (d[6]) code = 3'd6;
else if (d[5]) code = 3'd5;
// ... a priority chain, same as the casex above
A priority chain of $N$ conditions has delay $O(N)$; a mux tree has delay
$O(\log N)$. When STA reports a critical path through a long else if chain and the conditions are in
fact mutually exclusive, rewriting as a case is a free timing win.$N$ 個條件的優先權鏈延遲為 $O(N)$;多工器樹的延遲則是 $O(\log N)$。當 STA 回報關鍵路徑穿過一長串 else if,而那些條件其實是互斥的,把它改寫成 case 就是白撿的時序改善。$N$ 個の条件からなる優先順位チェーンの遅延は $O(N)$、マルチプレクサツリーの遅延は $O(\log N)$ です。STA が長い else if 連鎖を通るクリティカルパスを報告し、しかも条件が実は互いに排他的なら、case に書き換えるだけでタイミングがただで改善します。
Four implementation concerns from the lecture: tri-state buffers, bidirectional buses, bus loading, and tri-state outputs with don't-cares.投影片提出四個實作上的考量:三態緩衝器、雙向匯流排、匯流排負載,以及帶 don't-care 的三態輸出。講義が挙げる実装上の論点は 4 つ:トライステートバッファ、双方向バス、バスの負荷、そしてドントケアを伴うトライステート出力です。
Tri-state buffer onto a shared bus接到共用匯流排上的三態緩衝器共有バスに接続するトライステートバッファ
assign bus = en_a ? data_a : 8'bz;
assign bus = en_b ? data_b : 8'bz;
// bus must be a net (wire/tri);
// en_a and en_b must never be 1 together
Bidirectional bus (inout)雙向匯流排(inout)双方向バス(inout)
inout [7:0] dbus;
assign dbus = wr_en ? data_out : 8'bz;
assign data_in = dbus;
// one net, two directions, one enable
Assigning x in a default branch means "I don't care" — the tool is free
to pick whatever minimizes logic. Assigning z means "drive nothing" — the tool must build a
tri-state device. The two produce entirely different hardware from nearly identical source, which is
why the lecture contrasts alu_with_z1 and alu_with_z2.在 default 分支賦值 x 表示「我不在乎」— 工具可以自由挑選最能簡化邏輯的值。賦值 z 則表示「什麼都不要驅動」— 工具必須做出一個三態元件。兩者的原始碼幾乎相同,硬體卻完全不同,這正是投影片要拿 alu_with_z1 和 alu_with_z2 對照的原因。default 分岐で x を代入するのは「どちらでもよい」という意味で、ツールは論理が最小になる値を自由に選べます。z を代入するのは「何も駆動しない」という意味で、ツールはトライステート素子を作らなければなりません。ソースはほとんど同じなのにハードウェアはまったく別物になります。講義が alu_with_z1 と alu_with_z2 を対比する理由がこれです。
Resource sharing should be done before RTL coding — it is an architectural decision, not something to hope the tool finds.資源共用應該在寫 RTL 之前就決定 — 這是架構決策,不是指望工具自己找出來的事。リソース共有は RTL を書く前に決めるべきです — アーキテクチャ上の判断であり、ツールが見つけてくれるのを期待するものではありません。
Two adders — costly兩個加法器 — 昂貴加算器 2 個 — 高価
always @ (*)
if (sel) y_out = accum + data_a;
else y_out = data_b + data_a;
// the tool may infer TWO adders
One adder — shared一個加法器 — 共用加算器 1 個 — 共有
wire [N-1:0] mux_out = sel ? accum : data_b;
assign y_out = mux_out + data_a;
// mux first, then ONE adder
Problem: For each fragment, state whether synthesis infers a latch, a flip-flop, or pure combinational logic, and why.題目:對每一段程式碼,判斷合成會推論出鎖存器、正反器,還是純組合邏輯,並說明理由。問題:各コード片について、合成がラッチ・フリップフロップ・純粋な組合せ論理のどれを推論するかを、理由とともに答えなさい。
// (a) // (b)
always @ (a or b) always @ (a)
begin begin
y = a & b; y = a & b;
z = a | b; z = a | b;
end end
// (c) // (d)
always @ (posedge clk) always @ (sel or a or b)
q <= d; if (sel) y = a;
else y = b;
// (e) // (f)
always @ (en or d) always @ (*)
if (en) q = d; case (op)
2'b00: y = a + b;
2'b01: y = a - b;
2'b10: y = a & b;
endcase
b is missing from the sensitivity list.
In simulation, y and z fail to update when b changes, so the
behavior looks like storage. Most modern synthesis tools ignore an incomplete sensitivity list and synthesize
pure combinational logic anyway — which means simulation and synthesis disagree. That
mismatch is worse than either outcome alone. Use always @(*).(b) 鎖存器 — 但很微妙。b 沒有列在敏感度列表裡。在模擬中,b 改變時 y 與 z 不會更新,所以這個 behavior 看起來像是有儲存。但大多數現代合成工具會忽略不完整的敏感度列表,照樣合成出純組合邏輯 — 也就是模擬與合成互相矛盾。這種不一致比其中任何一種結果單獨出現都更糟。請用 always @(*)。(b) ラッチ — ただし微妙な例。b がセンシティビティリストにありません。シミュレーションでは b が変化しても y と z が更新されないため、記憶があるように見えます。しかし現代の合成ツールの多くは不完全なセンシティビティリストを無視して純粋な組合せ論理を合成します — つまりシミュレーションと合成が食い違うのです。この不一致はどちらか一方の結果よりたちが悪いものです。always @(*) を使いましょう。if has a matching else, so y is
assigned on every path. A 2-to-1 mux.(d) 組合邏輯。這個 if 有配對的 else,所以 y 在每條路徑上都被賦值。一個 2 對 1 多工器。(d) 組合せ論理。この if には対応する else があるので、y はどの経路でも代入されます。2 対 1 マルチプレクサです。else, so when en is 0,
q must hold. This is the correct way to describe a transparent latch. It is only a bug
when you did not mean it.(e) 鎖存器 — 而且是刻意的。沒有 else,所以 en 為 0 時 q 必須保住。這正是描述透通鎖存器的正確方式。只有在你並非有意如此時,它才是 bug。(e) ラッチ — ただし意図的なもの。else がないので en が 0 のとき q は保持されます。透過ラッチを記述する正しい方法です。意図していなかった場合にだけバグになります。op = 2'b11 is uncovered, so y holds. Add
default: y = 'bx; (don't-care, cheapest) or default: y = 0; (defined, safer).(f) 鎖存器。op = 2'b11 沒有被涵蓋,所以 y 會保住。加上 default: y = 'bx;(don't-care,最省)或 default: y = 0;(有明確值,較安全)。(f) ラッチ。op = 2'b11 が網羅されていないので y は保持されます。default: y = 'bx;(ドントケア、最も安価)か default: y = 0;(値が定まり安全)を加えてください。The diagnostic question: "Is there any reachable input combination for which this variable is not assigned?" If yes, you get a latch. That single question resolves every case above.診斷用的一問:「有沒有任何可達的輸入組合,會讓這個變數沒被賦值?」如果有,你就會得到鎖存器。這一個問題就能解決上面全部的情況。診断のための問い:「この変数が代入されない到達可能な入力の組合せはあるか?」あるならラッチができます。この 1 つの問いで上のすべての場合が判定できます。
A register variable in a behavior is synthesized as a flip-flop if it is (1) aligned with clock behavior — i.e. the behavior is edge-sensitive to a clock — and (2) assigned a value by some assignment in that behavior.一個 behavior 內的 register 變數,若同時滿足 (1)與時脈行為對齊 — 也就是該 behavior 對某個時脈是邊緣敏感的 — 以及 (2) 在該 behavior 內被某個賦值指派了值,就會被合成成正反器。behavior 内のレジスタ変数は、(1)クロック動作と整合していること — すなわちその behavior があるクロックにエッジセンシティブであること — と、(2) その behavior 内のいずれかの代入で値を与えられていることの両方を満たすとき、フリップフロップとして合成されます。
always @ (posedge clk)
case ({set1, set2})
2'b00: data_a <= 1'b0;
2'b01: data_a <= 1'b1;
2'b10: data_a <= 1'b1;
default: data_a <= 1'b1;
endcase
// synthesizes to: combinational decode -> D input of ONE flip-flop
The hardware is a mux (or decode logic) feeding a D flip-flop. Note that the mux collapses: since three of the four cases give 1, the tool reduces the decode to a single gate.硬體是一個多工器(或解碼邏輯)餵進一個 D 正反器。注意這個多工器會塌縮:因為四種情況中有三種都給 1,工具會把解碼縮成單一個閘。ハードウェアはマルチプレクサ(あるいはデコード論理)が D フリップフロップに入る形です。ただしこのマルチプレクサは潰れます。4 つのケースのうち 3 つが 1 を与えるため、ツールはデコードを 1 つのゲートにまとめます。
Asynchronous reset (active high)非同步重置(高態有效)非同期リセット(正論理)
always @ (posedge clk or posedge reset) if (reset) data_out <= 4'd0; // first stmt else data_out <= data_in; // last = sync
Reset appears in the sensitivity list. Reset pulse width may be arbitrary — it takes effect immediately.重置訊號出現在敏感度列表裡。重置脈衝的寬度可以任意 — 它會立刻生效。リセットがセンシティビティリストに入ります。リセットパルスの幅は任意でかまいません — 直ちに効きます。
Synchronous reset (active high)同步重置(高態有效)同期リセット(正論理)
always @ (posedge clk) if (reset) data_out <= 4'd0; else data_out <= data_in;
Reset is not in the sensitivity list. Caution: the reset pulse must be wider than one clock period, or it may be missed entirely.重置訊號不在敏感度列表裡。注意:重置脈衝必須比一個時脈週期還寬,否則可能整個被漏掉。リセットはセンシティビティリストに入りません。注意:リセットパルスは1 クロック周期より広くなければならず、さもないと丸ごと見逃されることがあります。
When the event control expression is sensitive to the edge of more than one signal:
an if statement must be the first statement in the behavior; the synchronizing signal
(the clock) is not tested explicitly; and the last branch must describe the synchronous
activity. Asynchronous control signals therefore automatically have priority over the clock — which is
what the flip-flop's physical set/reset pins do. Also: no signal may be qualified by both posedge and
negedge, and there may be only one clock edge in the list.當事件控制運算式對一個以上訊號的邊緣敏感時:if 敘述必須是 behavior 的第一個敘述;同步訊號(時脈)不可被顯式測試;而且最後一個分支必須描述同步行為。因此非同步控制訊號會自動取得高於時脈的優先權 — 這正是正反器實體 set/reset 接腳的作用。此外:任何訊號都不可以同時被 posedge 與 negedge 修飾,而且列表中只能有一個時脈邊緣。イベント制御式が複数の信号のエッジに反応する場合:if 文は behavior の最初の文でなければならず、同期信号(クロック)を明示的に判定してはならず、最後の分岐が同期動作を記述しなければなりません。その結果、非同期制御信号は自動的にクロックより高い優先度を持ちます — フリップフロップの物理的な set/reset ピンの働きそのものです。さらに、同じ信号を posedge と negedge の両方で修飾することはできず、リストに入れられるクロックエッジは1 つだけです。
Plain shift register單純的移位暫存器単純なシフトレジスタ
always @ (posedge clk)
data_out <= {data_out[6:0], serial_in};
// always catches the input data
Shift register with judgement (enable)帶判斷(enable)的移位暫存器判定(イネーブル)付きのシフトレジスタ
always @ (posedge clk)
if (shift_en)
data_out <= {data_out[6:0], serial_in};
// no else -> holds; this is a FF with
// enable, NOT a latch (it is clocked)
else is safe here but not in Section 10.3為什麼這裡少了 else 沒問題,10.3 節卻不行ここでは else がなくても安全で、10.3 節ではそうでない理由Inside always @(posedge clk), a missing else means "keep the
current value", which a flip-flop does natively — the tool implements it with a clock-enable pin or a feedback
mux. Inside a level-sensitive combinational behavior, the same omission has nowhere to store the value, so a
latch must be created. Same code, opposite verdict, because of the sensitivity list.在 always @(posedge clk) 裡少了 else 代表「保持目前的值」,而正反器本來就會這麼做 — 工具會用 clock-enable 接腳或一個回授多工器實作它。但在準位敏感的組合 behavior 裡,同樣的省略沒有任何地方能存這個值,所以必須造出一個鎖存器。同樣的程式碼,相反的判決,差別只在敏感度列表。always @(posedge clk) の中で else が欠けているのは「現在の値を保つ」という意味であり、フリップフロップは本来それをする素子です — ツールはクロックイネーブル端子か帰還マルチプレクサで実装します。ところがレベルセンシティブな組合せ behavior では、同じ省略でも値を置く場所がないため、ラッチを作らざるを得ません。同じコードでも判定が逆になるのは、センシティビティリストのせいです。
Barrel shifter with load可載入的桶形移位器ロード機能付きバレルシフタ
always @ (posedge clk)
if (load) q <= data_in;
else if (sl) q <= {q[6:0], q[7]}; // rotate left
else if (sr) q <= {q[0], q[7:1]}; // rotate right
Ring counter環形計數器リングカウンタ
always @ (posedge clk or posedge rst)
if (rst) q <= 4'b0001;
else q <= {q[2:0], q[3]};
// one-hot sequencer; 4 states
A ripple counter clocks each stage from the previous stage's output. It is small, but the stages do not change together, the tool cannot analyse it with STA (each stage is its own clock domain), and it cannot be scan-tested normally. Prefer a synchronous counter — all flip-flops on the same clock, with combinational increment logic — in anything you intend to tape out.漣波計數器是拿前一級的輸出去打下一級的時脈。它很小,但各級不會同時改變,工具也無法用 STA 分析它(每一級自成一個時脈域),而且沒辦法正常做掃描測試。任何你打算下線的設計,都該優先選同步計數器 — 所有正反器接同一個時脈,再配上組合的遞增邏輯。リプルカウンタは前段の出力で次段のクロックを叩きます。小さくはありますが、各段が同時に変化せず、ツールは STA で解析できず(各段が独自のクロックドメインになるため)、通常のスキャンテストもできません。テープアウトするつもりの設計では同期カウンタ — すべてのフリップフロップを同じクロックにつなぎ、組合せのインクリメント論理を添えたもの — を選んでください。
A 16-bit adder built as two 8-bit adders in series has a critical path through both. Splitting it with a register stage halves the path.把 16 位元加法器做成兩個 8 位元加法器串接,關鍵路徑就會穿過兩者。插入一級暫存器把它切開,路徑長度就少一半。16 ビット加算器を 8 ビット加算器 2 段の直列で作ると、クリティカルパスは両方を貫きます。レジスタ段を挟んで分割すれば、経路長は半分になります。
module add16_pipe (sum, cout, a, b, cin, clk); output [15:0] sum; output cout; input [15:0] a, b; input cin, clk; wire [7:0] sum_lo; wire c_mid; reg [7:0] sum_lo_r, a_hi_r, b_hi_r; reg c_mid_r; wire [7:0] sum_hi; add8 U_LO (.s(sum_lo), .co(c_mid), .a(a[7:0]), .b(b[7:0]), .ci(cin)); always @ (posedge clk) begin // pipeline registers sum_lo_r <= sum_lo; c_mid_r <= c_mid; a_hi_r <= a[15:8]; // MSB operands must be delayed too b_hi_r <= b[15:8]; end add8 U_HI (.s(sum_hi), .co(cout), .a(a_hi_r), .b(b_hi_r), .ci(c_mid_r)); assign sum = {sum_hi, sum_lo_r}; endmodule
Forgetting to register a[15:8] and b[15:8]. The MSB adder would
then see cycle-$n$ operands with a cycle-$(n{-}1)$ carry, and the result is wrong for every input change. Every
pipeline stage must delay all signals that cross it, not just the ones on the critical path.忘了把 a[15:8] 與 b[15:8] 也暫存起來。這樣高位元加法器看到的是第 $n$ 週期的運算元配上第 $(n{-}1)$ 週期的進位,只要輸入一變結果就錯。每一級管線都必須把所有穿越它的訊號延後,不能只顧關鍵路徑上的那些。a[15:8] と b[15:8] をレジスタに通し忘れることです。そうすると上位側の加算器はサイクル $n$ のオペランドにサイクル $(n{-}1)$ のキャリーを組み合わせて見ることになり、入力が変わるたびに結果が誤ります。パイプラインの各段は、クリティカルパス上の信号だけでなく、そこを横切るすべての信号を遅らせなければなりません。
Problem: (a) Rewrite the asynchronous-reset flip-flop so the reset is active low.
(b) Why can a synchronous reset pulse be missed but an asynchronous one cannot? (c) Give one advantage of each
style. (d) What is wrong with always @ (posedge clk or reset)?題目:(a) 把非同步重置的正反器改寫成低態有效重置。(b) 為什麼同步重置脈衝可能被漏掉,非同步的卻不會?(c) 各舉出一項兩種風格的優點。(d) always @ (posedge clk or reset) 有什麼問題?問題:(a) 非同期リセットのフリップフロップを、リセットが負論理になるよう書き直しなさい。(b) 同期リセットのパルスは見逃されうるのに、非同期リセットではそうならないのはなぜですか。(c) それぞれのスタイルの利点を 1 つずつ挙げなさい。(d) always @ (posedge clk or reset) の何が問題ですか。
(a) Active-low reset means the reset action happens at value 0, so the sensitivity list must watch the falling edge:(a) 低態有效代表重置動作發生在值為 0 的時候,所以敏感度列表要盯的是下降邊緣:(a) 負論理とはリセット動作が値 0 のときに起こるという意味なので、センシティビティリストは立ち下がりエッジを見る必要があります。
always @ (posedge clk or negedge rst_n) if (!rst_n) q <= 1'b0; else q <= d;
The edge qualifier and the polarity of the test must agree: negedge rst_n pairs with
if (!rst_n). Mismatching them is a synthesis error, not just a style problem.邊緣修飾子與測試的極性必須一致:negedge rst_n 要配 if (!rst_n)。兩者不搭是合成錯誤,不只是寫法風格的問題。エッジ修飾子と判定の極性は一致していなければなりません:negedge rst_n には if (!rst_n) が対応します。食い違えば合成エラーであり、単なるスタイルの問題ではありません。
(b) A synchronous reset is only sampled at the clock edge, so a pulse that rises and falls entirely between two edges is never seen. An asynchronous reset is in the sensitivity list, so its own edge wakes the behavior immediately — independent of the clock. Hence the lecture's caution that a synchronous reset pulse must be wider than one clock period.(b) 同步重置只在時脈邊緣被取樣,所以一個完全落在兩個邊緣之間、起了又落的脈衝根本不會被看到。非同步重置在敏感度列表裡,它自己的邊緣會立刻喚醒該 behavior — 與時脈無關。這就是投影片提醒「同步重置脈衝必須比一個時脈週期還寬」的原因。(b) 同期リセットはクロックエッジでのみサンプルされるため、2 つのエッジのあいだで立って落ちてしまうパルスはまったく見えません。非同期リセットはセンシティビティリストにあるので、自身のエッジが即座に behavior を起動します — クロックとは無関係です。講義が「同期リセットのパルスは 1 クロック周期より広くすること」と注意する理由がこれです。
(c)
Asynchronous: works even when the clock is not running (essential at power-up, and for low-power
modes where the clock is gated off); uses the flip-flop's dedicated reset pin, so it costs no extra logic in the
datapath.
Synchronous: every path is a normal clocked path, so STA covers it and there is no
reset-recovery/removal timing to close; it is also immune to glitches on the reset line, which an asynchronous reset
would propagate straight into the register.(c)
非同步:即使時脈沒在跑也有效(上電時必要,時脈被閘控關掉的低功耗模式也是);它用的是正反器專屬的重置接腳,所以不會在資料路徑上多花任何邏輯。
同步:每條路徑都是一般的時脈路徑,STA 涵蓋得到,也不必去收斂 reset recovery/removal 的時序;而且它對重置線上的突波免疫,那種突波在非同步重置下會直接打進暫存器。(c)
非同期:クロックが動いていなくても効きます(電源投入時に必須で、クロックをゲーティングする低消費電力モードでも同様)。フリップフロップ専用のリセットピンを使うので、データパスに余分な論理を足しません。
同期:どの経路も普通のクロック同期経路なので STA でカバーでき、リセットのリカバリ/リムーバル・タイミングを閉じる必要もありません。さらにリセット線上のグリッチに強く、非同期リセットならそのままレジスタに伝わってしまうものを遮断できます。
(d) reset appears without an edge qualifier while clk has one. Mixing
edge-qualified and non-qualified signals in the same event control is illegal for synthesis: the tool cannot tell
whether you mean an asynchronous reset or a level-sensitive dependency. Every asynchronous control in the list must
carry its own posedge/negedge, and there must be exactly one clock edge.(d) reset 沒有邊緣修飾子,clk 卻有。在同一個事件控制裡混用有邊緣修飾與沒有的訊號,對合成而言是不合法的:工具無法判斷你指的是非同步重置,還是準位相依。列表中每一個非同步控制都必須帶自己的 posedge/negedge,而且只能有恰好一個時脈邊緣。(d) clk にはエッジ修飾子があるのに reset にはありません。同じイベント制御の中でエッジ修飾のある信号とない信号を混ぜるのは合成上不正です。非同期リセットのつもりなのか、レベル依存のつもりなのかをツールが判断できないからです。リスト中の非同期制御にはそれぞれ posedge/negedge を付け、クロックエッジはちょうど 1 つにしてください。
| Construct語法結構構文 | Synthesis behavior合成行為合成時の扱い |
|---|---|
Nets declared as input/output ports宣告為 input/output 埠的 netinput/output ポートとして宣言されたネット | retained會保留保持される |
| Internal nets內部 net内部ネット | may be eliminated by logic optimization; the tool offers directives to force one to survive可能被邏輯最佳化消掉;工具提供指令可以強制保留某一條論理最適化で消されることがある。特定のネットを残すよう強制するディレクティブがツールにある |
wand, worwand、worwand、wor | implemented as logic gates會實作成邏輯閘論理ゲートとして実装される |
integerintegerinteger | 32-bit register by default; the size may be reduced during optimization. Declare constants with a fixed size to keep the hardware small.預設是 32 位元的 register;最佳化過程中位元數可能被縮小。請用固定位元數宣告常數,讓硬體維持精簡。既定では 32 ビットのレジスタ。最適化の過程でビット幅が縮められることがある。ハードウェアを小さく保つため、定数はサイズを明示して宣言すること。 |
real, time, realtimereal、time、realtimereal、time、realtime | not supported不支援非対応 |
x and z are permittedx 與 z 允許出現在哪裡x と z が許される場所| Value值値 | Allowable uses in synthesizable code可合成程式碼中允許的用法合成可能なコードでの許容される用法 |
|---|---|
x | casex; casez; the default of a conditional (if, case, ?:) — where it means "don't care"; assigned to a wire or reg by a UDPcasex;casez;條件式(if、case、?:)的 default — 此時代表「don't care」;由 UDP 指派給 wire 或 regcasex、casez、条件文(if、case、?:)の default(この場合は「ドントケア」の意味)、UDP が wire や reg に与える値 |
z | only in constructs implying a tri-state output — as the default outcome of a conditional statement只能出現在隱含三態輸出的結構中 — 作為條件敘述的預設結果トライステート出力を含意する構文でのみ — 条件文の既定の結果として |
| Operator class運算子類別演算子の分類 | Implementation實作方式実装のされ方 |
|---|---|
| Adder / subtractor加法器/減法器加算器/減算器 | ripple-carry or carry-look-ahead, chosen by the tool from the timing constraint漣波進位或超前進位,由工具依時序約束自行選擇リップルキャリーかキャリー先見か、タイミング制約に応じてツールが選ぶ |
* and /* 與 /* と / | may not be implemented efficiently as combinational logic. Special cases: use shift when one operand is a power of 2; use a part-select for % when the divisor is a power of 2當成組合邏輯實作時未必有效率。特例:其中一個運算元是 2 的冪次時改用位移;除數是 2 的冪次時,% 可用部分選取取代組合せ論理として効率よく実装できるとは限らない。特例:一方のオペランドが 2 のべき乗ならシフトを使い、除数が 2 のべき乗なら % は部分選択で置き換える |
Shift << >>位移 << >>シフト << >> | the shift amount, or the number of bits storing it, must be a constant. Inside a behavior they become shift registers and muxes built from low-level gates — not necessarily mapped to a shift-register library cell位移量,或存放位移量的位元數,必須是常數。寫在 behavior 內時會變成由低階閘組成的移位暫存器與多工器 — 未必會映射到函式庫裡的移位暫存器單元シフト量、またはそれを保持するビット数は定数でなければならない。behavior の中では低レベルのゲートから作られたシフトレジスタとマルチプレクサになり、ライブラリのシフトレジスタセルに割り当てられるとは限らない |
Relational < > <= >=關係 < > <= >=関係 < > <= >= | combinational logic, often an adder/subtractor: $A \ge B$ iff the sign bit of $A-B$ is 0組合邏輯,通常是一個加法器/減法器:$A \ge B$ 的充要條件是 $A-B$ 的符號位元為 0組合せ論理。多くは加算器/減算器:$A \ge B$ であることと $A-B$ の符号ビットが 0 であることは同値 |
Identity == != === !==相等 == != === !==等価 == != === !== | simple combinational comparators. ===/!== are not synthesizable — silicon has no x簡單的組合比較器。===/!== 不可合成 — 矽晶片上沒有 x単純な組合せ比較器。===/!== は合成できない — シリコンに x は存在しない |
| Reduction, bitwise, logical縮減、位元、邏輯リダクション・ビット単位・論理 | translated to Boolean equations, then mapped to physical gates先翻成布林方程式,再映射到實體閘まずブール式に変換され、その後に実ゲートへ割り当てられる |
Conditional ?:條件 ?:条件 ?: | muxes, or gates that implement muxes多工器,或實作多工器功能的閘マルチプレクサ、またはそれを実現するゲート |
Concatenation {}串接 {}連結 {} | generally supported; equivalent to a logical bus with no functionality of its own — zero gates一般都支援;等同於一條本身沒有功能的邏輯匯流排 — 零個閘通常サポートされる。それ自体は機能を持たない論理バスと等価 — ゲート数はゼロ |
Because * is expensive and shifts are free, any multiplication by a constant
should be hand-decomposed into shifts and adds. This is exactly what Lecture 8's temperature converter does —
see Practice 14.因為 * 很貴而位移不用錢,任何乘以常數的運算都該手動拆成位移與加法。第 8 講的溫度轉換器做的正是這件事 — 見練習 14。* は高価でシフトはただ同然なので、定数倍はすべて手作業でシフトと加算に分解すべきです。第 8 講の温度変換器がまさにこれを行っています — 演習 14 を参照。
specify blocks — ignored by synthesis.specify 區塊 — 合成時會被忽略。specify ブロック — 合成では無視されます。`define, `include) — processed normally;
they act before synthesis sees the code.編譯器指令(`define、`include)— 正常處理;它們在合成看到程式碼之前就已經作用完畢。コンパイラディレクティブ(`define、`include)— 通常どおり処理されます。合成がコードを見る前に作用し終えています。s2 appears in the port list but affects nothing,
the port stays — only internal logic is trimmed.沒被用到的輸入仍會保留。如果 s2 出現在埠列表卻什麼都不影響,這個埠還是會留著 — 被修掉的只有內部邏輯。使われていない入力も残ります。s2 がポートリストにあるのに何にも影響しない場合でも、ポート自体は残ります — 削られるのは内部論理だけです。A loop is static (data-independent) if the compiler can determine the number of iterations. Cross that with "contains internal timing control or not" and you get four cases.如果編譯器能判定迭代次數,這個迴圈就是靜態的(與資料無關)。再與「有沒有內部時序控制」交叉,就得到四種情形。コンパイラが繰り返し回数を決定できるとき、そのループは静的(データ非依存)です。これに「内部にタイミング制御があるか」を掛け合わせると 4 通りになります。
| Type類型型 | Static?靜態?静的か | Internal timing control?有內部時序控制?内部タイミング制御があるか | Synthesizes to合成結果合成結果 |
|---|---|---|---|
| I | yes是はい | no否いいえ | combinational logic by loop unrolling — recommended以迴圈展開得到組合邏輯 — 建議使用ループ展開により組合せ論理になる — 推奨 |
| IIIIII | yes是はい | yes是はい | sequential logic; activity distributed over one or more clock cycles — not recommended序向邏輯;活動分散在一個或多個時脈週期 — 不建議順序論理。動作が 1 つ以上のクロックサイクルに分散する — 非推奨 |
| IIIIIIIII | no否いいえ | no否いいえ | not synthesizable — it would be an iterative circuit of data-dependent size不可合成 — 那會是一個大小取決於資料的迭代電路合成不可 — 規模がデータに依存する反復回路になってしまう |
| IVIVIV | no否いいえ | yes是はい | sequential logic, cycle count determined at run time — not recommended序向邏輯,週期數在執行時才決定 — 不建議順序論理。サイクル数は実行時に決まる — 非推奨 |
Type I — the one to use類型 I — 該用的那一種型 I — 使うべきもの
always @ (a or b) begin
for (k = 0; k < 8; k = k + 1)
y[k] = a[k] & b[k];
end
// unrolls to 8 independent AND gates
// change the event control to
// @(posedge clk) and the same loop
// produces 8 registered outputs
Type III — simulates, will not synthesize類型 III — 模擬得動,但合成不了型 III — シミュレーションは通るが合成できない
always @ (data) begin
count = 0;
tmp = data;
while (tmp) begin // bound depends on data
count = count + tmp[0];
tmp = tmp >> 1;
end
end
The "counting ones" problem is the lecture's running example across all four types. The synthesizable version is
Type I — a fixed-bound for loop:「數 1 的個數」是投影片貫穿四種類型的例子。可合成的版本是類型 I — 上界固定的 for 迴圈:「1 の個数を数える」問題は、講義が 4 つの型すべてで使い回す例です。合成可能な版は型 I — 上限が固定された for ループです。
always @ (data) begin count = 0; for (k = 0; k < 8; k = k + 1) // bound is a constant -> static count = count + data[k]; end // unrolls into an adder tree: 8 one-bit addends -> 4-bit result
| TaskTasktask | FunctionFunctionfunction | |
|---|---|---|
| How the tool handles it工具怎麼處理ツールの扱い | expanded inline就地展開インライン展開される | expanded at the site of its call在被呼叫的位置展開呼び出し箇所で展開される |
| Restriction限制制限 | may not contain inout ports; no timing controls不可含 inout 埠;不可有時序控制inout ポートを含めない。タイミング制御も不可 | no incompletely specified case or if不可有規格不完整的 case 或 if記述が不完全な case や if は不可 |
| Result結果結果 | combinational logic (when free of timing control)組合邏輯(在沒有時序控制的前提下)組合せ論理(タイミング制御がない場合) | always combinational logic一律是組合邏輯常に組合せ論理 |
A task used as a full adder and a function used as an arithmetic unit both synthesize to the plain gate networks you would write by hand — the abstraction is free.拿 task 當全加器、拿 function 當算術單元,合成出來的都是你手寫也會得到的那種單純閘網路 — 這層抽象是免費的。task を全加算器として、function を演算ユニットとして使っても、合成されるのは手で書いた場合と同じ素朴なゲート網です — この抽象化はただで手に入ります。
Problem: Classify each loop by type (I–IV) and state whether it synthesizes.題目:把每個迴圈依類型(I–IV)分類,並說明它能不能合成。問題:各ループを型(I–IV)で分類し、合成できるかどうかを答えなさい。
// (a) // (b)
for (i = 0; i < N; i = i + 1) for (i = 0; i < N; i = i + 1)
@(posedge clk) sum = sum + a[i]; sum = sum + a[i];
// N is a parameter
// (c) // (d)
i = 0; i = 0;
while (a[i] == 0) i = i + 1; while (a[i] == 0)
@(posedge clk) i = i + 1;
N is known), but contains an internal edge-
sensitive event control. It does synthesize, into sequential logic spread over N clock cycles, but
the lecture marks this type not recommended: the resulting state machine is implicit and hard
to constrain.(a) 類型 II — 上界是靜態的(N 已知),但內部含有邊緣敏感的事件控制。它確實能合成,變成分散在 N 個時脈週期上的序向邏輯,但投影片把這一類標為不建議:得到的狀態機是隱式的,很難下約束。(a) 型 II — 上限は静的(N は既知)ですが、内部にエッジセンシティブなイベント制御があります。合成はできて、N クロックに分散する順序論理になりますが、講義はこの型を非推奨としています。できあがる状態機械が暗黙的で、制約をかけにくいからです。a. Not
synthesizable. It simulates fine, which is what makes it dangerous: it passes verification and fails
at synthesis. To make it synthesizable, convert to a fixed-bound for with a "found" flag, or
build an explicit FSM.(c) 類型 III — 上界取決於 a 裡的資料。不可合成。它模擬起來好好的,這正是它危險的地方:它通過了驗證,卻在合成時掛掉。要讓它可合成,就改寫成上界固定的 for 加一個「找到了」旗標,或是建一個顯式的 FSM。(c) 型 III — 上限が a の中身に依存します。合成不可。シミュレーションは問題なく通ってしまうのが厄介で、検証を通過してから合成で落ちます。合成できるようにするには、上限を固定した for と「見つかった」フラグに書き換えるか、明示的な FSM を作ります。The practical takeaway: only Type I belongs in RTL. If you need a data-dependent number of iterations, that is a state machine, and you should write it as one (Section 9.3) rather than hoping the tool infers a good one.實務結論:RTL 裡只應該出現類型 I。如果你需要與資料相依的迭代次數,那就是一台狀態機,你應該把它當成狀態機來寫(9.3 節),而不是指望工具幫你推論出一台好的。実務上の結論:RTL に置いてよいのは型 I だけです。データ依存の繰り返し回数が必要なら、それは状態機械なので、ツールが良いものを推論してくれるのを期待せず、状態機械として書いてください(9.3 節)。
A First-In First-Out buffer is the standard elastic store between two blocks running at different rates — the single most reused block in a communication IC. Internally it is a memory array plus a read pointer, a write pointer, and status flags.先進先出緩衝器是兩個速率不同的區塊之間標準的彈性儲存 — 通訊 IC 裡被重用最多次的一個區塊。內部就是一個記憶體陣列,加上讀指標、寫指標與狀態旗標。先入れ先出しバッファは、速度の異なる 2 つのブロックのあいだに置く標準的な弾性記憶であり、通信 IC で最も再利用されるブロックです。中身はメモリ配列に読み出しポインタ・書き込みポインタ・ステータスフラグを添えたものです。
module fifo (data_out, full, empty, data_in, wr, rd, clk, rst); parameter WIDTH = 8, DEPTH = 16, AWID = 4; // AWID = log2(DEPTH) output [WIDTH-1:0] data_out; output full, empty; input [WIDTH-1:0] data_in; input wr, rd, clk, rst; reg [WIDTH-1:0] mem [0:DEPTH-1]; // the storage array reg [AWID-1:0] wr_ptr, rd_ptr; reg [AWID:0] count; // one extra bit: 0 .. DEPTH reg [WIDTH-1:0] data_out; assign full = (count == DEPTH); assign empty = (count == 0); always @ (posedge clk or posedge rst) begin if (rst) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; end else begin if (wr && !full) begin mem[wr_ptr] <= data_in; wr_ptr <= wr_ptr + 1'b1; // wraps naturally at 2^AWID end if (rd && !empty) begin data_out <= mem[rd_ptr]; rd_ptr <= rd_ptr + 1'b1; end case ({wr && !full, rd && !empty}) 2'b10: count <= count + 1'b1; // write only 2'b01: count <= count - 1'b1; // read only default: count <= count; // idle, or simultaneous r+w endcase end end endmodule
count is one bit wider than the pointers. With 4-bit pointers, full and empty both
give wr_ptr == rd_ptr and cannot be distinguished. A separate counter that can reach DEPTH
resolves the ambiguity.count 比指標多一個位元。用 4 位元指標時,滿與空都會給出 wr_ptr == rd_ptr,分不出來。用一個能數到 DEPTH 的獨立計數器就解決了這個歧義。count はポインタより 1 ビット広い。4 ビットのポインタでは、満杯のときも空のときも wr_ptr == rd_ptr となって区別できません。DEPTH まで数えられる別のカウンタを置けば、このあいまいさは解消します。count unchanged — handled by the
default branch, which also completes the case and so prevents a latch.同時讀寫時 count 不變 — 由 default 分支處理,它同時也把 case 補完,因而防止了鎖存器。読み書きが同時に起きたとき count は変わりません — default 分岐が処理します。この分岐は case を完結させる役目も果たし、ラッチを防ぎます。The FIFO application in Lecture 8. Five circuits in a chain:第 8 講中 FIFO 的應用。串成一列的五個電路:第 8 講における FIFO の応用です。5 つの回路が直列につながります。
always @ (posedge clk or posedge rst)
if (rst) temp_reg <= 0;
else if (sample) temp_reg <= temp_sensor; // store/latch the input data
Both obvious codings are wrong for hardware:兩種直覺寫法在硬體上都是錯的:素直に思いつく 2 つの書き方は、どちらもハードウェアとしては誤りです。
assign temp_out = temp_in * 9 / 5 + 32; // non-synthesizable division assign temp_out = (9 * temp_in) / 5 + 32; // same problem
The standard IC-design move is to approximate 1.8 by a sum of powers of two. The lecture uses $1.75 = 1 + \tfrac{1}{2} + \tfrac{1}{4}$.IC 設計的標準做法是用 2 的冪次之和去逼近 1.8。投影片取 $1.75 = 1 + \tfrac{1}{2} + \tfrac{1}{4}$。IC 設計の定石は、1.8 を 2 のべき乗の和で近似することです。講義では $1.75 = 1 + \tfrac{1}{2} + \tfrac{1}{4}$ を使います。
Alternative 1 — 1 + 0.5 + 0.25替代方案 1 — 1 + 0.5 + 0.25代替案 1 — 1 + 0.5 + 0.25
parameter k32 = 6'b100000; // 32
assign temp_out = temp_in
+ (temp_in >> 1)
+ (temp_in >> 2) + k32;
Alternative 2 — 2 − 0.25替代方案 2 — 2 − 0.25代替案 2 — 2 − 0.25
assign temp_out = ((temp_in << 1)
- (temp_in >> 2)) + k32;
Writing it as temp_in/k1 + temp_in/k2 with
parameter k1 = 2'b10, k2 = 3'b100 is synthesizable, because the divisors are constant powers of
two and the tool turns them into shifts. But the result is not $1.8\,T_c$, it is $1.75\,T_c$ — an approximation
error of $-0.05\,T_c$, which at $T_c = 100$ °C is a 5 °C error. Whether that is acceptable is a
specification question, not a coding question. Alternative 2 gives the same value with one adder instead of
two.配上 parameter k1 = 2'b10, k2 = 3'b100 寫成 temp_in/k1 + temp_in/k2 確實可以合成,因為除數是常數且是 2 的冪次,工具會把它們變成位移。但算出來的不是 $1.8\,T_c$ 而是 $1.75\,T_c$ — 逼近誤差為 $-0.05\,T_c$,在 $T_c = 100$ °C 時就是 5 °C 的誤差。這能不能接受是規格問題,不是寫法問題。替代方案 2 用一個加法器就能得到同樣的值,而不是兩個。parameter k1 = 2'b10, k2 = 3'b100 を添えて temp_in/k1 + temp_in/k2 と書けば、除数が定数かつ 2 のべき乗なのでツールがシフトに変換し、確かに合成できます。しかし得られるのは $1.8\,T_c$ ではなく $1.75\,T_c$ で、近似誤差は $-0.05\,T_c$、$T_c = 100$ °C なら 5 °C の誤差です。それが許容できるかは仕様の問題であって、コーディングの問題ではありません。代替案 2 なら加算器 2 個ではなく 1 個で同じ値が得られます。
reg [WIDTH-1:0] d0, d1, d2, d3; always @ (posedge clk) begin // 4-deep shift register d0 <= temp_f; d1 <= d0; d2 <= d1; d3 <= d2; end assign avg = (d0 + d1 + d2 + d3) >> 2; // divide by 4 = shift right 2
Note the same trick again: averaging four samples is a division by a power of two, so it costs a wire re-indexing, not a divider.注意同樣的技巧又出現了:對四個取樣取平均就是除以 2 的冪次,代價只是重新編排線的索引,不是一個除法器。同じ技がまた使われている点に注目してください。4 サンプルの平均は 2 のべき乗による除算なので、コストは配線の添字の付け替えだけで、除算器は不要です。
A bit-slice ALU from the classic era, used here because it exercises every construct in the course: a register file, muxes, an ALU, a shift register, and an output selector, all driven by one instruction word.一顆經典年代的位元切片 ALU。這裡拿它當例子,是因為它把整門課的語法結構都操練了一遍:暫存器檔案、多工器、ALU、移位暫存器與輸出選擇器,全都由一個指令字驅動。古典的な時代のビットスライス ALU です。ここで取り上げるのは、レジスタファイル・マルチプレクサ・ALU・シフトレジスタ・出力セレクタという、この講義のすべての構文を 1 つの命令語で動かして見せてくれるからです。
The 9-bit instruction is split into three independent 3-bit fields:9 位元的指令被切成三個互相獨立的 3 位元欄位:9 ビットの命令は、互いに独立した 3 ビットのフィールド 3 つに分かれます。
| Field欄位フィールド | Controls控制什麼制御する対象 |
|---|---|
i[2:0] | the operands for the ALU (operand selector)ALU 的運算元(運算元選擇器)ALU のオペランド(オペランドセレクタ) |
i[5:3] | the operation of the ALUALU 的運算ALU の演算 |
i[8:6] | the destination of the ALU output (output selector)ALU 輸出的去處(輸出選擇器)ALU 出力の行き先(出力セレクタ) |
// Mnemonics via compiler directives — readability with zero hardware cost `define ADD 3'b000 `define SUBR 3'b001 `define SUBS 3'b010 `define OR 3'b011 `define AND 3'b100 // (1) Register file: 16 words, dual read address reg [3:0] ram [0:15]; assign ad = ram[a_addr]; assign bd = ram[b_addr]; // (3) ALU: a complete case -> a mux, not a priority chain always @ (*) case (i[5:3]) `ADD: {co, F} = r + s + cin; `SUBR: {co, F} = s - r - cin; `SUBS: {co, F} = r - s - cin; `OR: {co, F} = {1'b0, r | s}; `AND: {co, F} = {1'b0, r & s}; default: {co, F} = 5'b0; // completes the case endcase
It is a compendium of the course's rules applied together: `define mnemonics
instead of magic numbers; a register file as a 2-D reg array; every case terminated with
default; mutually exclusive case items so the ALU becomes a balanced mux rather than a priority chain;
non-blocking assignment in the clocked blocks and blocking in the combinational ones. Nothing new — just
everything at once.它是整門課規則同時上場的一本合集:用 `define 助記符取代魔術數字;把暫存器檔案寫成二維 reg 陣列;每個 case 都以 default 收尾;case 項目互斥,讓 ALU 變成平衡的多工器而不是優先權鏈;時脈區塊用非阻擋式賦值、組合區塊用阻擋式。沒有新東西 — 只是全部一次到齊。この講義の規則がいっぺんに使われている見本市です。マジックナンバーの代わりに `define のニーモニックを使い、レジスタファイルを 2 次元の reg 配列で表し、すべての case を default で締め、case 項目を互いに排他的にして ALU を優先順位チェーンではなくバランスの取れたマルチプレクサにし、クロック同期ブロックではノンブロッキング、組合せブロックではブロッキング代入を使う。新しいものは何もありません — ただすべてが一度に出てくるだけです。
Problem: (a) Implement $y = 1.8x$ using only shifts and adds, with error smaller than the
lecture's 1.75 approximation. (b) How many adders does your version need? (c) For an 8-bit unsigned
temp_in, how wide must temp_out be for $T_f = 1.75\,T_c + 32$ not to overflow?題目:(a) 只用位移與加法實作 $y = 1.8x$,誤差要比投影片的 1.75 逼近更小。(b) 你的版本需要幾個加法器?(c) 若 temp_in 是 8 位元無號數,temp_out 要多寬,$T_f = 1.75\,T_c + 32$ 才不會溢位?問題:(a) シフトと加算だけで $y = 1.8x$ を実装し、講義の 1.75 近似より誤差を小さくしなさい。(b) その版には加算器がいくつ必要ですか。(c) temp_in が 8 ビット符号なしのとき、$T_f = 1.75\,T_c + 32$ がオーバーフローしないためには temp_out は何ビット必要ですか。
(a) Expand 1.8 in binary: $1.8_{10} = 1.11001100\overline{1100}_2$. Truncating after four fractional bits gives(a) 把 1.8 展開成二進位:$1.8_{10} = 1.11001100\overline{1100}_2$。取到小數點後四位後截斷,得到(a) 1.8 を 2 進展開すると $1.8_{10} = 1.11001100\overline{1100}_2$ です。小数第 4 位で打ち切ると、
$$1 + \tfrac{1}{2} + \tfrac{1}{4} + \tfrac{1}{32} = 1.78125$$$$1 + \tfrac{1}{2} + \tfrac{1}{4} + \tfrac{1}{32} = 1.78125$$$$1 + \tfrac{1}{2} + \tfrac{1}{4} + \tfrac{1}{32} = 1.78125$$assign y = x + (x >> 1) + (x >> 2) + (x >> 5);
Error is $1.8 - 1.78125 = 0.01875$, versus $1.8 - 1.75 = 0.05$ for the lecture's version — about 2.7 times better. Adding the next term $\tfrac{1}{64}$ gives 1.796875, error 0.003125.誤差是 $1.8 - 1.78125 = 0.01875$,對比投影片版本的 $1.8 - 1.75 = 0.05$ — 大約好 2.7 倍。再加上一項 $\tfrac{1}{64}$ 得到 1.796875,誤差 0.003125。誤差は $1.8 - 1.78125 = 0.01875$ で、講義版の $1.8 - 1.75 = 0.05$ に対しておよそ 2.7 倍良くなります。さらに $\tfrac{1}{64}$ を足すと 1.796875、誤差は 0.003125 です。
(b) Four terms require three adders (plus one more for the +32).
The lecture's 1.75 needs two adders for the multiply. So the improved accuracy costs one adder — a genuine
area-versus-accuracy trade, and exactly the kind of decision the course means by "do resource sharing before RTL
coding".(b) 四項需要三個加法器(再加一個做 +32)。投影片的 1.75 在乘法部分只要兩個加法器。所以更高的精度代價是多一個加法器 — 這是不折不扣的面積對精度取捨,也正是本課程說「資源共用要在寫 RTL 之前做」的那種決策。(b) 4 項には加算器 3 個が必要です(+32 用にもう 1 個)。講義の 1.75 は乗算部分に加算器 2 個で済みます。つまり精度を上げる代償は加算器 1 個 — 面積と精度の正真正銘のトレードオフであり、この講義が「リソース共有は RTL を書く前に」というときに念頭に置いている判断そのものです。
A cheaper route to similar accuracy: $1.8 \approx 2 - \tfrac{1}{4} + \tfrac{1}{16} - \ldots$ Using $2 - \tfrac{1}{4} = 1.75$ takes one adder/subtractor, matching Alternative 2 in the lecture; adding $+\tfrac{1}{32}$ gives 1.78125 with two.要達到相近精度還有更便宜的路:$1.8 \approx 2 - \tfrac{1}{4} + \tfrac{1}{16} - \ldots$ 只取 $2 - \tfrac{1}{4} = 1.75$ 需要一個加減器,等同投影片的替代方案 2;再加上 $+\tfrac{1}{32}$ 得到 1.78125,需要兩個。同程度の精度に達するより安い道もあります:$1.8 \approx 2 - \tfrac{1}{4} + \tfrac{1}{16} - \ldots$。$2 - \tfrac{1}{4} = 1.75$ なら加減算器 1 個で、講義の代替案 2 と同じです。$+\tfrac{1}{32}$ を足して 1.78125 にするなら 2 個必要です。
(c) Worst case is $x = 255$:(c) 最壞情況是 $x = 255$:(c) 最悪の場合は $x = 255$ です。
$$y_{\max} = 1.75 \times 255 + 32 = 446.25 + 32 = 478.25$$$$y_{\max} = 1.75 \times 255 + 32 = 446.25 + 32 = 478.25$$$$y_{\max} = 1.75 \times 255 + 32 = 446.25 + 32 = 478.25$$$\lceil \log_2 479 \rceil = 9$, so 9 bits suffice for the integer part. If you keep the two fractional bits produced by the shifts rather than truncating them, the result needs 11 bits total in a $9.2$ fixed- point format.$\lceil \log_2 479 \rceil = 9$,所以整數部分 9 個位元就夠。如果你把位移產生的兩個小數位保留下來而不截掉,結果需要總共 11 個位元,格式為 $9.2$ 定點數。$\lceil \log_2 479 \rceil = 9$ なので、整数部は 9 ビットで足ります。シフトで生じる小数 2 ビットを切り捨てずに残すなら、$9.2$ の固定小数点形式で合計 11 ビット必要です。
The general habit: after any constant-multiply decomposition, recompute the worst-case output range and size the target accordingly. Silent truncation in a temperature path is a wrong reading; in a communication receiver it is a raised bit-error rate.通用的習慣:做完任何常數乘法分解之後,重新算一次最壞情況的輸出範圍,再據此決定目標的位元寬度。溫度路徑上的無聲截斷只是讀數錯了;在通訊接收機裡,那就是位元錯誤率上升。身につけるべき習慣:定数乗算を分解したら、必ず最悪ケースの出力範囲を計算し直し、それに合わせて格納先の幅を決めること。温度計測経路での黙った切り捨ては読み値の誤りで済みますが、通信受信機ではビット誤り率の悪化になります。
assign or a primitive/module outputNet:由 assign 或原件/模組輸出驅動ネット:assign か、プリミティブ/モジュールの出力に駆動されるz; uninitialised register = x未被驅動的 net = z;未初始化的 register = x駆動されていないネット = z、初期化されていないレジスタ = xwire未宣告的識別字預設為 wire宣言されていない識別子は既定で wire= blocking → combinational always @(*)= 阻擋式 → 組合的 always @(*)= ブロッキング → 組合せの always @(*)<= non-blocking → sequential always @(posedge clk)<= 非阻擋式 → 序向的 always @(posedge clk)<= ノンブロッキング → 順序回路の always @(posedge clk)#5 a = b; suspends the flow#5 a = b; 會暫停流程#5 a = b; はフローを止めるa = #5 b; evaluates now, assigns later, still suspendsa = #5 b; 現在求值、稍後賦值,一樣會暫停a = #5 b; は今評価して後で代入し、やはりフローを止めるa <= #5 b; evaluates now, assigns later, does not suspenda <= #5 b; 現在求值、稍後賦值,不會暫停a <= #5 b; は今評価して後で代入し、フローを止めないalways @(*))敏感度列表要完整(或用 always @(*))センシティビティリストを完全にする(または always @(*) を使う)default on every case每個 case 都要有 defaultすべての case に default を置くelse on every combinational if chain每個組合的 if 串都要有 else組合せの if 連鎖にはすべて else を置くinitial, fork/join, wait, named eventsinitial、fork/join、wait、具名事件initial、fork/join、wait、名前付きイベントforce/release, $tasks延遲控制、force/release、$ 系統任務遅延制御、force/release、$ システムタスクspecify blocks序向 UDP、specify 區塊順序回路 UDP、specify ブロック=== / !==, real/time===/!==、real/time===/!==、real/time| Trap陷阱思い込み | What actually happens實際上會怎樣実際に起きること |
|---|---|
reg means a flip-flopreg 就代表正反器reg はフリップフロップを意味する | No. It means "holds a value between procedural assignments". Only a clock edge creates a flip-flop.不對。它的意思是「在兩次程序式賦值之間保住一個值」。只有時脈邊緣才會造出正反器。違います。「手続き型代入と代入の間で値を保持する」という意味です。フリップフロップを生むのはクロックエッジだけです。 |
case is faster than ifcase 比 if 快case は if より速い | No. What matters is whether the conditions are mutually exclusive → mux, or overlapping → priority chain.不對。重點在於條件是否互斥 → 多工器,還是重疊 → 優先權鏈。違います。効くのは条件が互いに排他的か(→ マルチプレクサ)、重なっているか(→ 優先順位チェーン)です。 |
a == b is always 0 or 1a == b 一定是 0 或 1a == b は必ず 0 か 1 になる | No. It is x if either operand contains x/z. Only === is guaranteed 0 or 1.不對。只要有一邊含 x/z,結果就是 x。只有 === 才保證是 0 或 1。違います。どちらかに x/z があれば結果は x です。0 か 1 が保証されるのは === だけです。 |
if (x) takes the true branchif (x) 會走真分支if (x) は真の分岐を通る | No. True is only the value 1; {0, x, z} are all false.不對。真只有值 1;{0, x, z} 全都是假。違います。真は値 1 だけで、{0, x, z} はすべて偽です。 |
Missing else always makes a latch少了 else 一定會生鎖存器else がなければ必ずラッチができる | Only in a level-sensitive behavior. In always @(posedge clk) it makes a clock-enabled flip-flop, which is fine.只有在準位敏感的 behavior 裡才是。在 always @(posedge clk) 裡它做出的是帶 clock enable 的正反器,這沒有問題。レベルセンシティブな behavior の場合だけです。always @(posedge clk) の中ではクロックイネーブル付きフリップフロップになり、問題ありません。 |
| Non-blocking delays the assignment by one cycle非阻擋式會把賦值延後一個週期ノンブロッキングは代入を 1 サイクル遅らせる | No. It delays the assignment to the end of the current time step. The one-cycle behavior comes from the clock edge, not the operator.不對。它把賦值延到目前這個時間步的末尾。一個週期的行為來自時脈邊緣,不是來自這個運算子。違います。代入を現在の時間ステップの終わりまで遅らせるだけです。1 サイクル分の振る舞いはクロックエッジによるもので、この演算子によるものではありません。 |
&(01xx) is x&(01xx) 是 x&(01xx) は x になる | No, it is 0. A controlling value settles a reduction regardless of unknowns.不對,是 0。不管有沒有未知值,控制值都能定下縮減運算的結果。違います、0 です。不定値があっても支配値がリダクションの結果を決めます。 |
| A narrow glitch always shows up at the gate output窄突波一定會出現在閘的輸出狭いグリッチは必ずゲート出力に現れる | No. Inertial delay swallows any pulse shorter than the gate delay.不對。慣性延遲會吞掉任何比閘延遲還短的脈衝。違います。慣性遅延はゲート遅延より短いパルスをすべて飲み込みます。 |
| Primitive instances must be named原件實體必須命名プリミティブのインスタンスには名前が必要 | No — optional for primitives and UDPs, mandatory for module instances.不對 — 原件與 UDP 可以省略,模組實體則是必要的。違います — プリミティブと UDP では省略でき、モジュールのインスタンスでは必須です。 |
| An incomplete sensitivity list is only a simulation issue敏感度列表不完整只是模擬的問題センシティビティリストの不備はシミュレーションだけの問題 | Worse: simulation and synthesis disagree, so the bug survives verification.更糟:模擬與合成會互相矛盾,所以這個 bug 會活著通過驗證。もっと悪いです。シミュレーションと合成が食い違うため、バグが検証を生き延びます。 |
Problem:題目:問題:
reg?為什麼組合邏輯 UDP 的輸出必須是 net,而序向 UDP 的輸出必須是 reg?組合せ論理 UDP の出力はネットでなければならず、順序回路 UDP の出力は reg でなければならないのはなぜですか。`timescale 10ps/1ps, what delay does nor #3.57 (z, x1, x2) produce?在 `timescale 10ps/1ps 之下,nor #3.57 (z, x1, x2) 產生多少延遲?`timescale 10ps/1ps のもとで、nor #3.57 (z, x1, x2) の遅延はいくらですか。{3{a}, 2{b}} expand to?{3{a}, 2{b}} 會展開成什麼?{3{a}, 2{b}} は何に展開されますか。posedge.寫出算作 posedge 的三種轉態。posedge とみなされる 3 つの遷移を挙げなさい。always block contains only a = ~a; with no timing control. What happens?某個 always 區塊裡只有 a = ~a;,沒有任何時序控制。會發生什麼事?ある always ブロックに a = ~a; だけがあり、タイミング制御が一切ありません。何が起こりますか。$stop, $finish, and disable.區分 $stop、$finish 與 disable。$stop、$finish、disable の違いを述べなさい。reg can hold a value between events.組合邏輯 UDP 的輸出是目前輸入的純函數,不需要儲存 — 一條 net 就承載得了。序向 UDP 有狀態,必須在兩次求值之間保住,而只有 reg 能在事件之間保住一個值。組合せ論理 UDP の出力は現在の入力の純粋な関数なので記憶は不要で、ネットで運べます。順序回路 UDP には評価と評価のあいだ保持しなければならない状態があり、イベント間で値を保てるのは reg だけです。{a, a, a, b, b} — a 5-bit vector.{a, a, a, b, b} — 一個 5 位元的向量。{a, a, a, b, b} — 5 ビットのベクタです。0->1, 0->x, x->1. (Symmetrically, negedge is
1->0, 1->x, x->0.)0->1、0->x、x->1。(對稱地,negedge 是 1->0、1->x、x->0。)0->1、0->x、x->1。(対称的に negedge は 1->0、1->x、x->0 です。)always that is to run forever needs a
# or @ somewhere in its body.模擬器會卡死。這個區塊在同一個時間步內不斷觸發自己,模擬時間永遠推不動,事件清單也永遠清不空。任何要永遠跑下去的 always,本體裡都必須有個 # 或 @。シミュレータがハングします。そのブロックが同じ時間ステップ内で自分自身を再起動し続け、シミュレーション時刻は進まず、イベントリストも空になりません。永久に回る always には、本体のどこかに # か @ が必要です。$stop halts the simulator into interactive mode — you can resume.
$finish ends the whole simulation and returns to the OS.
disable terminates only a named block or task; simulation continues.$stop 讓模擬器停進互動模式 — 還能繼續。$finish 結束整個模擬並回到作業系統。disable 只終止某個具名區塊或 task;模擬會繼續下去。$stop はシミュレータを対話モードで停止させます — 再開できます。$finish はシミュレーション全体を終了して OS に戻ります。disable は名前付きブロックか task だけを終了させ、シミュレーションは続きます。wr_ptr == rd_ptr and are
indistinguishable. A counter that can represent 0 through DEPTH inclusive needs $n+1$ bits and separates the
two cases unambiguously.用 $n$ 位元指標時,滿與空兩種情況都給出 wr_ptr == rd_ptr,無法區分。而一個能表示 0 到 DEPTH(含)的計數器需要 $n+1$ 個位元,這樣就能毫不含糊地把兩者分開。$n$ ビットのポインタでは、満杯と空のどちらでも wr_ptr == rd_ptr となり区別できません。0 から DEPTH まで(両端を含む)を表せるカウンタには $n+1$ ビットが必要で、これなら 2 つの状態を明確に分けられます。Verilog is a platform. It supports hardware design (the design module) and also C/C++-like coding (the testbench, non-synthesized). How do you write Verilog well?Verilog 是一個平台。它既支援硬體設計(設計模組),也支援類似 C/C++ 的寫程式方式(測試平台,不合成)。那要怎麼把 Verilog 寫好?Verilog はプラットフォームです。ハードウェア設計(設計モジュール)も、C/C++ に近いコーディング(合成しないテストベンチ)も支えます。では、どうすれば Verilog をうまく書けるでしょうか。
assign blocks and always blocks.養成好的撰寫習慣:命名規則、註解,以及 assign 區塊與 always 區塊之間一致的分工。良い書き方の習慣をつけること:命名規則、コメント、そして assign ブロックと always ブロックの一貫した使い分け。Hardware divides into two parts — combinational circuits and sequential circuits. Draw the picture (the architecture) first, then make the connections (the coding).硬體分成兩部分 — 組合電路與序向電路。先畫圖(架構),再接線(寫程式)。ハードウェアは 2 つに分かれます — 組合せ回路と順序回路です。まず絵(アーキテクチャ)を描き、それから配線(コーディング)をすること。