Skip to content

Commit 2159d81

Browse files
committed
Fix D/I sources to cross compile
1 parent 4cdd1af commit 2159d81

File tree

5 files changed

+174
-62
lines changed

5 files changed

+174
-62
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.experimental.hierarchy
4+
5+
import scala.reflect.runtime.{universe => ru}
6+
import scala.collection.mutable
7+
8+
import chisel3._
9+
import chisel3.experimental.{BaseModule, SourceInfo, UnlocatableSourceInfo}
10+
import chisel3.reflect.DataMirror
11+
import chisel3.reflect.DataMirror.internal.isSynthesizable
12+
import chisel3.internal.Builder
13+
14+
private[chisel3] trait InstantiateImpl {
15+
16+
// Data uses referential equality by default, but for looking up Data in the cache, we need to use
17+
// structural equality for Data unbound types and literal values
18+
// Note that this is somewhat incomplete because we can't handle the general case of user-defined
19+
// types that contain Data.
20+
// A more complete and robust solution would require either refining hashCode and equality on Data
21+
// to have the desired behavior, or using a different Map implementation that uses typeclasses for
22+
// equality and hashcode (eg. cats-collections-core's HashMap)
23+
private class DataBox(private val d: Data) {
24+
25+
private def convertDataForHashing(data: Data): Any = data match {
26+
// Using toString is a bit weird but it works
27+
case elt: Element => elt.toString
28+
case rec: Record =>
29+
// Purely structural, actual class of Record isn't involved
30+
rec.elements.map { case (name, data) => name -> convertDataForHashing(data) }
31+
case vec: Vec[_] =>
32+
// We could map on elements but that's a lot of duplicated work for a type
33+
// Note that empty vecs of the same type will give same hash value, probably should be equal
34+
// as well, but Vec.typeEquivalent checks sample_element so they will not be equal
35+
("Vec", vec.size, vec.headOption.map(convertDataForHashing(_)))
36+
}
37+
38+
override def hashCode: Int = convertDataForHashing(d).hashCode
39+
40+
// If literals, check same types and equal
41+
// If types, chck same types
42+
// If bound, fall back to normal equality
43+
override def equals(that: Any): Boolean = {
44+
that match {
45+
case that: DataBox =>
46+
// def because it's not needed by non-literal but is synthesizable check
47+
def sameTypes = DataMirror.checkTypeEquivalence(this.d, that.d)
48+
// Lits are synthesizable so must check them first
49+
if (this.d.isLit) {
50+
that.d.isLit &&
51+
(this.d.litValue == that.d.litValue) &&
52+
sameTypes
53+
} else if (isSynthesizable(this.d)) {
54+
this.d.equals(that.d)
55+
} else {
56+
// We have checked that this.d is not synthesizable but need to check that.d as well
57+
sameTypes && !isSynthesizable(that.d)
58+
}
59+
60+
case _ => false
61+
}
62+
}
63+
}
64+
65+
// Recursively box all Data (by traversing Products and Iterables) in DataBoxes
66+
private def boxAllData(a: Any): Any = a match {
67+
case d: Data => new DataBox(d) // Must check this before Iterable because Vec is Iterable
68+
// Must check before Product, because many Iterables are Products, but can still be equal, eg. List(1) == Vector(1)
69+
case it: Iterable[_] => it.map(boxAllData(_))
70+
case p: Product => Vector(p.getClass) ++ p.productIterator.map(boxAllData(_))
71+
case other => other
72+
}
73+
74+
import chisel3.internal.BuilderContextCache
75+
// Include type of module in key since different modules could have the same arguments
76+
private case class CacheKey[A <: BaseModule](args: Any, tt: Any, modulePrefix: List[String])
77+
extends BuilderContextCache.Key[Definition[A]]
78+
79+
protected def _instanceImpl[K, A <: BaseModule](
80+
args: K,
81+
f: K => A,
82+
tt: Any
83+
)(
84+
implicit sourceInfo: SourceInfo
85+
): Instance[A] = Instance.do_apply(_definitionImpl(args, f, tt))(sourceInfo)
86+
87+
/** This is not part of the public API, do not call directly! */
88+
protected def _definitionImpl[K, A <: BaseModule](
89+
args: K,
90+
f: K => A,
91+
tt: Any
92+
): Definition[A] = {
93+
val modulePrefix = Builder.getModulePrefixList
94+
Builder.contextCache
95+
.getOrElseUpdate(
96+
CacheKey[A](boxAllData(args), tt, modulePrefix), {
97+
// The definition needs to have no source locator because otherwise it will be unstably
98+
// derived from the first invocation of Instantiate for the particular Module
99+
Definition.do_apply(f(args))(UnlocatableSourceInfo)
100+
}
101+
)
102+
.asInstanceOf[Definition[A]]
103+
}
104+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package chisel3.experimental.hierarchy.core
2+
3+
import chisel3._
4+
import scala.collection.mutable.{HashMap, HashSet}
5+
import chisel3.experimental.BaseModule
6+
import _root_.firrtl.annotations.IsModule
7+
import scala.reflect.runtime.universe.TypeTag
8+
9+
trait Hierarchy[+A] extends HierarchyImpl[A] {
10+
/** Determine whether underlying proto is of type provided.
11+
*
12+
* @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
13+
* @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
14+
* @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
15+
*
16+
* E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
17+
* @return Whether underlying proto is of provided type (with caveats outlined above)
18+
*/
19+
def isA[B: TypeTag]: Boolean = {
20+
val tptag = implicitly[TypeTag[B]]
21+
// drop any type information for the comparison, because the proto will not have that information.
22+
val name = tptag.tpe.toString.takeWhile(_ != '[')
23+
inBaseClasses(name)
24+
}
25+
26+
}
27+
28+
object Hierarchy {
29+
implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) {
30+
31+
/** Returns the toTarget of this hierarchy
32+
* @return target of this hierarchy
33+
*/
34+
def toTarget: IsModule = i match {
35+
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget
36+
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget
37+
case _ => throw new InternalErrorException("Match error: toTarget i=$i")
38+
}
39+
40+
/** Returns the toAbsoluteTarget of this hierarchy
41+
* @return absoluteTarget of this Hierarchy
42+
*/
43+
def toAbsoluteTarget: IsModule = i match {
44+
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget
45+
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget
46+
case _ => throw new InternalErrorException("Match error: toAbsoluteTarget i=$i")
47+
}
48+
49+
/** Returns the toRelativeTarget of this hierarchy
50+
* @return relativeTarget of this Hierarchy
51+
*/
52+
def toRelativeTarget(root: Option[BaseModule]): IsModule = i match {
53+
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toRelativeTarget(root)
54+
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toRelativeTarget(root)
55+
case _ => throw new InternalErrorException("Match error: toAbsoluteTarget i=$i")
56+
}
57+
58+
/** Returns the toRelativeTarget of this hierarchy
59+
* @return relativeTarget of this Hierarchy
60+
*/
61+
def toRelativeTargetToHierarchy(root: Option[Hierarchy[BaseModule]]): IsModule = i match {
62+
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toRelativeTargetToHierarchy(root)
63+
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toRelativeTargetToHierarchy(root)
64+
case _ => throw new InternalErrorException("Match error: toAbsoluteTarget i=$i")
65+
}
66+
67+
}
68+
}

