自從循序電路的出現,我們大量接觸時間的觀念,順序變得相當重要!
最開始我們只使用到 = 來執行賦值的行為,而之後增加了 <= 來建構不同的電路。我們也說到這兩個符號的區別在於 Blocking 和 Nonblocking 。
Blocking 和 Nonblocking 聽起來相當學術,用簡單的方式來說就是 Nonblocking 代表「平行處理」,而 Blocking 代表的是「按照既定順序處理」。
今天我們就來探討 Initial & Always block 的運作模式和執行順序!
Initial 經常在 testbench 中出現,但是我們還沒真正認識這個語法。以往在提到 initial 時,我只提到這種程式區塊有別於 always block ,他只會被執行一次。這是他最重要的性質,而在撰寫 testbench 時也確實只需要此一性質。但是如果我們要完成更加複雜的電路,了解 initial 是必須的!
Initial 不只是只被執行一次,他還是在程式一開始就被執行,即時脈為 0 秒時。當然如果在 initial 之前增加延遲時間是個例外,他仍會被延遲。這種程式區塊還有一個特質,就是區塊間為獨立的,不會被干擾。我們舉一個例子來說明!
initial begin
#1 x = 5;
#5 y = 3;
end
initial begin
#2 a = 5;
#2 b = 3;
end
#3 initial begin
// statement 1
end
這段程式碼共包含 3 個 initial blocks ,其中前兩個 initial blocks 的起始時間為程式一開始 (0s) ,而第三個需等待 3 個時間單位才被執行。我們來分析 x, y, a, b 四個變數被執行的順序吧!
變數 | 開始執行時間(區塊) | 開始執行時間(程式) |
---|---|---|
x | 1 | 1 |
y | 6 | 6 |
a | 2 | 2 |
b | 4 | 4 |
由於這兩個是沒有被延遲的 initial blocks ,因此不論是從程式來看這個變數,還是從所屬的區塊來看,都有相同的開始執行的時間。總結來說,順序為 x, a, b, y 。由於各個變數之間沒有關聯,因此看不出差異,如果關聯一出現,順序變得相當重要。 |
提到 initial 就一定要提到他的好兄弟 always 。
Always 也是在程式一開始 (0s) 時就會被執行,當然要符合定義的觸發條件。與 initial 不同的是他會被重複執行,直到時脈結束。在寫 C 語言時,我們稱這種情況稱為無窮迴圈。舉一個例子吧!
always #5 clk = ~clk;
上述這段程式碼會被不斷執行,由於沒有觸發條件限制,因此從 0s 時,就會開始執行。這段程式碼的用途在產生時脈,包含著交替的高位和低位。
既然 always 就像是一個迴圈,我們不會在其中做「初始化」變數的動作,否則每當 always 被觸發,變數都會被初始,先前留下的資訊當就被破壞殆盡。因此初始化這個行為會被留在 initial block 中執行。
相同的道理,我們要怎麼知道程式結束?寫過 testbench ,我們都知道要使用 $finish 或 $stop 來產生停止的訊號。因為程式只會停止一次,所以想必這個訊號也會是在 initial 中產生的。
小小補充:
同樣是程式結束,為什麼要區分 $finish 和 $stop ?
在作業系統的概念中,有一種叫做 interrupt 的概念也可以強制停止程式,他是透過 $stop 來產生的。
在硬體中,大家都知道電源是必須的,因此 power off 也可以用來強制停止程式,而這是透過 $finish 來產生的。
雖然都是停止程式,但是其中的意涵不太相同,希望大家可以了解。