Search code examples
chisel

test rocket chip util 'Arbiters.scala', got error 'bits operated ... must be hardware ..."


I copied a rocket-chip util module 'Arbiters.scala' to a separate work directory, test with the following code:

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

There's no problem when compiling. However, in the step 'Elaborating design...', it reported [error] chisel3.core.Binding$ExpectedHardwareException: mux condition 'chisel3.core.Bool@46' must be hardware, not a bare Chisel type"

The related code is

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

when I change this line to the following one, the error's gone (the scala code still has this kind of errs, but not in this line).

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

The rocket chip codes should have been evaluated for many times, right? I think there must have sth I have missed... Some configurations?

Thank you for any hints!

Appendix(the 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) }
    }
  }
}

Solution

  • The issue is that almost all of the code in rocket-chip has been written against older Chisel2-style APIs and should be compiled with the compatibility wrapper import Chisel._. I see you used import chisel3._ which has somewhat stricter semantics.

    For this specific case, the difference between Chisel2 and Chisel3 is that ports (val io) must be wrapped in IO(...), ie.

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

    Note that I also changed Vec(arbN, Decoupled(typ.cloneType)).flip to Flipped(Vec(arbN, Decoupled(typ))) and removed the .cloneType on val out. The latter two changes are not required for this to compile but they will be flagged as deprecation warnings as of Chisel 3.1.2.