summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/experimental/Trace.scala
blob: eb2ed46a7d0a9bc0cfa57e757ed5913789b7adab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package chisel3.experimental

import chisel3.internal.HasId
import chisel3.{Aggregate, Data, Element, Module, RawModule}
import firrtl.AnnotationSeq
import firrtl.annotations.{Annotation, CompleteTarget, SingleTargetAnnotation}
import firrtl.transforms.DontTouchAllTargets

/** The util that records the reference map from original [[Data]]/[[Module]] annotated in Chisel and final FIRRTL.
  * @example
  * {{{
  *   class Dut extends Module {
  *     val a = WireDefault(Bool())
  *     Trace.traceName(a)
  *   }
  *   val annos = (new ChiselStage).execute(Seq(ChiselGeneratorAnnotation(() => new Dut)))
  *   val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule]
  *   // get final reference of `a` Seq(ReferenceTarget("Dut", "Dut", Seq.empty, "a", Seq.empty))
  *   val firrtlReferenceOfDutA = finalTarget(annos)(dut.a)
  * }}}
  */
object Trace {

  /** Trace a Instance name. */
  @deprecated("switch to traceNameV2 (until Chisel 3.6)", "3.5.5")
  def traceName(x: Module): Unit = traceName(x: RawModule)

  /** Trace a Instance name. */
  @deprecated("switch to traceNameV2 (until Chisel 3.6)", "3.5.5")
  def traceName(x: RawModule): Unit = {
    annotate(new ChiselAnnotation {
      def toFirrtl: Annotation = TraceNameAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget)
    })
  }

  /** Trace a Data name. This adds "don't touch" semantics to anything traced. */
  @deprecated(
    "switch to traceNameV2 (until Chisel 3.6) and add dontTouch if you want \"don't touch\" behavior",
    "3.5.5"
  )
  def traceName(x: Data): Unit = {
    x match {
      case aggregate: Aggregate =>
        annotate(new ChiselAnnotation {
          def toFirrtl: Annotation = TraceNameAnnotation(aggregate.toAbsoluteTarget, aggregate.toAbsoluteTarget)
        })
        aggregate.getElements.foreach(traceName)
      case element: Element =>
        annotate(new ChiselAnnotation {
          def toFirrtl: Annotation = TraceNameAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget)
        })
    }
  }

  /** Trace an Instance name. */
  def traceNameV2(x: RawModule): Unit = {
    annotate(new ChiselAnnotation {
      def toFirrtl: Annotation = TraceAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget)
    })
  }

  /** Trace a Data name. This does NOT add "don't touch" semantics to the traced data. If you want this behavior, use an explicit [[chisel3.dontTouch]]. */
  def traceNameV2(x: Data): Unit = {
    x match {
      case aggregate: Aggregate =>
        annotate(new ChiselAnnotation {
          def toFirrtl: Annotation = TraceAnnotation(aggregate.toAbsoluteTarget, aggregate.toAbsoluteTarget)
        })
        aggregate.elementsIterator.foreach(traceNameV2)
      case element: Element =>
        annotate(new ChiselAnnotation {
          def toFirrtl: Annotation = TraceAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget)
        })
    }
  }

  /** An Annotation that records the original target annotate from Chisel.  This adds don't touch behavior.
    *
    * @param target target that should be renamed by [[firrtl.RenameMap]] in the firrtl transforms.
    * @param chiselTarget original annotated target in Chisel, which should not be changed or renamed in FIRRTL.
    */
  private case class TraceNameAnnotation[T <: CompleteTarget](target: T, chiselTarget: T)
      extends SingleTargetAnnotation[T]
      with DontTouchAllTargets {
    def duplicate(n: T): Annotation = this.copy(target = n)
  }

  /** An Annotation that records the original target annotate from Chisel.  This does NOT add don't touch behavior.
    *
    * @param target target that should be renamed by [[firrtl.RenameMap]] in the firrtl transforms.
    * @param chiselTarget original annotated target in Chisel, which should not be changed or renamed in FIRRTL.
    */
  private case class TraceAnnotation[T <: CompleteTarget](target: T, chiselTarget: T)
      extends SingleTargetAnnotation[T] {
    def duplicate(n: T): Annotation = this.copy(target = n)
  }

  /** Get [[CompleteTarget]] of the target `x` for `annos`.
    * This API can be used to find the final reference to a signal or module which is marked by `traceName`
    */
  def finalTarget(annos: AnnotationSeq)(x: HasId): Seq[CompleteTarget] = finalTargetMap(annos)
    .getOrElse(x.toAbsoluteTarget, Seq.empty)

  /** Get all traced signal/module for `annos`
    * This API can be used to gather all final reference to the signal or module which is marked by `traceName`
    */
  def finalTargetMap(annos: AnnotationSeq): Map[CompleteTarget, Seq[CompleteTarget]] = annos.collect {
    case TraceNameAnnotation(t, chiselTarget) => chiselTarget -> t
    case TraceAnnotation(t, chiselTarget)     => chiselTarget -> t
  }.groupBy(_._1).map { case (k, v) => k -> v.map(_._2) }
}