pretty code

顯示具有 Verilog 標籤的文章。 顯示所有文章
顯示具有 Verilog 標籤的文章。 顯示所有文章

2025年8月3日 星期日

force, release, deposit command

一般來說,當我們 Testbench 測試時若遇到結果不如預期,往往都是某些訊號忘了設定,此時使用 force 便可以輕鬆搞定。

這樣的 case 一般不需要用到 release 解除原本的 force。

但換句話說,如果是需要 release 的 case,EDA 廠商的 Tcl deposit command 會比較好用,不需要另外記得 release,只要驅動該訊號的 input 有所變動,自然會以新值取代原本 deposit 給予的值。

即使記得 release 也不是什麼 case 都能讓原本的訊號繼續工作?

假設我們是對某根訊號 force x,假設這個訊號的電路是跟自己做反向,那這個訊號就會永遠 unknown 下去。

不知道觀察到的現象是否可以解釋 unknown 還是有機會無法回復呢?


2025年7月20日 星期日

電路是個很神奇的東東

雖然 debug 很煩,很多時候會找不到方向,還有問題一直無法收斂,但多少還是可以從中學到一點新知識。

電路是個很神奇的東東,可能只是某一個 bit 不對,就導致整個 simulation 不如預期。

昨天剛好跟同事討論到 $display 出現了 xX 的字眼,查了一下,才知道這兩者是有細微的不同。

簡單來說,當訊號中有一部分是 unknown,就會看到大寫的 X。

反之,如果訊號全部 unknown,便是小寫的 x。

長知識了XD

下面是一個簡單的例子以及規格書描述。


2025年7月5日 星期六

動態改變 Verilog 選項

很多時候,工作就是一連串的取捨。

以 Verilog 來說,`ifdef 是編譯時期決定的,可以用這個來決定 Verilog 的行為。

但如果我們想要增加功能,我們就必須重新 define 新的 macro 並重新編譯才行。

想要動態改變 Verilog 選項,就必須使用 $test$plusargs 或是 $value$plusargs,前者類似 `ifdef,我們想要知道的是某個值是否有定義,後者則是我們想知道某個值是什麼。

下面便是一個簡單的例子。


值得注意的是,使用 `ifef 或是 `$test$plusargs 並沒有什麼準則,端看你的需求是什麼?

動態改變某個選項,意味 simulation 必須一直做判斷求值的動作,我想這多少也會增加 simulation 的時間?

假設不考慮效能的話,動態一定是比 `ifdef 好,至少你可以一眼看出程式在幹嗎!


自己寫的 Verilog 還好搞,像是 vendor 的 Testbench,它的各個 define 散落各地,光要把他們集合起來餵給 iverilog 就是個大工程。

純軟的人真倒楣,走到哪都要看到爛 code,10 幾年前我看高通以及微軟的 AK 已經覺得夠爛了,沒想到現在看到 Synopsys 的 code,我才知道人外有人,天外有天。

一爛還有一爛爛,連文件跟 Testbench 都對不起來是怎樣?

2025年7月3日 星期四

fsdb 替代方案

雖然在 github 找了幾個關於 fsdb 的替代方案,不過 Windows 上並沒有合適的檔案可供測試,故暫時無法得知一些替代方案是否可以解決?

看起來除了控制 VCD 的 level 與 instance 層級之外,目前的最好解法便是在適當的地方,呼叫系統指令暫時關掉不想要的 dump 動作。

跑起來的感覺大概就像下面那張圖一樣。

從 100 ns 開始,呼叫 $dumpoff 停止 dump,接著在 200 ns 開始,呼叫 $dumpon 恢復 dump。


另外,下午在找資料的過程中,無意間發現當初開發 fsdb 的人。

一般來說,我都會很佩服這樣的人!

不過,唉,不說了…

但是有機會我還是會去買他或是她的書來看,至少在 coding 這一項,對方一定是比我強沒錯!

正所謂海納百川,不以人廢言。

2025年7月1日 星期二

沒事多讀規格書

原本我以為 timescale 是可以細到針對個別 Verilog 設定XD

昨天在 2005 規格書好像沒有看到?可能是跟我邊分心連到工作站做事有關,不過卻意外多知道一個函數 $printtimescale( ),可以印出目前檔案的 timescale 設定。

今天突然想到,自己寫個 Testbench 來驗證不就好了!

於是我對 Verilog 又多懂了一點點…

今日重點

01. $printtimescale 可以印出目前 timescale。
02. 看起來所有檔案只能用同一個,後面會覆蓋前面(待確認?)。


2025/07/02 更新

下午因為硬碟空間不足,苦等原本測試未果,無法繼續下一個測試。

乾脆跟 Google AI 對談,順便切磋一下彼此對 EDA 軟體心得,後來順口問了一句有關 `timescale 的想法,居然發現 AI 給的例子完美證明了 `timescale 是可以對個別 module 做設定。

我本來的例子由於是 include,因此會原地展開,才會有我後者取代前者的結論。

下面是 AI 給的例子,因為是個別編譯,故分別保留各自的 `timescale。


