1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
// SPDX-License-Identifier: Apache-2.0
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
|