首页 > 解决方案 > 测试火箭芯片实用程序'Arbiters.scala',出现错误'位操作......必须是硬件......“

问题描述

我将一个火箭芯片实用模块“Arbiters.scala”复制到一个单独的工作目录中,使用以下代码进行测试:

object try_arbiter extends App {
  chisel3.Driver.execute(args, () => new HellaCountingArbiter(UInt(4.W), 3, 5))
}

编译时没有问题。然而,在“详细设计......”步骤中,它报告了[error] chisel3.core.Binding$ExpectedHardwareException: mux condition 'chisel3.core.Bool@46' must be hardware, not a bare Chisel type"

相关代码是

PriorityEncoder(io.in.map(_.valid))

当我将此行更改为以下行时,错误消失了(scala 代码仍然有这种错误,但不在这一行中)。

PriorityEncoder(io.in.map(x => Wire(x.valid)))

火箭芯片代码应该已经评估过很多次了吧?我想一定有我错过的……一些配置?

感谢您的任何提示!

附录(Arbiters.scala):

package rocket_examples

import chisel3._
import chisel3.util._

/** A generalized locking RR arbiter that addresses the limitations of the
 *  version in the Chisel standard library */
abstract class HellaLockingArbiter[T <: Data](typ: T, arbN: Int, rr: Boolean = false)
    extends Module {

  val io = new Bundle {
    val in = Vec(arbN, Decoupled(typ.cloneType)).flip
    val out = Decoupled(typ.cloneType)
  }

  def rotateLeft[T <: Data](norm: Vec[T], rot: UInt): Vec[T] = {
    val n = norm.size
    Vec.tabulate(n) { i =>
      Mux(rot < UInt(n - i), norm(UInt(i) + rot), norm(rot - UInt(n - i)))
    }
  }

  val lockIdx = Reg(init = UInt(0, log2Up(arbN)))
  val locked = Reg(init = Bool(false))

  val choice = if (rr) {
    PriorityMux(
      rotateLeft(Vec(io.in.map(_.valid)), lockIdx + UInt(1)),
      rotateLeft(Vec((0 until arbN).map(UInt(_))), lockIdx + UInt(1)))
  } else {
    PriorityEncoder(io.in.map(_.valid))
  }

  val chosen = Mux(locked, lockIdx, choice)

  for (i <- 0 until arbN) {
    io.in(i).ready := io.out.ready && chosen === UInt(i)
  }

  io.out.valid := io.in(chosen).valid
  io.out.bits := io.in(chosen).bits
}

/** This locking arbiter determines when it is safe to unlock
 *  by peeking at the data */
class HellaPeekingArbiter[T <: Data](
      typ: T, arbN: Int,
      canUnlock: T => Bool,
      needsLock: Option[T => Bool] = None,
      rr: Boolean = false)
    extends HellaLockingArbiter(typ, arbN, rr) {

  def realNeedsLock(data: T): Bool =
    needsLock.map(_(data)).getOrElse(Bool(true))

  when (io.out.fire()) {
    when (!locked && realNeedsLock(io.out.bits)) {
      lockIdx := choice
      locked := Bool(true)
    }
    // the unlock statement takes precedent
    when (canUnlock(io.out.bits)) {
      locked := Bool(false)
    }
  }
}

/** This arbiter determines when it is safe to unlock by counting transactions */
class HellaCountingArbiter[T <: Data](
      typ: T, arbN: Int, count: Int,
      val needsLock: Option[T => Bool] = None,
      rr: Boolean = false)
    extends HellaLockingArbiter(typ, arbN, rr) {

  def realNeedsLock(data: T): Bool =
    needsLock.map(_(data)).getOrElse(Bool(true))

  // if count is 1, you should use a non-locking arbiter
  require(count > 1, "CountingArbiter cannot have count <= 1")

  val lock_ctr = Counter(count)

  when (io.out.fire()) {
    when (!locked && realNeedsLock(io.out.bits)) {
      lockIdx := choice
      locked := Bool(true)
      lock_ctr.inc()
    }

    when (locked) {
      when (lock_ctr.inc()) { locked := Bool(false) }
    }
  }
}

标签: chisel

解决方案


问题是 Rocket-chip 中的几乎所有代码都是针对较旧的 Chisel2 风格的 API 编写的,并且应该使用兼容性包装器进行编译import Chisel._。我看到你使用import chisel3._了它有更严格的语义。

对于这种特定情况,Chisel2 和 Chisel3 之间的区别在于端口 ( val io) 必须包含在 中IO(...),即。

  val io = IO(new Bundle {
    val in = Flipped(Vec(arbN, Decoupled(typ)))
    val out = Decoupled(typ)
  })

请注意,我也更改Vec(arbN, Decoupled(typ.cloneType)).flipFlipped(Vec(arbN, Decoupled(typ)))并删除了.cloneTypeon val out。编译不需要后两个更改,但从 Chisel 3.1.2 开始,它们将被标记为弃用警告。


推荐阅读