diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/chisel3/ChiselExecutionOptions.scala | 34 | ||||
| -rw-r--r-- | src/main/scala/chisel3/Driver.scala | 161 | ||||
| -rw-r--r-- | src/main/scala/chisel3/compatibility.scala | 19 | ||||
| -rw-r--r-- | src/main/scala/chisel3/internal/firrtl/Emitter.scala | 6 | ||||
| -rw-r--r-- | src/main/scala/chisel3/package.scala | 23 | ||||
| -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/ComplexAssign.scala | 2 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/DriverSpec.scala | 33 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/IOCompatibility.scala | 16 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/MultiAssign.scala | 5 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/Reg.scala | 1 | ||||
| -rw-r--r-- | src/test/scala/cookbook/Bundle2UInt.scala | 31 | ||||
| -rw-r--r-- | src/test/scala/cookbook/CookbookSpec.scala | 25 | ||||
| -rw-r--r-- | src/test/scala/cookbook/UInt2Bundle.scala | 30 | ||||
| -rw-r--r-- | src/test/scala/cookbook/UInt2VecOfBool.scala | 29 | ||||
| -rw-r--r-- | src/test/scala/cookbook/VecOfBool2UInt.scala | 28 |
17 files changed, 415 insertions, 64 deletions
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 } + } +} |
