Skip to content

Commit 7b8ffad

Browse files
authored
make SRAM targets accessible from SRAMInterface (#3728)
1 parent 9e08939 commit 7b8ffad

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
import firrtl.annotations.{IsMember, Named}
4-
import chisel3.internal.ExceptionHelpers
3+
import firrtl.annotations.{IsMember, Named, ReferenceTarget}
4+
import chisel3.internal.{ExceptionHelpers, NamedComponent}
5+
import chisel3.experimental.BaseModule
56

67
import java.util.{MissingFormatArgumentException, UnknownFormatConversionException}
78
import scala.collection.mutable
@@ -412,4 +413,25 @@ package object chisel3 {
412413
"this feature will not be supported as part of the migration to the MLIR-based FIRRTL Compiler (MFC). For more information about this migration, please see the Chisel ROADMAP.md."
413414

414415
final val deprecatedPublicAPIMsg = "APIs in chisel3.internal are not intended to be public"
416+
417+
/** Contains universal methods for target accesses.
418+
*/
419+
sealed trait HasTarget {
420+
def toTarget: ReferenceTarget
421+
def toAbsoluteTarget: ReferenceTarget
422+
def toRelativeTarget(root: Option[BaseModule]): ReferenceTarget
423+
}
424+
425+
object HasTarget {
426+
427+
/** This wrapping hides the actual object, ensuring users only have access
428+
* to the target methods (instead of the type of the underlying object).
429+
*/
430+
private[chisel3] def apply(t: NamedComponent): HasTarget = new HasTarget {
431+
def toTarget = t.toTarget
432+
def toAbsoluteTarget = t.toAbsoluteTarget
433+
def toRelativeTarget(root: Option[BaseModule]) = t.toRelativeTarget(root)
434+
}
435+
436+
}
415437
}

src/main/scala/chisel3/util/SRAM.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class MemoryReadWritePort[T <: Data](tpe: T, addrWidth: Int, masked: Boolean) ex
7979
* @param numReadPorts The number of read ports
8080
* @param numWritePorts The number of write ports
8181
* @param numReadwritePorts The number of read/write ports
82+
* @param masked Whether the memory is write masked
8283
*/
8384
class SRAMInterface[T <: Data](
8485
memSize: BigInt,
@@ -104,6 +105,11 @@ class SRAMInterface[T <: Data](
104105
val writePorts: Vec[MemoryWritePort[T]] = Vec(numWritePorts, new MemoryWritePort(tpe, addrWidth, masked))
105106
val readwritePorts: Vec[MemoryReadWritePort[T]] =
106107
Vec(numReadwritePorts, new MemoryReadWritePort(tpe, addrWidth, masked))
108+
109+
private[chisel3] var _underlying: Option[HasTarget] = None
110+
111+
/** Target information for annotating the underlying SRAM if it is known. */
112+
def underlying: Option[HasTarget] = _underlying
107113
}
108114

109115
/** A memory file with which to preload an [[SRAM]]
@@ -459,8 +465,9 @@ object SRAM {
459465
)
460466
}
461467

462-
val _out = Wire(new SRAMInterface(size, tpe, numReadPorts, numWritePorts, numReadwritePorts, isVecMem))
463468
val mem = SyncReadMem(size, tpe)
469+
val _out = Wire(new SRAMInterface(size, tpe, numReadPorts, numWritePorts, numReadwritePorts, isVecMem))
470+
_out._underlying = Some(HasTarget(mem))
464471

465472
for ((clock, port) <- readPortClocks.zip(_out.readPorts)) {
466473
port.data := mem.read(port.address, port.enable, clock)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chiselTests.util
4+
5+
import chisel3._
6+
import chisel3.util.SRAM
7+
import chisel3.experimental.{annotate, ChiselAnnotation}
8+
import chiselTests.ChiselFlatSpec
9+
import _root_.circt.stage.ChiselStage.emitCHIRRTL
10+
import firrtl.annotations.{Annotation, ReferenceTarget, SingleTargetAnnotation}
11+
12+
class SRAMSpec extends ChiselFlatSpec {
13+
case class DummyAnno(target: ReferenceTarget) extends SingleTargetAnnotation[ReferenceTarget] {
14+
override def duplicate(n: ReferenceTarget) = this.copy(target = n)
15+
}
16+
behavior.of("SRAMInterface")
17+
18+
it should "Provide target information about its instantiating SRAM" in {
19+
20+
class Top extends Module {
21+
val sram = SRAM(
22+
size = 32,
23+
tpe = UInt(8.W),
24+
numReadPorts = 0,
25+
numWritePorts = 0,
26+
numReadwritePorts = 1
27+
)
28+
require(sram.underlying.nonEmpty)
29+
annotate(new ChiselAnnotation {
30+
override def toFirrtl: Annotation = DummyAnno(sram.underlying.get.toTarget)
31+
})
32+
}
33+
val (chirrtlCircuit, annos) = getFirrtlAndAnnos(new Top)
34+
val chirrtl = chirrtlCircuit.serialize
35+
chirrtl should include("module Top :")
36+
chirrtl should include("smem sram_mem : UInt<8> [32]")
37+
chirrtl should include(
38+
"wire sram : { readPorts : { flip address : UInt<6>, flip enable : UInt<1>, data : UInt<8>}[0], writePorts : { flip address : UInt<6>, flip enable : UInt<1>, flip data : UInt<8>}[0], readwritePorts : { flip address : UInt<6>, flip enable : UInt<1>, flip isWrite : UInt<1>, readData : UInt<8>, flip writeData : UInt<8>}[1]}"
39+
)
40+
41+
val dummyAnno = annos.collectFirst { case DummyAnno(t) => (t.toString) }
42+
dummyAnno should be(Some("~Top|Top>sram_mem"))
43+
}
44+
45+
}

0 commit comments

Comments
 (0)