core/src/main/scala/chisel3/experimental/hierarchy/core/Definition.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import chisel3.internal.{Builder, DynamicContext}
99
import chisel3.internal.firrtl.Converter
1010
import chisel3.experimental.{BaseModule, SourceInfo}
1111
import firrtl.annotations.{IsModule, ModuleTarget, NoTargetAnnotation}
12-
1312
import firrtl.seqToAnnoSeq
1413

1514
import scala.annotation.nowarn

core/src/main/scala/chisel3/experimental/hierarchy/core/Hierarchy.scala renamed to core/src/main/scala/chisel3/experimental/hierarchy/core/HierarchyImpl.scala

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package chisel3.experimental.hierarchy.core
55
import chisel3._
66

77
import scala.collection.mutable.{HashMap, HashSet}
8-
import scala.reflect.runtime.universe.TypeTag
98
import chisel3.experimental.BaseModule
109
import _root_.firrtl.annotations.IsModule
1110

@@ -15,7 +14,7 @@ import scala.annotation.implicitNotFound
1514
*
1615
* Enables writing functions which are Instance/Definition agnostic
1716
*/
18-
sealed trait Hierarchy[+A] {
17+
trait HierarchyImpl[+A] {
1918
private[chisel3] def underlying: Underlying[A]
2019
private[chisel3] def proto: A = underlying match {
2120
case Proto(value) => value
@@ -26,22 +25,6 @@ sealed trait Hierarchy[+A] {
2625
private[chisel3] val cache = HashMap[Data, Data]()
2726
private[chisel3] def getInnerDataContext: Option[BaseModule]
2827

29-
/** Determine whether underlying proto is of type provided.
30-
*
31-
* @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
32-
* @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
33-
* @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
34-
*
35-
* E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
36-
* @return Whether underlying proto is of provided type (with caveats outlined above)
37-
*/
38-
def isA[B: TypeTag]: Boolean = {
39-
val tptag = implicitly[TypeTag[B]]
40-
// drop any type information for the comparison, because the proto will not have that information.
41-
val name = tptag.tpe.toString.takeWhile(_ != '[')
42-
inBaseClasses(name)
43-
}
44-
4528
// This code handles a special-case where, within an mdoc context, the type returned from
4629
// scala reflection (typetag) looks different than when returned from java reflection.
4730
// This function detects this case and reshapes the string to match.
@@ -95,45 +78,3 @@ sealed trait Hierarchy[+A] {
9578

9679
// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file.
9780
private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A]
98-
99-
object Hierarchy {
100-
implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) {
101-
102-
/** Returns the toTarget of this hierarchy
103-
* @return target of this hierarchy
104-
*/
105-
def toTarget: IsModule = i match {
106-
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget
107-
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget
108-
case _ => throw new InternalErrorException(s"Match error: toTarget i=$i")
109-
}
110-
111-
/** Returns the toAbsoluteTarget of this hierarchy
112-
* @return absoluteTarget of this Hierarchy
113-
*/
114-
def toAbsoluteTarget: IsModule = i match {
115-
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget
116-
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget
117-
case _ => throw new InternalErrorException(s"Match error: toAbsoluteTarget i=$i")
118-
}
119-
120-
/** Returns the toRelativeTarget of this hierarchy
121-
* @return relativeTarget of this Hierarchy
122-
*/
123-
def toRelativeTarget(root: Option[BaseModule]): IsModule = i match {
124-
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toRelativeTarget(root)
125-
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toRelativeTarget(root)
126-
case _ => throw new InternalErrorException(s"Match error: toAbsoluteTarget i=$i")
127-
}
128-
129-
/** Returns the toRelativeTarget of this hierarchy
130-
* @return relativeTarget of this Hierarchy
131-
*/
132-
def toRelativeTargetToHierarchy(root: Option[Hierarchy[BaseModule]]): IsModule = i match {
133-
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toRelativeTargetToHierarchy(root)
134-
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toRelativeTargetToHierarchy(root)
135-
case _ => throw new InternalErrorException(s"Match error: toAbsoluteTarget i=$i")
136-
}
137-
138-
}
139-
}

core/src/main/scala/chisel3/experimental/hierarchy/core/Instance.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ object Instance extends SourceInfoDoc {
166166
Some(component)
167167
}
168168
}
169-
Definition(new EmptyExtModule() {})
169+
Definition(new EmptyExtModule() {}.asInstanceOf[Underlying[_]])
170170
}
171171

172172
val ports = experimental.CloneModuleAsRecord(definition.proto)

0 commit comments

Comments
 (0)