FPGA開発日記

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

ハードウェア記述言語Chiselコンパイラの内部解析(7. FixedPoint型を使ったコードを書いてみる)

https://cdn-ak.f.st-hatena.com/images/fotolife/m/msyksphinz/20181105/20181105012126.png

Chiselの改造をするためにいくつか型を追加する試行をしたが、一つ題材として浮動小数点をサポートできる型を作ってみたい。 この練習をするために、まずはChiselで標準的にサポートされているFixedPoint型について少し触ってみることにした。

ChiselのFixedPoint型を使うためには、以下のように宣言すればよいらしい。以下は入出力ポートをFixedPoint型にした様子。

class fixedpoint_test extends Module
{
  val io = IO(new Bundle {
    val in1 = Input (FixedPoint(16.W, 12.BP))
    val in2 = Input (FixedPoint(16.W, 12.BP))
    val out = Output(FixedPoint(24.W, 16.BP))
  })

  io.out := io.in1 + io.in2
}

果たしてこれでどういうコードが出てくるかというと、

  wire [15:0] _T_12; // @[fixedpoint.scala 15:20:@9.4]
  wire [15:0] _T_13; // @[fixedpoint.scala 15:20:@10.4]
  wire [19:0] _GEN_0; // @[fixedpoint.scala 15:10:@11.4]
  wire [19:0] _GEN_1; // @[fixedpoint.scala 15:10:@11.4]
  assign _T_12 = $signed(io_in1) + $signed(io_in2); // @[fixedpoint.scala 15:20:@9.4]
  assign _T_13 = $signed(_T_12); // @[fixedpoint.scala 15:20:@10.4]
  assign _GEN_0 = {{4{_T_13[15]}},_T_13}; // @[fixedpoint.scala 15:10:@11.4]
  assign _GEN_1 = $signed(_GEN_0) << 4; // @[fixedpoint.scala 15:10:@11.4]
  assign io_out = {{4{_GEN_1[19]}},_GEN_1}; // @[fixedpoint.scala 15:10:@11.4]

つまり、仮数部が12ビット、全体が16ビットのFixedPoint同氏を加算し、それを仮数部16ビット、全体で24ビットのFixedPointの値に拡張して出力する。 こういった処理が可能である。

いろんな長さのFixedPointの値を処理することができる。 以下は仮数部をずらした場合の処理。Chisel的には全体のビット数を合わせてから処理する。

指数部4ビット、仮数部12ビットのFixedPointと、指数部4ビット、仮数部8ビットの値のFixedPointの値を加算した場合の処理。

  val io = IO(new Bundle {
    val in1 = Input (FixedPoint(16.W, 12.BP))
    val in2 = Input (FixedPoint(12.W,  8.BP))
    val out = Output(FixedPoint(16.W, 12.BP))
  })

  io.out := io.in1 + io.in2
f:id:msyksphinz:20190914174555p:plain

今度はもう少し複雑。指数部4ビット、仮数部12ビットのFixedPointと、指数部6ビット、仮数部6ビットの値を加算する。

  val io = IO(new Bundle {
    val in1 = Input (FixedPoint(16.W, 12.BP))
    val in2 = Input (FixedPoint(12.W,  6.BP))
    val out = Output(FixedPoint(18.W, 12.BP))
  })

  io.out := io.in1 + io.in2
f:id:msyksphinz:20190914175347p:plain
  wire [17:0] _GEN_0; // @[fixedpoint.scala 15:20:@8.4]
  wire [17:0] _GEN_1; // @[fixedpoint.scala 15:20:@8.4]
  wire [17:0] _GEN_2; // @[fixedpoint.scala 15:20:@8.4]
  wire [18:0] _T_11; // @[fixedpoint.scala 15:20:@8.4]
  wire [17:0] _T_12; // @[fixedpoint.scala 15:20:@9.4]
  assign _GEN_0 = {{6{io_in2[11]}},io_in2}; // @[fixedpoint.scala 15:20:@8.4]
  assign _GEN_1 = {{2{io_in1[15]}},io_in1}; // @[fixedpoint.scala 15:20:@8.4]
  assign _GEN_2 = $signed(_GEN_0) << 6; // @[fixedpoint.scala 15:20:@8.4]
  assign _T_11 = $signed(_GEN_1) + $signed(_GEN_2); // @[fixedpoint.scala 15:20:@8.4]
  assign _T_12 = $signed(_GEN_1) + $signed(_GEN_2); // @[fixedpoint.scala 15:20:@9.4]
  assign io_out = $signed(_T_12); // @[fixedpoint.scala 15:10:@11.4]