ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

Chiselで設計したハードウェアをVerilogのRTLに変換する流れのまとめ

スポンサーリンク

前回のChiselの記事ではBundleを使ってオプションのIOポートをまとめて制御する方法を紹介した。

www.tech-diningyo.info

最近Chisel周りの調査をいろいろやっているが、ChiselのコードをVerilogのRTLに変換する方法についてを簡単にまとめた日本語の記事が見当たらない気がしたので今更感はあるがまとめておこうと思う。

ChiselのハードウェアデザインからVerilogのRTLを生成する方法

stack overflowにまとめてくれているものがあったので、一応こいつも貼っておく。

stackoverflow.com

変換するChiselのコードが書かれたファイル

ものすごく単純な加算器を用意した。これをTop.scalaというファイル名で保存する。

import chisel3._

class Top(in0Bits: Int, in1Bits: Int) extends Module {
  val io = IO(new Bundle {
    val in0 = Input(UInt(in0Bits.W))
    val in1 = Input(UInt(in0Bits.W))
    val out = Output(UInt((in0Bits+1).W))
  })

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

object Elaborate extends App {
  chisel3.Driver.execute(args, () => new Top(32, 32))
}

上記はChisel→Verilog RTLを生成する上で必要な処理が全て書かれたものになっている。

build.sbtの準備

あとはChiselが動作する環境があれば何でも良い。でも一番手っ取り早いのはsbtを使うことだと思う。 sbtをインストールして動作する環境を準備したあとに以下のような"build.sbt"を作成しよう。

scalaVersion := "2.11.8"

resolvers ++= Seq(
  Resolver.sonatypeRepo("snapshots"),
  Resolver.sonatypeRepo("releases")
)

libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.0-SNAPSHOT"

ディレクトリ構造

sbtを使用する場合は、標準のディレクトリ構成が存在しているため最初はそれに従うのが吉。 とりあえず今回RTLを生成するために必要な構成は以下の様なもの。

diningyo@diningyo-pc:/home/diningyo/workspace/make_rtl$ tree
.
├── build.sbt
└── src
    └── main
        └── scala
            └── Top.scala

sbtを実行してRTLを生成

ここまで来たら、あとはsbtを使って実行をするだけ。

$ sbt "run"

正常に流れると初回実行時なら依存関係のライブラリのダウンロードをsbtが行った後に、Top.scalaに書いてある以下のコードをsbtが検出して実行してくれる。

object Elaborate extends App {
  chisel3.Driver.execute(args, () => new Top(32, 32, true))
}

Chiselのコードにエラーが無ければエラボレートが正常に終了してbuild.sbtと同じディレクトリに以下の3つのファイルが生成されるはずだ。

.
├── Top.anno
├── Top.fir
├── Top.v    : 生成されたVerilogのRTL
  • Top.v
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif

module Top(
  input         clock,
  input         reset,
  input  [31:0] io_in0,
  input  [31:0] io_in1,
  output [32:0] io_out
);
  wire [32:0] _T_5;
  wire [31:0] _T_6;
  assign _T_5 = io_in0 + io_in1;
  assign _T_6 = _T_5[31:0];
  assign io_out = {{1'd0}, _T_6};
endmodule

まとめ

ここまでのことをすごくまとめて書くと、以下の4ステップ。

  1. Chiselが実行できる環境を整える(sbt使うのが楽)
  2. Chiselで所望のデザインを設計
  3. メイン関数を生成(上記の例ではextends Appを使って作ってます)して 1. RTLを生成したいChiselデザインをchisel3.Driver.executeに流す
  4. sbt "run"で実行するとchisel3.Driver.executeがよしなにやってくれる

興味があれば、是非トライしてみて頂きたい!
いずれもう少し掘り下げた記事も書けるいいな。