各種好用的 SystemVerilog 語法 (07) - local variable

Share on:

本文內容採用創用 CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款授權.

在所有的程式語言中,都會強調說區域變數 (local variable) 就該藏的好好的,不該在 global 被看到,不然 code 會很難讀。Verilog 的語法特性卻會傾向把變數都放在 global,本文將會討論如何解決。

舉例而言,我們在實做一個基本的 adder tree:

1typedef logic [31:0] value_t;
2value_t vin [4];
3value_t vout;
4value_t vtmp [2];
5always_comb begin
6   vtmp[0] = vin[0] + vin[1];
7   vtmp[1] = vin[2] + vin[3];
8   vout = vtmp[0] + vtmp[1];
9end

其中,大多數的情形下 vtmp 不會被其他的 code 用到,但是對於複雜的 code,讀者往往無法快速判斷這個變數會不會有其他人用到,會需要往上往下搜尋幾次,浪費時間。

一個常見的解法是用 function 或是 module 包起來:

 1function value_t AdderTree;
 2   input value_t vin [4];
 3   value_t vtmp [2];
 4begin
 5   vtmp[0] = vin[0] + vin[1];
 6   vtmp[1] = vin[2] + vin[3];
 7   AdderTree = vtmp[0] + vtmp[1];
 8end endfunction
 9
10value_t vin [4];
11value_t vout;
12assign vout = AdderTree(vin);

這樣做有一個缺點是 Verilog 的 function 功能其實限制很多,例如只可以 return 一個值。此外要打的字也很多,如果是 module 的話就更難打了,另外,做成 function 的話 waveform 就不會 dump 中間的暫時變數,雖然優點是加速模擬,但是這有時候不是我們希望發生的。

一個相當簡單的解法是用一個 named block 把不想洩漏的變數藏起來,就只要用跟著冒號的 begin end 包起來就好(end 後面不一定要打,但是會稍微提昇可讀性)。

 1typedef logic [31:0] value_t;
 2value_t vin [4];
 3value_t vout;
 4
 5begin : adder_tree
 6value_t vtmp [2];
 7always_comb begin
 8   vtmp[0] = vin[0] + vin[1];
 9   vtmp[1] = vin[2] + vin[3];
10   vout = vtmp[0] + vtmp[1];
11end
12end : adder_tree

根據測試這在 EDA tool 是可以 nested 的,甚至第二層可以用一樣的名字不會衝突,以下程式在 Verilator 下面也可以成功。

 1typedef logic [31:0] value_t;
 2value_t vin [4];
 3value_t vout;
 4
 5begin : adder_tree
 6begin : adder_tree
 7value_t vtmp [2];
 8always_comb begin
 9   vtmp[0] = vin[0] + vin[1];
10   vtmp[1] = vin[2] + vin[3];
11   vout = vtmp[0] + vtmp[1];
12end
13end : adder_tree
14end : adder_tree