惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
V
V2EX
爱范儿
爱范儿
Martin Fowler
Martin Fowler
T
The Blog of Author Tim Ferriss
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
Check Point Blog
罗磊的独立博客
A
About on SuperTechFans
MyScale Blog
MyScale Blog
S
Security @ Cisco Blogs
博客园 - 聂微东
Simon Willison's Weblog
Simon Willison's Weblog
Cyberwarzone
Cyberwarzone
云风的 BLOG
云风的 BLOG
U
Unit 42
Latest news
Latest news
Apple Machine Learning Research
Apple Machine Learning Research
Security Latest
Security Latest
Y
Y Combinator Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
The Hacker News
The Hacker News
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
NISL@THU
NISL@THU
美团技术团队
S
Securelist
P
Privacy International News Feed
T
Tenable Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
www.infosecurity-magazine.com
www.infosecurity-magazine.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security
B
Blog RSS Feed
W
WeLiveSecurity
A
Arctic Wolf
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google DeepMind News
Google DeepMind News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
N
Netflix TechBlog - Medium
有赞技术团队
有赞技术团队
V2EX - 技术
V2EX - 技术

博客园 - 真 OO无双

(轉貼) Bit Twiddling Hacks (SOC) (Verilog) (C) (筆記) 如何移除VirtualBox所遺留下的驅動程式? (SOC) (VirtualBox) (筆記) always block內省略else所代表的電路 (SOC) (Verilog) (原創) 如何在Qsys Subsystem使用Interrupt? (SOC) (Nios II) (Qsys) (原創) Qsys或RTL做修改後,Nios II SBT該如何面對新的硬體? (SOC) (Nios II) (Qsys) (原創) 如何解決目錄改變時,Nios II project無法編譯的問題? (SOC) (Nios II) (DE2-70) (原創) Qsys Generation Tab的Simulation設定的意義 (SOC) (Nios II) (Qsys) (筆記) 如何寫入binary file某個byte連續n byte的值? (C/C++) (C) (筆記) 如何寫入binary file某個byte的值? (C/C++) (C) (筆記) 如何讀取binary file某個byte連續n byte的值? (C/C++) (C) (筆記) 如何讀取binary file某個byte的值? (C/C++) (C) (原創) Altera Technology Roadshow 2011 Taipei (SOC) (Quartus II) (Nios II) (Qsys) (原創) 如何在安裝SELinux的環境執行Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (筆記) 如何得知Quartus II最新版到底修改了哪些東西? (SOC) (Quartus II) (Nios II) (SOPC Builder) (Qsys) (筆記) Qsys resource整理 (SOC) (Nios II) (Qsys) (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox) (筆記) 如何在RedHat Linux安裝VirtualBox Guest Additions? (SOC) (Linux) (RedHat) (VirtualBox) (筆記) 常用設定暫存器值的編程技巧 (SOC) (C/C++) (C) (Verilog) (原創) Quartus II安裝新觀念:如何將Quartus II安裝在VirtualBox內? (SOC) (Quartus II) (VirtualBox)
(筆記) $dispaly()、$strobe()、$monitor() 、$fwrite()與blocking / nonblocking的關係 (SOC) (Verilog) (Debussy) (Verdi)
真 OO无双 · 2011-06-25 · via 博客园 - 真 OO无双

Abstract
除了看波型圖外,在寫Testbench時還可搭配Verilog本身所帶的一些函數做驗證,如$display()、$strobe()、$monitor()與$fwrite()等,這些函數在遇到blocking與nonblocking時,該如何使用才正確呢?它與Debussy / Verdi的nWave又有什麼關係呢?

Introduction
使用環境:ModelSim SE 6.3e + Debussy 5.4 v9

本文將討論以下主題:

1.Verilog的『stratified event queue』

2.blocking / nonblocking與$display()、$strobe()、$monitor()、$fwrite()的執行順序

3.Debussy / Verdi的nWave與blocking / nonblocking的關係

4.Conclusion

先來看一下摘自[1] Clifford E. Cummings 2000, Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kills, Sunburst Design, Inc.這篇paper的一段範例,我稍加修改,另外加上了常用的$fwrite()與Debussy的$fsdbDumpvars()與$fsdbDumpvars()一起測試。

nb_schedule1.v / Verilog

