summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/Mem.scala
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/Mem.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/Mem.scala215
1 files changed, 215 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/Mem.scala b/chiselFrontend/src/main/scala/chisel3/Mem.scala
new file mode 100644
index 00000000..c64c0e35
--- /dev/null
+++ b/chiselFrontend/src/main/scala/chisel3/Mem.scala
@@ -0,0 +1,215 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, MemTransform}
+
+object Mem {
+ // scalastyle:off line.size.limit
+ @chiselRuntimeDeprecated
+ @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](t: T, size: BigInt)(implicit compileOptions: CompileOptions): Mem[T] = do_apply(size, t)(UnlocatableSourceInfo, compileOptions)
+
+ // scalastyle:off line.size.limit
+ @chiselRuntimeDeprecated
+ @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](t: T, size: Int)(implicit compileOptions: CompileOptions): Mem[T] = do_apply(size, t)(UnlocatableSourceInfo, compileOptions)
+
+ /** Creates a combinational/asynchronous-read, sequential/synchronous-write [[Mem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: BigInt, t: T): Mem[T] = macro MemTransform.apply[T]
+
+ /** Creates a combinational/asynchronous-read, sequential/synchronous-write [[Mem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: Int, t: T): Mem[T] = macro MemTransform.apply[T]
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: BigInt, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Mem[T] = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "memory type")
+ }
+ val mt = t.cloneTypeFull
+ val mem = new Mem(mt, size)
+ pushCommand(DefMemory(sourceInfo, mem, mt, size))
+ mem
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Mem[T] =
+ do_apply(BigInt(size), t)(sourceInfo, compileOptions)
+}
+
+sealed abstract class MemBase[T <: Data](t: T, val length: BigInt) extends HasId with NamedComponent with SourceInfoDoc {
+ // REVIEW TODO: make accessors (static/dynamic, read/write) combinations consistent.
+
+ /** Creates a read accessor into the memory with static addressing. See the
+ * class documentation of the memory for more detailed information.
+ */
+ def apply(x: BigInt): T = macro SourceInfoTransform.xArg
+
+ /** Creates a read accessor into the memory with static addressing. See the
+ * class documentation of the memory for more detailed information.
+ */
+ def apply(x: Int): T = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(idx: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ require(idx >= 0 && idx < length)
+ apply(idx.asUInt)
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(idx: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ do_apply(BigInt(idx))(sourceInfo, compileOptions)
+
+ /** Creates a read/write accessor into the memory with dynamic addressing.
+ * See the class documentation of the memory for more detailed information.
+ */
+ def apply(x: UInt): T = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(idx: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ makePort(sourceInfo, idx, MemPortDirection.INFER)
+
+ /** Creates a read accessor into the memory with dynamic addressing. See the
+ * class documentation of the memory for more detailed information.
+ */
+ def read(x: UInt): T = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_read(idx: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ makePort(sourceInfo, idx, MemPortDirection.READ)
+
+ /** Creates a write accessor into the memory.
+ *
+ * @param idx memory element index to write into
+ * @param data new data to write
+ */
+ def write(idx: UInt, data: T)(implicit compileOptions: CompileOptions): Unit = {
+ implicit val sourceInfo = UnlocatableSourceInfo
+ makePort(UnlocatableSourceInfo, idx, MemPortDirection.WRITE) := data
+ }
+
+ /** Creates a masked write accessor into the memory.
+ *
+ * @param idx memory element index to write into
+ * @param data new data to write
+ * @param mask write mask as a Seq of Bool: a write to the Vec element in
+ * memory is only performed if the corresponding mask index is true.
+ *
+ * @note this is only allowed if the memory's element data type is a Vec
+ */
+ def write(idx: UInt, data: T, mask: Seq[Bool]) (implicit evidence: T <:< Vec[_], compileOptions: CompileOptions): Unit = {
+ implicit val sourceInfo = UnlocatableSourceInfo
+ val accessor = makePort(sourceInfo, idx, MemPortDirection.WRITE).asInstanceOf[Vec[Data]]
+ val dataVec = data.asInstanceOf[Vec[Data]]
+ if (accessor.length != dataVec.length) {
+ Builder.error(s"Mem write data must contain ${accessor.length} elements (found ${dataVec.length})")
+ }
+ if (accessor.length != mask.length) {
+ Builder.error(s"Mem write mask must contain ${accessor.length} elements (found ${mask.length})")
+ }
+ for (((cond, port), datum) <- mask zip accessor zip dataVec)
+ when (cond) { port := datum }
+ }
+
+ private def makePort(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection)(implicit compileOptions: CompileOptions): T = {
+ requireIsHardware(idx, "memory port index")
+ val i = Vec.truncateIndex(idx, length)(sourceInfo, compileOptions)
+
+ val port = pushCommand(
+ DefMemPort(sourceInfo,
+ t.cloneTypeFull, Node(this), dir, i.ref, Builder.forcedClock.ref)
+ ).id
+ // Bind each element of port to being a MemoryPort
+ port.bind(MemoryPortBinding(Builder.forcedUserModule))
+ port
+ }
+}
+
+/** A combinational/asynchronous-read, sequential/synchronous-write memory.
+ *
+ * Writes take effect on the rising clock edge after the request. Reads are
+ * combinational (requests will return data on the same cycle).
+ * Read-after-write hazards are not an issue.
+ *
+ * @note when multiple conflicting writes are performed on a Mem element, the
+ * result is undefined (unlike Vec, where the last assignment wins)
+ */
+sealed class Mem[T <: Data] private (t: T, length: BigInt) extends MemBase(t, length)
+
+object SyncReadMem {
+ @chiselRuntimeDeprecated
+ @deprecated("SeqMem/SyncReadMem argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](t: T, size: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = do_apply(size, t)
+
+ @chiselRuntimeDeprecated
+ @deprecated("SeqMem/SyncReadMem argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](t: T, size: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = do_apply(size, t)
+
+ /** Creates a sequential/synchronous-read, sequential/synchronous-write [[SyncReadMem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: BigInt, t: T): SyncReadMem[T] = macro MemTransform.apply[T]
+
+ /** Creates a sequential/synchronous-read, sequential/synchronous-write [[SyncReadMem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: Int, t: T): SyncReadMem[T] = macro MemTransform.apply[T]
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: BigInt, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "memory type")
+ }
+ val mt = t.cloneTypeFull
+ val mem = new SyncReadMem(mt, size)
+ pushCommand(DefSeqMemory(sourceInfo, mem, mt, size))
+ mem
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] =
+ do_apply(BigInt(size), t)(sourceInfo, compileOptions)
+}
+
+/** A sequential/synchronous-read, sequential/synchronous-write memory.
+ *
+ * Writes take effect on the rising clock edge after the request. Reads return
+ * data on the rising edge after the request. Read-after-write behavior (when
+ * a read and write to the same address are requested on the same cycle) is
+ * undefined.
+ *
+ * @note when multiple conflicting writes are performed on a Mem element, the
+ * result is undefined (unlike Vec, where the last assignment wins)
+ */
+sealed class SyncReadMem[T <: Data] private (t: T, n: BigInt) extends MemBase[T](t, n) {
+ def read(x: UInt, en: Bool): T = macro SourceInfoTransform.xEnArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_read(addr: UInt, enable: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val a = Wire(UInt())
+ a := DontCare
+ var port: Option[T] = None
+ when (enable) {
+ a := addr
+ port = Some(read(a))
+ }
+ port.get
+ }
+}