雖然我昨天又看了一次規格書,實在看不出這樣的結論?

不過,我跟 AI 都一致認為這樣容易產生 bug,最好的方式還是有一個統一的 include 檔案,大家才能都用同樣的設定。

2025年6月29日 星期日

1'bx = false

果然跟我想的一樣,1'bx 在 Verilog 中屬於 false 的情況。

我的 Testbench 結束條件是某個 register bit !=  1,IP Vender Testbench 的結束條件是判斷 bit == 1'b1,就會繼續在 while loop 中。

但不知為何,我失敗的 Test case 會讀到 1'bx,因為等於 false,自然會跳出迴圈。
 
下面是我模擬程式的示意圖。


雖然 IP Vender 判斷條件寫的 code 不嚴謹!但問題不是出在這裡,而是為什麼除了 REVISION_CHECK 外的測試,在讀 Shadow register 時居然會讀到 0 or 1 以外的值?

感覺問題本質又回到了原點:

01. 客戶給的 C code 和 firmware 是否正確?
02. 是否有哪個設定是錯的,比如像 cfg 到底是不是 hard code?
03. Testbench 是否有哪邊給的訊號是錯的或是說是否需要調整 timing,就像我用 APB 連 REVISION_CHECK 都過不了?

2025年6月12日 星期四

Verilog - Implicit declarations

在 Verilog 2005 4.5 中提到了 Implicit declarations。

簡單來說,變數可以直接使用XD

在我這種寫純C 出生的看來,這種 coding 真的是大逆不道!

如果只是一個地方忘記宣告就算了,偏偏我看到的卻是幾乎所有的變數都這樣使用,重點是這個 Testbench 還是御三家中的某個 IP 的 Testbench。

一個要錢的東西你這樣寫,我只想問候他老母?

不過也不排除這樣寫是故意的,大大增加你修改 Testbench 的不便XD

雖然我現在就是要確定你每個 net 給什麼值,假設你在這個 Testbench 中 include 一堆檔案,我得一個一個看過去才知道你到底是否有在哪個地方宣告並賦值?這大大增加了我 trace code 的不便!

尤其這裡用了一堆 define,其對應的 endif 也沒給註解!

我實在是很難一眼看出我要的東西到底在不在。

第一個問題很簡單,如果是自己寫的 Verilog,加上下面語法即可報錯。

