summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
blob: 99eacc7d0ca0e04726d50706617537d54899ddbf (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// SPDX-License-Identifier: Apache-2.0

package chisel3.experimental.hierarchy

import scala.language.experimental.macros
import chisel3._

import scala.collection.mutable.HashMap
import chisel3.internal.{Builder, DynamicContext}
import chisel3.internal.sourceinfo.{DefinitionTransform, DefinitionWrapTransform, SourceInfo}
import chisel3.experimental.BaseModule
import chisel3.internal.BaseModule.IsClone
import firrtl.annotations.{IsModule, ModuleTarget}
import firrtl.annotations.{IsModule, ModuleTarget, NoTargetAnnotation}

/** User-facing Definition type.
  * Represents a definition of an object of type [[A]] which are marked as @instantiable
  * Can be created using Definition.apply method.
  *
  * These definitions are then used to create multiple [[Instance]]s.
  *
  * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object
  */
final case class Definition[+A] private[chisel3] (private[chisel3] underlying: Underlying[A])
    extends IsLookupable
    with SealedHierarchy[A] {

  /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
    * Instead, mark the field you are accessing with [[@public]]
    *
    * Given a selector function (that) which selects a member from the original, return the
    *   corresponding member from the instance.
    *
    * Our @instantiable and @public macros generate the calls to this apply method
    *
    * By calling this function, we summon the proper Lookupable typeclass from our implicit scope.
    *
    * @param that a user-specified lookup function
    * @param lookup typeclass which contains the correct lookup function, based on the types of A and B
    * @param macroGenerated a value created in the macro, to make it harder for users to use this API
    */
  def _lookup[B, C](
    that: A => B
  )(
    implicit lookup: Lookupable[B],
    macroGenerated:  chisel3.internal.MacroGenerated
  ): lookup.C = {
    lookup.definitionLookup(that, this)
  }

  /** @return the context of any Data's return from inside the instance */
  private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match {
    case value: BaseModule =>
      val newChild = Module.do_pseudo_apply(new internal.BaseModule.DefinitionClone(value))(
        chisel3.internal.sourceinfo.UnlocatableSourceInfo,
        chisel3.ExplicitCompileOptions.Strict
      )
      newChild._circuit = value._circuit.orElse(Some(value))
      newChild._parent = None
      Some(newChild)
    case value: IsInstantiable => None
  }

  override def toDefinition: Definition[A] = this
  override def toInstance:   Instance[A] = new Instance(underlying)

}

/** Factory methods for constructing [[Definition]]s */
object Definition extends SourceInfoDoc {
  implicit class DefinitionBaseModuleExtensions[T <: BaseModule](d: Definition[T]) {

    /** If this is an instance of a Module, returns the toTarget of this instance
      * @return target of this instance
      */
    def toTarget: ModuleTarget = d.proto.toTarget

    /** If this is an instance of a Module, returns the toAbsoluteTarget of this instance
      * @return absoluteTarget of this instance
      */
    def toAbsoluteTarget: IsModule = d.proto.toAbsoluteTarget
  }

  /** A construction method to build a Definition of a Module
    *
    * @param proto the Module being defined
    *
    * @return the input module as a Definition
    */
  def apply[T <: BaseModule with IsInstantiable](proto: => T): Definition[T] = macro DefinitionTransform.apply[T]

  /** A construction method to build a Definition of a Module
    *
    * @param bc the Module being defined
    *
    * @return the input module as a Definition
    */
  def do_apply[T <: BaseModule with IsInstantiable](
    proto: => T
  )(
    implicit sourceInfo: SourceInfo,
    compileOptions:      CompileOptions
  ): Definition[T] = {
    val dynamicContext = {
      val context = Builder.captureContext()
      new DynamicContext(Nil, context.throwOnFirstError, context.warnReflectiveNaming, context.warningsAsErrors)
    }
    Builder.globalNamespace.copyTo(dynamicContext.globalNamespace)
    dynamicContext.inDefinition = true
    val (ir, module) = Builder.build(Module(proto), dynamicContext, false)
    Builder.components ++= ir.components
    Builder.annotations ++= ir.annotations
    module._circuit = Builder.currentModule
    dynamicContext.globalNamespace.copyTo(Builder.globalNamespace)
    new Definition(Proto(module))
  }

}

/** Stores a [[Definition]] that is imported so that its Instances can be
  * compiled separately.
  */
case class ImportDefinitionAnnotation[T <: BaseModule with IsInstantiable](
  definition:      Definition[T],
  overrideDefName: Option[String] = None)
    extends NoTargetAnnotation