[SystemVerilog] 階層名のつけられ方(Class編)

今回はclass内の階層名についてです。筆者が調べた限り、LRMにはclass内の階層名についての明確な定義はありませんでした。従ってシミュレータ依存の動作となります。

classの階層名については、通常は意識する必要はありません。ただ以前に、cover()関連で少し疑問に思ったことがあり、それが理由で動作を調べようと思い立ちました。以下のようにclass内のテストシナリオの中にcover(1)を挿入し、そのシナリオが実行されたことのチェックポイントとして使用した時です。

```verilog
task some_test()
  do_some_test;
  cv:cover(1);
endtask
```

この時のcoverpointの名前cvはフルパス名で表示されるので、そのの命名ルールがテスト結果のメトリクスを収集、解析する為に必要でです。

```
"testbench.sv", 6: $unit::\TestClass::displayHierarchy .cv, 1 attempts, 1 total match, 1 first match
```

今回はclass中で$display("%m")で表示されるパス名と、cover()のレポートのパス名がどうなるかをVCS P-2019.06-1で調べました。動作確認したコードを記載しますので、他のシミュレータの結果は各自ご確認ください。

なお、module内での階層名はインスタンスベースでしたが、classの場合はタイプベースになります。classインスタンスはシミュレーション中に動的に生成、消去されるため、moduleのように静的な階層構造を持たないためです。

# 基本
基本的な、class内での結果です。

```verilog
`define DISPLAY_HIER $display("time = %02t, line = %03d, hierarchy = %m", $time, `__LINE__)

class TestClass;
  virtual function void displayHierarchy();
    `DISPLAY_HIER;
    cv: cover(1);
  endfunction
endclass

module topmdl();
  initial begin
    TestClass testClass;

    testClass = new();
    testClass.displayHierarchy();
  end
endmodule
```

```
Compiler version P-2019.06-1; Runtime version P-2019.06-1;  Oct 23 00:38 2020
time =  0, line = 005, hierarchy = $unit::\TestClass::displayHierarchy 
"testbench.sv", 6: $unit::\TestClass::displayHierarchy .cv, 1 attempts, 1 total match, 1 first match
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ns
```

階層名は以下で表され
`$unit::\<class名>::<function名>`

そこに位置するcover()は以下で表されるようです
`<階層名> :: .<coverpoint名>`
階層名と.の間にあるスペースが謎ですね。シミュレータのバージョンが変わるとここらへんも変わるかもしれません。


# Prameterized value Class
Parameterized classはパラメータ毎に別のクラスとして扱われるため(LRM 8.25 Parameterized classes)、階層のclass名が変わるはずです。

```verilog

`define DISPLAY_HIER $display("time = %02t, line = %03d, hierarchy = %m", $time, `__LINE__)

class ValParamClass #(parameter int P = 1);
  virtual function void displayHierarchy();
    `DISPLAY_HIER;
    cv: cover(1);
  endfunction
endclass


module topmdl();
  initial begin
    ValParamClass valParamClass1;
    ValParamClass#(.P(1)) valParamClass2;
    ValParamClass#(.P('hee)) valParamClass3;

    valParamClass1 = new();
    valParamClass2 = new();
    valParamClass3 = new();

    valParamClass1.displayHierarchy();
    valParamClass2.displayHierarchy();
    valParamClass3.displayHierarchy();
  end
endmodule
```

```
Compiler version P-2019.06-1; Runtime version P-2019.06-1;  Oct 23 01:43 2020
time =  0, line = 005, hierarchy = $unit::\ValParamClass#(1)::displayHierarchy 
time =  0, line = 005, hierarchy = $unit::\ValParamClass#(1)::displayHierarchy 
time =  0, line = 005, hierarchy = $unit::\ValParamClass#(32'sh000000ee)::displayHierarchy 
"testbench.sv", 6: vcs_paramclassrepository::\ValParamClass#(1)::displayHierarchy .cv, 2 attempts, 2 total match, 2 first match
"testbench.sv", 6: vcs_paramclassrepository::\ValParamClass#(32'sh000000ee)::displayHierarchy .cv, 1 attempts, 1 total match, 1 first match
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 n
```

クラス名は`\<class名>#(<パラメータ値>)`になるようです。パラメータ値のフォーマットにゆらぎがあります。1はそのままなのに'h33が32'sh000000eeに変換されています。


# Prameterized type class

