FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

Chiselでfor文を用いた同一モジュールの複数インスタンス化の方法

Verilogでは、同一モジュールを複数インスタンスするときは以下のようにgenerate forが使える。

for (genvar i=1; i<=10; i=i+1) begin 
  subblock u_subblock(
        .clk(clk),
        .reset_n(reset_n),
        .a(a[i]),
        .b(b[i]),
        .out(out[i])
    );
end

これと同様に、Chiselでもfor文を用いた同一モジュールの複数インスタンス化が行える。書き方は単純だ。

class multi_module (width: Int) extends Module()
{
  val io = IO(new Bundle {
    val in0  = Input(Vec(width, UInt(32.W)))
    val in1  = Input(Vec(width, UInt(32.W)))
    val out = Output(Vec(width, UInt(32.W)))
  })

  val sub_modules = for (w <- 0 until width) yield {
    val d = Module (new sub_module)
    d
  }

  sub_modules.zipWithIndex.map { case (sub, i) =>
    sub.io.in0 := io.in0(i)
    sub.io.in1 := io.in0(i)
    io.out(i) := sub.io.out
  }
}

大きく分けて2種類の手法を示した。一つはfor文を用いてモジュールそのものをインスタンス化する。ここでは、multi_moduleモジュールの中でsub_moduleを複数回インスタンスしている。 インスタンスする個数はパラメータwidthに依存している。 このとき、sub_modulesがその複数のモジュールを配列の形式として格納している。

サブモジュールを操作するにあたり、同様にfor文で回しても良いのだが、それ以外にmapを使った方法が取れる。 sub_modules.zipWithIndex.mapでは、sub_modulesに格納されている複数のモジュールを、zipWithIndexで0から番号のついたペアに変換し、それぞれに対してmapを行う。

  • sub_modules : {sub_modules(0), sub_modules(1), sub_modules(2), sub_modules(3), ...}
  • sub_modules.zipWithIndex : {{sub_modules(0), 0}, {sub_modules(1), 1}, {sub_modules(2), 2}, {sub_modules(3), 3}, ...}

それぞれに対して、入出力ポートを接続する記述をしている。 これで、生成されるVerilogは以下のようになった。

  wire [31:0] sub_modules_4_io_in1; // @[multi_module.scala 15:20:@65.4]
  wire [31:0] sub_modules_4_io_out; // @[multi_module.scala 15:20:@65.4]
  sub_module sub_modules_0 ( // @[multi_module.scala 15:20:@53.4]
    .io_in0(sub_modules_0_io_in0),
    .io_in1(sub_modules_0_io_in1),
    .io_out(sub_modules_0_io_out)
  );
  sub_module sub_modules_1 ( // @[multi_module.scala 15:20:@56.4]
    .io_in0(sub_modules_1_io_in0),
    .io_in1(sub_modules_1_io_in1),
    .io_out(sub_modules_1_io_out)
  );
  sub_module sub_modules_2 ( // @[multi_module.scala 15:20:@59.4]
    .io_in0(sub_modules_2_io_in0),
    .io_in1(sub_modules_2_io_in1),
    .io_out(sub_modules_2_io_out)
  );
...
  assign io_out_0 = sub_modules_0_io_out; // @[multi_module.scala 22:15:@70.4]
...
  assign io_out_4 = sub_modules_4_io_out; // @[multi_module.scala 22:15:@82.4]
  assign sub_modules_0_io_in0 = io_in0_0; // @[multi_module.scala 20:16:@68.4]
...
  assign sub_modules_2_io_in0 = io_in0_2; // @[multi_module.scala 20:16:@74.4]
  assign sub_modules_2_io_in1 = io_in0_2; // @[multi_module.scala 21:16:@75.4]
  assign sub_modules_3_io_in0 = io_in0_3; // @[multi_module.scala 20:16:@77.4]
...
  assign sub_modules_4_io_in1 = io_in0_4; // @[multi_module.scala 21:16:@81.4]
f:id:msyksphinz:20190719002040p:plain
モジュールのインスタンスイメージ