各種好用的 SystemVerilog 語法 (066) - typedef (union)

Share on:

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

前面說明了 SystemVerilog typedef 在整數、structenum都能大幅簡化 verilog 程式碼,進一步降低 code 出錯的可能性,這邊再講最後一個 enum 的用法。

繼續使用 MIPS instruction 當作例子,展示 SystemVerilog 提供的 struct 功能

仔細分析他的排法,可以發現除了 opcode 之外,剩下的 26-bit 代表的意義有三種可能性(這邊為了節省版面就 hardcode bit 數了)。

1typedef struct packed {
2   logic [5:0] opcode;
3   // remaining 26 bits
4} MipsInstructionType;

那麼,這邊的 26-bit 資料要怎麼寫呢?首先,i-type, r-type 都是另外的一個 struct,需要另外實做兩個 MipsNonOpcodeRtype 以及 MipsNonOpcodeItype

最後,j-type 單一整數就不用特別處理,把這兩個 struct 跟 26-bit 的整數包成一個 union

 1typedef struct packed {
 2   logic [4:0] rs;
 3   logic [4:0] rt;
 4   logic [4:0] rd;
 5   logic [4:0] shamt;
 6   logic [5:0] funct;
 7} MipsNonOpcodeRtype;
 8
 9typedef struct packed {
10   logic [4:0] rs;
11   logic [4:0] rt;
12   logic [15:0] immediate;
13} MipsNonOpcodeItype;
14
15typedef union packed {
16   MipsNonOpcodeItype rtype;
17   MipsNonOpcodeItype itype;
18   logic [25:0] jtype_address;
19} MipsNonOpcode;
 1typedef struct packed {
 2   logic [5:0] opcode;
 3   MipsNonOpcode non_opcode;
 4} MipsInstructionType;
 5
 6MipsInstructionType inst;
 7always_comb begin
 8   inst = 32'h89abcdef;
 9   if (inst.opcode == /*Some i-type code*/) begin
10      inst.itype.immediate = ...;
11   end else if (inst.opcode == /*Some j-type code*/) begin
12      inst.jtype_address = ...;
13   end
14end

可以看到,只要 union 定義好,所有的 decode 馬上完成,所有 field 都可以用 c-style 的方式 access,大大減少了出錯的風險。

雖然 union 使用上很精簡,但是我的經驗上,如果 union 的結構有好幾層,其實不是很好 trace,struct/union 的命名也會很混亂(命名很難想,像是 NonOpcode 是什麼爛名字)。我也試過上面雖然可以把 immediate 也用 union 實做,當下就覺得可讀性就已經有點差了,因此建議使用到 union 的時候不要太深,或是要仔細斟酌一下 code 真的有變好讀嗎。

舉例而言,可能有人覺得,如果把 j-type 包裝成只有一個 member 的 struct,寫法會比較對稱,但是我覺得真的很囉唆。

 1typedef struct packed {
 2   logic [25:0] address;
 3} MipsNonOpcodeJtype;
 4
 5typedef union packed {
 6   MipsNonOpcodeRtype rtype;
 7   MipsNonOpcodeItype itype;
 8   MipsNonOpcodeJtype jtype;
 9} MipsNonOpcode;
10
11assign inst.jtype.address = ...;