Chiselでトレイトを使って機能を拡張する話、関数の追加やポート幅の拡張などの方法は分かったが、ポートを増やすためにはどのようにすれば良いのだろうか。
いろいろ調べていると、MultiIOModuleという機能が使えそうであった。
MultiIOModuleのサンプルを見ると、モジュールに対してトレイトでI/Oを追加したり、機能を追加することができるように見える。 この手法について調査した。
ベースとなるモジュール
ベースとなるモジュールは以下だ。派生元がModuleクラスではなく、MultiIOModuleであることに注意。
in_A
とin_B
から受け取った値を、ハッシュ値を計算してhashに出力する単純な機能だ。
abstract class MultiIOTest extends MultiIOModule { def Width: Int = 32 def HashWidth: Int = 32 val in_A = IO(Input(SInt(Width.W))) val in_B = IO(Input(SInt(Width.W))) val hash = IO(Output(UInt(HashWidth.W))) hash := (in_A.asUInt ^ in_B.asUInt)(HashWidth-1, 0) }
ここで、幾つかのトレイトを定義する。ここでは、64bitのポートと16bitのポートを追加するトレイトだ。ポート名はval_out
と言う。
trait AddMultiIOTrait extends MultiIOModule { def OutWidth: Int = 64 val val_out = IO(Output(UInt(OutWidth.W))) val_out := 0.U } trait SubMultiIOTrait extends MultiIOModule { def OutWidth: Int = 16 val val_out = IO(Output(UInt(OutWidth.W))) val_out := 1.U }
では、このトレイトを接続する鵜。ベースとなるMultiIOTest
モジュールに対して、トレイトとしてAddMultiIOTrait
とSubMultiIOTrait
を追加するわけだ。
class AddMultiIOTest extends MultiIOTest with AddMultiIOTrait class SubMultiIOTest extends MultiIOTest with SubMultiIOTrait
一方で、このトレイトで追加したI/Oに、ベースとなるモジュールからI/Oを接続して拡張する場合にはどうするか。 このためにはトレイトに機能を追加する方法と、モジュールに機能を追加する方法がある。
FuncMultiIOTrait
は、ポートの宣言だけを行っている。一方でFunc2MultiIOTrait
はポートの宣言と、機能の追加(in_A - in_B)の実装を行っている。
trait FuncMultiIOTrait extends MultiIOModule { def OutWidth: Int = 32 val sub_out = IO(Output(SInt(OutWidth.W))) } trait Func2MultiIOTrait extends MultiIOTest { def OutWidth: Int = 32 val sub_out = IO(Output(SInt(OutWidth.W))) sub_out := in_A - in_B }
これらは、どちらもインスタンス化できる。
class FuncMultiIOTest extends MultiIOTest with FuncMultiIOTrait { sub_out := in_A - in_B } class Func2MultiIOTest extends MultiIOTest with Func2MultiIOTrait
結果として、Func2MultiIOTest.vを見てみよう。
object MultiIOTest extends App { chisel3.Driver.execute(args, () => new AddMultiIOTest()) chisel3.Driver.execute(args, () => new SubMultiIOTest()) chisel3.Driver.execute(args, () => new FuncMultiIOTest()) chisel3.Driver.execute(args, () => new Func2MultiIOTest()) }
module Func2MultiIOTest( // @[:@3.2] input clock, // @[:@4.4] input reset, // @[:@5.4] input [31:0] in_A, // @[:@6.4] input [31:0] in_B, // @[:@7.4] output [31:0] hash, // @[:@8.4] output [31:0] sub_out // @[:@9.4] ); wire [31:0] _T_10; // @[multiio_test.scala 15:17:@11.4] wire [31:0] _T_11; // @[multiio_test.scala 15:31:@12.4] wire [32:0] _T_16; // @[multiio_test.scala 43:19:@16.4] wire [31:0] _T_17; // @[multiio_test.scala 43:19:@17.4] assign _T_10 = $unsigned(in_A); // @[multiio_test.scala 15:17:@11.4] assign _T_11 = $unsigned(in_B); // @[multiio_test.scala 15:31:@12.4] assign _T_16 = $signed(in_A) - $signed(in_B); // @[multiio_test.scala 43:19:@16.4] assign _T_17 = $signed(in_A) - $signed(in_B); // @[multiio_test.scala 43:19:@17.4] assign hash = _T_10 ^ _T_11; // @[multiio_test.scala 15:8:@15.4] assign sub_out = $signed(_T_17); // @[multiio_test.scala 43:11:@19.4] endmodule
Verilogが正しく生成できている!