diff options
| -rw-r--r-- | build.sbt | 27 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 2 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 5 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Data.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/chisel3/ChiselExecutionOptions.scala | 34 | ||||
| -rw-r--r-- | src/main/scala/chisel3/Driver.scala | 148 | ||||
| -rw-r--r-- | src/main/scala/chisel3/internal/firrtl/Emitter.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/chisel3/package.scala | 1 | ||||
| -rw-r--r-- | src/main/scala/chisel3/testers/TesterDriver.scala | 35 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/BitPat.scala | 1 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/BundleWire.scala | 28 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/DriverSpec.scala | 33 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/Reg.scala | 1 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/Vec.scala | 6 |
14 files changed, 293 insertions, 32 deletions
@@ -21,6 +21,8 @@ lazy val commonSettings = Seq ( scalaVersion := "2.11.7" ) +val defaultVersions = Map("firrtl" -> "1.1-SNAPSHOT") + lazy val chiselSettings = Seq ( name := "chisel3", @@ -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, diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 9d8a9061..5e88560c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -19,6 +19,8 @@ sealed abstract class Aggregate extends Data { private[core] def width: Width = flatten.map(_.width).reduce(_ + _) private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) + + override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = SeqUtils.do_asUInt(this.flatten) } object Vec { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 741f6aee..a5d954b6 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -282,9 +282,6 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) pushOp(DefPrim(sourceInfo, UInt(w), ConcatOp, this.ref, that.ref)) } - @deprecated("Use asUInt, which does the same thing but makes the reinterpret cast more explicit", "chisel3") - override def toBits: UInt = do_asUInt(DeprecatedSourceInfo) - override def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { val res = Wire(this, null).asInstanceOf[this.type] res := that @@ -463,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 @@ -658,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 bd2e9065..86858e5d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -254,7 +254,7 @@ abstract class Data extends HasId { * * This performs the inverse operation of fromBits(Bits). */ - @deprecated("Use asUInt, which does the same thing but makes the reinterpret cast more explicit", "chisel3") + @deprecated("Best alternative, .toUInt() or if Bits really needed, .toUInt().toBits()", "chisel3") def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) /** Reinterpret cast to UInt. 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 b0c7aeda..a0713379 100644 --- a/src/main/scala/chisel3/Driver.scala +++ b/src/main/scala/chisel3/Driver.scala @@ -2,11 +2,36 @@ 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 { @@ -32,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", @@ -68,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 @@ -105,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 @@ -112,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)) @@ -137,6 +212,71 @@ 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/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala index e0daa95c..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 } } diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala index 0a57b7de..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 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/BundleWire.scala b/src/test/scala/chiselTests/BundleWire.scala index 53d46e93..5b38ff6e 100644 --- a/src/test/scala/chiselTests/BundleWire.scala +++ b/src/test/scala/chiselTests/BundleWire.scala @@ -24,6 +24,27 @@ class BundleWire(n: Int) extends Module { } } +class BundleToUnitTester extends BasicTester { + val bundle1 = Wire(new Bundle { + val a = UInt(width = 4) + val b = UInt(width = 4) + }) + val bundle2 = Wire(new Bundle { + val a = UInt(width = 2) + val b = UInt(width = 6) + }) + + // 0b00011011 split as 0001 1011 and as 00 011011 + bundle1.a := 1.U + bundle1.b := 11.U + bundle2.a := 0.U + bundle2.b := 27.U + + assert(bundle1.asUInt() === bundle2.asUInt()) + + stop() +} + class BundleWireTester(n: Int, x: Int, y: Int) extends BasicTester { val dut = Module(new BundleWire(n)) dut.io.in.x := UInt(x) @@ -43,3 +64,10 @@ class BundleWireSpec extends ChiselPropSpec { } } } + +class BundleToUIntSpec extends ChiselPropSpec { + property("Bundles with same data but different, underlying elements should compare as UInt") { + assertTesterPasses( new BundleToUnitTester ) + } +} + 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/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/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala index c5447610..0d5a2188 100644 --- a/src/test/scala/chiselTests/Vec.scala +++ b/src/test/scala/chiselTests/Vec.scala @@ -23,9 +23,9 @@ class TabulateTester(n: Int) extends BasicTester { val x = Vec(Array.tabulate(n){ i => UInt(i * 2) }) val u = Vec.tabulate(n)(i => UInt(i*2)) - assert(v.toBits === x.toBits) - assert(v.toBits === u.toBits) - assert(x.toBits === u.toBits) + assert(v.asUInt() === x.asUInt()) + assert(v.asUInt() === u.asUInt()) + assert(x.asUInt() === u.asUInt()) stop() } |
