Chisel:如何为 SyncReadMem 类实现“读取”函数或宏?

问题描述

谁能帮我理解“读取”宏是如何实现的?我感觉实际上调用了下面的“do_read”函数,但无法弄清楚它是如何完成的。我对“SourceInfoTransform”类很感兴趣。谁能给我一个关于它的用法提示? 下面列出了“SyncReadMem”实现。

在此先感谢您的帮助!

最好的问候,

-飞

sealed class SyncReadMem[T <: Data] private (t: T,n: BigInt,val readUnderWrite: SyncReadMem.ReadUnderWrite) extends MemBase[T](t,n) {
  def read(x: UInt,en: Bool): T = macro SourceInfoTransform.xEnArg

  /** @group SourceInfoTransformMacro */
  def do_read(addr: UInt,enable: Bool)(implicit sourceInfo: SourceInfo,compileOptions: CompileOptions): T = {
    val a = Wire(UInt())
    a := DontCare
    var port: Option[T] = None
    when (enable) {
      a := addr
      port = Some(read(a))
    }
    port.get
  }
}

解决方法

SourceInfoTransform 是将 def read 转换为 def do_read 的 Scala 宏。宏的代码位于 src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scalagithub.com/chipsalliance/chisel3 中。在该文件中,有许多变换类用于处理具有不同参数数量的不同凿子构造。 SourceInfoTransform 的主要用途是获取 Chisel/Scala 源代码的行号,以便可以在异常和生成的 Firrtl 和 Verilog 中报告。在这里is an article on macros,还有更多可用的。 祝你好运。

,

Chick 的回答大部分是正确的——它在“如何”和在哪里看上是正确的,但在“为什么”上略有错误:

SourceInfoTransform 的主要用途是获取 Chisel/Scala 源码的行号

这并不完全正确,您只需拥有 implicit sourceInfo: SourceInfo 即可获得源定位器,如果您愿意,也可以在原始 def read 上使用它。当您想在调用 SourceInfoTransform 方法后立即进行位提取时,read 宏的作用是解决歧义,例如。

myMem.read(addr,en)(16,0)

如果我们直接使用隐式定义 read,编译器会认为您试图将 160 作为隐式参数传递,而实际上,您是尝试在结果 .apply 上调用 T(如果它是 Bits 的子类型)。宏解决了歧义,以便编译器知道您没有尝试传递隐式。

这是我对此进行描述的演讲的链接(警告,虽然关于源定位器和宏的一小部分是正确的,但大部分演讲已过时):{{3 }}