Skip to content

Commit a7a68e5

Browse files
authored
Implement Lookupable for HasTarget (used by SRAM) (#4481)
1 parent 8c718b2 commit a7a68e5

File tree

6 files changed

+80
-7
lines changed

6 files changed

+80
-7
lines changed

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,46 @@ object Lookupable {
405405
}
406406
}
407407

408+
// TODO, this, cloneMemToContext, and cloneDataToContext should be unified
409+
private def cloneHasTargetToContext(
410+
hasTarget: HasTarget,
411+
context: BaseModule
412+
)(
413+
implicit sourceInfo: SourceInfo
414+
): HasTarget = {
415+
hasTarget match {
416+
case HasTarget.Impl(st: SramTarget) =>
417+
st._parent match {
418+
case None => hasTarget
419+
case Some(parent) =>
420+
val newParent = cloneModuleToContext(Proto(parent), context)
421+
newParent match {
422+
case Proto(p) if p == parent => hasTarget
423+
case Clone(mod: BaseModule) =>
424+
val existingMod = Builder.currentModule
425+
Builder.currentModule = Some(mod)
426+
val newChild = new SramTarget
427+
Builder.currentModule = existingMod
428+
newChild.setRef(st.getRef, true)
429+
HasTarget(newChild)
430+
case _ =>
431+
throw new InternalErrorException(s"Match error: newParent=$newParent")
432+
}
433+
}
434+
}
435+
}
436+
437+
implicit def lookupHasTarget(implicit sourceInfo: SourceInfo): Simple[HasTarget] =
438+
new Lookupable[HasTarget] {
439+
type C = HasTarget
440+
def definitionLookup[A](that: A => HasTarget, definition: Definition[A]): C = {
441+
cloneHasTargetToContext(that(definition.proto), definition.getInnerDataContext.get)
442+
}
443+
def instanceLookup[A](that: A => HasTarget, instance: Instance[A]): C = {
444+
cloneHasTargetToContext(that(instance.proto), instance.getInnerDataContext.get)
445+
}
446+
}
447+
408448
import scala.language.higherKinds // Required to avoid warning for lookupIterable type parameter
409449
implicit def lookupIterable[B, F[_] <: Iterable[_]](
410450
implicit sourceInfo: SourceInfo,

core/src/main/scala/chisel3/package.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ package object chisel3 {
421421

422422
/** Exposes target information and suggestName functionality of a NamedComponent.
423423
*/
424+
// This is only currently used for SRAM to hide the underlying Memory but still let users annotate it.
425+
// Rather than generalizing this, it's more likely that we'll just delete it (and the use in SRAM) in favor of Path Properties.
424426
sealed trait HasTarget {
425427
def toTarget: ReferenceTarget
426428
def toAbsoluteTarget: ReferenceTarget
@@ -436,11 +438,7 @@ package object chisel3 {
436438
}
437439

438440
object HasTarget {
439-
440-
/** This wrapping hides the actual object, ensuring users only have access
441-
* to the target methods (instead of the type of the underlying object).
442-
*/
443-
private[chisel3] def apply(t: NamedComponent): HasTarget = new HasTarget {
441+
private[chisel3] case class Impl(t: SramTarget) extends HasTarget {
444442
def toTarget = t.toTarget
445443
def toAbsoluteTarget = t.toAbsoluteTarget
446444
def toRelativeTarget(root: Option[BaseModule]) = t.toRelativeTarget(root)
@@ -449,5 +447,10 @@ package object chisel3 {
449447
def suggestName(seed: String): Unit = t.suggestName(seed)
450448
}
451449

450+
/** This wrapping hides the actual object, ensuring users only have access
451+
* to the target methods (instead of the type of the underlying object).
452+
*/
453+
private[chisel3] def apply(t: SramTarget): HasTarget = Impl(t)
454+
452455
}
453456
}

src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package chiselTests.experimental.hierarchy
44

55
import _root_.firrtl.annotations._
66
import chisel3.experimental.{annotate, BaseModule}
7-
import chisel3.{Data, MemBase}
7+
import chisel3.{Data, HasTarget, MemBase}
88
import chisel3.experimental.hierarchy.{Definition, Hierarchy, Instance}
99

1010
// These annotations exist purely for testing purposes
@@ -24,8 +24,13 @@ private[hierarchy] object Annotations {
2424
extends chisel3.experimental.ChiselAnnotation {
2525
def toFirrtl = if (isAbsolute) MarkAnnotation(m.toAbsoluteTarget, tag) else MarkAnnotation(m.toTarget, tag)
2626
}
27+
case class MarkChiselHasTargetAnnotation(d: HasTarget, tag: String, isAbsolute: Boolean)
28+
extends chisel3.experimental.ChiselAnnotation {
29+
def toFirrtl = if (isAbsolute) MarkAnnotation(d.toAbsoluteTarget, tag) else MarkAnnotation(d.toTarget, tag)
30+
}
2731
def mark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, false))
2832
def mark[T <: Data](d: MemBase[T], tag: String): Unit = annotate(MarkChiselMemAnnotation(d, tag, false))
33+
def mark(d: HasTarget, tag: String): Unit = annotate(MarkChiselHasTargetAnnotation(d, tag, false))
2934
def mark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
3035
def amark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, true))
3136
def amark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))

