diff options
| author | Albert Magyar | 2019-10-16 01:43:56 -0700 |
|---|---|---|
| committer | Albert Magyar | 2019-10-21 10:02:46 -0700 |
| commit | 24f7d90b032f7058ae379ff3592c9d29c7f987e7 (patch) | |
| tree | 0933b15baca7520faf5aae0f9e1fc60bb36390d4 /src/test | |
| parent | 24df1cdcc0981f6e32662a42fe01135681db18c4 (diff) | |
Add tests for memories with latency >1, toggling enables
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/scala/firrtlTests/MemLatencySpec.scala | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/test/scala/firrtlTests/MemLatencySpec.scala b/src/test/scala/firrtlTests/MemLatencySpec.scala new file mode 100644 index 00000000..79986cc2 --- /dev/null +++ b/src/test/scala/firrtlTests/MemLatencySpec.scala @@ -0,0 +1,130 @@ +package firrtlTests + +import firrtlTests.execution._ + +object MemLatencySpec { + case class Write(addr: Int, data: Int, mask: Option[Boolean] = None) + case class Read(addr: Int, expectedValue: Int) + case class MemAccess(w: Option[Write], r: Option[Read]) + def writeOnly(addr: Int, data: Int) = MemAccess(Some(Write(addr, data)), None) + def readOnly(addr: Int, expectedValue: Int) = MemAccess(None, Some(Read(addr, expectedValue))) +} + +abstract class MemLatencySpec(rLatency: Int, wLatency: Int, ruw: String) + extends SimpleExecutionTest + with VerilogExecution { + + import MemLatencySpec._ + + require(rLatency >= 0, s"Illegal read-latency ${rLatency} supplied to MemLatencySpec") + require(wLatency > 0, s"Illegal write-latency ${wLatency} supplied to MemLatencySpec") + + val body = + s"""mem m : + | data-type => UInt<32> + | depth => 256 + | reader => r + | writer => w + | read-latency => ${rLatency} + | write-latency => ${wLatency} + | read-under-write => ${ruw} + |m.r.clk <= clock + |m.w.clk <= clock + |""".stripMargin + + val memAccesses: Seq[MemAccess] + + def mask2Poke(m: Option[Boolean]) = m match { + case Some(false) => Poke("m.w.mask", 0) + case _ => Poke("m.w.mask", 1) + } + + def wPokes = memAccesses.map { + case MemAccess(Some(Write(a, d, m)), _) => + Seq(Poke("m.w.en", 1), Poke("m.w.addr", a), Poke("m.w.data", d), mask2Poke(m)) + case _ => Seq(Poke("m.w.en", 0), Invalidate("m.w.addr"), Invalidate("m.w.data")) + } + + def rPokes = memAccesses.map { + case MemAccess(_, Some(Read(a, _))) => Seq(Poke("m.r.en", 1), Poke("m.r.addr", a)) + case _ => Seq(Poke("m.r.en", 0), Invalidate("m.r.addr")) + } + + // Need to idle for <rLatency> cycles at the end + val idle = Seq(Poke("m.w.en", 0), Poke("m.r.en", 0)) + def pokes = (wPokes zip rPokes).map { case (wp, rp) => wp ++ rp } ++ Seq.fill(rLatency)(idle) + + // Need to delay read value expects by <rLatency> + def expects = Seq.fill(rLatency)(Seq(Step(1))) ++ memAccesses.map { + case MemAccess(_, Some(Read(_, expected))) => Seq(Expect("m.r.data", expected), Step(1)) + case _ => Seq(Step(1)) + } + + def commands: Seq[SimpleTestCommand] = (pokes zip expects).flatMap { case (p, e) => p ++ e } +} + +trait ToggleMaskAndEnable { + import MemLatencySpec._ + /** + * A canonical sequence of memory accesses for sanity checking memories of different latencies. + * The shortest true "RAW" hazard is reading address 14 two accesses after writing it. Since this + * access assumed the new value of 87, this means that the access pattern is only valid for + * certain combinations of read- and write-latencies that vary between read- and write-first + * memories. + * + * @note Read-first mems should return expected values for (write-latency <= 2) + * @note Write-first mems should return expected values for (write-latency <= read-latency + 2) + */ + val memAccesses: Seq[MemAccess] = Seq( + MemAccess(Some(Write(6, 32)), None), + MemAccess(Some(Write(14, 87)), None), + MemAccess(None, None), + MemAccess(Some(Write(19, 63)), Some(Read(14, 87))), + MemAccess(Some(Write(22, 49)), None), + MemAccess(Some(Write(11, 99)), Some(Read(6, 32))), + MemAccess(Some(Write(42, 42)), None), + MemAccess(Some(Write(77, 81)), None), + MemAccess(Some(Write(6, 7)), Some(Read(19, 63))), + MemAccess(Some(Write(39, 5)), Some(Read(42, 42))), + MemAccess(Some(Write(39, 6, Some(false))), Some(Read(77, 81))), // set mask to zero, should not write + MemAccess(None, Some(Read(6, 7))), // also read a twice-written address + MemAccess(None, Some(Read(39, 5))) // ensure masked writes didn't happen + ) +} + +/* + * This framework is for execution tests, so these tests all focus on + * *legal* configurations. Illegal memory parameters that should + * result in errors should be tested in MemSpec. + */ + +// These two are the same in practice, but the two tests could help expose bugs in VerilogMemDelays +class CombMemSpecNewRUW extends MemLatencySpec(rLatency = 0, wLatency = 1, ruw = "new") with ToggleMaskAndEnable +class CombMemSpecOldRUW extends MemLatencySpec(rLatency = 0, wLatency = 1, ruw = "old") with ToggleMaskAndEnable + +// Odd combination: combinational read with 2-cycle write latency +class CombMemWL2SpecNewRUW extends MemLatencySpec(rLatency = 0, wLatency = 2, ruw = "new") with ToggleMaskAndEnable +class CombMemWL2SpecOldRUW extends MemLatencySpec(rLatency = 0, wLatency = 2, ruw = "old") with ToggleMaskAndEnable + +// Standard sync read mem +class WriteFirstMemToggleSpec extends MemLatencySpec(rLatency = 1, wLatency = 1, ruw = "new") with ToggleMaskAndEnable +class ReadFirstMemToggleSpec extends MemLatencySpec(rLatency = 1, wLatency = 1, ruw = "old") with ToggleMaskAndEnable + +// Read latency 2 +class WriteFirstMemToggleSpecRL2 extends MemLatencySpec(rLatency = 2, wLatency = 1, ruw = "new") with ToggleMaskAndEnable +class ReadFirstMemToggleSpecRL2 extends MemLatencySpec(rLatency = 2, wLatency = 1, ruw = "old") with ToggleMaskAndEnable + +// Write latency 2 +class WriteFirstMemToggleSpecWL2 extends MemLatencySpec(rLatency = 1, wLatency = 2, ruw = "new") with ToggleMaskAndEnable +class ReadFirstMemToggleSpecWL2 extends MemLatencySpec(rLatency = 1, wLatency = 2, ruw = "old") with ToggleMaskAndEnable + +// Read latency 2, write latency 2 +class WriteFirstMemToggleSpecRL2WL2 extends MemLatencySpec(rLatency = 2, wLatency = 2, ruw = "new") with ToggleMaskAndEnable +class ReadFirstMemToggleSpecRL2WL2 extends MemLatencySpec(rLatency = 2, wLatency = 2, ruw = "old") with ToggleMaskAndEnable + +// Read latency 3, write latency 2 +class WriteFirstMemToggleSpecRL3WL2 extends MemLatencySpec(rLatency = 3, wLatency = 2, ruw = "new") with ToggleMaskAndEnable +class ReadFirstMemToggleSpecRL3WL2 extends MemLatencySpec(rLatency = 3, wLatency = 2, ruw = "old") with ToggleMaskAndEnable + +// Read latency 2, write latency 4 -> ToggleSpec pattern only valid for write-first at this combo +class WriteFirstMemToggleSpecRL2WL4 extends MemLatencySpec(rLatency = 2, wLatency = 4, ruw = "new") with ToggleMaskAndEnable |
