FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

ChiselでMapやReduceを使ったいくつかのハードウェア記述Tips

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

ChiselはScalaをベースとしたハードウェア記述言語なので、Verilog-HDLではあまり見かけることのない記述ができる。

最近使っているChiselの便利な技法のいくつかをまとめてみる。

  • Vecの中身を.reducを使ってリダクションする

Vecにはreductionなどの記法が用意されている。具体的には、あまり説明のないAPI一覧の資料を見てほしいのだが、

https://chisel.eecs.berkeley.edu/api/3.1.0/chisel3/core/Vec.htmlchisel.eecs.berkeley.edu

例えば、こんな感じで書く。

class map_test(WIDTH: Int = 32) extends Module {
  val io = IO(new Bundle {
    val in_val  = Input (Vec(WIDTH, UInt(16.W)))
    val reduc   = Output(UInt(16.W))
  })

  io.reduc   := io.in_val.reduce(_ +& _)
}

入力信号の16bit×WIDTHのベクトル形式の信号を受け取り、それらのすべての要素を加算(+&はビット拡張を行いながら加算する)してその結果を返す。 これは+&以外でも、論理演算などでも使える。 reduce(_ | _)など。

  • Vecの内容すべてに処理を適用するための.map

Mapを使うと、すべての要素に処理を適用できる。例えば、以下はWIDTH長のベクトル入力に対してすべてNOT演算を適用する。

class map_test(WIDTH: Int = 32) extends Module {
  val io = IO(new Bundle {
    val in_bool = Input (Vec(WIDTH, Bool()))
    val not_out = Output(Vec(WIDTH, Bool()))
  })
  io.not_out := io.in_bool.map(x => ~x)
}

in_boolのすべてのベクトルに対して、NOT演算を適用してその結果をio.not_outに渡している。

  • Mapでベクトルの要素を取り出して、さらにReducする

.mapは上記のような処理の適用だけでなく、ベクトル内の要素の取り出しにも使える。例えば、以下はValidIO信号の中のbits要素(ValidIOvalidbitsの2種類から構成されているデータ型である)を取り出して、それらをすべてのベクトルに対してreducする。

class map_test(WIDTH: Int = 32) extends Module {
  val io = IO(new Bundle {
    val in_validio  = Input(Vec(WIDTH, ValidIO(UInt(16.W))))
    val out_validio = Output(UInt(16.W))
  })
  io.out_validio := io.in_validio.map(x => x.bits).reduce(_ +& _)
}

mapにより要素の取り出しを行い、その結果に対してreducを適用した。

このように、簡単な処理であればVerilog-HDLのようにfor文を使わずに処理を実現できる。