Skip to content

Commit

Permalink
Refactor out fromBits => asTypeOf, deprecate flatten and other bad APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
ducky64 committed Feb 15, 2017
1 parent 8d2fff4 commit aecef26
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 123 deletions.
33 changes: 33 additions & 0 deletions chiselFrontend/src/main/scala/Mux.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// See LICENSE for license details.

package chisel3.core

import scala.language.experimental.macros

import chisel3.internal.Builder.{pushOp}
import chisel3.internal.sourceinfo.{SourceInfo, MuxTransform}
import chisel3.internal.firrtl._
import chisel3.internal.firrtl.PrimOp._

object Mux {
/** Creates a mux, whose output is one of the inputs depending on the
* value of the condition.
*
* @param cond condition determining the input to choose
* @param con the value chosen when `cond` is true
* @param alt the value chosen when `cond` is false
* @example
* {{{
* val muxOut = Mux(data_in === 3.U, 3.U(4.W), 0.U(4.W))
* }}}
*/
def apply[T <: Data](cond: Bool, con: T, alt: T): T = macro MuxTransform.apply[T]

def do_apply[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): T = {
Binding.checkSynthesizable(cond, s"'cond' ($cond)")
Binding.checkSynthesizable(con, s"'con' ($con)")
Binding.checkSynthesizable(alt, s"'alt' ($alt)")
val d = cloneSupertype(Seq(con, alt), "Mux")
pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref))
}
}
71 changes: 42 additions & 29 deletions chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,25 @@ import chisel3.internal.sourceinfo._
* of) other Data objects.
*/
sealed abstract class Aggregate extends Data {
private[core] def cloneTypeWidth(width: Width): this.type = cloneType
private[core] def width: Width = flatten.map(_.width).reduce(_ + _)
/** Returns a Seq of the immediate contents of this Aggregate, in order.
*/
def getElements: Seq[Data]

private[core] def width: Width = getElements.map(_.width).reduce(_ + _)
private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
pushCommand(BulkConnect(sourceInfo, this.lref, that.lref))

override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = SeqUtils.do_asUInt(this.flatten)
def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = {
SeqUtils.do_asUInt(getElements.map(_.asUInt()))
}
private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Unit = {
var i = 0
val wire = Wire(this.chiselCloneType)
val bits =
if (that.width.known && that.width.get >= wire.width.get) {
that
} else {
Wire(that.cloneTypeWidth(wire.width), init = that)
}
for (x <- wire.flatten) {
x := x.fromBits(bits(i + x.getWidth-1, i))
val bits = Wire(UInt(this.width), init=that) // handles width padding
for (x <- getElements) {
x.connectFromBits(bits(i + x.getWidth - 1, i))
i += x.getWidth
}
wire.asInstanceOf[this.type]
}
}

Expand Down Expand Up @@ -78,19 +77,16 @@ object Vec {

// Check that types are homogeneous. Width mismatch for Elements is safe.
require(!elts.isEmpty)
def eltsCompatible(a: Data, b: Data) = a match {
case _: Element => a.getClass == b.getClass
case _: Aggregate => Mux.typesCompatible(a, b)
}

val t = elts.head
for (e <- elts.tail)
require(eltsCompatible(t, e), s"can't create Vec of heterogeneous types ${t.getClass} and ${e.getClass}")
val vec = Wire(new Vec(cloneSupertype(elts, "Vec"), elts.length))

val maxWidth = elts.map(_.width).reduce(_ max _)
val vec = Wire(new Vec(t.cloneTypeWidth(maxWidth).chiselCloneType, elts.length))
def doConnect(sink: T, source: T) = {
if (elts.head.flatten.exists(_.dir != Direction.Unspecified)) {
// TODO: this looks bad, and should feel bad. Replace with a better abstraction.
val hasDirectioned = vec.sample_element match {
case t: Aggregate => t.flatten.exists(_.dir != Direction.Unspecified)
case t: Element => t.dir != Direction.Unspecified
}
if (hasDirectioned) {
sink bulkConnect source
} else {
sink connect source
Expand Down Expand Up @@ -163,13 +159,20 @@ object Vec {
*/
sealed class Vec[T <: Data] private (gen: => T, val length: Int)
extends Aggregate with VecLike[T] {
private[core] override def typeEquivalent(that: Data): Boolean = that match {
case that: Vec[T] =>
this.length == that.length &&
(this.sample_element typeEquivalent that.sample_element)
case _ => false
}

// Note: the constructor takes a gen() function instead of a Seq to enforce
// that all elements must be the same and because it makes FIRRTL generation
// simpler.
private val self: Seq[T] = Vector.fill(length)(gen)

/**
* sample_element 'tracks' all changes to the elements of self.
* sample_element 'tracks' all changes to the elements.
* For consistency, sample_element is always used for creating dynamically
* indexed ports and outputing the FIRRTL type.
*
Expand All @@ -181,7 +184,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
// This is somewhat weird although I think the best course of action here is
// to deprecate allElements in favor of dispatched functions to Data or
// a pattern matched recursive descent
private[chisel3] final def allElements: Seq[Element] =
private[chisel3] final override def allElements: Seq[Element] =
(sample_element +: self).flatMap(_.allElements)

/** Strong bulk connect, assigning elements in this Vec from elements in a Seq.
Expand Down Expand Up @@ -244,8 +247,8 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
}

private[chisel3] def toType: String = s"${sample_element.toType}[$length]"
private[chisel3] lazy val flatten: IndexedSeq[Bits] =
(0 until length).flatMap(i => this.apply(i).flatten)
override def getElements: Seq[Data] =
(0 until length).map(apply(_))

for ((elt, i) <- self.zipWithIndex)
elt.setRef(this, i)
Expand Down Expand Up @@ -377,7 +380,15 @@ abstract class Record extends Aggregate {
elements.toIndexedSeq.reverse.map(e => eltPort(e._2)).mkString("{", ", ", "}")
}

private[chisel3] lazy val flatten = elements.toIndexedSeq.flatMap(_._2.flatten)
private[core] override def typeEquivalent(that: Data): Boolean = that match {
case that: Record =>
this.getClass == that.getClass &&
this.elements.size == that.elements.size &&
this.elements.forall{case (name, model) =>
that.elements.contains(name) &&
(that.elements(name) typeEquivalent model)}
case _ => false
}

// NOTE: This sets up dependent references, it can be done before closing the Module
private[chisel3] override def _onModuleClose: Unit = { // scalastyle:ignore method.name
Expand All @@ -390,6 +401,8 @@ abstract class Record extends Aggregate {

private[chisel3] final def allElements: Seq[Element] = elements.toIndexedSeq.flatMap(_._2.allElements)

override def getElements: Seq[Data] = elements.toIndexedSeq.map(_._2)

// Helper because Bundle elements are reversed before printing
private[chisel3] def toPrintableHelper(elts: Seq[(String, Data)]): Printable = {
val xs =
Expand Down
89 changes: 23 additions & 66 deletions chiselFrontend/src/main/scala/chisel3/core/Bits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import chisel3.internal._
import chisel3.internal.Builder.{pushCommand, pushOp}
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform,
UIntTransform, MuxTransform}
UIntTransform}
import chisel3.internal.firrtl.PrimOp._
// TODO: remove this once we have CompileOptions threaded through the macro system.
import chisel3.core.ExplicitCompileOptions.NotStrict
Expand Down Expand Up @@ -54,7 +54,9 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg])
// Arguments for: self-checking code (can't do arithmetic on bits)
// Arguments against: generates down to a FIRRTL UInt anyways

private[chisel3] def flatten: IndexedSeq[Bits] = IndexedSeq(this)
// Only used for Mux, which needs to return a value of the same type with width the larger of the
// inputs.
private[core] def cloneTypeWidth(width: Width): this.type

def cloneType: this.type = cloneTypeWidth(width)

Expand Down Expand Up @@ -390,6 +392,9 @@ abstract trait Num[T <: Data] {
sealed class UInt private[core] (width: Width, lit: Option[ULit] = None)
extends Bits(width, lit) with Num[UInt] {

private[core] override def typeEquivalent(that: Data): Boolean =
that.isInstanceOf[UInt] && this.width == that.width

private[core] override def cloneTypeWidth(w: Width): this.type =
new UInt(w).asInstanceOf[this.type]
private[chisel3] def toType = s"UInt$width"
Expand Down Expand Up @@ -513,13 +518,9 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None)
throwException(s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint")
}
}
def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
val res = Wire(this, null).asInstanceOf[this.type]
res := (that match {
case u: UInt => u
case _ => that.asUInt
})
res
private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Unit = {
this := that.asUInt
}
}

Expand Down Expand Up @@ -555,6 +556,9 @@ object Bits extends UIntFactory
sealed class SInt private[core] (width: Width, lit: Option[SLit] = None)
extends Bits(width, lit) with Num[SInt] {

private[core] override def typeEquivalent(that: Data): Boolean =
this.getClass == that.getClass && this.width == that.width // TODO: should this be true for unspecified widths?

private[core] override def cloneTypeWidth(w: Width): this.type =
new SInt(w).asInstanceOf[this.type]
private[chisel3] def toType = s"SInt$width"
Expand Down Expand Up @@ -657,13 +661,8 @@ sealed class SInt private[core] (width: Width, lit: Option[SLit] = None)
throwException(s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint")
}
}
def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
val res = Wire(this, null).asInstanceOf[this.type]
res := (that match {
case s: SInt => s
case _ => that.asSInt
})
res
private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
this := that.asSInt
}
}

Expand Down Expand Up @@ -756,52 +755,6 @@ trait BoolFactory {

object Bool extends BoolFactory

object Mux {
/** Creates a mux, whose output is one of the inputs depending on the
* value of the condition.
*
* @param cond condition determining the input to choose
* @param con the value chosen when `cond` is true
* @param alt the value chosen when `cond` is false
* @example
* {{{
* val muxOut = Mux(data_in === 3.U, 3.U(4.W), 0.U(4.W))
* }}}
*/
def apply[T <: Data](cond: Bool, con: T, alt: T): T = macro MuxTransform.apply[T]

def do_apply[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): T =
(con, alt) match {
// Handle Mux(cond, UInt, Bool) carefully so that the concrete type is UInt
case (c: Bool, a: Bool) => doMux(cond, c, a).asInstanceOf[T]
case (c: UInt, a: Bool) => doMux(cond, c, a << 0).asInstanceOf[T]
case (c: Bool, a: UInt) => doMux(cond, c << 0, a).asInstanceOf[T]
case (c: Bits, a: Bits) => doMux(cond, c, a).asInstanceOf[T]
case _ => doAggregateMux(cond, con, alt)
}

private def doMux[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): T = {
require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}")
Binding.checkSynthesizable(cond, s"'cond' ($cond)")
Binding.checkSynthesizable(con, s"'con' ($con)")
Binding.checkSynthesizable(alt, s"'alt' ($alt)")
val d = alt.cloneTypeWidth(con.width max alt.width)
pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref))
}

private[core] def typesCompatible[T <: Data](x: T, y: T): Boolean = {
val sameTypes = x.getClass == y.getClass
val sameElements = x.flatten zip y.flatten forall { case (a, b) => a.getClass == b.getClass && a.width == b.width }
val sameNumElements = x.flatten.size == y.flatten.size
sameTypes && sameElements && sameNumElements
}

private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): T = {
require(typesCompatible(con, alt), s"can't Mux between heterogeneous types ${con.getClass} and ${alt.getClass}")
doMux(cond, con, alt)
}
}

//scalastyle:off number.of.methods
/**
* A sealed class representing a fixed point number that has a bit width and a binary point
Expand All @@ -817,6 +770,11 @@ object Mux {
*/
sealed class FixedPoint private (width: Width, val binaryPoint: BinaryPoint, lit: Option[FPLit] = None)
extends Bits(width, lit) with Num[FixedPoint] {
private[core] override def typeEquivalent(that: Data): Boolean = that match {
case that: FixedPoint => this.width == that.width && this.binaryPoint == that.binaryPoint // TODO: should this be true for unspecified widths?
case _ => false
}

private[core] override def cloneTypeWidth(w: Width): this.type =
new FixedPoint(w, binaryPoint).asInstanceOf[this.type]
private[chisel3] def toType = s"Fixed$width$binaryPoint"
Expand Down Expand Up @@ -926,13 +884,12 @@ sealed class FixedPoint private (width: Width, val binaryPoint: BinaryPoint, lit

override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = pushOp(DefPrim(sourceInfo, SInt(this.width), AsSIntOp, ref))
def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
val res = Wire(this, null).asInstanceOf[this.type]
res := (that match {
private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
// TODO: redefine as just asFixedPoint on that, where FixedPoint.asFixedPoint just works.
this := (that match {
case fp: FixedPoint => fp.asSInt.asFixedPoint(this.binaryPoint)
case _ => that.asFixedPoint(this.binaryPoint)
})
res
}
//TODO(chick): Consider "convert" as an arithmetic conversion to UInt/SInt
}
Expand Down
Loading

0 comments on commit aecef26

Please sign in to comment.