Outline — click to expand大綱 — 點擊展開アウトライン — クリックで展開
1. Behaviors1. 行為描述1. ビヘイビア
2. Blocking / Non-blocking2. 阻擋式/非阻擋式2. ブロッキング/ノンブロッキング
3. Procedural Continuous Assignment3. 程序式連續賦值3. 手続き型連続代入
4. Timing Controls4. 時序控制4. タイミング制御
5. Intra-Assignment Delay5. 賦值內延遲5. 代入内遅延
6. Simulation Scheduling6. 模擬排程6. シミュレーションのスケジューリング
7. Activity Flow Control7. 流程控制7. 動作フロー制御
8. fork ... join & Races8. fork ... join 與競爭8. fork ... join と競合
9. Summary9. 總結9. まとめ
← DCIC Study Guides← DCIC 自學指南總覽← DCIC 自学ガイド一覧
EE5733 Digital Communication IC Design · Lecture 4 (Part 1)EE5733 數位通訊積體電路設計 · 第 4 講(上)EE5733 デジタル通信 IC 設計 · 第 4 回(前編)

Behavioral Descriptions行為描述動作記述

initial / always, blocking vs non-blocking, procedural continuous assignment, timing controls, intra-assignment delay, scheduling, flow control and fork/join — a self-study guide to behavioral descriptionsinitial / always、阻擋式與非阻擋式賦值、程序式連續賦值、時序控制、賦值內延遲、模擬排程、流程控制與 fork/join — 行為描述自學指南initial / always、ブロッキング代入とノンブロッキング代入、手続き型連続代入、タイミング制御、代入内遅延、スケジューリング、フロー制御と fork/join — 動作記述の自学ガイド

Contents目錄目次

  1. Behaviors: initial and always行為描述:initial 與 alwaysビヘイビア:initial と always
  2. Blocking vs Non-Blocking Assignment阻擋式與非阻擋式賦值ブロッキング代入とノンブロッキング代入
  3. Procedural Continuous Assignment (PCA)程序式連續賦值(PCA)手続き型連続代入(PCA)
  4. Procedural Timing Controls程序式時序控制手続き型タイミング制御
  5. Intra-Assignment Delay賦值內延遲代入内遅延
  6. Simulation of Procedural Assignments程序式賦值的模擬手続き型代入のシミュレーション
  7. Activity Flow Control流程控制動作フロー制御
  8. Parallel Activity Flow: fork ... join平行流程:fork ... join並列動作フロー:fork ... join
  9. Summary and Exam Checklist總結與考前重點まとめと試験前チェックリスト

1. Behaviors: initial and always1. 行為描述:initial 與 always1. ビヘイビア:initial と always

1.1 Merging all different levels1.1 混合各種不同的描述層次1.1 あらゆる記述レベルの混在

A single Verilog module may freely mix every description level: continuous assignments (dataflow), primitive and UDP instances (gate level), sub-module instances (structural) and procedural blocks (behavioral).同一個 Verilog 模組可以自由混用所有描述層次:連續賦值(資料流)、基本閘與 UDP 的實體化(閘層次)、子模組的實體化(結構式),以及程序區塊(行為式)。一つの Verilog モジュールの中で、あらゆる記述レベルを自由に混在させてよい。連続代入(データフロー)、プリミティブと UDP のインスタンス(ゲートレベル)、サブモジュールのインスタンス(構造記述)、そして手続きブロック(動作記述)である。

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      // "always" block
    ...
  end
endmodule

1.2 Procedural assignments: initial vs always1.2 程序式賦值:initial 與 always1.2 手続き型代入:initial と always

initial — runs onceinitial — 只執行一次initial — 一度だけ実行
initial            // an "initial" behavior
  begin
    sig_a = 0;     // procedural assignments
    sig_b = 1;     // execute sequentially
    sig_c = 0;
  end
