aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/resources/features/Printf.fir16
-rw-r--r--src/test/resources/top.cpp88
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala6
-rw-r--r--src/test/scala/firrtlTests/StringSpec.scala113
4 files changed, 220 insertions, 3 deletions
diff --git a/src/test/resources/features/Printf.fir b/src/test/resources/features/Printf.fir
new file mode 100644
index 00000000..d0c1c775
--- /dev/null
+++ b/src/test/resources/features/Printf.fir
@@ -0,0 +1,16 @@
+circuit Top :
+ module Top :
+ input clk : Clock
+ input reset : UInt<1>
+
+ reg count : UInt<10>, clk with :
+ reset => (reset, UInt<6>(0))
+ reg const : UInt<32> clk with :
+ reset => (reset, UInt(123456))
+
+ node notReset = not(reset)
+ count <= add(count, UInt(1))
+ printf(clk, notReset, "\tcount = %d 0x%x b%b\\\'%d%%\'\n", count, count, count, const)
+
+ when eq(count, UInt(255)) :
+ stop(clk, UInt(1), 0)
diff --git a/src/test/resources/top.cpp b/src/test/resources/top.cpp
new file mode 100644
index 00000000..8bfe2a99
--- /dev/null
+++ b/src/test/resources/top.cpp
@@ -0,0 +1,88 @@
+#include <verilated.h>
+#include <iostream>
+
+#if VM_TRACE
+# include <verilated_vcd_c.h> // Trace file format header
+#endif
+
+using namespace std;
+
+//VGCDTester *top;
+TOP_TYPE *top;
+
+vluint64_t main_time = 0; // Current simulation time
+ // This is a 64-bit integer to reduce wrap over issues and
+ // allow modulus. You can also use a double, if you wish.
+
+double sc_time_stamp () { // Called by $time in Verilog
+ return main_time; // converts to double, to match
+ // what SystemC does
+}
+
+// TODO Provide command-line options like vcd filename, timeout count, etc.
+const long timeout = 100000000L;
+
+int main(int argc, char** argv) {
+ Verilated::commandArgs(argc, argv); // Remember args
+ top = new TOP_TYPE;
+
+#if VM_TRACE // If verilator was invoked with --trace
+ Verilated::traceEverOn(true); // Verilator must compute traced signals
+ VL_PRINTF("Enabling waves...\n");
+ VerilatedVcdC* tfp = new VerilatedVcdC;
+ top->trace (tfp, 99); // Trace 99 levels of hierarchy
+ tfp->open ("dump.vcd"); // Open the dump file
+#endif
+
+
+ top->reset = 1;
+
+ cout << "Starting simulation!\n";
+
+ while (!Verilated::gotFinish() && main_time < timeout) {
+ if (main_time > 10) {
+ top->reset = 0; // Deassert reset
+ }
+ if ((main_time % 10) == 1) {
+ top->clk = 1; // Toggle clock
+ }
+ if ((main_time % 10) == 6) {
+ top->clk = 0;
+ }
+ top->eval(); // Evaluate model
+#if VM_TRACE
+ if (tfp) tfp->dump (main_time); // Create waveform trace for this timestamp
+#endif
+ main_time++; // Time passes...
+ }
+
+ if (main_time >= timeout) {
+ cout << "Simulation terminated by timeout at time " << main_time <<
+ " (cycle " << main_time / 10 << ")"<< endl;
+ return -1;
+ } else {
+ cout << "Simulation completed at time " << main_time <<
+ " (cycle " << main_time / 10 << ")"<< endl;
+ }
+
+ // Run for 10 more clocks
+ vluint64_t end_time = main_time + 100;
+ while (main_time < end_time) {
+ if ((main_time % 10) == 1) {
+ top->clk = 1; // Toggle clock
+ }
+ if ((main_time % 10) == 6) {
+ top->clk = 0;
+ }
+ top->eval(); // Evaluate model
+#if VM_TRACE
+ if (tfp) tfp->dump (main_time); // Create waveform trace for this timestamp
+#endif
+ main_time++; // Time passes...
+ }
+
+#if VM_TRACE
+ if (tfp) tfp->close();
+#endif
+}
+
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
index 438a5282..a8ccb0a9 100644
--- a/src/test/scala/firrtlTests/FirrtlSpec.scala
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -90,7 +90,7 @@ trait BackendCompilationUtilities {
val e = Process(s"./V${prefix}", dir) !
ProcessLogger(line => {
triggered = triggered || line.contains(assertionMsg)
- System.out.println(line)
+ //System.out.println(line)
})
triggered
}
@@ -101,7 +101,7 @@ trait BackendCompilationUtilities {
}
trait FirrtlRunners extends BackendCompilationUtilities {
- lazy val cpp = new File(s"/integration/top.cpp")
+ lazy val cppHarness = new File(s"/top.cpp")
def compileFirrtlTest(prefix: String, srcDir: String): File = {
val testDir = createTempDirectory(prefix)
copyResourceToFile(s"${srcDir}/${prefix}.fir", new File(testDir, s"${prefix}.fir"))
@@ -112,7 +112,7 @@ trait FirrtlRunners extends BackendCompilationUtilities {
def runFirrtlTest(prefix: String, srcDir: String) {
val testDir = compileFirrtlTest(prefix, srcDir)
val harness = new File(testDir, s"top.cpp")
- copyResourceToFile(cpp.toString, harness)
+ copyResourceToFile(cppHarness.toString, harness)
verilogToCpp(prefix, testDir, Seq(), harness).!
cppToExe(prefix, testDir).!
diff --git a/src/test/scala/firrtlTests/StringSpec.scala b/src/test/scala/firrtlTests/StringSpec.scala
new file mode 100644
index 00000000..2278a147
--- /dev/null
+++ b/src/test/scala/firrtlTests/StringSpec.scala
@@ -0,0 +1,113 @@
+
+package firrtlTests
+
+import firrtl._
+
+import java.io._
+
+import scala.sys.process._
+import org.scalatest._
+import org.scalatest.prop._
+import org.scalatest.Assertions._
+import org.scalacheck._
+
+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(cppHarness.toString, harness)
+
+ verilogToCpp(prefix, testDir, Seq(), harness).!
+ cppToExe(prefix, testDir).!
+
+ // 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{|}~"""
+ val whitelistBA: Array[Byte] = Array.range(0x20, 0x7e) map (_.toByte)
+
+ property(s"Character whitelist should be supported: [$whitelist] ") {
+ val lit = firrtl.FIRRTLStringLitHandler.unescape(whitelist)
+ // Check internal
+ lit.array zip whitelistBA foreach { case (b, e) =>
+ assert(b == e, s"(${b.toChar} did not equal expected ${e.toChar})")
+ }
+ // Check result
+ assert(lit.serialize == whitelist)
+ }
+
+ // Valid escapes = \n, \t, \\, \", \'
+ val esc = """\\\'\"\t\n"""
+ val validEsc = Seq('n', 't', '\\', '"', '\'')
+ property(s"Escape characters [$esc] should parse") {
+ val lit = firrtl.FIRRTLStringLitHandler.unescape(esc)
+ assert(lit.array(0) == 0x5c)
+ assert(lit.array(1) == 0x27)
+ assert(lit.array(2) == 0x22)
+ assert(lit.array(3) == 0x09)
+ assert(lit.array(4) == 0x0a)
+ assert(lit.array.length == 5)
+ }
+
+ // Generators for random testing
+ val validChar = for (c <- Gen.choose(0x20.toChar, 0x7e.toChar) if c != '\\') yield c
+ val validCharSeq = Gen.containerOf[Seq, Char](validChar)
+ val invalidChar = Gen.oneOf(Gen.choose(0x00.toChar, 0x1f.toChar),
+ Gen.choose(0x7f.toChar, 0xff.toChar))
+ val invalidEsc = for (
+ c <- Gen.choose(0x00.toChar, 0xff.toChar
+ ) if (!validEsc.contains(c))) yield c
+
+ property("Random invalid strings should fail") {
+ forAll(validCharSeq, invalidChar, validCharSeq) {
+ (head: Seq[Char], bad: Char, tail: Seq[Char]) =>
+ val str = ((head :+ bad) ++ tail).mkString
+ intercept[InvalidStringLitException] {
+ firrtl.FIRRTLStringLitHandler.unescape(str)
+ }
+ }
+ }
+
+ property(s"Invalid escape characters should fail") {
+ forAll(validCharSeq, invalidEsc, validCharSeq) {
+ (head: Seq[Char], badEsc: Char, tail: Seq[Char]) =>
+ val str = (head ++ Seq('\\', badEsc) ++ tail).mkString
+ intercept[InvalidEscapeCharException] {
+ firrtl.FIRRTLStringLitHandler.unescape(str)
+ }
+ }
+ }
+}