summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Magyar2020-02-03 13:42:39 -0700
committerGitHub2020-02-03 13:42:39 -0700
commit509895c428f73b1c47e018df33e6cb64834e6e94 (patch)
treee2912c1c7528df820fe9163272397edd7efa1259
parent4f1f638663a7176ac28d95d71c14a37021314c3b (diff)
Add read-under-write parameter to SyncReadMem (#1183)
* Add support for readUnderWrite to SyncReadMem * Add write collision behavior test to MemorySpec * Update constant names
-rw-r--r--chiselFrontend/src/main/scala/chisel3/Mem.scala25
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala4
-rw-r--r--coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala3
-rw-r--r--src/main/scala/chisel3/internal/firrtl/Emitter.scala2
-rw-r--r--src/test/scala/chiselTests/Mem.scala28
6 files changed, 58 insertions, 8 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/Mem.scala b/chiselFrontend/src/main/scala/chisel3/Mem.scala
index 7fbbaefd..24ab4b8e 100644
--- a/chiselFrontend/src/main/scala/chisel3/Mem.scala
+++ b/chiselFrontend/src/main/scala/chisel3/Mem.scala
@@ -4,11 +4,14 @@ package chisel3
import scala.language.experimental.macros
+import firrtl.{ir => fir}
+
import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, MemTransform}
+
object Mem {
/** Creates a combinational/asynchronous-read, sequential/synchronous-write [[Mem]].
@@ -142,12 +145,19 @@ sealed class Mem[T <: Data] private (t: T, length: BigInt) extends MemBase(t, le
object SyncReadMem {
+
+ type ReadUnderWrite = fir.ReadUnderWrite.Value
+ val Undefined = fir.ReadUnderWrite.Undefined
+ val ReadFirst = fir.ReadUnderWrite.Old
+ val WriteFirst = fir.ReadUnderWrite.New
+
/** 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]
+ def apply[T <: Data](size: BigInt, t: T, ruw: ReadUnderWrite): SyncReadMem[T] = macro MemTransform.apply_ruw[T]
/** Creates a sequential/synchronous-read, sequential/synchronous-write [[SyncReadMem]].
*
@@ -155,21 +165,28 @@ object SyncReadMem {
* @param t data type of memory element
*/
def apply[T <: Data](size: Int, t: T): SyncReadMem[T] = macro MemTransform.apply[T]
+ def apply[T <: Data](size: Int, t: T, ruw: ReadUnderWrite): SyncReadMem[T] = macro MemTransform.apply_ruw[T]
/** @group SourceInfoTransformMacro */
- def do_apply[T <: Data](size: BigInt, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = {
+ def do_apply[T <: Data](size: BigInt, t: T, ruw: ReadUnderWrite = Undefined)(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))
+ val mem = new SyncReadMem(mt, size, ruw)
+ pushCommand(DefSeqMemory(sourceInfo, mem, mt, size, ruw))
mem
}
/** @group SourceInfoTransformMacro */
+ // Alternate signatures can't use default parameter values
def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] =
do_apply(BigInt(size), t)(sourceInfo, compileOptions)
+
+ /** @group SourceInfoTransformMacro */
+ // Alternate signatures can't use default parameter values
+ def do_apply[T <: Data](size: Int, t: T, ruw: ReadUnderWrite)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] =
+ do_apply(BigInt(size), t, ruw)(sourceInfo, compileOptions)
}
/** A sequential/synchronous-read, sequential/synchronous-write memory.
@@ -182,7 +199,7 @@ object SyncReadMem {
* @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) {
+sealed class SyncReadMem[T <: Data] private (t: T, n: BigInt, val readUnderWrite: SyncReadMem.ReadUnderWrite) extends MemBase[T](t, n) {
def read(x: UInt, en: Bool): T = macro SourceInfoTransform.xEnArg
/** @group SourceInfoTransformMacro */
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
index 548ed294..5c1d6935 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -106,8 +106,8 @@ private[chisel3] object Converter {
convert(reset, ctx), convert(init, ctx)))
case e @ DefMemory(info, id, t, size) =>
Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, false))
- case e @ DefSeqMemory(info, id, t, size) =>
- Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, true))
+ case e @ DefSeqMemory(info, id, t, size, ruw) =>
+ Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, true, ruw))
case e: DefMemPort[_] =>
Some(firrtl.CDefMPort(convert(e.sourceInfo), e.name, fir.UnknownType,
e.source.fullName(ctx), Seq(convert(e.index, ctx), convert(e.clock, ctx)), convert(e.dir)))
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
index e76a8d60..a16d84bb 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -2,6 +2,8 @@
package chisel3.internal.firrtl
+import firrtl.{ir => fir}
+
import chisel3._
import chisel3.internal._
import chisel3.internal.sourceinfo.SourceInfo
@@ -721,7 +723,7 @@ case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition
case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition
case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition
case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition
-case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition
+case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition
case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition
case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition
case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command
diff --git a/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
index d38396f4..6d7c3411 100644
--- a/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
+++ b/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
@@ -53,6 +53,9 @@ class MemTransform(val c: Context) extends SourceInfoTransformMacro {
def apply[T: c.WeakTypeTag](size: c.Tree, t: c.Tree): c.Tree = {
q"$thisObj.do_apply($size, $t)($implicitSourceInfo, $implicitCompileOptions)"
}
+ def apply_ruw[T: c.WeakTypeTag](size: c.Tree, t: c.Tree, ruw: c.Tree): c.Tree = {
+ q"$thisObj.do_apply($size, $t, $ruw)($implicitSourceInfo, $implicitCompileOptions)"
+ }
}
// Workaround for https://github.com/sbt/sbt/issues/3966
diff --git a/src/main/scala/chisel3/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
index 3409ce94..1341b5f6 100644
--- a/src/main/scala/chisel3/internal/firrtl/Emitter.scala
+++ b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
@@ -69,7 +69,7 @@ private class Emitter(circuit: Circuit) {
case e: DefReg => s"reg ${e.name} : ${emitType(e.id)}, ${e.clock.fullName(ctx)}"
case e: DefRegInit => s"reg ${e.name} : ${emitType(e.id)}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))" // scalastyle:ignore line.size.limit
case e: DefMemory => s"cmem ${e.name} : ${emitType(e.t)}[${e.size}]"
- case e: DefSeqMemory => s"smem ${e.name} : ${emitType(e.t)}[${e.size}]"
+ case e: DefSeqMemory => s"smem ${e.name} : ${emitType(e.t)}[${e.size}], ${e.readUnderWrite}"
case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}" // scalastyle:ignore line.size.limit
case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}"
case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}"
diff --git a/src/test/scala/chiselTests/Mem.scala b/src/test/scala/chiselTests/Mem.scala
index ebdb1483..49085f9b 100644
--- a/src/test/scala/chiselTests/Mem.scala
+++ b/src/test/scala/chiselTests/Mem.scala
@@ -33,6 +33,30 @@ class SyncReadMemTester extends BasicTester {
}
}
+class SyncReadMemWriteCollisionTester extends BasicTester {
+ val (cnt, _) = Counter(true.B, 5)
+
+ // Write-first
+ val m0 = SyncReadMem(2, UInt(2.W), SyncReadMem.WriteFirst)
+ val rd0 = m0.read(cnt)
+ m0.write(cnt, cnt)
+
+ // Read-first
+ val m1 = SyncReadMem(2, UInt(2.W), SyncReadMem.ReadFirst)
+ val rd1 = m1.read(cnt)
+ m1.write(cnt, cnt)
+
+ // Read data from address 0
+ when (cnt === 3.U) {
+ assert(rd0 === 2.U)
+ assert(rd1 === 0.U)
+ }
+
+ when (cnt === 4.U) {
+ stop()
+ }
+}
+
class SyncReadMemWithZeroWidthTester extends BasicTester {
val (cnt, _) = Counter(true.B, 3)
val mem = SyncReadMem(2, UInt(0.W))
@@ -81,6 +105,10 @@ class MemorySpec extends ChiselPropSpec {
assertTesterPasses { new SyncReadMemTester }
}
+ property("SyncReadMem write collision behaviors should work") {
+ assertTesterPasses { new SyncReadMemWriteCollisionTester }
+ }
+
property("SyncReadMem should work with zero width entry") {
assertTesterPasses { new SyncReadMemWithZeroWidthTester }
}