```verilog

`define DISPLAY_HIER $display("time = %02t, line = %03d, hierarchy = %m", $time, `__LINE__)

class TypeParamClass #(parameter type T = int);
  virtual function void displayHierarchy();
    `DISPLAY_HIER;
    cv: cover(1);
  endfunction
endclass


module topmdl();
  initial begin
    TypeParamClass typeParamClass1;
    TypeParamClass#(.T(int)) typeParamClass2;
    TypeParamClass#(.T(logic[7:0])) typeParamClass3;
    TypeParamClass#(.T(string)) typeParamClass4;

    typeParamClass1 = new();
    typeParamClass2 = new();
    typeParamClass3 = new();
    typeParamClass4 = new();

    typeParamClass1.displayHierarchy();
    typeParamClass2.displayHierarchy();
    typeParamClass3.displayHierarchy();
    typeParamClass4.displayHierarchy();
  end
endmodule
```

```
Compiler version P-2019.06-1; Runtime version P-2019.06-1;  Oct 23 01:47 2020
time =  0, line = 005, hierarchy = $unit::\TypeParamClass#(int)::displayHierarchy 
time =  0, line = 005, hierarchy = $unit::\TypeParamClass#(int)::displayHierarchy 
time =  0, line = 005, hierarchy = $unit::\TypeParamClass#(logic[7:0])::displayHierarchy 
time =  0, line = 005, hierarchy = $unit::\TypeParamClass#(string)::displayHierarchy 
"testbench.sv", 6: vcs_paramclassrepository::\TypeParamClass#(int)::displayHierarchy .cv, 2 attempts, 2 total match, 2 first match
"testbench.sv", 6: vcs_paramclassrepository::\TypeParamClass#(logic[7:0])::displayHierarchy .cv, 1 attempts, 1 total match, 1 first match
"testbench.sv", 6: vcs_paramclassrepository::\TypeParamClass#(string)::displayHierarchy .cv, 1 attempts, 1 total match, 1 first match
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ns
```


class名は`\<class名>#(<type名>)`に変換されるようです。




# Nested class
classの中でローカルなクラスを定義することができます(LRM 8:23 Class scope resulution operator ::)。

```verilog

`define DISPLAY_HIER $display("time = %02t, line = %03d, hierarchy = %m", $time, `__LINE__)

class BaseClass;
  class ClassInClass;
    virtual function void displayHierarchy();
      `DISPLAY_HIER;
      cv:cover(1);
    endfunction
  endclass

  virtual function void displayHierarchy();
    ClassInClass classInClass;

    classInClass = new();
    classInClass.displayHierarchy();
  endfunction
endclass

module topmdl();
  initial begin
    BaseClass baseClass;

    baseClass = new();
    baseClass.displayHierarchy();
  end
endmodule
```

階層名は以下のようになるようです。
`$unit::\<class名>::<nested_class名>::<function名>`

```
Compiler version P-2019.06-1; Runtime version P-2019.06-1;  Oct 23 01:22 2020
time =  0, line = 006, hierarchy = $unit::\BaseClass::ClassInClass::displayHierarchy 
"testbench.sv", 7: $unit::\BaseClass::ClassInClass::displayHierarchy .cv, 1 attempts, 1 total match, 1 first match
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ns
```

# cover()の注意点
最後に注意点です。cover()をunnamed blockに入れると、その階層名はシミュレータが勝手に命名することになるので、
ソースコードの他の部分の変更によって階層名が変わってしまう可能性があります。

以下の例だと、unnamed blockの階層名は、ソースコードの上から順番に命名されていきますので、後から間に別の
unnamed blockが入ると名前がずれてしまいます。

```verilog
`define DISPLAY_HIER $display("time = %02t, line = %03d, hierarchy = %m", $time, `__LINE__)

module topmdl();
  initial begin
    begin
      int i;
      `DISPLAY_HIER;
      cv1: cover(1);
    end

    begin
      int i;
      `DISPLAY_HIER;
      cv2: cover(1);
    end

    begin:b
      int i;
      `DISPLAY_HIER;
      cv3: cover(1);
    end
  end
endmodule
```

```
Compiler version P-2019.06-1; Runtime version P-2019.06-1;  Oct 23 00:55 2020
time =  0, line = 007, hierarchy = topmdl.unnamed$$_0
time =  0, line = 013, hierarchy = topmdl.unnamed$$_1
time =  0, line = 019, hierarchy = topmdl.b
"testbench.sv", 8: topmdl.unnamed$$_0.cv1, 1 attempts, 1 total match, 1 first match
"testbench.sv", 14: topmdl.unnamed$$_1.cv2, 1 attempts, 1 total match, 1 first match
"testbench.sv", 20: topmdl.b.cv3, 1 attempts, 1 total match, 1 first match
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ns
```

cover()はunnamed blockに入れないよう注意が必要です。unnamed blockについては[こちら](https://qiita.com/triggerfish/items/81b8752b42502b787c72#unnamed-block)も参照願います。