pretty code

2023年12月29日 星期五

Some tips in Makefile - 002

01. export 

ABC ?= abc

上面表示如果 $(ABC) 未定義,則值等於 abc。

我們可以在呼叫 make 前,在 Shell 下 export ABC=ddd,則 Makefile 中就可以看到被定義成 ddd,另外一種方式則是 make ABC=ddd xxxx_target。

如果在 Makefile 中寫成 export ABC ?= abc,則這個 $(ABC) 可以傳遞到其他的程序。

假設是這樣執行 $(shell ./test.sh),即使用了 export,test.sh 中也看不到 $ABC 這個變數,這部份待確認?

順帶一提,在 Shell 下使用 export 則是將變數傳給其他的程序,比如另一個 shell script 或是執行檔等,像 C 語言可以用 getenv 取的環境變數。

02. 只看 make 執行過程,不真正執行

make -n 即可。

03. 使用 wildcard, abspath, notdir

像是在 Makefile 印出當前目錄下的所有檔案但不包括目錄本身,如果要絕對路徑則是用 abspath 取代 notdir 即可。

$(foreach log, $(notdir  $(wildcard ./*.log), $(info $(log)))

另外,foreach 語法如下:

$(foreach n, list, text)

list 是一串用空白分隔的字串,n 是當前取到的單一字串,text 則是你要做的事。

04. $@, $^, $<, $?, $*

有一 rule 如下:

main.o:    main.c def.h
            gcc -c main.c

假設 def.h 有更動過。

$@ = main.o  --> target
$^ = main.c  def.h  --> dependence
$< = main.c  --> first dependence
$? = def.h  --> changed file
$* = main  --> the primary name of target

故 gcc -c main.c  可以寫成 gcc -c $<。

另外,假設 target = all,則 $* 是空字串,因為 all 沒有副檔名。

2023年12月28日 星期四

Some tips in Makefile - 001

今天開始接觸未來可能的工作流程,雖然只是練習用,但也算是有點感覺了。

主管還很貼心的提供了一個小測驗,由於我對 Tcl 或是 Makefile 都只是略懂,一開始先花點時間整理脈絡,直到看到主管說的關鍵字後,便開始主攻這個測驗。

雖然這個測驗有點像腦筋急轉彎?但在一步一步分解問題後,最後還是能找到解法,但我也花了一個小時多有,還好在吃飯前順利搞定。

簡單快速紀錄一下,今天學到的東西XD

01. Makefile 變數賦值

= 在使用到變數時展開。
:= 宣告變數時就展開。
?= 變數為空時才給值。
+= 將值附加到原本變數。

02. .DEFAULT_GOAL

如題,此變數為 GNU make 的一個特殊變數,有設定這個,假設 make 後面沒帶 target 就會以這個變數為主,而不是檔案中找到的第一個 target。

03. $$0 in awk command of Makefile

原本 awk 取原始字串是 $0,但在 Makefile 中 $ 有特殊用途,故在 awk 指令中,需要多加一個 $。

另外,如果想印出 $@,則應該要這樣寫 @echo \$$@。

04. env variable in Tcl

puts $::env(OS),此指令的意思是印出 OS 這個環境變數,env 本身是 array,array in Tcl 是關聯陣列。

05. call proc in some Tcl files.

source $::env(SCRIPTS_DIR)/report_metrics.tcl
report_metrics 6 "finish"

report_metrics.tcl 檔案中都是函數,這樣就可以呼叫該檔案裡面的 report_metrics 函數。

06. /usr/bin/time -f '%E %MKb' sleep 5

time 是用來記錄執行指令的時間,不同的 format 可以顯示不同的資訊,上面表示記錄 sleep 5 執行的時間及最大記憶體使用。

07. export QT_QPA_PLATFORM = offscreen,console 執行時就不會報錯。

08. $(shell command -v ls)

執行 command 查詢 ls 指令。

09. awk, mawk, gawk 三個是不同的程式

awk 'match($$0, pattern, array) 是錯的,因為這是 gawk 才有的語法,awk 有 match 但不能將 pattern 裡面抓到的 group 資訊存到 array。

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。

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