src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,16 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
390390
"Cannot create a memory port in a different module (Top) than where the memory is (HasMems)."
391391
)
392392
}
393+
it("(3.o): should work on HasTarget") {
394+
class Top() extends Module {
395+
val i = Definition(new HasHasTarget)
396+
mark(i.x, "x")
397+
}
398+
val (_, annos) = getFirrtlAndAnnos(new Top)
399+
annos.collect { case c: MarkAnnotation => c } should contain(
400+
MarkAnnotation("~Top|HasHasTarget>sram_sram".rt, "x")
401+
)
402+
}
393403
}
394404
describe("(4): toDefinition") {
395405
it("(4.a): should work on modules") {

src/test/scala/chiselTests/experimental/hierarchy/Examples.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
package chiselTests.experimental.hierarchy
44

55
import chisel3._
6-
import chisel3.util.Valid
6+
import chisel3.util.{SRAM, Valid}
77
import chisel3.experimental.hierarchy._
88
import chisel3.experimental.{attach, Analog, BaseModule}
99

@@ -223,6 +223,11 @@ object Examples {
223223
@public val xy = (x, y)
224224
}
225225
@instantiable
226+
class HasHasTarget() extends Module {
227+
val sram = SRAM(1024, UInt(8.W), 1, 1, 0)
228+
@public val x: HasTarget = sram.underlying.get
229+
}
230+
@instantiable
226231
class HasVec() extends Module {
227232
@public val x = VecInit(1.U, 2.U, 3.U)
228233
}

src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,16 @@ class InstanceSpec extends ChiselFunSpec with Utils {
464464
val (chirrtl, _) = getFirrtlAndAnnos(new AddTwoNestedInstantiableDataWrapper(4))
465465
exactly(3, chirrtl.serialize.split('\n')) should include("connect i1.in, i0.out")
466466
}
467+
it("(3.r): should work on HasTarget") {
468+
class Top() extends Module {
469+
val i = Instance(Definition(new HasHasTarget))
470+
mark(i.x, "x")
471+
}
472+
val (_, annos) = getFirrtlAndAnnos(new Top)
473+
annos.collect { case c: MarkAnnotation => c } should contain(
474+
MarkAnnotation("~Top|Top/i:HasHasTarget>sram_sram".rt, "x")
475+
)
476+
}
467477
}
468478
describe("(4) toInstance") {
469479
it("(4.a): should work on modules") {

0 commit comments

Comments
 (0)