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
|
// See LICENSE for license details.
package firrtlTests
import org.scalatest._
import firrtl._
import org.scalacheck.Gen
import org.scalacheck.Prop.forAll
class ParserSpec extends FirrtlFlatSpec {
private object MemTests {
val prelude = Seq("circuit top :", " module top :", " mem m : ")
val fields = Map("data-type" -> "UInt<32>",
"depth" -> "4",
"read-latency" -> "1",
"write-latency" -> "1",
"reader" -> "a",
"writer" -> "b",
"readwriter" -> "c"
)
def fieldsToSeq(m: Map[String, String]): Seq[String] =
m map { case (k,v) => s" ${k} => ${v}" } toSeq
}
private object RegTests {
val prelude = Seq("circuit top :", " module top :")
val reg = " reg r : UInt<32>, clock"
val reset = "reset => (radReset, UInt(\"hdeadbeef\"))"
}
private object KeywordTests {
val prelude = Seq("circuit top :", " module top :")
val keywords = Seq("circuit", "module", "extmodule", "parameter", "input", "output", "UInt",
"SInt", "Analog", "Fixed", "flip", "Clock", "wire", "reg", "reset", "with", "mem", "depth",
"reader", "writer", "readwriter", "inst", "of", "node", "is", "invalid", "when", "else",
"stop", "printf", "skip", "old", "new", "undefined", "mux", "validif", "cmem", "smem",
"mport", "infer", "read", "write", "rdwr") ++ PrimOps.listing
}
// ********** Memories **********
"Memories" should "allow arbitrary ordering of fields" in {
val fields = MemTests.fieldsToSeq(MemTests.fields)
val golden = firrtl.Parser.parse((MemTests.prelude ++ fields))
fields.permutations foreach { permutation =>
val circuit = firrtl.Parser.parse((MemTests.prelude ++ permutation))
assert(golden === circuit)
}
}
it should "have exactly one of each: data-type, depth, read-latency, and write-latency" in {
import MemTests._
def parseWithoutField(s: String) = firrtl.Parser.parse((prelude ++ fieldsToSeq(fields - s)))
def parseWithDuplicate(k: String, v: String) =
firrtl.Parser.parse((prelude ++ fieldsToSeq(fields) :+ s" ${k} => ${v}"))
Seq("data-type", "depth", "read-latency", "write-latency") foreach { field =>
evaluating { parseWithoutField(field) } should produce [ParameterNotSpecifiedException]
evaluating { parseWithDuplicate(field, fields(field)) } should produce [ParameterRedefinedException]
}
}
// ********** Registers **********
"Registers" should "allow no implicit reset" in {
import RegTests._
firrtl.Parser.parse((prelude :+ reg))
}
it should "allow same-line reset" in {
import RegTests._
firrtl.Parser.parse((prelude :+ s"${reg} with : (${reset})" :+ " wire a : UInt"))
}
it should "allow multi-line reset" in {
import RegTests._
firrtl.Parser.parse((prelude :+ s"${reg} with :\n (${reset})"))
}
// ********** Keywords **********
"Keywords" should "be allowed as Ids" in {
import KeywordTests._
keywords foreach { keyword =>
firrtl.Parser.parse((prelude :+ s" wire ${keyword} : UInt"))
}
}
it should "be allowed on lhs in connects" in {
import KeywordTests._
keywords foreach { keyword =>
firrtl.Parser.parse((prelude ++ Seq(s" wire ${keyword} : UInt",
s" ${keyword} <= ${keyword}")))
}
}
}
class ParserPropSpec extends FirrtlPropSpec {
// Disable shrinking on error.
import org.scalacheck.Shrink
implicit val noShrinkString = Shrink[String](_ => Stream.empty)
def legalStartChar = Gen.frequency((1, '_'), (20, Gen.alphaChar))
def legalChar = Gen.frequency((1, Gen.numChar), (1, '$'), (10, legalStartChar))
def identifier = for {
x <- legalStartChar
xs <- Gen.listOf(legalChar)
} yield (x :: xs).mkString
property("Identifiers should allow [A-Za-z0-9_$] but not allow starting with a digit or $") {
forAll (identifier) { id =>
whenever(id.nonEmpty) {
val input = s"""
|circuit Test :
| module Test :
| input $id : UInt<32>
|""".stripMargin
firrtl.Parser.parse(input split "\n")
}
}
}
def bundleField = for {
xs <- Gen.nonEmptyListOf(legalChar)
} yield xs.mkString
property("Bundle fields should allow [A-Za-z0-9_] including starting with a digit or $") {
forAll (identifier, bundleField) { case (id, field) =>
whenever(id.nonEmpty && field.nonEmpty) {
val input = s"""
|circuit Test :
| module Test :
| input $id : { $field : UInt<32> }
|""".stripMargin
firrtl.Parser.parse(input split "\n")
}
}
}
}
|