diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 8700b444237..47f4b3e726c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -93,7 +93,7 @@ trait VecFactory { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(gen, "vec type") } - new Vec(gen.chiselCloneType, n) + new Vec(gen.cloneTypeFull, n) } /** Truncate an index to implement modulo-power-of-2 addressing. */ @@ -580,9 +580,3 @@ class Bundle(implicit compileOptions: CompileOptions) extends Record { */ override def toPrintable: Printable = toPrintableHelper(elements.toList.reverse) } - -private[core] object Bundle { - val keywords = List("flip", "asInput", "asOutput", "cloneType", "chiselCloneType", "toBits", - "widthOption", "signalName", "signalPathName", "signalParent", "signalComponent") -} - diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index b5c9d319016..aa286e0d4dc 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -87,6 +87,10 @@ object DataMirror { // Internal reflection-style APIs, subject to change and removal whenever. object internal { def isSynthesizable(target: Data) = target.hasBinding + // For those odd cases where you need to care about object reference and uniqueness + def chiselTypeClone[T<:Data](target: Data): T = { + target.cloneTypeFull.asInstanceOf[T] + } } } @@ -126,7 +130,7 @@ private[core] object cloneSupertype { throw new AssertionError( s"can't create $createdType with heterogeneous Bits types ${elt1.getClass} and ${elt2.getClass}") }).asInstanceOf[T] } - model.chiselCloneType + model.cloneTypeFull } else { for (elt <- elts.tail) { @@ -135,11 +139,20 @@ private[core] object cloneSupertype { require(elt typeEquivalent elts.head, s"can't create $createdType with non-equivalent types ${elts.head} and ${elt}") } - elts.head.chiselCloneType + elts.head.cloneTypeFull } } } +/** Returns the chisel type of a hardware object, allowing other hardware to be constructed from it. + */ +object chiselTypeOf { + def apply[T <: Data](target: T): T = { + requireIsHardware(target) + target.cloneTypeFull.asInstanceOf[T] + } +} + /** * Input, Output, and Flipped are used to define the directions of Module IOs. * @@ -148,22 +161,31 @@ private[core] object cloneSupertype { * Thus, an error will be thrown if these are used on bound Data */ object Input { - def apply[T<:Data](source: T): T = { - val out = source.cloneType + def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = { + if (compileOptions.checkSynthesizable) { + requireIsChiselType(source) + } + val out = source.cloneType.asInstanceOf[T] out.specifiedDirection = SpecifiedDirection.Input out } } object Output { - def apply[T<:Data](source: T): T = { - val out = source.cloneType + def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = { + if (compileOptions.checkSynthesizable) { + requireIsChiselType(source) + } + val out = source.cloneType.asInstanceOf[T] out.specifiedDirection = SpecifiedDirection.Output out } } object Flipped { - def apply[T<:Data](source: T): T = { - val out = source.cloneType + def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = { + if (compileOptions.checkSynthesizable) { + requireIsChiselType(source) + } + val out = source.cloneType.asInstanceOf[T] out.specifiedDirection = SpecifiedDirection.flip(source.specifiedDirection) out } @@ -314,25 +336,27 @@ abstract class Data extends HasId { private[chisel3] def width: Width private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit - /** cloneType must be defined for any Chisel object extending Data. + /** Internal API; Chisel users should look at chisel3.chiselTypeOf(...). + * + * cloneType must be defined for any Chisel object extending Data. * It is responsible for constructing a basic copy of the object being cloned. - * If cloneType needs to recursively clone elements of an object, it should call - * the cloneType methods on those elements. + * * @return a copy of the object. */ def cloneType: this.type - /** chiselCloneType is called at the top-level of a clone chain. - * It calls the client's cloneType() method to construct a basic copy of the object being cloned, - * then performs any fixups required to reconstruct the appropriate core state of the cloned object. - * @return a copy of the object with appropriate core state. + /** Internal API; Chisel users should look at chisel3.chiselTypeOf(...). + * + * Returns a copy of this data type, with hardware bindings (if any) removed. + * Directionality data is still preserved. */ - def chiselCloneType: this.type = { - val clone = this.cloneType // get a fresh object, without bindings + private[chisel3] def cloneTypeFull: this.type = { + val clone = this.cloneType.asInstanceOf[this.type] // get a fresh object, without bindings // Only the top-level direction needs to be fixed up, cloneType should do the rest clone.specifiedDirection = specifiedDirection clone } + final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) def litArg(): Option[LitArg] = None @@ -357,7 +381,7 @@ abstract class Data extends HasId { /** Does a reinterpret cast of the bits in this node into the format that provides. * Returns a new Wire of that type. Does not modify existing nodes. * - * x.asTypeOf(that) performs the inverse operation of x = that.toBits. + * x.asTypeOf(that) performs the inverse operation of x := that.toBits. * * @note bit widths are NOT checked, may pad or drop bits from input * @note that should have known widths @@ -365,7 +389,7 @@ abstract class Data extends HasId { def asTypeOf[T <: Data](that: T): T = macro SourceInfoTransform.thatArg def do_asTypeOf[T <: Data](that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { - val thatCloned = Wire(that.chiselCloneType) + val thatCloned = Wire(that.cloneTypeFull) thatCloned.connectFromBits(this.asUInt()) thatCloned } @@ -395,7 +419,7 @@ trait WireFactory { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(t, "wire type") } - val x = t.chiselCloneType + val x = t.cloneTypeFull // Bind each element of x to being a Wire x.bind(WireBinding(Builder.forcedUserModule)) @@ -413,10 +437,10 @@ 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 + case Some(lit) if lit.forcedWidth => init.cloneTypeFull case _ => init match { case init: Bits => init.cloneTypeWidth(Width()) - case init => init.chiselCloneType + case init => init.cloneTypeFull } }).asInstanceOf[T] apply(model, init) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 1e7a795aba5..72d91c3c33c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -23,7 +23,7 @@ object Mem { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(t, "memory type") } - val mt = t.chiselCloneType + val mt = t.cloneTypeFull val mem = new Mem(mt, size) pushCommand(DefMemory(sourceInfo, mem, mt, size)) mem @@ -92,7 +92,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId { val port = pushCommand( DefMemPort(sourceInfo, - t.chiselCloneType, Node(this), dir, i.ref, Node(Builder.forcedClock)) + t.cloneTypeFull, Node(this), dir, i.ref, Node(Builder.forcedClock)) ).id // Bind each element of port to being a MemoryPort port.bind(MemoryPortBinding(Builder.forcedUserModule)) @@ -126,7 +126,7 @@ object SyncReadMem { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(t, "memory type") } - val mt = t.chiselCloneType + val mt = t.cloneTypeFull val mem = new SyncReadMem(mt, size) pushCommand(DefSeqMemory(sourceInfo, mem, mt, size)) mem diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 19bbee1c7e8..14674b370b9 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -19,7 +19,7 @@ object Reg { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(t, "reg type") } - val reg = t.chiselCloneType + val reg = t.cloneTypeFull val clock = Node(Builder.forcedClock) reg.bind(RegBinding(Builder.forcedUserModule)) @@ -36,7 +36,7 @@ object RegNext { def apply[T <: Data](next: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { val model = (next match { case next: Bits => next.cloneTypeWidth(Width()) - case next => next.chiselCloneType + case next => next.cloneTypeFull }).asInstanceOf[T] val reg = Reg(model) @@ -53,7 +53,7 @@ object RegNext { def apply[T <: Data](next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { val model = (next match { case next: Bits => next.cloneTypeWidth(Width()) - case next => next.chiselCloneType + case next => next.cloneTypeFull }).asInstanceOf[T] val reg = RegInit(model, init) // TODO: this makes NO sense @@ -71,10 +71,10 @@ object RegInit { def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { val model = (init.litArg match { // For e.g. Reg(init=UInt(0, k)), fix the Reg's width to k - case Some(lit) if lit.forcedWidth => init.chiselCloneType + case Some(lit) if lit.forcedWidth => init.cloneTypeFull case _ => init match { case init: Bits => init.cloneTypeWidth(Width()) - case init => init.chiselCloneType + case init => init.cloneTypeFull } }).asInstanceOf[T] RegInit(model, init) @@ -86,7 +86,7 @@ object RegInit { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(t, "reg type") } - val reg = t.chiselCloneType + val reg = t.cloneTypeFull val clock = Node(Builder.forcedClock) val reset = Node(Builder.forcedReset) diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index f181caba1c2..d65196d97e7 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -42,6 +42,12 @@ package object Chisel { // scalastyle:ignore package.object.name } } } + implicit class cloneTypeable[T <: Data](val target: T) extends AnyVal { + import chisel3.core.DataMirror + def chiselCloneType: T = { + DataMirror.internal.chiselTypeClone(target).asInstanceOf[T] + } + } type ChiselException = chisel3.internal.ChiselException diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala index ee77ba230d8..d335f1f101a 100644 --- a/src/main/scala/chisel3/package.scala +++ b/src/main/scala/chisel3/package.scala @@ -19,6 +19,7 @@ package object chisel3 { // scalastyle:ignore package.object.name val Input = chisel3.core.Input val Output = chisel3.core.Output val Flipped = chisel3.core.Flipped + val chiselTypeOf = chisel3.core.chiselTypeOf type Data = chisel3.core.Data object Wire extends chisel3.core.WireFactory { @@ -56,6 +57,13 @@ package object chisel3 { // scalastyle:ignore package.object.name } } + implicit class cloneTypeable[T <: Data](val target: T) extends AnyVal { + @deprecated("chiselCloneType is deprecated, use chiselTypeOf(...) to get the Chisel Type of a hardware object", "chisel3") + def chiselCloneType: T = { + target.cloneTypeFull.asInstanceOf[T] + } + } + type Aggregate = chisel3.core.Aggregate object Vec extends chisel3.core.VecFactory { import scala.language.experimental.macros diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index ef09c07deed..451fd039191 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -281,7 +281,7 @@ object Queue entries: Int = 2, pipe: Boolean = false, flow: Boolean = false): DecoupledIO[T] = { - val q = Module(new Queue(enq.bits.cloneType, entries, pipe, flow)) + val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow)) q.io.enq.valid := enq.valid // not using <> so that override is allowed q.io.enq.bits := enq.bits enq.ready := q.io.enq.ready diff --git a/src/main/scala/chisel3/util/Reg.scala b/src/main/scala/chisel3/util/Reg.scala index 34c4d6d8c04..34d22a07edb 100644 --- a/src/main/scala/chisel3/util/Reg.scala +++ b/src/main/scala/chisel3/util/Reg.scala @@ -8,8 +8,7 @@ object RegEnable { /** Returns a register with the specified next, update enable gate, and no reset initialization. */ def apply[T <: Data](next: T, enable: Bool): T = { - val clonedNext = next.chiselCloneType - val r = Reg(clonedNext) + val r = Reg(chiselTypeOf(next)) when (enable) { r := next } r } diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala index 432cd2783b7..e84e6a02f78 100644 --- a/src/test/scala/chiselTests/Module.scala +++ b/src/test/scala/chiselTests/Module.scala @@ -41,7 +41,7 @@ class ModuleVecTester(c: ModuleVec) extends Tester(c) { class ModuleWire extends Module { val io = IO(new SimpleIO) - val inc = Wire(Module(new PlusOne).io.chiselCloneType) + val inc = Wire(chiselTypeOf(Module(new PlusOne).io)) inc.in := io.in io.out := inc.out } diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala index 9b8855c45c2..6c62ab26155 100644 --- a/src/test/scala/chiselTests/Vec.scala +++ b/src/test/scala/chiselTests/Vec.scala @@ -145,7 +145,7 @@ class ZeroEntryVecTester extends BasicTester { require(bundleWithZeroEntryVec.asUInt.getWidth == 1) val m = Module(new Module { - val io = IO(Output(bundleWithZeroEntryVec.cloneType)) + val io = IO(Output(bundleWithZeroEntryVec)) }) WireInit(m.io.bar)