`default_nettype none


第二個問題就有點小麻煩

理論上如果我知道所有的 define 是什麼,我是可以透過 iverilog 的前置處理來幫我去掉不要的 define,再用 sed 去掉拿掉 define 留下來的連續空白,我就可以有一個清爽的 Testbench 來用。


但問題是我連完整的 Testbench 都有缺,我根本無法確認所有的 define?

2025/07/06 更新

雖然 implicit declaration 很不可取,但我最近 blog 文章的 demo 也是用了這個技巧,讓我可以用一張圖片表達我想表達的意思,所以我也用了很多這個技巧來減少我的 Verilog 行數XD

不過我寫 Verilog 絕對不會這樣用就是了。

2025年6月4日 星期三

原來我對 Verilog 理解有誤

一直以為在 Verilog 中,想要用某個 module,一定要建立一個實體,沒想到好像不是這樣?

這幾天又把手上的 IP test 相關 flow 又看更深了一層,在看的過程中就覺得哪邊怪怪的,原來是 module 不用一定要建立實體?

晚上回到家,寫了一個測試來驗證,好像真的不用,難道是 System Verilog 的緣故?先記錄一下,回頭再來確認!


2025/06/05 更新

早上翻遍了 Verilog 規格書,還是看不到不用實體化的理由?

於是問了一下 Bard,他也是一直跟我說不行,直到我說我用 iverilog + vvp 是可以跑的,他才告訴我一個答案,一開始我還半信半疑,不過,有了方向就好解決,打開 -v 選項一切都無所遁形!

下面是 Bard 的回答

你觀察到的現象是正確的!

你的 tb.v 程式碼能夠被 iverilog tb.v + vvp a.out 正確執行,這主要是因為 Icarus Verilog (iverilog) 編譯器的一個特性,以及 Verilog/SystemVerilog 語言中階層式參考 (Hierarchical Reference) 的規則。

Icarus Verilog 的行為:

自動辨識頂層模組 (Top-Level Modules):

iverilog 預設會將那些沒有被其他模組實例化的模組視為頂層模組 (top-level modules)。

在你的 tb.v 檔案中,cfg 和 test 這兩個模組都沒有被其他模組實例化,所以 iverilog 會將它們都視為頂層模組。

這意味著 iverilog 會為 cfg 和 test 各自創建一個獨立的實例,位於模擬器內部的一個抽象的 "root" 級別。

即使 cfg 模組沒有被 test 模組直接實例化,但 test 模組可以透過階層式參考的方式來存取 cfg 模組內部定義的訊號。

在 iverilog 預設將 cfg 視為頂層模組的情況下,它會被分配一個預設的階層名稱,通常就是它本身的模組名稱,或是在內部樹狀結構中被編譯器視為一個根實例。

所以,當 test 模組嘗試使用 cfg.num 時,iverilog 能夠解析這個路徑,找到 cfg 這個頂層模組的實例,並進一步找到它內部的 num 訊號。

為什麼這在真實硬體設計中不常見:

雖然 iverilog 允許這樣做並能正確模擬,但在實際的 RTL (Register Transfer Level) 硬體設計中,這並不是一個好的設計習慣,通常會避免。

缺乏明確的連接性: 

在硬體中,你必須明確指定一個模組如何與另一個模組互動(透過實例化和端口連接)。你目前的寫法模糊了這種關係,讓人難以理解訊號是如何傳遞的。

模擬器/合成器行為差異: 

雖然 iverilog 支援這種階層式參考,但其他模擬器或硬體合成器 (Synthesizer) 可能對這種寫法有不同的解釋或根本不支援。合成器在將 Verilog 程式碼轉換為實際電路時,需要明確的連接關係,而這種直接的階層式參考對於合成器來說通常是難以理解和實現的。

可讀性與維護性: 

這種寫法降低了程式碼的可讀性。當專案變大時,很難追蹤哪個模組直接存取了另一個模組的內部訊號,這會增加維護的複雜性。

模組的封裝性: 

模組應該有良好的封裝性 (encapsulation),即外部模組只能透過其定義的端口與之互動,而不應該直接進入其內部存取訊號。直接的階層式參考打破了這種封裝。

總結:

iverilog 允許你的 tb.v 程式碼正確執行,是因為它有足夠的智慧來辨識多個未被實例化的模組為頂層模組,並支援跨層次的階層式參考。

然而,在撰寫可合成的硬體描述語言時,強烈建議遵循實例化 (instantiation) 和端口連接 (port mapping) 的標準方式來建立模組之間的關係,或者使用 參數 (parameters) 或 SystemVerilog 的封裝 (packages) 來定義全域常數,以確保程式碼的清晰度、可攜性以及可合成性。

下面是我回家測試的結果


確實使用 -s 指定 top module 後,iverilog 便會報錯,可見 Bard 沒有騙人XD

2025年5月27日 星期二

Vim vtags

雖然經過這一年的洗禮,我已經習慣了 Vim,也把自己購買放在公司專用的 UltraEdit 移除了。

即便上星期寫了一個 trace variable 並顯示位於哪個 module 的 Vim function,想要好好在 netlist 中 trace variable 還是很痛苦,沒有 EDA 可用就是這麼辛苦XD

今天看到一個 vtags 的小玩意,想說是不是能幫助我看一些東西?沒想到這個東西不能在 Windows 上執行,還好我有 WSL2 環境,果然在 Linux 就可以順利執行。

可惜,手上的 netlist 過於龐大,vtags 會讓 Vim 當機,故我也沒看到他的廬山真面目!

回家試了一下,左邊是 <Space> + v,右下是在 module 那行執行 mt 的結果,看起來似乎跟我的 netlist_treeview 差不多意思,看的都是 hierarchy 的結果,並非我想的訊號追蹤?


還有像 ORFS 裡面的 jpeg_encoder 因為 yosys 綜合後,會用到很多 escaped identifier,故 vtags 也無法支援。


難道,我又要自己寫 tool 了嗎?這可是一件大工程呀!

另一個可以嘗試的方向是 GNU global,看起來只要找到 plugin,就可以處理 verilog 的專案?

2025/05/27 再次更新

原來是我耍笨,看起來可以用來追蹤訊號,詳此處

拿它來改出我要的工具?

2025年3月7日 星期五

Verilog $value$plusargs

平常用 iverilog 時,最常使用的是 -D 選項,此選項是 for 編譯時期使用。

如果我們想要在 simulation 時期傳遞參數,就必須使用 Verilog-2001 新增的語法 $value$plusargs

既然是 simulation 時期,故必須在模擬時傳遞參數,也就是需要傳遞參數給 vvp 這支程式。

module TB;
reg[512*8:1] _new_path;
initial begin
if ($value$plusargs("NEWPATH=%s", _new_path)) begin
$display("%0s", _new_path);
end
else begin
$display("No NEWPATH");
end
end
endmodule

vvp -n test.vcd +NEWPATH="XXXXX"

2024年9月7日 星期六

又是 Verilog

前幾天為了快速讓 DC 可以往後跑下去驗證環境是否正常,還沒等到樓上同事的回覆,我就已經先改好了,在我看了大神的幾篇 race conditon 文章後,個人覺得從 = 改成 <= 的結果是一樣的,畢竟在那個 T 中,外面取 signal 的其他 module,如果本身判斷處也是 sequential logic,勢必要在下一個 T 才能收到這個變化,不會因為這裡寫成 blocking assignment 就會有所改變,至少我個人目前的理解是這樣。

早上起床後有寫了支測試程式試了一下,看起來跟我想的一樣,但因為早上急著出門,一直到剛剛才有時間整理一下,馬上現學現賣早上學會的分割視窗功能,雖然這邊有點為用而用,畢竟 VIM 本身就可以分割視窗,但這裡真的是分割視窗,視窗分別各開一個 VIM。


畢竟我手上沒有 code,m1 module 是我憑大意寫出來的,但應該有還原出原模組的用意?

m1 out[1:0] 使用 Blocking assignment
m2 out[1:0] 使用 Non-blocking assignment

test1 使用 sequential logic 判斷 m1 out[1:0] 值用
test2 使用 sequential logic 判斷 m2 out[1:0] 值用

test3 使用 combinational logic 判斷 m1 out[1:0] 值用
test4 使用 combinational logic 判斷 m2 out[1:0] 值用


因為我 0ns 沒有拿來幹嗎,故 testbench 在這個時間點都用 blocking assignment。

為了避免 5ns 使用 blocking assignment 跟 clk assignment 產生 race condtion,我將 d 跟 flag 設值提早到 4ns 處,因為我 m1 和 m2 就是要在 5ns 開始判斷訊號做事,不要拖到下一個 posedge clok。  

10ns 雖然也是使用 Non-blocking assignment,但我沒有 negedge clk 的 case,故這裡即使用 blocking assignment 也不怕 race condtion。


從 waveform 可以看出,5ns 時,不管是 test1 或是 test2 在 testbench 那端,因為是用 sequential logic 去接 data 訊號,故輸出是 x。

相反的 test3 和 test4 因為是用 combinational logic 去接 data 訊號,故輸出是 1。

因此,截至目前為止,我對 Verilog 的理解是:

01. 在 testbench 那端使用 blocking assignment 設值,大部分情況在另一個 module 的循序邏輯都可以看到該訊號變化,但如果 testbench 那端的 data 設值是跟 clk 在同一個時間點,有可能 clk 會先改變(看各家 simulation 實作,Spec 這裡順序是不確定的,看誰先從 active region 被取出),這意味著在別的 module 的循序邏輯會看不到該訊號變化。

02. testbench non-blocking assignment 沒有異議,一定是別的 module 循序邏輯的下一個 clock 才能捕捉到。

03. 如果 module 組合邏輯的輸出,跟本身模組裡面的循序邏輯設值有關,即使是透過組合邏輯輸出,testbench 或是其他使用的 module 那端,也是要在下一個 clk 才會反映出來,除非使用端也是用組合邏輯接,但只要這個訊號有被其他循序邏輯用到,就是要等下一個 clk。

我的理解應該是對的吧?

2024年8月25日 星期日

Verilog 里程碑

Verilog 真的是很神奇的一門語言!

有時候覺得懂了,有時候卻又覺得什麼都不懂!至少無法像我會的其他程式語言一樣,可以隨心所欲的拿它來解決任何問題。

HDLBits 是一個很好的網站,可以拿它來學習 Verilog,但它有一些缺點,我們無法看到它的 Testbench,所以有時 debug 會有點困難,不過想想 leedcode 也是如此,似乎也很正常?

另外,它其實是會跑 Synthesis,故它其實是用合成出來的 netlist 來跑 Testbench。換句話說,如果寫出來的 Verilog 有問題,則有可能會跑不過 post-synthesis simulation。


這題我覺得是一個學習 Verilog 的里程碑,至少對我來說是如此。

照它題意,它希望你用前幾題學到的技巧,來解決這題,也就是將前幾題的電路用在此處。

但我一直無法順利用小電路來解決此一道題,我甚至想寫 3 個 module 來解此問題,其中最後兩個訊號,我感覺是一樣的意思,故想用同一個 module 來解題,換句話說,我的 top_module,就只是 initial 4 個實體罷了。

雖然可以用 iverilog 跑成功,但是在 HDLBit 就是會錯在 130 ns 的時間點,在知道 HDLBits 是用 netlist 跑合成後,我甚至用 DC 試跑合成,果然我的 netlist 用 ncverilog 也會跑出問題,問題是出在 DC 會報 time loop warning,故它在 3 個 cell 處會忽略 timing arc,我在 dump waveform 會一直無限膨脹檔案大小,卡在 100 ns 處,感覺是我組合邏輯哪邊有問題?


如果我放棄使用小電路方式來解題,改在 top_module 用 FSM 寫出所有的 code,就可以順利通過 HDLBits 的 Testbench。

我想讓 shift_ena、counting、done 都委由 submodule 來設定,但這會有 timing 問題,有時候為了滿足 timing 我甚至會在 submodule 改用組合邏輯提早一個 T 將訊號送出,好滿足下一個 submodule 的 timing。

先不說這樣設計對不對,但我還是想用這樣的方式來解決這一道題目,說它是我學習 Verilog 的里程碑還真不為過。

想當年我初學程式以及使用 Keil C 撰寫 8051 也都是卡在某個地方,後來意外打通之後,世界突然就變輕盈了,真希望趕快打通這裡。

2024/08/25 更新

忘記在哪個 github 看到,有人確實是用兩個電路來解決此題,recognizer and shifter,但是他是在 top_module 統一控制 output 訊號。

目前只知道,HDLBits 會故意在不同階段亂送某階段需要觀察的訊號,但我還是想不通我的 130 ns 錯在哪裡?

2024/08/26 更新

我的第一個 submodule pattern 是用來捕捉 1101 訊號用,故其餘的 submodules 都是靠他往下走,所以我需要讓 pattern 不要被 data 訊號影響,這是我錯誤的第一個點,也就是說整個電路未完成前(未收到 ack 前),我的 pattern 應該要讓他一直處在 reset 狀態才對。

其餘的錯誤就是其他 submodules 忘記在 END state 回到 IDLE 階段。


雖然目前暫時解決了,但為了配合時序圖,提早改變 output 訊號感覺還是很怪?

我覺得要不就是我不能這樣劃分 submodule,不然就是我的 verilog 寫法還是哪邊觀念不對。

2024/08/27 更新

今天看 1500 spec 時,文件也有提到需讓待測 core 視情況處在穩定狀態(reset),看起來這是用 Verilog 描述電路時的一個重要關鍵,就像我們純軟在 task 做完時,會 reset 變數一樣!

補上 gtkwave 訊號 configuration,之後有空再來繼續改進此電路XD

橘色劃線的訊號就是為了配合時序控制下一個電路而提早 1T 改變的回饋觸發訊號。


2024/08/29 更新

看 1500 spec 突然想到,米利型 FSM 的輸出不只要看 state 也會看輸入,我的 stop_module 頗有這樣的味道在?done_counting or ack 就是我要配合的輸入。

另外在看同事 wrapper demo code 時,發現該同事會用很多 assign 語法,甚至還看到他不直接 posedge clk 而是改用 assign 語法將 wire 搭配一些條件判斷將 clk 指派給該 wire,之後反而直接用 posedge wire_name?

原來我沒看過的 Verilog code 還真多,雖然還沒深入探討,但應該是為了 timing 或是為了縮短減少測試時間?應該吧?

2024/08/30 更新

昨天忘記補充,摩爾型 3 段式 FSM 的 output logic,我有看到用組合的也有看到用循序的。

我覺得比較合理的應該是用組合邏輯,但我有看到一個比較合理的說法,為了避免組合邏輯 path 過長影響 timing,所以會多敲一級改用循序邏輯。

不過在我這邊的 case 就不適用,因為我的 timing 已經太慢,用循序會再多慢上 1T。

2024年8月17日 星期六

2024 week 33 新玩意

01. Synthesis area improvement

這兩個禮拜除了研究 Verilog race condition 現象外,其餘時間都在包 SRAM wrapper!

部門資深同事著實太忙,想說自己來研究一下好了,Width 還算簡單,但 Depth 就需要稍微想一下,第一版出來後,對照時序圖寫了 testbench,也確認功能有合乎預期。

這星期再一次 review 同事那包 RTL code 才發現,有一個名為 dual port 的 FIFO SRAM,其真實行為居然是 1R1W,故只好再包另外一種 SRAM wrapper。

這個 wrapper 比較特別,有設計 bypass,但居然是 sequential logic?我唯一想到的就是不要太早反應 SRAM 吐回去的 data?不然正常來說,不管是調整 Width 或是 Depth,我們應該都用 combinationl logic 即可。

除了寫 testbench 外,也順便用 DC 跑 Synthesis,post-synthesis simulation 也是正常。

在等待工作站 code ready 的空檔,順便研究一下 RTL code 與面積的關係。

我需要的 SRAM wrapper 跟真實的 SRAM 資訊如下:

DP 4096X96 ( SP512X32 )
DP 1024X96 ( SP512X32 )
2P 1024X64 ( 2P512X32 )

1 和 2 其實是相關的,故我一開始是用 2 的 module 再包一層,但這樣面積會比較大,拆成 8 顆 512X96 後,面積就改進了。

一些取餘數跟 Address 位址一開始沒想到的 code,在改正後,面積居然沒變,看起來 DC 有一定的功力,知道如何優化。

但隨著 code 不斷再精簡(通常來說,RTL code 越多,其實合出來的 cell 也就越多),最後兩種 wrapper 面積分別可以減少 300 和 200 左右。

我用的 Cell Library INV 的某 cell 面積大概是 1.29,其他一些小 cell 約略是 0.29 左右,基底的 SRAM 以 1P 來看則約莫是 5000 多一點。

過程中還發生了小插曲,因為被 KB5041578 事件搞了,最後一版的 RTL code 還未跑 simulation,故等到下午 IT 處理後補跑才發現資料都是錯的,由於這裡沒有用 Git,工作站空間也很吃緊,故我也沒建 local git,因改動的東西確實太多(第一版 code 真的很差,雖然可讀性比較好,但應該是我還用 SW 思維寫 code 的緣故,之後應該會慢慢習慣),只好一層一層 wrapper 檢查回來,但也很快地找到原因。

我發現組合邏輯善用 bit operation 後,大部分可以有效減少面積,但撰寫時就要特別注意資料寬度是否一致。

由於同事那包 RTL code,其 SRAM port 和 active signal 都跟我用的 Cell Library 不同,考量這只是中繼 wrapper(最終還是要用 Memory Compiler 重新產生,只是什麼軟體都要 License,目前部門還沒有相關 License 可用),故把 difference 直接改在最底層的 module code 中。

原本的 code:

localparam WIDTH = 32;

input WEB;

if (WEB)
    BWEB = 32'h00000000;
else
    BWEB = 32'hFFFFFFFF;

改進後:

BWEB = (~(32'h00000000 | WEB)

正確的 code:

BWEB = (~(32'h00000000 | {WIDTH{WEB}};

只是 or 操作的長度不對,結果就天差地遠XD

02. testbench simulation

雖然知道了 Verilog race conditon,也看了Clifford E. Cummings 大神的幾篇論文,但對於 testbench 設值的時間點還是不知道有沒有一般公認的標準可供遵循?大神的論文雖然有些建議,但我還是覺得看 Spec 寫 testbench 還是最適當?

寫 testbench 時,我們很容易讓 clk 和 data 在同一個 timing 中更改,這其實要看 active event region 被 simulaor 取出執行的順序,故結果不一定跟你想的一樣?

這也是為什麼 VCS 有一個 deraceclockdata 的 flag 可設,雖然應該要使用者自行避免才對。

我自己感覺 iverilog 行為是這樣?

testbench 中設定的值,不管是 clk or data,sensitivity list 的 signal,就是你在另外 module 中會用 if 判斷的,iverilog 會先設值,接著是 clk,最後才是 data,就是 RHS 的 signal。

順帶一提,要 trace iverilog 的 code 應該要從 vvp 和 tgt-verilog 的資料夾開始,當初稍微一喵的感覺是這樣?

不過在前項 SRAM wrapper 的研究中,TSMC SRAM 確實是在 postedge 前,address 和 data 就要 ready,我最早版本的 SRAM testbench 也是這樣設值,差別在 TSMC Spec 看起來最好不管是讀或寫,最好都保持 2 個 T 後,第 3 個 T 才繼續下一動操作,雖然我用他們的 verilog code 跑 testbench 用原始版本 1 個操作使用 1 個 T 也是正常?

我目前的結論是還是看時序圖寫 testbench 最準。

希望等到越來越有經驗後,能夠回過頭來給個最後結論。

由於 Verilog 及相關知識都是自行上網學習,也不知道自己看的方向是否正確?

2024年8月11日 星期日

Verilog race condition example

在 IEEE Std 1364-2005 Section 11 提到 Event simulation 和 stratified event queue 等概念,雖然只有 4 頁,但卻很難用自己的話來闡述它。

簡單來說,event 在執行時,會將其加到 event queue 並分為 5 大區塊,只有放到 active event region 的 event 才會被移出,其它 region 則是會隨時機移到 active event queue。

由於 simulation 是用軟體模擬,不像硬體電路可以並行,故在執行上會有先後之分,因此這章節會定義哪些 execution event 其執行順序是確定的,哪些又不是。

因此我們要注意撰寫 Verilog code 以避免 race condtion 發生。

下面是一個簡單的例子可以看出隨著調整不同區塊的位置,其模擬結果也會不同。

flag = 1

0: initial1 d = 0
0: initial2 d = 0
0: always1 d = 0
0: always2 d = 0

flag = 0

0: initial1 d = x
0: initial2 d = x
0: always1 d = 1
0: always2 d = 1

`timescale 1ns/1ns
`define flag 0

module test();
    reg d;
    
    initial begin
        if (`flag)
            d = 0;
    end
    
    initial begin
        $display("%t: initial1 d = %d", $time, d);
    end
    
    always @(*) begin
        $display("%t: always1 d = %d", $time, d);
    end
    
    always @(*) begin
        $display("%t: always2 d = %d", $time, d);
    end
    
    initial begin
        $display("%t: initial2 d = %d", $time, d);
    end
    
    initial begin
        if (!`flag)
            d = 1;
    end
endmodule

2024年3月23日 星期六

這週新玩意

01. Verilog 奇怪語法

wire [63:0] data;
wire [7:0] array [7:0];

array [0] = data[0+:8] 前面指的是 base,後面指的是寬度,意思是從 base + width 的範圍,也就是等於 data[8:0]。

這個語法是從 Verilog 2001 開始的,請詳 4.2.1 Vector bit-select and part-select addressing。

02. sed

sed -i "s/abc/def/g" file_name

每次都會忘記,-i 表示要修改檔案,要把所有的 abc 取代成 def。

03. search cell name in cell files

grep -EH 'cell\s*\(\s*\"*sky130_fd_sc_hd__a22o_1' *.lib | sed 's/:\s*cell/ /g' | awk -v var="$PWD" '{print var "/" $1}'

為了在眾多檔案裡找到 cell 位在那個 cell libraries?利用上述語法,我可以得到完整的路徑,便可以貼到我的檔案去做後續的處理。


-EH 要看 grep 版本,我的 WSL 需要這兩個,E 表示 extend,H 表示顯示檔案名,記得工作站不需要。

sed 是把找到的檔案,將檔名跟搜尋 pattern 分開隔出空白。

awk 則是把 $PWD 環境變數傳進去,利用 print 組出完整檔案路徑。

2023年12月27日 星期三

iverilog + GTKWave 使用小技巧


這應該是我看過寫得最好的文章了。

除了教你如何 dump array,也教你如何儲存設定好的波形檔案(GTKWave -> File -> Write Save File As,假設檔名為 config.gtkw),下次啟動 GTKWave 就不用重拉了(gtkwave config.gtkw),這應該更有助於 debug。

後悔沒早看到這篇文章,只來得及儲存除法流水線範例設定檔。

2023年12月26日 星期二

Display verilog array built by iverilog in GTKWave

Ans:使用 generate 語法即可,generate for block 要不要命名都可以,這應該是目前最方便的 workaround 了。

`timescale 1ns/1ns
`define VIEW 1

module test;
    initial begin
        if (`VIEW == 1) begin
            $dumpfile("wave.vcd");
            $dumpvars(0, test);
        end
    end

    reg [3:0]  buffer[0:7];

    genvar j;
    generate
        for (j = 0; j < 8; j = j + 1) begin: buffer_array
            wire [3:0] buff;
            assign buff = buffer[j];
        end
    endgenerate

    integer i;
    initial begin
        for (i = 0; i < 8; i = i + 1) begin
            #10;
            buffer[i] = i[3:0];        
        end
        
        #200;
        $finish;    
    end
    
