Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

the cloneType and chiselCloneType hot mess 🔥 #653

Merged
merged 7 commits into from
Oct 5, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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")
}

68 changes: 46 additions & 22 deletions chiselFrontend/src/main/scala/chisel3/core/Data.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
}
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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.
*
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -357,15 +381,15 @@ 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
*/
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
}
Expand Down Expand Up @@ -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))
Expand All @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions chiselFrontend/src/main/scala/chisel3/core/Mem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion chiselFrontend/src/main/scala/chisel3/core/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ abstract class BaseModule extends HasId {
* TODO(twigg): Specifically walk the Data definition to call out which nodes
* are problematic.
*/
protected def IO[T<:Data](iodef: T): iodef.type = {
protected def IO[T<:Data](iodef: T): T = {
require(!_closed, "Can't add more ports after module close")
requireIsChiselType(iodef, "io type")

Expand Down
12 changes: 6 additions & 6 deletions chiselFrontend/src/main/scala/chisel3/core/Reg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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)

Expand All @@ -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

Expand All @@ -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)
Expand All @@ -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)

Expand Down
6 changes: 6 additions & 0 deletions src/main/scala/chisel3/compatibility.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/chisel3/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/chisel3/util/Decoupled.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions src/main/scala/chisel3/util/Reg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/chiselTests/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/chiselTests/Vec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down