diff options
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 3 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Data.scala | 1 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Module.scala | 32 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 3 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala | 12 | ||||
| -rw-r--r-- | src/main/scala/chisel3/compatibility.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/chisel3/compatibility/debug.scala | 8 | ||||
| -rw-r--r-- | src/main/scala/chisel3/package.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/BitPat.scala | 3 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/Bitwise.scala | 15 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/CircuitMath.scala | 16 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/OneHot.scala | 2 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/BetterNamingTests.scala | 101 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/GCD.scala | 2 |
14 files changed, 166 insertions, 36 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 07c113fd..20ac0e4a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -36,6 +36,7 @@ abstract class Element(private[core] val width: Width) extends Data { def dir: Direction = binding.direction.get private[chisel3] final def allElements: Seq[Element] = Seq(this) + def widthKnown: Boolean = width.known } /** A data type for values represented by a single bitvector. Provides basic @@ -521,7 +522,7 @@ private[core] sealed trait UIntFactory { /** Create a UInt port with specified width. */ def width(width: Width): UInt = new UInt(width) /** Create a UInt with a specified width - compatibility with Chisel2. */ - def apply(dummy: Direction, width: Int): UInt = apply(Width(width)) + def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) /** Create a UInt literal with fixed width. */ def apply(value: BigInt, width: Int): UInt = Lit(value, Width(width)) /** Create a UInt literal with inferred width. */ diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index fee5c01c..9e362fa6 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -208,7 +208,6 @@ object Wire { Binding.checkSynthesizable(init, s"'init' ($init)") x := init } - x } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index e8474e39..a593f539 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -2,7 +2,7 @@ package chisel3.core -import scala.collection.mutable.{ArrayBuffer, HashSet} +import scala.collection.mutable.ArrayBuffer import scala.language.experimental.macros import chisel3.internal._ @@ -136,13 +136,35 @@ extends HasId { } // Suggest names to nodes using runtime reflection - val valNames = HashSet[String](getClass.getDeclaredFields.map(_.getName):_*) + def getValNames(c: Class[_]): Set[String] = { + if (c == classOf[Module]) Set() + else getValNames(c.getSuperclass) ++ c.getDeclaredFields.map(_.getName) + } + val valNames = getValNames(this.getClass) def isPublicVal(m: java.lang.reflect.Method) = m.getParameterTypes.isEmpty && valNames.contains(m.getName) + + /** Recursively suggests names to supported "container" classes + * Arbitrary nestings of supported classes are allowed so long as the + * innermost element is of type HasId + * Currently supported: + * - Iterable + * - Option + * (Note that Map is Iterable[Tuple2[_,_]] and thus excluded) + */ + def nameRecursively(prefix: String, nameMe: Any): Unit = + nameMe match { + case (id: HasId) => id.suggestName(prefix) + case Some(elt) => nameRecursively(prefix, elt) + case (iter: Iterable[_]) if iter.hasDefiniteSize => + for ((elt, i) <- iter.zipWithIndex) { + nameRecursively(s"${prefix}_${i}", elt) + } + case _ => // Do nothing + } val methods = getClass.getMethods.sortWith(_.getName > _.getName) - for (m <- methods; if isPublicVal(m)) m.invoke(this) match { - case (id: HasId) => id.suggestName(m.getName) - case _ => + for (m <- methods if isPublicVal(m)) { + nameRecursively(m.getName, m.invoke(this)) } // For Module instances we haven't named, suggest the name of the Module diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index c1693531..f5706833 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -8,8 +8,7 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { - private[core] def makeType[T <: Data](t: T = null, next: T = null, -init: T = null): T = { + private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") t.chiselCloneType diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index b06fd7a5..f4eec422 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -23,14 +23,10 @@ private[chisel3] object SeqUtils { /** Counts the number of true Bools in a Seq */ def count(in: Seq[Bool]): UInt = macro SourceInfoTransform.inArg - def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = { - if (in.size == 0) { - UInt.Lit(0) - } else if (in.size == 1) { - in.head - } else { - count(in.slice(0, in.size/2)) + (UInt.Lit(0) ## count(in.slice(in.size/2, in.size))) - } + def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = in.size match { + case 0 => UInt.Lit(0) + case 1 => in.head + case n => count(in take n/2) +& count(in drop n/2) } /** Returns data value corresponding to first true predicate */ diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index 9360acbc..b7020b5e 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -63,7 +63,7 @@ package object Chisel { val ImplicitConversions = chisel3.util.ImplicitConversions val chiselMain = chisel3.compatibility.chiselMain val throwException = chisel3.compatibility.throwException - val debug = chisel3.core.debug + val debug = chisel3.compatibility.debug object testers { type BasicTester = chisel3.testers.BasicTester diff --git a/src/main/scala/chisel3/compatibility/debug.scala b/src/main/scala/chisel3/compatibility/debug.scala new file mode 100644 index 00000000..c3966dae --- /dev/null +++ b/src/main/scala/chisel3/compatibility/debug.scala @@ -0,0 +1,8 @@ +package chisel3.compatibility + +import chisel3.core._ + +@deprecated("debug doesn't do anything in Chisel3 as no pruning happens in the frontend", "chisel3") +object debug { // scalastyle:ignore object.name + def apply (arg: Data): Data = arg +} diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala index d47ed890..9a79b109 100644 --- a/src/main/scala/chisel3/package.scala +++ b/src/main/scala/chisel3/package.scala @@ -100,7 +100,7 @@ package object chisel3 { 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 diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 3ae192a2..5b37bd1b 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -68,7 +68,8 @@ object BitPat { */ def apply(x: UInt): BitPat = { require(x.isLit) - BitPat("b" + x.litValue.toString(2)) + val len = if (x.widthKnown) x.getWidth else 0 + apply("b" + x.litValue.toString(2).reverse.padTo(len, "0").reverse.mkString) } } diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala index b2a9a28c..2743e59f 100644 --- a/src/main/scala/chisel3/util/Bitwise.scala +++ b/src/main/scala/chisel3/util/Bitwise.scala @@ -11,7 +11,7 @@ import chisel3.core.SeqUtils object FillInterleaved { def apply(n: Int, in: UInt): UInt = apply(n, in.toBools) - def apply(n: Int, in: Seq[Bool]): UInt = Vec(in.map(Fill(n, _))).toBits + def apply(n: Int, in: Seq[Bool]): UInt = Cat(in.map(Fill(n, _)).reverse) } /** Returns the number of bits set (i.e value is 1) in the input signal. @@ -29,22 +29,17 @@ object Fill { n match { case 0 => UInt.width(0) case 1 => x - case y if n > 1 => + case _ if x.widthKnown && x.getWidth == 1 => + Mux(x.toBool, UInt((BigInt(1) << n) - 1, n), UInt(0, n)) + case _ if n > 1 => val p2 = Array.ofDim[UInt](log2Up(n + 1)) p2(0) = x for (i <- 1 until p2.length) p2(i) = Cat(p2(i-1), p2(i-1)) - Cat((0 until log2Up(y + 1)).filter(i => (y & (1 << i)) != 0).map(p2(_))) + Cat((0 until log2Up(n + 1)).filter(i => (n & (1 << i)) != 0).map(p2(_))) case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") } } - /** Fan out x n times */ - def apply(n: Int, x: Bool): UInt = - if (n > 1) { - UInt(0,n) - x - } else { - apply(n, x: UInt) - } } /** Litte/big bit endian convertion: reverse the order of the bits in a UInt. diff --git a/src/main/scala/chisel3/util/CircuitMath.scala b/src/main/scala/chisel3/util/CircuitMath.scala index 8f8bde4a..27bd7bfb 100644 --- a/src/main/scala/chisel3/util/CircuitMath.scala +++ b/src/main/scala/chisel3/util/CircuitMath.scala @@ -7,11 +7,11 @@ package chisel3.util import chisel3._ -/** Compute Log2 with truncation of a UInt in hardware using a Mux Tree - * An alternative interpretation is it computes the minimum number of bits needed to represent x +/** Compute the base-2 integer logarithm of a UInt * @example * {{{ data_out := Log2(data_in) }}} - * @note Truncation is used so Log2(UInt.Lit(12412)) = 13*/ + * @note The result is truncated, so e.g. Log2(13.U) = 3 + */ object Log2 { /** Compute the Log2 on the least significant n bits of x */ def apply(x: Bits, width: Int): UInt = { @@ -19,10 +19,18 @@ object Log2 { UInt.Lit(0) } else if (width == 2) { x(1) + } else if (width <= divideAndConquerThreshold) { + Mux(x(width-1), UInt.Lit(width-1), apply(x, width-1)) } else { - Mux(x(width-1), UInt.width(width-1), apply(x, width-1)) + val mid = 1 << (log2Ceil(width) - 1) + val hi = x(width-1, mid) + val lo = x(mid-1, 0) + val useHi = hi.orR + Cat(useHi, Mux(useHi, Log2(hi, width - mid), Log2(lo, mid))) } } def apply(x: Bits): UInt = apply(x, x.getWidth) + + private def divideAndConquerThreshold = 4 } diff --git a/src/main/scala/chisel3/util/OneHot.scala b/src/main/scala/chisel3/util/OneHot.scala index c1f94ba6..49661115 100644 --- a/src/main/scala/chisel3/util/OneHot.scala +++ b/src/main/scala/chisel3/util/OneHot.scala @@ -10,7 +10,7 @@ import chisel3._ /** Converts from One Hot Encoding to a UInt indicating which bit is active * This is the inverse of [[Chisel.UIntToOH UIntToOH]]*/ object OHToUInt { - def apply(in: Seq[Bool]): UInt = apply(Vec(in)) + def apply(in: Seq[Bool]): UInt = apply(Cat(in.reverse), in.size) def apply(in: Vec[Bool]): UInt = apply(in.toBits, in.size) def apply(in: Bits): UInt = apply(in, in.getWidth) diff --git a/src/test/scala/chiselTests/BetterNamingTests.scala b/src/test/scala/chiselTests/BetterNamingTests.scala new file mode 100644 index 00000000..44fc542a --- /dev/null +++ b/src/test/scala/chiselTests/BetterNamingTests.scala @@ -0,0 +1,101 @@ +package chiselTests + +import org.scalatest.{FlatSpec, Matchers} +import collection.mutable + +import Chisel._ + + +// Defined outside of the class so we don't get $ in name +class Other(w: Int) extends Module { + val io = new Bundle { + val a = UInt(width = w) + } +} +class PerNameIndexing(count: Int) extends Module { + val io = new Bundle { } + + val wires = Seq.tabulate(count) { i => Module(new Other(i)) } + val queues = Seq.tabulate(count) { i => Module(new Queue(UInt(width = i), 16)) } +} + +// Note this only checks Iterable[Chisel.Data] which excludes Maps +class IterableNaming extends Module { + val io = new Bundle { } + + val seq = Seq.tabulate(3) { i => + Seq.tabulate(2) { j => Wire(init = (i * j).U) } + } + val optSet = Some(Set(Wire(init = 0.U), + Wire(init = 1.U), + Wire(init = 2.U), + Wire(init = 3.U))) + + val stack = mutable.Stack[Module]() + for (i <- 0 until 4) { + stack push Module(new Other(i)) + } + + def streamFrom(x: Int): Stream[Module] = + Module(new Other(x)) #:: streamFrom(x + 1) + val stream = streamFrom(0) // Check that we don't get into infinite loop + val list = stream.take(8).toList +} + +/* Better Naming Tests + * + * These tests are intended to validate that Chisel picks better names + */ +class BetterNamingTests extends FlatSpec { + + behavior of "Better Naming" + + it should "provide unique counters for each name" in { + val verilog = Driver.emit(() => new PerNameIndexing(4)) + val ModuleDef = """\s*module\s+(\S+)\s+:\s*""".r + val expectedModules = Set("PerNameIndexing", + "Queue", "Queue_1", "Queue_2", "Queue_3", + "Other", "Other_1", "Other_2", "Other_3") + val foundModules = for { + ModuleDef(name) <- verilog.split("\n").toSeq + } yield name + assert(foundModules.toSet === expectedModules) + } + + it should "provide names for things defined in Iterable[HasId] and Option[HasId]" in { + val verilog = Driver.emit(() => new IterableNaming) + + val lines = verilog.split("\n").toSeq + + val SeqDef = """\s*wire\s+seq_(\d+)_(\d+)\s+:\s+UInt\s*""".r + val seqs = for { + i <- (0 until 3) + j <- (0 until 2) + } yield (i.toString, j.toString) + val foundSeqs = for { + SeqDef(i, j) <- lines + } yield (i, j) + assert(foundSeqs.toSet === seqs.toSet) + + val OptSetDef = """\s*wire\s+optSet_(\d+)\s+:\s+UInt\s*""".r + val optSets = (0 until 4) map (_.toString) + val foundOptSets = for { + OptSetDef(i) <- lines + } yield i + assert(foundOptSets.toSet === optSets.toSet) + + val StackDef = """\s*inst\s+stack_(\d+)\s+of\s+Other.*""".r + val stacks = (0 until 4) map (_.toString) + val foundStacks = for { + StackDef(i) <- lines + } yield i + assert(foundStacks.toSet === stacks.toSet) + + val ListDef = """\s*inst\s+list_(\d+)\s+of\s+Other.*""".r + val lists = (0 until 8) map (_.toString) + val foundLists = for { + ListDef(i) <- lines + } yield i + assert(foundLists.toSet === lists.toSet) + } +} diff --git a/src/test/scala/chiselTests/GCD.scala b/src/test/scala/chiselTests/GCD.scala index 5e4c897a..d683ce34 100644 --- a/src/test/scala/chiselTests/GCD.scala +++ b/src/test/scala/chiselTests/GCD.scala @@ -30,7 +30,7 @@ class GCDTester(a: Int, b: Int, z: Int) extends BasicTester { dut.io.a := a.U dut.io.b := b.U dut.io.e := first - when(first) { first := false.B } + when(first) { first := Bool(false) } when(!first && dut.io.v) { assert(dut.io.z === z.U) stop() |