1 module nb_schedule1;
2
3  reg a, b;
4 integer fp;
5
6 initial begin
7 fp = $fopen("log.txt","w");
8 a = 0;
9 b = 0;
10 #1;
11 a = 0;
12 b = 1;
13 a <= b;
14 b <= a;
15
16 $monitor("%0dns :\$monitor: a=%b b=%b" , $stime, a, b);
17 $display("%0dns :\$display: a=%b b=%b" , $stime, a, b);
18 $strobe ("%0dns :\$strobe : a=%b b=%b\n", $stime, a, b);
19 $fwrite(fp, "%0dns :\$fwrite : a=%b b=%b\n", $stime, a, b);
20 #0 $display("%0dns :#0 : a=%b b=%b" , $stime, a, b);
21
22
23 #1 $monitor("%0dns :\$monitor: a=%b b=%b" , $stime, a, b);
24 $display("%0dns :\$display: a=%b b=%b" , $stime, a, b);
25 $strobe ("%0dns :\$strobe : a=%b b=%b\n", $stime, a, b);
26 $fwrite(fp, "%0dns :\$fwrite : a=%b b=%b\n", $stime, a, b);
27 #0 $display("%0dns :#0 : a=%b b=%b" , $stime, a, b);
28
29
30 $fclose(fp);
31 end
32
33 initial begin
34 $fsdbDumpfile("nb_schedule1.fsdb");
35 $fsdbDumpvars(0, nb_schedule1);
36 end
37
38 endmodule

執行結果

# 1ns :$display: a=0 b=1
# 1ns :#
0 : a=0 b=1
# 1ns :$monitor: a
=1 b=0
# 1ns :$strobe : a
=1 b=0
#
# 2ns :$display: a
=1 b=0
# 2ns :#
0 : a=1 b=0
# 2ns :$monitor: a
=1 b=0
# 2ns :$strobe : a
=1 b=0

文字檔部份

1ns :$fwrite : a=0 b=1
2ns :$fwrite : a
=1 b=0

Debussy的nWave

strobe00

假如結果如你預期,恭喜你,那表示你的觀念非常清楚,如果不是,請你繼續往下看,我將會解釋這段範例程式。

Verilog的『stratified event queue』

我在(原創) 深入探討blocking與nonblocking (SOC) (Verilog)曾經討論過Verilog在Simulator內實際的運行方式,這裡再稍為提一下。

在軟體的世界,程式碼基本上是一行一行地執行,也就是再同一個時間點,只有一件事情會發生;但在硬體的世界裡,電路卻可以平行執行,也就是在同一個時間點,有很多事情可以同時發生。我們現在要在一個只能『循序處理』的軟體去『模擬』能『平行處理』的硬體,勢必有些特殊的機制才行。

在Simulator內,為了要模擬出硬體的平行處理機制,時間軸是個虛擬的時間軸,另外搭配了5個event queue,也就是說,當一個時間點的5個event queue內的所有程式碼都執行過後,時間軸才會自動加1,如此就很巧妙的『看起來』好像在同一個時間點作了很多事情,不過事實上對於軟體與CPU來說,依然是同一時間點只發生了一件事情。

strobe01

在IEEE Verilog Standard中定義了這5個Event Queue,依序討論如下:

1.Active Events:

大部分的Verilog程式碼都在此執行,其中包括以綠色字表示的blocking asignments以及continuous assignments (也就是用assign寫的),至於nonblocking部分,只執行RHS (Right Hand Side),也就是只執行nonblocking右測的部分,唯一用紅色表示的是本文所要討論的$display()與$fwrite(),也是屬於Active Events,值的注意的是,在Active Events中的程式碼,若是同一個時間點,且在同一個sequential block,程式碼是依序執行,但是IEEE Verilog Standard並不保證在同一個時間點,不同的sequential block內的程式碼誰先執行,也就是說若你寫的程式碼都屬於Active Events所執行,但分屬不同的sequential block,且彼此互相依賴,就可能出現Race Condition的情形發生

當在Active Events的程式碼執行完後,會自動移出Active Events。

2.Inactive Events

當Active Events執行完後,Inactive Events的程式碼會依序變成Active Events而執行之。

Inactive Events執行的是blocking assignments且帶#0 delay,因為是#0,所以理論上還是屬於同一個時間點,只是執行順序略晚於正常的blocking assignments,這也是為什麼遇到Race Condition時,常常加上#0就會正常,這就是因為#0是屬於Inactive Events,執行順序很明顯的在Active Events之後,因此不會有在Active Events內不保證誰先誰後執行,而造成Race Condition發生。

很多人認為#0會在每個時間點的最後執行,這是個錯誤的觀念,事實上,#0只是在Inactive Events,比Nonblocking Events還要早。

3.Nonblocking Events

當Inactive Events執行完後,接著Nonblocking Event的程式碼會依序變成Active Events而執行之。

Nonblocking Events執行的是nonblocking的LHS(Left Hand Side)部分,在此我們可以明確地發現,blocking發生在Active Events,而nonblocking雖然在Active Events已經執行了RHS,但真正完成LHS是在Nonblocking Events,也就是blocking會在nonblocking之前先完成。這也是為什麼同一個時間點,nonblocking可以讀到blocking所做的改變,但是blocking卻無法讀到nonblocking的改變,因為blocking已經先執行,必須要等到下一個clk edge才能讀到nonblocking所做的改變。

除此之外,還有一個常見的迷思也可在此澄清,我們都知道寫sequential logic時要用nonblocking寫,事實上用blocking也是可以寫,只是blocking寫很容易造成Race Condition,要很小心注意其先後順序,但為什麼用nonblocking寫就不會有Race Condition呢?

