Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SRAM API: Add a parameter to initialize the memory #3364

Merged
merged 8 commits into from
Jun 22, 2023
72 changes: 68 additions & 4 deletions src/main/scala/chisel3/util/SRAM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import chisel3._
import chisel3.internal.Builder
import chisel3.experimental.SourceInfo
import chisel3.internal.sourceinfo.{MemTransform, SourceInfoTransform}
import chisel3.util.experimental.loadMemoryFromFileInline
import scala.language.reflectiveCalls
import scala.language.experimental.macros

Expand Down Expand Up @@ -106,6 +107,34 @@ class SRAMInterface[T <: Data](

object SRAM {

/** Generates a [[SyncReadMem]] within the current module, connected to an explicit number
* of read, write, and read/write ports. This SRAM abstraction has both read and write capabilities: that is,
* it contains at least one read accessor (a read-only or read-write port), and at least one write accessor
* (a write-only or read-write port).
*
* @param size The desired size of the inner `SyncReadMem`
* @tparam T The data type of the memory element
* @param numReadPorts The number of desired read ports >= 0, and (numReadPorts + numReadwritePorts) > 0
* @param numWritePorts The number of desired write ports >= 0, and (numWritePorts + numReadwritePorts) > 0
* @param numReadwritePorts The number of desired read/write ports >= 0, and the above two conditions must hold
* @param contents A filesystem path to a binary file to preload this SRAM's contents with
jared-barocsi marked this conversation as resolved.
Show resolved Hide resolved
*
* @return A new `SRAMInterface` wire containing the control signals for each instantiated port
* @note This does *not* return the `SyncReadMem` itself, you must interact with it using the returned bundle
* @note Read-only memories (R >= 1, W === 0, RW === 0) and write-only memories (R === 0, W >= 1, RW === 0) are not supported by this API, and will result in an error if declared.
*/
def apply[T <: Data](
size: BigInt,
tpe: T,
numReadPorts: Int,
numWritePorts: Int,
numReadwritePorts: Int,
contents: Option[String] = None
jared-barocsi marked this conversation as resolved.
Show resolved Hide resolved
)(
implicit sourceInfo: SourceInfo
): SRAMInterface[T] =
memInterface_impl(size, tpe)(numReadPorts, numWritePorts, numReadwritePorts, Builder.forcedClock, contents)

/** Generates a [[SyncReadMem]] within the current module, connected to an explicit number
* of read, write, and read/write ports. This SRAM abstraction has both read and write capabilities: that is,
* it contains at least one read accessor (a read-only or read-write port), and at least one write accessor
Expand All @@ -130,7 +159,7 @@ object SRAM {
)(
implicit sourceInfo: SourceInfo
): SRAMInterface[T] =
memInterface_impl(size, tpe)(numReadPorts, numWritePorts, numReadwritePorts, Builder.forcedClock)
memInterface_impl(size, tpe)(numReadPorts, numWritePorts, numReadwritePorts, Builder.forcedClock, None)

/** Generates a [[SyncReadMem]] within the current module, connected to an explicit number
* of read, write, and read/write ports, with masking capability on all write and read/write ports.
Expand All @@ -157,15 +186,45 @@ object SRAM {
implicit evidence: T <:< Vec[_],
sourceInfo: SourceInfo
): SRAMInterface[T] =
masked_memInterface_impl(size, tpe)(numReadPorts, numWritePorts, numReadwritePorts, Builder.forcedClock)
masked_memInterface_impl(size, tpe)(numReadPorts, numWritePorts, numReadwritePorts, Builder.forcedClock, None)

/** Generates a [[SyncReadMem]] within the current module, connected to an explicit number
* of read, write, and read/write ports, with masking capability on all write and read/write ports.
* This SRAM abstraction has both read and write capabilities: that is, it contains at least one read
* accessor (a read-only or read-write port), and at least one write accessor (a write-only or read-write port).
*
* @param size The desired size of the inner `SyncReadMem`
* @tparam T The data type of the memory element
* @param numReadPorts The number of desired read ports >= 0, and (numReadPorts + numReadwritePorts) > 0
* @param numWritePorts The number of desired write ports >= 0, and (numWritePorts + numReadwritePorts) > 0
* @param numReadwritePorts The number of desired read/write ports >= 0, and the above two conditions must hold
* @param contents A filesystem path to a binary file to preload this SRAM's contents with
*
* @return A new `SRAMInterface` wire containing the control signals for each instantiated port
* @note This does *not* return the `SyncReadMem` itself, you must interact with it using the returned bundle
* @note Read-only memories (R >= 1, W === 0, RW === 0) and write-only memories (R === 0, W >= 1, RW === 0) are not supported by this API, and will result in an error if declared.
*/
def masked[T <: Data](
size: BigInt,
tpe: T,
numReadPorts: Int,
numWritePorts: Int,
numReadwritePorts: Int,
contents: Option[String] = None
)(
implicit evidence: T <:< Vec[_],
sourceInfo: SourceInfo
): SRAMInterface[T] =
masked_memInterface_impl(size, tpe)(numReadPorts, numWritePorts, numReadwritePorts, Builder.forcedClock, contents)

private def memInterface_impl[T <: Data](
size: BigInt,
tpe: T
)(numReadPorts: Int,
numWritePorts: Int,
numReadwritePorts: Int,
clock: Clock
clock: Clock,
contents: Option[String]
)(
implicit sourceInfo: SourceInfo
): SRAMInterface[T] = {
Expand Down Expand Up @@ -205,6 +264,8 @@ object SRAM {
)
}

contents.map { path: String => loadMemoryFromFileInline(mem, path) }

_out
}

Expand All @@ -214,7 +275,8 @@ object SRAM {
)(numReadPorts: Int,
numWritePorts: Int,
numReadwritePorts: Int,
clock: Clock
clock: Clock,
contents: Option[String]
)(
implicit sourceInfo: SourceInfo,
evidence: T <:< Vec[_]
Expand Down Expand Up @@ -261,6 +323,8 @@ object SRAM {
)
}

contents.map { path: String => loadMemoryFromFileInline(mem, path) }

_out
}

Expand Down