久しぶりにChisel-Bootcampネタ。 前回のChisel-Bootcampの学習ではジェネリクス型について学んだ。
今回はModule3.6の残りの部分を見ていく。ただエラーが出たりするので、そのへんは追って調査する事にして飛ばしていく。
型クラスと使うジェネリクス
ここではMAC演算を行うモジュールを例に進めていくようだ。
そのまま引用したほうが良さそうなのでBootcampの文をペタリ。
以下にMACの例題を示す。これは
FixedPoint
、SInt
やdsptools
が提供するDspComplex[T]
向けにさえも生成可能なMACとなっている。dsptools
が型クラスを用いているため、型境界の文法が異なっている。これについてはこのBootcampの範囲を超えるので、型クラスの使用に関して情報が必要ならdsptools
のREADMEを参照してほしい。
以下のMac
の型パラメータ部分の表記[T <: Data : Ring]
はT
はData
かRing
のサブタイプであることを意味する。要はData
かRing
を継承して作られた型であればOKということだ。
Ring
はdsptools
で提供される型の一種となるとのこと。
import chisel3.experimental._ import dsptools.numbers._ class Mac[T <: Data : Ring](genIn : T, genOut: T) extends Module { val io = IO(new Bundle { val a = Input(genIn.cloneType) val b = Input(genIn.cloneType) val c = Input(genIn.cloneType) val out = Output(genOut.cloneType) }) io.out := io.a * io.b + io.c } println(getVerilog(new Mac(UInt(4.W), UInt(6.W)) )) println(getVerilog(new Mac(SInt(4.W), SInt(6.W)) )) println(getVerilog(new Mac(FixedPoint(4.W, 3.BP), FixedPoint(6.W, 4.BP))))
ここで大事なのは”型クラス”を使っている、ということ。これを使ってMac
を構成しておくことでインスタンスの生成時にMac
の入出力のデータ型を変更できるようにしている。
- 実行結果
上記のソースコードのnew Mac
で生成された3つともがエラボレートに成功し、RTLが出力されている。
またそれぞれのケースにおいて、内部の計算がUInt
/SInt
/FixedPoint
に対応したものになっていることもわかるかと思う。
[info] [0.001] Elaborating design... [info] [0.639] Done elaborating. Total FIRRTL Compile Time: 229.9 ms module cmd2HelperMac( // @[:@3.2] input clock, // @[:@4.4] input reset, // @[:@5.4] input [3:0] io_a, // @[:@6.4] input [3:0] io_b, // @[:@6.4] input [3:0] io_c, // @[:@6.4] output [5:0] io_out // @[:@6.4] ); wire [7:0] _T_13; // @[UIntTypeClass.scala 39:41:@8.4] wire [7:0] _GEN_0; // @[UIntTypeClass.scala 18:40:@9.4] wire [8:0] _T_14; // @[UIntTypeClass.scala 18:40:@9.4] wire [7:0] _T_15; // @[UIntTypeClass.scala 18:40:@10.4] assign _T_13 = io_a * io_b; // @[UIntTypeClass.scala 39:41:@8.4] assign _GEN_0 = {{4'd0}, io_c}; // @[UIntTypeClass.scala 18:40:@9.4] assign _T_14 = _T_13 + _GEN_0; // @[UIntTypeClass.scala 18:40:@9.4] assign _T_15 = _T_14[7:0]; // @[UIntTypeClass.scala 18:40:@10.4] assign io_out = _T_15[5:0]; endmodule [info] [0.000] Elaborating design... [info] [0.016] Done elaborating. Total FIRRTL Compile Time: 21.4 ms module cmd2HelperMac( // @[:@3.2] input clock, // @[:@4.4] input reset, // @[:@5.4] input [3:0] io_a, // @[:@6.4] input [3:0] io_b, // @[:@6.4] input [3:0] io_c, // @[:@6.4] output [5:0] io_out // @[:@6.4] ); wire [7:0] _T_13; // @[SIntTypeClass.scala 44:41:@8.4] wire [7:0] _GEN_0; // @[SIntTypeClass.scala 18:40:@9.4] wire [8:0] _T_14; // @[SIntTypeClass.scala 18:40:@9.4] wire [7:0] _T_15; // @[SIntTypeClass.scala 18:40:@10.4] wire [7:0] _T_16; // @[SIntTypeClass.scala 18:40:@11.4] wire [5:0] _GEN_1; assign _T_13 = $signed(io_a) * $signed(io_b); // @[SIntTypeClass.scala 44:41:@8.4] assign _GEN_0 = {{4{io_c[3]}},io_c}; // @[SIntTypeClass.scala 18:40:@9.4] assign _T_14 = $signed(_T_13) + $signed(_GEN_0); // @[SIntTypeClass.scala 18:40:@9.4] assign _T_15 = _T_14[7:0]; // @[SIntTypeClass.scala 18:40:@10.4] assign _T_16 = $signed(_T_15); // @[SIntTypeClass.scala 18:40:@11.4] assign _GEN_1 = _T_16[5:0]; assign io_out = $signed(_GEN_1); endmodule [info] [0.000] Elaborating design... [info] [0.023] Done elaborating. Total FIRRTL Compile Time: 19.4 ms module cmd2HelperMac( // @[:@3.2] input clock, // @[:@4.4] input reset, // @[:@5.4] input [3:0] io_a, // @[:@6.4] input [3:0] io_b, // @[:@6.4] input [3:0] io_c, // @[:@6.4] output [5:0] io_out // @[:@6.4] ); wire [7:0] _T_13; // @[FixedPointTypeClass.scala 43:59:@8.4] wire [6:0] _GEN_0; // @[FixedPointTypeClass.scala 21:58:@9.4] wire [6:0] _GEN_1; // @[FixedPointTypeClass.scala 21:58:@9.4] wire [7:0] _GEN_2; // @[FixedPointTypeClass.scala 21:58:@9.4] wire [8:0] _T_14; // @[FixedPointTypeClass.scala 21:58:@9.4] wire [7:0] _T_15; // @[FixedPointTypeClass.scala 21:58:@10.4] wire [7:0] _T_16; // @[FixedPointTypeClass.scala 21:58:@11.4] assign _T_13 = $signed(io_a) * $signed(io_b); // @[FixedPointTypeClass.scala 43:59:@8.4] assign _GEN_0 = {{3{io_c[3]}},io_c}; // @[FixedPointTypeClass.scala 21:58:@9.4] assign _GEN_1 = $signed(_GEN_0) << 3; // @[FixedPointTypeClass.scala 21:58:@9.4] assign _GEN_2 = {{1{_GEN_1[6]}},_GEN_1}; // @[FixedPointTypeClass.scala 21:58:@9.4] assign _T_14 = $signed(_T_13) + $signed(_GEN_2); // @[FixedPointTypeClass.scala 21:58:@9.4] assign _T_15 = _T_14[7:0]; // @[FixedPointTypeClass.scala 21:58:@10.4] assign _T_16 = $signed(_T_15); // @[FixedPointTypeClass.scala 21:58:@11.4] assign io_out = _T_16[7:2]; endmodule
演習:MACオブジェクト
問題文は以下の通り。
Macモジュールは少ない幾つかの入力と唯一の出力を持っている。Chiselでコードを書く際には
val out = Mac(a, b, c)
のように書けたほうが便利なはずだ。以下のMac
モジュールが正しく機能するようにMac
のコンパニオン・オブジェクトのメソッドapply
を実装しよう
object Mac { def apply[T <: Data : Ring](a: T, b: T, c: T): T = { ??? // ここを実装する } } class MacTestModule extends Module { val io = IO(new Bundle { val uin = Input(UInt(4.W)) val uout = Output(UInt()) val sin = Input(SInt(4.W)) val sout = Output(SInt()) //val fin = Input(FixedPoint(16.W, 12.BP)) //val fout = Output(FixedPoint()) }) // for each IO pair, do out = in * in + in io.uout := Mac(io.uin, io.uin, io.uin) io.sout := Mac(io.sin, io.sin, io.sin) //io.fout := Mac(io.fin, io.fin, io.fin) } println(getVerilog(new MacTestModule))
ただ、この問題、、、もはや答えを載せるまでも無いよね、、、ということで答えは割愛。だってMAC演算書けば良いんだもの。普通に書けばエラボレートが通ってRTLが生成される。
演習??:積分器
問題文は以下。
次の画像のような積分器を設計しよう。
genReg
のビット幅はn1で、genIn
のビット幅はn2となる。
Reg
/RegInit
/RegNext
/RegEnable
などをT <: Data
の型のテンプレートとするのを忘れないようにしよう
、、、ということなんですが、これどうみても答えがそのまま載ってるんだよなー。。。。
class Integrator[T <: Data : Ring](genIn: T, genReg: T) extends Module { val io = IO(new Bundle { val in = Input(genIn.cloneType) val out = Output(genReg.cloneType) }) val reg = RegInit(genReg, Ring[T].zero) // init to zero reg := reg + io.in io.out := reg } class IntegratorSIntTester(c: Integrator[SInt]) extends PeekPokeTester(c) { poke(c.io.in, 3) expect(c.io.out, 0) step(1) poke(c.io.in, -4) expect(c.io.out, 3) step(1) poke(c.io.in, 6) expect(c.io.out, -1) step(1) expect(c.io.out, 5) } chisel3.iotesters.Driver(() => new Integrator(SInt(4.W), SInt(8.W))) { c => new IntegratorSIntTester(c) } ```` ということでそのまま載せちゃう。 ポイントは問題文にもあるとおりで、`Integrator`内部で使用する各種HW素子の型を`genReg`/`genIn`から引き継ぐようにすること、、くらいかな。 イマイチ`Ring`が理解できてないので、これは追って使うときに調べてみよう。 因みに、これをChiselのデータ型にしたものみたい。 [https://ja.wikipedia.org/wiki/%E7%92%B0_(%E6%95%B0%E5%AD%A6):embed:cite] Module3.6はこの後に”独自の型を作る”というのが続いているのだが、手元の環境で例題を動かすとヌルポインタ例外が起きて動かないので飛ばすことにした。多分後で`dsptools`を使うことになると思うのでその時にここのサンプルコードについても調査を行おうと思う。 ということでこれでModule3.6もお終い。