IO 的建议名称(Vec(...))
suggestName for IO(Vec(...))
我有一个这样的模块...
class ApbSplitter (clients : List[ApbRange]) extends MultiIOModule {
val nApb = clients.length
val apb = IO(Vec(nApb, new ApbChannel()))
val apb_m = IO(Flipped(new ApbChannel))
...
我想做的是为 Vec 的每个元素提供 suggestName,这样就可以不用前缀为 apb_0_
apb_1_
等...这是我为每个元素提供的内容。
我可以 apb.suggestName
但这只会影响前导前缀和数组索引。做 apb(idx).suggestName("blah")
编译但没有效果。
有什么方法可以做到这一点?
我猜你的新 apbChannel 有一堆输入输出信号或电线。因此,如果你的 apbChannel 有一个(比如)val ip = Input(Bool())
,你可以 apb(idx).ip.suggestName("blah")
而不是 apb(idx).suggestName
通过消除 Vec 并创建 IO 列表来实现它
case class ApbRange (name: String, loAddr : Int, hiAddr : Int)
class ApbSplitter (clients : List[ApbRange]) extends MultiIOModule {
val apb = clients.map({x => IO(new ApbChannel).suggestName(x.name)})
val apb_m = IO(Flipped(new ApbChannel))
...
不确定这是否规范,但似乎可以很好地解决问题。
用 Brian 的 回答这个问题,并评论他自己对此 post 的回答。这将是一个很长的答案,因为它涉及 Chisel API 中的几个缺陷,这些缺陷正在改进中,但肯定与当前版本(2021 年 8 月 12 日的 v3.4.3)相关。
Brian 的回答是正确的,如果您想命名需要使用 Seq
而不是 Vec
的各个字段。这样做的原因是,从 Chisel 的角度来看,Vec
类型的 IO
是具有聚合类型的单个端口,而 Seq
只是一系列不相关的端口。 Seq
是 Scala 构造(而 Vec
来自 Chisel),因此 Chisel 本身对 Seq
.
中端口之间的关系一无所知。
那么问题是您需要 Vec
来进行动态索引。您可以使用 VecInit
从您的 Seq
创建动态索引 Wire
每当您需要进行动态索引时:
class MyModule(names: Seq[String]) extends RawModule {
val enq = names.map(n => IO(Flipped(Decoupled(UInt(8.W)))).suggestName(n))
val idx = IO(Input(UInt(log2Ceil(names.size).W)))
val deq = IO(Decoupled(UInt(8.W)))
// enqWire connects all fields of enq
val enqWire = VecInit(enq)
// Need to make sure backpressure is always driven
enqWire.foreach(_.ready := false.B)
deq <> enqWire(idx)
}
只要 deq
本身就是一个端口,它就可以工作。如果 deq
是一根电线,它将 不 工作,因为 <>
是一个交换运算符,因此在连接 2 条双向电线时会产生歧义。如需更详细的解释,请参阅 this PR comment.
如果 deq
由于某种原因需要成为 Wire
,您可以使用 将 Vecs 作为端口的辅助模块:
class InnerHelper(n: Int) extends RawModule {
val enq = IO(Flipped(Vec(n, Decoupled(UInt(8.W)))))
val idx = IO(Input(UInt(log2Ceil(n).W)))
val jdx = IO(Input(UInt(log2Ceil(n).W)))
val deq = IO(Vec(n, Decoupled(UInt(8.W))))
// backpressure defaults
enq.foreach(_.ready := false.B)
deq.foreach { x =>
x.valid := false.B
x.bits := DontCare
}
deq(jdx) <> enq(idx)
}
class MyModule(names: Seq[String]) extends RawModule {
val enq = names.map(n => IO(Flipped(Decoupled(UInt(8.W)))).suggestName(n))
val idx = IO(Input(UInt(log2Ceil(names.size).W)))
val jdx = IO(Input(UInt(log2Ceil(names.size).W)))
val deq = names.map(n => IO(Decoupled(UInt(8.W))).suggestName(s"${n}_out"))
val helper = Module(new InnerHelper(names.size))
helper.enq <> enq
helper.idx := idx
helper.jdx := jdx
helper.deq <> deq
}
虽然有点蛋疼,但至少解决了歧义。我们可以构建其他实用程序——例如,我们可以创建一个实用程序方法来创建一个模块,以便动态索引 Seq
的返回值是一个新子模块的端口,但它有点棘手。
好消息是更好的方法即将到来——DataView 在 Chisel 3.5 中应该可以 view a Seq
作为 Vec
(而不是必须使用 VecInit
来创建 Wire
),这样可以更轻松地避免此 Wire
<>
连接歧义问题。我也希望“修复”<>
的 Wires,或者提供一个新的不可交换的运算符 :<>
,但尚未开发。
我有一个这样的模块...
class ApbSplitter (clients : List[ApbRange]) extends MultiIOModule {
val nApb = clients.length
val apb = IO(Vec(nApb, new ApbChannel()))
val apb_m = IO(Flipped(new ApbChannel))
...
我想做的是为 Vec 的每个元素提供 suggestName,这样就可以不用前缀为 apb_0_
apb_1_
等...这是我为每个元素提供的内容。
我可以 apb.suggestName
但这只会影响前导前缀和数组索引。做 apb(idx).suggestName("blah")
编译但没有效果。
有什么方法可以做到这一点?
我猜你的新 apbChannel 有一堆输入输出信号或电线。因此,如果你的 apbChannel 有一个(比如)val ip = Input(Bool())
,你可以 apb(idx).ip.suggestName("blah")
通过消除 Vec 并创建 IO 列表来实现它
case class ApbRange (name: String, loAddr : Int, hiAddr : Int)
class ApbSplitter (clients : List[ApbRange]) extends MultiIOModule {
val apb = clients.map({x => IO(new ApbChannel).suggestName(x.name)})
val apb_m = IO(Flipped(new ApbChannel))
...
不确定这是否规范,但似乎可以很好地解决问题。
用 Brian 的
Brian 的回答是正确的,如果您想命名需要使用 Seq
而不是 Vec
的各个字段。这样做的原因是,从 Chisel 的角度来看,Vec
类型的 IO
是具有聚合类型的单个端口,而 Seq
只是一系列不相关的端口。 Seq
是 Scala 构造(而 Vec
来自 Chisel),因此 Chisel 本身对 Seq
.
那么问题是您需要 Vec
来进行动态索引。您可以使用 VecInit
从您的 Seq
创建动态索引 Wire
每当您需要进行动态索引时:
class MyModule(names: Seq[String]) extends RawModule {
val enq = names.map(n => IO(Flipped(Decoupled(UInt(8.W)))).suggestName(n))
val idx = IO(Input(UInt(log2Ceil(names.size).W)))
val deq = IO(Decoupled(UInt(8.W)))
// enqWire connects all fields of enq
val enqWire = VecInit(enq)
// Need to make sure backpressure is always driven
enqWire.foreach(_.ready := false.B)
deq <> enqWire(idx)
}
只要 deq
本身就是一个端口,它就可以工作。如果 deq
是一根电线,它将 不 工作,因为 <>
是一个交换运算符,因此在连接 2 条双向电线时会产生歧义。如需更详细的解释,请参阅 this PR comment.
如果 deq
由于某种原因需要成为 Wire
,您可以使用 将 Vecs 作为端口的辅助模块:
class InnerHelper(n: Int) extends RawModule {
val enq = IO(Flipped(Vec(n, Decoupled(UInt(8.W)))))
val idx = IO(Input(UInt(log2Ceil(n).W)))
val jdx = IO(Input(UInt(log2Ceil(n).W)))
val deq = IO(Vec(n, Decoupled(UInt(8.W))))
// backpressure defaults
enq.foreach(_.ready := false.B)
deq.foreach { x =>
x.valid := false.B
x.bits := DontCare
}
deq(jdx) <> enq(idx)
}
class MyModule(names: Seq[String]) extends RawModule {
val enq = names.map(n => IO(Flipped(Decoupled(UInt(8.W)))).suggestName(n))
val idx = IO(Input(UInt(log2Ceil(names.size).W)))
val jdx = IO(Input(UInt(log2Ceil(names.size).W)))
val deq = names.map(n => IO(Decoupled(UInt(8.W))).suggestName(s"${n}_out"))
val helper = Module(new InnerHelper(names.size))
helper.enq <> enq
helper.idx := idx
helper.jdx := jdx
helper.deq <> deq
}
虽然有点蛋疼,但至少解决了歧义。我们可以构建其他实用程序——例如,我们可以创建一个实用程序方法来创建一个模块,以便动态索引 Seq
的返回值是一个新子模块的端口,但它有点棘手。
好消息是更好的方法即将到来——DataView 在 Chisel 3.5 中应该可以 view a Seq
作为 Vec
(而不是必须使用 VecInit
来创建 Wire
),这样可以更轻松地避免此 Wire
<>
连接歧义问题。我也希望“修复”<>
的 Wires,或者提供一个新的不可交换的运算符 :<>
,但尚未开发。