diff options
23 files changed, 492 insertions, 79 deletions
@@ -127,7 +127,7 @@ This will walk you through installing Chisel and its dependencies: ``` git pull - git checkout verilator_3_880 + git checkout verilator_3_886 ``` 1. In the Verilator repository directory, build and install: @@ -21,8 +21,10 @@ lazy val commonSettings = Seq ( scalaVersion := "2.11.7" ) +val defaultVersions = Map("firrtl" -> "1.1-SNAPSHOT") + lazy val chiselSettings = Seq ( - name := "Chisel3", + name := "chisel3", publishMavenStyle := true, publishArtifact in Test := false, @@ -62,19 +64,24 @@ lazy val chiselSettings = Seq ( Resolver.sonatypeRepo("releases") ), - /* Bumping "com.novocode" % "junit-interface" % "0.11", causes DelayTest testSeqReadBundle to fail - * in subtly disturbing ways on Linux (but not on Mac): - * - some fields in the generated .h file are re-named, - * - an additional field is added - * - the generated .cpp file has additional differences: - * - different temps in clock_lo - * - missing assignments - * - change of assignment order - * - use of "Tx" vs. "Tx.values" - */ + libraryDependencies ++= (Seq("firrtl").map { + dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }), + + +/* Bumping "com.novocode" % "junit-interface" % "0.11", causes DelayTest testSeqReadBundle to fail + * in subtly disturbing ways on Linux (but not on Mac): + * - some fields in the generated .h file are re-named, + * - an additional field is added + * - the generated .cpp file has additional differences: + * - different temps in clock_lo + * - missing assignments + * - change of assignment order + * - use of "Tx" vs. "Tx.values" + */ libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.5" % "test", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.12.4" % "test", + libraryDependencies += "com.github.scopt" %% "scopt" % "3.4.0", // Tests from other projects may still run concurrently. parallelExecution in Test := true, @@ -101,6 +108,13 @@ lazy val chiselFrontend = (project in file("chiselFrontend")). dependsOn(coreMacros) lazy val chisel = (project in file(".")). + enablePlugins(BuildInfoPlugin). + settings( + // We should really be using name.value, but currently, the package is "Chisel" (uppercase first letter) + buildInfoPackage := /* name.value */ "chisel3", + buildInfoOptions += BuildInfoOption.BuildTime, + buildInfoKeys := Seq[BuildInfoKey](buildInfoPackage, version, scalaVersion, sbtVersion) + ). settings(commonSettings: _*). settings(customUnidocSettings: _*). settings(chiselSettings: _*). diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index 5378f3ae..467cb4eb 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -53,6 +53,7 @@ object Binding { case class BindingException(message: String) extends Exception(message) def AlreadyBoundException(binding: String) = BindingException(s": Already bound to $binding") def NotSynthesizableException = BindingException(s": Not bound to synthesizable node, currently only Type description") + def MissingIOWrapperException = BindingException(": Missing IO() wrapper") // This recursively walks down the Data tree to look at all the leaf 'Element's // Will build up an error string in case something goes wrong @@ -138,6 +139,29 @@ object Binding { } } } + + /** Diagnose a binding error caused by a missing IO() wrapper. + * @param element the element triggering the binding error. + * @return true if the element is a member of the module's io but ioDefined is false. + */ + def isMissingIOWrapper(element: Element): Boolean = { + element._parent match { + case None => false + case Some(x: Module) => { + // If the IO() wrapper has been executed, it isn't missing. + if (x.ioDefined) { + false + } else { + // TODO: We should issue the message only once, and if we get here, + // we know the wrapper is missing, whether or not the element is a member of io. + // But if it's not an io element, we want to issue the complementary "unbound" error. + // Revisit this when we collect error messages instead of throwing exceptions. + x.io.flatten.contains(element) + } + } + } + } + try walkToBinding( target, element => element.binding match { @@ -145,10 +169,16 @@ object Binding { case binding => // The following kludge is an attempt to provide backward compatibility // It should be done at at higher level. - if ((forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) - throw NotSynthesizableException - else + if ((forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) { + // Generate a better error message if this is a result of a missing IO() wrapper. + if (isMissingIOWrapper(element)) { + throw MissingIOWrapperException + } else { + throw NotSynthesizableException + } + } else { Binding.bind(element, PortBinder(element._parent.get), "Error: IO") + } } ) catch { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 00d0cc14..a5d954b6 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -460,6 +460,7 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) override def do_<= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) override def do_>= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) + @deprecated("Use '=/=', which avoids potential precedence problems", "chisel3") final def != (that: UInt): Bool = macro SourceInfoTransform.thatArg final def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg final def === (that: UInt): Bool = macro SourceInfoTransform.thatArg @@ -655,6 +656,7 @@ sealed class SInt private (width: Width, lit: Option[SLit] = None) override def do_<= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) override def do_>= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) + @deprecated("Use '=/=', which avoids potential precedence problems", "chisel3") final def != (that: SInt): Bool = macro SourceInfoTransform.thatArg final def =/= (that: SInt): Bool = macro SourceInfoTransform.thatArg final def === (that: SInt): Bool = macro SourceInfoTransform.thatArg diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 0e473e7e..86858e5d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -173,7 +173,19 @@ abstract class Data extends HasId { private[core] def width: Width private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit + /** cloneType must be defined for any Chisel object extending Data. + * It is responsible for constructing a basic copy of the object being cloned. + * If cloneType needs to recursively clone elements of an object, it should call + * the cloneType methods on those elements. + * @return a copy of the object. + */ def cloneType: this.type + + /** chiselCloneType is called at the top-level of a clone chain. + * It calls the client's cloneType() method to construct a basic copy of the object being cloned, + * then performs any fixups required to reconstruct the appropriate core state of the cloned object. + * @return a copy of the object with appropriate core state. + */ def chiselCloneType: this.type = { // Call the user-supplied cloneType method val clone = this.cloneType @@ -181,6 +193,7 @@ abstract class Data extends HasId { //TODO(twigg): Do recursively for better error messages for((clone_elem, source_elem) <- clone.allElements zip this.allElements) { clone_elem.binding = UnboundBinding(source_elem.binding.direction) + Data.setFirrtlDirection(clone_elem, Data.getFirrtlDirection(source_elem)) } clone } diff --git a/project/plugins.sbt b/project/plugins.sbt index 58166621..5ff66b4f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -14,4 +14,7 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.4") addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.8.2") +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1") + addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.3.3") + diff --git a/src/main/scala/chisel3/ChiselExecutionOptions.scala b/src/main/scala/chisel3/ChiselExecutionOptions.scala new file mode 100644 index 00000000..6f58153f --- /dev/null +++ b/src/main/scala/chisel3/ChiselExecutionOptions.scala @@ -0,0 +1,34 @@ +// See LICENSE for license details. + +package chisel3 + +import firrtl.{ExecutionOptionsManager, ComposableOptions} + +//TODO: provide support for running firrtl as separate process, could alternatively be controlled by external driver +//TODO: provide option for not saving chirrtl file, instead calling firrtl with in memory chirrtl +/** + * Options that are specific to chisel. + * + * @param runFirrtlCompiler when true just run chisel, when false run chisel then compile its output with firrtl + * @note this extends FirrtlExecutionOptions which extends CommonOptions providing easy access to down chain options + */ +case class ChiselExecutionOptions( + runFirrtlCompiler: Boolean = true + // var runFirrtlAsProcess: Boolean = false + ) extends ComposableOptions + +trait HasChiselExecutionOptions { + self: ExecutionOptionsManager => + + var chiselOptions = ChiselExecutionOptions() + + parser.note("chisel3 options") + + parser.opt[Unit]("no-run-firrtl") + .abbr("chnrf") + .foreach { _ => + chiselOptions = chiselOptions.copy(runFirrtlCompiler = false) + } + .text("Stop after chisel emits chirrtl file") +} + diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala index 5e0a3a0f..a0713379 100644 --- a/src/main/scala/chisel3/Driver.scala +++ b/src/main/scala/chisel3/Driver.scala @@ -2,11 +2,37 @@ package chisel3 +import chisel3.internal.firrtl.Emitter + import scala.sys.process._ import java.io._ -import internal._ import internal.firrtl._ +import firrtl._ + +/** + * The Driver provides methods to invoke the chisel3 compiler and the firrtl compiler. + * By default firrtl is automatically run after chisel. an [[ExecutionOptionsManager]] + * is needed to manage options. It can parser command line arguments or coordinate + * multiple chisel toolchain tools options. + * + * @example + * {{{ + * val optionsManager = new ExecutionOptionsManager("chisel3") + * with FirrtlExecutionOptions + * with ChiselExecutionOptions { + * commonOptions = CommonOption(targetDirName = "my_target_dir") + * chiselOptions = ChiselExecutionOptions(runFirrtlCompiler = false) + * } + * chisel3.Driver.execute(optionsManager, () => new Dut) + * }}} + * or via command line arguments + * @example {{{ + * args = "--no-run-firrtl --target-dir my-target-dir".split(" +") + * chisel3.execute(args, () => new DUT) + * }}} + */ +import BuildInfo._ trait BackendCompilationUtilities { /** Create a temporary directory with the prefix name. Exists here because it doesn't in Java 6. @@ -31,6 +57,32 @@ trait BackendCompilationUtilities { vf } + /** + * like 'firrtlToVerilog' except it runs the process inside the same JVM + * + * @param prefix basename of the file + * @param dir directory where file lives + * @return true if compiler completed successfully + */ + def compileFirrtlToVerilog(prefix: String, dir: File): Boolean = { + val optionsManager = new ExecutionOptionsManager("chisel3") with HasChiselExecutionOptions with HasFirrtlOptions { + commonOptions = CommonOptions(topName = prefix, targetDirName = dir.getAbsolutePath) + firrtlOptions = FirrtlExecutionOptions(compilerName = "verilog") + } + + firrtl.Driver.execute(optionsManager) match { + case _: FirrtlExecutionSuccess => true + case _: FirrtlExecutionFailure => false + } + } + + /** + * compule chirrtl to verilog by using a separate process + * + * @param prefix basename of the file + * @param dir directory where file lives + * @return true if compiler completed successfully + */ def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder = { Process( Seq("firrtl", @@ -67,13 +119,13 @@ trait BackendCompilationUtilities { "-Wno-WIDTH", "-Wno-STMTDLY", "--trace", - "-O2", + "-O0", "--top-module", topModule, "+define+TOP_TYPE=V" + dutFile, s"+define+PRINTF_COND=!$topModule.reset", s"+define+STOP_COND=!$topModule.reset", "-CFLAGS", - s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$dutFile -include V$dutFile.h""", + s"""-Wno-undefined-bool-conversion -O0 -DTOP_TYPE=V$dutFile -include V$dutFile.h""", "-Mdir", dir.toString, "--exe", cppHarness.toString) System.out.println(s"${command.mkString(" ")}") // scalastyle:ignore regex @@ -86,14 +138,17 @@ trait BackendCompilationUtilities { def executeExpectingFailure( prefix: String, dir: File, - assertionMsg: String = "Assertion failed"): Boolean = { + assertionMsg: String = ""): Boolean = { var triggered = false + val assertionMessageSupplied = assertionMsg != "" val e = Process(s"./V${prefix}", dir) ! ProcessLogger(line => { - triggered = triggered || line.contains(assertionMsg) + triggered = triggered || (assertionMessageSupplied && line.contains(assertionMsg)) System.out.println(line) // scalastyle:ignore regex }) - triggered + // Fail if a line contained an assertion or if we get a non-zero exit code + // or, we get a SIGABRT (assertion failure) and we didn't provide a specific assertion message + triggered || (e != 0 && (e != 134 || !assertionMessageSupplied)) } def executeExpectingSuccess(prefix: String, dir: File): Boolean = { @@ -101,6 +156,30 @@ trait BackendCompilationUtilities { } } +/** + * This family provides return values from the chisel3 and possibly firrtl compile steps + */ +trait ChiselExecutionResult + +/** + * + * @param circuitOption Optional circuit, has information like circuit name + * @param emitted The emitted Chirrrl text + * @param firrtlResultOption Optional Firrtl result, @see ucb-bar/firrtl for details + */ +case class ChiselExecutionSucccess( + circuitOption: Option[Circuit], + emitted: String, + firrtlResultOption: Option[FirrtlExecutionResult] + ) extends ChiselExecutionResult + +/** + * Getting one of these indicates failure of some sort + * + * @param message a clue perhaps will be provided in the here + */ +case class ChiselExecutionFailure(message: String) extends ChiselExecutionResult + object Driver extends BackendCompilationUtilities { /** Elaborates the Module specified in the gen function into a Circuit @@ -108,7 +187,7 @@ object Driver extends BackendCompilationUtilities { * @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 elaborate[T <: Module](gen: () => T): Circuit = internal.Builder.build(Module(gen())) def emit[T <: Module](gen: () => T): String = Emitter.emit(elaborate(gen)) @@ -132,4 +211,72 @@ object Driver extends BackendCompilationUtilities { } def targetDir(): String = { target_dir getOrElse new File(".").getCanonicalPath } + + /** + * Run the chisel3 compiler and possibly the firrtl compiler with options specified + * + * @param optionsManager The options specified + * @param dut The device under test + * @return An execution result with useful stuff, or failure with message + */ + def execute( + optionsManager: ExecutionOptionsManager with HasChiselExecutionOptions with HasFirrtlOptions, + dut: () => Module): ChiselExecutionResult = { + val circuit = elaborate(dut) + + // this little hack let's us set the topName with the circuit name if it has not been set from args + optionsManager.setTopNameIfNotSet(circuit.name) + + val firrtlOptions = optionsManager.firrtlOptions + val chiselOptions = optionsManager.chiselOptions + + // use input because firrtl will be reading this + val firrtlString = Emitter.emit(circuit) + val firrtlFileName = firrtlOptions.getInputFileName(optionsManager) + val firrtlFile = new File(firrtlFileName) + + val w = new FileWriter(firrtlFile) + w.write(firrtlString) + w.close() + + val firrtlExecutionResult = if(chiselOptions.runFirrtlCompiler) { + Some(firrtl.Driver.execute(optionsManager)) + } + else { + None + } + ChiselExecutionSucccess(Some(circuit), firrtlString, firrtlExecutionResult) + } + + /** + * Run the chisel3 compiler and possibly the firrtl compiler with options specified via an array of Strings + * + * @param args The options specified, command line style + * @param dut The device under test + * @return An execution result with useful stuff, or failure with message + */ + def execute(args: Array[String], dut: () => Module): ChiselExecutionResult = { + val optionsManager = new ExecutionOptionsManager("chisel3") with HasChiselExecutionOptions with HasFirrtlOptions + + optionsManager.parse(args) match { + case true => + execute(optionsManager, dut) + case _ => + ChiselExecutionFailure("could not parse results") + } + } + + /** + * This is just here as command line way to see what the options are + * It will not successfully run + * TODO: Look into dynamic class loading as way to make this main useful + * + * @param args unused args + */ + def main(args: Array[String]) { + execute(Array("--help"), null) + } + + val version = BuildInfo.version + val chiselVersionString = BuildInfo.toString } diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index d13fcb06..d0d2ddb4 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -158,25 +158,6 @@ package object Chisel { // scalastyle:ignore package.object.name type DecoupledIO[+T <: Data] = chisel3.util.DecoupledIO[T] val DecoupledIO = chisel3.util.Decoupled val Decoupled = chisel3.util.Decoupled - class EnqIO[+T <: Data](gen: T) extends DecoupledIO(gen) { - def init(): Unit = { - this.noenq() - } - override def cloneType: this.type = EnqIO(gen).asInstanceOf[this.type] - } - class DeqIO[+T <: Data](gen: T) extends DecoupledIO(gen) { - chisel3.core.Binding.bind(this, chisel3.core.FlippedBinder, "Error: Cannot flip ") - def init(): Unit = { - this.nodeq() - } - override def cloneType: this.type = DeqIO(gen).asInstanceOf[this.type] - } - object EnqIO { - def apply[T<:Data](gen: T): DecoupledIO[T] = DecoupledIO(gen) - } - object DeqIO { - def apply[T<:Data](gen: T): DecoupledIO[T] = Flipped(DecoupledIO(gen)) - } type QueueIO[T <: Data] = chisel3.util.QueueIO[T] type Queue[T <: Data] = chisel3.util.Queue[T] val Queue = chisel3.util.Queue diff --git a/src/main/scala/chisel3/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala index f1908089..0793fd7d 100644 --- a/src/main/scala/chisel3/internal/firrtl/Emitter.scala +++ b/src/main/scala/chisel3/internal/firrtl/Emitter.scala @@ -40,7 +40,7 @@ private class Emitter(circuit: Circuit) { s"skip" } e.sourceInfo match { - case SourceLine(filename, line, col) => s"${firrtlLine} @[${filename} ${line}:${col}] " + case SourceLine(filename, line, col) => s"${firrtlLine} @[${filename} ${line}:${col}]" case _: NoSourceInfo => firrtlLine } } @@ -102,7 +102,9 @@ private class Emitter(circuit: Circuit) { private def unindent() { require(indentLevel > 0); indentLevel -= 1 } private def withIndent(f: => Unit) { indent(); f; unindent() } - private val res = new StringBuilder(s"circuit ${circuit.name} : ") + private val res = new StringBuilder() + res ++= s";${Driver.chiselVersionString}\n" + res ++= s"circuit ${circuit.name} : " withIndent { circuit.components.foreach(c => res ++= emit(c)) } res ++= newline } diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala index 17ddd55a..d0808980 100644 --- a/src/main/scala/chisel3/package.scala +++ b/src/main/scala/chisel3/package.scala @@ -152,6 +152,7 @@ package object chisel3 { // scalastyle:ignore package.object.name implicit class fromUIntToBitPatComparable(val x: UInt) extends AnyVal { final def === (that: BitPat): Bool = macro SourceInfoTransform.thatArg + @deprecated("Use '=/=', which avoids potential precedence problems", "chisel3") final def != (that: BitPat): Bool = macro SourceInfoTransform.thatArg final def =/= (that: BitPat): Bool = macro SourceInfoTransform.thatArg @@ -166,28 +167,6 @@ package object chisel3 { // scalastyle:ignore package.object.name val NODIR = chisel3.core.Direction.Unspecified type ChiselException = chisel3.internal.ChiselException - class EnqIO[+T <: Data](gen: T) extends DecoupledIO(gen) { - def init(): Unit = { - this.noenq() - } - override def cloneType: this.type = EnqIO(gen).asInstanceOf[this.type] - } - class DeqIO[+T <: Data](gen: T) extends DecoupledIO(gen) { - val Data = chisel3.core.Data - Data.setFirrtlDirection(this, Data.getFirrtlDirection(this).flip) - Binding.bind(this, FlippedBinder, "Error: Cannot flip ") - def init(): Unit = { - this.nodeq() - } - override def cloneType: this.type = DeqIO(gen).asInstanceOf[this.type] - } - object EnqIO { - def apply[T<:Data](gen: T): EnqIO[T] = new EnqIO(gen) - } - object DeqIO { - def apply[T<:Data](gen: T): DeqIO[T] = new DeqIO(gen) - } - // Debugger/Tester access to internal Chisel data structures and methods. def getDataElements(a: Aggregate): Seq[Element] = { a.allElements diff --git a/src/main/scala/chisel3/testers/TesterDriver.scala b/src/main/scala/chisel3/testers/TesterDriver.scala index 586fa780..76b9a2e9 100644 --- a/src/main/scala/chisel3/testers/TesterDriver.scala +++ b/src/main/scala/chisel3/testers/TesterDriver.scala @@ -3,15 +3,13 @@ package chisel3.testers import chisel3._ -import scala.io.Source -import scala.sys.process._ import java.io._ object TesterDriver extends BackendCompilationUtilities { /** Copy the contents of a resource to a destination file. */ def copyResourceToFile(name: String, file: File) { - val in = getClass().getResourceAsStream(name) + val in = getClass.getResourceAsStream(name) if (in == null) { throw new FileNotFoundException(s"Resource '$name'") } @@ -22,7 +20,9 @@ object TesterDriver extends BackendCompilationUtilities { /** For use with modules that should successfully be elaborated by the * frontend, and which can be turned into executables with assertions. */ - def execute(t: () => BasicTester, additionalVResources: Seq[String] = Seq()): Boolean = { + def execute(t: () => BasicTester, + additionalVResources: Seq[String] = Seq(), + runFirrtlasProcess: Boolean = false): Boolean = { // Invoke the chisel compiler to get the circuit's IR val circuit = Driver.elaborate(finishWrapper(t)) @@ -46,13 +46,28 @@ object TesterDriver extends BackendCompilationUtilities { out }) - // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe - if ((firrtlToVerilog(target, path) #&& + if(runFirrtlasProcess) { + // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe + if ((firrtlToVerilog(target, path) #&& verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&& - cppToExe(target, path)).! == 0) { - executeExpectingSuccess(target, path) - } else { - false + cppToExe(target, path)).! == 0) { + executeExpectingSuccess(target, path) + } else { + false + } + } + else { + // Compile firrtl + if (!compileFirrtlToVerilog(target, path)) { + return false + } + // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe + if ((verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&& + cppToExe(target, path)).! == 0) { + executeExpectingSuccess(target, path) + } else { + false + } } } /** diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 972010a6..e58258c7 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -82,6 +82,7 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) { def getWidth: Int = width def === (that: UInt): Bool = macro SourceInfoTransform.thatArg def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg + @deprecated("Use '=/=', which avoids potential precedence problems", "chisel3") def != (that: UInt): Bool = macro SourceInfoTransform.thatArg def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = value.asUInt === (that & mask.asUInt) // scalastyle:ignore method.name diff --git a/src/test/scala/chiselTests/ComplexAssign.scala b/src/test/scala/chiselTests/ComplexAssign.scala index 0a1f31cc..c5a23f82 100644 --- a/src/test/scala/chiselTests/ComplexAssign.scala +++ b/src/test/scala/chiselTests/ComplexAssign.scala @@ -11,7 +11,7 @@ import chisel3.util._ class Complex[T <: Data](val re: T, val im: T) extends Bundle { override def cloneType: this.type = - new Complex(re.chiselCloneType, im.chiselCloneType).asInstanceOf[this.type] + new Complex(re.cloneType, im.cloneType).asInstanceOf[this.type] } class ComplexAssign(w: Int) extends Module { diff --git a/src/test/scala/chiselTests/DriverSpec.scala b/src/test/scala/chiselTests/DriverSpec.scala new file mode 100644 index 00000000..4f9619e3 --- /dev/null +++ b/src/test/scala/chiselTests/DriverSpec.scala @@ -0,0 +1,33 @@ +// See LICENSE for license details. + +package chiselTests + +import chisel3._ + +import org.scalatest.{Matchers, FreeSpec} + +class DummyModule extends Module { + val io = IO(new Bundle { + val in = UInt(INPUT, 1) + val out = UInt(OUTPUT, 1) + }) + io.out := io.in +} + +class DriverSpec extends FreeSpec with Matchers { + "Driver's execute methods are used to run chisel and firrtl" - { + "options can be picked up from comand line with no args" in { + Driver.execute(Array.empty[String], () => new DummyModule) + } + "options can be picked up from comand line setting top name" in { + Driver.execute(Array("-tn", "dm", "-td", "local-build"), () => new DummyModule) + } + "execute returns a chisel execution result" in { + val args = Array("--compiler", "low") + val result = Driver.execute(Array.empty[String], () => new DummyModule) + result shouldBe a[ChiselExecutionSucccess] + val successResult = result.asInstanceOf[ChiselExecutionSucccess] + successResult.emitted should include ("circuit DummyModule") + } + } +} diff --git a/src/test/scala/chiselTests/IOCompatibility.scala b/src/test/scala/chiselTests/IOCompatibility.scala index 7bf3dded..552fe776 100644 --- a/src/test/scala/chiselTests/IOCompatibility.scala +++ b/src/test/scala/chiselTests/IOCompatibility.scala @@ -3,6 +3,8 @@ package chiselTests import chisel3._ +import chisel3.core.Binding.BindingException +import org.scalatest._ class IOCSimpleIO extends Bundle { val in = Input(UInt(width=32)) @@ -33,7 +35,7 @@ class IOCModuleWire extends Module { io.out := inc.out } -class IOCompatibilitySpec extends ChiselPropSpec { +class IOCompatibilitySpec extends ChiselPropSpec with Matchers { property("IOCModuleVec should elaborate") { elaborate { new IOCModuleVec(2) } @@ -42,4 +44,16 @@ class IOCompatibilitySpec extends ChiselPropSpec { property("IOCModuleWire should elaborate") { elaborate { new IOCModuleWire } } + + + class IOUnwrapped extends Module { + val io = new IOCSimpleIO + io.out := io.in + } + + property("Unwrapped IO should generate an exception") { + a [BindingException] should be thrownBy { + elaborate(new IOUnwrapped) + } + } } diff --git a/src/test/scala/chiselTests/MultiAssign.scala b/src/test/scala/chiselTests/MultiAssign.scala index fa4c4898..397ea4c2 100644 --- a/src/test/scala/chiselTests/MultiAssign.scala +++ b/src/test/scala/chiselTests/MultiAssign.scala @@ -9,7 +9,8 @@ import chisel3.testers.BasicTester import chisel3.util._ class LastAssignTester() extends BasicTester { - val cnt = Counter(2) + val countOnClockCycles = Bool(true) + val (cnt, wrap) = Counter(countOnClockCycles,2) val test = Wire(UInt.width(4)) assert(test === 7.U) // allow read references before assign references @@ -20,7 +21,7 @@ class LastAssignTester() extends BasicTester { test := 7.U assert(test === 7.U) // this obviously should work - when(cnt.value === 1.U) { + when(cnt === 1.U) { stop() } } diff --git a/src/test/scala/chiselTests/Reg.scala b/src/test/scala/chiselTests/Reg.scala index a9086223..90992c01 100644 --- a/src/test/scala/chiselTests/Reg.scala +++ b/src/test/scala/chiselTests/Reg.scala @@ -2,6 +2,7 @@ package chiselTests +import firrtl.ir.Input import org.scalatest._ import chisel3._ import chisel3.core.DataMirror diff --git a/src/test/scala/cookbook/Bundle2UInt.scala b/src/test/scala/cookbook/Bundle2UInt.scala new file mode 100644 index 00000000..d74218a8 --- /dev/null +++ b/src/test/scala/cookbook/Bundle2UInt.scala @@ -0,0 +1,31 @@ +// See LICENSE for license details. + +package cookbook + +import chisel3._ + +/* ### How do I create a UInt from an instance of a Bundle? + * + * Call asUInt on the Bundle instance + */ +class Bundle2UInt extends CookbookTester(0) { + // Example + class MyBundle extends Bundle { + val foo = UInt(width = 4) + val bar = UInt(width = 4) + } + val bundle = Wire(new MyBundle) + bundle.foo := UInt(0xc) + bundle.bar := UInt(0x3) + val uint = bundle.asUInt + printf(p"$uint") // 195 + + // Test + assert(uint === UInt(0xc3)) +} + +class Bundle2UIntSpec extends CookbookSpec { + "Bundle2UInt" should "work" in { + assertTesterPasses { new Bundle2UInt } + } +} diff --git a/src/test/scala/cookbook/CookbookSpec.scala b/src/test/scala/cookbook/CookbookSpec.scala new file mode 100644 index 00000000..b244f3cf --- /dev/null +++ b/src/test/scala/cookbook/CookbookSpec.scala @@ -0,0 +1,25 @@ +// See LICENSE for license details. + +package cookbook + +import chisel3._ +import chisel3.util._ +import chisel3.testers.BasicTester + +import chiselTests.ChiselFlatSpec + +/** Tester for concise cookbook tests + * + * Provides a length of test after which the test will pass + */ +abstract class CookbookTester(length: Int) extends BasicTester { + require(length >= 0, "Simulation length must be non-negative!") + + // No IO allowed, cookbook tests must be self-contained + override final val io = new Bundle { } + + val (cycle, done) = Counter(Bool(true), length) + when (done) { stop() } +} + +abstract class CookbookSpec extends ChiselFlatSpec diff --git a/src/test/scala/cookbook/UInt2Bundle.scala b/src/test/scala/cookbook/UInt2Bundle.scala new file mode 100644 index 00000000..fbf7fe8a --- /dev/null +++ b/src/test/scala/cookbook/UInt2Bundle.scala @@ -0,0 +1,30 @@ +// See LICENSE for license details. + +package cookbook + +import chisel3._ + +/* ### How do I create a Bundle from a UInt? + * + * On an instance of the Bundle, call the method fromBits with the UInt as the argument + */ +class UInt2Bundle extends CookbookTester(0) { + // Example + class MyBundle extends Bundle { + val foo = UInt(width = 4) + val bar = UInt(width = 4) + } + val uint = UInt(0xb4) + val bundle = (new MyBundle).fromBits(uint) + printf(p"$bundle") // Bundle(foo -> 11, bar -> 4) + + // Test + assert(bundle.foo === UInt(0xb)) + assert(bundle.bar === UInt(0x4)) +} + +class UInt2BundleSpec extends CookbookSpec { + "UInt2Bundle" should "work" in { + assertTesterPasses { new UInt2Bundle } + } +} diff --git a/src/test/scala/cookbook/UInt2VecOfBool.scala b/src/test/scala/cookbook/UInt2VecOfBool.scala new file mode 100644 index 00000000..ad4a0334 --- /dev/null +++ b/src/test/scala/cookbook/UInt2VecOfBool.scala @@ -0,0 +1,29 @@ +// See LICENSE for license details. + +package cookbook + +import chisel3._ + +/* ### How do I create a Vec of Bools from a UInt? + * + * Use the builtin function [[chisel3.core.Bits.toBools]] to create a Scala Seq of Bool, + * then wrap the resulting Seq in Vec(...) + */ +class UInt2VecOfBool extends CookbookTester(0) { + // Example + val uint = UInt(0xc) + val vec = Vec(uint.toBools) + printf(p"$vec") // Vec(0, 0, 1, 1) + + // Test + assert(vec(0) === Bool(false)) + assert(vec(1) === Bool(false)) + assert(vec(2) === Bool(true)) + assert(vec(3) === Bool(true)) +} + +class UInt2VecOfBoolSpec extends CookbookSpec { + "UInt2VecOfBool" should "work" in { + assertTesterPasses { new UInt2VecOfBool } + } +} diff --git a/src/test/scala/cookbook/VecOfBool2UInt.scala b/src/test/scala/cookbook/VecOfBool2UInt.scala new file mode 100644 index 00000000..5852120c --- /dev/null +++ b/src/test/scala/cookbook/VecOfBool2UInt.scala @@ -0,0 +1,28 @@ +// See LICENSE for license details. + +package cookbook + +import chisel3._ + +/* ### How do I create a UInt from a Vec of Bool? + * + * Use the builtin function asUInt + */ +class VecOfBool2UInt extends CookbookTester(0) { + // Example + val vec = Vec(Bool(true), Bool(false), Bool(true), Bool(true)) + val uint = vec.asUInt + printf(p"$uint") // 13 + + /* Test + * + * (remember leftmost Bool in Vec is low order bit) + */ + assert(UInt(0xd) === uint) +} + +class VecOfBool2UIntSpec extends CookbookSpec { + "VecOfBool2UInt" should "work" in { + assertTesterPasses { new VecOfBool2UInt } + } +} |
