日曜技術者のメモ

趣味でやった事のメモ書きです。

SystemVerilogのパラメータ付きクラスを試してみた(解決編)

SystemVerilogのパラメータ付きクラスを試してみたを更新してから
Twitterで「Baseクラス作ったらpushできる」と教えて頂き解決しました。

修正したコード

module top();

class c_hoge_base; //Baseクラス追加
  
  virtual function void print(); 
  endfunction
  
endclass

//Baseクラス継承
class c_hoge #(int k = 0) extends c_hoge_base; 

  function void print(); //Warning対策にvoidを追加
    $display("k = %d",k);
  endfunction
  
endclass:c_hoge

//型をBaseクラスにする
c_hoge_base q_c_hoge[$];
c_hoge_base h_c_hoge[*];
c_hoge_base i_c_hoge_base;

initial begin
  c_hoge#(0) i0_c_hoge;
  c_hoge#(1) i1_c_hoge;
  c_hoge#(2) i2_c_hoge;
  c_hoge#(3) i3_c_hoge;
  
  i0_c_hoge = new();
  i1_c_hoge = new();
  i2_c_hoge = new();
  i3_c_hoge = new();
  
  i0_c_hoge.print();
  i1_c_hoge.print();
  i2_c_hoge.print();
  i3_c_hoge.print();

  q_c_hoge.push_back(i0_c_hoge);
  h_c_hoge["hoge0"] = i0_c_hoge;

  q_c_hoge.push_back(i1_c_hoge);
  h_c_hoge["hoge1"] = i1_c_hoge;
  
  $display("pop_front");
  i_c_hoge_base = q_c_hoge.pop_front();
  i_c_hoge_base.print();
  i_c_hoge_base = q_c_hoge.pop_front();
  i_c_hoge_base.print();

  $display("hash table");
  h_c_hoge["hoge0"].print();
  
end
endmodule

実行結果

# k =           0
# k =           1
# k =           2
# k =           3
# pop_front
# k =           0
# k =           1
# hash table
# k =           0

これでパラメータ付きクラスでもキューや連想配列に入れる事が出来ました。
後、newの引数でいいじゃんというツッコミも頂いたので私の使用例を載せました。

