From 6e12ed9fd7a771eb30f44b8e1c4ab33f6ad8e0a6 Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Thu, 17 Aug 2017 17:24:02 -0700 Subject: More of the bindings refactor (#635) Rest of the binding refactor --- .../src/main/scala/chisel3/core/Aggregate.scala | 162 ++++++++++----------- .../src/main/scala/chisel3/core/Data.scala | 48 +++--- .../src/main/scala/chisel3/core/Mem.scala | 7 +- .../src/main/scala/chisel3/core/Reg.scala | 2 + 4 files changed, 113 insertions(+), 106 deletions(-) (limited to 'chiselFrontend') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index ca46323b..8700b444 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -76,7 +76,7 @@ sealed abstract class Aggregate extends Data { private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = { var i = 0 - val bits = Wire(UInt(this.width), init=that) // handles width padding + val bits = WireInit(UInt(this.width), that) // handles width padding for (x <- flatten) { x.connectFromBits(bits(i + x.getWidth - 1, i)) i += x.getWidth @@ -84,96 +84,18 @@ sealed abstract class Aggregate extends Data { } } -object Vec { +trait VecFactory { /** Creates a new [[Vec]] with `n` entries of the specified data type. * * @note elements are NOT assigned by default and have no value */ - def apply[T <: Data](n: Int, gen: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = new Vec(gen.chiselCloneType, n) - - @deprecated("Vec argument order should be size, t; this will be removed by the official release", "chisel3") - def apply[T <: Data](gen: T, n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = new Vec(gen.chiselCloneType, n) - - /** Creates a new [[Vec]] composed of elements of the input Seq of [[Data]] - * nodes. - * - * @note input elements should be of the same type (this is checked at the - * FIRRTL level, but not at the Scala / Chisel level) - * @note the width of all output elements is the width of the largest input - * element - * @note output elements are connected from the input elements - */ - def apply[T <: Data](elts: Seq[T]): Vec[T] = macro VecTransform.apply_elts - - def do_apply[T <: Data](elts: Seq[T])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = { - // REVIEW TODO: this should be removed in favor of the apply(elts: T*) - // varargs constructor, which is more in line with the style of the Scala - // collection API. However, a deprecation phase isn't possible, since - // changing apply(elt0, elts*) to apply(elts*) causes a function collision - // with apply(Seq) after type erasure. Workarounds by either introducing a - // DummyImplicit or additional type parameter will break some code. - - // Check that types are homogeneous. Width mismatch for Elements is safe. - require(!elts.isEmpty) - elts.foreach(requireIsHardware(_, "vec element")) - - val vec = Wire(new Vec(cloneSupertype(elts, "Vec"), elts.length)) - - // TODO: try to remove the logic for this mess - elts.head.direction match { - case ActualDirection.Input | ActualDirection.Output | ActualDirection.Unspecified => - // When internal wires are involved, driver / sink must be specified explicitly, otherwise - // the system is unable to infer which is driver / sink - (vec zip elts).foreach(x => x._1 := x._2) - case ActualDirection.Bidirectional(_) => - // For bidirectional, must issue a bulk connect so subelements are resolved correctly. - // Bulk connecting two wires may not succeed because Chisel frontend does not infer - // directions. - (vec zip elts).foreach(x => x._1 <> x._2) + def apply[T <: Data](n: Int, gen: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = { + if (compileOptions.declaredTypeMustBeUnbound) { + requireIsChiselType(gen, "vec type") } - vec + new Vec(gen.chiselCloneType, n) } - /** Creates a new [[Vec]] composed of the input [[Data]] nodes. - * - * @note input elements should be of the same type (this is checked at the - * FIRRTL level, but not at the Scala / Chisel level) - * @note the width of all output elements is the width of the largest input - * element - * @note output elements are connected from the input elements - */ - def apply[T <: Data](elt0: T, elts: T*): Vec[T] = macro VecTransform.apply_elt0 - - def do_apply[T <: Data](elt0: T, elts: T*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = - apply(elt0 +: elts.toSeq) - - /** Creates a new [[Vec]] of length `n` composed of the results of the given - * function applied over a range of integer values starting from 0. - * - * @param n number of elements in the vector (the function is applied from - * 0 to `n-1`) - * @param gen function that takes in an Int (the index) and returns a - * [[Data]] that becomes the output element - */ - def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] = macro VecTransform.tabulate - - def do_tabulate[T <: Data](n: Int)(gen: (Int) => T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = - apply((0 until n).map(i => gen(i))) - - /** Creates a new [[Vec]] of length `n` composed of the result of the given - * function repeatedly applied. - * - * @param n number of elements (amd the number of times the function is - * called) - * @param gen function that generates the [[Data]] that becomes the output - * element - */ - @deprecated("Vec.fill(n)(gen) is deprecated. Please use Vec(Seq.fill(n)(gen))", "chisel3") - def fill[T <: Data](n: Int)(gen: => T): Vec[T] = macro VecTransform.fill - - def do_fill[T <: Data](n: Int)(gen: => T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = - apply(Seq.fill(n)(gen)) - /** Truncate an index to implement modulo-power-of-2 addressing. */ private[core] def truncateIndex(idx: UInt, n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = { val w = BigInt(n-1).bitLength @@ -184,6 +106,8 @@ object Vec { } } +object Vec extends VecFactory + /** A vector (array) of [[Data]] elements. Provides hardware versions of various * collection transformation functions found in software array implementations. * @@ -208,7 +132,7 @@ object Vec { * - when multiple conflicting assignments are performed on a Vec element, the last one takes effect (unlike Mem, where the result is undefined) * - Vecs, unlike classes in Scala's collection library, are propagated intact to FIRRTL as a vector type, which may make debugging easier */ -sealed class Vec[T <: Data] private (gen: => T, val length: Int) +sealed class Vec[T <: Data] private[core] (gen: => T, val length: Int) extends Aggregate with VecLike[T] { private[core] override def typeEquivalent(that: Data): Boolean = that match { case that: Vec[T] => @@ -326,6 +250,74 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) } } +object VecInit { + /** Creates a new [[Vec]] composed of elements of the input Seq of [[Data]] + * nodes. + * + * @note input elements should be of the same type (this is checked at the + * FIRRTL level, but not at the Scala / Chisel level) + * @note the width of all output elements is the width of the largest input + * element + * @note output elements are connected from the input elements + */ + def apply[T <: Data](elts: Seq[T]): Vec[T] = macro VecTransform.apply_elts + + def do_apply[T <: Data](elts: Seq[T])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = { + // REVIEW TODO: this should be removed in favor of the apply(elts: T*) + // varargs constructor, which is more in line with the style of the Scala + // collection API. However, a deprecation phase isn't possible, since + // changing apply(elt0, elts*) to apply(elts*) causes a function collision + // with apply(Seq) after type erasure. Workarounds by either introducing a + // DummyImplicit or additional type parameter will break some code. + + // Check that types are homogeneous. Width mismatch for Elements is safe. + require(!elts.isEmpty) + elts.foreach(requireIsHardware(_, "vec element")) + + val vec = Wire(new Vec(cloneSupertype(elts, "Vec"), elts.length)) + + // TODO: try to remove the logic for this mess + elts.head.direction match { + case ActualDirection.Input | ActualDirection.Output | ActualDirection.Unspecified => + // When internal wires are involved, driver / sink must be specified explicitly, otherwise + // the system is unable to infer which is driver / sink + (vec zip elts).foreach(x => x._1 := x._2) + case ActualDirection.Bidirectional(_) => + // For bidirectional, must issue a bulk connect so subelements are resolved correctly. + // Bulk connecting two wires may not succeed because Chisel frontend does not infer + // directions. + (vec zip elts).foreach(x => x._1 <> x._2) + } + vec + } + + /** Creates a new [[Vec]] composed of the input [[Data]] nodes. + * + * @note input elements should be of the same type (this is checked at the + * FIRRTL level, but not at the Scala / Chisel level) + * @note the width of all output elements is the width of the largest input + * element + * @note output elements are connected from the input elements + */ + def apply[T <: Data](elt0: T, elts: T*): Vec[T] = macro VecTransform.apply_elt0 + + def do_apply[T <: Data](elt0: T, elts: T*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = + apply(elt0 +: elts.toSeq) + + /** Creates a new [[Vec]] of length `n` composed of the results of the given + * function applied over a range of integer values starting from 0. + * + * @param n number of elements in the vector (the function is applied from + * 0 to `n-1`) + * @param gen function that takes in an Int (the index) and returns a + * [[Data]] that becomes the output element + */ + def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] = macro VecTransform.tabulate + + def do_tabulate[T <: Data](n: Int)(gen: (Int) => T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = + apply((0 until n).map(i => gen(i))) +} + /** A trait for [[Vec]]s containing common hardware generators for collection * operations. */ diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index be1fe753..f61478c8 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -83,8 +83,11 @@ object DataMirror { requireIsHardware(target, "node requested directionality on") target.direction } - // TODO: really not a reflection-style API, but a workaround for dir in the compatibility package - def isSynthesizable(target: Data) = target.hasBinding + + // Internal reflection-style APIs, subject to change and removal whenever. + object internal { + def isSynthesizable(target: Data) = target.hasBinding + } } /** Creates a clone of the super-type of the input elements. Super-type is defined as: @@ -379,9 +382,27 @@ abstract class Data extends HasId { def toPrintable: Printable } -object Wire { - // No source info since Scala macros don't yet support named / default arguments. - def apply[T <: Data](dummy: Int = 0, init: T)(implicit compileOptions: CompileOptions): T = { +trait WireFactory { + def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + if (compileOptions.declaredTypeMustBeUnbound) { + requireIsChiselType(t, "wire type") + } + val x = t.chiselCloneType + + // Bind each element of x to being a Wire + x.bind(WireBinding(Builder.forcedUserModule)) + + pushCommand(DefWire(sourceInfo, x)) + pushCommand(DefInvalid(sourceInfo, x.ref)) + + x + } +} + +object Wire extends WireFactory + +object WireInit { + def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { val model = (init.litArg match { // For e.g. Wire(init=0.U(k.W)), fix the Reg's width to k case Some(lit) if lit.forcedWidth => init.chiselCloneType @@ -393,24 +414,11 @@ object Wire { apply(model, init) } - // No source info since Scala macros don't yet support named / default arguments. - def apply[T <: Data](t: T, init: T)(implicit compileOptions: CompileOptions): T = { + def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { implicit val noSourceInfo = UnlocatableSourceInfo - val x = apply(t) + val x = Wire(t) requireIsHardware(init, "wire initializer") x := init x } - - def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { - val x = t.chiselCloneType - - // Bind each element of x to being a Wire - x.bind(WireBinding(Builder.forcedUserModule)) - - pushCommand(DefWire(sourceInfo, x)) - pushCommand(DefInvalid(sourceInfo, x.ref)) - - x - } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 47d48061..1e7a795a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -20,8 +20,10 @@ object Mem { */ def apply[T <: Data](size: Int, t: T): Mem[T] = macro MemTransform.apply[T] def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Mem[T] = { + if (compileOptions.declaredTypeMustBeUnbound) { + requireIsChiselType(t, "memory type") + } val mt = t.chiselCloneType - val mem = new Mem(mt, size) pushCommand(DefMemory(sourceInfo, mem, mt, size)) mem @@ -121,6 +123,9 @@ object SyncReadMem { def apply[T <: Data](size: Int, t: T): SyncReadMem[T] = macro MemTransform.apply[T] def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = { + if (compileOptions.declaredTypeMustBeUnbound) { + requireIsChiselType(t, "memory type") + } val mt = t.chiselCloneType val mem = new SyncReadMem(mt, size) pushCommand(DefSeqMemory(sourceInfo, mem, mt, size)) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 3fdb3398..19bbee1c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -40,6 +40,7 @@ object RegNext { }).asInstanceOf[T] val reg = Reg(model) + requireIsHardware(next, "reg next") reg := next reg @@ -56,6 +57,7 @@ object RegNext { }).asInstanceOf[T] val reg = RegInit(model, init) // TODO: this makes NO sense + requireIsHardware(next, "reg next") reg := next reg -- cgit v1.2.3