From d7697eb14a0195cc3726bf45fdf38c631b6f6507 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Fri, 20 May 2016 13:38:18 -0700 Subject: Update BackendCompilationUtilities.verilogToCpp to specify top-module This prevents Verilator from erroring when it cannot determine the top-module. It also changes the PRINTF_COND guard to correctly use the top-level reset instead of just the top of the Chisel-generated code. --- src/main/scala/Chisel/Driver.scala | 9 ++++----- src/main/scala/Chisel/testers/TesterDriver.scala | 2 +- src/test/scala/chiselTests/Harness.scala | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala index d5952834..02204684 100644 --- a/src/main/scala/Chisel/Driver.scala +++ b/src/main/scala/Chisel/Driver.scala @@ -46,17 +46,15 @@ trait BackendCompilationUtilities { * The Verilator prefix will be V$dutFile, and running this will generate * C++ sources and headers as well as a makefile to compile them. * - * Verilator will automatically locate the top-level module as the one among - * all the files which are not included elsewhere. If multiple ones exist, - * the compilation will fail. - * * @param dutFile name of the DUT .v without the .v extension + * @param name of the top-level module in the design * @param dir output directory * @param vSources list of additional Verilog sources to compile * @param cppHarness C++ testharness to compile/link against */ def verilogToCpp( dutFile: String, + topModule: String, dir: File, vSources: Seq[File], cppHarness: File @@ -70,8 +68,9 @@ trait BackendCompilationUtilities { "-Wno-STMTDLY", "--trace", "-O2", + "--top-module", topModule, "+define+TOP_TYPE=V" + dutFile, - s"+define+PRINTF_COND=!$dutFile.reset", + s"+define+PRINTF_COND=!$topModule.reset", "-CFLAGS", s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$dutFile -include V$dutFile.h""", "-Mdir", dir.toString, diff --git a/src/main/scala/Chisel/testers/TesterDriver.scala b/src/main/scala/Chisel/testers/TesterDriver.scala index c0cdfb3f..a56bb8b7 100644 --- a/src/main/scala/Chisel/testers/TesterDriver.scala +++ b/src/main/scala/Chisel/testers/TesterDriver.scala @@ -47,7 +47,7 @@ object TesterDriver extends BackendCompilationUtilities { // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe if ((firrtlToVerilog(target, path) #&& - verilogToCpp(target, path, additionalVFiles, cppHarness) #&& + verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&& cppToExe(target, path)).! == 0) { executeExpectingSuccess(target, path) } else { diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala index b06f4572..bc838766 100644 --- a/src/test/scala/chiselTests/Harness.scala +++ b/src/test/scala/chiselTests/Harness.scala @@ -55,7 +55,7 @@ int main(int argc, char **argv, char **env) { val cppHarness = makeCppHarness(fname) make(fname) - verilogToCpp(target, path, Seq(), cppHarness).! + verilogToCpp(target, target, path, Seq(), cppHarness).! cppToExe(target, path).! (path, target) } -- cgit v1.2.3 From e92f2f69477a6ce86fc148a1a95db5797f2e3051 Mon Sep 17 00:00:00 2001 From: ducky Date: Thu, 5 May 2016 13:22:04 -0700 Subject: Implementation of source locators --- .../scala/Chisel/internal/firrtl/Emitter.scala | 112 +++++++++++++++++++++ src/main/scala/Chisel/testers/BasicTester.scala | 8 +- 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/Chisel/internal/firrtl/Emitter.scala (limited to 'src') diff --git a/src/main/scala/Chisel/internal/firrtl/Emitter.scala b/src/main/scala/Chisel/internal/firrtl/Emitter.scala new file mode 100644 index 00000000..7ca3268a --- /dev/null +++ b/src/main/scala/Chisel/internal/firrtl/Emitter.scala @@ -0,0 +1,112 @@ +// See LICENSE for license details. + +package Chisel.internal.firrtl +import Chisel._ +import Chisel.internal.sourceinfo.{NoSourceInfo, SourceLine} + +private[Chisel] object Emitter { + def emit(circuit: Circuit): String = new Emitter(circuit).toString +} + +private class Emitter(circuit: Circuit) { + override def toString: String = res.toString + + private def emitPort(e: Port): String = + s"${e.dir} ${e.id.getRef.name} : ${e.id.toType}" + private def emit(e: Command, ctx: Component): String = { + val firrtlLine = e match { + case e: DefPrim[_] => s"node ${e.name} = ${e.op.name}(${e.args.map(_.fullName(ctx)).mkString(", ")})" + case e: DefWire => s"wire ${e.name} : ${e.id.toType}" + case e: DefReg => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)}" + case e: DefRegInit => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))" + case e: DefMemory => s"cmem ${e.name} : ${e.t.toType}[${e.size}]" + case e: DefSeqMemory => s"smem ${e.name} : ${e.t.toType}[${e.size}]" + case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}" + case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}" + case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}" + case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})" + case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})""" + case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid" + case e: DefInstance => { + val modName = moduleMap.get(e.id.name).get + s"inst ${e.name} of $modName" + } + + case w: WhenBegin => + indent() + s"when ${w.pred.fullName(ctx)} :" + case _: WhenEnd => + unindent() + s"skip" + } + e.sourceInfo match { + case SourceLine(filename, line, col) => s"${firrtlLine} @[${filename} ${line}:${col}] " + case _: NoSourceInfo => firrtlLine + } + } + + // Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already. + private val defnMap = collection.mutable.HashMap[String, String]() + // Map of Component name to FIRRTL id. + private val moduleMap = collection.mutable.HashMap[String, String]() + + /** Generates the FIRRTL module definition with a specified name. + */ + private def moduleDefn(m: Component, name: String): String = { + val body = new StringBuilder + m.id match { + case _: BlackBox => body ++= newline + s"extmodule $name : " + case _: Module => body ++= newline + s"module $name : " + } + withIndent { + for (p <- m.ports) + body ++= newline + emitPort(p) + body ++= newline + + m.id match { + case _: BlackBox => + // TODO: BlackBoxes should be empty, but funkiness in Module() means + // it's not for now. Eventually, this should assert out. + case _: Module => for (cmd <- m.commands) { + body ++= newline + emit(cmd, m) + } + } + body ++= newline + } + body.toString() + } + + /** Returns the FIRRTL declaration and body of a module, or nothing if it's a + * duplicate of something already emitted (on the basis of simple string + * matching). + */ + private def emit(m: Component): String = { + // Generate the body. + val moduleName = m.id.getClass.getName.split('.').last + val defn = moduleDefn(m, moduleName) + + defnMap get defn match { + case Some(deduplicatedName) => + moduleMap(m.name) = deduplicatedName + "" + case None => + require(!(moduleMap contains m.name), + "emitting module with same name but different contents") + + moduleMap(m.name) = m.name + defnMap(defn) = m.name + + moduleDefn(m, m.name) + } + } + + private var indentLevel = 0 + private def newline = "\n" + (" " * indentLevel) + private def indent(): Unit = indentLevel += 1 + 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} : ") + withIndent { circuit.components.foreach(c => res ++= emit(c)) } + res ++= newline +} diff --git a/src/main/scala/Chisel/testers/BasicTester.scala b/src/main/scala/Chisel/testers/BasicTester.scala index d3e9e7c8..b8c1494a 100644 --- a/src/main/scala/Chisel/testers/BasicTester.scala +++ b/src/main/scala/Chisel/testers/BasicTester.scala @@ -3,9 +3,12 @@ package Chisel.testers import Chisel._ +import scala.language.experimental.macros + import internal._ import internal.Builder.pushCommand import internal.firrtl._ +import internal.sourceinfo.SourceInfo class BasicTester extends Module { // The testbench has no IOs, rather it should communicate using printf, assert, and stop. @@ -19,9 +22,10 @@ class BasicTester extends Module { * reset). If your definition of reset is not the encapsulating Module's * reset, you will need to gate this externally. */ - def stop() { + def stop()(implicit sourceInfo: SourceInfo) { + // TODO: rewrite this using library-style SourceInfo passing. when (!reset) { - pushCommand(Stop(Node(clock), 0)) + pushCommand(Stop(sourceInfo, Node(clock), 0)) } } -- cgit v1.2.3 From 3b10267257de7662abbbc235d9bfd8a8b89f69f5 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 26 May 2016 01:01:55 -0700 Subject: Fix type constraint on PriorityMux --- src/main/scala/Chisel/util/Mux.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main/scala/Chisel/util/Mux.scala b/src/main/scala/Chisel/util/Mux.scala index a7d835f6..9d92321a 100644 --- a/src/main/scala/Chisel/util/Mux.scala +++ b/src/main/scala/Chisel/util/Mux.scala @@ -25,9 +25,9 @@ object Mux1H */ object PriorityMux { - def apply[T <: Bits](in: Seq[(Bool, T)]): T = SeqUtils.priorityMux(in) - def apply[T <: Bits](sel: Seq[Bool], in: Seq[T]): T = apply(sel zip in) - def apply[T <: Bits](sel: Bits, in: Seq[T]): T = apply((0 until in.size).map(sel(_)), in) + def apply[T <: Data](in: Seq[(Bool, T)]): T = SeqUtils.priorityMux(in) + def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = apply(sel zip in) + def apply[T <: Data](sel: Bits, in: Seq[T]): T = apply((0 until in.size).map(sel(_)), in) } /** MuxLookup creates a cascade of n Muxs to search for a key value */ -- cgit v1.2.3 From 2e2e3da0c07cd1dc873c064510f68123cae69059 Mon Sep 17 00:00:00 2001 From: Ducky Date: Mon, 23 May 2016 14:09:26 -0700 Subject: Move BitPat out of core/frontend, add implicit conversion --- src/main/scala/Chisel/BitPat.scala | 88 +++++++++++++++++++++++++++++++++++++ src/main/scala/Chisel/package.scala | 14 ++++++ 2 files changed, 102 insertions(+) create mode 100644 src/main/scala/Chisel/BitPat.scala (limited to 'src') diff --git a/src/main/scala/Chisel/BitPat.scala b/src/main/scala/Chisel/BitPat.scala new file mode 100644 index 00000000..cf412542 --- /dev/null +++ b/src/main/scala/Chisel/BitPat.scala @@ -0,0 +1,88 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import Chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} + +object BitPat { + /** Parses a bit pattern string into (bits, mask, width). + * + * @return bits the literal value, with don't cares being 0 + * @return mask the mask bits, with don't cares being 0 and cares being 1 + * @return width the number of bits in the literal, including values and + * don't cares. + */ + private def parse(x: String): (BigInt, BigInt, Int) = { + // Notes: + // While Verilog Xs also handle octal and hex cases, there isn't a + // compelling argument and no one has asked for it. + // If ? parsing is to be exposed, the return API needs further scrutiny + // (especially with things like mask polarity). + require(x.head == 'b', "BitPats must be in binary and be prefixed with 'b'") + var bits = BigInt(0) + var mask = BigInt(0) + for (d <- x.tail) { + if (d != '_') { + require("01?".contains(d), "Literal: " + x + " contains illegal character: " + d) + mask = (mask << 1) + (if (d == '?') 0 else 1) + bits = (bits << 1) + (if (d == '1') 1 else 0) + } + } + (bits, mask, x.length - 1) + } + + /** Creates a [[BitPat]] literal from a string. + * + * @param n the literal value as a string, in binary, prefixed with 'b' + * @note legal characters are '0', '1', and '?', as well as '_' as white + * space (which are ignored) + */ + def apply(n: String): BitPat = { + val (bits, mask, width) = parse(n) + new BitPat(bits, mask, width) + } + + /** Creates a [[BitPat]] of all don't cares of the specified bitwidth. */ + def dontCare(width: Int): BitPat = BitPat("b" + ("?" * width)) + + @deprecated("Use BitPat.dontCare", "chisel3") + def DC(width: Int): BitPat = dontCare(width) // scalastyle:ignore method.name + + /** Allows BitPats to be used where a UInt is expected. + * + * @note the BitPat must not have don't care bits (will error out otherwise) + */ + implicit def bitPatToUInt(x: BitPat): UInt = { + require(x.mask == (BigInt(1) << x.getWidth) - 1) + UInt(x.value, x.getWidth) + } + + /** Allows UInts to be used where a BitPat is expected, useful for when an + * interface is defined with BitPats but not all cases need the partial + * matching capability. + * + * @note the UInt must be a literal + */ + implicit def apply(x: UInt): BitPat = { + require(x.isLit) + BitPat("b" + x.litValue.toString(2)) + } +} + +// TODO: Break out of Core? (this doesn't involve FIRRTL generation) +/** Bit patterns are literals with masks, used to represent values with don't + * cares. Equality comparisons will ignore don't care bits (for example, + * BitPat(0b10?1) === UInt(0b1001) and UInt(0b1011)). + */ +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 + def != (that: UInt): Bool = macro SourceInfoTransform.thatArg + + def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = UInt(value) === (that & UInt(mask)) + def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = !(this === that) + def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = this =/= that +} diff --git a/src/main/scala/Chisel/package.scala b/src/main/scala/Chisel/package.scala index 61fb6904..f05e8b5d 100644 --- a/src/main/scala/Chisel/package.scala +++ b/src/main/scala/Chisel/package.scala @@ -1,5 +1,9 @@ package object Chisel { + import scala.language.experimental.macros + import internal.firrtl.Width + import internal.sourceinfo.{SourceInfo, SourceInfoTransform} + implicit class fromBigIntToLiteral(val x: BigInt) extends AnyVal { def U: UInt = UInt(x, Width()) def S: SInt = SInt(x, Width()) @@ -14,4 +18,14 @@ package object Chisel { implicit class fromBooleanToLiteral(val x: Boolean) extends AnyVal { def B: Bool = Bool(x) } + + implicit class fromUIntToBitPatComparable(val x: UInt) extends AnyVal { + final def === (that: BitPat): Bool = macro SourceInfoTransform.thatArg + final def != (that: BitPat): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: BitPat): Bool = macro SourceInfoTransform.thatArg + + def do_=== (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that === x + def do_!= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that != x + def do_=/= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that =/= x + } } -- cgit v1.2.3 From 0b6f6b67f9b511468936ca30218343283071a69d Mon Sep 17 00:00:00 2001 From: ducky Date: Thu, 26 May 2016 21:43:11 -0700 Subject: Remove unsafe implicit conversions from BitPat --- src/main/scala/Chisel/BitPat.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main/scala/Chisel/BitPat.scala b/src/main/scala/Chisel/BitPat.scala index cf412542..96206f63 100644 --- a/src/main/scala/Chisel/BitPat.scala +++ b/src/main/scala/Chisel/BitPat.scala @@ -54,7 +54,7 @@ object BitPat { * * @note the BitPat must not have don't care bits (will error out otherwise) */ - implicit def bitPatToUInt(x: BitPat): UInt = { + def bitPatToUInt(x: BitPat): UInt = { require(x.mask == (BigInt(1) << x.getWidth) - 1) UInt(x.value, x.getWidth) } @@ -65,7 +65,7 @@ object BitPat { * * @note the UInt must be a literal */ - implicit def apply(x: UInt): BitPat = { + def apply(x: UInt): BitPat = { require(x.isLit) BitPat("b" + x.litValue.toString(2)) } -- cgit v1.2.3 From fd53af8642237998e23456a3fd1648ac84607db0 Mon Sep 17 00:00:00 2001 From: Wesley W. Terpstra Date: Wed, 1 Jun 2016 16:09:20 -0700 Subject: Fix a fairly serious bug whereby Vec's could incorrectly compare as equal (#204) * chiselTests: include an example of two empty Vectors killing FIRRTL * Aggregate: fix a bug whereby Vec[T] was using equals/hashCode of Seq In Chisel, two vectors are NOT equal just if their contents are equal. For example, two empty vectors should not be considered equal. This patch makes Vec use the HasId._id for equality like other Chisel types. Without this fix, Bundle.namedElts.seen: HashSet[Data]() will eliminate one of the named vectors and emit bad IR. --- src/test/scala/chiselTests/Vec.scala | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala index 5239c6ba..943d9e4b 100644 --- a/src/test/scala/chiselTests/Vec.scala +++ b/src/test/scala/chiselTests/Vec.scala @@ -41,6 +41,32 @@ class ShiftRegisterTester(n: Int) extends BasicTester { } } +class FunBundle extends Bundle { + val stuff = UInt(width = 10) +} + +class ZeroModule extends Module { + val io = new Bundle { + val mem = UInt(width = 10) + val interrupts = Vec(2, Bool()).asInput + val mmio_axi = Vec(0, new FunBundle) + val mmio_ahb = Vec(0, new FunBundle).flip + } + + io.mmio_axi <> io.mmio_ahb + + io.mem := UInt(0) + when (io.interrupts(0)) { io.mem := UInt(1) } + when (io.interrupts(1)) { io.mem := UInt(2) } +} + +class ZeroTester extends BasicTester { + val foo = Module(new ZeroModule) + foo.io.interrupts := Vec.tabulate(2) { _ => Bool(true) } + assert (foo.io.mem === UInt(2)) + stop() +} + class VecSpec extends ChiselPropSpec { property("Vecs should be assignable") { forAll(safeUIntN(8)) { case(w: Int, v: List[Int]) => @@ -55,4 +81,8 @@ class VecSpec extends ChiselPropSpec { property("Regs of vecs should be usable as shift registers") { forAll(smallPosInts) { (n: Int) => assertTesterPasses{ new ShiftRegisterTester(n) } } } + + property("Dual empty Vectors") { + assertTesterPasses{ new ZeroTester } + } } -- cgit v1.2.3