问题描述
谁能帮我理解“读取”宏是如何实现的?我感觉实际上调用了下面的“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.scala
的 github.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
,编译器会认为您试图将 16
和 0
作为隐式参数传递,而实际上,您是尝试在结果 .apply
上调用 T
(如果它是 Bits
的子类型)。宏解决了歧义,以便编译器知道您没有尝试传递隐式。
这是我对此进行描述的演讲的链接(警告,虽然关于源定位器和宏的一小部分是正确的,但大部分演讲已过时):{{3 }}