测试火箭芯片实用程序 'Arbiters.scala',出现错误“位操作......必须是硬件......”
test rocket chip util 'Arbiters.scala', got error 'bits operated ... must be hardware ..."
我复制了一个rocket-chip util模块'Arbiters.scala'到一个单独的工作目录,用下面的代码测试:
object try_arbiter extends App {
chisel3.Driver.execute(args, () => new HellaCountingArbiter(UInt(4.W), 3, 5))
}
编译没有问题。但是,在步骤'Elaborating design...'中,它报告了[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) }
}
}
}
问题是 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)).flip
更改为 Flipped(Vec(arbN, Decoupled(typ)))
并删除了 val out
上的 .cloneType
。后两项更改不需要编译,但从 Chisel 3.1.2 开始,它们将被标记为弃用警告。
我复制了一个rocket-chip util模块'Arbiters.scala'到一个单独的工作目录,用下面的代码测试:
object try_arbiter extends App {
chisel3.Driver.execute(args, () => new HellaCountingArbiter(UInt(4.W), 3, 5))
}
编译没有问题。但是,在步骤'Elaborating design...'中,它报告了[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) }
}
}
}
问题是 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)).flip
更改为 Flipped(Vec(arbN, Decoupled(typ)))
并删除了 val out
上的 .cloneType
。后两项更改不需要编译,但从 Chisel 3.1.2 开始,它们将被标记为弃用警告。