From e92f2f69477a6ce86fc148a1a95db5797f2e3051 Mon Sep 17 00:00:00 2001 From: ducky Date: Thu, 5 May 2016 13:22:04 -0700 Subject: Implementation of source locators --- .../src/main/scala/Chisel/Aggregate.scala | 73 ++- chiselFrontend/src/main/scala/Chisel/Assert.scala | 73 +++ chiselFrontend/src/main/scala/Chisel/BitPat.scala | 14 +- chiselFrontend/src/main/scala/Chisel/Bits.scala | 495 ++++++++++++++------- .../src/main/scala/Chisel/BlackBox.scala | 5 +- .../src/main/scala/Chisel/CoreUtil.scala | 97 ---- chiselFrontend/src/main/scala/Chisel/Data.scala | 49 +- chiselFrontend/src/main/scala/Chisel/Mem.scala | 35 +- chiselFrontend/src/main/scala/Chisel/Module.scala | 32 +- chiselFrontend/src/main/scala/Chisel/Printf.scala | 36 ++ chiselFrontend/src/main/scala/Chisel/Reg.scala | 25 +- .../src/main/scala/Chisel/SeqUtils.scala | 20 +- chiselFrontend/src/main/scala/Chisel/When.scala | 21 +- .../main/scala/Chisel/internal/SourceInfo.scala | 51 +++ .../scala/Chisel/internal/firrtl/Emitter.scala | 105 ----- .../src/main/scala/Chisel/internal/firrtl/IR.scala | 37 +- 16 files changed, 705 insertions(+), 463 deletions(-) create mode 100644 chiselFrontend/src/main/scala/Chisel/Assert.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/CoreUtil.scala create mode 100644 chiselFrontend/src/main/scala/Chisel/Printf.scala create mode 100644 chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala (limited to 'chiselFrontend/src/main') diff --git a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala index 4d35e2f0..197135d7 100644 --- a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala +++ b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala @@ -4,10 +4,12 @@ package Chisel import scala.collection.immutable.ListMap import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} +import scala.language.experimental.macros import internal._ import internal.Builder.pushCommand import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -36,14 +38,15 @@ object Vec { * element * @note output elements are connected from the input elements */ - def apply[T <: Data](elts: Seq[T]): Vec[T] = { + def apply[T <: Data](elts: Seq[T]): Vec[T] = macro VecTransform.apply_elts + + def do_apply[T <: Data](elts: Seq[T])(implicit sourceInfo: SourceInfo): 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. - require(!elts.isEmpty) val width = elts.map(_.width).reduce(_ max _) val vec = Wire(new Vec(elts.head.cloneTypeWidth(width), elts.length)) @@ -60,7 +63,9 @@ object Vec { * element * @note output elements are connected from the input elements */ - def apply[T <: Data](elt0: T, elts: T*): Vec[T] = + 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): Vec[T] = apply(elt0 +: elts.toSeq) /** Creates a new [[Vec]] of length `n` composed of the results of the given @@ -71,7 +76,9 @@ object Vec { * @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] = + 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): Vec[T] = apply((0 until n).map(i => gen(i))) /** Creates a new [[Vec]] of length `n` composed of the result of the given @@ -82,7 +89,10 @@ object Vec { * @param gen function that generates the [[Data]] that becomes the output * element */ - def fill[T <: Data](n: Int)(gen: => T): Vec[T] = apply(Seq.fill(n)(gen)) + 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): Vec[T] = + apply(Seq.fill(n)(gen)) } /** A vector (array) of [[Data]] elements. Provides hardware versions of various @@ -102,18 +112,18 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) private val self = IndexedSeq.fill(length)(gen) - override def <> (that: Data): Unit = this := that + override def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this := that /** Strong bulk connect, assigning elements in this Vec from elements in a Seq. * * @note the length of this Vec must match the length of the input Seq */ - def <> (that: Seq[T]): Unit = this := that + def <> (that: Seq[T])(implicit sourceInfo: SourceInfo): Unit = this := that // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data - def <> (that: Vec[T]): Unit = this := that.asInstanceOf[Data] + def <> (that: Vec[T])(implicit sourceInfo: SourceInfo): Unit = this := that.asInstanceOf[Data] - override def := (that: Data): Unit = that match { + override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: Vec[_] => this connect that case _ => this badConnect that } @@ -122,14 +132,14 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) * * @note the length of this Vec must match the length of the input Seq */ - def := (that: Seq[T]): Unit = { + def := (that: Seq[T])(implicit sourceInfo: SourceInfo): Unit = { require(this.length == that.length) for ((a, b) <- this zip that) a := b } // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data - def := (that: Vec[T]): Unit = this connect that + def := (that: Vec[T])(implicit sourceInfo: SourceInfo): Unit = this connect that /** Creates a dynamically indexed read or write accessor into the array. */ @@ -147,7 +157,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) def read(idx: UInt): T = apply(idx) @deprecated("Use Vec.apply instead", "chisel3") - def write(idx: UInt, data: T): Unit = apply(idx) := data + def write(idx: UInt, data: T): Unit = apply(idx).:=(data)(DeprecatedSourceInfo) override def cloneType: this.type = Vec(length, gen).asInstanceOf[this.type] @@ -175,20 +185,32 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] { /** Outputs true if p outputs true for every element. */ - def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_ && _) + def forall(p: T => Bool): Bool = macro SourceInfoTransform.pArg + + def do_forall(p: T => Bool)(implicit sourceInfo: SourceInfo): Bool = + (this map p).fold(Bool(true))(_ && _) /** Outputs true if p outputs true for at least one element. */ - def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_ || _) + def exists(p: T => Bool): Bool = macro SourceInfoTransform.pArg + + def do_exists(p: T => Bool)(implicit sourceInfo: SourceInfo): Bool = + (this map p).fold(Bool(false))(_ || _) /** Outputs true if the vector contains at least one element equal to x (using * the === operator). */ - def contains(x: T)(implicit evidence: T <:< UInt): Bool = this.exists(_ === x) + def contains(x: T)(implicit ev: T <:< UInt): Bool = macro VecTransform.contains + + def do_contains(x: T)(implicit sourceInfo: SourceInfo, ev: T <:< UInt): Bool = + this.exists(_ === x) /** Outputs the number of elements for which p is true. */ - def count(p: T => Bool): UInt = SeqUtils.count(this map p) + def count(p: T => Bool): UInt = macro SourceInfoTransform.pArg + + def do_count(p: T => Bool)(implicit sourceInfo: SourceInfo): UInt = + SeqUtils.count(this map p) /** Helper function that appends an index (literal value) to each element, * useful for hardware generators which output an index. @@ -197,11 +219,17 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] { /** Outputs the index of the first element for which p outputs true. */ - def indexWhere(p: T => Bool): UInt = SeqUtils.priorityMux(indexWhereHelper(p)) + def indexWhere(p: T => Bool): UInt = macro SourceInfoTransform.pArg + + def do_indexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): UInt = + SeqUtils.priorityMux(indexWhereHelper(p)) /** Outputs the index of the last element for which p outputs true. */ - def lastIndexWhere(p: T => Bool): UInt = SeqUtils.priorityMux(indexWhereHelper(p).reverse) + def lastIndexWhere(p: T => Bool): UInt = macro SourceInfoTransform.pArg + + def do_lastIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): UInt = + SeqUtils.priorityMux(indexWhereHelper(p).reverse) /** Outputs the index of the element for which p outputs true, assuming that * the there is exactly one such element. @@ -213,7 +241,10 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] { * true is NOT checked (useful in cases where the condition doesn't always * hold, but the results are not used in those cases) */ - def onlyIndexWhere(p: T => Bool): UInt = SeqUtils.oneHotMux(indexWhereHelper(p)) + def onlyIndexWhere(p: T => Bool): UInt = macro SourceInfoTransform.pArg + + def do_onlyIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): UInt = + SeqUtils.oneHotMux(indexWhereHelper(p)) } /** Base class for data types defined as a bundle of other data types. @@ -237,13 +268,13 @@ class Bundle extends Aggregate(NO_DIR) { * mySubModule.io <> io * }}} */ - override def <> (that: Data): Unit = that match { + override def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: Bundle => this bulkConnect that case _ => this badConnect that } // TODO: replace with better defined FIRRTL strong-connect operator - override def := (that: Data): Unit = this <> that + override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this <> that lazy val elements: ListMap[String, Data] = ListMap(namedElts:_*) diff --git a/chiselFrontend/src/main/scala/Chisel/Assert.scala b/chiselFrontend/src/main/scala/Chisel/Assert.scala new file mode 100644 index 00000000..c086f014 --- /dev/null +++ b/chiselFrontend/src/main/scala/Chisel/Assert.scala @@ -0,0 +1,73 @@ +// See LICENSE for license details. + +package Chisel + +import scala.reflect.macros.blackbox.Context +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.SourceInfo + +object assert { // scalastyle:ignore object.name + /** Checks for a condition to be valid in the circuit at all times. If the + * condition evaluates to false, the circuit simulation stops with an error. + * + * Does not fire when in reset (defined as the encapsulating Module's + * reset). If your definition of reset is not the encapsulating Module's + * reset, you will need to gate this externally. + * + * May be called outside of a Module (like defined in a function), so + * functions using assert make the standard Module assumptions (single clock + * and single reset). + * + * @param cond condition, assertion fires (simulation fails) when false + * @param message optional message to print when the assertion fires + * + * @note currently cannot be used in core Chisel / libraries because macro + * defs need to be compiled first and the SBT project is not set up to do + * that + */ + // Macros currently can't take default arguments, so we need two functions to emulate defaults. + def apply(cond: Bool, message: String)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl_msg + def apply(cond: Bool)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl + + def apply_impl_msg(c: Context)(cond: c.Tree, message: c.Tree)(sourceInfo: c.Tree): c.Tree = { + import c.universe._ + val p = c.enclosingPosition + val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}" + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do")) + q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message))($sourceInfo)" + } + + def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: c.Tree): c.Tree = { + import c.universe._ + val p = c.enclosingPosition + val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}" + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do")) + q"$apply_impl_do($cond, $condStr, _root_.scala.None)($sourceInfo)" + } + + def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) { + when (!(cond || Builder.dynamicContext.currentModule.get.reset)) { + message match { + case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n") + case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n") + } + pushCommand(Stop(sourceInfo, Node(Builder.dynamicContext.currentModule.get.clock), 1)) + } + } + + /** An elaboration-time assertion, otherwise the same as the above run-time + * assertion. */ + def apply(cond: Boolean, message: => String) { + Predef.assert(cond, message) + } + + /** A workaround for default-value overloading problems in Scala, just + * 'assert(cond, "")' */ + def apply(cond: Boolean) { + Predef.assert(cond, "") + } +} diff --git a/chiselFrontend/src/main/scala/Chisel/BitPat.scala b/chiselFrontend/src/main/scala/Chisel/BitPat.scala index a1bf1985..cf412542 100644 --- a/chiselFrontend/src/main/scala/Chisel/BitPat.scala +++ b/chiselFrontend/src/main/scala/Chisel/BitPat.scala @@ -2,6 +2,10 @@ package Chisel +import scala.language.experimental.macros + +import Chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} + object BitPat { /** Parses a bit pattern string into (bits, mask, width). * @@ -74,7 +78,11 @@ object BitPat { */ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) { def getWidth: Int = width - def === (other: UInt): Bool = UInt(value) === (other & UInt(mask)) - def =/= (other: UInt): Bool = !(this === other) - def != (other: UInt): Bool = this =/= other + def === (that: UInt): Bool = macro SourceInfoTransform.thatArg + def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg + def != (that: UInt): Bool = macro SourceInfoTransform.thatArg + + def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = UInt(value) === (that & UInt(mask)) + def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = !(this === that) + def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = this =/= that } diff --git a/chiselFrontend/src/main/scala/Chisel/Bits.scala b/chiselFrontend/src/main/scala/Chisel/Bits.scala index ce177ef1..2783c160 100644 --- a/chiselFrontend/src/main/scala/Chisel/Bits.scala +++ b/chiselFrontend/src/main/scala/Chisel/Bits.scala @@ -2,9 +2,13 @@ package Chisel +import scala.language.experimental.macros + import internal._ import internal.Builder.pushOp import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, + UIntTransform, MuxTransform} import firrtl.PrimOp._ /** Element is a leaf data type: it cannot contain other Data objects. Example @@ -27,37 +31,43 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: def cloneType: this.type = cloneTypeWidth(width) - override def <> (that: Data): Unit = this := that + override def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this := that + + final def tail(n: Int): UInt = macro SourceInfoTransform.nArg + final def head(n: Int): UInt = macro SourceInfoTransform.nArg - def tail(n: Int): UInt = { + def do_tail(n: Int)(implicit sourceInfo: SourceInfo): UInt = { val w = width match { case KnownWidth(x) => require(x >= n, s"Can't tail($n) for width $x < $n") Width(x - n) case UnknownWidth() => Width() } - binop(UInt(width = w), TailOp, n) + binop(sourceInfo, UInt(width = w), TailOp, n) } - def head(n: Int): UInt = { + + def do_head(n: Int)(implicit sourceInfo: SourceInfo): UInt = { width match { case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n") case UnknownWidth() => } - binop(UInt(width = n), HeadOp, n) + binop(sourceInfo, UInt(width = n), HeadOp, n) } /** Returns the specified bit on this wire as a [[Bool]], statically * addressed. */ - final def apply(x: BigInt): Bool = { + final def apply(x: BigInt): Bool = macro SourceInfoTransform.xArg + + final def do_apply(x: BigInt)(implicit sourceInfo: SourceInfo): Bool = { if (x < 0) { Builder.error(s"Negative bit indices are illegal (got $x)") } if (isLit()) { Bool(((litValue() >> x.toInt) & 1) == 1) } else { - pushOp(DefPrim(Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x))) + pushOp(DefPrim(sourceInfo, Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x))) } } @@ -66,14 +76,18 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: * * @note convenience method allowing direct use of Ints without implicits */ - final def apply(x: Int): Bool = - apply(BigInt(x)) + final def apply(x: Int): Bool = macro SourceInfoTransform.xArg + + final def do_apply(x: Int)(implicit sourceInfo: SourceInfo): Bool = apply(BigInt(x)) /** Returns the specified bit on this wire as a [[Bool]], dynamically * addressed. */ - final def apply(x: UInt): Bool = + final def apply(x: UInt): Bool = macro SourceInfoTransform.xArg + + final def do_apply(x: UInt)(implicit sourceInfo: SourceInfo): Bool = { (this >> x)(0) + } /** Returns a subset of bits on this wire from `hi` to `lo` (inclusive), * statically addressed. @@ -84,7 +98,9 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: * myBits(1,0) => 0b01 // extracts the two least significant bits * }}} */ - final def apply(x: Int, y: Int): UInt = { + final def apply(x: Int, y: Int): UInt = macro SourceInfoTransform.xyArg + + final def do_apply(x: Int, y: Int)(implicit sourceInfo: SourceInfo): UInt = { if (x < y || y < 0) { Builder.error(s"Invalid bit range ($x,$y)") } @@ -92,114 +108,154 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: if (isLit()) { UInt((litValue >> y) & ((BigInt(1) << w) - 1), w) } else { - pushOp(DefPrim(UInt(width = w), BitsExtractOp, this.ref, ILit(x), ILit(y))) + pushOp(DefPrim(sourceInfo, UInt(width = w), BitsExtractOp, this.ref, ILit(x), ILit(y))) } } // REVIEW TODO: again, is this necessary? Or just have this and use implicits? - final def apply(x: BigInt, y: BigInt): UInt = apply(x.toInt, y.toInt) - - private[Chisel] def unop[T <: Data](dest: T, op: PrimOp): T = - pushOp(DefPrim(dest, op, this.ref)) - private[Chisel] def binop[T <: Data](dest: T, op: PrimOp, other: BigInt): T = - pushOp(DefPrim(dest, op, this.ref, ILit(other))) - private[Chisel] def binop[T <: Data](dest: T, op: PrimOp, other: Bits): T = - pushOp(DefPrim(dest, op, this.ref, other.ref)) - private[Chisel] def compop(op: PrimOp, other: Bits): Bool = - pushOp(DefPrim(Bool(), op, this.ref, other.ref)) - private[Chisel] def redop(op: PrimOp): Bool = - pushOp(DefPrim(Bool(), op, this.ref)) + final def apply(x: BigInt, y: BigInt): UInt = macro SourceInfoTransform.xyArg + + final def do_apply(x: BigInt, y: BigInt)(implicit sourceInfo: SourceInfo): UInt = + apply(x.toInt, y.toInt) + + private[Chisel] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref)) + private[Chisel] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) + private[Chisel] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) + + private[Chisel] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = + pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) + private[Chisel] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = + pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) /** Returns this wire zero padded up to the specified width. * * @note for SInts only, this does sign extension */ - def pad (other: Int): this.type = binop(cloneTypeWidth(this.width max Width(other)), PadOp, other) + final def pad(that: Int): this.type = macro SourceInfoTransform.thatArg + + def do_pad(that: Int)(implicit sourceInfo: SourceInfo): this.type = + binop(sourceInfo, cloneTypeWidth(this.width max Width(that)), PadOp, that) + + /** Returns this wire bitwise-inverted. */ + final def unary_~ (): Bits = macro SourceInfoWhiteboxTransform.noArg + + def do_unary_~ (implicit sourceInfo: SourceInfo): Bits + /** Shift left operation */ // REVIEW TODO: redundant // REVIEW TODO: should these return this.type or Bits? - def << (other: BigInt): Bits + final def << (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): Bits /** Returns this wire statically left shifted by the specified amount, * inserting zeros into the least significant bits. * * The width of the output is `other` larger than the input. */ - def << (other: Int): Bits + final def << (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_<< (that: Int)(implicit sourceInfo: SourceInfo): Bits /** Returns this wire dynamically left shifted by the specified amount, * inserting zeros into the least significant bits. * * The width of the output is `pow(2, width(other))` larger than the input. */ - def << (other: UInt): Bits + final def << (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): Bits /** Shift right operation */ // REVIEW TODO: redundant - def >> (other: BigInt): Bits + final def >> (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): Bits /** Returns this wire statically right shifted by the specified amount, * inserting zeros into the most significant bits. * * The width of the output is the same as the input. */ - def >> (other: Int): Bits + final def >> (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_>> (that: Int)(implicit sourceInfo: SourceInfo): Bits /** Returns this wire dynamically right shifted by the specified amount, * inserting zeros into the most significant bits. * * The width of the output is the same as the input. */ - def >> (other: UInt): Bits + final def >> (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): Bits /** Returns the contents of this wire as a [[Vec]] of [[Bool]]s. */ - def toBools: Seq[Bool] = Seq.tabulate(this.getWidth)(i => this(i)) + final def toBools(): Seq[Bool] = macro SourceInfoTransform.noArg + + def toBools(implicit sourceInfo: SourceInfo): Seq[Bool] = + Seq.tabulate(this.getWidth)(i => this(i)) /** Reinterpret cast to a SInt. * * @note value not guaranteed to be preserved: for example, an UInt of width * 3 and value 7 (0b111) would become a SInt with value -1 */ - def asSInt(): SInt + final def asSInt(): SInt = macro SourceInfoTransform.noArg + + def do_asSInt(implicit sourceInfo: SourceInfo): SInt /** Reinterpret cast to an UInt. * * @note value not guaranteed to be preserved: for example, a SInt of width * 3 and value -1 (0b111) would become an UInt with value 7 */ - def asUInt(): UInt + final def asUInt(): UInt = macro SourceInfoTransform.noArg + + def do_asUInt(implicit sourceInfo: SourceInfo): UInt /** Reinterpret cast to Bits. */ - def asBits(): Bits = asUInt + final def asBits(): Bits = macro SourceInfoTransform.noArg + + def do_asBits(implicit sourceInfo: SourceInfo): Bits = asUInt() @deprecated("Use asSInt, which makes the reinterpret cast more explicit", "chisel3") - final def toSInt(): SInt = asSInt + final def toSInt(): SInt = do_asSInt(DeprecatedSourceInfo) @deprecated("Use asUInt, which makes the reinterpret cast more explicit", "chisel3") - final def toUInt(): UInt = asUInt + final def toUInt(): UInt = do_asUInt(DeprecatedSourceInfo) + + final def toBool(): Bool = macro SourceInfoTransform.noArg - def toBool(): Bool = width match { + def do_toBool(implicit sourceInfo: SourceInfo): Bool = { + width match { case KnownWidth(1) => this(0) case _ => throwException(s"can't covert UInt<$width> to Bool") } + } /** Returns this wire concatenated with `other`, where this wire forms the * most significant part and `other` forms the least significant part. * * The width of the output is sum of the inputs. */ - def ## (other: Bits): UInt = { - val w = this.width + other.width - pushOp(DefPrim(UInt(w), ConcatOp, this.ref, other.ref)) + final def ## (that: Bits): UInt = macro SourceInfoTransform.thatArg + + def do_## (that: Bits)(implicit sourceInfo: SourceInfo): UInt = { + val w = this.width + that.width + pushOp(DefPrim(sourceInfo, UInt(w), ConcatOp, this.ref, that.ref)) } @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") - override def toBits: UInt = asUInt + override def toBits: UInt = do_asUInt(DeprecatedSourceInfo) - override def fromBits(n: Bits): this.type = { - val res = Wire(this).asInstanceOf[this.type] - res := n + override def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { + val res = Wire(this, null).asInstanceOf[this.type] + res := that res } } @@ -223,7 +279,9 @@ abstract trait Num[T <: Data] { /** Outputs the sum of `this` and `b`. The resulting width is the max of the * operands plus 1 (should not overflow). */ - def + (b: T): T + final def + (that: T): T = macro SourceInfoTransform.thatArg + + def do_+ (that: T)(implicit sourceInfo: SourceInfo): T /** Outputs the product of `this` and `b`. The resulting width is the sum of * the operands. @@ -231,46 +289,68 @@ abstract trait Num[T <: Data] { * @note can generate a single-cycle multiplier, which can result in * significant cycle time and area costs */ - def * (b: T): T + final def * (that: T): T = macro SourceInfoTransform.thatArg + + def do_* (that: T)(implicit sourceInfo: SourceInfo): T /** Outputs the quotient of `this` and `b`. * * TODO: full rules */ - def / (b: T): T + final def / (that: T): T = macro SourceInfoTransform.thatArg - def % (b: T): T + def do_/ (that: T)(implicit sourceInfo: SourceInfo): T + + final def % (that: T): T = macro SourceInfoTransform.thatArg + + def do_% (that: T)(implicit sourceInfo: SourceInfo): T /** Outputs the difference of `this` and `b`. The resulting width is the max * of the operands plus 1 (should not overflow). */ - def - (b: T): T + final def - (that: T): T = macro SourceInfoTransform.thatArg + + def do_- (that: T)(implicit sourceInfo: SourceInfo): T /** Outputs true if `this` < `b`. */ - def < (b: T): Bool + final def < (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_< (that: T)(implicit sourceInfo: SourceInfo): Bool /** Outputs true if `this` <= `b`. */ - def <= (b: T): Bool + final def <= (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_<= (that: T)(implicit sourceInfo: SourceInfo): Bool /** Outputs true if `this` > `b`. */ - def > (b: T): Bool + final def > (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_> (that: T)(implicit sourceInfo: SourceInfo): Bool /** Outputs true if `this` >= `b`. */ - def >= (b: T): Bool + final def >= (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_>= (that: T)(implicit sourceInfo: SourceInfo): Bool /** Outputs the minimum of `this` and `b`. The resulting width is the max of * the operands. */ - def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b) + final def min(that: T): T = macro SourceInfoTransform.thatArg + + def do_min(that: T)(implicit sourceInfo: SourceInfo): T = + Mux(this < that, this.asInstanceOf[T], that) /** Outputs the maximum of `this` and `b`. The resulting width is the max of * the operands. */ - def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T]) + final def max(that: T): T = macro SourceInfoTransform.thatArg + + def do_max(that: T)(implicit sourceInfo: SourceInfo): T = + Mux(this < that, that, this.asInstanceOf[T]) } /** A data type for unsigned integers, represented as a binary bitvector. @@ -285,76 +365,128 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi override private[Chisel] def fromInt(value: BigInt, width: Int): this.type = UInt(value, width).asInstanceOf[this.type] - override def := (that: Data): Unit = that match { + override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: UInt => this connect that case _ => this badConnect that } // TODO: refactor to share documentation with Num or add independent scaladoc - def unary_- : UInt = UInt(0) - this - def unary_-% : UInt = UInt(0) -% this - def +& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), AddOp, other) - def + (other: UInt): UInt = this +% other - def +% (other: UInt): UInt = (this +& other) tail 1 - def -& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), SubOp, other) - def - (other: UInt): UInt = this -% other - def -% (other: UInt): UInt = (this -& other) tail 1 - def * (other: UInt): UInt = binop(UInt(this.width + other.width), TimesOp, other) - def * (other: SInt): SInt = other * this - def / (other: UInt): UInt = binop(UInt(this.width), DivideOp, other) - def % (other: UInt): UInt = binop(UInt(this.width), RemOp, other) - - def & (other: UInt): UInt = binop(UInt(this.width max other.width), BitAndOp, other) - def | (other: UInt): UInt = binop(UInt(this.width max other.width), BitOrOp, other) - def ^ (other: UInt): UInt = binop(UInt(this.width max other.width), BitXorOp, other) + final def unary_- (): UInt = macro SourceInfoTransform.noArg + final def unary_-% (): UInt = macro SourceInfoTransform.noArg + + def do_unary_- (implicit sourceInfo: SourceInfo) : UInt = UInt(0) - this + def do_unary_-% (implicit sourceInfo: SourceInfo): UInt = UInt(0) -% this + + override def do_+ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this +% that + override def do_- (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this -% that + override def do_/ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width), DivideOp, that) + override def do_% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width), RemOp, that) + override def do_* (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width + that.width), TimesOp, that) + + final def * (that: SInt): SInt = macro SourceInfoTransform.thatArg + def do_* (that: SInt)(implicit sourceInfo: SourceInfo): SInt = that * this + + final def +& (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def +% (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def -& (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def -% (that: UInt): UInt = macro SourceInfoTransform.thatArg + + def do_+& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt((this.width max that.width) + 1), AddOp, that) + def do_+% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + (this +& that).tail(1) + def do_-& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt((this.width max that.width) + 1), SubOp, that) + def do_-% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + (this -& that).tail(1) + + final def & (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def | (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def ^ (that: UInt): UInt = macro SourceInfoTransform.thatArg + + def do_& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that) + def do_| (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that) + def do_^ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that) /** Returns this wire bitwise-inverted. */ - def unary_~ : UInt = unop(UInt(width = width), BitNotOp) + def do_unary_~ (implicit sourceInfo: SourceInfo): UInt = + unop(sourceInfo, UInt(width = width), BitNotOp) // REVIEW TODO: Can this be defined on Bits? - def orR: Bool = this != UInt(0) - def andR: Bool = ~this === UInt(0) - def xorR: Bool = redop(XorReduceOp) - - def < (other: UInt): Bool = compop(LessOp, other) - def > (other: UInt): Bool = compop(GreaterOp, other) - def <= (other: UInt): Bool = compop(LessEqOp, other) - def >= (other: UInt): Bool = compop(GreaterEqOp, other) - def != (other: UInt): Bool = compop(NotEqualOp, other) - def =/= (other: UInt): Bool = compop(NotEqualOp, other) - def === (other: UInt): Bool = compop(EqualOp, other) - def unary_! : Bool = this === Bits(0) - - // REVIEW TODO: Can these also not be defined on Bits? - def << (other: Int): UInt = binop(UInt(this.width + other), ShiftLeftOp, other) - def << (other: BigInt): UInt = this << other.toInt - def << (other: UInt): UInt = binop(UInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other) - def >> (other: Int): UInt = binop(UInt(this.width.shiftRight(other)), ShiftRightOp, other) - def >> (other: BigInt): UInt = this >> other.toInt - def >> (other: UInt): UInt = binop(UInt(this.width), DynamicShiftRightOp, other) - - def bitSet(off: UInt, dat: Bool): UInt = { + final def orR(): Bool = macro SourceInfoTransform.noArg + final def andR(): Bool = macro SourceInfoTransform.noArg + final def xorR(): Bool = macro SourceInfoTransform.noArg + + def do_orR(implicit sourceInfo: SourceInfo): Bool = this != UInt(0) + def do_andR(implicit sourceInfo: SourceInfo): Bool = ~this === UInt(0) + def do_xorR(implicit sourceInfo: SourceInfo): Bool = redop(sourceInfo, XorReduceOp) + + override def do_< (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) + override def do_> (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterOp, that) + override def do_<= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) + override def do_>= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) + + final def != (that: UInt): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg + final def === (that: UInt): Bool = macro SourceInfoTransform.thatArg + + def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, EqualOp, that) + + final def unary_! () : Bool = macro SourceInfoTransform.noArg + + def do_unary_! (implicit sourceInfo: SourceInfo) : Bool = this === Bits(0) + + override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width + that), ShiftLeftOp, that) + override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): UInt = + this << that.toInt + override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that) + override def do_>> (that: Int)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width.shiftRight(that)), ShiftRightOp, that) + override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): UInt = + this >> that.toInt + override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width), DynamicShiftRightOp, that) + + final def bitSet(off: UInt, dat: Bool): UInt = macro UIntTransform.bitset + + def do_bitSet(off: UInt, dat: Bool)(implicit sourceInfo: SourceInfo): UInt = { val bit = UInt(1, 1) << off Mux(dat, this | bit, ~(~this | bit)) } - def === (that: BitPat): Bool = that === this - def != (that: BitPat): Bool = that != this - def =/= (that: BitPat): Bool = that =/= this + final def === (that: BitPat): Bool = macro SourceInfoTransform.thatArg + final def != (that: BitPat): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: BitPat): Bool = macro SourceInfoTransform.thatArg + + def do_=== (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that === this + def do_!= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that != this + def do_=/= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that =/= this /** Returns this UInt as a [[SInt]] with an additional zero in the MSB. */ // TODO: this eventually will be renamed as toSInt, once the existing toSInt // completes its deprecation phase. - def zext(): SInt = pushOp(DefPrim(SInt(width + 1), ConvertOp, ref)) + final def zext(): SInt = macro SourceInfoTransform.noArg + def do_zext(implicit sourceInfo: SourceInfo): SInt = + pushOp(DefPrim(sourceInfo, SInt(width + 1), ConvertOp, ref)) /** Returns this UInt as a [[SInt]], without changing width or bit value. The * SInt is not guaranteed to have the same value (for example, if the MSB is * high, it will be interpreted as a negative value). */ - def asSInt(): SInt = pushOp(DefPrim(SInt(width), AsSIntOp, ref)) - - def asUInt(): UInt = this + override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = + pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref)) + override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = this } // This is currently a factory because both Bits and UInt inherit it. @@ -415,7 +547,7 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non new SInt(dir, w).asInstanceOf[this.type] private[Chisel] def toType = s"SInt$width" - override def := (that: Data): Unit = that match { + override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: SInt => this connect that case _ => this badConnect that } @@ -423,50 +555,94 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non override private[Chisel] def fromInt(value: BigInt, width: Int): this.type = SInt(value, width).asInstanceOf[this.type] - def unary_- : SInt = SInt(0) - this - def unary_-% : SInt = SInt(0) -% this - /** add (width +1) operator */ - def +& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), AddOp, other) + final def unary_- (): SInt = macro SourceInfoTransform.noArg + final def unary_-% (): SInt = macro SourceInfoTransform.noArg + + def unary_- (implicit sourceInfo: SourceInfo): SInt = SInt(0) - this + def unary_-% (implicit sourceInfo: SourceInfo): SInt = SInt(0) -% this + /** add (default - no growth) operator */ - def + (other: SInt): SInt = this +% other + override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + this +% that + /** subtract (default - no growth) operator */ + override def do_- (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + this -% that + override def do_* (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width + that.width), TimesOp, that) + override def do_/ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width), DivideOp, that) + override def do_% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width), RemOp, that) + + final def * (that: UInt): SInt = macro SourceInfoTransform.thatArg + def do_* (that: UInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width + that.width), TimesOp, that) + + /** add (width +1) operator */ + final def +& (that: SInt): SInt = macro SourceInfoTransform.thatArg /** add (no growth) operator */ - def +% (other: SInt): SInt = (this +& other).tail(1).asSInt + final def +% (that: SInt): SInt = macro SourceInfoTransform.thatArg /** subtract (width +1) operator */ - def -& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), SubOp, other) - /** subtract (default - no growth) operator */ - def - (other: SInt): SInt = this -% other + final def -& (that: SInt): SInt = macro SourceInfoTransform.thatArg /** subtract (no growth) operator */ - def -% (other: SInt): SInt = (this -& other).tail(1).asSInt - def * (other: SInt): SInt = binop(SInt(this.width + other.width), TimesOp, other) - def * (other: UInt): SInt = binop(SInt(this.width + other.width), TimesOp, other) - def / (other: SInt): SInt = binop(SInt(this.width), DivideOp, other) - def % (other: SInt): SInt = binop(SInt(this.width), RemOp, other) - - def & (other: SInt): SInt = binop(UInt(this.width max other.width), BitAndOp, other).asSInt - def | (other: SInt): SInt = binop(UInt(this.width max other.width), BitOrOp, other).asSInt - def ^ (other: SInt): SInt = binop(UInt(this.width max other.width), BitXorOp, other).asSInt + final def -% (that: SInt): SInt = macro SourceInfoTransform.thatArg + + def do_+& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt((this.width max that.width) + 1), AddOp, that) + def do_+% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + (this +& that).tail(1).asSInt + def do_-& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt((this.width max that.width) + 1), SubOp, that) + def do_-% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + (this -& that).tail(1).asSInt + + final def & (that: SInt): SInt = macro SourceInfoTransform.thatArg + final def | (that: SInt): SInt = macro SourceInfoTransform.thatArg + final def ^ (that: SInt): SInt = macro SourceInfoTransform.thatArg + + def do_& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that).asSInt + def do_| (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that).asSInt + def do_^ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that).asSInt /** Returns this wire bitwise-inverted. */ - def unary_~ : SInt = unop(UInt(width = width), BitNotOp).asSInt - - def < (other: SInt): Bool = compop(LessOp, other) - def > (other: SInt): Bool = compop(GreaterOp, other) - def <= (other: SInt): Bool = compop(LessEqOp, other) - def >= (other: SInt): Bool = compop(GreaterEqOp, other) - def != (other: SInt): Bool = compop(NotEqualOp, other) - def =/= (other: SInt): Bool = compop(NotEqualOp, other) - def === (other: SInt): Bool = compop(EqualOp, other) - def abs(): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt) - - def << (other: Int): SInt = binop(SInt(this.width + other), ShiftLeftOp, other) - def << (other: BigInt): SInt = this << other.toInt - def << (other: UInt): SInt = binop(SInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other) - def >> (other: Int): SInt = binop(SInt(this.width.shiftRight(other)), ShiftRightOp, other) - def >> (other: BigInt): SInt = this >> other.toInt - def >> (other: UInt): SInt = binop(SInt(this.width), DynamicShiftRightOp, other) - - def asUInt(): UInt = pushOp(DefPrim(UInt(this.width), AsUIntOp, ref)) - def asSInt(): SInt = this + def do_unary_~ (implicit sourceInfo: SourceInfo): SInt = + unop(sourceInfo, UInt(width = width), BitNotOp).asSInt + + override def do_< (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) + override def do_> (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterOp, that) + override def do_<= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) + override def do_>= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) + + final def != (that: SInt): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: SInt): Bool = macro SourceInfoTransform.thatArg + final def === (that: SInt): Bool = macro SourceInfoTransform.thatArg + + def do_!= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=/= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=== (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, EqualOp, that) + + final def abs(): UInt = macro SourceInfoTransform.noArg + + def do_abs(implicit sourceInfo: SourceInfo): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt) + + override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width + that), ShiftLeftOp, that) + override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): SInt = + this << that.toInt + override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that) + override def do_>> (that: Int)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width.shiftRight(that)), ShiftRightOp, that) + override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): SInt = + this >> that.toInt + override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width), DynamicShiftRightOp, that) + + override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) + override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = this } object SInt { @@ -510,20 +686,32 @@ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Wi // REVIEW TODO: Why does this need to exist and have different conventions // than Bits? - def & (other: Bool): Bool = binop(Bool(), BitAndOp, other) - def | (other: Bool): Bool = binop(Bool(), BitOrOp, other) - def ^ (other: Bool): Bool = binop(Bool(), BitXorOp, other) + final def & (that: Bool): Bool = macro SourceInfoTransform.thatArg + final def | (that: Bool): Bool = macro SourceInfoTransform.thatArg + final def ^ (that: Bool): Bool = macro SourceInfoTransform.thatArg + + def do_& (that: Bool)(implicit sourceInfo: SourceInfo): Bool = + binop(sourceInfo, Bool(), BitAndOp, that) + def do_| (that: Bool)(implicit sourceInfo: SourceInfo): Bool = + binop(sourceInfo, Bool(), BitOrOp, that) + def do_^ (that: Bool)(implicit sourceInfo: SourceInfo): Bool = + binop(sourceInfo, Bool(), BitXorOp, that) /** Returns this wire bitwise-inverted. */ - override def unary_~ : Bool = unop(Bool(), BitNotOp) + override def do_unary_~ (implicit sourceInfo: SourceInfo): Bool = + unop(sourceInfo, Bool(), BitNotOp) /** Outputs the logical OR of two Bools. */ - def || (that: Bool): Bool = this | that + def || (that: Bool): Bool = macro SourceInfoTransform.thatArg + + def do_|| (that: Bool)(implicit sourceInfo: SourceInfo): Bool = this | that /** Outputs the logical AND of two Bools. */ - def && (that: Bool): Bool = this & that + def && (that: Bool): Bool = macro SourceInfoTransform.thatArg + + def do_&& (that: Bool)(implicit sourceInfo: SourceInfo): Bool = this & that } object Bool { @@ -548,7 +736,10 @@ object Mux { * val muxOut = Mux(data_in === UInt(3), UInt(3, 4), UInt(0, 4)) * }}} */ - def apply[T <: Data](cond: Bool, con: T, alt: T): T = (con, alt) match { + 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] @@ -557,13 +748,13 @@ object Mux { case _ => doAggregateMux(cond, con, alt) } - private def doMux[T <: Data](cond: Bool, con: T, alt: T): T = { + 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}") val d = alt.cloneTypeWidth(con.width max alt.width) - pushOp(DefPrim(d, MultiplexOp, cond.ref, con.ref, alt.ref)) + pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref)) } - private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T): T = { + private def doAggregateMux[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}") for ((c, a) <- con.flatten zip alt.flatten) require(c.width == a.width, "can't Mux between aggregates of different width") diff --git a/chiselFrontend/src/main/scala/Chisel/BlackBox.scala b/chiselFrontend/src/main/scala/Chisel/BlackBox.scala index be72934d..b634f021 100644 --- a/chiselFrontend/src/main/scala/Chisel/BlackBox.scala +++ b/chiselFrontend/src/main/scala/Chisel/BlackBox.scala @@ -4,6 +4,7 @@ package Chisel import internal.Builder.pushCommand import internal.firrtl.{ModuleIO, DefInvalid} +import internal.sourceinfo.SourceInfo /** Defines a black box, which is a module that can be referenced from within * Chisel, but is not defined in the emitted Verilog. Useful for connecting @@ -39,10 +40,10 @@ abstract class BlackBox extends Module { // Don't setup clock, reset // Cann't invalide io in one bunch, must invalidate each part separately - override private[Chisel] def setupInParent(): this.type = _parent match { + override private[Chisel] def setupInParent(implicit sourceInfo: SourceInfo): this.type = _parent match { case Some(p) => { // Just init instance inputs - for((_,port) <- ports) pushCommand(DefInvalid(port.ref)) + for((_,port) <- ports) pushCommand(DefInvalid(sourceInfo, port.ref)) this } case None => this diff --git a/chiselFrontend/src/main/scala/Chisel/CoreUtil.scala b/chiselFrontend/src/main/scala/Chisel/CoreUtil.scala deleted file mode 100644 index 708b516e..00000000 --- a/chiselFrontend/src/main/scala/Chisel/CoreUtil.scala +++ /dev/null @@ -1,97 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ - -import scala.language.experimental.macros -import scala.reflect.macros.blackbox.Context - -object assert { // scalastyle:ignore object.name - /** Checks for a condition to be valid in the circuit at all times. If the - * condition evaluates to false, the circuit simulation stops with an error. - * - * Does not fire when in reset (defined as the encapsulating Module's - * reset). If your definition of reset is not the encapsulating Module's - * reset, you will need to gate this externally. - * - * May be called outside of a Module (like defined in a function), so - * functions using assert make the standard Module assumptions (single clock - * and single reset). - * - * @param cond condition, assertion fires (simulation fails) when false - * @param message optional message to print when the assertion fires - * - * @note currently cannot be used in core Chisel / libraries because macro - * defs need to be compiled first and the SBT project is not set up to do - * that - */ - def apply(cond: Bool, message: String): Unit = macro apply_impl_msg - def apply(cond: Bool): Unit = macro apply_impl // macros currently can't take default arguments - - def apply_impl_msg(c: Context)(cond: c.Tree, message: c.Tree): c.Tree = { - import c.universe._ - val p = c.enclosingPosition - val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}" - val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do")) - q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message))" - } - - def apply_impl(c: Context)(cond: c.Tree): c.Tree = { - import c.universe._ - val p = c.enclosingPosition - val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}" - val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do")) - q"$apply_impl_do($cond, $condStr, _root_.scala.None)" - } - - def apply_impl_do(cond: Bool, line: String, message: Option[String]) { - when (!(cond || Builder.dynamicContext.currentModule.get.reset)) { - message match { - case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n") - case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n") - } - pushCommand(Stop(Node(Builder.dynamicContext.currentModule.get.clock), 1)) - } - } - - /** An elaboration-time assertion, otherwise the same as the above run-time - * assertion. */ - def apply(cond: Boolean, message: => String) { - Predef.assert(cond, message) - } - - /** A workaround for default-value overloading problems in Scala, just - * 'assert(cond, "")' */ - def apply(cond: Boolean) { - Predef.assert(cond, "") - } -} - -object printf { // scalastyle:ignore object.name - /** Prints a message in simulation. - * - * Does not fire when in reset (defined as the encapsulating Module's - * reset). If your definition of reset is not the encapsulating Module's - * reset, you will need to gate this externally. - * - * May be called outside of a Module (like defined in a function), so - * functions using printf make the standard Module assumptions (single clock - * and single reset). - * - * @param fmt printf format string - * @param data format string varargs containing data to print - */ - def apply(fmt: String, data: Bits*) { - when (!Builder.dynamicContext.currentModule.get.reset) { - printfWithoutReset(fmt, data:_*) - } - } - - private[Chisel] def printfWithoutReset(fmt: String, data: Bits*) { - val clock = Builder.dynamicContext.currentModule.get.clock - pushCommand(Printf(Node(clock), fmt, data.map((d: Bits) => d.ref))) - } -} diff --git a/chiselFrontend/src/main/scala/Chisel/Data.scala b/chiselFrontend/src/main/scala/Chisel/Data.scala index 8879491c..d16843f7 100644 --- a/chiselFrontend/src/main/scala/Chisel/Data.scala +++ b/chiselFrontend/src/main/scala/Chisel/Data.scala @@ -2,9 +2,12 @@ package Chisel +import scala.language.experimental.macros + import internal._ import internal.Builder.pushCommand import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} sealed abstract class Direction(name: String) { override def toString: String = name @@ -48,19 +51,21 @@ abstract class Data(dirArg: Direction) extends HasId { def asOutput: this.type = cloneType.overrideDirection(_ => OUTPUT, _ => false) def flip(): this.type = cloneType.overrideDirection(_.flip, !_) - private[Chisel] def badConnect(that: Data): Unit = + private[Chisel] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = throwException(s"cannot connect ${this} and ${that}") - private[Chisel] def connect(that: Data): Unit = - pushCommand(Connect(this.lref, that.ref)) - private[Chisel] def bulkConnect(that: Data): Unit = - pushCommand(BulkConnect(this.lref, that.lref)) + private[Chisel] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(Connect(sourceInfo, this.lref, that.ref)) + private[Chisel] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) private[Chisel] def lref: Node = Node(this) private[Chisel] def ref: Arg = if (isLit) litArg.get else lref private[Chisel] def cloneTypeWidth(width: Width): this.type private[Chisel] def toType: String - def := (that: Data): Unit = this badConnect that - def <> (that: Data): Unit = this badConnect that + def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this badConnect that + + def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this badConnect that + def cloneType: this.type def litArg(): Option[LitArg] = None def litValue(): BigInt = litArg.get.num @@ -90,14 +95,16 @@ abstract class Data(dirArg: Direction) extends HasId { * @note does NOT check bit widths, may drop bits during assignment * @note what fromBits assigs to must have known widths */ - def fromBits(n: Bits): this.type = { + def fromBits(that: Bits): this.type = macro SourceInfoTransform.thatArg + + def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { var i = 0 val wire = Wire(this.cloneType) val bits = - if (n.width.known && n.width.get >= wire.width.get) { - n + if (that.width.known && that.width.get >= wire.width.get) { + that } else { - Wire(n.cloneTypeWidth(wire.width), init = n) + Wire(that.cloneTypeWidth(wire.width), init = that) } for (x <- wire.flatten) { x := bits(i + x.getWidth-1, i) @@ -110,23 +117,25 @@ abstract class Data(dirArg: Direction) extends HasId { * * This performs the inverse operation of fromBits(Bits). */ - def toBits(): UInt = SeqUtils.asUInt(this.flatten) + @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") + def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) } object Wire { - def apply[T <: Data](t: T): T = - makeWire(t, null.asInstanceOf[T]) + def apply[T <: Data](t: T): T = macro WireTransform.apply[T] + // No source info since Scala macros don't yet support named / default arguments. def apply[T <: Data](dummy: Int = 0, init: T): T = - makeWire(null.asInstanceOf[T], init) + do_apply(null.asInstanceOf[T], init)(UnlocatableSourceInfo) + // No source info since Scala macros don't yet support named / default arguments. def apply[T <: Data](t: T, init: T): T = - makeWire(t, init) + do_apply(t, init)(UnlocatableSourceInfo) - private def makeWire[T <: Data](t: T, init: T): T = { + def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { val x = Reg.makeType(t, null.asInstanceOf[T], init) - pushCommand(DefWire(x)) - pushCommand(DefInvalid(x.ref)) + pushCommand(DefWire(sourceInfo, x)) + pushCommand(DefInvalid(sourceInfo, x.ref)) if (init != null) { x := init } @@ -145,7 +154,7 @@ sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { private[Chisel] def cloneTypeWidth(width: Width): this.type = cloneType private[Chisel] def toType = "Clock" - override def := (that: Data): Unit = that match { + override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: Clock => this connect that case _ => this badConnect that } diff --git a/chiselFrontend/src/main/scala/Chisel/Mem.scala b/chiselFrontend/src/main/scala/Chisel/Mem.scala index 2958a287..e34d5499 100644 --- a/chiselFrontend/src/main/scala/Chisel/Mem.scala +++ b/chiselFrontend/src/main/scala/Chisel/Mem.scala @@ -2,23 +2,28 @@ package Chisel +import scala.language.experimental.macros + import internal._ import internal.Builder.pushCommand import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} object Mem { @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") - def apply[T <: Data](t: T, size: Int): Mem[T] = apply(size, t) + def apply[T <: Data](t: T, size: Int): Mem[T] = do_apply(size, t)(UnlocatableSourceInfo) /** Creates a combinational-read, sequential-write [[Mem]]. * * @param size number of elements in the memory * @param t data type of memory element */ - def apply[T <: Data](size: Int, t: T): Mem[T] = { + 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): Mem[T] = { val mt = t.cloneType val mem = new Mem(mt, size) - pushCommand(DefMemory(mem, mt, size)) // TODO multi-clock + pushCommand(DefMemory(sourceInfo, mem, mt, size)) // TODO multi-clock mem } } @@ -34,12 +39,12 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi /** Creates a read/write accessor into the memory with dynamic addressing. * See the class documentation of the memory for more detailed information. */ - def apply(idx: UInt): T = makePort(idx, MemPortDirection.INFER) + def apply(idx: UInt): T = makePort(UnlocatableSourceInfo, idx, MemPortDirection.INFER) /** Creates a read accessor into the memory with dynamic addressing. See the * class documentation of the memory for more detailed information. */ - def read(idx: UInt): T = makePort(idx, MemPortDirection.READ) + def read(idx: UInt): T = makePort(UnlocatableSourceInfo, idx, MemPortDirection.READ) /** Creates a write accessor into the memory. * @@ -47,7 +52,8 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * @param data new data to write */ def write(idx: UInt, data: T): Unit = { - makePort(idx, MemPortDirection.WRITE) := data + implicit val sourceInfo = UnlocatableSourceInfo + makePort(UnlocatableSourceInfo, idx, MemPortDirection.WRITE) := data } /** Creates a masked write accessor into the memory. @@ -60,7 +66,8 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * @note this is only allowed if the memory's element data type is a Vec */ def write(idx: UInt, data: T, mask: Seq[Bool]) (implicit evidence: T <:< Vec[_]): Unit = { - val accessor = makePort(idx, MemPortDirection.WRITE).asInstanceOf[Vec[Data]] + implicit val sourceInfo = UnlocatableSourceInfo + val accessor = makePort(sourceInfo, idx, MemPortDirection.WRITE).asInstanceOf[Vec[Data]] val dataVec = data.asInstanceOf[Vec[Data]] if (accessor.length != dataVec.length) { Builder.error(s"Mem write data must contain ${accessor.length} elements (found ${dataVec.length})") @@ -72,8 +79,9 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi when (cond) { port := datum } } - private def makePort(idx: UInt, dir: MemPortDirection): T = - pushCommand(DefMemPort(t.cloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock))).id + private def makePort(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection): T = + pushCommand(DefMemPort(sourceInfo, + t.cloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock))).id } /** A combinational-read, sequential-write memory. @@ -89,17 +97,19 @@ sealed class Mem[T <: Data](t: T, length: Int) extends MemBase(t, length) object SeqMem { @deprecated("SeqMem argument order should be size, t; this will be removed by the official release", "chisel3") - def apply[T <: Data](t: T, size: Int): SeqMem[T] = apply(size, t) + def apply[T <: Data](t: T, size: Int): SeqMem[T] = do_apply(size, t)(DeprecatedSourceInfo) /** Creates a sequential-read, sequential-write [[SeqMem]]. * * @param size number of elements in the memory * @param t data type of memory element */ - def apply[T <: Data](size: Int, t: T): SeqMem[T] = { + def apply[T <: Data](size: Int, t: T): SeqMem[T] = macro MemTransform.apply[T] + + def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo): SeqMem[T] = { val mt = t.cloneType val mem = new SeqMem(mt, size) - pushCommand(DefSeqMemory(mem, mt, size)) // TODO multi-clock + pushCommand(DefSeqMemory(sourceInfo, mem, mt, size)) // TODO multi-clock mem } } @@ -116,6 +126,7 @@ object SeqMem { */ sealed class SeqMem[T <: Data](t: T, n: Int) extends MemBase[T](t, n) { def read(addr: UInt, enable: Bool): T = { + implicit val sourceInfo = UnlocatableSourceInfo val a = Wire(UInt()) when (enable) { a := addr } read(a) diff --git a/chiselFrontend/src/main/scala/Chisel/Module.scala b/chiselFrontend/src/main/scala/Chisel/Module.scala index 3e839cac..45744196 100644 --- a/chiselFrontend/src/main/scala/Chisel/Module.scala +++ b/chiselFrontend/src/main/scala/Chisel/Module.scala @@ -3,11 +3,13 @@ package Chisel import scala.collection.mutable.{ArrayBuffer, HashSet} +import scala.language.experimental.macros import internal._ import internal.Builder.pushCommand import internal.Builder.dynamicContext import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -17,15 +19,21 @@ object Module { * * @return the input module `m` with Chisel metadata properly set */ - def apply[T <: Module](bc: => T): T = { + def apply[T <: Module](bc: => T): T = macro InstTransform.apply[T] + + def do_apply[T <: Module](bc: => T)(implicit sourceInfo: SourceInfo): T = { + // Don't generate source info referencing parents inside a module, sincce this interferes with + // module de-duplication in FIRRTL emission. + val childSourceInfo = UnlocatableSourceInfo + val parent = dynamicContext.currentModule val m = bc.setRefs() - m._commands.prepend(DefInvalid(m.io.ref)) // init module outputs + m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs dynamicContext.currentModule = parent val ports = m.computePorts Builder.components += Component(m, m.name, ports, m._commands) - pushCommand(DefInstance(m, ports)) - m.setupInParent() + pushCommand(DefInstance(sourceInfo, m, ports)) + m.setupInParent(childSourceInfo) } } @@ -70,14 +78,16 @@ extends HasId { Port(port, if (port.dir == NO_DIR) bundleDir else port.dir) } - private[Chisel] def setupInParent(): this.type = _parent match { - case Some(p) => { - pushCommand(DefInvalid(io.ref)) // init instance inputs - clock := override_clock.getOrElse(p.clock) - reset := override_reset.getOrElse(p.reset) - this + private[Chisel] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { + _parent match { + case Some(p) => { + pushCommand(DefInvalid(sourceInfo, io.ref)) // init instance inputs + clock := override_clock.getOrElse(p.clock) + reset := override_reset.getOrElse(p.reset) + this + } + case None => this } - case None => this } private[Chisel] def setRefs(): this.type = { diff --git a/chiselFrontend/src/main/scala/Chisel/Printf.scala b/chiselFrontend/src/main/scala/Chisel/Printf.scala new file mode 100644 index 00000000..f068f637 --- /dev/null +++ b/chiselFrontend/src/main/scala/Chisel/Printf.scala @@ -0,0 +1,36 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.SourceInfo + +object printf { // scalastyle:ignore object.name + /** Prints a message in simulation. + * + * Does not fire when in reset (defined as the encapsulating Module's + * reset). If your definition of reset is not the encapsulating Module's + * reset, you will need to gate this externally. + * + * May be called outside of a Module (like defined in a function), so + * functions using printf make the standard Module assumptions (single clock + * and single reset). + * + * @param fmt printf format string + * @param data format string varargs containing data to print + */ + def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + when (!(Builder.dynamicContext.currentModule.get.reset)) { + printfWithoutReset(fmt, data:_*) + } + } + + private[Chisel] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + val clock = Builder.dynamicContext.currentModule.get.clock + pushCommand(Printf(sourceInfo, Node(clock), fmt, data.map((d: Bits) => d.ref))) + } +} diff --git a/chiselFrontend/src/main/scala/Chisel/Reg.scala b/chiselFrontend/src/main/scala/Chisel/Reg.scala index e69061c5..c8faa5c9 100644 --- a/chiselFrontend/src/main/scala/Chisel/Reg.scala +++ b/chiselFrontend/src/main/scala/Chisel/Reg.scala @@ -5,6 +5,7 @@ package Chisel import internal._ import internal.Builder.pushCommand import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { private[Chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { @@ -36,7 +37,18 @@ object Reg { * is a valid value. In those cases, you can either use the outType only Reg * constructor or pass in `null.asInstanceOf[T]`. */ - def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = { + def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = + // Scala macros can't (yet) handle named or default arguments. + do_apply(t, next, init)(UnlocatableSourceInfo) + + /** Creates a register without initialization (reset is ignored). Value does + * not change unless assigned to (using the := operator). + * + * @param outType: data type for the register + */ + def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T]) + + def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo): T = { // TODO: write this in a way that doesn't need nulls (bad Scala style), // null.asInstanceOf[T], and two constructors. Using Option types are an // option, but introduces cumbersome syntax (wrap everything in a Some()). @@ -47,20 +59,13 @@ object Reg { val x = makeType(t, next, init) val clock = Node(x._parent.get.clock) // TODO multi-clock if (init == null) { - pushCommand(DefReg(x, clock)) + pushCommand(DefReg(sourceInfo, x, clock)) } else { - pushCommand(DefRegInit(x, clock, Node(x._parent.get.reset), init.ref)) + pushCommand(DefRegInit(sourceInfo, x, clock, Node(x._parent.get.reset), init.ref)) } if (next != null) { x := next } x } - - /** Creates a register without initialization (reset is ignored). Value does - * not change unless assigned to (using the := operator). - * - * @param outType: data type for the register - */ - def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T]) } diff --git a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala index c63f5735..e3e58cb4 100644 --- a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala @@ -2,9 +2,15 @@ package Chisel +import scala.language.experimental.macros + +import internal.sourceinfo.{SourceInfo, SourceInfoTransform} + private[Chisel] object SeqUtils { /** Equivalent to Cat(r(n-1), ..., r(0)) */ - def asUInt[T <: Bits](in: Seq[T]): UInt = { + def asUInt[T <: Bits](in: Seq[T]): UInt = macro SourceInfoTransform.inArg + + def do_asUInt[T <: Bits](in: Seq[T])(implicit sourceInfo: SourceInfo): UInt = { if (in.tail.isEmpty) { in.head.asUInt } else { @@ -15,7 +21,9 @@ private[Chisel] object SeqUtils { } /** Counts the number of true Bools in a Seq */ - def count(in: Seq[Bool]): UInt = { + def count(in: Seq[Bool]): UInt = macro SourceInfoTransform.inArg + + def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = { if (in.size == 0) { UInt(0) } else if (in.size == 1) { @@ -26,7 +34,9 @@ private[Chisel] object SeqUtils { } /** Returns data value corresponding to first true predicate */ - def priorityMux[T <: Bits](in: Seq[(Bool, T)]): T = { + def priorityMux[T <: Bits](in: Seq[(Bool, T)]): T = macro SourceInfoTransform.inArg + + def do_priorityMux[T <: Bits](in: Seq[(Bool, T)])(implicit sourceInfo: SourceInfo): T = { if (in.size == 1) { in.head._2 } else { @@ -35,7 +45,9 @@ private[Chisel] object SeqUtils { } /** Returns data value corresponding to lone true predicate */ - def oneHotMux[T <: Data](in: Iterable[(Bool, T)]): T = { + def oneHotMux[T <: Data](in: Iterable[(Bool, T)]): T = macro SourceInfoTransform.inArg + + def do_oneHotMux[T <: Data](in: Iterable[(Bool, T)])(implicit sourceInfo: SourceInfo): T = { if (in.tail.isEmpty) { in.head._2 } else { diff --git a/chiselFrontend/src/main/scala/Chisel/When.scala b/chiselFrontend/src/main/scala/Chisel/When.scala index 5f6b02c5..90b3d1a5 100644 --- a/chiselFrontend/src/main/scala/Chisel/When.scala +++ b/chiselFrontend/src/main/scala/Chisel/When.scala @@ -2,9 +2,12 @@ package Chisel +import scala.language.experimental.macros + import internal._ import internal.Builder.pushCommand import internal.firrtl._ +import internal.sourceinfo.{SourceInfo} object when { // scalastyle:ignore object.name /** Create a `when` condition block, where whether a block of logic is @@ -24,8 +27,8 @@ object when { // scalastyle:ignore object.name * } * }}} */ - def apply(cond: Bool)(block: => Unit): WhenContext = { - new WhenContext(cond, !cond)(block) + def apply(cond: Bool)(block: => Unit)(implicit sourceInfo: SourceInfo): WhenContext = { + new WhenContext(sourceInfo, cond, !cond, block) } } @@ -36,21 +39,21 @@ object when { // scalastyle:ignore object.name * that both the condition is true and all the previous conditions have been * false. */ -class WhenContext(cond: Bool, prevCond: => Bool)(block: => Unit) { +final class WhenContext(sourceInfo: SourceInfo, cond: Bool, prevCond: => Bool, block: => Unit) { /** This block of logic gets executed if above conditions have been false * and this condition is true. */ - def elsewhen (elseCond: Bool)(block: => Unit): WhenContext = { - new WhenContext(prevCond && elseCond, prevCond && !elseCond)(block) + def elsewhen (elseCond: Bool)(block: => Unit)(implicit sourceInfo: SourceInfo): WhenContext = { + new WhenContext(sourceInfo, prevCond && elseCond, prevCond && !elseCond, block) } /** This block of logic gets executed only if the above conditions were all * false. No additional logic blocks may be appended past the `otherwise`. */ - def otherwise(block: => Unit): Unit = - new WhenContext(prevCond, null)(block) + def otherwise(block: => Unit)(implicit sourceInfo: SourceInfo): Unit = + new WhenContext(sourceInfo, prevCond, null, block) - pushCommand(WhenBegin(cond.ref)) + pushCommand(WhenBegin(sourceInfo, cond.ref)) block - pushCommand(WhenEnd()) + pushCommand(WhenEnd(sourceInfo)) } diff --git a/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala new file mode 100644 index 00000000..66bfc7a4 --- /dev/null +++ b/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala @@ -0,0 +1,51 @@ +// See LICENSE for license details. + +// This file contains macros for adding source locators at the point of invocation. +// +// This is not part of coreMacros to disallow this macro from being implicitly invoked in Chisel +// frontend (and generating source locators in Chisel core), which is almost certainly a bug. +// +// Note: While these functions and definitions are not private (macros can't be +// private), these are NOT meant to be part of the public API (yet) and no +// forward compatibility guarantees are made. +// A future revision may stabilize the source locator API to allow library +// writers to append source locator information at the point of a library +// function invocation. + +package Chisel.internal.sourceinfo + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +/** Abstract base class for generalized source information. + */ +sealed trait SourceInfo + +sealed trait NoSourceInfo extends SourceInfo + +/** For when source info can't be generated because of a technical limitation, like for Reg because + * Scala macros don't support named or default arguments. + */ +case object UnlocatableSourceInfo extends NoSourceInfo + +/** For when source info isn't generated because the function is deprecated and we're lazy. + */ +case object DeprecatedSourceInfo extends NoSourceInfo + +/** For FIRRTL lines from a Scala source line. + */ +case class SourceLine(filename: String, line: Int, col: Int) extends SourceInfo + +/** Provides a macro that returns the source information at the invocation point. + */ +object SourceInfoMacro { + def generate_source_info(c: Context): c.Tree = { + import c.universe._ + val p = c.enclosingPosition + q"_root_.Chisel.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})" + } +} + +object SourceInfo { + implicit def materialize: SourceInfo = macro SourceInfoMacro.generate_source_info +} diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala deleted file mode 100644 index 34547503..00000000 --- a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala +++ /dev/null @@ -1,105 +0,0 @@ -// See LICENSE for license details. - -package Chisel.internal.firrtl -import Chisel._ - -private[Chisel] object Emitter { - def emit(circuit: Circuit): String = new Emitter(circuit).toString -} - -private class Emitter(circuit: Circuit) { - override def toString: String = res.toString - - private def emitPort(e: Port): String = - s"${e.dir} ${e.id.getRef.name} : ${e.id.toType}" - private def emit(e: Command, ctx: Component): String = e match { - case e: DefPrim[_] => s"node ${e.name} = ${e.op.name}(${e.args.map(_.fullName(ctx)).mkString(", ")})" - case e: DefWire => s"wire ${e.name} : ${e.id.toType}" - case e: DefReg => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)}" - case e: DefRegInit => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))" - case e: DefMemory => s"cmem ${e.name} : ${e.t.toType}[${e.size}]" - case e: DefSeqMemory => s"smem ${e.name} : ${e.t.toType}[${e.size}]" - case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}" - case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}" - case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}" - case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})" - case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})""" - case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid" - case e: DefInstance => { - val modName = moduleMap.get(e.id.name).get - s"inst ${e.name} of $modName" - } - - case w: WhenBegin => - indent() - s"when ${w.pred.fullName(ctx)} :" - case _: WhenEnd => - unindent() - "skip" - } - - // Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already. - private val defnMap = collection.mutable.HashMap[String, String]() - // Map of Component name to FIRRTL id. - private val moduleMap = collection.mutable.HashMap[String, String]() - - /** Generates the FIRRTL module definition with a specified name. - */ - private def moduleDefn(m: Component, name: String): String = { - val body = new StringBuilder - m.id match { - case _: BlackBox => body ++= newline + s"extmodule $name : " - case _: Module => body ++= newline + s"module $name : " - } - withIndent { - for (p <- m.ports) - body ++= newline + emitPort(p) - body ++= newline - - m.id match { - case _: BlackBox => - // TODO: BlackBoxes should be empty, but funkiness in Module() means - // it's not for now. Eventually, this should assert out. - case _: Module => for (cmd <- m.commands) { - body ++= newline + emit(cmd, m) - } - } - body ++= newline - } - body.toString() - } - - /** Returns the FIRRTL declaration and body of a module, or nothing if it's a - * duplicate of something already emitted (on the basis of simple string - * matching). - */ - private def emit(m: Component): String = { - // Generate the body. - val moduleName = m.id.getClass.getName.split('.').last - val defn = moduleDefn(m, moduleName) - - defnMap get defn match { - case Some(deduplicatedName) => - moduleMap(m.name) = deduplicatedName - "" - case None => - require(!(moduleMap contains m.name), - "emitting module with same name but different contents") - - moduleMap(m.name) = m.name - defnMap(defn) = m.name - - moduleDefn(m, m.name) - } - } - - private var indentLevel = 0 - private def newline = "\n" + (" " * indentLevel) - private def indent(): Unit = indentLevel += 1 - private def unindent() { require(indentLevel > 0); indentLevel -= 1 } - private def withIndent(f: => Unit) { indent(); f; unindent() } - - private val res = new StringBuilder(s"circuit ${circuit.name} : ") - withIndent { circuit.components.foreach(c => res ++= emit(c)) } - res ++= newline -} diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala index 91dcf5d2..62784cee 100644 --- a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala @@ -3,6 +3,7 @@ package Chisel.internal.firrtl import Chisel._ import Chisel.internal._ +import Chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} case class PrimOp(val name: String) { override def toString: String = name @@ -142,29 +143,31 @@ object MemPortDirection { object INFER extends MemPortDirection("infer") } -abstract class Command +abstract class Command { + def sourceInfo: SourceInfo +} abstract class Definition extends Command { def id: HasId def name: String = id.getRef.name } -case class DefPrim[T <: Data](id: T, op: PrimOp, args: Arg*) extends Definition -case class DefInvalid(arg: Arg) extends Command -case class DefWire(id: Data) extends Definition -case class DefReg(id: Data, clock: Arg) extends Definition -case class DefRegInit(id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition -case class DefMemory(id: HasId, t: Data, size: Int) extends Definition -case class DefSeqMemory(id: HasId, t: Data, size: Int) extends Definition -case class DefMemPort[T <: Data](id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition -case class DefInstance(id: Module, ports: Seq[Port]) extends Definition -case class WhenBegin(pred: Arg) extends Command -case class WhenEnd() extends Command -case class Connect(loc: Node, exp: Arg) extends Command -case class BulkConnect(loc1: Node, loc2: Node) extends Command -case class ConnectInit(loc: Node, exp: Arg) extends Command -case class Stop(clk: Arg, ret: Int) extends Command +case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition +case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command +case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition +case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition +case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition +case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition +case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition +case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition +case class DefInstance(sourceInfo: SourceInfo, id: Module, ports: Seq[Port]) extends Definition +case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command +case class WhenEnd(sourceInfo: SourceInfo) extends Command +case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command +case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +case class Stop(sourceInfo: SourceInfo, clk: Arg, ret: Int) extends Command case class Component(id: Module, name: String, ports: Seq[Port], commands: Seq[Command]) extends Arg case class Port(id: Data, dir: Direction) -case class Printf(clk: Arg, formatIn: String, ids: Seq[Arg]) extends Command { +case class Printf(sourceInfo: SourceInfo, clk: Arg, formatIn: String, ids: Seq[Arg]) extends Command { require(formatIn.forall(c => c.toInt > 0 && c.toInt < 128), "format strings must comprise non-null ASCII values") def format: String = { def escaped(x: Char) = { -- cgit v1.2.3 From 3b10267257de7662abbbc235d9bfd8a8b89f69f5 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 26 May 2016 01:01:55 -0700 Subject: Fix type constraint on PriorityMux --- chiselFrontend/src/main/scala/Chisel/SeqUtils.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src/main') diff --git a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala index e3e58cb4..9a15fd5f 100644 --- a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala @@ -34,9 +34,9 @@ private[Chisel] object SeqUtils { } /** Returns data value corresponding to first true predicate */ - def priorityMux[T <: Bits](in: Seq[(Bool, T)]): T = macro SourceInfoTransform.inArg + def priorityMux[T <: Data](in: Seq[(Bool, T)]): T = macro SourceInfoTransform.inArg - def do_priorityMux[T <: Bits](in: Seq[(Bool, T)])(implicit sourceInfo: SourceInfo): T = { + def do_priorityMux[T <: Data](in: Seq[(Bool, T)])(implicit sourceInfo: SourceInfo): T = { if (in.size == 1) { in.head._2 } else { -- cgit v1.2.3 From 2e2e3da0c07cd1dc873c064510f68123cae69059 Mon Sep 17 00:00:00 2001 From: Ducky Date: Mon, 23 May 2016 14:09:26 -0700 Subject: Move BitPat out of core/frontend, add implicit conversion --- chiselFrontend/src/main/scala/Chisel/BitPat.scala | 88 ----------------------- chiselFrontend/src/main/scala/Chisel/Bits.scala | 8 --- 2 files changed, 96 deletions(-) delete mode 100644 chiselFrontend/src/main/scala/Chisel/BitPat.scala (limited to 'chiselFrontend/src/main') diff --git a/chiselFrontend/src/main/scala/Chisel/BitPat.scala b/chiselFrontend/src/main/scala/Chisel/BitPat.scala deleted file mode 100644 index cf412542..00000000 --- a/chiselFrontend/src/main/scala/Chisel/BitPat.scala +++ /dev/null @@ -1,88 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import Chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} - -object BitPat { - /** Parses a bit pattern string into (bits, mask, width). - * - * @return bits the literal value, with don't cares being 0 - * @return mask the mask bits, with don't cares being 0 and cares being 1 - * @return width the number of bits in the literal, including values and - * don't cares. - */ - private def parse(x: String): (BigInt, BigInt, Int) = { - // Notes: - // While Verilog Xs also handle octal and hex cases, there isn't a - // compelling argument and no one has asked for it. - // If ? parsing is to be exposed, the return API needs further scrutiny - // (especially with things like mask polarity). - require(x.head == 'b', "BitPats must be in binary and be prefixed with 'b'") - var bits = BigInt(0) - var mask = BigInt(0) - for (d <- x.tail) { - if (d != '_') { - require("01?".contains(d), "Literal: " + x + " contains illegal character: " + d) - mask = (mask << 1) + (if (d == '?') 0 else 1) - bits = (bits << 1) + (if (d == '1') 1 else 0) - } - } - (bits, mask, x.length - 1) - } - - /** Creates a [[BitPat]] literal from a string. - * - * @param n the literal value as a string, in binary, prefixed with 'b' - * @note legal characters are '0', '1', and '?', as well as '_' as white - * space (which are ignored) - */ - def apply(n: String): BitPat = { - val (bits, mask, width) = parse(n) - new BitPat(bits, mask, width) - } - - /** Creates a [[BitPat]] of all don't cares of the specified bitwidth. */ - def dontCare(width: Int): BitPat = BitPat("b" + ("?" * width)) - - @deprecated("Use BitPat.dontCare", "chisel3") - def DC(width: Int): BitPat = dontCare(width) // scalastyle:ignore method.name - - /** Allows BitPats to be used where a UInt is expected. - * - * @note the BitPat must not have don't care bits (will error out otherwise) - */ - implicit def bitPatToUInt(x: BitPat): UInt = { - require(x.mask == (BigInt(1) << x.getWidth) - 1) - UInt(x.value, x.getWidth) - } - - /** Allows UInts to be used where a BitPat is expected, useful for when an - * interface is defined with BitPats but not all cases need the partial - * matching capability. - * - * @note the UInt must be a literal - */ - implicit def apply(x: UInt): BitPat = { - require(x.isLit) - BitPat("b" + x.litValue.toString(2)) - } -} - -// TODO: Break out of Core? (this doesn't involve FIRRTL generation) -/** Bit patterns are literals with masks, used to represent values with don't - * cares. Equality comparisons will ignore don't care bits (for example, - * BitPat(0b10?1) === UInt(0b1001) and UInt(0b1011)). - */ -sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) { - def getWidth: Int = width - def === (that: UInt): Bool = macro SourceInfoTransform.thatArg - def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg - def != (that: UInt): Bool = macro SourceInfoTransform.thatArg - - def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = UInt(value) === (that & UInt(mask)) - def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = !(this === that) - def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = this =/= that -} diff --git a/chiselFrontend/src/main/scala/Chisel/Bits.scala b/chiselFrontend/src/main/scala/Chisel/Bits.scala index 2783c160..bc8cc8e2 100644 --- a/chiselFrontend/src/main/scala/Chisel/Bits.scala +++ b/chiselFrontend/src/main/scala/Chisel/Bits.scala @@ -464,14 +464,6 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi Mux(dat, this | bit, ~(~this | bit)) } - final def === (that: BitPat): Bool = macro SourceInfoTransform.thatArg - final def != (that: BitPat): Bool = macro SourceInfoTransform.thatArg - final def =/= (that: BitPat): Bool = macro SourceInfoTransform.thatArg - - def do_=== (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that === this - def do_!= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that != this - def do_=/= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that =/= this - /** Returns this UInt as a [[SInt]] with an additional zero in the MSB. */ // TODO: this eventually will be renamed as toSInt, once the existing toSInt -- cgit v1.2.3 From fd53af8642237998e23456a3fd1648ac84607db0 Mon Sep 17 00:00:00 2001 From: Wesley W. Terpstra Date: Wed, 1 Jun 2016 16:09:20 -0700 Subject: Fix a fairly serious bug whereby Vec's could incorrectly compare as equal (#204) * chiselTests: include an example of two empty Vectors killing FIRRTL * Aggregate: fix a bug whereby Vec[T] was using equals/hashCode of Seq In Chisel, two vectors are NOT equal just if their contents are equal. For example, two empty vectors should not be considered equal. This patch makes Vec use the HasId._id for equality like other Chisel types. Without this fix, Bundle.namedElts.seen: HashSet[Data]() will eliminate one of the named vectors and emit bad IR. --- chiselFrontend/src/main/scala/Chisel/Aggregate.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'chiselFrontend/src/main') diff --git a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala index 197135d7..1eef5d69 100644 --- a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala +++ b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala @@ -174,9 +174,13 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) /** A trait for [[Vec]]s containing common hardware generators for collection * operations. */ -trait VecLike[T <: Data] extends collection.IndexedSeq[T] { +trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId { def apply(idx: UInt): T + // IndexedSeq has its own hashCode/equals that we must not use + override def hashCode: Int = super[HasId].hashCode + override def equals(that: Any): Boolean = super[HasId].equals(that) + @deprecated("Use Vec.apply instead", "chisel3") def read(idx: UInt): T -- cgit v1.2.3