endmodule


2023/12/27 更新

還有另一個作法是使用 $dumpvars,這個似乎是 iverilog 作者在回網友郵件中建議的?這個語法更少,雖然 vpp 模擬時會有 warning,不過在 GTKwave 中不會多一個臨時變數,看起來更直觀,但似乎不是都可以用?請詳此處

module test;
    initial begin
        if (`VIEW == 1) begin
            $dumpfile("wave.vcd");
            $dumpvars(0, test);
            for (i = 0; i < 8; i = i + 1) begin
$dumpvars(1, test.buffer[i]);
    end
        end
    end

    reg [3:0]  buffer[0:7];

timescale in iverilog compiler

下午看乘法器流水線範例時,在看懂了 wave 後,想要印出各個實例化的模組是否在我想的時間內進去主要的計算區塊(mult_cell.v, en == 1),於是便多傳了一個 id 進去並在 en == 1 時,使用 $display($time, " ", id); 來印出目前時間。

沒想到不管怎樣 $time 永遠印出 0,明明 wave 都是間隔 1 個 cycle 時 rdy 才等於 1?

想了一個下午,終於在 5 點多想到原因。

timescale 是 compiler directive,可以在 Standard 2001 Section 19 看到相關說明。

顧名思義,這個指令是在編譯階段決定,由於這個範例有 3 支檔案,沒辦法用我之前的 Windows batch 編譯,只能手動打指令編譯,但我在呼叫 iverilog 時,沒有將 Testbench 擺在最前面,導致 iverilog 在編譯 cell module 或 man module 時,因為未看到 timescale 指令,故無法正確計算 $time。

下次一定要記得將 Testbench 擺在第一個。

如果當初 iverilog 後有帶 -W all,此時也會看到相關警告訊息。

D:\Verilog\05_manual_build>iverilog -W all -o wave mult_cell.v mult_man.v mult_tb.v
mult_tb.v:76: warning: implicit definition of wire 'rstn'.
warning: Some modules have no timescale. This may cause
       : confusing timing results.      Affected modules are:
       :   -- module mult_cell declared here: mult_cell.v:1
       :   -- module mult_man declared here: mult_man.v:1

修正後終於可以驗證我的想法對不對了。


雖然將 -W all 打開,可以避免這個失誤,但會多出很多不必要的警告訊息。

之後也許可以參考這裡,只設定必要的 Warning 即可。

-Wanachronisms
-Wimplicit
-Wimplicit-dimensions
-Wmacro-replacement
-Wportbind
-Wselect-range
-Wtimescale
-Wsensitivity-entire-array

2023年12月25日 星期一

Verilog 非阻塞賦值

雖然知道這個概念,但每次看 wave 時都會中招XD

reg [3:0] a = 1,  b = 0;
always @(posedge clk) begin
    if (a != 0) 
        a <= a + 1    
end

always @(posedge clk) begin
    if (a == 1)
        b <=  1
end

假設兩個 always block 第一次 if 那個時間點是 10 ns,在此當下 a = 1, b = 0,因為電路是並行緣故。

但因為 wave 在此點後都會顯示新的值,故常會認為該點也是新的值!

我想我還需要一點時間來習慣,這個非流水線乘法器是個不錯的例子,忘記可以回來複習。

另外,關於如何在白紙上計算驗證也是我現在頭痛的問題,寫的真亂。


65 ns 時,因為 data_rdy = 1,故會進到 cnt 與 cnt_temp 互相作用的那個 always block,但因為電路並行,故 cnt_temp 值還未反映到 cnt,因此 mult1 和 mult2 那個 always block if 判斷都要看非阻塞賦值前的值,同理兩個 shift 變數也要以非阻塞賦值前的值來做計算。

2023年12月18日 星期一

學習 Verilog 前應該要知道的事

Hardware Description Language (HDL) 是硬體描述語言,我們比較常聽到的是 VHDL 和 Verilog。

因為是描述語言,重點是描述硬體行為,故在學習時不能用軟體程式語言的思維去理解它,比如硬體電路是並行的,不像一般循序程式語法有先後順序概念(雖然在 Testbench 中可以使用 delay 或阻塞賦值確保順序)。

Verilog 共有 3 個標準,我們比較常用的應該是 Verilog-2001。

Verilog 1364 - 1995 (Verilog - 95)
Verilog 1364 - 2001 (Verilog - 2001)
Verilog 1364 - 2005 (Verilog - 2005)

SystemVerilog 則是為了補充 VHDL 和 Verilog 的不足,有點像是他們的超集合。

SystemVerilog 除了是 HDL 也是 Hardware Verification Language。

其實還有很多,後續再慢慢補充吧…