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

ハードウェア記述言語Chiselコンパイラの内部解析(4. Chiselで代入演算子がハードウェアに落ちるまで)




val io = IO(new Bundle {
  val in = Input(Bool())
  val out = Output(Bool())
io.out := io.in

この:=という代入演算子は、Scalaで定義されたものではない。Scala演算子オーバーロードを行うことができ、Chisel向けに作られた代入演算子である。 これによりChiselのハードウェアデータ型は、互いに接続することが可能になる。

Chiselのハードウェアデータ型は、UInt, SInt, Boolが定義されており、それぞれのデータはChisel内のBits.scalaに定義がある。

  • chisel3/ChiselFrontend/src/main/scala/chisel3/Bits.scala
sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[UInt] {
sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[SInt] {
sealed class Bool() extends UInt(1.W) with Reset {

要するに、UInt, SIntBitsクラスを継承しており、BoolUIntを継承している。



/** A data type for values represented by a single bitvector. This provides basic bitwise operations.
  * @groupdesc Bitwise Bitwise hardware operators
  * @define coll [[Bits]]
  * @define sumWidthInt    @note The width of the returned $coll is `width of this` + `that`.
  * @define sumWidth       @note The width of the returned $coll is `width of this` + `width of that`.
  * @define unchangedWidth @note The width of the returned $coll is unchanged, i.e., the `width of this`.
sealed abstract class Bits(private[chisel3] val width: Width) extends Element with ToBoolable { //scalastyle:off number.of.methods


  • chisel3/chiselFrontend/src/main/scala/chisel3/Data.scala
  /** Connect this $coll to that $coll mono-directionally and element-wise.
    * This uses the [[MonoConnect]] algorithm.
    * @param that the $coll to connect to
    * @group Connect
  final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) // scalastyle:ignore line.size.limit


  private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit

さらに内部をのぞいてみると、MonoConnect.connect()という関数が呼ばれている。これはつまり一方方向の接続だ。ついでに見てみると、BulkConnect.connect()という関数も存在しており、これはA <> Bのための実装だと思われる。

  • chisel3/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala
private[chisel3] object MonoConnect {
  /** This function is what recursively tries to connect a sink and source together
  * There is some cleverness in the use of internal try-catch to catch exceptions
  * during the recursive decent and then rethrow them with extra information added.
  * This gives the user a 'path' to where in the connections things went wrong.
  def connect(  //scalastyle:off cyclomatic.complexity method.length
      sourceInfo: SourceInfo,
      connectCompileOptions: CompileOptions,
      sink: Data,
      source: Data,
      context_mod: RawModule): Unit =
    (sink, source) match {
      // Handle legal element cases, note (Bool, Bool) is caught by the first two, as Bool is a UInt
      case (sink_e: Bool, source_e: UInt) =>
        elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
      case (sink_e: UInt, source_e: Bool) =>
        elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
      case (sink_e: UInt, source_e: UInt) =>


  def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Element, source: Element, context_mod: RawModule): Unit = { // scalastyle:ignore line.size.limit
    import BindingDirection.{Internal, Input, Output} // Using extensively so import these
    // CASE: Context is same module that both left node and right node are in
    if( (context_mod == sink_mod) && (context_mod == source_mod) ) {
      ((sink_direction, source_direction): @unchecked) match {
        //    SINK          SOURCE
        case (Output,       _) => issueConnect(sink, source)
        case (Internal,     _) => issueConnect(sink, source)
        case (Input,        _) => throw UnwritableSinkException


  • chisel3/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
  private def issueConnect(sink: Element, source: Element)(implicit sourceInfo: SourceInfo): Unit = {
    // If the source is a DontCare, generate a DefInvalid for the sink,
    //  otherwise, issue a Connect.
    source.topBinding match {
      case b: DontCareBinding => pushCommand(DefInvalid(sourceInfo, sink.lref))
      case _ => pushCommand(Connect(sourceInfo, sink.lref, source.ref))