diff options
Diffstat (limited to 'chiselFrontend')
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Data.scala | 127 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 117 |
2 files changed, 214 insertions, 30 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index f292d3c6..e56412e6 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -429,9 +429,9 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { */ def litValue(): BigInt = litOption.get - /** Returns the width, in bits, if currently known. - * @throws java.util.NoSuchElementException if the width is not known. */ - final def getWidth: Int = width.get + /** Returns the width, in bits, if currently known. */ + final def getWidth: Int = + if (isWidthKnown) width.get else throwException(s"Width of $this is unknown!") /** Returns whether the width is currently known. */ final def isWidthKnown: Boolean = width.known /** Returns Some(width) if the width is known, else None. */ @@ -484,6 +484,10 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { } trait WireFactory { + /** @usecase def apply[T <: Data](t: T): T + * Construct a [[Wire]] from a type template + * @param t The template from which to construct this wire + */ def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { if (compileOptions.declaredTypeMustBeUnbound) { requireIsChiselType(t, "wire type") @@ -502,17 +506,88 @@ trait WireFactory { } } +/** Utility for constructing hardware wires + * + * The width of a `Wire` (inferred or not) is copied from the type template + * {{{ + * val w0 = Wire(UInt()) // width is inferred + * val w1 = Wire(UInt(8.W)) // width is set to 8 + * + * val w2 = Wire(Vec(4, UInt())) // width is inferred + * val w3 = Wire(Vec(4, UInt(8.W))) // width of each element is set to 8 + * + * class MyBundle { + * val unknown = UInt() + * val known = UInt(8.W) + * } + * val w4 = Wire(new MyBundle) + * // Width of w4.unknown is inferred + * // Width of w4.known is set to 8 + * }}} + * + */ object Wire extends WireFactory +/** Utility for constructing hardware wires with a default connection + * + * The two forms of `WireInit` differ in how the type and width of the resulting [[Wire]] are + * specified. + * + * ==Single Argument== + * The single argument form uses the argument to specify both the type and default connection. For + * non-literal [[Bits]], the width of the [[Wire]] will be inferred. For literal [[Bits]] and all + * non-Bits arguments, the type will be copied from the argument. See the following examples for + * more details: + * + * 1. Literal [[Bits]] initializer: width will be set to match + * {{{ + * val w1 = WireInit(1.U) // width will be inferred to be 1 + * val w2 = WireInit(1.U(8.W)) // width is set to 8 + * }}} + * + * 2. Non-Literal [[Element]] initializer - width will be inferred + * {{{ + * val x = Wire(UInt()) + * val y = Wire(UInt(8.W)) + * val w1 = WireInit(x) // width will be inferred + * val w2 = WireInit(y) // width will be inferred + * }}} + * + * 3. [[Aggregate]] initializer - width will be set to match the aggregate + * + * {{{ + * class MyBundle { + * val unknown = UInt() + * val known = UInt(8.W) + * } + * val w1 = Wire(new MyBundle) + * val w2 = WireInit(w1) + * // Width of w2.unknown is inferred + * // Width of w2.known is set to 8 + * }}} + * + * ==Double Argument== + * The double argument form allows the type of the [[Wire]] and the default connection to be + * specified independently. + * + * The width inference semantics for `WireInit` with two arguments match those of [[Wire]]. The + * first argument to `WireInit` is the type template which defines the width of the `Wire` in + * exactly the same way as the only argument to [[Wire]]. + * + * More explicitly, you can reason about `WireInit` with multiple arguments as if it were defined + * as: + * {{{ + * def WireInit[T <: Data](t: T, init: T): T = { + * val x = Wire(t) + * x := init + * x + * } + * }}} + * + * @note The `Init` in `WireInit` refers to a `default` connection. This is in contrast to + * [[RegInit]] where the `Init` refers to a value on reset. + */ object WireInit { - def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { - val model = (init match { - // For e.g. Wire(init=0.U(k.W)), fix the Reg's width to k - case init: Bits if init.litIsForcedWidth == Some(false) => init.cloneTypeWidth(Width()) - case _ => init.cloneTypeFull - }).asInstanceOf[T] - apply(model, init) - } private def applyImpl[T <: Data](t: T, init: Data)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { implicit val noSourceInfo = UnlocatableSourceInfo @@ -522,12 +597,38 @@ object WireInit { x } - def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + /** @usecase def apply[T <: Data](t: T, init: DontCare.type): T + * Construct a [[Wire]] with a type template and a [[DontCare]] default + * @param t The type template used to construct this [[Wire]] + * @param init The default connection to this [[Wire]], can only be [[DontCare]] + * @note This is really just a specialized form of `apply[T <: Data](t: T, init: T): T` with [[DontCare]] + * as `init` + */ + def apply[T <: Data](t: T, init: DontCare.type)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { applyImpl(t, init) } - def apply[T <: Data](t: T, init: DontCare.type)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + + /** @usecase def apply[T <: Data](t: T, init: T): T + * Construct a [[Wire]] with a type template and a default connection + * @param t The type template used to construct this [[Wire]] + * @param init The hardware value that will serve as the default value + */ + def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { applyImpl(t, init) } + + /** @usecase def apply[T <: Data](init: T): T + * Construct a [[Wire]] with a default connection + * @param init The hardware value that will serve as a type template and default value + */ + def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + val model = (init match { + // If init is a literal without forced width OR any non-literal, let width be inferred + case init: Bits if !init.litIsForcedWidth.getOrElse(false) => init.cloneTypeWidth(Width()) + case _ => init.cloneTypeFull + }).asInstanceOf[T] + apply(model, init) + } } /** RHS (source) for Invalidate API. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 11611c82..27156f8b 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -9,11 +9,31 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo} +/** Utility for constructing hardware registers + * + * The width of a `Reg` (inferred or not) is copied from the type template + * {{{ + * val r0 = Reg(UInt()) // width is inferred + * val r1 = Reg(UInt(8.W)) // width is set to 8 + * + * val r2 = Reg(Vec(4, UInt())) // width is inferred + * val r3 = Reg(Vec(4, UInt(8.W))) // width of each element is set to 8 + * + * class MyBundle { + * val unknown = UInt() + * val known = UInt(8.W) + * } + * val r4 = Reg(new MyBundle) + * // Width of r4.unknown is inferred + * // Width of r4.known is set to 8 + * }}} + * + */ object Reg { - /** Creates a register without initialization (reset is ignored). Value does - * not change unless assigned to (using the := operator). - * - * @param t: data type for the register + /** @usecase def apply[T <: Data](t: T): T + * Construct a [[Reg]] from a type template with no initialization value (reset is ignored). + * Value will not change unless the [[Reg]] is given a connection. + * @param t The template from which to construct this wire */ def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { if (compileOptions.declaredTypeMustBeUnbound) { @@ -64,20 +84,69 @@ object RegNext { } } +/** Utility for constructing hardware registers with an initialization value. + * + * The register is set to the initialization value when the current implicit `reset` is high + * + * The two forms of `RegInit` differ in how the type and width of the resulting [[Reg]] are + * specified. + * + * ==Single Argument== + * The single argument form uses the argument to specify both the type and reset value. For + * non-literal [[Bits]], the width of the [[Reg]] will be inferred. For literal [[Bits]] and all + * non-Bits arguments, the type will be copied from the argument. See the following examples for + * more details: + * + * 1. Literal [[Bits]] initializer: width will be set to match + * {{{ + * val r1 = RegInit(1.U) // width will be inferred to be 1 + * val r2 = RegInit(1.U(8.W)) // width is set to 8 + * }}} + * + * 2. Non-Literal [[Element]] initializer - width will be inferred + * {{{ + * val x = Wire(UInt()) + * val y = Wire(UInt(8.W)) + * val r1 = RegInit(x) // width will be inferred + * val r2 = RegInit(y) // width will be inferred + * }}} + * + * 3. [[Aggregate]] initializer - width will be set to match the aggregate + * + * {{{ + * class MyBundle { + * val unknown = UInt() + * val known = UInt(8.W) + * } + * val w1 = Reg(new MyBundle) + * val w2 = RegInit(w1) + * // Width of w2.unknown is inferred + * // Width of w2.known is set to 8 + * }}} + * + * ==Double Argument== + * The double argument form allows the type of the [[Reg]] and the default connection to be + * specified independently. + * + * The width inference semantics for `RegInit` with two arguments match those of [[Reg]]. The + * first argument to `RegInit` is the type template which defines the width of the `Reg` in + * exactly the same way as the only argument to [[Wire]]. + * + * More explicitly, you can reason about `RegInit` with multiple arguments as if it were defined + * as: + * {{{ + * def RegInit[T <: Data](t: T, init: T): T = { + * val x = Reg(t) + * x := init + * x + * } + * }}} + */ object RegInit { - /** Returns a register pre-initialized (on reset) to the specified value. - * Register type is inferred from the initializer. - */ - def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { - val model = (init match { - // For e.g. Reg(init=UInt(0, k)), fix the Reg's width to k - case init: Bits if init.litIsForcedWidth == Some(false) => init.cloneTypeWidth(Width()) - case init => init.cloneTypeFull - }).asInstanceOf[T] - RegInit(model, init) - } - - /** Creates a register given an explicit type and an initialization (reset) value. + /** @usecase def apply[T <: Data](t: T, init: T): T + * Construct a [[Reg]] from a type template initialized to the specified value on reset + * @param t The type template used to construct this [[Reg]] + * @param init The value the [[Reg]] is initialized to on reset */ def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { if (compileOptions.declaredTypeMustBeUnbound) { @@ -92,4 +161,18 @@ object RegInit { pushCommand(DefRegInit(sourceInfo, reg, clock, reset, init.ref)) reg } + + /** @usecase def apply[T <: Data](init: T): T + * Construct a [[Reg]] initialized on reset to the specified value. + * @param init Initial value that serves as a type template and reset value + */ + def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + val model = (init match { + // If init is a literal without forced width OR any non-literal, let width be inferred + case init: Bits if !init.litIsForcedWidth.getOrElse(false) => init.cloneTypeWidth(Width()) + case init => init.cloneTypeFull + }).asInstanceOf[T] + RegInit(model, init) + } + } |