このコードでやりたい事は

  • モジュールtest_modelをgenerateで複数インスタンス
  • test_model内にはtaskが宣言されていてこれをクラスから参照したい。
  • writeタスクは手が入れれないのでパス指定で呼び出すしかない。(writeタスクをクラスに移動できるならこんな事しなくても大丈夫ですが・・・)
  • できるだけループ宣言を使って記述を減らしたい(ただしこの例では減らせませんでした^^;

後、enum連想配列使ってクラス配列を任意の文字列で呼び出すのが
どのモデルにつながっているか見わかりやすくて好きなので使っています。

typedef enum {
  test_model_A,
  test_model_B,
  test_model_C,
  test_model_D,
  test_model_E
} e_model_name;

parameter MODEL_NUM = 5;

/*************test_module**************/
/*変更できないモデル*/
module test_model();
  task write(int a);
    $display("test_model write task %d",a);
  endtask
  
endmodule : test_model

/***************prg_top*****************/

module prg_top();
  class piyo_base;
    virtual task start();
    endtask
    
    virtual task exec();
    endtask
  endclass
  
  class piyo#(e_model_name k = test_model_A) extends piyo_base;
    int m_val;
    e_model_name m_e_model_name;
    
    function new(int val);
      m_val = val;
      m_e_model_name = k;
    endfunction
    
    task start();
      $display("start : This Class %s , m_val = %0d",m_e_model_name,m_val);
    endtask
    
    task exec();
      $display("exec : This Class %s , m_val = %0d",m_e_model_name,m_val);
      $root.top.model_loop[k].i_test_model.write(m_val);//ここのkはパラメータでないとダメ(変数は使えない)
    endtask
    
  endclass
  
  piyo_base piyo_h_array[e_model_name];
  
  piyo#(test_model_A) i_piyo0;
  piyo#(test_model_B) i_piyo1;
  piyo#(test_model_C) i_piyo2;
  piyo#(test_model_D) i_piyo3;
  piyo#(test_model_E) i_piyo4;        

  initial begin
    i_piyo0 = new(10);
    i_piyo1 = new(20);
    i_piyo2 = new(30);
    i_piyo3 = new(40);
    i_piyo4 = new(50);    

    piyo_h_array[test_model_A] = i_piyo0;
    piyo_h_array[test_model_B] = i_piyo1;
    piyo_h_array[test_model_C] = i_piyo2;
    piyo_h_array[test_model_D] = i_piyo3;
    piyo_h_array[test_model_E] = i_piyo4;    

    $display("\n-----start task-----");
    foreach (piyo_h_array[i]) begin
      piyo_h_array[i].start;
    end
    
    $display("\n-----exec task-----");
    piyo_h_array[test_model_B].exec;
    piyo_h_array[test_model_C].exec;
    
    $finish;
  end
  
endmodule:prg_top
    
/***************top*****************/

module top();
  generate
    genvar i;
    for(i=0; i<MODEL_NUM;i=i+1)begin : model_loop
      test_model i_test_model();
    end
  endgenerate
  
  prg_top i_prg_top();
endmodule : top

実行結果

# 
# -----start task-----
# start : This Class test_model_A , m_val = 10
# start : This Class test_model_B , m_val = 20
# start : This Class test_model_C , m_val = 30
# start : This Class test_model_D , m_val = 40
# start : This Class test_model_E , m_val = 50
# 
# -----exec task-----
# exec : This Class test_model_B , m_val = 20
# test_model write task          20
# exec : This Class test_model_C , m_val = 30
# test_model write task          30
# ** Note: $finish    : E:/altera/13.0/test/test2.sv(81)


i_piyo0~i_piyo4までの宣言をループ内に入れる事が出来ればもっと
コードが短くなると思いますがやり方が思いつきませんでした。

そもそもこんなやり方しなくてももっと良い方法があるかも・・・

7/4追記:

コメントで指摘してもらったdefineマクロで
i_piyo0~i_piyo4が簡潔にならないか試してみました。

//マクロ定義
`define PIYO_INSTANCE(val) piyo#(val``) i_piyo``val``;
`define PIYO_SET(val,init) i_piyo``val`` = new(init``); \
                           piyo_h_array[``val``] = i_piyo``val``;

//宣言(一部抜粋)
  `PIYO_INSTANCE(0) //piyo#(test_model_A) i_piyo0;
  `PIYO_INSTANCE(1) //piyo#(test_model_B) i_piyo1;
  `PIYO_INSTANCE(2) //piyo#(test_model_C) i_piyo2;
  `PIYO_INSTANCE(3) //piyo#(test_model_D) i_piyo3;
  `PIYO_INSTANCE(4) //piyo#(test_model_E) i_piyo4;

  initial begin

    `PIYO_SET(0,10)  //i_piyo0 = new(10); piyo_h_array[test_model_A] = i_piyo0;
    `PIYO_SET(1,20)  //i_piyo1 = new(20); piyo_h_array[test_model_B] = i_piyo1;
    `PIYO_SET(2,30)  //i_piyo2 = new(30); piyo_h_array[test_model_C] = i_piyo2;
    `PIYO_SET(3,40)  //i_piyo3 = new(40); piyo_h_array[test_model_D] = i_piyo3;
    `PIYO_SET(4,50)  //i_piyo4 = new(50); piyo_h_array[test_model_E] = i_piyo4;
	

ちょっと記述は少なくなったかな?
本当は↓の様にループで書ければ良かったのだが残念ながらエラーになりました。

  generate
    genvar j;
    for(j=0; j<MODEL_NUM;j=j+1)begin : model_loop
      `PIYO_INSTANCE(j)
    end
  endgenerate