Diplomacyを使ったOCPプロトコルの作成、Bufferのデバッグを行っているが、どうも良く分からないところがある。
例えばBufferのインタフェースにQueueを挿入せずにそのまま接続しようとした場合、以下のようなエラーが発生してしまう。
val ram0 = LazyModule(new OCPRAM(AddressSet(0x000, 0x3ff))) val xbar = LazyModule(new OCPBuffer(BufferCmdParams.none, BufferParams.none)) ram0.node := xbar.node := pusher.node [error] Caused by: chisel3.internal.ChiselException: Connection between left (CmdReadyIO(Wire in OCPBuffer)) and source (CmdReadyIO(Wire in OCPBuffer)) failed @.accept: Locally unclear whether Left or Right (both internal) ううん、これは何なのかよくわからない。Data.scalaにおいて、Biconnect.connectが呼ばれているのは分かった。
private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit ... BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule) // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Element, right: Element, context_mod: RawModule): Unit = { // scalastyle:ignore line.size.limit cyclomatic.complexity method.length import BindingDirection.{Internal, Input, Output} // Using extensively so import these // If left or right have no location, assume in context module // This can occur if one of them is a literal, unbound will error previously val left_mod: BaseModule = left.topBinding.location.getOrElse(context_mod) val right_mod: BaseModule = right.topBinding.location.getOrElse(context_mod) val left_direction = BindingDirection.from(left.topBinding, left.direction) val right_direction = BindingDirection.from(right.topBinding, right.direction) // CASE: Context is same module as left node and right node is in a child module if( (left_mod == context_mod) && (right_mod.parent.map( == context_mod).getOrElse(false)) ) { // Thus, right node better be a port node and thus have a direction hint ((left_direction, right_direction): @unchecked) match { // CURRENT MOD CHILD MOD case (Input, Input) => issueConnectL2R(left, right) case (Internal, Input) => issueConnectL2R(left, right) case (Output, Output) => issueConnectR2L(left, right) case (Internal, Output) => issueConnectR2L(left, right) case (Input, Output) => throw BothDriversException case (Output, Input) => throw NeitherDriverException case (_, Internal) => throw UnknownRelationException } } なぜかleft_directionとright_directionがどちらもInternalになっており、どうしても接続できない。
TileLinkで同様の試行をしても問題が発生しない。良く分からないのでTileLinkと全く同じバスを作って内部の接続状況を観察しよう。
いろいろ見ていると、どうやらBulkConnect内において以下の条件が違うらしい。
private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit if (connectCompileOptions.checkSynthesizable) { ... } else { this legacyConnect that } 最終的に、compileOptionsの違いだった。
chiselFrontend/src/main/scala/chisel3/Data.scala
final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) // scalastyle:ignore line.size.limit compileOptionsはimplicitなので探すのが大変なのだが、compatibilityに挿入されているらしい。やはりCompatibilityを一度介さないとだめなのか。
src/main/scala/chisel3/compatibility.scala
package object Chisel { // scalastyle:ignore package.object.name number.of.types number.of.methods ... implicit val defaultCompileOptions = chisel3.ExplicitCompileOptions.NotStrict そうしてchisel3パッケージではなくChiselパッケージを使うことで動作した。