summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/resources/top.cpp91
-rw-r--r--src/main/scala/Chisel/Aggregate.scala15
-rw-r--r--src/main/scala/Chisel/Driver.scala141
-rw-r--r--src/main/scala/Chisel/Module.scala40
-rw-r--r--src/main/scala/Chisel/Parameters.scala669
-rw-r--r--src/main/scala/Chisel/internal/Builder.scala10
-rw-r--r--src/main/scala/Chisel/ir/IR.scala2
-rw-r--r--src/main/scala/Chisel/testers/BasicTester.scala2
-rw-r--r--src/main/scala/Chisel/testers/Driver.scala21
-rw-r--r--src/main/scala/Chisel/testers/TesterDriver.scala37
-rw-r--r--src/test/scala/chiselTests/BitwiseOps.scala22
-rw-r--r--src/test/scala/chiselTests/BundleWire.scala16
-rw-r--r--src/test/scala/chiselTests/ChiselSpec.scala8
-rw-r--r--src/test/scala/chiselTests/ComplexAssign.scala28
-rw-r--r--src/test/scala/chiselTests/Counter.scala40
-rw-r--r--src/test/scala/chiselTests/Decoder.scala20
-rw-r--r--src/test/scala/chiselTests/GCD.scala26
-rw-r--r--src/test/scala/chiselTests/Harness.scala75
-rw-r--r--src/test/scala/chiselTests/MulLookup.scala16
-rw-r--r--src/test/scala/chiselTests/Tbl.scala30
-rw-r--r--src/test/scala/chiselTests/Vec.scala58
21 files changed, 438 insertions, 929 deletions
diff --git a/src/main/resources/top.cpp b/src/main/resources/top.cpp
new file mode 100644
index 00000000..8951032e
--- /dev/null
+++ b/src/main/resources/top.cpp
@@ -0,0 +1,91 @@
+#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) {
+ vluint32_t done = 0;
+ 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() && !done && main_time < timeout) {
+ if (main_time > 10) {
+ top->reset = 0; // Deassert reset
+ }
+ if ((main_time % 10) == 1) {
+ top->clock = 1; // Toggle clock
+ }
+ if ((main_time % 10) == 6) {
+ top->clock = 0;
+ }
+ top->eval(); // Evaluate model
+#if VM_TRACE
+ if (tfp) tfp->dump (main_time); // Create waveform trace for this timestamp
+#endif
+ done = top->io__024done;
+ main_time++; // Time passes...
+ }
+
+ // Run for 10 more clocks
+ vluint64_t end_time = main_time + 100;
+ while (main_time < end_time) {
+ if ((main_time % 10) == 1) {
+ top->clock = 1; // Toggle clock
+ }
+ if ((main_time % 10) == 6) {
+ top->clock = 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
+
+ if (main_time >= timeout)
+ cout << "Simulation terminated by timeout at cycle " << main_time << endl;
+ else
+ cout << "Simulation completed at cycle " << main_time << endl;
+
+ int error = top->io__024error;
+ cout << "Simulation return value: " << error << endl;
+
+ return error;
+}
+
diff --git a/src/main/scala/Chisel/Aggregate.scala b/src/main/scala/Chisel/Aggregate.scala
index 07362b9b..e6ac6b85 100644
--- a/src/main/scala/Chisel/Aggregate.scala
+++ b/src/main/scala/Chisel/Aggregate.scala
@@ -313,17 +313,6 @@ class Bundle extends Aggregate(NO_DIR) {
}
}
-object Bundle {
- private val keywords =
- HashSet[String]("flip", "asInput", "asOutput", "cloneType", "toBits")
-
- def apply[T <: Bundle](b: => T)(implicit p: Parameters): T = {
- Builder.paramsScope(p.push){ b }
- }
-
- //TODO @deprecated("Use Chisel.paramsScope object","08-01-2015")
- def apply[T <: Bundle](b: => T, f: PartialFunction[Any,Any]): T = {
- val q = Builder.getParams.alterPartial(f)
- apply(b)(q)
- }
+private[Chisel] object Bundle {
+ val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits")
}
diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala
index 5247dc0f..64356b21 100644
--- a/src/main/scala/Chisel/Driver.scala
+++ b/src/main/scala/Chisel/Driver.scala
@@ -2,75 +2,100 @@
package Chisel
-import collection.mutable.{ArrayBuffer, HashSet, HashMap, Stack, LinkedHashSet, Queue => ScalaQueue}
-import scala.math.min
+import scala.sys.process._
+import java.io._
trait FileSystemUtilities {
- def createOutputFile(name: String, contents: String) {
- val f = new java.io.FileWriter(name)
- f.write(contents)
- f.close
+ def writeTempFile(pre: String, post: String, contents: String): File = {
+ val t = File.createTempFile(pre, post)
+ val w = new FileWriter(t)
+ w.write(contents)
+ w.close()
+ t
+ }
+
+ // This "fire-and-forgets" the method, which can be lazily read through
+ // a Stream[String], and accumulates all errors on a StringBuffer
+ def sourceFilesAt(baseDir: String): (Stream[String], StringBuffer) = {
+ val buffer = new StringBuffer()
+ val cmd = Seq("find", baseDir, "-name", "*.scala", "-type", "f")
+ val lines = cmd lines_! ProcessLogger(buffer append _)
+ (lines, buffer)
}
}
-object Driver extends FileSystemUtilities {
+trait BackendCompilationUtilities {
+ def makeHarness(template: String => String, post: String)(f: File): File = {
+ val prefix = f.toString.split("/").last
+ val vf = new File(f.toString + post)
+ val w = new FileWriter(vf)
+ w.write(template(prefix))
+ w.close()
+ vf
+ }
- /** Instantiates a ChiselConfig class with the given name and uses it for elaboration */
- def elaborateWithConfigName[T <: Module](
- gen: () => T,
- configClassName: String,
- projectName: Option[String] = None,
- collectConstraints: Boolean = false): Unit = {
- val className = projectName match {
- case Some(pn) => s"$pn.$configClassName"
- case None => configClassName
- }
- val config = try {
- Class.forName(className).newInstance.asInstanceOf[ChiselConfig]
- } catch {
- case e: java.lang.ClassNotFoundException =>
- throwException("Could not find the ChiselConfig subclass you asked for (i.e. \"" +
- className + "\"), did you misspell it?", e)
- }
- elaborateWithConfig(gen, config, collectConstraints)
+ def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder = {
+ Process(
+ Seq("firrtl",
+ "-i", s"$prefix.fir",
+ "-o", s"$prefix.v",
+ "-X", "verilog"),
+ dir)
}
- /** Uses the provided ChiselConfig for elaboration */
- def elaborateWithConfig[T <: Module](
- gen: () => T,
- config: ChiselConfig,
- collectConstraints: Boolean = false): Unit = {
- val world = if(collectConstraints) config.toCollector else config.toInstance
- val p = Parameters.root(world)
- config.topConstraints.foreach(c => p.constrain(c))
- elaborate(gen, p, config)
+ def verilogToCpp(
+ prefix: String,
+ dir: File,
+ vDut: File,
+ cppHarness: File,
+ vH: File): ProcessBuilder =
+ Seq("verilator",
+ "--cc", vDut.toString,
+ "--assert",
+ "--Wno-fatal",
+ "--trace",
+ "-O2",
+ "+define+TOP_TYPE=V"+prefix,
+ "-CFLAGS", s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$prefix -include ${vH.toString}""",
+ "-Mdir", dir.toString,
+ "--exe", cppHarness.toString)
+
+ def cppToExe(prefix: String, dir: File): ProcessBuilder =
+ Seq("make", "-C", dir.toString, "-j", "-f", s"V${prefix}.mk", s"V${prefix}")
+
+ def executeExpectingFailure(
+ prefix: String,
+ dir: File,
+ assertionMsg: String = "Assertion failed"): Boolean = {
+ var triggered = false
+ val e = Process(s"./V${prefix}", dir) ! ProcessLogger(line =>
+ triggered = triggered || line.contains(assertionMsg))
+ triggered
}
- /** Elaborates the circuit specified in the gen function, optionally uses
- * a parameter space to supply context-aware values.
- * TODO: Distinguish between cases where we dump to file vs return IR for
- * use by other Drivers.
- */
- private[Chisel] def elaborateWrappedModule[T <: Module](gen: () => T, p: Parameters, c: Option[ChiselConfig]) {
- val ir = Builder.build(gen())
- val name = c match {
- case None => ir.name
- case Some(config) => s"${ir.name}.$config"
- }
- createOutputFile(s"$name.knb", p.getKnobs)
- createOutputFile(s"$name.cst", p.getConstraints)
- createOutputFile(s"$name.prm", ir.parameterDump.getDump)
- createOutputFile(s"$name.fir", ir.emit)
+ def executeExpectingSuccess(prefix: String, dir: File): Boolean = {
+ !executeExpectingFailure(prefix, dir)
}
- def elaborate[T <: Module](gen: () => T): Unit =
- elaborate(gen, Parameters.empty)
- def elaborate[T <: Module](gen: () => T, p: Parameters): Unit =
- elaborateWrappedModule(() => Module(gen())(p), p, None)
- private def elaborate[T <: Module](gen: () => T, p: Parameters, c: ChiselConfig): Unit =
- elaborateWrappedModule(() => Module(gen())(p), p, Some(c))
+
}
-object chiselMain {
- def apply[T <: Module](args: Array[String], gen: () => T, p: Parameters = Parameters.empty): Unit =
- Driver.elaborateWrappedModule(gen, p, None)
+object Driver extends FileSystemUtilities with BackendCompilationUtilities {
+
+ /** Elaborates the Module specified in the gen function into a Circuit
+ *
+ * @param gen a function that creates a Module hierarchy
+ *
+ * @return the resulting Chisel IR in the form of a Circuit (TODO: Should be FIRRTL IR)
+ */
+ def elaborate[T <: Module](gen: () => T): Circuit = Builder.build(Module(gen()))
+
+ def emit[T <: Module](gen: () => T): String = elaborate(gen).emit
+
+ def dumpFirrtl(ir: Circuit, optName: Option[File]): File = {
+ val f = optName.getOrElse(new File(ir.name + ".fir"))
+ val w = new FileWriter(f)
+ w.write(ir.emit)
+ w.close()
+ f
+ }
}
diff --git a/src/main/scala/Chisel/Module.scala b/src/main/scala/Chisel/Module.scala
index 1c1c02de..f799a7ce 100644
--- a/src/main/scala/Chisel/Module.scala
+++ b/src/main/scala/Chisel/Module.scala
@@ -6,37 +6,27 @@ import Builder.pushCommand
import Builder.dynamicContext
object Module {
- // TODO: update documentation when parameters gets removed from core Chisel
- // and this gets simplified.
/** A wrapper method that all Module instantiations must be wrapped in
* (necessary to help Chisel track internal state).
*
* @param m the Module being created
- * @param p Parameters passed down implicitly from that it is created in
*
- * @return the input module `m`
+ * @return the input module `m` with Chisel metadata properly set
*/
- def apply[T <: Module](bc: => T)(implicit currParams: Parameters = Builder.getParams.push): T = {
- paramsScope(currParams) {
- val parent = dynamicContext.currentModule
- val m = bc.setRefs()
- // init module outputs
- m._commands prependAll (for (p <- m.io.flatten; if p.dir == OUTPUT)
- yield Connect(p.lref, p.fromInt(0).ref))
- dynamicContext.currentModule = parent
- val ports = m.computePorts
- Builder.components += Component(m, m.name, ports, m._commands)
- pushCommand(DefInstance(m, ports))
- // init instance inputs
- for (p <- m.io.flatten; if p.dir == INPUT)
- p := p.fromInt(0)
- m
- }.connectImplicitIOs()
- }
-
- //TODO @deprecated("Use Chisel.paramsScope object","08-01-2015")
- def apply[T <: Module](m: => T, f: PartialFunction[Any,Any]): T = {
- apply(m)(Builder.getParams.alterPartial(f))
+ def apply[T <: Module](bc: => T): T = {
+ val parent = dynamicContext.currentModule
+ val m = bc.setRefs()
+ // init module outputs
+ m._commands prependAll (for (p <- m.io.flatten; if p.dir == OUTPUT)
+ yield Connect(p.lref, p.fromInt(0).ref))
+ dynamicContext.currentModule = parent
+ val ports = m.computePorts
+ Builder.components += Component(m, m.name, ports, m._commands)
+ pushCommand(DefInstance(m, ports))
+ // init instance inputs
+ for (p <- m.io.flatten; if p.dir == INPUT)
+ p := p.fromInt(0)
+ m.connectImplicitIOs()
}
}
diff --git a/src/main/scala/Chisel/Parameters.scala b/src/main/scala/Chisel/Parameters.scala
deleted file mode 100644
index c2d32fbd..00000000
--- a/src/main/scala/Chisel/Parameters.scala
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- Constructing Hardware in a Scala Embedded Language, Copyright (c) 2014, The
- Regents of the University of California, through Lawrence Berkeley National
- Laboratory (subject to receipt of any required approvals from the U.S. Dept.
- of Energy). All rights reserved.
-
- If you have questions about your rights to use or distribute this software,
- please contact Berkeley Lab's Technology Transfer Department at TTD@lbl.gov.
-
- NOTICE. This software is owned by the U.S. Department of Energy. As such,
- the U.S. Government has been granted for itself and others acting on its
- behalf a paid-up, nonexclusive, irrevocable, worldwide license in the Software
- to reproduce, prepare derivative works, and perform publicly and display
- publicly. Beginning five (5) years after the date permission to assert
- copyright is obtained from the U.S. Department of Energy, and subject to any
- subsequent five (5) year renewals, the U.S. Government is granted for itself
- and others acting on its behalf a paid-up, nonexclusive, irrevocable,
- worldwide license in the Software to reproduce, prepare derivative works,
- distribute copies to the public, perform publicly and display publicly, and to
- permit others to do so.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- (1) Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- (2) Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- (3) Neither the name of the University of California, Lawrence Berkeley
- National Laboratory, U.S. Dept. of Energy nor the names of its contributors
- may be used to endorse or promote products derived from this software without
- specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- You are under no obligation whatsoever to provide any bug fixes, patches, or
- upgrades to the features, functionality or performance of the source code
- ("Enhancements") to anyone; however, if you choose to make your Enhancements
- available either publicly, or directly to Lawrence Berkeley National
- Laboratory, without imposing a separate written license agreement for such
- Enhancements, then you hereby grant the following license: a non-exclusive,
- royalty-free perpetual license to install, use, modify, prepare derivative
- works, incorporate into other computer software, distribute, and sublicense
- such enhancements or derivative works thereof, in binary and source code form.
-
- Authors: J. Bachan, A. Izraelevitz, H. Cook
-*/
-
-package Chisel
-
-import scala.collection.immutable.{Seq=>Seq, Iterable=>Iterable}
-import scala.{collection=>readonly}
-import scala.collection.mutable
-
-// Convention: leading _'s on names means private to the outside world
-// but accessible to anything in this file.
-
-@deprecated("params is now globally available as Chisel.params object","08-01-2015")
-abstract trait UsesParameters { }
-
-object params {
- def apply[T](field:Any):T = Builder.getParams.apply(field)
- def apply[T](field:Field[T]):T = Builder.getParams.apply(field)
- // TODO: provide other mutators of Parameters? or @deprecate this and make
- // Parameters private, only mutateable through paramsScope?
- def alterPartial[T](mask: PartialFunction[Any,Any]): Parameters = {
- Builder.getParams.alterPartial(mask)
- }
- def constrain(gen:ViewSym=>Ex[Boolean]) = Builder.getParams.constrain(gen)
-}
-
-object paramsScope {
- def apply[T](p: Parameters)(body: => T): T = {
- Builder.paramsScope(p)(body)
- }
- def apply[T,S](mask: Map[S,Any])(body: => T): T = {
- apply(Builder.getParams.alter(mask))(body)
- }
- def apply[T](mask: PartialFunction[Any,Any])(body: => T): T = {
- apply(Builder.getParams.alterPartial(mask))(body)
- }
-}
-
-class ParameterUndefinedException(field:Any, cause:Throwable=null)
- extends RuntimeException("Parameter " + field + " undefined.", cause)
-class KnobUndefinedException(field:Any, cause:Throwable=null)
- extends RuntimeException("Knob " + field + " undefined.", cause)
-
-// Knobs are top level free variables that go into the constraint solver.
-final case class Knob[T](name:Any)
-
-// Fields are wrappers around particular a particular parameter's type
-class Field[T]
-
-class ChiselConfig(
- val topDefinitions: World.TopDefs = { (a,b,c) => {throw new scala.MatchError(a)}},
- val topConstraints: List[ViewSym=>Ex[Boolean]] = List( ex => ExLit[Boolean](true) ),
- val knobValues: Any=>Any = { case x => {throw new scala.MatchError(x)}}
-) {
- import Implicits._
- type Constraint = ViewSym=>Ex[Boolean]
-
- def this(that: ChiselConfig) = this(that.topDefinitions,
- that.topConstraints,
- that.knobValues)
-
- def ++(that: ChiselConfig) = {
- new ChiselConfig(this.addDefinitions(that.topDefinitions),
- this.addConstraints(that.topConstraints),
- this.addKnobValues(that.knobValues))
- }
-
- def addDefinitions(that: World.TopDefs): World.TopDefs = {
- (pname,site,here) => {
- try this.topDefinitions(pname, site, here)
- catch {
- case e: scala.MatchError => that(pname, site, here)
- }
- }
- }
-
- def addConstraints(that: List[Constraint]):List[Constraint] = {
- this.topConstraints ++ that
- }
-
-
- def addKnobValues(that: Any=>Any): Any=>Any = { case x =>
- try this.knobValues(x)
- catch {
- case e: scala.MatchError => that(x)
- }
- }
-
- def toCollector = new Collector(this.topDefinitions, this.knobValues)
- def toInstance = new Instance(this.topDefinitions, this.knobValues)
- override def toString = this.getClass.getSimpleName
-}
-
-// TODO eliminate this or move it to DynamicContext
-object Dump {
- def apply[T](key:Any,value:T):T = Builder.parameterDump.apply(key, value)
- def apply[T](knob:Knob[T]):Knob[T] = Builder.parameterDump.apply(knob)
-}
-
-class ParameterDump {
- val dump = mutable.Set[Tuple2[Any,Any]]()
- val knobList = mutable.ListBuffer[Any]()
- def apply[T](key:Any,value:T):T = {addToDump(key,value); value}
- def apply[T](knob:Knob[T]):Knob[T] = {knobList += knob.name; knob}
- def addToDump(key:Any,value:Any) = dump += ((key,value))
- def getDump:String = if (!dump.isEmpty) {
- dump.map(_.toString).reduce(_+"\n"+_) + "\n"
- } else {
- ""
- }
-}
-
-// objects given to the user in mask functions (site,here,up)
-abstract class View {
- protected val deftSite: View // when views are queried without a specifying a site this is the default
-
- // use `this` view's behavior to query for a parameters value as if
- // the original site were `site`
- def apply[T](pname:Any, site:View):T
- def sym[T](pname:Any, site:View):Ex[T]
-
- // query for a parameters value using the default site
- final def apply[T](pname:Any):T = apply[T](pname, deftSite)
- final def apply[T](field:Field[T]):T = apply[T](field.asInstanceOf[Any], deftSite)
-
- final def sym[T](pname:Any):Ex[T] = sym[T](pname, deftSite)
- final def sym[T](field:Field[T]):Ex[T] = sym[T](field.asInstanceOf[Any], deftSite)
-}
-
-/* Wrap a View to make the application return the symbolic expression,
- * basically a shorthand to save typing '.sym'
- * before:
- * val v: View
- * v.sym[Int]("x") // returns Ex[_]
- * now:
- * val vs = ViewSym(v)
- * vs[Int]("xs") // Ex[_]
-*/
-final case class ViewSym(view:View) {
- def apply[T](f:Any):Ex[T] = view.sym[T](f)
- def apply[T](f:Field[T]):Ex[T] = view.sym[T](f)
- def apply[T](f:Any, site:View):Ex[T] = view.sym[T](f, site)
- def apply[T](f:Field[T], site:View):Ex[T] = view.sym[T](f, site)
-}
-
-
-// internal type to represent functions that evaluate parameter values
-abstract class _Lookup {
-
- def apply[T](pname:Any, site:View):Ex[T]
-
- // build a new Lookup that just defers to this one
- final def push() = {
- val me = this
- new _Lookup {
- def apply[T](pname:Any, site:View) = me.apply(pname, site)
- }
- }
-}
-
-// Internal type used as name in all ExVar[T]'s
-sealed abstract class _Var[T]
-
-// Variables which are 'free' parameters when seen from the top level.
-final case class _VarKnob[T](kname:Any) extends _Var[T] {
- override def toString = kname.toString
-}
-// Variables whose values are computed by `expr`. The term 'let' comes
-// from the idea of 'let' bindings in functional languages i.e.:
-final case class _VarLet[T](pname:Any,expr:Ex[T]) extends _Var[T] {
- override def toString = pname.toString + "{" + expr.toString + "}"
-}
-
-
-object World {
- // An alias for the type of function provided by user to describe parameters that
- // reach the top level. The return of this function can be either:
- // Knob(k): this parameter maps to the constraint variable `k`
- // Ex: this parameter is computed using the expression
- // Any(thing else): variable takes a literal value
- type TopDefs = (/*pname:*/Any,/*site:*/View,/*here:*/View) => Any/*Knob[_] | Ex[_] | Any*/
-}
-
-// Worlds collect the variable definitions and constraints seen when building hardware.
-abstract class World(
- topDefs: World.TopDefs
- ) {
-
- val _knobs = new mutable.HashSet[Any]
- abstract class _View extends View {
- val look: _Lookup
-
- def apply[T](pname:Any, site:View):T = {
- _eval(look(pname, site).asInstanceOf[Ex[T]])
- }
- def sym[T](pname:Any, site:View):Ex[T] = {
- _bindLet[T](pname,look(pname, site).asInstanceOf[Ex[T]])
- }
- }
-
- // evaluate an expression against this world
- def _eval[T](e:Ex[T]):T = {
- Ex.eval(e, {
- case v:_VarKnob[_] => {
- _knobs += v.kname
- val e = _knobValue(v.kname)
- if(Builder.parameterDump.knobList.contains(v.kname)) {Builder.parameterDump.addToDump(v.kname,e);e} else e
- }
- case v:_VarLet[_] => _eval(v.expr.asInstanceOf[Ex[T]])
- })
- }
-
- // create a view whose default site is itself
- def _siteView(look:_Lookup):View = {
- val _look = look
- new _View {
- val look = _look
- val deftSite = this
- }
- }
-
- // create a View which with a supplied default site
- def _otherView(look:_Lookup, deftSite:View):View = {
- val _look = look
- val _deft = deftSite
- new _View {
- val look = _look
- val deftSite = _deft
- }
- }
-
- // the top level lookup
- def _topLook():_Lookup = {
- class TopLookup extends _Lookup {
-
- def apply[T](pname:Any, site:View):Ex[T] = {
- val here = _otherView(this, site)
- (
- try topDefs(pname, site, here)
- catch {
- case e:scala.MatchError => throw new ParameterUndefinedException(pname, e)
- }
- ) match {
- case k:Knob[T @unchecked] => ExVar[T](_VarKnob[T](k.name))
- case ex:Ex[T @unchecked] => _bindLet[T](pname,ex)
- case lit => ExLit(lit.asInstanceOf[T])
- }
- }
- }
- new TopLookup
- }
-
- def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T]
-
- def _constrain(e:Ex[Boolean]):Unit
-
- def _knobValue(kname:Any):Any
-
- def getConstraints:String = ""
-
- def getKnobs:String = ""
-}
-
-// a world responsible for collecting all constraints in the first pass
-class Collector(
- topDefs: World.TopDefs,
- knobVal: Any=>Any // maps knob names to default-values
- )
- extends World(topDefs) {
-
- val _constraints = new mutable.HashSet[Ex[Boolean]]
-
- def knobs():List[Any] = {
- _knobs.toList
- }
-
- def constraints():List[Ex[Boolean]] = {
- _constraints.toList
- }
-
- def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = {
- expr match {
- case e:ExVar[T] => expr
- case e:ExLit[T] => expr
- case _ => ExVar[T](_VarLet[T](pname,expr))
- }
- }
-
- def _constrain(c:Ex[Boolean]) = {
- _constraints += c // add the constraint
-
- // Also add all equality constraints for all bound variables in the
- // constraint expression and do it recursively for all expressions
- // being bound to.
- var q = List[Ex[_]](c)
- while(!q.isEmpty) {
- val e = q.head // pop an expression
- q = q.tail
- // walk over the variables in `e`
- for(e <- Ex.unfurl(e)) {
- e match {
- case ExVar(_VarLet(p,e1)) => {
- // form the equality constraint
- val c1 = ExEq[Any](e.asInstanceOf[Ex[Any]], e1.asInstanceOf[Ex[Any]])
- // recurse into the expression if its never been seen before
- if(!_constraints.contains(c1)) {
- _constraints += c1
- q ::= e1 // push
- }
- }
- case _ => {}
- }
- }
- }
- }
-
- def _knobValue(kname:Any) = {
- try knobVal(kname)
- catch {
- case e:scala.MatchError => throw new KnobUndefinedException(kname, e)
- }
- }
-
- override def getConstraints:String = if(constraints.isEmpty) "" else constraints.map("( " + _.toString + " )").reduce(_ +"\n" + _) + "\n"
-
- override def getKnobs:String = if(knobs.isEmpty) "" else {
- knobs.map(_.toString).reduce(_ + "\n" + _) + "\n"
- }
-}
-
-// a world instantianted to a specific mapping of knobs to values
-class Instance(
- topDefs: World.TopDefs,
- knobVal: Any=>Any
- )
- extends World(topDefs) {
-
- def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = expr
- def _constrain(e:Ex[Boolean]) = {}
- def _knobValue(kname:Any) = {
- try knobVal(kname)
- catch {
- case e:scala.MatchError => throw new KnobUndefinedException(kname, e)
- }
- }
-}
-
-object Parameters {
- def root(w:World) = {
- new Parameters(w, w._topLook())
- }
- def empty = Parameters.root(new Collector((a,b,c) => {throw new ParameterUndefinedException(a); a},(a:Any) => {throw new KnobUndefinedException(a); a}))
-
- // Mask making helpers
-
- // Lift a regular function into a mask by looking for MatchError's and
- // interpreting those as calls to up
- def makeMask(mask:(Any,View,View,View)=>Any) = {
- (f:Any, site:View, here:View, up:View) => {
- try mask(f,site,here,up)
- catch {case e:MatchError => up.sym[Any](f, site)}
- }
- }
-
- // Lift a Map to be a mask.
- def makeMask(mask:Map[Any,Any]) = {
- (f:Any, site:View, here:View, up:View) => {
- mask.get(f) match {
- case Some(y) => y
- case None => up.sym[Any](f, site)
- }
- }
- }
-
- // Lift a PartialFunction to be a mask.
- def makeMask(mask:PartialFunction[Any,Any]) = {
- (f:Any, site:View, here:View, up:View) => {
-
- if(mask.isDefinedAt(f))
- mask.apply(f)
- else {
- up.sym[Any](f, site)
- }
- }
- }
-}
-
-final class Parameters(
- private val _world: World,
- private val _look: _Lookup
- ) {
-
- private def _site() = _world._siteView(_look)
-
- // Create a new Parameters that just defers to this one. This is identical
- // to doing an `alter` but not overriding any values.
- def push():Parameters =
- new Parameters(_world, _look.push())
-
- def apply[T](field:Any):T =
- _world._eval(_look(field, _site())).asInstanceOf[T]
-
- def apply[T](field:Field[T]):T =
- _world._eval(_look(field, _site())).asInstanceOf[T]
-
- def constrain(gen:ViewSym=>Ex[Boolean]) = {
- val g = gen(new ViewSym(_site()))
- if(!_world._eval(g)) Builder.error("Constraint failed: " + g.toString)
- _world._constrain(g)
- }
-
- private def _alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) = {
- class KidLookup extends _Lookup {
-
- def apply[T](f:Any, site:View):Ex[T] = {
- val here = _world._otherView(this, site)
- val up = _world._otherView(_look, site)
-
- mask(f, site, here, up) match {
- case e:Ex[T @unchecked] => e
- case lit => ExLit(lit.asInstanceOf[T])
- }
- }
- }
-
- new Parameters(_world, new KidLookup)
- }
-
- def alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) =
- _alter(Parameters.makeMask(mask))
-
- def alter[T](mask:Map[T,Any]) =
- _alter(Parameters.makeMask(mask.asInstanceOf[Map[Any,Any]]))
-
- def alterPartial(mask:PartialFunction[Any,Any]) =
- _alter(Parameters.makeMask(mask))
-
- def getConstraints:String = _world.getConstraints
-
- def getKnobs:String = _world.getKnobs
-}
-
-
-/*
- Expression Library
-*/
-abstract class Ex[T] {
- override def toString = Ex.pretty(this)
-}
-
-case class IntEx (expr:Ex[Int]) {
- def === (x:IntEx):Ex[Boolean] = (ExEq[Int](expr,x.expr))
- def + (x:IntEx):Ex[Int] = ExAdd(expr,x.expr)
- def - (x:IntEx):Ex[Int] = ExSub(expr,x.expr)
- def * (x:IntEx):Ex[Int] = ExMul(expr,x.expr)
- def % (x:IntEx):Ex[Int] = ExMod(expr,x.expr)
- def < (x:IntEx):Ex[Boolean] = ExLt(expr,x.expr)
- def > (x:IntEx):Ex[Boolean] = ExGt(expr,x.expr)
- def <= (x:IntEx):Ex[Boolean] = ExLte(expr,x.expr)
- def >= (x:IntEx):Ex[Boolean] = ExGte(expr,x.expr)
- def in (x:List[IntEx]):Ex[Boolean] = {
- val canBound = x.map(_.expr match {
- case e:ExVar[_] => false
- case _ => true
- }).reduce(_ && _)
- if (canBound) {
- val max = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).max
- val min = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).min
- ExAnd(IntEx(expr) in Range(min,max), IntEx(expr) _in x)
- } else {
- IntEx(expr) _in x
- }
- }
- def in (x:Range):Ex[Boolean] = ExAnd(ExGte(expr,ExLit[Int](x.min)),ExLte(expr,ExLit[Int](x.max)))
- private def _in (x:List[IntEx]):Ex[Boolean] = {
- if (x.isEmpty) ExLit[Boolean](false) else {
- ExOr(IntEx(expr) === x.head,IntEx(expr) _in x.tail)
- }
- }
-}
-
-case class BoolEx (expr:Ex[Boolean]) {
- def && (x:BoolEx):Ex[Boolean] = ExAnd(expr,x.expr)
- def || (x:BoolEx):Ex[Boolean] = ExOr(expr,x.expr)
- def ^ (x:BoolEx):Ex[Boolean] = ExXor(expr,x.expr)
- def === (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr)
- def !== (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr)
-}
-
-object Implicits {
- implicit def ExInt_IntEx(i:Ex[Int]):IntEx = IntEx(i)
- implicit def Int_IntEx(i:Int):IntEx = IntEx(ExLit[Int](i))
- implicit def ExBool_BoolEx(b:Ex[Boolean]):BoolEx = BoolEx(b)
- implicit def Bool_IntEx(b:Boolean):BoolEx = BoolEx(ExLit[Boolean](b))
-
- implicit def ListInt_ListExInt(l:List[Int]):List[IntEx] = l.map((x:Int) => IntEx(ExLit[Int](x)))
- implicit def ListExInt_ListExInt(l:List[Ex[Int]]):List[IntEx] = l.map((x:Ex[Int]) => IntEx(x))
-}
-
-final case class ExLit[T](value:T) extends Ex[T]
-final case class ExVar[T](name:Any) extends Ex[T]
-
-final case class ExAnd(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean]
-final case class ExOr(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean]
-final case class ExXor(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean]
-
-final case class ExEq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean]
-final case class ExNeq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean]
-
-final case class ExLt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
-final case class ExLte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
-final case class ExGt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
-final case class ExGte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
-final case class ExAdd(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
-final case class ExSub(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
-final case class ExMul(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
-final case class ExMod(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
-
-object Ex {
- // evaluate an expression given a context that maps variable names to values
- def eval[T](e:Ex[T], ctx:Any=>Any):T = e match {
- case ExLit(v) => v.asInstanceOf[T]
- case ExVar(nm) => ctx(nm).asInstanceOf[T]
- case ExAnd(a,b) => eval(a,ctx) && eval(b,ctx)
- case ExOr(a,b) => eval(a,ctx) || eval(b,ctx)
- case ExXor(a,b) => eval(a,ctx) ^ eval(b,ctx)
- case e:ExEq[u] => eval(e.a,ctx) == eval(e.b,ctx)
- case e:ExNeq[u] => eval(e.a,ctx) != eval(e.b,ctx)
- case ExLt(a,b) => eval(a,ctx) < eval(b,ctx)
- case ExLte(a,b) => eval(a,ctx) <= eval(b,ctx)
- case ExGt(a,b) => eval(a,ctx) > eval(b,ctx)
- case ExGte(a,b) => eval(a,ctx) >= eval(b,ctx)
- case ExAdd(a,b) => eval(a,ctx) + eval(b,ctx)
- case ExSub(a,b) => eval(a,ctx) - eval(b,ctx)
- case ExMul(a,b) => eval(a,ctx) * eval(b,ctx)
- case ExMod(a,b) => eval(a,ctx) % eval(b,ctx)
- }
-
- // get shallow list of subexpressions
- def subExs(e:Ex[_]):List[Ex[_]] = e match {
- case ExLit(_) => Nil
- case ExVar(_) => Nil
- case ExAnd(a,b) => List(a,b)
- case ExOr(a,b) => List(a,b)
- case ExXor(a,b) => List(a,b)
- case ExEq(a,b) => List(a,b)
- case ExNeq(a,b) => List(a,b)
- case ExLt(a,b) => List(a,b)
- case ExLte(a,b) => List(a,b)
- case ExGt(a,b) => List(a,b)
- case ExGte(a,b) => List(a,b)
- case ExAdd(a,b) => List(a,b)
- case ExSub(a,b) => List(a,b)
- case ExMul(a,b) => List(a,b)
- case ExMod(a,b) => List(a,b)
- }
-
- // get all subexpressions including the expression given
- def unfurl(e:Ex[_]):List[Ex[_]] =
- e :: (subExs(e) flatMap unfurl)
-
- // pretty-print expression
- def pretty(e:Ex[_]):String = {
- // precedence rank for deciding where to put parentheses
- def rank(e:Ex[_]):Int = e match {
- case e:ExAnd => 40
- case e:ExOr => 50
- case e:ExXor => 50
- case e:ExEq[_] => 30
- case e:ExNeq[_] => 30
- case e:ExLt => 30
- case e:ExLte => 30
- case e:ExGt => 30
- case e:ExGte => 30
- case e:ExAdd => 20
- case e:ExSub => 20
- case e:ExMul => 20
- case e:ExMod => 20
- case e:ExLit[_] => 0
- case e:ExVar[_] => 0
- }
-
- val r = rank(e)
-
- def term(t:Ex[_]):String = {
- val rt = rank(t)
- //if(rt >= r)
- "( " + t.toString + " )"
- //else
- //t.toString
- }
-
- import Implicits._
- e match {
- case ExLit(v) => v.toString
- case e:ExVar[_]=> "$"+e.name
- case ExAnd(a,b) => term(a)+" && "+term(b)
- case ExOr(a,b) => term(a)+" || "+term(b)
- case ExXor(a,b) => term(a)+" ^ "+term(b)
- case ExEq(a,b) => term(a)+" = "+term(b)
- case ExNeq(a,b) => term(a)+" != "+term(b)
- case ExLt(a,b) => term(a)+" < "+term(b)
- case ExLte(a,b) => term(a)+" <= "+term(b)
- case ExGt(a,b) => term(a)+" > "+term(b)
- case ExGte(a,b) => term(a)+" >= "+term(b)
- case ExAdd(a,b) => term(a)+" + "+term(b)
- case ExSub(a,b) => term(a)+" - "+term(b)
- case ExMul(a,b) => term(a)+" * "+term(b)
- case ExMod(a,b) => term(a)+" % "+term(b)
- }
- }
-}
diff --git a/src/main/scala/Chisel/internal/Builder.scala b/src/main/scala/Chisel/internal/Builder.scala
index b3c4ae40..79d5d6aa 100644
--- a/src/main/scala/Chisel/internal/Builder.scala
+++ b/src/main/scala/Chisel/internal/Builder.scala
@@ -74,21 +74,18 @@ private class DynamicContext {
val globalRefMap = new RefMap
val components = ArrayBuffer[Component]()
var currentModule: Option[Module] = None
- val parameterDump = new ParameterDump
val errors = new ErrorLog
}
private object Builder {
// All global mutable state must be referenced via dynamicContextVar!!
private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)
- private val currentParamsVar = new DynamicVariable[Parameters](Parameters.empty)
def dynamicContext: DynamicContext = dynamicContextVar.value.get
def idGen: IdGen = dynamicContext.idGen
def globalNamespace: Namespace = dynamicContext.globalNamespace
def globalRefMap: RefMap = dynamicContext.globalRefMap
def components: ArrayBuffer[Component] = dynamicContext.components
- def parameterDump: ParameterDump = dynamicContext.parameterDump
def pushCommand[T <: Command](c: T): T = {
dynamicContext.currentModule.foreach(_._commands += c)
@@ -99,11 +96,6 @@ private object Builder {
def errors: ErrorLog = dynamicContext.errors
def error(m: => String): Unit = errors.error(m)
- def getParams: Parameters = currentParamsVar.value
- def paramsScope[T](p: Parameters)(body: => T): T = {
- currentParamsVar.withValue(p)(body)
- }
-
def build[T <: Module](f: => T): Circuit = {
dynamicContextVar.withValue(Some(new DynamicContext)) {
errors.info("Elaborating design...")
@@ -112,7 +104,7 @@ private object Builder {
errors.checkpoint()
errors.info("Done elaborating.")
- Circuit(components.last.name, components, globalRefMap, parameterDump)
+ Circuit(components.last.name, components, globalRefMap)
}
}
}
diff --git a/src/main/scala/Chisel/ir/IR.scala b/src/main/scala/Chisel/ir/IR.scala
index e25d3f56..106ad20c 100644
--- a/src/main/scala/Chisel/ir/IR.scala
+++ b/src/main/scala/Chisel/ir/IR.scala
@@ -152,6 +152,6 @@ case class ConnectInit(loc: Node, exp: Arg) extends Command
case class Component(id: Module, name: String, ports: Seq[Port], commands: Seq[Command]) extends Arg
case class Port(id: Data, dir: Direction)
-case class Circuit(name: String, components: Seq[Component], refMap: RefMap, parameterDump: ParameterDump) {
+case class Circuit(name: String, components: Seq[Component], refMap: RefMap) {
def emit: String = new Emitter(this).toString
}
diff --git a/src/main/scala/Chisel/testers/BasicTester.scala b/src/main/scala/Chisel/testers/BasicTester.scala
index c73567c4..dbb269bb 100644
--- a/src/main/scala/Chisel/testers/BasicTester.scala
+++ b/src/main/scala/Chisel/testers/BasicTester.scala
@@ -10,4 +10,6 @@ class BasicTester extends Module {
}
io.done := Bool(false)
io.error := UInt(0)
+
+ def popCount(n: Long) = n.toBinaryString.count(_=='1')
}
diff --git a/src/main/scala/Chisel/testers/Driver.scala b/src/main/scala/Chisel/testers/Driver.scala
deleted file mode 100644
index 860ef69c..00000000
--- a/src/main/scala/Chisel/testers/Driver.scala
+++ /dev/null
@@ -1,21 +0,0 @@
-// See LICENSE for license details.
-
-package Chisel.testers
-import Chisel._
-
-object TesterDriver {
- /** For use with modules that should successfully be elaborated by the
- * frontend, and which can be turned into executeables with error codes. */
- def execute(t: => BasicTester): Boolean = {
- val circuit = Builder.build(Module(t))
- //val executable = invokeFIRRTL(circuit)
- //Process(executable) !
- true
- }
-
- /** For use with modules that should illicit errors from the frontend
- * or which produce IR with consistantly checkable properties. */
- def elaborate(t: => Module): Circuit = {
- Builder.build(Module(t))
- }
-}
diff --git a/src/main/scala/Chisel/testers/TesterDriver.scala b/src/main/scala/Chisel/testers/TesterDriver.scala
new file mode 100644
index 00000000..657f7d37
--- /dev/null
+++ b/src/main/scala/Chisel/testers/TesterDriver.scala
@@ -0,0 +1,37 @@
+// See LICENSE for license details.
+
+package Chisel.testers
+import Chisel._
+import scala.sys.process._
+import java.io.File
+
+object TesterDriver extends BackendCompilationUtilities with FileSystemUtilities {
+ /** For use with modules that should successfully be elaborated by the
+ * frontend, and which can be turned into executeables with assertions. */
+ def execute(t: () => BasicTester): Boolean = {
+ // Invoke the chisel compiler to get the circuit's IR
+ val circuit = Driver.elaborate(t)
+
+ // Set up a bunch of file handlers based on a random temp filename,
+ // plus the quirks of Verilator's naming conventions
+ val target = circuit.name
+ val fname = File.createTempFile(target, "")
+ val path = fname.getParentFile.toString
+ val prefix = fname.toString.split("/").last
+ val dir = new File(System.getProperty("java.io.tmpdir"))
+ val vDut = new File(fname.toString + ".v")
+ val vH = new File(path + "/V" + prefix + ".h")
+ val cppHarness = new File(fname.toString + ".cpp")
+
+ // For now, dump the IR out to a file
+ Driver.dumpFirrtl(circuit, Some(new File(fname.toString + ".fir")))
+
+ // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe
+ if(((new File(System.getProperty("user.dir") + "/src/main/resources/top.cpp") #> cppHarness) #&&
+ firrtlToVerilog(prefix, dir) #&&
+ verilogToCpp(prefix, dir, vDut, cppHarness, vH) #&&
+ cppToExe(prefix, dir)).! == 0) {
+ executeExpectingSuccess(prefix, dir)
+ } else false
+ }
+}
diff --git a/src/test/scala/chiselTests/BitwiseOps.scala b/src/test/scala/chiselTests/BitwiseOps.scala
index 86c7131b..d180c11e 100644
--- a/src/test/scala/chiselTests/BitwiseOps.scala
+++ b/src/test/scala/chiselTests/BitwiseOps.scala
@@ -7,18 +7,18 @@ import org.scalatest._
import org.scalatest.prop._
import Chisel.testers.BasicTester
-class BitwiseOpsSpec extends ChiselPropSpec {
+class BitwiseOpsTester(w: Int, _a: Int, _b: Int) extends BasicTester {
+ io.done := Bool(true)
+ val mask = (1 << w) - 1
+ val a = UInt(_a)
+ val b = UInt(_b)
+ when(~a != UInt(mask & ~_a)) { io.error := UInt(1) }
+ when((a & b) != UInt(mask & (_a & _b))) { io.error := UInt(2) }
+ when((a | b) != UInt(mask & (_a | _b))) { io.error := UInt(3) }
+ when((a ^ b) != UInt(mask & (_a ^ _b))) { io.error := UInt(4) }
+}
- class BitwiseOpsTester(w: Int, _a: Int, _b: Int) extends BasicTester {
- io.done := Bool(true)
- val mask = (1 << w) - 1
- val a = UInt(_a)
- val b = UInt(_b)
- when(~a != UInt(mask & ~_a)) { io.error := UInt(1) }
- when((a & b) != UInt(mask & (_a & _b))) { io.error := UInt(2) }
- when((a | b) != UInt(mask & (_a | _b))) { io.error := UInt(3) }
- when((a ^ b) != UInt(mask & (_a ^ _b))) { io.error := UInt(4) }
- }
+class BitwiseOpsSpec extends ChiselPropSpec {
property("All bit-wise ops should return the correct result") {
forAll(safeUIntPair) { case(w: Int, a: Int, b: Int) =>
diff --git a/src/test/scala/chiselTests/BundleWire.scala b/src/test/scala/chiselTests/BundleWire.scala
index 99dc665f..5beed039 100644
--- a/src/test/scala/chiselTests/BundleWire.scala
+++ b/src/test/scala/chiselTests/BundleWire.scala
@@ -23,15 +23,15 @@ class BundleWire(n: Int) extends Module {
}
}
-class BundleWireSpec extends ChiselPropSpec {
+class BundleWireTester(n: Int, x: Int, y: Int) extends BasicTester {
+ val dut = Module(new BundleWire(n))
+ io.done := Bool(true)
+ dut.io.in.x := UInt(x)
+ dut.io.in.y := UInt(y)
+ io.error := dut.io.outs.map(o => o.x != UInt(x) || o.y != UInt(y)).foldLeft(UInt(0))(_##_)
+}
- class BundleWireTester(n: Int, x: Int, y: Int) extends BasicTester {
- val dut = Module(new BundleWire(n))
- io.done := Bool(true)
- dut.io.in.x := UInt(x)
- dut.io.in.y := UInt(y)
- io.error := dut.io.outs.map(o => o.x != UInt(x) || o.y != UInt(y)).foldLeft(UInt(0))(_##_)
- }
+class BundleWireSpec extends ChiselPropSpec {
property("All vec elems should match the inputs") {
forAll(vecSizes, safeUInts, safeUInts) { (n: Int, x: Int, y: Int) =>
diff --git a/src/test/scala/chiselTests/ChiselSpec.scala b/src/test/scala/chiselTests/ChiselSpec.scala
index 1fe77a0e..88aaf06c 100644
--- a/src/test/scala/chiselTests/ChiselSpec.scala
+++ b/src/test/scala/chiselTests/ChiselSpec.scala
@@ -10,8 +10,8 @@ import Chisel.testers._
/** Common utility functions for Chisel unit tests. */
trait ChiselRunners {
- def execute(t: => BasicTester): Boolean = TesterDriver.execute(t)
- def elaborate(t: => Module): Circuit = TesterDriver.elaborate(t)
+ def execute(t: => BasicTester): Boolean = TesterDriver.execute(() => t)
+ def elaborate(t: => Module): Circuit = Driver.elaborate(() => t)
}
/** Spec base class for BDD-style testers. */
@@ -19,11 +19,9 @@ class ChiselFlatSpec extends FlatSpec with ChiselRunners with Matchers
/** Spec base class for property-based testers. */
class ChiselPropSpec extends PropSpec with ChiselRunners with PropertyChecks {
- /** Returns the number of 1s in the binary representation of the input. */
- def popCount(n: Long): Int = n.toBinaryString.count(_ == '1')
// Generator for small positive integers.
- val smallPosInts = Gen.choose(1, 7)
+ val smallPosInts = Gen.choose(1, 4)
// Generator for widths considered "safe".
val safeUIntWidth = Gen.choose(1, 30)
diff --git a/src/test/scala/chiselTests/ComplexAssign.scala b/src/test/scala/chiselTests/ComplexAssign.scala
index 09743e04..64fc8bda 100644
--- a/src/test/scala/chiselTests/ComplexAssign.scala
+++ b/src/test/scala/chiselTests/ComplexAssign.scala
@@ -29,23 +29,23 @@ class ComplexAssign(w: Int) extends Module {
}
}
+class ComplexAssignTester(enList: List[Boolean], re: Int, im: Int) extends BasicTester {
+ val (cnt, wrap) = Counter(Bool(true), enList.size)
+ val dut = Module(new ComplexAssign(32))
+ dut.io.in.re := UInt(re)
+ dut.io.in.im := UInt(im)
+ dut.io.e := Vec(enList.map(Bool(_)))(cnt)
+ val re_correct = dut.io.out.re === Mux(dut.io.e, dut.io.in.re, UInt(0))
+ val im_correct = dut.io.out.im === Mux(dut.io.e, dut.io.in.im, UInt(0))
+ when(!re_correct || !im_correct) {
+ io.done := Bool(true); io.error := cnt
+ } .elsewhen(wrap) { io.done := Bool(true) }
+}
+
class ComplexAssignSpec extends ChiselPropSpec {
- class ComplexAssignTester(enList: List[Boolean], re: Int, im: Int) extends BasicTester {
- val (cnt, wrap) = Counter(Bool(true), enList.size)
- val dut = Module(new ComplexAssign(32))
- dut.io.in.re := UInt(re)
- dut.io.in.im := UInt(im)
- dut.io.e := Vec(enList.map(Bool(_)))(cnt)
- val re_correct = dut.io.out.re === Mux(dut.io.e, dut.io.in.re, UInt(0))
- val im_correct = dut.io.out.im === Mux(dut.io.e, dut.io.in.im, UInt(0))
- when(!re_correct || !im_correct) {
- io.done := Bool(true); io.error := cnt
- } .elsewhen(wrap) { io.done := Bool(true) }
- }
-
property("All complex assignments should return the correct result") {
- forAll(enSequence(4), safeUInts, safeUInts) { (en: List[Boolean], re: Int, im: Int) =>
+ forAll(enSequence(2), safeUInts, safeUInts) { (en: List[Boolean], re: Int, im: Int) =>
assert(execute{ new ComplexAssignTester(en, re, im) })
}
}
diff --git a/src/test/scala/chiselTests/Counter.scala b/src/test/scala/chiselTests/Counter.scala
index 0e8601b3..080130df 100644
--- a/src/test/scala/chiselTests/Counter.scala
+++ b/src/test/scala/chiselTests/Counter.scala
@@ -6,37 +6,37 @@ import org.scalatest._
import org.scalatest.prop._
import Chisel.testers.BasicTester
-class CounterSpec extends ChiselPropSpec {
+class CountTester(max: Int) extends BasicTester {
+ val cnt = Counter(max)
+ when(cnt.value === UInt(max)) { io.done := Bool(true) }
+}
- class CountTester(max: Int) extends BasicTester {
- val cnt = Counter(max)
- when(cnt.value === UInt(max)) { io.done := Bool(true) }
+class EnableTester(seed: Int) extends BasicTester {
+ val ens = Reg(init = UInt(seed))
+ ens := ens >> 1
+ val (cntEn, cntWrap) = Counter(ens(0), 32)
+ val cnt = Counter(32)
+ when(cnt.value === UInt(31)) {
+ io.done := Bool(true)
+ io.error := cnt.value != UInt(popCount(seed))
}
+}
+
+class WrapTester(max: Int) extends BasicTester {
+ val (cnt, wrap) = Counter(Bool(true), max)
+ when(wrap) { io.done := Bool(true); io.error := cnt != UInt(max) }
+}
+
+class CounterSpec extends ChiselPropSpec {
property("Counter should count up") {
forAll(smallPosInts) { (max: Int) => assert(execute{ new CountTester(max) }) }
}
- class EnableTester(seed: Int) extends BasicTester {
- val ens = Reg(init = UInt(seed))
- ens := ens >> 1
- val (cntEn, cntWrap) = Counter(ens(0), 32)
- val cnt = Counter(32)
- when(cnt.value === UInt(31)) {
- io.done := Bool(true)
- io.error := cnt.value != UInt(popCount(seed))
- }
- }
-
property("Counter can be en/disabled") {
forAll(safeUInts) { (seed: Int) => assert(execute{ new EnableTester(seed) }) }
}
- class WrapTester(max: Int) extends BasicTester {
- val (cnt, wrap) = Counter(Bool(true), max)
- when(wrap) { io.done := Bool(true); io.error := cnt != UInt(max) }
- }
-
property("Counter should wrap") {
forAll(smallPosInts) { (max: Int) => assert(execute{ new WrapTester(max) }) }
}
diff --git a/src/test/scala/chiselTests/Decoder.scala b/src/test/scala/chiselTests/Decoder.scala
index 9ac0a3b7..7751804b 100644
--- a/src/test/scala/chiselTests/Decoder.scala
+++ b/src/test/scala/chiselTests/Decoder.scala
@@ -15,16 +15,16 @@ class Decoder(bitpats: List[String]) extends Module {
io.matched := Vec(bitpats.map(BitPat(_) === io.inst)).reduce(_||_)
}
-class DecoderSpec extends ChiselPropSpec {
+class DecoderTester(pairs: List[(String, String)]) extends BasicTester {
+ val (insts, bitpats) = pairs.unzip
+ val (cnt, wrap) = Counter(Bool(true), pairs.size)
+ val dut = Module(new Decoder(bitpats))
+ dut.io.inst := Vec(insts.map(UInt(_)))(cnt)
+ when(!dut.io.matched) { io.done := Bool(true); io.error := cnt }
+ when(wrap) { io.done := Bool(true) }
+}
- class DecoderTester(pairs: List[(String, String)]) extends BasicTester {
- val (insts, bitpats) = pairs.unzip
- val (cnt, wrap) = Counter(Bool(true), pairs.size)
- val dut = Module(new Decoder(bitpats))
- dut.io.inst := Vec(insts.map(UInt(_)))(cnt)
- when(!dut.io.matched) { io.done := Bool(true); io.error := cnt }
- when(wrap) { io.done := Bool(true) }
- }
+class DecoderSpec extends ChiselPropSpec {
// Use a single Int to make both a specific instruction and a BitPat that will match it
val bitpatPair = for(seed <- Arbitrary.arbitrary[Int]) yield {
@@ -36,7 +36,7 @@ class DecoderSpec extends ChiselPropSpec {
private def nPairs(n: Int) = Gen.containerOfN[List, (String,String)](n,bitpatPair)
property("BitPat wildcards should be usable in decoding") {
- forAll(nPairs(16)){ (pairs: List[(String, String)]) =>
+ forAll(nPairs(4)){ (pairs: List[(String, String)]) =>
assert(execute{ new DecoderTester(pairs) })
}
}
diff --git a/src/test/scala/chiselTests/GCD.scala b/src/test/scala/chiselTests/GCD.scala
index 48a96f0d..acc1e84e 100644
--- a/src/test/scala/chiselTests/GCD.scala
+++ b/src/test/scala/chiselTests/GCD.scala
@@ -24,21 +24,21 @@ class GCD extends Module {
io.v := y === UInt(0)
}
-class GCDSpec extends ChiselPropSpec {
-
- class GCDTester(a: Int, b: Int, z: Int) extends BasicTester {
- val dut = Module(new GCD)
- val first = Reg(init=Bool(true))
- dut.io.a := UInt(a)
- dut.io.b := UInt(b)
- dut.io.e := first
- when(first) { first := Bool(false) }
- when(dut.io.v) {
- io.done := Bool(true)
- io.error := (dut.io.z != UInt(z)).toUInt
- }
+class GCDTester(a: Int, b: Int, z: Int) extends BasicTester {
+ val dut = Module(new GCD)
+ val first = Reg(init=Bool(true))
+ dut.io.a := UInt(a)
+ dut.io.b := UInt(b)
+ dut.io.e := first
+ when(first) { first := Bool(false) }
+ when(dut.io.v) {
+ io.done := Bool(true)
+ io.error := (dut.io.z != UInt(z)).toUInt
}
+}
+class GCDSpec extends ChiselPropSpec {
+
//TODO: use generators and this function to make z's
def gcd(a: Int, b: Int): Int = if(b == 0) a else gcd(b, a%b)
diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala
new file mode 100644
index 00000000..98ad3b11
--- /dev/null
+++ b/src/test/scala/chiselTests/Harness.scala
@@ -0,0 +1,75 @@
+package chiselTests
+import Chisel.testers.BasicTester
+import org.scalatest._
+import org.scalatest.prop._
+import java.io.File
+
+class HarnessSpec extends ChiselPropSpec
+ with Chisel.BackendCompilationUtilities {
+
+ def makeTrivialVerilog = makeHarness((prefix: String) => s"""
+module ${prefix};
+ initial begin
+ $$display("$prefix!");
+ $$finish;
+ end
+endmodule
+""", ".v") _
+
+ def makeFailingVerilog = makeHarness((prefix: String) => s"""
+module $prefix;
+ initial begin
+ assert (1 == 0) else $$error("My specific, expected error message!");
+ $$display("$prefix!");
+ $$finish;
+ end
+endmodule
+""", ".v") _
+
+ def makeCppHarness = makeHarness((prefix: String) => s"""
+#include "V$prefix.h"
+#include "verilated.h"
+
+vluint64_t main_time = 0;
+double sc_time_stamp () { return main_time; }
+
+int main(int argc, char **argv, char **env) {
+ Verilated::commandArgs(argc, argv);
+ V${prefix}* top = new V${prefix};
+ while (!Verilated::gotFinish()) { top->eval(); }
+ delete top;
+ exit(0);
+}
+""", ".cpp") _
+
+ val dir = new File(System.getProperty("java.io.tmpdir"))
+
+ def simpleHarnessBackend(make: File => File): String = {
+ val target = "test"
+ val fname = File.createTempFile(target, "")
+ val path = fname.getParentFile.toString
+ val prefix = fname.toString.split("/").last
+ val vDut = make(fname)
+ val vH = new File(path + "/V" + prefix + ".h")
+ val cppHarness = makeCppHarness(fname)
+ verilogToCpp(target, dir, vDut, cppHarness, vH).!
+ cppToExe(prefix, dir).!
+ prefix
+ }
+
+ property("Test making trivial verilog harness and executing") {
+ val prefix = simpleHarnessBackend(makeTrivialVerilog)
+
+ assert(executeExpectingSuccess(prefix, dir))
+ }
+
+ property("Test that assertion failues in Verilog are caught") {
+ val prefix = simpleHarnessBackend(makeFailingVerilog)
+
+ assert(!executeExpectingSuccess(prefix, dir))
+ assert(executeExpectingFailure(prefix, dir))
+ assert(executeExpectingFailure(prefix, dir, "My specific, expected error message!"))
+ assert(!executeExpectingFailure(prefix, dir, "A string that doesn't match any test output"))
+ }
+}
+
diff --git a/src/test/scala/chiselTests/MulLookup.scala b/src/test/scala/chiselTests/MulLookup.scala
index 18dcc431..93917a4e 100644
--- a/src/test/scala/chiselTests/MulLookup.scala
+++ b/src/test/scala/chiselTests/MulLookup.scala
@@ -22,15 +22,15 @@ class MulLookup(val w: Int) extends Module {
io.z := tbl(((io.x << w) | io.y))
}
-class MulLookupSpec extends ChiselPropSpec {
+class MulLookupTester(w: Int, x: Int, y: Int) extends BasicTester {
+ val dut = Module(new MulLookup(w))
+ dut.io.x := UInt(x)
+ dut.io.y := UInt(y)
+ io.done := Bool(true)
+ io.error := dut.io.z != UInt(x * y)
+}
- class MulLookupTester(w: Int, x: Int, y: Int) extends BasicTester {
- val dut = Module(new MulLookup(w))
- dut.io.x := UInt(x)
- dut.io.y := UInt(y)
- io.done := Bool(true)
- io.error := dut.io.z != UInt(x * y)
- }
+class MulLookupSpec extends ChiselPropSpec {
property("Mul lookup table should return the correct result") {
forAll(smallPosInts, smallPosInts) { (x: Int, y: Int) =>
diff --git a/src/test/scala/chiselTests/Tbl.scala b/src/test/scala/chiselTests/Tbl.scala
index 072f993f..40f71c69 100644
--- a/src/test/scala/chiselTests/Tbl.scala
+++ b/src/test/scala/chiselTests/Tbl.scala
@@ -23,22 +23,22 @@ class Tbl(w: Int, n: Int) extends Module {
}
}
-class TblSpec extends ChiselPropSpec {
+class TblTester(w: Int, n: Int, idxs: List[Int], values: List[Int]) extends BasicTester {
+ val (cnt, wrap) = Counter(Bool(true), idxs.size)
+ val dut = Module(new Tbl(w, n))
+ val vvalues = Vec(values.map(UInt(_)))
+ val vidxs = Vec(idxs.map(UInt(_)))
+ val prev_idx = vidxs(cnt - UInt(1))
+ val prev_value = vvalues(cnt - UInt(1))
+ dut.io.wi := vidxs(cnt)
+ dut.io.ri := prev_idx
+ dut.io.we := Bool(true) //TODO enSequence
+ dut.io.d := vvalues(cnt)
+ when(cnt > UInt(0) && dut.io.o != prev_value) { io.done := Bool(true); io.error := prev_idx }
+ when(wrap) { io.done := Bool(true) }
+}
- class TblTester(w: Int, n: Int, idxs: List[Int], values: List[Int]) extends BasicTester {
- val (cnt, wrap) = Counter(Bool(true), idxs.size)
- val dut = Module(new Tbl(w, n))
- val vvalues = Vec(values.map(UInt(_)))
- val vidxs = Vec(idxs.map(UInt(_)))
- val prev_idx = vidxs(cnt - UInt(1))
- val prev_value = vvalues(cnt - UInt(1))
- dut.io.wi := vidxs(cnt)
- dut.io.ri := prev_idx
- dut.io.we := Bool(true) //TODO enSequence
- dut.io.d := vvalues(cnt)
- when(cnt > UInt(0) && dut.io.o != prev_value) { io.done := Bool(true); io.error := prev_idx }
- when(wrap) { io.done := Bool(true) }
- }
+class TblSpec extends ChiselPropSpec {
property("All table reads should return the previous write") {
forAll(safeUIntPairN(8)) { case(w: Int, pairs: List[(Int, Int)]) =>
diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala
index ea670f37..4430ab66 100644
--- a/src/test/scala/chiselTests/Vec.scala
+++ b/src/test/scala/chiselTests/Vec.scala
@@ -7,15 +7,36 @@ import org.scalatest._
import org.scalatest.prop._
import Chisel.testers.BasicTester
-class VecSpec extends ChiselPropSpec {
+class ValueTester(w: Int, values: List[Int]) extends BasicTester {
+ io.done := Bool(true)
+ val v = Vec(values.map(UInt(_, width = w))) // TODO: does this need a Wire? Why no error?
+ io.error := v.zip(values).map { case(a,b) =>
+ a != UInt(b)
+ }.foldLeft(UInt(0))(_##_)
+}
- class ValueTester(w: Int, values: List[Int]) extends BasicTester {
- io.done := Bool(true)
- val v = Vec(values.map(UInt(_, width = w))) // TODO: does this need a Wire? Why no error?
- io.error := v.zip(values).map { case(a,b) =>
- a != UInt(b)
- }.foldLeft(UInt(0))(_##_)
- }
+class TabulateTester(n: Int) extends BasicTester {
+ io.done := Bool(true)
+ val v = Vec(Range(0, n).map(i => UInt(i * 2)))
+ val x = Vec(Array.tabulate(n){ i => UInt(i * 2) })
+ val u = Vec.tabulate(n)(i => UInt(i*2))
+ when(v.toBits != x.toBits) { io.error := UInt(1) }
+ when(v.toBits != u.toBits) { io.error := UInt(2) }
+ when(x.toBits != u.toBits) { io.error := UInt(3) }
+}
+
+class ShiftRegisterTester(n: Int) extends BasicTester {
+ val (cnt, wrap) = Counter(Bool(true), n*2)
+ when(wrap) { io.done := Bool(true) }
+
+ val shifter = Vec(Reg(UInt(width = log2Up(n))), n)
+ (shifter, shifter drop 1).zipped.foreach(_ := _)
+ shifter(n-1) := cnt
+ val expected = cnt - UInt(n)
+ when(cnt >= UInt(n) && expected != shifter(0)) { io.done := Bool(true); io.error := expected }
+}
+
+class VecSpec extends ChiselPropSpec {
property("Vecs should be assignable") {
forAll(safeUIntN(8)) { case(w: Int, v: List[Int]) =>
@@ -23,31 +44,10 @@ class VecSpec extends ChiselPropSpec {
}
}
- class TabulateTester(n: Int) extends BasicTester {
- io.done := Bool(true)
- val v = Vec(Range(0, n).map(i => UInt(i * 2)))
- val x = Vec(Array.tabulate(n){ i => UInt(i * 2) })
- val u = Vec.tabulate(n)(i => UInt(i*2))
- when(v.toBits != x.toBits) { io.error := UInt(1) }
- when(v.toBits != u.toBits) { io.error := UInt(2) }
- when(x.toBits != u.toBits) { io.error := UInt(3) }
- }
-
property("Vecs should tabulate correctly") {
forAll(smallPosInts) { (n: Int) => assert(execute{ new TabulateTester(n) }) }
}
- class ShiftRegisterTester(n: Int) extends BasicTester {
- val (cnt, wrap) = Counter(Bool(true), n*2)
- when(wrap) { io.done := Bool(true) }
-
- val shifter = Vec(Reg(UInt(width = log2Up(n))), n)
- (shifter, shifter drop 1).zipped.foreach(_ := _)
- shifter(n-1) := cnt
- val expected = cnt - UInt(n)
- when(cnt >= UInt(n) && expected != shifter(0)) { io.done := Bool(true); io.error := expected }
- }
-
property("Vecs of regs should be usable as shift registers") {
forAll(smallPosInts) { (n: Int) => assert(execute{ new ShiftRegisterTester(n) }) }
}