【问题标题】:suggestName for IO(Vec(...))IO的建议名称(Vec(...))
【发布时间】:2021-05-04 15:15:07
【问题描述】:

我有一个这样的模块...

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 的每个元素提出建议名称,这样就可以代替 apb_0_ apb_1_ 等前缀...这是我为每个元素提供的任何内容。

我可以apb.suggestName 但这只会影响前导前缀并且数组索引仍然存在。执行apb(idx).suggestName("blah") 编译但没有效果。

有什么方法可以做到这一点?

【问题讨论】:

    标签: chisel


    【解决方案1】:

    通过消除 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))
      ...
    

    不确定这是否规范,但似乎可以解决问题。

    【讨论】:

    • 不接受我的回答,因为如果您确实需要以 Vec 的身份访问 apb 的元素(与 Seq 一样,我这样做),此方法将失效。
    【解决方案2】:

    用布赖恩的other 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

    For example:

    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 是 Wire,它将不起作用,因为 &lt;&gt; 是可交换运算符,因此在连接 2 条双向电线时会产生歧义。如需更详细的说明,请参阅this PR comment

    如果由于某种原因deq 需要成为Wire,您可以使用确实将 Vecs 作为端口的辅助模块:

    For example:

    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 的返回值是新的子模块,但有点棘手。

    好消息是一种更好的方法即将到来——Chisel 3.5 中的DataView 应该可以查看 SeqVec(而不是必须使用 @ 987654350@ 创建一个 Wire) 可以更轻松地避免此 Wire &lt;&gt; 连接歧义问题。我也希望为 Wires “修复”&lt;&gt;,或者提供一个新的运算符,它不是可交换的 :&lt;&gt;,但这还没有工作。

    【讨论】:

    • 是的 - 成功了!当然,现在我已经多次调用 emitVerilog 并带有各种不同的风格,并且需要以某种方式统一 InnerModule 的实例。
    • 如果类型不同,则不会进行Dedup。您可以使用 InlineInstance 来确保这些助手被内联,因此这些模块不会出现在 Verilog 中:chisel-lang.org/api/latest/chisel3/util/experimental/…
    【解决方案3】:

    我猜你的新 apbChannel 有一堆输入输出信号或线。因此,如果您的 apbChannel 有(比如说)val ip = Input(Bool()),则可以使用 apb(idx).suggestName 而不是 apb(idx).ip.suggestName("blah")

    【讨论】:

    • 遗憾的是,这也没有任何效果。包装 Bundle 的 Vec 似乎修复了命名。
    • 试试这个 val ip = Input(Bool()).suggestName("blah")
    • 也不行,这无论如何都会覆盖“内部”名称,而不是由 Vec 预先添加的“外部”名称,这就是我所追求的。
    猜你喜欢
    • 2023-03-06
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多