理由就在於nonblocking的RHS是在Active Events,而LHS是在Nonblocking Events,儘管彼此互相依賴,但Nonblocking Events很明顯地在Active Events之後,所以執行順序可以明確地確定,不像用blocking寫時,因為在Active Events內執行順序不確定,造成結果不可預期而產生Race Condition。

4.Monitor Events

當Nonblocking Events執行完後,接著Monitor Events的程式碼會依序變成Active Events而執行之。

我們都知道$display()無法觀察nonblocking所改變的結果,必須要使用$strobe()才可以,這是為什麼呢?因為$display()是屬於Active Events,而nonblocking完成於Nonblocking Events,明顯在Active Events之後,所以$display()跟本欄不到nonblocking所造成的改變,必須使用比Nonblocking Events更晚執行的Monitor Events中的$strobe()才可以觀察到nonblocking所改變的結果。

5.Verilog PLI Events

當Monitor Events執行完後,接著Verilog PLI Events的程式碼會依序變成Active Events而執行之。

Verilog PLI是允許你用C語言去寫一些Simulator的擴充功能,如Debussy / Verdi的$fsdbDumpfile()、$fsdbDumpvars()就是透過Verilog PLI,以前我ㄧ直搞不懂為什麼我用$display()與$fwrite()所dump的值與在Debussy / Verdi的nWave所看到的值不一樣,後來才發現原來$display()與$fwrite()是屬於Active Events,而$fsdbDumpfile()與$fsdbDumpvars是屬於Verilog PLI Events,比Nonblocking Events晚執行,這也是為什麼Debussy / Verdi可以顯示每個時間點nonblocking的值,而$display()與$fwrite()卻無法dump每個時間點的nonblocking,彼此的結果會差1個clock。

blocking / nonblocking與$display()、$strobe()、$monitor()、$fwrite()的執行順序

了解Verilog Simulator的『stratified event queue』之後,為了解釋nb_schedule1為什麼會有這樣的執行結果,我們將所有程式依照其在Event Queue的執行順序重新排列如下圖所示:

strobe02 

我們可以發現,儘管nonblocking與$monitor()、$strobe()寫在$display()與$fwrite()前面,但真正在執行時,Verilog Simulator還是會把它放在該放的Event Queue內,因為$display()與$fwrite()是放在Active Events,所以會印出a=0, b=1,接下來是Inactive Events的#0 $display(),也是顯示a=0, b=1,再過來是Nonblocking Events,執行 a <= b與b<=a,最後才是Monitor Events的$monitor()與$strobe(),因為nonblocking已經執行過,a與b的值已經改變,所以a=1, b=0,接下來因為a與b的值都不再改變,所以印出的值都不會再變。

Debussy / Verdi的nWave與blocking / nonblocking的關係

strobe03

在nWave內,1 ns時,所顯示的是a=1, b=0,若你是用$display()與$fwrite()去dump資料時,會得到a=0, b=1,也就是說,$display()與$fwrite()看到的是blocking的值,而nWave看到的是nonblocking的值,因為$fsdbDumpfile()與$fsdbDumpvars()是在Verilog PLI Events,執行點是在Nonblocking Events之後。

這也是為什麼有些工程師在寫sequential logic時,會在nonblocking加上#1,為的就是在Debussy / Verdi下看波形圖時比較好看,而Synthesizer會自動忽略nonblocking的#1,所以結果不會受影響。

Conclusion
1.因為blocking與nonblocking的關係,所以程式碼執行的順序不見的會依照我們所寫的順序,而是要依照『stratified event queue』的執行順序執行。

2.若皆屬Active Events的程式碼,在同一個時間點,在同一個sequential block內會依序執行,但在不同的sequential block內就無法保證誰會先執行,若彼此依賴有相關,就有可能造成Race Condition。

3.#0的blocking會比較晚一點執行,可以暫時解決Race Condition所造成的問題,不過這不是一個推薦的coding style,建議找出Race Condition的真正原因,而改用nonblocking去解決。

4.#0並不是最後執行,只是在Inactive Events而已,比Active Events稍晚,但還是比Nonblocking Events早。

5.Sequential logic也是可以用blocking寫,只是很容易造成Race Condition,必須很小心的安排blocking的執行順序,不是一個推薦的coding style。

6.$display()只能觀察到blocking,無法觀察到nonblocking,若要觀察nonblocking,要使用$strobe()與$monitor()。

7.$fsdbDumpfile()與$fsdbDumpvars()比$strobe()與$monitor()還晚執行,所以在Debussy / Verdi總是觀察到nonblocking的值,會比使用$display()與$fwrite()早1個clock。

完整程式碼下載
nb_schedule1.7z

See Also
(筆記)如何使用blocking與nonblocking assignment? (SOC) (Verilog)
(原創) 深入探討blocking與nonblocking (SOC) (Verilog)

Reference
[1] Clifford E. Cummings 2000, Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kills, Sunburst Design, Inc.

全文完。