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
|
// SPDX-License-Identifier: Apache-2.0
package firrtlTests
import firrtl.ir.StringLit
import firrtl.testutils._
import java.io._
import scala.sys.process._
import annotation.tailrec
import org.scalacheck._
import org.scalacheck.Arbitrary._
class PrintfSpec extends FirrtlPropSpec {
property("Printf should correctly print values in each format %x, %d, %b") {
val prefix = "Printf"
val testDir = compileFirrtlTest(prefix, "/features")
val harness = new File(testDir, s"top.cpp")
copyResourceToFile(cppHarnessResourceName, harness)
verilogToCpp(prefix, testDir, Seq(), harness) #&&
cppToExe(prefix, testDir) ! loggingProcessLogger
// Check for correct Printf:
// Count up from 0, match decimal, hex, and binary
// see /features/Print.fir to see what we're matching
val regex = """\tcount\s+=\s+(\d+)\s+0x(\w+)\s+b([01]+).*""".r
var done = false
var expected = 0
var error = false
val ret = Process(s"./V${prefix}", testDir) !
ProcessLogger(line => {
line match {
case regex(dec, hex, bin) => {
if (!done) {
// Must mark error before assertion or sbt test will pass
if (Integer.parseInt(dec, 10) != expected) error = true
assert(Integer.parseInt(dec, 10) == expected)
if (Integer.parseInt(hex, 16) != expected) error = true
assert(Integer.parseInt(hex, 16) == expected)
if (Integer.parseInt(bin, 2) != expected) error = true
assert(Integer.parseInt(bin, 2) == expected)
expected += 1
}
}
case _ => // Do Nothing
}
})
if (error) fail()
}
}
class StringSpec extends FirrtlPropSpec {
// Whitelist is [0x20 - 0x7e]
val whitelist =
""" !\"#$%&\''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ""" +
"""[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"""
property(s"Character whitelist should be supported: [$whitelist] ") {
val lit = StringLit.unescape(whitelist)
// We accept \' but don't bother escaping it ourselves
val res = whitelist.replaceAll("""\\'""", "'")
// Check result
assert(lit.serialize == res)
assert(lit.verilogEscape.tail.init == res)
}
// Valid escapes = \n, \t, \\, \", \'
val esc = """\\\'\"\t\n"""
val validEsc = Seq('n', 't', '\\', '"', '\'')
property(s"Escape characters [$esc] should parse") {
val lit = StringLit.unescape(esc)
assert(lit.string(0).toByte == 0x5c)
assert(lit.string(1).toByte == 0x27)
assert(lit.string(2).toByte == 0x22)
assert(lit.string(3).toByte == 0x09)
assert(lit.string(4).toByte == 0x0a)
assert(lit.string.length == 5)
}
// From IEEE 1364-2001 2.6
def isValidVerilogString(str: String): Boolean = {
@tailrec def rec(xs: List[Char]): Boolean = xs match {
case Nil => true
case '\\' :: esc =>
if (Set('n', 't', '\\', '"').contains(esc.head)) rec(esc.tail)
else { // Check valid octal escape, otherwise illegal
val next3 = esc.take(3)
if (next3.size == 3 && next3.forall(('0' to '7').toSet.contains)) rec(esc.drop(3))
else false
}
case char :: tail => // Check Legal ASCII
if (char.toInt < 256 && char.toInt >= 0) rec(tail)
else false
}
rec(str.toList)
}
// From IEEE 1364-2001 17.1.1.2
val legalFormats = "HhDdOoBbCcLlVvMmSsTtUuZz%".toSet
def isValidVerilogFormat(str: String): Boolean = str.toSeq.sliding(2).forall {
case Seq('%', char) if legalFormats contains char => true
case _ => true
}
// Generators for legal Firrtl format strings
val genFormat = Gen.oneOf("bdxc%").map(List('%', _))
val genEsc = Gen.oneOf(esc.toSeq).map(List(_))
val genChar = arbitrary[Char].suchThat(c => (c != '%' && c != '\\')).map(List(_))
val genFragment = Gen.frequency((10, genChar), (1, genFormat), (1, genEsc)).map(_.mkString)
val genString = Gen.listOf[String](genFragment).map(_.mkString)
property("Firrtl Format Strings with Unicode chars should emit as legal Verilog Strings") {
forAll(genString) { str =>
val verilogStr = StringLit(str).verilogFormat.verilogEscape
assert(isValidVerilogString(verilogStr))
assert(isValidVerilogFormat(verilogStr))
}
}
}
|