diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 655ff7e8cdc..fea333dde76 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -90,7 +90,7 @@ jobs: $CHISEL_FIRTOOL_PATH/firtool -version >> $GITHUB_STEP_SUMMARY echo \`\`\` >> $GITHUB_STEP_SUMMARY - name: Test - run: ./mill -j0 firrtl[_].test + svsim[_].test + chisel[_].test + run: ./mill -j0 firrtl[].test + svsim[].test + chisel[].test - name: Binary compatibility # TODO either make this also check the plugin or decide that we don't # support binary compatibility for the plugin @@ -132,7 +132,7 @@ jobs: $CHISEL_FIRTOOL_PATH/firtool -version >> $GITHUB_STEP_SUMMARY echo \`\`\` >> $GITHUB_STEP_SUMMARY - name: Compile with Mill - run: ./mill __.compile + run: ./mill compileAll doc: name: Formatting @@ -183,7 +183,7 @@ jobs: dir=$(dirname $(which firtool)) echo "CHISEL_FIRTOOL_PATH=$dir" >> "$GITHUB_ENV" - name: Integration Tests - run: ./mill -j0 integrationTests[_].test + run: ./mill -j0 integrationTests[].test # Currently just a sanity check that the benchmarking flow works benchmark: diff --git a/build.sc b/build.sc index 20480dd3830..bce888a8d5c 100644 --- a/build.sc +++ b/build.sc @@ -34,15 +34,34 @@ object v extends Module { val java21Min213 = 11 val minVersion = if (javaVersion > 11) java21Min213 else 0 val versions = minVersion to latest213 - versions.map(v => s"2.13.$v").toSeq + val versionSeq = versions.map(v => s"2.13.$v").toSeq + versionSeq ++ Seq("3.3.4") } val scalaCrossVersions = Seq( - "2.13.15" + "2.13.15", + "3.3.4" ) def isScala3(ver: String): Boolean = ver.startsWith("3.") + def buildUnits(): Seq[ScalaModule] = { + scalaCrossVersions.flatMap { ver => + Seq(chisel(ver), stdlib(ver), unipublish) + } ++ scalaCrossVersions.filterNot(isScala3(_)).flatMap { ver2 => + Seq( + chisel(ver2).test, + firrtl(ver2).test, + svsim(ver2).test, + integrationTests(ver2).test, + litutility(ver2), + panamaconverter(ver2), + panamalib(ver2), + panamaom(ver2) + ) + } + } + val scalaVersion = scalaCrossVersions.head val jmhVersion = "1.37" val osLib = ivy"com.lihaoyi::os-lib:0.10.0" @@ -96,6 +115,10 @@ object v extends Module { ) } +def compileAll() = T.command { + T.traverse(v.buildUnits())(_.compile)() +} + trait ChiselPublishModule extends CiReleaseModule { // Publish information def pomSettings = PomSettings( @@ -251,7 +274,7 @@ trait Core extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { ) override def ivyDeps = if (v.isScala3(crossScalaVersion)) { - super.ivyDeps() ++ commonDeps + super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver.withDottyCompat(scalaVersion())) } else { super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver) } @@ -309,7 +332,13 @@ trait Plugin extends CrossSbtModule with ScalafmtModule with ChiselPublishModule def scalaReflectIvy = v.scalaReflect(crossScalaVersion) def scalaCompilerIvy: Dep = v.scalaCompiler(crossScalaVersion) - def ivyDeps = super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy) + def ivyDeps = T { + if (!v.isScala3(crossScalaVersion)) { + super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy) + } else { + super.ivyDeps() + } + } } object chisel extends Cross[Chisel](v.scalaCrossVersions) diff --git a/core/src/main/scala/chisel3/experimental/SerializableModuleGenerator.scala b/core/src/main/scala-2/chisel3/experimental/SerializableModuleGenerator.scala similarity index 100% rename from core/src/main/scala/chisel3/experimental/SerializableModuleGenerator.scala rename to core/src/main/scala-2/chisel3/experimental/SerializableModuleGenerator.scala diff --git a/core/src/main/scala-2/chisel3/experimental/dataview/ChiselSubtypeOf.scala b/core/src/main/scala-2/chisel3/experimental/dataview/ChiselSubtypeOf.scala index b8ca824c7ab..f30d868065e 100644 --- a/core/src/main/scala-2/chisel3/experimental/dataview/ChiselSubtypeOf.scala +++ b/core/src/main/scala-2/chisel3/experimental/dataview/ChiselSubtypeOf.scala @@ -27,6 +27,7 @@ import scala.reflect.macros.blackbox.Context */ sealed trait ChiselSubtypeOf[A, B] +// return an empty tree here instead of a quasiquote for scala3 compatibility object ChiselSubtypeOf { // TODO return an empty tree here instead of a quasiquote for scala3 compatibility def genChiselSubtypeOf[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context): c.Tree = { diff --git a/core/src/main/scala-2/chisel3/experimental/hierarchy/IsA.scala b/core/src/main/scala-2/chisel3/experimental/hierarchy/IsA.scala new file mode 100644 index 00000000000..24adecbf438 --- /dev/null +++ b/core/src/main/scala-2/chisel3/experimental/hierarchy/IsA.scala @@ -0,0 +1,54 @@ +package chisel3.experimental.hierarchy.core + +import chisel3._ +import scala.reflect.runtime.universe.TypeTag + +trait HierarchyProto[+A] { + private[chisel3] def underlying: Underlying[A] + private[chisel3] def proto: A = underlying match { + case Proto(value) => value + case Clone(i: IsClone[A]) => i.getProto + } +} + +trait HierarchyIsA[+A] extends HierarchyProto[A] { + // This code handles a special-case where, within an mdoc context, the type returned from + // scala reflection (typetag) looks different than when returned from java reflection. + // This function detects this case and reshapes the string to match. + private def modifyReplString(clz: String): String = { + if (clz != null) { + clz.split('.').toList match { + case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".") + case other => clz + } + } else clz + } + + private lazy val superClasses = calculateSuperClasses(super.proto.getClass()) + private def calculateSuperClasses(clz: Class[_]): Set[String] = { + if (clz != null) { + Set(modifyReplString(clz.getCanonicalName())) ++ + clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++ + calculateSuperClasses(clz.getSuperclass()) + } else { + Set.empty[String] + } + } + private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz) + + /** Determine whether underlying proto is of type provided. + * + * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class. + * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure. + * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type + * + * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String] + * @return Whether underlying proto is of provided type (with caveats outlined above) + */ + def isA[B: TypeTag]: Boolean = { + val tptag = implicitly[TypeTag[B]] + // drop any type information for the comparison, because the proto will not have that information. + val name = tptag.tpe.toString.takeWhile(_ != '[') + inBaseClasses(name) + } +} diff --git a/core/src/main/scala-3/chisel3/Aggregate.scala b/core/src/main/scala-3/chisel3/Aggregate.scala new file mode 100644 index 00000000000..b7c6e778918 --- /dev/null +++ b/core/src/main/scala-3/chisel3/Aggregate.scala @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.VecLiterals.AddVecLiteralConstructor + +import scala.collection.immutable.{SeqMap, VectorMap} +import scala.collection.mutable.{HashSet, LinkedHashMap} +import chisel3.experimental.{BaseModule, BundleLiteralException, OpaqueType, SourceInfo, VecLiteralException} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ + +import java.lang.Math.{floor, log10, pow} +import scala.collection.mutable + +/** An abstract class for data types that solely consist of (are an aggregate + * of) other Data objects. + */ +sealed trait Aggregate extends AggregateImpl + +/** A vector (array) of [[Data]] elements. Provides hardware versions of various + * collection transformation functions found in software array implementations. + * + * Careful consideration should be given over the use of [[Vec]] vs + * [[scala.collection.immutable.Seq Seq]] or some other Scala collection. In general [[Vec]] only + * needs to be used when there is a need to express the hardware collection in a [[Reg]] or IO + * [[Bundle]] or when access to elements of the array is indexed via a hardware signal. + * + * Example of indexing into a [[Vec]] using a hardware address and where the [[Vec]] is defined in + * an IO [[Bundle]] + * + * {{{ + * val io = IO(new Bundle { + * val in = Input(Vec(20, UInt(16.W))) + * val addr = Input(UInt(5.W)) + * val out = Output(UInt(16.W)) + * }) + * io.out := io.in(io.addr) + * }}} + * + * @tparam T type of elements + * + * @note + * - when multiple conflicting assignments are performed on a Vec element, the last one takes effect (unlike Mem, where the result is undefined) + * - Vecs, unlike classes in Scala's collection library, are propagated intact to FIRRTL as a vector type, which may make debugging easier + */ +sealed class Vec[T <: Data] private[chisel3] (gen: => T, length: Int) + extends VecImpl[T](gen, length) + with VecLike[T] + with Aggregate { + + override def toString: String = super[VecImpl].toString + + def apply(p: UInt)(using sourceInfo: SourceInfo): T = _applyImpl(p) + + /** A reduce operation in a tree like structure instead of sequentially + * @example An adder tree + * {{{ + * val sumOut = inputNums.reduceTree((a: T, b: T) => (a + b)) + * }}} + */ + // def reduceTree(redOp: (T, T) => T): T = macro VecTransform.reduceTreeDefault + + /** A reduce operation in a tree like structure instead of sequentially + * @example A pipelined adder tree + * {{{ + * val sumOut = inputNums.reduceTree( + * (a: T, b: T) => RegNext(a + b), + * (a: T) => RegNext(a) + * ) + * }}} + */ + def reduceTree( + redOp: (T, T) => T, + layerOp: (T) => T = (x: T) => x + )( + using sourceInfo: SourceInfo + ): T = _reduceTreeImpl(redOp, layerOp) +} + +object Vec extends VecFactory + +object VecInit extends VecInitImpl with SourceInfoDoc { + + /** Creates a new [[Vec]] composed of elements of the input Seq of [[Data]] + * nodes. + * + * @note input elements should be of the same type (this is checked at the + * FIRRTL level, but not at the Scala / Chisel level) + * @note the width of all output elements is the width of the largest input + * element + * @note output elements are connected from the input elements + */ + def apply[T <: Data](elts: Seq[T])(using sourceInfo: SourceInfo): Vec[T] = _applyImpl(elts) + + /** Creates a new [[Vec]] composed of the input [[Data]] nodes. + * + * @note input elements should be of the same type (this is checked at the + * FIRRTL level, but not at the Scala / Chisel level) + * @note the width of all output elements is the width of the largest input + * element + * @note output elements are connected from the input elements + */ + def apply[T <: Data](elt0: T, elts: T*)(using sourceInfo: SourceInfo): Vec[T] = _applyImpl(elt0, elts: _*) + + /** Creates a new [[Vec]] of length `n` composed of the results of the given + * function applied over a range of integer values starting from 0. + * + * @param n number of elements in the vector (the function is applied from + * 0 to `n-1`) + * @param gen function that takes in an Int (the index) and returns a + * [[Data]] that becomes the output element + */ + def tabulate[T <: Data]( + n: Int + )(gen: (Int) => T + )( + using sourceInfo: SourceInfo + ): Vec[T] = _tabulateImpl(n)(gen) + + /** Creates a new 2D [[Vec]] of length `n by m` composed of the results of the given + * function applied over a range of integer values starting from 0. + * + * @param n number of 1D vectors inside outer vector + * @param m number of elements in each 1D vector (the function is applied from + * 0 to `n-1`) + * @param gen function that takes in an Int (the index) and returns a + * [[Data]] that becomes the output element + */ + def tabulate[T <: Data]( + n: Int, + m: Int + )(gen: (Int, Int) => T + )( + using sourceInfo: SourceInfo + ): Vec[Vec[T]] = _tabulateImpl(n, m)(gen) + + /** Creates a new 3D [[Vec]] of length `n by m by p` composed of the results of the given + * function applied over a range of integer values starting from 0. + * + * @param n number of 2D vectors inside outer vector + * @param m number of 1D vectors in each 2D vector + * @param p number of elements in each 1D vector + * @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, + m: Int, + p: Int + )(gen: (Int, Int, Int) => T + )( + using sourceInfo: SourceInfo + ): Vec[Vec[Vec[T]]] = _tabulateImpl(n, m, p)(gen) + + /** Creates a new [[Vec]] of length `n` composed of the result of the given + * function applied to an element of data type T. + * + * @param n number of elements in the vector + * @param gen function that takes in an element T and returns an output + * element of the same type + */ + def fill[T <: Data](n: Int)(gen: => T)(using sourceInfo: SourceInfo): Vec[T] = _fillImpl(n)(gen) + + /** Creates a new 2D [[Vec]] of length `n by m` composed of the result of the given + * function applied to an element of data type T. + * + * @param n number of inner vectors (rows) in the outer vector + * @param m number of elements in each inner vector (column) + * @param gen function that takes in an element T and returns an output + * element of the same type + */ + def fill[T <: Data]( + n: Int, + m: Int + )(gen: => T + )( + using sourceInfo: SourceInfo + ): Vec[Vec[T]] = _fillImpl(n, m)(gen) + + /** Creates a new 3D [[Vec]] of length `n by m by p` composed of the result of the given + * function applied to an element of data type T. + * + * @param n number of 2D vectors inside outer vector + * @param m number of 1D vectors in each 2D vector + * @param p number of elements in each 1D vector + * @param gen function that takes in an element T and returns an output + * element of the same type + */ + def fill[T <: Data]( + n: Int, + m: Int, + p: Int + )(gen: => T + )( + using sourceInfo: SourceInfo + ): Vec[Vec[Vec[T]]] = _fillImpl(n, m, p)(gen) + + /** Creates a new [[Vec]] of length `n` composed of the result of the given + * function applied to an element of data type T. + * + * @param start First element in the Vec + * @param len Lenth of elements in the Vec + * @param f Function that applies the element T from previous index and returns the output + * element to the next index + */ + def iterate[T <: Data]( + start: T, + len: Int + )(f: (T) => T + )( + using sourceInfo: SourceInfo + ): Vec[T] = _iterateImpl(start, len)(f) +} + +/** A trait for [[Vec]]s containing common hardware generators for collection + * operations. + */ +trait VecLike[T <: Data] extends VecLikeImpl[T] with SourceInfoDoc { + + /** Creates a dynamically indexed read or write accessor into the array. + */ + def apply(p: UInt)(using sourceInfo: SourceInfo): T + + /** Outputs true if p outputs true for every element. + */ + def forall(p: T => Bool)(using sourceInfo: SourceInfo): Bool = _forallImpl(p) + + /** Outputs true if p outputs true for at least one element. + */ + def exists(p: T => Bool)(using sourceInfo: SourceInfo): Bool = _existsImpl(p) + + /** Outputs true if the vector contains at least one element equal to x (using + * the === operator). + */ + def contains(x: T)(using sourceInfo: SourceInfo, ev: T <:< UInt): Bool = _containsImpl(x) + + /** Outputs the number of elements for which p is true. + */ + def count(p: T => Bool)(using sourceInfo: SourceInfo): UInt = _countImpl(p) + + /** Outputs the index of the first element for which p outputs true. + */ + def indexWhere(p: T => Bool)(using sourceInfo: SourceInfo): UInt = _indexWhereImpl(p) + + /** Outputs the index of the last element for which p outputs true. + */ + def lastIndexWhere(p: T => Bool)(using sourceInfo: SourceInfo): UInt = _lastIndexWhereImpl(p) + + /** Outputs the index of the element for which p outputs true, assuming that + * the there is exactly one such element. + * + * The implementation may be more efficient than a priority mux, but + * incorrect results are possible if there is not exactly one true element. + * + * @note the assumption that there is only one element for which p outputs + * 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)(using sourceInfo: SourceInfo): UInt = _onlyIndexWhereImpl(p) +} + +/** Base class for Aggregates based on key values pairs of String and Data + * + * Record should only be extended by libraries and fairly sophisticated generators. + * RTL writers should use [[Bundle]]. See [[Record#elements]] for an example. + */ +abstract class Record extends Aggregate with RecordImpl diff --git a/core/src/main/scala-3/chisel3/Bits.scala b/core/src/main/scala-3/chisel3/Bits.scala new file mode 100644 index 00000000000..f197bce4356 --- /dev/null +++ b/core/src/main/scala-3/chisel3/Bits.scala @@ -0,0 +1,648 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.internal._ +import chisel3.internal.Builder.pushOp +import chisel3.internal.firrtl.ir._ +import chisel3.internal.firrtl.ir.PrimOp._ +import chisel3.experimental.{requireIsHardware, SourceInfo} + +/** Exists to unify common interfaces of [[Bits]] and [[Reset]]. + * + * @note This is a workaround because macros cannot override abstract methods. + */ +private[chisel3] sealed trait ToBoolable extends Element { + def asBool: Bool +} + +/** A data type for values represented by a single bitvector. This provides basic bitwise operations. + * + * @groupdesc Bitwise Bitwise hardware operators + * @define coll [[Bits]] + * @define sumWidthInt @note The width of the returned $coll is `width of this` + `that`. + * @define sumWidth @note The width of the returned $coll is `width of this` + `width of that`. + * @define unchangedWidth @note The width of the returned $coll is unchanged, i.e., the `width of this`. + */ +sealed abstract class Bits(private[chisel3] val width: Width) extends BitsImpl with ToBoolable { + + /** Tail operator + * + * @param n the number of bits to remove + * @return This $coll with the `n` most significant bits removed. + * @group Bitwise + */ + def tail(n: Int)(using sourceInfo: SourceInfo): UInt = _tailImpl(n) + + /** Head operator + * + * @param n the number of bits to take + * @return The `n` most significant bits of this $coll + * @group Bitwise + */ + def head(n: Int)(using sourceInfo: SourceInfo): UInt = _headImpl(n) + + /** Returns the specified bit on this $coll as a [[Bool]], statically addressed. + * + * @param x an index + * @return the specified bit + */ + + final def extract(x: BigInt)(using sourceInfo: SourceInfo): Bool = _extractImpl(x) + + /** Returns the specified bit on this $coll as a [[Bool]], statically addressed. + * + * @param x an index + * @return the specified bit + */ + final def apply(x: Int)(using sourceInfo: SourceInfo): Bool = _applyImpl(x) + + /** Grab the bottom n bits. Return 0.U(0.W) if n==0. */ + final def take(n: Int)(using sourceInfo: SourceInfo): UInt = _takeImpl(n) + + /** Returns the specified bit on this wire as a [[Bool]], dynamically addressed. + * + * @param x a hardware component whose value will be used for dynamic addressing + * @return the specified bit + */ + final def extract(x: UInt)(using sourceInfo: SourceInfo): Bool = _extractImpl(x) + + /** Returns the specified bit on this wire as a [[Bool]], dynamically addressed. + * + * @param x a hardware component whose value will be used for dynamic addressing + * @return the specified bit + */ + final def apply(x: UInt)(using sourceInfo: SourceInfo): Bool = _applyImpl(x) + + /** Returns a subset of bits on this $coll from `hi` to `lo` (inclusive), statically addressed. + * + * @example + * {{{ + * myBits = 0x5 = 0b101 + * myBits(1,0) => 0b01 // extracts the two least significant bits + * }}} + * @param x the high bit + * @param y the low bit + * @return a hardware component contain the requested bits + */ + final def apply(x: Int, y: Int)(using sourceInfo: SourceInfo): UInt = _applyImpl(x, y) + + // REVIEW TODO: again, is this necessary? Or just have this and use implicits? + /** Returns a subset of bits on this $coll from `hi` to `lo` (inclusive), statically addressed. + * + * @example + * {{{ + * myBits = 0x5 = 0b101 + * myBits(1,0) => 0b01 // extracts the two least significant bits + * }}} + * @param x the high bit + * @param y the low bit + * @return a hardware component contain the requested bits + */ + final def apply(x: BigInt, y: BigInt)(using sourceInfo: SourceInfo): UInt = _applyImpl(x, y) + + /** Pad operator + * + * @param that the width to pad to + * @return this @coll zero padded up to width `that`. If `that` is less than the width of the original component, + * this method returns the original component. + * @note For [[SInt]]s only, this will do sign extension. + * @group Bitwise + */ + def pad(that: Int)(using sourceInfo: SourceInfo): Bits = _padImpl(that) + + /** Bitwise inversion operator + * + * @return this $coll with each bit inverted + * @group Bitwise + */ + def unary_~(using sourceInfo: SourceInfo): Bits = _impl_unary_~ + + /** Static left shift operator + * + * @param that an amount to shift by + * @return this $coll with `that` many zeros concatenated to its least significant end + * $sumWidthInt + * @group Bitwise + */ + def <<(that: BigInt)(using sourceInfo: SourceInfo): Bits = _impl_<<(that) + + /** Static left shift operator + * + * @param that an amount to shift by + * @return this $coll with `that` many zeros concatenated to its least significant end + * $sumWidthInt + * @group Bitwise + */ + def <<(that: Int)(using sourceInfo: SourceInfo): Bits = _impl_<<(that) + + /** Dynamic left shift operator + * + * @param that a hardware component + * @return this $coll dynamically shifted left by `that` many places, shifting in zeros from the right + * @note The width of the returned $coll is `width of this + pow(2, width of that) - 1`. + * @group Bitwise + */ + def <<(that: UInt)(using sourceInfo: SourceInfo): Bits = _impl_<<(that) + + /** Static right shift operator + * + * @param that an amount to shift by + * @return this $coll with `that` many least significant bits truncated + * $unchangedWidth + * @group Bitwise + */ + def >>(that: BigInt)(using sourceInfo: SourceInfo): Bits = _impl_>>(that) + + /** Static right shift operator + * + * @param that an amount to shift by + * @return this $coll with `that` many least significant bits truncated + * $unchangedWidth + * @group Bitwise + */ + def >>(that: Int)(using sourceInfo: SourceInfo): Bits = _impl_>>(that) + + /** Dynamic right shift operator + * + * @param that a hardware component + * @return this $coll dynamically shifted right by the value of `that` component, inserting zeros into the most + * significant bits. + * $unchangedWidth + * @group Bitwise + */ + def >>(that: UInt)(using sourceInfo: SourceInfo): Bits = _impl_>>(that) + + /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */ + def asBools(using sourceInfo: SourceInfo): Seq[Bool] = _asBoolsImpl + + /** Reinterpret this $coll as an [[SInt]] + * + * @note The arithmetic value is not preserved if the most-significant bit is set. For example, a [[UInt]] of + * width 3 and value 7 (0b111) would become an [[SInt]] of width 3 and value -1. + */ + def asSInt(using sourceInfo: SourceInfo): SInt = _asSIntImpl + + def asBool: Bool = _asBoolImpl + + /** Concatenation operator + * + * @param that a hardware component + * @return this $coll concatenated to the most significant end of `that` + * $sumWidth + * @group Bitwise + */ + def ##(that: Bits)(using sourceInfo: SourceInfo): UInt = _impl_##(that) +} + +object Bits extends UIntFactory + +/** A data type for unsigned integers, represented as a binary bitvector. Defines arithmetic operations between other + * integer types. + * + * @define coll [[UInt]] + * @define numType $coll + * @define expandingWidth @note The width of the returned $coll is `width of this` + `1`. + * @define constantWidth @note The width of the returned $coll is unchanged, i.e., `width of this`. + */ +sealed class UInt private[chisel3] (width: Width) extends Bits(width) with UIntImpl { + + // TODO: refactor to share documentation with Num or add independent scaladoc + /** Unary negation (expanding width) + * + * @return a $coll equal to zero minus this $coll + * $constantWidth + * @group Arithmetic + */ + def unary_-(using sourceInfo: SourceInfo): UInt = _impl_unary_- + + /** Unary negation (constant width) + * + * @return a $coll equal to zero minus this $coll shifted right by one. + * $constantWidth + * @group Arithmetic + */ + def unary_-%(using sourceInfo: SourceInfo): UInt = _impl_unary_-% + + override def +(that: UInt): UInt = _impl_+(that) + override def -(that: UInt): UInt = _impl_-(that) + override def /(that: UInt): UInt = _impl_/(that) + override def %(that: UInt): UInt = _impl_%(that) + override def *(that: UInt): UInt = _impl_*(that) + + /** Multiplication operator + * + * @param that a hardware [[SInt]] + * @return the product of this $coll and `that` + * $sumWidth + * $singleCycleMul + * @group Arithmetic + */ + def *(that: SInt): SInt = _impl_*(that) + + /** Addition operator (expanding width) + * + * @param that a hardware $coll + * @return the sum of this $coll and `that` + * $maxWidthPlusOne + * @group Arithmetic + */ + def +&(that: UInt): UInt = _impl_+&(that) + + /** Addition operator (constant width) + * + * @param that a hardware $coll + * @return the sum of this $coll and `that` + * $maxWidth + * @group Arithmetic + */ + def +%(that: UInt): UInt = _impl_+%(that) + + /** Subtraction operator (increasing width) + * + * @param that a hardware $coll + * @return the difference of this $coll less `that` + * $maxWidthPlusOne + * @group Arithmetic + */ + def -&(that: UInt): UInt = _impl_-&(that) + + /** Subtraction operator (constant width) + * + * @param that a hardware $coll + * @return the difference of this $coll less `that` + * $maxWidth + * @group Arithmetic + */ + def -%(that: UInt): UInt = _impl_-%(that) + + /** Bitwise and operator + * + * @param that a hardware $coll + * @return the bitwise and of this $coll and `that` + * $maxWidth + * @group Bitwise + */ + def &(that: UInt): UInt = _impl_&(that) + + /** Bitwise or operator + * + * @param that a hardware $coll + * @return the bitwise or of this $coll and `that` + * $maxWidth + * @group Bitwise + */ + def |(that: UInt): UInt = _impl_|(that) + + /** Bitwise exclusive or (xor) operator + * + * @param that a hardware $coll + * @return the bitwise xor of this $coll and `that` + * $maxWidth + * @group Bitwise + */ + def ^(that: UInt): UInt = _impl_^(that) + + def abs: UInt = _absImpl + + override def unary_~(using sourceInfo: SourceInfo): UInt = _impl_unary_~ + + // REVIEW TODO: Can these be defined on Bits? + /** Or reduction operator + * + * @return a hardware [[Bool]] resulting from every bit of this $coll or'd together + * @group Bitwise + */ + def orR: Bool = _orRImpl + + /** And reduction operator + * + * @return a hardware [[Bool]] resulting from every bit of this $coll and'd together + * @group Bitwise + */ + def andR: Bool = _andRImpl + + /** Exclusive or (xor) reduction operator + * + * @return a hardware [[Bool]] resulting from every bit of this $coll xor'd together + * @group Bitwise + */ + final def xorR(using sourceInfo: SourceInfo): Bool = _xorRImpl + + override def <(that: UInt): Bool = _impl_<(that) + override def >(that: UInt): Bool = _impl_>(that) + override def <=(that: UInt): Bool = _impl_<=(that) + override def >=(that: UInt): Bool = _impl_>=(that) + + /** Dynamic not equals operator + * + * @param that a hardware $coll + * @return a hardware [[Bool]] asserted if this $coll is not equal to `that` + * @group Comparison + */ + def =/=(that: UInt)(using sourceInfo: SourceInfo): Bool = _impl_=/=(that) + + /** Dynamic equals operator + * + * @param that a hardware $coll + * @return a hardware [[Bool]] asserted if this $coll is equal to `that` + * @group Comparison + */ + def ===(that: UInt)(using sourceInfo: SourceInfo): Bool = _impl_===(that) + + /** Unary not + * + * @return a hardware [[Bool]] asserted if this $coll equals zero + * @group Bitwise + */ + def unary_!(using sourceInfo: SourceInfo): Bool = _impl_unary_! + + override def <<(that: Int)(using sourceInfo: SourceInfo): UInt = _impl_<<(that) + override def <<(that: BigInt)(using sourceInfo: SourceInfo): UInt = _impl_<<(that) + override def <<(that: UInt)(using sourceInfo: SourceInfo): UInt = _impl_<<(that) + + override def >>(that: Int)(using sourceInfo: SourceInfo): UInt = _impl_>>(that) + override def >>(that: BigInt)(using sourceInfo: SourceInfo): UInt = _impl_>>(that) + override def >>(that: UInt)(using sourceInfo: SourceInfo): UInt = _impl_>>(that) + + /** + * Circular shift to the left + * @param that number of bits to rotate + * @return UInt of same width rotated left n bits + */ + def rotateLeft(n: Int)(using sourceInfo: SourceInfo): UInt = _rotateLeftImpl(n) + + def rotateLeft(n: UInt)(using sourceInfo: SourceInfo): UInt = _rotateLeftImpl(n) + + /** + * Circular shift to the right + * @param that number of bits to rotate + * @return UInt of same width rotated right n bits + */ + def rotateRight(n: Int)(using sourceInfo: SourceInfo): UInt = _rotateRightImpl(n) + + def rotateRight(n: UInt)(using sourceInfo: SourceInfo): UInt = _rotateRightImpl(n) + + /** Conditionally set or clear a bit + * + * @param off a dynamic offset + * @param dat set if true, clear if false + * @return a hrdware $coll with bit `off` set or cleared based on the value of `dat` + * $unchangedWidth + */ + def bitSet(off: UInt, dat: Bool)(using sourceInfo: SourceInfo): UInt = _bitSetImpl(off, dat) + + // TODO: this eventually will be renamed as toSInt, once the existing toSInt + // completes its deprecation phase. + /** Zero extend as [[SInt]] + * + * @return an [[SInt]] equal to this $coll with an additional zero in its most significant bit + * @note The width of the returned [[SInt]] is `width of this` + `1`. + */ + def zext(using sourceInfo: SourceInfo): SInt = _zextImpl + + override def asSInt(using sourceInfo: SourceInfo): SInt = _asSIntImpl +} + +object UInt extends UIntFactory + +sealed class SInt private[chisel3] (width: Width) extends Bits(width) with SIntImpl { + + /** Unary negation (constant width) + * + * @return a hardware $coll equal to zero minus this $coll + * $constantWidth + * @group Arithmetic + */ + final def unary_-(using sourceInfo: SourceInfo): SInt = _impl_unary_- + + /** Unary negation (constant width) + * + * @return a hardware $coll equal to zero minus `this` shifted right by one + * $constantWidth + * @group Arithmetic + */ + def unary_-%(using sourceInfo: SourceInfo): SInt = _impl_unary_-% + + /** add (default - no growth) operator */ + override def +(that: SInt): SInt = _impl_+(that) + + /** subtract (default - no growth) operator */ + override def -(that: SInt): SInt = _impl_-(that) + override def *(that: SInt): SInt = _impl_*(that) + override def /(that: SInt): SInt = _impl_/(that) + override def %(that: SInt): SInt = _impl_%(that) + + /** Multiplication operator + * + * @param that a hardware $coll + * @return the product of this $coll and `that` + * $sumWidth + * $singleCycleMul + * @group Arithmetic + */ + def *(that: UInt)(using sourceInfo: SourceInfo): SInt = _impl_*(that) + + /** Addition operator (expanding width) + * + * @param that a hardware $coll + * @return the sum of this $coll and `that` + * $maxWidthPlusOne + * @group Arithmetic + */ + def +&(that: SInt)(using sourceInfo: SourceInfo): SInt = _impl_+&(that) + + /** Addition operator (constant width) + * + * @param that a hardware $coll + * @return the sum of this $coll and `that` shifted right by one + * $maxWidth + * @group Arithmetic + */ + def +%(that: SInt)(using sourceInfo: SourceInfo): SInt = _impl_+%(that) + + /** Subtraction operator (increasing width) + * + * @param that a hardware $coll + * @return the difference of this $coll less `that` + * $maxWidthPlusOne + * @group Arithmetic + */ + def -&(that: SInt)(using sourceInfo: SourceInfo): SInt = _impl_-&(that) + + /** Subtraction operator (constant width) + * + * @param that a hardware $coll + * @return the difference of this $coll less `that` shifted right by one + * $maxWidth + * @group Arithmetic + */ + def -%(that: SInt)(using sourceInfo: SourceInfo): SInt = _impl_-%(that) + + /** Bitwise and operator + * + * @param that a hardware $coll + * @return the bitwise and of this $coll and `that` + * $maxWidth + * @group Bitwise + */ + def &(that: SInt)(using sourceInfo: SourceInfo): SInt = _impl_&(that) + + /** Bitwise or operator + * + * @param that a hardware $coll + * @return the bitwise or of this $coll and `that` + * $maxWidth + * @group Bitwise + */ + def |(that: SInt): SInt = _impl_|(that) + + /** Bitwise exclusive or (xor) operator + * + * @param that a hardware $coll + * @return the bitwise xor of this $coll and `that` + * $maxWidth + * @group Bitwise + */ + def ^(that: SInt)(using sourceInfo: SourceInfo): SInt = _impl_^(that) + + override def unary_~(using sourceInfo: SourceInfo): SInt = _impl_unary_~ + + override def <(that: SInt): Bool = _impl_<(that) + override def >(that: SInt): Bool = _impl_>(that) + override def <=(that: SInt): Bool = _impl_<=(that) + override def >=(that: SInt): Bool = _impl_>=(that) + + /** Dynamic not equals operator + * + * @param that a hardware $coll + * @return a hardware [[Bool]] asserted if this $coll is not equal to `that` + * @group Comparison + */ + def =/=(that: SInt): Bool = _impl_=/=(that) + + /** Dynamic equals operator + * + * @param that a hardware $coll + * @return a hardware [[Bool]] asserted if this $coll is equal to `that` + * @group Comparison + */ + def ===(that: SInt): Bool = _impl_===(that) + + def abs: SInt = _absImpl + + override def <<(that: Int)(using sourceInfo: SourceInfo): SInt = _impl_<<(that) + override def <<(that: BigInt)(using sourceInfo: SourceInfo): SInt = _impl_<<(that) + override def <<(that: UInt)(using sourceInfo: SourceInfo): SInt = _impl_<<(that) + + override def >>(that: Int)(using sourceInfo: SourceInfo): SInt = _impl_>>(that) + override def >>(that: BigInt)(using sourceInfo: SourceInfo): SInt = _impl_>>(that) + override def >>(that: UInt)(using sourceInfo: SourceInfo): SInt = _impl_>>(that) + + override def asSInt(using sourceInfo: SourceInfo): SInt = _asSIntImpl +} + +object SInt extends SIntFactory + +sealed trait Reset extends ResetImpl with ToBoolable { + def asAsyncReset(using sourceInfo: SourceInfo): AsyncReset + def asDisable(using sourceInfo: SourceInfo): Disable = _asDisableImpl +} + +object Reset { + def apply(): Reset = new ResetType +} + +/** "Abstract" Reset Type inferred in FIRRTL to either [[AsyncReset]] or [[Bool]] + * + * @note This shares a common interface with [[AsyncReset]] and [[Bool]] but is not their actual + * super type due to Bool inheriting from abstract class UInt + */ +final class ResetType(private[chisel3] val width: Width = Width(1)) extends Reset with ResetTypeImpl with ToBoolable { + def asAsyncReset(using sourceInfo: SourceInfo): AsyncReset = _asAsyncResetImpl + def asBool: Bool = _asBoolImpl + def toBool: Bool = asBool +} + +object AsyncReset { + def apply(): AsyncReset = new AsyncReset +} + +/** Data type representing asynchronous reset signals + * + * These signals are similar to [[Clock]]s in that they must be glitch-free for proper circuit + * operation. [[Reg]]s defined with the implicit reset being an [[AsyncReset]] will be + * asychronously reset registers. + */ +sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends AsyncResetImpl with Reset { + override def toString: String = stringAccessor("AsyncReset") + def asAsyncReset(using sourceInfo: SourceInfo): AsyncReset = _asAsyncResetImpl + def asBool: Bool = _asBoolImpl + def toBool: Bool = _asBoolImpl +} + +// REVIEW TODO: Why does this extend UInt and not Bits? Does defining airth +// operations on a Bool make sense? +/** A data type for booleans, defined as a single bit indicating true or false. + * + * @define coll [[Bool]] + * @define numType $coll + */ +sealed class Bool() extends UInt(1.W) with BoolImpl with Reset { + + // REVIEW TODO: Why does this need to exist and have different conventions + // than Bits? + + /** Bitwise and operator + * + * @param that a hardware $coll + * @return the bitwise and of this $coll and `that` + * @group Bitwise + */ + def &(that: Bool)(using sourceInfo: SourceInfo): Bool = _impl_&(that) + + /** Bitwise or operator + * + * @param that a hardware $coll + * @return the bitwise or of this $coll and `that` + * @group Bitwise + */ + def |(that: Bool): Bool = _impl_|(that) + + /** Bitwise exclusive or (xor) operator + * + * @param that a hardware $coll + * @return the bitwise xor of this $coll and `that` + * @group Bitwise + */ + def ^(that: Bool)(using sourceInfo: SourceInfo): Bool = _impl_^(that) + + override def unary_~(using sourceInfo: SourceInfo): Bool = _impl_unary_~ + + /** Logical or operator + * + * @param that a hardware $coll + * @return the logical or of this $coll and `that` + * @note this is equivalent to [[Bool!.|(that:chisel3\.Bool)* Bool.|)]] + * @group Logical + */ + def ||(that: Bool)(using sourceInfo: SourceInfo): Bool = _impl_||(that) + + /** Logical and operator + * + * @param that a hardware $coll + * @return the logical and of this $coll and `that` + * @note this is equivalent to [[Bool!.&(that:chisel3\.Bool)* Bool.&]] + * @group Logical + */ + def &&(that: Bool)(using sourceInfo: SourceInfo): Bool = _impl_&&(that) + + override def asBool: Bool = _asBoolImpl + + /** Reinterprets this $coll as a clock */ + def asClock(using sourceInfo: SourceInfo): Clock = _asClockImpl + + def asAsyncReset(using sourceInfo: SourceInfo): AsyncReset = _asAsyncResetImpl +} + +object Bool extends BoolFactory diff --git a/core/src/main/scala-3/chisel3/ChiselEnum.scala b/core/src/main/scala-3/chisel3/ChiselEnum.scala new file mode 100644 index 00000000000..5535de71de9 --- /dev/null +++ b/core/src/main/scala-3/chisel3/ChiselEnum.scala @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.SourceInfo + +abstract class EnumType(factory: ChiselEnum, selfAnnotating: Boolean = true) + extends EnumTypeImpl(factory, selfAnnotating) { + + final def ===(that: EnumType)(using sourceInfo: SourceInfo): Bool = _impl_===(that) + final def =/=(that: EnumType)(using sourceInfo: SourceInfo): Bool = _impl_=/=(that) + final def <(that: EnumType)(using sourceInfo: SourceInfo): Bool = _impl_<(that) + final def <=(that: EnumType)(using sourceInfo: SourceInfo): Bool = _impl_>(that) + final def >(that: EnumType)(using sourceInfo: SourceInfo): Bool = _impl_<=(that) + final def >=(that: EnumType)(using sourceInfo: SourceInfo): Bool = _impl_>=(that) +} + +abstract class ChiselEnum extends ChiselEnumImpl diff --git a/core/src/main/scala-3/chisel3/Clock.scala b/core/src/main/scala-3/chisel3/Clock.scala new file mode 100644 index 00000000000..a8aa42f446d --- /dev/null +++ b/core/src/main/scala-3/chisel3/Clock.scala @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.SourceInfo + +object Clock { + def apply(): Clock = new Clock +} + +// TODO: Document this. +sealed class Clock extends ClockImpl { + + /** Returns the contents of the clock wire as a [[Bool]]. */ + def asBool(using sourceInfo: SourceInfo): Bool = _asBoolImpl +} diff --git a/core/src/main/scala-3/chisel3/Data.scala b/core/src/main/scala-3/chisel3/Data.scala new file mode 100644 index 00000000000..268aad8316e --- /dev/null +++ b/core/src/main/scala-3/chisel3/Data.scala @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.SourceInfo + +/** This forms the root of the type system for wire data types. The data value + * must be representable as some number (need not be known at Chisel compile + * time) of bits, and must have methods to pack / unpack structured data to / + * from bits. + * + * @groupdesc Connect Utilities for connecting hardware components + * @define coll data + */ +abstract class Data extends DataImpl with SourceInfoDoc { + + /** Does a reinterpret cast of the bits in this node into the format that provides. + * Returns a new Wire of that type. Does not modify existing nodes. + * + * x.asTypeOf(that) performs the inverse operation of x := that.toBits. + * + * @note bit widths are NOT checked, may pad or drop bits from input + * @note that should have known widths + */ + def asTypeOf[T <: Data](that: T)(using sourceInfo: SourceInfo): T = _asTypeOfImpl(that) + + /** Reinterpret cast to 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 + * @note Aggregates are recursively packed with the first element appearing + * in the least-significant bits of the result. + */ + def asUInt: UInt = _asUIntImpl +} + +object Data extends ObjectDataImpl diff --git a/core/src/main/scala-3/chisel3/Disable.scala b/core/src/main/scala-3/chisel3/Disable.scala new file mode 100644 index 00000000000..8affd4068df --- /dev/null +++ b/core/src/main/scala-3/chisel3/Disable.scala @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.internal._ +import chisel3.experimental.SourceInfo + +/** API for handling disabling of simulation constructs + * + * Disables may be non-synthesizable so they can only be used for disabling simulation constructs + * + * The default disable is the "hasBeenReset" of the currently in scope reset. + * It can be set by the user via the [[withDisable]] API + * + * Users can access the current `Disable` with [[Module.disable]] + */ +// We could just an OpaqueType, but since OpaqueTypes have some API holes, this non-Data type +class Disable private[chisel3] (private[chisel3] val value: Bool) extends DisableImpl { + + /** Logical not + * + * @return invert the logical value of this `Disable` + * @group Bitwise + */ + def unary_!(using sourceInfo: SourceInfo): Disable = new Disable(!this.value) +} + +object Disable extends ObectDisableImpl diff --git a/core/src/main/scala-3/chisel3/Mem.scala b/core/src/main/scala-3/chisel3/Mem.scala new file mode 100644 index 00000000000..fb76fa19332 --- /dev/null +++ b/core/src/main/scala-3/chisel3/Mem.scala @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.SourceInfo + +object Mem extends ObjectMemImpl with SourceInfoDoc { + + /** Creates a combinational/asynchronous-read, sequential/synchronous-write [[Mem]]. + * + * @param size number of elements in the memory + * @param t data type of memory element + */ + def apply[T <: Data]( + size: BigInt, + t: T + )( + using sourceInfo: SourceInfo + ): Mem[T] = _applyImpl(size, t) + + /** Creates a combinational/asynchronous-read, sequential/synchronous-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)(using sourceInfo: SourceInfo): Mem[T] = _applyImpl(size, t) +} + +sealed abstract class MemBase[T <: Data](val t: T, val length: BigInt, protected val sourceInfo: SourceInfo) + extends MemBaseImpl[T] + with SourceInfoDoc { + + // REVIEW TODO: make accessors (static/dynamic, read/write) combinations consistent. + + /** Creates a read accessor into the memory with static addressing. See the + * class documentation of the memory for more detailed information. + */ + def apply(idx: BigInt)(using sourceInfo: SourceInfo): T = _applyImpl(idx) + + /** Creates a read accessor into the memory with static addressing. See the + * class documentation of the memory for more detailed information. + */ + def apply(idx: Int)(using sourceInfo: SourceInfo): T = _applyImpl(idx) + + /** 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)(using sourceInfo: SourceInfo): T = _applyImpl(idx) + + def apply(idx: UInt, clock: Clock)(using sourceInfo: SourceInfo): T = _applyImpl(idx, clock) + + /** 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)(using sourceInfo: SourceInfo): T = _readImpl(idx) + + /** Creates a read accessor into the memory with dynamic addressing. + * Takes a clock parameter to bind a clock that may be different + * from the implicit clock. See the class documentation of the memory + * for more detailed information. + */ + def read(idx: UInt, clock: Clock)(using sourceInfo: SourceInfo): T = _readImpl(idx, clock) + + /** Creates a write accessor into the memory. + * + * @param idx memory element index to write into + * @param data new data to write + */ + def write(idx: UInt, data: T)(using sourceInfo: SourceInfo): Unit = _writeImpl(idx, data) + + /** Creates a write accessor into the memory with a clock + * that may be different from the implicit clock. + * + * @param idx memory element index to write into + * @param data new data to write + * @param clock clock to bind to this accessor + */ + def write(idx: UInt, data: T, clock: Clock)(using sourceInfo: SourceInfo): Unit = _writeImpl(idx, data, clock) + + /** Creates a masked write accessor into the memory. + * + * @param idx memory element index to write into + * @param data new data to write + * @param mask write mask as a Seq of Bool: a write to the Vec element in + * memory is only performed if the corresponding mask index is true. + * + * @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[_], + sourceInfo: SourceInfo + ): Unit = _writeImpl(idx, data, mask) + + /** Creates a masked write accessor into the memory with a clock + * that may be different from the implicit clock. + * + * @param idx memory element index to write into + * @param data new data to write + * @param mask write mask as a Seq of Bool: a write to the Vec element in + * memory is only performed if the corresponding mask index is true. + * @param clock clock to bind to this accessor + * + * @note this is only allowed if the memory's element data type is a Vec + */ + def write( + idx: UInt, + data: T, + mask: Seq[Bool], + clock: Clock + )( + implicit evidence: T <:< Vec[_], + sourceInfo: SourceInfo + ): Unit = _writeImpl(idx, data, mask, clock) +} + +/** A combinational/asynchronous-read, sequential/synchronous-write memory. + * + * Writes take effect on the rising clock edge after the request. Reads are + * combinational (requests will return data on the same cycle). + * Read-after-write hazards are not an issue. + * + * @note when multiple conflicting writes are performed on a Mem element, the + * result is undefined (unlike Vec, where the last assignment wins) + */ +sealed class Mem[T <: Data] private[chisel3] (t: T, length: BigInt, sourceInfo: SourceInfo) + extends MemBase(t, length, sourceInfo) + with MemImpl[T] + +object SyncReadMem extends ObjectSyncReadMemImpl { + + /** Creates a sequential/synchronous-read, sequential/synchronous-write [[SyncReadMem]]. + * + * @param size number of elements in the memory + * @param t data type of memory element + */ + def apply[T <: Data]( + size: Int, + t: T + )( + using sourceInfo: SourceInfo + ): SyncReadMem[T] = _applyImpl(size, t) + + def apply[T <: Data]( + size: BigInt, + t: T, + ruw: ReadUnderWrite = Undefined + )( + using sourceInfo: SourceInfo + ): SyncReadMem[T] = _applyImpl(size, t, ruw) +} + +/** A sequential/synchronous-read, sequential/synchronous-write memory. + * + * Writes take effect on the rising clock edge after the request. Reads return + * data on the rising edge after the request. Read-after-write behavior (when + * a read and write to the same address are requested on the same cycle) is + * undefined. + * + * @note when multiple conflicting writes are performed on a Mem element, the + * result is undefined (unlike Vec, where the last assignment wins) + */ +sealed class SyncReadMem[T <: Data] private[chisel3] ( + t: T, + n: BigInt, + val readUnderWrite: SyncReadMem.ReadUnderWrite, + sourceInfo: SourceInfo) + extends MemBase[T](t, n, sourceInfo) + with SyncReadMemImpl[T] { + + override def read(idx: UInt)(using sourceInfo: SourceInfo): T = _readImpl(idx) + + def read(idx: UInt, en: Bool)(using sourceInfo: SourceInfo): T = _readImpl(idx, en) + + def read(idx: UInt, en: Bool, clock: Clock)(using sourceInfo: SourceInfo): T = _readImpl(idx, en, clock) + + /** Generates an explicit read-write port for this SyncReadMem. Note that this does not infer + * port directionality based on connection semantics and the `when` context unlike SyncReadMem.apply(), + * so the behavior of the port must be controlled by changing the values of the input parameters. + * + * @param idx memory element index to write into + * @param writeData new data to write + * @param enable enables access to the memory + * @param isWrite performs a write instead of a read when enable is true; the return + * value becomes undefined when this parameter is true + * + * @return The read data of the memory, which gives the value at idx when enable is true and isWrite is false, + * or an undefined value otherwise, on the following clock cycle. + * + * @example Controlling a read/write port with IO signals + * {{{ + * class MyMemWrapper extends Module { + * val width = 2 + * + * val io = IO(new Bundle { + * val address = Input(UInt()) + * val wdata = Input(UInt(width.W)) + * val enable = Input(Bool()) + * val isWrite = Input(Bool()) + * val rdata = Output(UInt(width.W)) + * }) + * + * val mem = SyncReadMem(2, UInt(width.W)) + * io.rdata := mem.readWrite(io.address, io.wdata, io.enable, io.isWrite) + * } + * + * }}} + */ + def readWrite(idx: UInt, writeData: T, en: Bool, isWrite: Bool)(using sourceInfo: SourceInfo): T = + _readWriteImpl(idx, writeData, en, isWrite) + + /** Generates an explicit read-write port for this SyncReadMem, using a clock that may be + * different from the implicit clock. + * + * @param idx memory element index to write into + * @param writeData new data to write + * @param enable enables access to the memory + * @param isWrite performs a write instead of a read when enable is true; the return + * value becomes undefined when this parameter is true + * @param clock clock to bind to this read-write port + * + * @return The read data of the memory, which gives the value at idx when enable is true and isWrite is false, + * or an undefined value otherwise, on the following clock cycle. + */ + def readWrite( + idx: UInt, + data: T, + en: Bool, + isWrite: Bool, + clock: Clock + )( + using sourceInfo: SourceInfo + ): T = _readWriteImpl(idx, data, en, isWrite, clock) + + /** Generates an explicit read-write port for this SyncReadMem, with a bytemask for + * performing partial writes to a Vec element. + * + * @param idx memory element index to write into + * @param writeData new data to write + * @param mask the write mask as a Seq of Bool: a write to the Vec element in + * memory is only performed if the corresponding mask index is true. + * @param enable enables access to the memory + * @param isWrite performs a write instead of a read when enable is true; the return + * value becomes undefined when this parameter is true + * + * @return The read data Vec of the memory at idx when enable is true and isWrite is false, + * or an undefined value otherwise, on the following clock cycle + * + * @example Controlling a read/masked write port with IO signals + * {{{ + * class MyMaskedMemWrapper extends Module { + * val width = 2 + * + * val io = IO(new Bundle { + * val address = Input(UInt()) + * val wdata = Input(Vec(2, UInt(width.W))) + * val mask = Input(Vec(2, Bool())) + * val enable = Input(Bool()) + * val isWrite = Input(Bool()) + * val rdata = Output(Vec(2, UInt(width.W))) + * }) + * + * val mem = SyncReadMem(2, Vec(2, UInt(width.W))) + * io.rdata := mem.readWrite(io.address, io.wdata, io.mask, io.enable, io.isWrite) + * } + * }}} + * + * @note this is only allowed if the memory's element data type is a Vec + */ + def readWrite( + idx: UInt, + writeData: T, + mask: Seq[Bool], + en: Bool, + isWrite: Bool + )( + implicit evidence: T <:< Vec[_], + sourceInfo: SourceInfo + ): T = _readWriteImpl(idx, writeData, mask, en, isWrite) + + /** Generates an explicit read-write port for this SyncReadMem, with a bytemask for + * performing partial writes to a Vec element and a clock that may be different from + * the implicit clock. + * + * @param idx memory element index to write into + * @param writeData new data to write + * @param mask the write mask as a Seq of Bool: a write to the Vec element in + * memory is only performed if the corresponding mask index is true. + * @param enable enables access to the memory + * @param isWrite performs a write instead of a read when enable is true; the return + * value becomes undefined when this parameter is true + * @param clock clock to bind to this read-write port + * + * @return The read data Vec of the memory at idx when enable is true and isWrite is false, + * or an undefined value otherwise, on the following clock cycle + * + * @note this is only allowed if the memory's element data type is a Vec + */ + def readWrite( + idx: UInt, + writeData: T, + mask: Seq[Bool], + en: Bool, + isWrite: Bool, + clock: Clock + )( + implicit evidence: T <:< Vec[_], + sourceInfo: SourceInfo + ): T = _readWriteImpl(idx, writeData, mask, en, isWrite, clock) +} diff --git a/core/src/main/scala-3/chisel3/Module.scala b/core/src/main/scala-3/chisel3/Module.scala new file mode 100644 index 00000000000..95559db5b21 --- /dev/null +++ b/core/src/main/scala-3/chisel3/Module.scala @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.{BaseModule, SourceInfo} + +object Module extends ObjectModuleImpl with SourceInfoDoc { + + /** A wrapper method that all Module instantiations must be wrapped in + * (necessary to help Chisel track internal state). + * + * @param bc the Module being created + * + * @return the input module `m` with Chisel metadata properly set + */ + // TODO(adkian-sifive) the callsite here explicitly passes + // sourceInfo so it cannot be a contextual parameter + def apply[T <: BaseModule](bc: => T): T = _applyImpl(bc) +} + +/** Abstract base class for Modules, which behave much like Verilog modules. + * These may contain both logic and state which are written in the Module + * body (constructor). + * This abstract base class includes an implicit clock and reset. + * + * @note Module instantiations must be wrapped in a Module() call. + */ +abstract class Module extends ModuleImpl diff --git a/core/src/main/scala-3/chisel3/Mux.scala b/core/src/main/scala-3/chisel3/Mux.scala new file mode 100644 index 00000000000..b61e4e3a712 --- /dev/null +++ b/core/src/main/scala-3/chisel3/Mux.scala @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.SourceInfo + +object Mux extends MuxImpl with SourceInfoDoc { + + /** 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 + )( + using sourceInfo: SourceInfo + ): T = _applyImpl(cond, con, alt) +} diff --git a/core/src/main/scala-3/chisel3/Num.scala b/core/src/main/scala-3/chisel3/Num.scala new file mode 100644 index 00000000000..b63e1d34762 --- /dev/null +++ b/core/src/main/scala-3/chisel3/Num.scala @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +// REVIEW TODO: Further discussion needed on what Num actually is. + +/** Abstract trait defining operations available on numeric-like hardware data types. + * + * @tparam T the underlying type of the number + * @groupdesc Arithmetic Arithmetic hardware operators + * @groupdesc Comparison Comparison hardware operators + * @groupdesc Logical Logical hardware operators + * @define coll numeric-like type + * @define numType hardware type + * @define canHaveHighCost can result in significant cycle time and area costs + * @define canGenerateA This method generates a + * @define singleCycleMul @note $canGenerateA fully combinational multiplier which $canHaveHighCost. + * @define singleCycleDiv @note $canGenerateA fully combinational divider which $canHaveHighCost. + * @define maxWidth @note The width of the returned $numType is `max(width of this, width of that)`. + * @define maxWidthPlusOne @note The width of the returned $numType is `max(width of this, width of that) + 1`. + * @define sumWidth @note The width of the returned $numType is `width of this` + `width of that`. + * @define unchangedWidth @note The width of the returned $numType is unchanged, i.e., the `width of this`. + */ +trait Num[T <: Data] { + self: Num[T] => + // def << (b: T): T + // def >> (b: T): T + //def unary_-(): T + + // REVIEW TODO: double check ops conventions against FIRRTL + + /** Addition operator + * + * @param that a $numType + * @return the sum of this $coll and `that` + * $maxWidth + * @group Arithmetic + */ + def +(that: T): T + + /** Multiplication operator + * + * @param that a $numType + * @return the product of this $coll and `that` + * $sumWidth + * $singleCycleMul + * @group Arithmetic + */ + def *(that: T): T + + /** Division operator + * + * @param that a $numType + * @return the quotient of this $coll divided by `that` + * $singleCycleDiv + * @todo full rules + * @group Arithmetic + */ + def /(that: T): T + + /** Modulo operator + * + * @param that a $numType + * @return the remainder of this $coll divided by `that` + * $singleCycleDiv + * @group Arithmetic + */ + def %(that: T): T + + /** Subtraction operator + * + * @param that a $numType + * @return the difference of this $coll less `that` + * $maxWidthPlusOne + * @group Arithmetic + */ + def -(that: T): T + + /** Less than operator + * + * @param that a $numType + * @return a hardware [[Bool]] asserted if this $coll is less than `that` + * @group Comparison + */ + def <(that: T): Bool + + /** Less than or equal to operator + * + * @param that a $numType + * @return a hardware [[Bool]] asserted if this $coll is less than or equal to `that` + * @group Comparison + */ + def <=(that: T): Bool + + /** Greater than operator + * + * @param that a hardware component + * @return a hardware [[Bool]] asserted if this $coll is greater than `that` + * @group Comparison + */ + def >(that: T): Bool + + /** Greater than or equal to operator + * + * @param that a hardware component + * @return a hardware [[Bool]] asserted if this $coll is greather than or equal to `that` + * @group Comparison + */ + def >=(that: T): Bool + + /** Absolute value operator + * + * @return a $numType with a value equal to the absolute value of this $coll + * $unchangedWidth + * @group Arithmetic + */ + @deprecated( + "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", + "Chisel 3.5" + ) + def abs: T + + /** Minimum operator + * + * @param that a hardware $coll + * @return a $numType with a value equal to the minimum value of this $coll and `that` + * $maxWidth + * @group Arithmetic + */ + def min(that: T): T = + Mux(this < that, this.asInstanceOf[T], that) + + /** Maximum operator + * + * @param that a $numType + * @return a $numType with a value equal to the minimum value of this $coll and `that` + * $maxWidth + * @group Arithmetic + */ + def max(that: T): T = + Mux(this < that, that, this.asInstanceOf[T]) +} + +object Num extends NumObject diff --git a/core/src/main/scala-3/chisel3/Printf.scala b/core/src/main/scala-3/chisel3/Printf.scala new file mode 100644 index 00000000000..fd765ef356a --- /dev/null +++ b/core/src/main/scala-3/chisel3/Printf.scala @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.experimental.SourceInfo +import chisel3.PrintfMacrosCompat._ + +import scala.language.experimental.macros + +/** Prints a message in simulation + * + * See apply methods for use + */ +object printf extends PrintfImpl { + + /** Named class for [[printf]]s. */ + final class Printf private[chisel3] (val pable: Printable) extends VerificationStatement + + /** Prints a message in simulation + * + * Prints a message every cycle. If defined within the scope of a [[when]] block, the message + * will only be printed on cycles that the when condition is true. + * + * 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), uses the current default clock + * and reset. These can be overriden with [[withClockAndReset]]. + * + * @see [[Printable]] documentation + * @param pable [[Printable]] to print + */ + def apply(pable: Printable)(using sourceInfo: SourceInfo): chisel3.printf.Printf = + PrintfMacrosCompat.printfWithReset(pable)(using sourceInfo) +} diff --git a/core/src/main/scala-3/chisel3/PrintfMacros.scala b/core/src/main/scala-3/chisel3/PrintfMacros.scala new file mode 100644 index 00000000000..08ac54d3cdc --- /dev/null +++ b/core/src/main/scala-3/chisel3/PrintfMacros.scala @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.experimental.SourceInfo + +object PrintfMacrosCompat { + private[chisel3] def printfWithReset( + pable: Printable + )( + using sourceInfo: SourceInfo + ): chisel3.printf.Printf = { + var printfId: chisel3.printf.Printf = null + when(!Module.reset.asBool) { + printfId = printfWithoutReset(pable) + } + printfId + } + + private[chisel3] def printfWithoutReset( + pable: Printable + )( + using sourceInfo: SourceInfo + ): chisel3.printf.Printf = { + val clock = Builder.forcedClock + val printfId = new chisel3.printf.Printf(pable) + + Printable.checkScope(pable) + + pushCommand(chisel3.internal.firrtl.ir.Printf(printfId, sourceInfo, clock.ref, pable)) + printfId + } +} diff --git a/core/src/main/scala-3/chisel3/SourceInfoDoc.scala b/core/src/main/scala-3/chisel3/SourceInfoDoc.scala new file mode 100644 index 00000000000..4de4c26eb91 --- /dev/null +++ b/core/src/main/scala-3/chisel3/SourceInfoDoc.scala @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +/** Does nothing */ +trait SourceInfoDoc diff --git a/core/src/main/scala-3/chisel3/VerificationStatement.scala b/core/src/main/scala-3/chisel3/VerificationStatement.scala new file mode 100644 index 00000000000..b4b3c691f49 --- /dev/null +++ b/core/src/main/scala-3/chisel3/VerificationStatement.scala @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import chisel3.experimental.{BaseModule, SourceInfo} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl.ir._ +import chisel3.layer.block + +import scala.language.experimental.macros + +/** Scaladoc information for internal verification statement macros + * that are used in objects assert, assume and cover. + * + * @groupdesc VerifPrintMacros + * + *
+ * '''These internal methods are not part of the public-facing API!''' + *
+ *