always — infinite loopalways — 無窮迴圈always — 無限ループ
always @ (b or c or d) begin
  if (b == 1'b1) begin
    a = c;
  end
  else begin
    a = d;
  end
end
Key points (click to expand)重點整理(點擊展開)要点のまとめ(クリックで展開)
  • initial: runs exactly once, starting at time 0; not synthesizable, used in a test-bench to generate stimulus.initial:只執行一次,從時間 0 開始;不可合成,用在 test-bench 產生激勵。initial:時刻 0 から一度だけ実行される。合成はできず、テストベンチで刺激を与えるために使う。
  • always: an infinite loop; combined with an @(...) sensitivity list it re-evaluates every time a listed signal changes.always:無窮迴圈;配合 @(...) 敏感列表,每當列表中訊號改變就重新計算。always:無限ループ。@(...) の感度リストと組み合わせると、リスト中の信号が変化するたびに再評価される。
  • Several initial / always blocks run in parallel with one another, while the statements inside a block execute in order.多個 initial / always 區塊之間是並行的,區塊內的敘述則依序執行。複数の initial / always ブロックは互いに並行に動作し、ブロック内の文は順番に実行される。
  • The example always @(b or c or d) above is a 2-to-1 multiplexer: the sensitivity list must contain every input that is read, otherwise the synthesized result and the simulation disagree.上例 always @(b or c or d) 是一個 2 對 1 多工器:敏感列表必須包含所有讀到的輸入,否則合成結果與模擬不一致。上の例 always @(b or c or d) は 2 対 1 のマルチプレクサである。感度リストには読み出すすべての入力を含めなければならず、さもないと合成結果とシミュレーションが一致しない。

2. Blocking vs Non-Blocking Assignment2. 阻擋式與非阻擋式賦值2. ブロッキング代入とノンブロッキング代入

2.1 The two operators2.1 兩種賦值運算子2.1 二つの代入演算子

Blocking =阻擋式 =ブロッキング =Non-blocking <=非阻擋式 <=ノンブロッキング <=
Semantics語意意味Assignment completes before the next statement starts賦值完成之後,下一個敘述才開始執行代入が完了してから次の文が実行されるAll RHS sampled first; LHS updated together at the end of the time step ("in parallel")先取樣所有右手邊(RHS);左手邊(LHS)在時間步結束時一起更新(「同時」發生)まずすべての右辺を採取し、時間ステップの終わりに左辺をまとめて更新する(「並行」に起こる)
Example範例例a = 0; a = 1; c = a; → c = 1a = 0; a <= 1; c = a; → c = 0
Typical use典型用途典型的な用途Combinational logic, test-bench sequencing組合邏輯、測試平台(test-bench)的流程安排組合せ論理、テストベンチの手順記述Sequential (clocked) logic序向(時脈同步)邏輯順序(クロック同期)論理
Ambiguous double non-blocking write同一步內兩次非阻擋式寫入是模稜兩可的同一ステップでの二重ノンブロッキング書き込みは曖昧

d <= 0; d <= 1; in the same time step — the lecture calls this ambiguous and treats it as illegal style. (The IEEE standard actually guarantees the last one wins within a single block, so d = 1, but relying on this is poor practice and some tools warn.)在同一個時間步內寫 d <= 0; d <= 1; — 課堂上認為這是模稜兩可的,視為不合法的寫法。(IEEE 標準其實保證同一區塊內最後一次生效,所以 d = 1;但依賴這一點並不是好習慣,有些工具會發出警告。)同一の時間ステップで d <= 0; d <= 1; と書く — 講義ではこれを曖昧とみなし、許されない書き方として扱う。(IEEE 規格では実際には同一ブロック内の最後の代入が勝つと保証されているので d = 1 になるが、これに頼るのは悪い習慣であり、警告を出すツールもある。)

2.2 Swap examples2.2 交換(swap)範例2.2 スワップの例

Start from a = 1; b = 0;.起始值為 a = 1; b = 0;。初期値を a = 1; b = 0; とする。

Code程式碼コードValues used實際讀到的值実際に読まれる値Result結果結果
a = b; b = a;b=0, then the new a=0b=0,接著讀到的是新的 a=0b=0、次に新しい a=0a=0, b=0 (no swap)a=0, b=0(沒有交換)a=0, b=0(交換されない)
b = a; a = b;a=1, then the new b=1a=1,接著讀到的是新的 b=1a=1、次に新しい b=1a=1, b=1 (no swap)a=1, b=1(沒有交換)a=1, b=1(交換されない)
a <= b; b <= a;old b=0, old a=1舊的 b=0、舊的 a=1古い b=0、古い a=1a=0, b=1 (swapped)a=0, b=1(成功交換)a=0, b=1(交換される)
b <= a; a <= b;old a=1, old b=0舊的 a=1、舊的 b=0古い a=1、古い b=0a=0, b=1 (swapped; order irrelevant)a=0, b=1(成功交換;順序無關)a=0, b=1(交換される。順序は無関係)
Key result關鍵結論重要な結論

With non-blocking assignments every RHS sees the values from before the time step, so the statement order does not matter. This is exactly how a bank of flip-flops sharing one clock behaves.使用非阻擋式賦值時,每一個 RHS 讀到的都是這個時間步開始之前的值,所以敘述的先後順序無關緊要。這正是一組共用同一時脈的正反器(flip-flop)的行為。ノンブロッキング代入では、どの右辺も時間ステップの直前の値を読む。したがって文の順序は結果に影響しない。これは一つのクロックを共有するフリップフロップ群の振る舞いそのものである。

2.3 Merged example — four flavours of delay2.3 綜合範例 — 四種延遲寫法2.3 総合例 — 四種類の遅延の書き方

module blocking_nonblocking();
reg a, b, c, d;

initial begin            // (A) blocking, inter-statement delay
  #10 a = 0;
  #11 a = 1;
  #12 a = 0;
  #13 a = 1;
end

initial begin            // (B) non-blocking, inter-statement delay
  #10 b <= 0;
  #11 b <= 1;
  #12 b <= 0;
  #13 b <= 1;
end

initial begin            // (C) blocking, intra-assignment delay
  c = #10 0;
  c = #11 1;
  c = #12 0;
  c = #13 1;
end

initial begin            // (D) non-blocking, intra-assignment delay
  d <= #10 0;
  d <= #11 1;
  d <= #12 0;
  d <= #13 1;
end

initial begin
  $monitor("TIME = %d A = %b B = %b C = %b D = %b", $time, a, b, c, d);
  #50 $finish;
end
endmodule
Block區塊ブロックWhy原因理由Change times變化時刻変化する時刻
A (#d a = v)Each delay suspends the block, delays accumulate每個延遲都會暫停整個區塊,所以延遲會累加各遅延がブロック全体を停止させるため、遅延が累積する10, 21, 33, 46
B (#d b <= v)Same — the # precedes the statement and still suspends the block同上 — # 放在敘述之前,一樣會暫停區塊同上 — # は文の前に置かれており、やはりブロックを停止させる10, 21, 33, 46
C (c = #d v)Blocking: block waits for each assignment to complete, so delays accumulate阻擋式:區塊要等每一次賦值完成才往下走,所以延遲累加ブロッキング:ブロックは各代入の完了を待つので、遅延が累積する10, 21, 33, 46
D (d <= #d v)Non-blocking: all four are scheduled at time 0 and the block does not wait非阻擋式:四行都在時間 0 被排程,區塊不等待ノンブロッキング:四つとも時刻 0 でスケジュールされ、ブロックは待たない10, 11, 12, 13
TIME =  0 A = x B = x C = x D = x
TIME = 10 A = 0 B = 0 C = 0 D = 0
TIME = 11 A = 0 B = 0 C = 0 D = 1
TIME = 12 A = 0 B = 0 C = 0 D = 0
TIME = 13 A = 0 B = 0 C = 0 D = 1
TIME = 21 A = 1 B = 1 C = 1 D = 1
TIME = 33 A = 0 B = 0 C = 0 D = 1
TIME = 46 A = 1 B = 1 C = 1 D = 1
abcd 0 10 21 33 46 t
Merged example waveform: a, b, c toggle at the accumulated times 10, 21, 33, 46; d glitches 0→1→0→1 at 10–13 because all four non-blocking intra-delay assignments are scheduled at time 0.綜合範例波形:a、b、c 在累加後的時刻 10、21、33、46 翻轉;d 則在 10–13 之間出現 0→1→0→1 的毛刺,因為四個非阻擋式賦值內延遲全都在時間 0 被排程。総合例の波形:a、b、c は累積した時刻 10、21、33、46 で反転する。d は四つのノンブロッキング代入内遅延がすべて時刻 0 でスケジュールされるため、10〜13 の間に 0→1→0→1 のグリッチを生じる。
Explanation: why is only d different? (click to expand)解說:為什麼只有 d 不一樣?(點擊展開)解説:なぜ d だけが違うのか?(クリックで展開)
  • #10 a = 0;: suspend the whole block for 10 units first, then perform the assignment → the delays accumulate.#10 a = 0;:先暫停整個區塊 10 個單位,再執行賦值 → 延遲會累加。#10 a = 0;:まずブロック全体を 10 単位停止させ、その後に代入を実行する → 遅延が累積する。
  • #10 b <= 0;: the # again sits in front of the statement and still suspends the block → same as a.#10 b <= 0;:# 一樣放在敘述前面,仍然是暫停區塊 → 與 a 相同。#10 b <= 0;:# はやはり文の前にあり、ブロックを停止させる → a と同じになる。
  • c = #10 0;: the RHS is evaluated at once but the write is postponed by 10; because it is blocking, the block waits for that write to finish before moving on → the delays accumulate too.c = #10 0;:RHS 立即計算,但「賦值」延後 10;因為是阻擋式,區塊要等這次賦值完成才往下走 → 也累加。c = #10 0;:右辺はただちに評価されるが、「書き込み」が 10 だけ先送りされる。ブロッキングなのでブロックはその書き込みの完了を待つ → やはり累積する。
  • d <= #10 0;: a non-blocking assignment only schedules a future update and the block does not wait, so all four lines are scheduled at time 0 and take effect at 10, 11, 12 and 13 respectively.d <= #10 0;:非阻擋式只「排程」未來的更新,區塊不等待,四行都在時間 0 被排程,分別在 10、11、12、13 生效。d <= #10 0;:ノンブロッキング代入は将来の更新を「スケジュール」するだけでブロックは待たない。四行とも時刻 0 でスケジュールされ、それぞれ 10、11、12、13 で有効になる。
Practice 1 — Register swap練習 1 — 暫存器交換演習 1 — レジスタのスワップ

Problem: Inside always @(posedge clk), which of the following swap x and y every clock? (a) x = y; y = x; (b) x <= y; y <= x; (c) tmp = x; x = y; y = tmp; (d) y <= x; x = y;題目:在 always @(posedge clk) 之中,下列哪些寫法會在每個時脈交換 x 與 y?(a) x = y; y = x; (b) x <= y; y <= x; (c) tmp = x; x = y; y = tmp; (d) y <= x; x = y;問題:always @(posedge clk) の中で、次のうちクロックごとに x と y を交換するのはどれか。(a) x = y; y = x; (b) x <= y; y <= x; (c) tmp = x; x = y; y = tmp; (d) y <= x; x = y;

Click to reveal solution點擊展開解答クリックで解答を表示

(a) No — both end up equal to the old y.(a) 不行 — 兩者最後都等於舊的 y。(a) 不可 — どちらも古い y と等しくなってしまう。

(b) Yes — both RHS sample the old values.(b) 可以 — 兩個 RHS 取樣到的都是舊值。(b) 可 — 両方の右辺が古い値を採取する。

(c) Yes in simulation; synthesizes to the same two flip-flops (tmp becomes a wire).(c) 在模擬上可以;合成後同樣是兩個正反器(tmp 變成一條 wire)。(c) シミュレーション上は可。合成すると同じ二つのフリップフロップになる(tmp は配線になる)。

(d) Yes numerically (x = y reads the old y since the non-blocking update has not happened yet), but mixing = and <= in one clocked block is bad style and invites simulation/synthesis mismatch. Use (b).(d) 數值上可以(非阻擋式的更新還沒發生,所以 x = y 讀到的是舊的 y),但在同一個時脈區塊內混用 = 與 <= 是不良寫法,容易造成模擬與合成不一致。請用 (b)。(d) 数値上は交換される(ノンブロッキングの更新はまだ起きていないので x = y は古い y を読む)。しかし一つのクロックブロック内で = と <= を混ぜるのは悪い書き方であり、シミュレーションと合成の不一致を招く。(b) を使うこと。

3. Procedural Continuous Assignment (PCA)3. 程序式連續賦值(PCA)3. 手続き型連続代入(PCA)

A PCA is executed from inside a procedural block, but once executed it behaves like a continuous assignment: the target keeps following the RHS expression until the binding is removed.PCA 是在程序區塊內執行的,但一旦執行,它的行為就像連續賦值:在綁定被解除之前,目標會持續跟著 RHS 運算式變化。PCA は手続きブロックの内部で実行されるが、いったん実行されると連続代入のように振る舞う。すなわち、束縛が解除されるまで対象は右辺の式に追従し続ける。

3.1 Method 1: assign ... deassign3.1 方法一:assign ... deassign3.1 方法 1:assign ... deassign

Example 1 — 4-to-1 mux with PCA範例 1 — 用 PCA 寫的 4 對 1 多工器例 1 — PCA で書いた 4 対 1 マルチプレクサ

module mux4_PCA (a, b, c, d, select, y_out);
  input       a, b, c, d;
  input [1:0] select;
  output      y_out;
  reg         y_out;

  always @ (select) begin          // Caution!!
    if      (select == 0) assign y_out = a;
    else if (select == 1) assign y_out = b;
    else if (select == 2) assign y_out = c;
    else if (select == 3) assign y_out = d;
    else                  assign y_out = 1'b0;
  end
endmodule
Caution — the sensitivity list注意 — 敏感列表注意 — 感度リスト

Only select is in the list, yet y_out still follows changes on a–d, because the PCA binding is continuous. Replace assign y_out = a with a plain y_out = a and the model breaks: data changes without a select change would be ignored (and synthesis would build a mux anyway, giving a sim/synth mismatch).列表裡只有 select,但 y_out 仍然會跟著 a–d 的變化,因為 PCA 的綁定是連續的。若把 assign y_out = a 改成單純的 y_out = a,模型就壞了:select 沒變而資料改變時會被忽略(而合成仍舊會做出一個多工器,造成模擬與合成不一致)。リストには select しか入っていないが、PCA の束縛が連続的であるため y_out は a〜d の変化にも追従する。assign y_out = a を単なる y_out = a に置き換えるとモデルは壊れる。select が変わらずにデータだけが変化した場合、それが無視されてしまうからである(それでも合成はマルチプレクサを作るので、シミュレーションと合成が食い違う)。

Example 2 — Flip-flop with asynchronous clear/preset範例 2 — 具非同步清除/預設的正反器例 2 — 非同期クリア/プリセット付きフリップフロップ Non-synthesized不可合成合成不可

module Flop_PCA (preset, clear, q, qbar, clock, data);
  input  preset, clear, clock, data;
  output q, qbar;
  reg    q;

  assign qbar = ~q;

  always @ (negedge clock)
    q = data;

  always @ (clear or preset)
    begin
      if      (!clear)  assign q = 0;     // async clear dominates
      else if (!preset) assign q = 1;
      else              deassign q;       // clock regains control
    end
endmodule

While clear or preset is active the PCA overrides the clocked assignment q = data; after deassign, q keeps its value until the next falling clock edge.clear 或 preset 有效期間,PCA 會蓋過時脈同步的賦值 q = data;執行 deassign 之後,q 會保持原值直到下一個時脈下降緣。clear または preset が有効な間、PCA はクロック同期の代入 q = data を上書きする。deassign の後、q は次のクロック立ち下がりまで値を保持する。

3.2 Method 2: force ... release3.2 方法二:force ... release3.2 方法 2:force ... release

...
force sig_a = 1;            // internal nodes of the DUT
force sig_b = 1;
force sig_c = 0;
sig_in1 = 0;
#5 sig_in1 = 1;
#5 sig_in1 = 0;
// insert code to construct tests
release sig_a;
release sig_b;
release sig_c;
...

In the lecture diagram sig_a, sig_b come from mod_abc and sig_c from mod_xyz; forcing them isolates the AND/OR gates feeding mod_def so they can be tested independently of the upstream modules.在課堂的圖中,sig_a、sig_b 來自 mod_abc,sig_c 來自 mod_xyz;把它們 force 住就能把餵給 mod_def 的 AND/OR 閘隔離出來,獨立於上游模組進行測試。講義の図では sig_a と sig_b は mod_abc から、sig_c は mod_xyz から来ている。これらを force すると、mod_def へ入力される AND/OR ゲートを切り離し、上流のモジュールとは独立に検証できる。 Non-synthesized不可合成合成不可

3.3 Net / register assignment modes3.3 net 與 register 的賦值模式3.3 net とレジスタの代入モード

Variable type變數型別変数の型Output of primitive基本閘的輸出プリミティブの出力Continuous assignment連續賦值連続代入Procedural assignment
(always / initial)
程序式賦值
(always / initial)
手続き型代入
(always / initial)
assign ... deassign
(PCA)
force ... release
(PCA)
NetYes可可Yes可可No不可不可No不可不可Yes可可
RegisterComb — No
Seq (UDP) — Yes
組合邏輯 — 不可
序向(UDP)— 可
組合せ — 不可
順序(UDP)— 可
No不可不可Yes可可Yes可可Yes可可
Key points (click to expand)重點整理(點擊展開)要点のまとめ(クリックで展開)
  • A PCA executes inside a procedural block but acts like a continuous assignment: as long as the binding exists, the target keeps following the RHS.PCA 在程序區塊內執行,但效果像連續賦值:只要綁定存在,目標就持續跟著 RHS 變化。PCA は手続きブロック内で実行されるが、効果は連続代入に近い。束縛が存在する限り、対象は右辺に追従し続ける。
  • assign/deassign: registers only. force/release: nets and registers alike, and it has the highest priority.assign/deassign:只能對 reg;force/release:net 與 reg 都可以,優先權最高。assign/deassign:reg のみ。force/release:net にも reg にも使え、優先度が最も高い。
  • Neither is recommended in synthesizable design; force/release is mainly for test-bench debugging and can drive internal nodes through hierarchical names.兩者都不建議用於可合成設計;force/release 主要用在 test-bench 除錯,可搭配階層式名稱強制內部節點。どちらも合成対象の設計には勧められない。force/release は主にテストベンチのデバッグ用で、階層名を使って内部ノードを強制できる。
  • Only the output of a sequential UDP may be declared as a reg, which is why the primitive-output column for registers reads "Comb No / Seq Yes".只有序向 UDP 的輸出可以宣告為 reg,所以表中 register 的 primitive 輸出欄是「Comb No / Seq Yes」。順序 UDP の出力だけが reg として宣言できる。そのため表のレジスタ行のプリミティブ出力欄は「Comb No / Seq Yes」となっている。

4. Procedural Timing Controls4. 程序式時序控制4. 手続き型タイミング制御

Five mechanisms: delay control #, event control @, event or, named events, and the wait construct.共有五種機制:延遲控制 #、事件控制 @、事件 or、具名事件,以及 wait 敘述。機構は五つある。遅延制御 #、イベント制御 @、イベントの or、名前付きイベント、そして wait 構文である。

4.1 Delay control operator (#)4.1 延遲控制運算子(#)4.1 遅延制御演算子(#) Non-synthesized不可合成合成不可

Suspends the activity flow at the location of the operator. Typical use: clock generators in test-benches.在運算子所在的位置暫停活動流程。典型用途:測試平台中的時脈產生器。演算子が置かれた位置で動作フローを停止させる。典型的な用途はテストベンチのクロック生成器である。

always
  begin
    #0  clock = 0;
    #50 clock = 1;
    #50;
  end           // period 100
always
  begin
    #clock_period/2;
    clock = ~clock;
  end           // clock must be initialised!
Tip小提醒ヒント

The right-hand version needs initial clock = 0;; otherwise ~x = x and the clock stays unknown forever. Also, an always block with no delay and no event control is a zero-delay infinite loop that hangs the simulator.右邊那個版本必須搭配 initial clock = 0;,否則 ~x = x,時脈會永遠停在未知值。另外,沒有延遲也沒有事件控制的 always 區塊是一個零延遲無窮迴圈,會讓模擬器卡死。右側の書き方には initial clock = 0; が必要である。さもないと ~x = x となり、クロックは不定のままになる。また、遅延もイベント制御も持たない always ブロックはゼロ遅延の無限ループとなり、シミュレータを停止させてしまう。

4.2 Event control operator (@)4.2 事件控制運算子(@)4.2 イベント制御演算子(@) Non-synthesized不可合成合成不可

Synchronizes execution to an event: the flow waits until the event occurs.把執行與某個事件同步:流程會等到該事件發生為止。実行をイベントに同期させる。フローはそのイベントが起こるまで待つ。

Example 1範例 1例 1
...
@ signal_1 a = b;   // wait for any change on signal_1
...
Example 2 — nested範例 2 — 巢狀例 2 — 入れ子
...
@ (event_a) begin
  ...
  @ (event_b) begin
    ...
  end
end
...

4.3 posedge and negedge4.3 posedge 與 negedge4.3 posedge と negedge

Edge邊緣エッジTransitions that count算數的轉態有効とみなされる遷移
posedge0→1, 0→x, x→1  (also 0→z, z→1)0→1、0→x、x→1  (也包含 0→z、z→1)0→1、0→x、x→1  (0→z、z→1 も含む)
negedge1→0, 1→x, x→0  (also 1→z, z→0)1→0、1→x、x→0  (也包含 1→z、z→0)1→0、1→x、x→0  (1→z、z→0 も含む)

Usually used for clock and reset signals in the sensitivity list:通常用在敏感列表中的時脈與重置訊號:通常は感度リスト中のクロックやリセット信号に用いる。

always @ (posedge clock) begin
  #10 b = a;     // samples a 10 units AFTER the edge
end

4.4 Event or4.4 事件 or4.4 イベントの or

Positive-edge D flip-flop with asynchronous active-low set and reset:具非同步低態有效 set 與 reset 的正緣觸發 D 型正反器:非同期かつ負論理の set と reset をもつ立ち上がりエッジ D フリップフロップ:

always @ (posedge clk or negedge set or negedge rst) begin
  if (rst == 0)
    q = 1'b0;          // reset has highest priority
  else if (set == 0)
    q = 1'b1;
  else if (clk == 1)
    q = data_in;       // woke up by the clock edge
  else
    q = q;
end
Explanation: why test clk == 1? (click to expand)解說:為什麼要檢查 clk == 1?(點擊展開)解説:なぜ clk == 1 を確認するのか?(クリックで展開)

When the block is woken by negedge rst or negedge set, the matching rst == 0 / set == 0 branch is taken first. But a negedge also covers 1→x: then rst == 0 evaluates to x (treated as false) and control falls through to a later branch. Adding if (clk == 1) confirms that the trigger really was a rising clock edge before data_in is taken; otherwise q holds its value. Synthesizable style normally just writes else q <= data_in; and switches to non-blocking assignment.由 negedge rst 或 negedge set 喚醒時,對應的 rst == 0 / set == 0 分支會先成立。但 negedge 也包含 1→x:此時 rst == 0 為 x(視為假),會落到後面的分支;加上 if (clk == 1) 確認觸發源真的是時脈上升緣,才取 data_in,否則保持 q。可合成風格通常直接寫 else q <= data_in; 並改用非阻擋式賦值。negedge rst や negedge set で起動された場合は、対応する rst == 0 / set == 0 の分岐がまず成立する。しかし negedge には 1→x も含まれ、そのとき rst == 0 は x(偽とみなされる)となって後ろの分岐に落ちてしまう。if (clk == 1) を加えることで、起動要因が本当にクロックの立ち上がりであることを確かめてから data_in を取り込み、そうでなければ q を保持する。合成可能な書き方では通常 else q <= data_in; と書き、ノンブロッキング代入に変える。

4.5 Named events4.5 具名事件4.5 名前付きイベント Non-synthesized不可合成合成不可

module top (clk, data, q);
  input  clk, data;
  output q;
  talker   M1 (clk);
  receiver M2 (q, data);
endmodule

module talker (clk);
  input clk;
  event do_it;
  always @ (posedge clk)
    -> do_it;           // trigger
endmodule
module receiver (q, data);
  input  data;
  output q;
  reg    q;
  always @ (top.M1.do_it) // hierarchical
    q = data;
endmodule

The receiver has no clock port at all — it is synchronized to talker only through the hierarchical event name top.M1.do_it.receiver 根本沒有時脈埠 — 它只透過階層式事件名稱 top.M1.do_it 與 talker 同步。receiver にはクロック端子が一切ない。階層イベント名 top.M1.do_it だけで talker と同期している。

4.6 wait statement4.6 wait 敘述4.6 wait 文 Non-synthesized不可合成合成不可

Suspends the activity flow until the expression is true (level-sensitive, unlike the edge-sensitive @). If the condition is already true, execution continues immediately.暫停活動流程直到運算式為真(屬於位準敏感,與邊緣敏感的 @ 不同)。若條件當下已經為真,則立即繼續執行。式が真になるまで動作フローを停止させる(エッジセンシティブな @ と異なり、レベルセンシティブである)。条件がすでに真であれば、ただちに実行を続ける。

data_out = 0;
wait (enable) data_out = data_in;
data_inenabledata_out
data_out stays 0 until enable becomes true, then takes data_in.data_out 維持 0,直到 enable 變為真,才取得 data_in 的值。data_out は enable が真になるまで 0 のままで、その後 data_in の値を取り込む。

5. Intra-Assignment Delay5. 賦值內延遲5. 代入内遅延

5.1 Postpone assignment, not evaluation5.1 延後的是賦值,不是運算5.1 先送りされるのは代入であって評価ではない

In lhs = #d rhs; or lhs = @(ev) rhs; the RHS is evaluated immediately; only the update of the LHS waits.在 lhs = #d rhs; 或 lhs = @(ev) rhs; 之中,RHS 會立刻被計算;只有 LHS 的更新要等待。lhs = #d rhs; や lhs = @(ev) rhs; では、右辺はただちに評価される。待たされるのは左辺の更新だけである。

Blocking阻擋式ブロッキング
a = #5 b;        // sample b now, write a at +5
c = d;           // runs at +5 (blocked)

e = @(bus) f;    // sample f now, write e at next bus change
g = h;           // runs after e is written
Non-blocking非阻擋式ノンブロッキング
initial begin
  @(posedge clk)
    g <= @(bus) k;   // sample k, schedule
    p <= q;          // runs immediately
end

always begin
  @(posedge clock)
    g <= @(bus) k;
end

The equivalent of a = #5 b; is begin temp = b; #5 a = temp; end.a = #5 b; 等價於 begin temp = b; #5 a = temp; end。a = #5 b; は begin temp = b; #5 a = temp; end と等価である。

5.2 Five delay styles compared5.2 五種延遲寫法的比較5.2 五つの遅延スタイルの比較

Code程式碼コードBehavior行為振る舞い
assign y = a | b;Zero-delay combinational.零延遲的組合邏輯。遅延ゼロの組合せ論理。
always @(a or b) y = a | b;Same as above (complete sensitivity list).與上一列相同(敏感列表完整)。上と同じ(感度リストが完全な場合)。
assign #5 y = a | b;Inertial delay: output follows after 5; pulses shorter than 5 are swallowed.慣性延遲:輸出延後 5 跟上;寬度小於 5 的脈衝會被吞掉。慣性遅延:出力は 5 遅れて追従し、幅が 5 未満のパルスは飲み込まれる。
always @(a or b) #5 y = a | b;Waits 5, then evaluates with the values at that moment. Input changes during the wait are missed (the block is not at the @).先等 5,再用那一刻的值計算。等待期間的輸入變化會被漏掉(因為區塊不在 @ 上)。まず 5 だけ待ち、その時点の値で評価する。待っている間の入力変化は取りこぼす(ブロックが @ にいないため)。
always @(a or b) y = #5 a | b;Evaluates at the change, writes 5 later. Changes during the wait are missed → output can get stuck at a stale value.在變化當下計算,5 之後才寫入。等待期間的變化會被漏掉 → 輸出可能卡在過時的值。変化した時点で評価し、5 後に書き込む。待機中の変化は取りこぼすため、出力が古い値のまま固定されることがある。
always @(a or b) y <= #5 a | b;Transport delay: every change is scheduled and the block returns to @ immediately, so every pulse is reproduced 5 later.傳輸延遲:每一次變化都被排程,而且區塊立刻回到 @,所以每個脈衝都會在 5 之後忠實重現。伝送遅延:変化のたびにスケジュールされ、ブロックはただちに @ へ戻る。そのためすべてのパルスが 5 遅れて忠実に再現される。
Rule of thumb實用原則目安となる指針

To model a delayed combinational output, use assign #d (inertial) or y <= #d expr (transport). Delays inside a blocking always silently lose events.要描述帶延遲的組合輸出,請用 assign #d(慣性)或 y <= #d expr(傳輸)。把延遲寫在阻擋式的 always 裡會無聲無息地漏掉事件。遅延付きの組合せ出力をモデル化するには assign #d(慣性)か y <= #d expr(伝送)を使う。ブロッキングの always 内に遅延を書くと、警告もなくイベントを取りこぼす。

Practice 2 — A glitch through six models練習 2 — 一個毛刺通過六種模型演習 2 — 一つのグリッチが 6 つのモデルを通る

Problem: b = 0 throughout; all outputs have settled to 0 before t = 0. Input a goes 0→1 at t = 2 and 1→0 at t = 4. Sketch y for each of the six descriptions of §5.2.題目:b = 0 始終不變;所有輸出在 t = 0 之前都已穩定為 0。輸入 a 在 t = 2 由 0→1,在 t = 4 由 1→0。請畫出 §5.2 六種描述各自的 y 波形。問題:b = 0 は終始変わらない。すべての出力は t = 0 以前に 0 に落ち着いている。入力 a は t = 2 で 0→1、t = 4 で 1→0 と変化する。§5.2 の六つの記述それぞれについて y の波形を描け。

Click to reveal solution點擊展開解答クリックで解答を表示
a assign assign #5 #5 y= y = #5 y <= #5 02479t
The always @(a or b) y = a | b form is identical to the first assign row.always @(a or b) y = a | b 這種寫法與第一列的 assign 完全相同。always @(a or b) y = a | b の形は、最初の assign の行とまったく同じである。
  • assign / always zero-delay: y = 1 on [2, 4).assign/always 零延遲:y 在 [2, 4) 區間為 1。assign/always 遅延ゼロ:y は [2, 4) の区間で 1 になる。
  • assign #5: pulse width 2 < 5 → swallowed, y stays 0.assign #5:脈衝寬度 2 < 5 → 被吞掉,y 維持 0。assign #5:パルス幅 2 < 5 のため飲み込まれ、y は 0 のまま。
  • #5 y = a|b: woken at 2, evaluates at 7 when a is already 0 → y stays 0; the fall at 4 was missed but happens not to matter.#5 y = a|b:在 2 被喚醒,到 7 才計算,此時 a 已經是 0 → y 維持 0;t = 4 的下降緣雖然被漏掉,但剛好不影響結果。#5 y = a|b:2 で起動され、7 で評価されるときには a はすでに 0 → y は 0 のまま。t = 4 の立ち下がりは取りこぼされるが、たまたま結果に影響しない。
  • y = #5 a|b: evaluates 1 at t = 2, writes at 7; the fall at 4 was missed while blocked → y stuck at 1.y = #5 a|b:在 t = 2 算出 1,到 7 才寫入;阻擋期間漏掉了 t = 4 的下降緣 → y 卡在 1。y = #5 a|b:t = 2 で 1 と評価し、7 で書き込む。ブロック中に t = 4 の立ち下がりを取りこぼすため → y は 1 のまま固定される。
  • y <= #5 a|b: schedules 1 @ 7 and 0 @ 9 → faithful pulse on [7, 9).y <= #5 a|b:排程在 7 寫 1、在 9 寫 0 → 在 [7, 9) 忠實重現脈衝。y <= #5 a|b:7 に 1、9 に 0 をスケジュールする → [7, 9) にパルスが忠実に再現される。

5.3 Repeated intra-assignment delay5.3 重複的賦值內延遲5.3 繰り返し付き代入内遅延 Non-synthesized不可合成合成不可

reg_a = repeat (5) @ (negedge clock) reg_b;
begin                     // equivalent
  temp = reg_b;
  @ (negedge clock);
  @ (negedge clock);
  @ (negedge clock);
  @ (negedge clock);
  @ (negedge clock);
  reg_a = temp;
end

Test-bench example:測試平台範例:テストベンチの例:

module repeater;
  reg clock;
  reg reg_a, reg_b;

  initial clock = 0;
  always #5 clock = ~clock;

  initial begin
    #5  reg_a = 1;
    #10 reg_a = 0;
    #5  reg_a = 1;
    #20 reg_a = 0;
  end

  initial #100 $finish;

  initial begin
    #10 reg_b = repeat (5) @ (posedge clock) reg_a;
  end
endmodule
Practice 3 — Repeater timing練習 3 — repeater 的時序演習 3 — repeater のタイミング

Problem: For the repeater module above, when does reg_b leave x, and to what value?題目:對於上面的 repeater 模組,reg_b 在什麼時候離開 x?變成什麼值?問題:上の repeater モジュールにおいて、reg_b はいつ x を脱し、どの値になるか。

Click to reveal solution點擊展開解答クリックで解答を表示
reg_a: 1 at t = 5, 0 at 15, 1 at 20, 0 at 40.reg_a:t = 5 時為 1,15 時為 0,20 時為 1,40 時為 0。reg_a:t = 5 で 1、15 で 0、20 で 1、40 で 0 となる。
Clock starts 0 and toggles every 5 → rising edges at 5, 15, 25, 35, 45, 55, ...時脈從 0 開始,每 5 翻轉一次 → 上升緣在 5、15、25、35、45、55、...クロックは 0 から始まり 5 ごとに反転する → 立ち上がりは 5、15、25、35、45、55、…
At t = 10 the RHS is sampled: reg_a = 1.在 t = 10 取樣 RHS:reg_a = 1。t = 10 で右辺が採取される:reg_a = 1。
Then wait for 5 rising edges after t = 10: 15, 25, 35, 45, 55.接著等待 t = 10 之後的 5 個上升緣:15、25、35、45、55。続いて t = 10 以降の立ち上がりを 5 回待つ:15、25、35、45、55。

reg_b becomes 1 at t = 55 — even though reg_a is 0 by then. The value was captured at t = 10.reg_b 在 t = 55 變成 1 — 即使此時 reg_a 已經是 0。因為值是在 t = 10 就被擷取下來的。reg_b は t = 55 で 1 になる。そのとき reg_a はすでに 0 であるが、値は t = 10 の時点で取り込まれているからである。

6. Simulation of Procedural Assignments6. 程序式賦值的模擬6. 手続き型代入のシミュレーション

6.1 Order of operations within one time step6.1 單一時間步內的執行順序6.1 一つの時間ステップ内での処理順序

  1. Evaluate expressions on the RHS.計算所有 RHS 上的運算式。右辺の式を評価する。
  2. Execute blocking assignments.執行阻擋式賦值。ブロッキング代入を実行する。
  3. Execute non-blocking assignments that do not have intra-assignment timing control.執行沒有賦值內時序控制的非阻擋式賦值。代入内タイミング制御を持たないノンブロッキング代入を実行する。
  4. Execute past assignments that were scheduled to execute in the current time step.執行過去排程、指定在目前時間步生效的賦值。過去にスケジュールされ、現在の時間ステップで実行される代入を処理する。
  5. Execute $monitor. ($display executes when it is encountered, i.e. before the non-blocking updates.)執行 $monitor。($display 則是在被執行到的當下就印出,也就是在非阻擋式更新之前。)$monitor を実行する。($display は出会った時点で実行される。つまりノンブロッキング更新の前である。)
  6. Advance simulation time.推進模擬時間。シミュレーション時刻を進める。

6.2 $display vs $monitor6.2 $display 與 $monitor6.2 $display と $monitor

initial begin
  a = 1;
  b = 0;
  a <= b;
  b <= a;
  $display("a=%b b=%b", a, b);
end
// display: a=1 b=0
initial begin
  a = 1;
  b = 0;
  a <= b;
  b <= a;
  $monitor("a=%b b=%b", a, b);
end
// monitor: a=0 b=1

$display prints immediately, before the non-blocking swap takes effect. $monitor prints at the end of the time step (and whenever an argument changes afterwards), so it sees the swapped values. $strobe behaves like a one-shot $monitor.$display 當下就印出,此時非阻擋式的交換尚未生效。$monitor 在時間步結束時才印(之後只要引數改變也會再印),所以看到的是交換後的值。$strobe 的行為就像只觸發一次的 $monitor。$display はその場でただちに出力するため、ノンブロッキングの交換はまだ反映されていない。$monitor は時間ステップの終わりに出力し(以降は引数が変化するたびに出力する)、交換後の値を見る。$strobe は一回限りの $monitor のように振る舞う。

Practice 4 — Predict the printout練習 4 — 預測輸出結果演習 4 — 出力を予測する
initial begin
  x = 0;
  x <= 1;
  $display("D x=%b", x);
  $strobe ("S x=%b", x);
  #1 $display("D1 x=%b", x);
end
Click to reveal solution點擊展開解答クリックで解答を表示

D x=0 (before the NBA update), S x=1 (end of time step 0), D1 x=1 (time 1).D x=0(非阻擋式更新之前)、S x=1(時間步 0 的結束)、D1 x=1(時間 1)。D x=0(ノンブロッキング更新の前)、S x=1(時間ステップ 0 の終わり)、D1 x=1(時刻 1)。

7. Activity Flow Control7. 活動流程控制7. 動作フロー制御

Constructs: conditional operator ?:, case / casex / casez, if ... else, loops (repeat, for, while, forever), disable, 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。

7.1 Conditional operator7.1 條件運算子7.1 条件演算子

Besides continuous assignments, ?: can be used in a procedural statement to assign a register:除了連續賦值之外,?: 也可以寫在程序式敘述中,對暫存器賦值:連続代入のほか、?: は手続き文の中でレジスタへの代入にも使える。

always @ (posedge clock)
  q = s ? a : b;

7.2 case, casex, casez7.2 case、casex、casez7.2 case、casex、casez

always @ (a or b or c or d or select)
begin
  case (select)
    0: y = a;
    1: y = b;
    2: y = c;
    3: y = d;
    default: y = 1'bx;
  endcase
end
Statement敘述文Bits treated as don't care被當成 don't care 的位元ドントケアとして扱われるビット
casenone — exact 4-value match沒有 — 四值完全比對なし — 4 値の完全一致
casezz (and ?)z(以及 ?)z(および ?)
casexx, z (and ?)x、z(以及 ?)x、z(および ?)
always @ (opcode or a or b or c)
casex (opcode)
  4'b1zzx : begin  // don't care bits 2:0
              out = a;
            end
  4'b01?? : begin  // bits 1:0 are don't care
              out = b;
            end
  4'b001? : begin  // bit 0 is don't care
              out = c;
            end
  default : begin
              out = 4'b0;
            end
endcase
casex pitfallcasex 的陷阱casex の落とし穴

Don't-care also applies to x/z in the expression. An unknown opcode 4'bxxxx matches the first item and hides the bug in simulation. Prefer casez with ?.don't care 也會套用到運算式中的 x/z。一個未知的 opcode 4'bxxxx 會比中第一個項目,在模擬中把錯誤掩蓋掉。建議改用 casez 搭配 ?。ドントケアは式の側の x/z にも適用される。未知のオペコード 4'bxxxx が最初の項目に一致してしまい、シミュレーション上でバグが隠れる。? を用いた casez を使うほうがよい。

Practice 5 — casex matching練習 5 — casex 的比對演習 5 — casex のマッチング

Problem: For the casex above, what is out when opcode = (a) 4'b1010 (b) 4'b0110 (c) 4'b0011 (d) 4'b0001 (e) 4'b0x10?題目:對於上面的 casex,當 opcode = (a) 4'b1010 (b) 4'b0110 (c) 4'b0011 (d) 4'b0001 (e) 4'b0x10 時,out 各是什麼?問題:上の casex について、opcode = (a) 4'b1010 (b) 4'b0110 (c) 4'b0011 (d) 4'b0001 (e) 4'b0x10 のとき、out はそれぞれ何になるか。

Click to reveal solution點擊展開解答クリックで解答を表示

(a) a — matches 1zzx. (b) b — 01??. (c) c — 001?. (d) 0 — default. (e) b — bit 2 is x and treated as don't care, so 0x10 first matches 01?? (items are checked in order).(a) a — 比中 1zzx。(b) b — 01??。(c) c — 001?。(d) 0 — 落到 default。(e) b — 第 2 位元是 x,被當成 don't care,所以 0x10 會先比中 01??(項目是依序比對的)。(a) a — 1zzx に一致する。(b) b — 01??。(c) c — 001?。(d) 0 — default に落ちる。(e) b — ビット 2 が x でドントケア扱いになるため、0x10 はまず 01?? に一致する(項目は順に照合される)。

7.3 if ... else7.3 if ... else7.3 if ... else

always @ (posedge clk) begin
  // if reset is asserted
  if (reset == 1'b0) begin
    counter <= 4'b0000;
  // if counter is enabled and up count is asserted
  end else if (enable == 1'b1 && up_en == 1'b1) begin
    counter <= counter + 1'b1;
  // if counter is enabled and down count is asserted
  end else if (enable == 1'b1 && down_en == 1'b1) begin
    counter <= counter - 1'b1;
  // if counting is disabled
  end else begin
    counter <= counter;   // redundant code
  end
end

The last branch is redundant in a clocked block: a register holds its value anyway. (In a combinational block, the missing else would create a latch.) Note the priority: up-count wins if both up_en and down_en are asserted.在時脈同步的區塊中,最後一個分支是多餘的:暫存器本來就會保持原值。(但在組合區塊中,少了 else 反而會產生閂鎖。)另外注意優先權:若 up_en 與 down_en 同時有效,上數會贏。クロック同期ブロックでは最後の分岐は冗長である。レジスタはもともと値を保持するからである。(ただし組合せブロックでは else が欠けるとラッチが生じる。)優先順位にも注意する。up_en と down_en が同時に有効なら、アップカウントが勝つ。

7.4 Loops: repeat, for, while7.4 迴圈:repeat、for、while7.4 ループ:repeat、for、while

repeat — fixed countrepeat — 固定次數repeat — 回数固定
parameter memory_size = 1024;
...
word_address = 0;
repeat (memory_size)
  begin
    memory[word_address] = 0;
    word_address = word_address + 1;
  end
while — count the 1s in awhile — 數出 a 之中有幾個 1while — a の中の 1 を数える
begin
  reg [7:0] temp;
  counter = 0;
  temp = a;
  while (temp)
    begin
      if (temp[0]) counter = counter + 1;
      // or: counter = counter + temp[0];
      temp = temp >> 1;
    end
end
for — integer indexfor — 用 integer 當索引for — integer をインデックスに使う
reg [15:0] data;
integer k;

for (k = 4; k > 0; k = k - 1)
  begin
    data[k+10] = 0;
    data[k+2]  = 1;
  end
for — 4-bit index (trap!)for — 4 位元索引(陷阱!)for — 4 ビットのインデックス(落とし穴!)
reg [3:0] k;

for (k = 0; k <= 15; k = k + 1)
  ...
Practice 6 — Loop traps練習 6 — 迴圈的陷阱演習 6 — ループの落とし穴

(a) Which bits of data does the left for loop write? (b) What happens with the right-hand loop? (c) With a = 8'b1011_0010, what does the while loop leave in counter, and how many iterations does it run?(a) 左邊的 for 迴圈會寫到 data 的哪些位元?(b) 右邊的迴圈會發生什麼事?(c) 若 a = 8'b1011_0010,while 迴圈最後留在 counter 的值是多少?總共跑了幾次?(a) 左の for ループは data のどのビットに書き込むか。(b) 右のループでは何が起こるか。(c) a = 8'b1011_0010 のとき、while ループが counter に残す値はいくつか。また何回繰り返すか。

Click to reveal solution點擊展開解答クリックで解答を表示

(a) k = 4, 3, 2, 1 → data[14:11] = 0, data[6:3] = 1; other bits untouched.(a) k = 4、3、2、1 → data[14:11] = 0、data[6:3] = 1;其餘位元不受影響。(a) k = 4、3、2、1 → data[14:11] = 0、data[6:3] = 1。他のビットは変化しない。

(b) Infinite loop: a 4-bit k wraps from 15 to 0, so k <= 15 is always true. Use integer k or a 5-bit index.(b) 無窮迴圈:4 位元的 k 會從 15 繞回 0,所以 k <= 15 永遠成立。請改用 integer k 或 5 位元的索引。(b) 無限ループになる。4 ビットの k は 15 から 0 へ折り返すため、k <= 15 が常に真になる。integer k か 5 ビットのインデックスを使うこと。

(c) Four 1-bits → counter = 4. The loop stops when temp becomes 0, i.e. after 8 shifts (the MSB is 1).(c) 共有四個 1 → counter = 4。迴圈在 temp 變成 0 時停止,也就是移位 8 次之後(因為 MSB 是 1)。(c) 1 のビットは四つ → counter = 4。ループは temp が 0 になった時点、すなわち 8 回シフトした後に止まる(MSB が 1 のため)。

7.5 Example: 4-bit carry look-ahead adder7.5 範例:4 位元超前進位加法器7.5 例:4 ビット桁上げ先見加算器

module Add_prop_gen (sum, c_out, a, b, c_in);  // behavioral model
  output [3:0] sum;
  output       c_out;
  input  [3:0] a, b;
  input        c_in;

  reg  [3:0] carrychain;
  wire [3:0] g = a & b;   // carry generate  (continuous assignment)
  wire [3:0] p = a ^ b;   // carry propagate (continuous assignment)

  always @ (a or b or c_in)               // event "or"
    begin : carry_generation              // named block
      integer i;
      #0 carrychain[0] = g[0] + (p[0] & c_in);   // #0 needed for simulation
      for (i = 1; i <= 3; i = i + 1)
        begin
          carrychain[i] = g[i] | (p[i] & carrychain[i-1]);
        end
    end

  wire [4:0] shiftedcarry = {carrychain, c_in};  // concatenation
  wire [3:0] sum   = p ^ shiftedcarry;           // summation (low 4 bits)
  wire       c_out = shiftedcarry[4];            // carry out, bit select
endmodule
Carry recurrence進位遞迴式桁上げの漸化式 $$g_i = a_i b_i,\qquad p_i = a_i \oplus b_i,\qquad c_{i+1} = g_i + p_i\,c_i,\qquad s_i = p_i \oplus c_i$$
Explanation (click to expand)解說(點擊展開)解説(クリックで展開)
  • Structure: g, p, sum and c_out use continuous assignments; only the carry chain is computed in an event-triggered always block — exactly the "mix every level" example.結構:g、p 與 sum、c_out 用連續賦值;只有進位鏈用事件觸發的 always 計算 — 正是「混合各種層次」的範例。構成:g、p と sum、c_out は連続代入で書き、桁上げ連鎖だけをイベント起動の always で計算している — まさに「各レベルを混在させる」例である。
  • shiftedcarry = {carrychain, c_in} is 5 bits wide: [0]=c_in, [i]=c_i. sum = p ^ shiftedcarry keeps only the low 4 bits, so $s_i = p_i \oplus c_i$.shiftedcarry = {carrychain, c_in} 是 5 位元:[0]=c_in、[i]=c_i。sum = p ^ shiftedcarry 只取低 4 位元,所以 $s_i = p_i \oplus c_i$。shiftedcarry = {carrychain, c_in} は 5 ビット幅で、[0]=c_in、[i]=c_i である。sum = p ^ shiftedcarry は下位 4 ビットだけを取るので $s_i = p_i \oplus c_i$ となる。
  • The first line writes g[0] + (...) instead of |: the result is only one bit wide, and $g_i$ and $p_i$ can never both be 1, so the addition is equivalent to an OR.第一行寫 g[0] + (...) 而非 |:結果只有 1 位元,而 $g_i$ 與 $p_i$ 不可能同時為 1,所以「加」等於「OR」。最初の行で | ではなく g[0] + (...) と書いている。結果は 1 ビットしかなく、$g_i$ と $p_i$ が同時に 1 になることはないので、「加算」は「OR」と等価である。
  • #0 pushes this block slightly later within the same time step, making sure the continuous assignments to g and p have already been updated.#0 讓這個區塊在同一時間步內延後一點執行,確保 g、p 的連續賦值已先更新。#0 によってこのブロックは同じ時間ステップ内で少し後ろにずれ、g と p への連続代入が先に更新されることが保証される。
  • A local variable such as integer i may only be declared inside a named block.在 named block 內才可以宣告區域變數 integer i。integer i のようなローカル変数は、名前付きブロックの中でしか宣言できない。

7.6 forever and disable7.6 forever 與 disable7.6 forever と disable

forever + disable a named blockforever + disable 一個具名區塊forever + 名前付きブロックの disable
initial
  begin : clock_loop
    clock = 0;
    forever
      #10 clock = ~clock;
  end

initial
  #100 disable clock_loop;
disable — find first onedisable — 找出第一個 1disable — 最初の 1 を見つける
module find_first_one (a, trigger, i);
  input  [15:0] a;
  input         trigger;
  output [4:0]  i;
  reg    [4:0]  i;

  always @ trigger
    begin : search
      for (i = 0; i < 16; i = i + 1)
        if (a[i] == 1) disable search;
    end
endmodule

The slide writes a bare disable; — disable must name a block or task, so the loop is wrapped in the named block search. If no bit is set, i ends at 16 (which is why it is 5 bits wide).投影片上只寫了一個光禿禿的 disable; — disable 必須指名一個區塊或任務,所以這裡把迴圈包在具名區塊 search 內。若沒有任何位元為 1,i 最後會停在 16(這就是它要宣告成 5 位元的原因)。スライドには disable; とだけ書かれている — disable はブロックまたはタスクを名指ししなければならないので、ここではループを名前付きブロック search で囲んでいる。どのビットも 1 でなければ i は 16 で終わる(5 ビット幅にしてある理由がこれである)。

Question問題問いAnswer解答答え
always vs forever?always is a module-level construct that starts at time 0 and can never be stopped. forever is a statement placed inside a procedural block; it can be started later (after initialisation) and terminated with disable.always 是模組層級的建構,從時間 0 開始,而且永遠停不下來。forever 則是放在程序區塊內的敘述;它可以晚一點才開始(例如初始化之後),也可以用 disable 終止。always はモジュールレベルの構文で、時刻 0 から始まり決して止められない。forever は手続きブロック内に置く文であり、初期化の後など遅れて開始でき、disable で終了させられる。
disable vs $finish?disable terminates only a named block or task; execution continues after it and the rest of the simulation goes on. $finish ends the entire simulation.disable 只終止一個具名區塊或任務;之後的敘述會繼續執行,整個模擬也照常進行。$finish 則是結束整個模擬。disable は名前付きブロックかタスクを終了させるだけで、その後の実行は続き、シミュレーション全体も続行する。$finish はシミュレーション全体を終了させる。

8. Parallel Activity Flow: fork ... join8. 平行活動流程:fork ... join8. 並列動作フロー:fork ... join

8.1 Parallel threads8.1 平行執行緒8.1 並列スレッド

fork
  #50  a = 1;
  #100 a = 0;
  #150 a = 1;
  #200 a = 0;
join
begin
  #50 a = 1;
  #50 a = 0;
  #50 a = 1;
  #50 a = 0;
end

Both produce the same waveform: in fork all delays are measured from the fork start (absolute), in begin ... end they accumulate (relative).兩者產生相同的波形:在 fork 中所有延遲都是從 fork 起點算起(絕對時間),在 begin ... end 中則會累加(相對時間)。どちらも同じ波形になる。fork では遅延がすべて fork の開始時点から数えられ(絶対時間)、begin ... end では累積する(相対時間)。

8.2 Race condition vs no race condition8.2 有競爭條件與無競爭條件8.2 競合が起きる場合と起きない場合

A race: the target value is ambiguous because different assignments occur in the same time step in no defined order.競爭(race):由於不同的賦值在同一個時間步內以未定義的順序發生,目標的值因此模稜兩可。競合(race)とは、異なる代入が同一の時間ステップ内で順序の定まらないまま起こるために、対象の値が曖昧になることをいう。

Race有競爭競合あり
fork
  #150 a = b;
  #150 c = a;
join
No race無競爭競合なし
fork
  a = #150 b;
  c = #150 a;
join

Left: both statements execute at t = 150; c gets either the old or the new a depending on thread order. Right: both RHS are sampled at t = 0 (intra-assignment delay), so c deterministically receives the original a — the pair behaves like a shift.左邊:兩個敘述都在 t = 150 執行;c 拿到舊的還是新的 a,取決於執行緒的順序。右邊:兩個 RHS 都在 t = 0 取樣(賦值內延遲),所以 c 必定拿到原本的 a — 這一對敘述的行為就像一次移位。左:どちらの文も t = 150 で実行される。c が古い a を得るか新しい a を得るかはスレッドの順序次第である。右:どちらの右辺も t = 0 で採取される(代入内遅延)ため、c は必ず元の a を受け取る — この二文はシフト動作のように振る舞う。

Practice 7 — fork timing and races練習 7 — fork 的時序與競爭演習 7 — fork のタイミングと競合

(a) When does each of the two blocks in §8.1 finish? (b) Rewrite the racing fork using non-blocking assignments. (c) Given(a) §8.1 的兩個區塊各在什麼時候結束?(b) 請用非阻擋式賦值改寫有競爭的那段 fork。(c) 給定(a) §8.1 の二つのブロックはそれぞれいつ終了するか。(b) 競合する fork をノンブロッキング代入で書き直せ。(c) 次のコードについて、

fork
  #10 x = 1;
  begin #5 y = 2; #10 y = 3; end
  #20 z = x + y;
join

at what time does the join complete and what is z?join 在什麼時刻完成?z 又是多少?join は何時刻で完了し、z はいくつになるか。

Click to reveal solution點擊展開解答クリックで解答を表示

(a) Both finish at t = 200 (fork: longest thread; begin: 50×4).(a) 兩者都在 t = 200 結束(fork:取最長的執行緒;begin:50×4 累加)。(a) どちらも t = 200 で終了する(fork は最長スレッド、begin は 50×4 の累積)。

(b) fork #150 a <= b; #150 c <= a; join — both RHS read in the same time step before any update, so c gets the old a.(b) fork #150 a <= b; #150 c <= a; join — 兩個 RHS 都在同一時間步、任何更新之前讀取,所以 c 拿到的是舊的 a。(b) fork #150 a <= b; #150 c <= a; join — どちらの右辺も同一時間ステップ内で、更新が起こる前に読まれるので、c は古い a を得る。

(c) x = 1 at 10, y = 2 at 5 and 3 at 15, z evaluated at 20 → z = 4; join completes at t = 20.(c) x 在 10 變成 1,y 在 5 變成 2、在 15 變成 3,z 在 20 計算 → z = 4;join 在 t = 20 完成。(c) x は 10 で 1、y は 5 で 2、15 で 3 になり、z は 20 で評価される → z = 4。join は t = 20 で完了する。

9. Summary and Exam Checklist9. 總結與考前重點9. まとめと試験前チェックリスト

Assignments賦值代入
  • = sequential; <= sample-all-then-update.= 依序執行;<= 先全部取樣再一起更新。= は逐次実行。<= は全部採取してから一括更新。
  • Clocked logic → <=; combinational → =.時脈同步邏輯用 <=;組合邏輯用 =。クロック同期論理は <=、組合せ論理は =。
  • Don't mix in one block.不要在同一個區塊內混用。一つのブロック内で混ぜないこと。
PCA
  • assign/deassign: reg only.assign/deassign:只能用於 reg。assign/deassign:reg のみ。
  • force/release: net or reg, highest priority.force/release:net 或 reg 都可以,優先權最高。force/release:net でも reg でも可、優先度は最高。
  • Both for simulation/debug.兩者都只用於模擬與除錯。どちらもシミュレーションとデバッグ用。
Timing controls時序控制タイミング制御
  • # delay, @ edge/event, wait level.# 是延遲,@ 是邊緣/事件,wait 是位準。# は遅延、@ はエッジ/イベント、wait はレベル。
  • posedge includes 0→x, x→1.posedge 也包含 0→x 與 x→1。posedge には 0→x と x→1 も含まれる。
  • Named event: event + ->.具名事件:用 event 宣告,用 -> 觸發。名前付きイベント:event で宣言し -> で起動。
Intra-assignment delay賦值內延遲代入内遅延
  • Evaluate now, assign later.現在計算,稍後才賦值。評価はいま、代入はあとで。
  • y <= #d = transport; assign #d = inertial.y <= #d 是傳輸延遲;assign #d 是慣性延遲。y <= #d は伝送遅延、assign #d は慣性遅延。
  • Blocking delays in always lose events.把延遲寫在阻擋式的 always 裡會漏掉事件。always 内のブロッキング遅延はイベントを取りこぼす。
Flow control流程控制フロー制御
  • Incomplete case/if in comb logic → latch.組合邏輯中不完整的 case/if → 產生閂鎖。組合せ論理で case/if が不完全 → ラッチが生じる。
  • casez safer than casex.casez 比 casex 安全。casez は casex より安全。
  • Loop index width can make a loop infinite.迴圈索引的位元寬度可能讓迴圈變成無窮迴圈。ループ変数のビット幅が無限ループを招くことがある。
Scheduling排程スケジューリング
  • $display before NBA update.$display 在非阻擋式更新之前印出。$display はノンブロッキング更新より前に出力。
  • $monitor/$strobe at end of step.$monitor/$strobe 在時間步結束時印出。$monitor/$strobe は時間ステップの終わりに出力。
  • fork/join: absolute delays, races possible.fork/join:延遲是絕對時間,可能產生競爭。fork/join:遅延は絶対時間で、競合が起こりうる。
Non-synthesizable list (from this lecture)不可合成清單(本講整理)合成できないものの一覧(本回のまとめ)

initial, # delays, named events, wait, assign/deassign and force/release (tool dependent), repeat intra-assignment delays, forever with delays, fork ... join.initial、# 延遲、具名事件、wait、assign/deassign 與 force/release(視工具而定)、repeat 形式的賦值內延遲、帶延遲的 forever、fork ... join。initial、# 遅延、名前付きイベント、wait、assign/deassign と force/release(ツール依存)、repeat 形式の代入内遅延、遅延付きの forever、fork ... join。