summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/scala/chisel3/Bits.scala13
-rw-r--r--core/src/main/scala/chisel3/Mem.scala9
-rw-r--r--core/src/main/scala/chisel3/Module.scala40
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/package.scala10
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala70
-rw-r--r--core/src/main/scala/chisel3/internal/BiConnect.scala130
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala1
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala206
-rw-r--r--docs/src/cookbooks/cookbook.md141
-rw-r--r--docs/src/cookbooks/cookbooks.md1
-rw-r--r--docs/src/cookbooks/verilog-vs-chisel.md833
-rw-r--r--docs/src/explanations/connection-operators.md2
-rw-r--r--docs/src/images/connection-operators-experiment.svg1
-rw-r--r--integration-tests/src/test/scala/chiselTests/util/experimental/algorithm/Bitwise.scala47
-rw-r--r--src/main/scala/chisel3/experimental/util/algorithm/Bitwise.scala48
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/TruthTable.scala9
-rw-r--r--src/main/scala/chisel3/verilog.scala22
-rw-r--r--src/test/scala/chiselTests/BulkConnectSpec.scala106
-rw-r--r--src/test/scala/chiselTests/BundleSpec.scala1
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala2
-rw-r--r--src/test/scala/chiselTests/MixedVecSpec.scala16
-rw-r--r--src/test/scala/chiselTests/Module.scala9
-rw-r--r--src/test/scala/chiselTests/RecordSpec.scala19
-rw-r--r--src/test/scala/chiselTests/UIntOps.scala18
-rw-r--r--src/test/scala/chiselTests/VecLiteralSpec.scala5
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala8
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala10
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala33
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Examples.scala19
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala91
-rw-r--r--src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala24
31 files changed, 1869 insertions, 75 deletions
diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala
index 8a616d02..4133592f 100644
--- a/core/src/main/scala/chisel3/Bits.scala
+++ b/core/src/main/scala/chisel3/Bits.scala
@@ -107,6 +107,12 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
(((value >> castToInt(x, "Index")) & 1) == 1).asBool
}.getOrElse {
requireIsHardware(this, "bits to be indexed")
+
+ widthOption match {
+ case Some(w) if x >= w => Builder.error(s"High index $x is out of range [0, ${w - 1}]")
+ case _ =>
+ }
+
pushOp(DefPrim(sourceInfo, Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x)))
}
}
@@ -160,6 +166,13 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
((value >> y) & ((BigInt(1) << w) - 1)).asUInt(w.W)
}.getOrElse {
requireIsHardware(this, "bits to be sliced")
+
+ widthOption match {
+ case Some(w) if y >= w => Builder.error(s"High and low indices $x and $y are both out of range [0, ${w - 1}]")
+ case Some(w) if x >= w => Builder.error(s"High index $x is out of range [0, ${w - 1}]")
+ case _ =>
+ }
+
pushOp(DefPrim(sourceInfo, UInt(Width(w)), BitsExtractOp, this.ref, ILit(x), ILit(y)))
}
}
diff --git a/core/src/main/scala/chisel3/Mem.scala b/core/src/main/scala/chisel3/Mem.scala
index 3f37308c..36984a3a 100644
--- a/core/src/main/scala/chisel3/Mem.scala
+++ b/core/src/main/scala/chisel3/Mem.scala
@@ -246,6 +246,11 @@ sealed abstract class MemBase[T <: Data](val t: T, val length: BigInt)
)(
implicit compileOptions: CompileOptions
): T = {
+ if (Builder.currentModule != _parent) {
+ throwException(
+ s"Cannot create a memory port in a different module (${Builder.currentModule.get.name}) than where the memory is (${_parent.get.name})."
+ )
+ }
requireIsHardware(idx, "memory port index")
val i = Vec.truncateIndex(idx, length)(sourceInfo, compileOptions)
@@ -267,7 +272,7 @@ sealed abstract class MemBase[T <: Data](val t: T, val length: BigInt)
* @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 (t: T, length: BigInt) extends MemBase(t, length)
+sealed class Mem[T <: Data] private[chisel3] (t: T, length: BigInt) extends MemBase(t, length)
object SyncReadMem {
@@ -345,7 +350,7 @@ object SyncReadMem {
* @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 (t: T, n: BigInt, val readUnderWrite: SyncReadMem.ReadUnderWrite)
+sealed class SyncReadMem[T <: Data] private[chisel3] (t: T, n: BigInt, val readUnderWrite: SyncReadMem.ReadUnderWrite)
extends MemBase[T](t, n) {
override def read(x: UInt): T = macro SourceInfoTransform.xArg
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 3611f5dd..84139630 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -101,8 +101,8 @@ object Module extends SourceInfoDoc {
compileOptions: CompileOptions
): T = {
val parent = Builder.currentModule
-
val module: T = bc // bc is actually evaluated here
+ if (!parent.isEmpty) { Builder.currentModule = parent }
module
}
@@ -229,6 +229,8 @@ package internal {
// Private internal class to serve as a _parent for Data in cloned ports
private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T) extends PseudoModule with IsClone[T] {
override def toString = s"ModuleClone(${getProto})"
+ // Do not call default addId function, which may modify a module that is already "closed"
+ override def addId(d: HasId): Unit = ()
def getPorts = _portsRecord
// ClonePorts that hold the bound ports for this module
// Used for setting the refs of both this module and the Record
@@ -246,8 +248,14 @@ package internal {
}
// Maps proto ports to module clone's ports
private[chisel3] lazy val ioMap: Map[Data, Data] = {
- val name2Port = getPorts.elements
- getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
+ getProto match {
+ // BlackBox needs special handling for its pseduo-io Bundle
+ case protoBB: BlackBox =>
+ Map(protoBB._io.get -> getPorts.elements("io"))
+ case _ =>
+ val name2Port = getPorts.elements
+ getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
+ }
}
// This module doesn't actually exist in the FIRRTL so no initialization to do
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
@@ -265,7 +273,17 @@ package internal {
case bad => throwException(s"Internal Error! Cloned-module Record $record has unexpected ref $bad")
}
// Set both the record and the module to have the same instance name
- record.setRef(ModuleCloneIO(getProto, instName), force = true) // force because we did .forceName first
+ val ref = ModuleCloneIO(getProto, instName)
+ record.setRef(ref, force = true) // force because we did .forceName first
+ getProto match {
+ // BlackBox needs special handling for its pseduo-io Bundle
+ case _: BlackBox =>
+ // Override the io Bundle's ref so that it thinks it is the top for purposes of
+ // generating FIRRTL
+ record.elements("io").setRef(ref, force = true)
+ case _ => // Do nothing
+ }
+
this.setRef(Ref(instName))
}
}
@@ -307,6 +325,8 @@ package internal {
override def toString = s"DefinitionClone(${getProto})"
// No addition components are generated
private[chisel3] def generateComponent(): Option[Component] = None
+ // Do not call default addId function, which may modify a module that is already "closed"
+ override def addId(d: HasId): Unit = ()
// Necessary for toTarget to work
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
// Module name is the same as proto's module name
@@ -325,8 +345,8 @@ package internal {
* @note These are not true Data (the Record doesn't correspond to anything in the emitted
* FIRRTL yet its elements *do*) so have some very specialized behavior.
*/
- private[chisel3] class ClonePorts(elts: Data*)(implicit compileOptions: CompileOptions) extends Record {
- val elements = ListMap(elts.map(d => d.instanceName -> d.cloneTypeFull): _*)
+ private[chisel3] class ClonePorts(elts: (String, Data)*)(implicit compileOptions: CompileOptions) extends Record {
+ val elements = ListMap(elts.map { case (name, d) => name -> d.cloneTypeFull }: _*)
def apply(field: String) = elements(field)
override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type]
}
@@ -347,12 +367,18 @@ package internal {
// Fake Module to serve as the _parent of the cloned ports
// We don't create this inside the ModuleClone because we need the ref to be set by the
// currentModule (and not clonePorts)
- val clonePorts = new ClonePorts(proto.getModulePorts: _*)
+ val clonePorts = proto match {
+ // BlackBox needs special handling for its pseduo-io Bundle
+ case b: BlackBox =>
+ new ClonePorts(proto.getChiselPorts :+ ("io" -> b._io.get): _*)
+ case _ => new ClonePorts(proto.getChiselPorts: _*)
+ }
clonePorts.bind(PortBinding(cloneParent))
clonePorts.setAllParents(Some(cloneParent))
cloneParent._portsRecord = clonePorts
// Normally handled during Module construction but ClonePorts really lives in its parent's parent
if (!compileOptions.explicitInvalidate) {
+ // FIXME This almost certainly doesn't work since clonePorts is not a real thing...
pushCommand(DefInvalid(sourceInfo, clonePorts.ref))
}
if (proto.isInstanceOf[Module]) {
diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala
index 3278d82c..891ecb81 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/package.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/package.scala
@@ -262,4 +262,14 @@ package object dataview {
}
}
+ /** Determine the target of a View if it is a single Target
+ *
+ * @note An Aggregate may be a view of unrelated [[Data]] (eg. like a Seq or tuple) and thus this
+ * there is no single Data representing the Target and this function will return None
+ * @return The single Data target of this view or None if a single Data doesn't exist
+ */
+ private[chisel3] def reifyToAggregate(data: Data): Option[Aggregate] = reifySingleData(data) match {
+ case Some(a: Aggregate) => Some(a)
+ case other => None
+ }
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
index 8552267a..60290f83 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
@@ -10,7 +10,7 @@ import scala.annotation.implicitNotFound
import scala.collection.mutable.HashMap
import chisel3._
import chisel3.experimental.dataview.{isView, reify, reifySingleData}
-import chisel3.internal.firrtl.{Arg, ILit, Index, Slot, ULit}
+import chisel3.internal.firrtl.{Arg, ILit, Index, ModuleIO, Slot, ULit}
import chisel3.internal.{throwException, AggregateViewBinding, Builder, ChildBinding, ViewBinding, ViewParent}
/** Represents lookup typeclass to determine how a value accessed from an original IsInstantiable
@@ -19,7 +19,7 @@ import chisel3.internal.{throwException, AggregateViewBinding, Builder, ChildBin
*/
@implicitNotFound(
"@public is only legal within a class or trait marked @instantiable, and only on vals of type" +
- " Data, BaseModule, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable, Option, or Either"
+ " Data, BaseModule, MemBase, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable, Option, Either, or Tuple2"
)
trait Lookupable[-B] {
type C // Return type of the lookup
@@ -123,8 +123,8 @@ object Lookupable {
def unrollCoordinates(res: List[Arg], d: Data): (List[Arg], Data) = d.binding.get match {
case ChildBinding(parent) =>
d.getRef match {
- case arg @ (_: Slot | _: Index) => unrollCoordinates(arg :: res, parent)
- case other => err(s"Unroll coordinates failed for '$arg'! Unexpected arg '$other'")
+ case arg @ (_: Slot | _: Index | _: ModuleIO) => unrollCoordinates(arg :: res, parent)
+ case other => err(s"unrollCoordinates failed for '$arg'! Unexpected arg '$other'")
}
case _ => (res, d)
}
@@ -135,6 +135,7 @@ object Lookupable {
val next = (coor.head, d) match {
case (Slot(_, name), rec: Record) => rec.elements(name)
case (Index(_, ILit(n)), vec: Vec[_]) => vec.apply(n.toInt)
+ case (ModuleIO(_, name), rec: Record) => rec.elements(name)
case (arg, _) => err(s"Unexpected Arg '$arg' applied to '$d'! Root was '$start'.")
}
applyCoordinates(coor.tail, next)
@@ -348,6 +349,45 @@ object Lookupable {
}
}
+ private[chisel3] def cloneMemToContext[T <: MemBase[_]](
+ mem: T,
+ context: BaseModule
+ )(
+ implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions
+ ): T = {
+ mem._parent match {
+ case None => mem
+ case Some(parent) =>
+ val newParent = cloneModuleToContext(Proto(parent), context)
+ newParent match {
+ case Proto(p) if p == parent => mem
+ case Clone(mod: BaseModule) =>
+ val existingMod = Builder.currentModule
+ Builder.currentModule = Some(mod)
+ val newChild: T = mem match {
+ case m: Mem[_] => new Mem(m.t.asInstanceOf[Data].cloneTypeFull, m.length).asInstanceOf[T]
+ case m: SyncReadMem[_] =>
+ new SyncReadMem(m.t.asInstanceOf[Data].cloneTypeFull, m.length, m.readUnderWrite).asInstanceOf[T]
+ }
+ Builder.currentModule = existingMod
+ newChild.setRef(mem.getRef, true)
+ newChild
+ }
+ }
+ }
+
+ implicit def lookupMem[B <: MemBase[_]](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) =
+ new Lookupable[B] {
+ type C = B
+ def definitionLookup[A](that: A => B, definition: Definition[A]): C = {
+ cloneMemToContext(that(definition.proto), definition.getInnerDataContext.get)
+ }
+ def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
+ cloneMemToContext(that(instance.proto), instance.getInnerDataContext.get)
+ }
+ }
+
import scala.language.higherKinds // Required to avoid warning for lookupIterable type parameter
implicit def lookupIterable[B, F[_] <: Iterable[_]](
implicit sourceInfo: SourceInfo,
@@ -402,6 +442,28 @@ object Lookupable {
}
}
}
+
+ implicit def lookupTuple2[X, Y](
+ implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions,
+ lookupableX: Lookupable[X],
+ lookupableY: Lookupable[Y]
+ ) = new Lookupable[(X, Y)] {
+ type C = (lookupableX.C, lookupableY.C)
+ def definitionLookup[A](that: A => (X, Y), definition: Definition[A]): C = {
+ val ret = that(definition.proto)
+ (
+ lookupableX.definitionLookup[A](_ => ret._1, definition),
+ lookupableY.definitionLookup[A](_ => ret._2, definition)
+ )
+ }
+ def instanceLookup[A](that: A => (X, Y), instance: Instance[A]): C = {
+ import instance._
+ val ret = that(proto)
+ (lookupableX.instanceLookup[A](_ => ret._1, instance), lookupableY.instanceLookup[A](_ => ret._2, instance))
+ }
+ }
+
implicit def lookupIsInstantiable[B <: IsInstantiable](
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions
diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala
index 5b4ad1b9..a8b425f5 100644
--- a/core/src/main/scala/chisel3/internal/BiConnect.scala
+++ b/core/src/main/scala/chisel3/internal/BiConnect.scala
@@ -3,15 +3,14 @@
package chisel3.internal
import chisel3._
-import chisel3.experimental.dataview.reify
+import chisel3.experimental.dataview.{isView, reify, reifyToAggregate}
import chisel3.experimental.{attach, Analog, BaseModule}
import chisel3.internal.Builder.pushCommand
-import chisel3.internal.firrtl.{Connect, DefInvalid}
+import chisel3.internal.firrtl.{Connect, Converter, DefInvalid}
import scala.language.experimental.macros
import chisel3.internal.sourceinfo._
-
-import scala.annotation.tailrec
+import _root_.firrtl.passes.CheckTypes
/**
* BiConnect.connect executes a bidirectional connection element-wise.
@@ -91,12 +90,28 @@ private[chisel3] object BiConnect {
if (left_v.length != right_v.length) {
throw MismatchedVecException
}
- for (idx <- 0 until left_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
+
+ val leftReified: Option[Aggregate] = if (isView(left_v)) reifyToAggregate(left_v) else Some(left_v)
+ val rightReified: Option[Aggregate] = if (isView(right_v)) reifyToAggregate(right_v) else Some(right_v)
+
+ if (
+ leftReified.nonEmpty && rightReified.nonEmpty && canBulkConnectAggregates(
+ leftReified.get,
+ rightReified.get,
+ sourceInfo,
+ connectCompileOptions,
+ context_mod
+ )
+ ) {
+ pushCommand(Connect(sourceInfo, leftReified.get.lref, rightReified.get.lref))
+ } else {
+ for (idx <- 0 until left_v.length) {
+ try {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
+ }
}
}
}
@@ -122,29 +137,31 @@ private[chisel3] object BiConnect {
}
}
}
- // Handle Records defined in Chisel._ code by emitting a FIRRTL partial connect
+ // Handle Records defined in Chisel._ code by emitting a FIRRTL bulk
+ // connect when possible and a partial connect otherwise
case pair @ (left_r: Record, right_r: Record) =>
val notStrict =
Seq(left_r.compileOptions, right_r.compileOptions).contains(ExplicitCompileOptions.NotStrict)
- if (notStrict) {
- // Traces flow from a child Data to its parent
- @tailrec def traceFlow(currentlyFlipped: Boolean, data: Data): Boolean = {
- import SpecifiedDirection.{Input => SInput, Flip => SFlip}
- val sdir = data.specifiedDirection
- val flipped = sdir == SInput || sdir == SFlip
- data.binding.get match {
- case ChildBinding(parent) => traceFlow(flipped ^ currentlyFlipped, parent)
- case PortBinding(enclosure) =>
- val childPort = enclosure != context_mod
- childPort ^ flipped ^ currentlyFlipped
- case _ => true
- }
- }
- def canBeSink(data: Data): Boolean = traceFlow(true, data)
- def canBeSource(data: Data): Boolean = traceFlow(false, data)
- // chisel3 <> is commutative but FIRRTL <- is not
- val flipConnection = !canBeSink(left_r) || !canBeSource(right_r)
- val (newLeft, newRight) = if (flipConnection) pair.swap else pair
+
+ // chisel3 <> is commutative but FIRRTL <- is not
+ val flipConnection =
+ !MonoConnect.canBeSink(left_r, context_mod) || !MonoConnect.canBeSource(right_r, context_mod)
+ val (newLeft, newRight) = if (flipConnection) (right_r, left_r) else (left_r, right_r)
+
+ val leftReified: Option[Aggregate] = if (isView(newLeft)) reifyToAggregate(newLeft) else Some(newLeft)
+ val rightReified: Option[Aggregate] = if (isView(newRight)) reifyToAggregate(newRight) else Some(newRight)
+
+ if (
+ leftReified.nonEmpty && rightReified.nonEmpty && canBulkConnectAggregates(
+ leftReified.get,
+ rightReified.get,
+ sourceInfo,
+ connectCompileOptions,
+ context_mod
+ )
+ ) {
+ pushCommand(Connect(sourceInfo, leftReified.get.lref, rightReified.get.lref))
+ } else if (notStrict) {
newLeft.bulkConnect(newRight)(sourceInfo, ExplicitCompileOptions.NotStrict)
} else {
recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
@@ -218,6 +235,59 @@ private[chisel3] object BiConnect {
}
}
+ /** Check whether two aggregates can be bulk connected (<=) in FIRRTL. From the
+ * FIRRTL specification, the following must hold for bulk connection:
+ *
+ * 1. The types of the left-hand and right-hand side expressions must be
+ * equivalent.
+ * 2. The bit widths of the two expressions must allow for data to always
+ * flow from a smaller bit width to an equal size or larger bit width.
+ * 3. The flow of the left-hand side expression must be sink or duplex
+ * 4. Either the flow of the right-hand side expression is source or duplex,
+ * or the right-hand side expression has a passive type.
+ */
+ private[chisel3] def canBulkConnectAggregates(
+ sink: Aggregate,
+ source: Aggregate,
+ sourceInfo: SourceInfo,
+ connectCompileOptions: CompileOptions,
+ context_mod: RawModule
+ ): Boolean = {
+
+ // check that the aggregates have the same types
+ def typeCheck = CheckTypes.validConnect(
+ Converter.extractType(sink, sourceInfo),
+ Converter.extractType(source, sourceInfo)
+ )
+
+ // check records live in appropriate contexts
+ def contextCheck =
+ MonoConnect.aggregateConnectContextCheck(
+ sourceInfo,
+ connectCompileOptions,
+ sink,
+ source,
+ context_mod
+ )
+
+ // sink must be writable and must also not be a literal
+ def bindingCheck = sink.topBinding match {
+ case _: ReadOnlyBinding => false
+ case _ => true
+ }
+
+ // check data can flow between provided aggregates
+ def flow_check = MonoConnect.canBeSink(sink, context_mod) && MonoConnect.canBeSource(source, context_mod)
+
+ // do not bulk connect source literals (results in infinite recursion from calling .ref)
+ def sourceNotLiteralCheck = source.topBinding match {
+ case _: LitBinding => false
+ case _ => true
+ }
+
+ typeCheck && contextCheck && bindingCheck && flow_check && sourceNotLiteralCheck
+ }
+
// These functions (finally) issue the connection operation
// Issue with right as sink, left as source
private def issueConnectL2R(left: Element, right: Element)(implicit sourceInfo: SourceInfo): Unit = {
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 247be57a..1ffe54ab 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -258,6 +258,7 @@ private[chisel3] trait HasId extends InstanceId {
(p._component, this) match {
case (Some(c), _) => refName(c)
case (None, d: Data) if d.topBindingOpt == Some(CrossModuleBinding) => _ref.get.localName
+ case (None, _: MemBase[Data]) => _ref.get.localName
case (None, _) =>
throwException(s"signalName/pathName should be called after circuit elaboration: $this, ${_parent}")
}
diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala
index b4d9aeff..40056c89 100644
--- a/core/src/main/scala/chisel3/internal/MonoConnect.scala
+++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -5,11 +5,13 @@ package chisel3.internal
import chisel3._
import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, Interval, UnsafeEnum}
import chisel3.internal.Builder.pushCommand
-import chisel3.experimental.dataview.reify
-import chisel3.internal.firrtl.{Connect, DefInvalid}
+import chisel3.internal.firrtl.{Connect, Converter, DefInvalid}
+import chisel3.experimental.dataview.{isView, reify, reifyToAggregate}
import scala.language.experimental.macros
import chisel3.internal.sourceinfo.SourceInfo
+import _root_.firrtl.passes.CheckTypes
+import scala.annotation.tailrec
/**
* MonoConnect.connect executes a mono-directional connection element-wise.
@@ -129,12 +131,28 @@ private[chisel3] object MonoConnect {
// Handle Vec case
case (sink_v: Vec[Data @unchecked], source_v: Vec[Data @unchecked]) =>
if (sink_v.length != source_v.length) { throw MismatchedVecException }
- for (idx <- 0 until sink_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod)
- } catch {
- case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message")
+
+ val sinkReified: Option[Aggregate] = if (isView(sink_v)) reifyToAggregate(sink_v) else Some(sink_v)
+ val sourceReified: Option[Aggregate] = if (isView(source_v)) reifyToAggregate(source_v) else Some(source_v)
+
+ if (
+ sinkReified.nonEmpty && sourceReified.nonEmpty && canBulkConnectAggregates(
+ sinkReified.get,
+ sourceReified.get,
+ sourceInfo,
+ connectCompileOptions,
+ context_mod
+ )
+ ) {
+ pushCommand(Connect(sourceInfo, sinkReified.get.lref, sourceReified.get.ref))
+ } else {
+ for (idx <- 0 until sink_v.length) {
+ try {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod)
+ } catch {
+ case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message")
+ }
}
}
// Handle Vec connected to DontCare. Apply the DontCare to individual elements.
@@ -150,19 +168,34 @@ private[chisel3] object MonoConnect {
// Handle Record case
case (sink_r: Record, source_r: Record) =>
- // For each field, descend with right
- for ((field, sink_sub) <- sink_r.elements) {
- try {
- source_r.elements.get(field) match {
- case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod)
- case None => {
- if (connectCompileOptions.connectFieldsMustMatch) {
- throw MissingFieldException(field)
+ val sinkReified: Option[Aggregate] = if (isView(sink_r)) reifyToAggregate(sink_r) else Some(sink_r)
+ val sourceReified: Option[Aggregate] = if (isView(source_r)) reifyToAggregate(source_r) else Some(source_r)
+
+ if (
+ sinkReified.nonEmpty && sourceReified.nonEmpty && canBulkConnectAggregates(
+ sinkReified.get,
+ sourceReified.get,
+ sourceInfo,
+ connectCompileOptions,
+ context_mod
+ )
+ ) {
+ pushCommand(Connect(sourceInfo, sinkReified.get.lref, sourceReified.get.ref))
+ } else {
+ // For each field, descend with right
+ for ((field, sink_sub) <- sink_r.elements) {
+ try {
+ source_r.elements.get(field) match {
+ case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod)
+ case None => {
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ throw MissingFieldException(field)
+ }
}
}
+ } catch {
+ case MonoConnectException(message) => throw MonoConnectException(s".$field$message")
}
- } catch {
- case MonoConnectException(message) => throw MonoConnectException(s".$field$message")
}
}
// Handle Record connected to DontCare. Apply the DontCare to individual elements.
@@ -190,6 +223,143 @@ private[chisel3] object MonoConnect {
case (sink, source) => throw MismatchedException(sink, source)
}
+ /** Determine if a valid connection can be made between a source [[Aggregate]] and sink
+ * [[Aggregate]] given their parent module and directionality context
+ *
+ * @return whether the source and sink exist in an appropriate context to be connected
+ */
+ private[chisel3] def aggregateConnectContextCheck(
+ implicit sourceInfo: SourceInfo,
+ connectCompileOptions: CompileOptions,
+ sink: Aggregate,
+ source: Aggregate,
+ context_mod: RawModule
+ ): Boolean = {
+ import ActualDirection.{Bidirectional, Input, Output}
+ // If source has no location, assume in context module
+ // This can occur if is a literal, unbound will error previously
+ val sink_mod: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException(sink, source))
+ val source_mod: BaseModule = source.topBinding.location.getOrElse(context_mod)
+
+ val sink_parent = Builder.retrieveParent(sink_mod, context_mod).getOrElse(None)
+ val source_parent = Builder.retrieveParent(source_mod, context_mod).getOrElse(None)
+
+ val sink_is_port = sink.topBinding match {
+ case PortBinding(_) => true
+ case _ => false
+ }
+ val source_is_port = source.topBinding match {
+ case PortBinding(_) => true
+ case _ => false
+ }
+
+ if (!checkWhenVisibility(sink)) {
+ throw SinkEscapedWhenScopeException(sink)
+ }
+
+ if (!checkWhenVisibility(source)) {
+ throw SourceEscapedWhenScopeException(source)
+ }
+
+ // CASE: Context is same module that both sink node and source node are in
+ if ((context_mod == sink_mod) && (context_mod == source_mod)) {
+ sink.direction != Input
+ }
+
+ // CASE: Context is same module as sink node and source node is in a child module
+ else if ((sink_mod == context_mod) && (source_parent == context_mod)) {
+ // NOTE: Workaround for bulk connecting non-agnostified FIRRTL ports
+ // See: https://github.com/freechipsproject/firrtl/issues/1703
+ // Original behavior should just check if the sink direction is an Input
+ val sinkCanBeInput = sink.direction match {
+ case Input => true
+ case Bidirectional(_) => true
+ case _ => false
+ }
+ // Thus, right node better be a port node and thus have a direction
+ if (!source_is_port) { !connectCompileOptions.dontAssumeDirectionality }
+ else if (sinkCanBeInput) {
+ if (source.direction == Output) {
+ !connectCompileOptions.dontTryConnectionsSwapped
+ } else { false }
+ } else { true }
+ }
+
+ // CASE: Context is same module as source node and sink node is in child module
+ else if ((source_mod == context_mod) && (sink_parent == context_mod)) {
+ // NOTE: Workaround for bulk connecting non-agnostified FIRRTL ports
+ // See: https://github.com/freechipsproject/firrtl/issues/1703
+ // Original behavior should just check if the sink direction is an Input
+ sink.direction match {
+ case Input => true
+ case Bidirectional(_) => true
+ case _ => false
+ }
+ }
+
+ // CASE: Context is the parent module of both the module containing sink node
+ // and the module containing source node
+ // Note: This includes case when sink and source in same module but in parent
+ else if ((sink_parent == context_mod) && (source_parent == context_mod)) {
+ // Thus both nodes must be ports and have a direction
+ if (!source_is_port) { !connectCompileOptions.dontAssumeDirectionality }
+ else if (sink_is_port) {
+ // NOTE: Workaround for bulk connecting non-agnostified FIRRTL ports
+ // See: https://github.com/freechipsproject/firrtl/issues/1703
+ // Original behavior should just check if the sink direction is an Input
+ sink.direction match {
+ case Input => true
+ case Bidirectional(_) => true // NOTE: Workaround for non-agnostified ports
+ case _ => false
+ }
+ } else { false }
+ }
+
+ // Not quite sure where left and right are compared to current module
+ // so just error out
+ else false
+ }
+
+ /** Trace flow from child Data to its parent. */
+ @tailrec private[chisel3] def traceFlow(currentlyFlipped: Boolean, data: Data, context_mod: RawModule): Boolean = {
+ import SpecifiedDirection.{Input => SInput, Flip => SFlip}
+ val sdir = data.specifiedDirection
+ val flipped = sdir == SInput || sdir == SFlip
+ data.binding.get match {
+ case ChildBinding(parent) => traceFlow(flipped ^ currentlyFlipped, parent, context_mod)
+ case PortBinding(enclosure) =>
+ val childPort = enclosure != context_mod
+ childPort ^ flipped ^ currentlyFlipped
+ case _ => true
+ }
+ }
+ def canBeSink(data: Data, context_mod: RawModule): Boolean = traceFlow(true, data, context_mod)
+ def canBeSource(data: Data, context_mod: RawModule): Boolean = traceFlow(false, data, context_mod)
+
+ /** Check whether two aggregates can be bulk connected (<=) in FIRRTL. (MonoConnect case)
+ *
+ * Mono-directional bulk connects only work if all signals of the sink are unidirectional
+ * In the case of a sink aggregate with bidirectional signals, e.g. `Decoupled`,
+ * a `BiConnect` is necessary.
+ */
+ private[chisel3] def canBulkConnectAggregates(
+ sink: Aggregate,
+ source: Aggregate,
+ sourceInfo: SourceInfo,
+ connectCompileOptions: CompileOptions,
+ context_mod: RawModule
+ ): Boolean = {
+ // Assuming we're using a <>, check if a bulk connect is valid in that case
+ def biConnectCheck =
+ BiConnect.canBulkConnectAggregates(sink, source, sourceInfo, connectCompileOptions, context_mod)
+
+ // Check that the Aggregate can be driven (not bidirectional or an input) to match Chisel semantics
+ def sinkCanBeDrivenCheck: Boolean =
+ sink.direction == ActualDirection.Output || sink.direction == ActualDirection.Unspecified
+
+ biConnectCheck && sinkCanBeDrivenCheck
+ }
+
// This function (finally) issues the connection operation
private def issueConnect(sink: Element, source: Element)(implicit sourceInfo: SourceInfo): Unit = {
// If the source is a DontCare, generate a DefInvalid for the sink,
diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md
index ec7e9ed2..ae7c7bf6 100644
--- a/docs/src/cookbooks/cookbook.md
+++ b/docs/src/cookbooks/cookbook.md
@@ -20,6 +20,8 @@ Please note that these examples make use of [Chisel's scala-style printing](../e
* [Can I make a 2D or 3D Vector?](#can-i-make-a-2D-or-3D-Vector)
* [How do I create a Vector of Registers?](#how-do-i-create-a-vector-of-registers)
* [How do I create a Reg of type Vec?](#how-do-i-create-a-reg-of-type-vec)
+* Bundles
+ * [How do I deal with aliased Bundle fields?](#aliased-bundle-fields)
* [How do I create a finite state machine?](#how-do-i-create-a-finite-state-machine-fsm)
* [How do I unpack a value ("reverse concatenation") like in Verilog?](#how-do-i-unpack-a-value-reverse-concatenation-like-in-verilog)
* [How do I do subword assignment (assign to some bits in a UInt)?](#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint)
@@ -231,6 +233,145 @@ class Foo extends RawModule {
}
```
+## Bundles
+
+### <a name="aliased-bundle-fields"></a> How do I deal with aliased Bundle fields?
+
+```scala mdoc:invisible:reset
+import chisel3._
+
+class Top[T <: Data](gen: T) extends Module {
+ val in = IO(Input(gen))
+ val out = IO(Output(gen))
+ out := in
+}
+```
+
+Following the `gen` pattern when creating Bundles can result in some opaque error messages:
+
+```scala mdoc
+class AliasedBundle[T <: Data](gen: T) extends Bundle {
+ val foo = gen
+ val bar = gen
+}
+```
+
+```scala mdoc:crash
+getVerilogString(new Top(new AliasedBundle(UInt(8.W))))
+```
+
+This error is saying that fields `foo` and `bar` of `AliasedBundle` are the
+exact same object in memory.
+This is a problem for Chisel because we need to be able to distinguish uses of
+`foo` and `bar` but cannot when they are referentially the same.
+
+Note that the following example looks different but will give you exactly the same issue:
+
+```scala mdoc
+class AlsoAliasedBundle[T <: Data](val gen: T) extends Bundle {
+ // ^ This val makes `gen` a field, just like `foo`
+ val foo = gen
+}
+```
+
+By making `gen` a `val`, it becomes a public field of the `class`, just like `foo`.
+
+```scala mdoc:crash
+getVerilogString(new Top(new AlsoAliasedBundle(UInt(8.W))))
+```
+
+There are several ways to solve this issue with their own advantages and disadvantages.
+
+#### 1. 0-arity function parameters
+
+Instead of passing an object as a parameter, you can pass a 0-arity function (a function with no arguments):
+
+```scala mdoc
+class UsingAFunctionBundle[T <: Data](gen: () => T) extends Bundle {
+ val foo = gen()
+ val bar = gen()
+}
+```
+
+Note that the type of `gen` is now `() => T`.
+Because it is now a function and not a subtype of `Data`, you can safely make `gen` a `val` without
+it becoming a hardware field of the `Bundle`.
+
+Note that this also means you must pass `gen` as a function, for example:
+
+```scala mdoc:silent
+getVerilogString(new Top(new UsingAFunctionBundle(() => UInt(8.W))))
+```
+
+<a name="aliased-warning"></a> **Warning**: you must ensure that `gen` creates fresh objects rather than capturing an already constructed value:
+
+```scala mdoc:crash
+class MisusedFunctionArguments extends Module {
+ // This usage is correct
+ val in = IO(Input(new UsingAFunctionBundle(() => UInt(8.W))))
+
+ // This usage is incorrect
+ val fizz = UInt(8.W)
+ val out = IO(Output(new UsingAFunctionBundle(() => fizz)))
+}
+getVerilogString(new MisusedFunctionArguments)
+```
+In the above example, value `fizz` and fields `foo` and `bar` of `out` are all the same object in memory.
+
+
+#### 2. By-name function parameters
+
+Functionally the same as (1) but with more subtle syntax, you can use [Scala by-name function parameters](https://docs.scala-lang.org/tour/by-name-parameters.html):
+
+```scala mdoc
+class UsingByNameParameters[T <: Data](gen: => T) extends Bundle {
+ val foo = gen
+ val bar = gen
+}
+```
+
+With this usage, you do not include `() =>` when passing the argument:
+
+```scala mdoc:silent
+getVerilogString(new Top(new UsingByNameParameters(UInt(8.W))))
+```
+
+Note that as this is just syntactic sugar over (1), the [same warning applies](#aliased-warning).
+
+#### 3. Directioned Bundle fields
+
+You can alternatively wrap the fields with `Output(...)`, which creates fresh instances of the passed argument.
+Chisel treats `Output` as the "default direction" so if all fields are outputs, the `Bundle` is functionally equivalent to a `Bundle` with no directioned fields.
+
+```scala mdoc
+class DirectionedBundle[T <: Data](gen: T) extends Bundle {
+ val foo = Output(gen)
+ val bar = Output(gen)
+}
+```
+
+```scala mdoc:invisible
+getVerilogString(new Top(new DirectionedBundle(UInt(8.W))))
+```
+
+This approach is admittedly a little ugly and may mislead others reading the code because it implies that this Bundle is intended to be used as an `Output`.
+
+#### 4. Call `.cloneType` directly
+
+You can also just call `.cloneType` on your `gen` argument directly.
+While we try to hide this implementation detail from the user, `.cloneType` is the mechanism by which Chisel creates fresh instances of `Data` objects:
+
+```scala mdoc
+class UsingCloneTypeBundle[T <: Data](gen: T) extends Bundle {
+ val foo = gen.cloneType
+ val bar = gen.cloneType
+}
+```
+
+```scala mdoc:invisible
+getVerilogString(new Top(new UsingCloneTypeBundle(UInt(8.W))))
+```
+
### How do I create a finite state machine (FSM)?
The advised way is to use [`ChiselEnum`](https://www.chisel-lang.org/api/latest/chisel3/experimental/index.html#ChiselEnum=chisel3.experimental.EnumFactory) to construct enumerated types representing the state of the FSM.
diff --git a/docs/src/cookbooks/cookbooks.md b/docs/src/cookbooks/cookbooks.md
index 7c3eb8b9..9681a1e8 100644
--- a/docs/src/cookbooks/cookbooks.md
+++ b/docs/src/cookbooks/cookbooks.md
@@ -11,6 +11,7 @@ If you have any requests or examples to share,
please [file an issue](https://github.com/chipsalliance/chisel3/issues/new) and let us know!
* [General Cookbooks](cookbook)
+* [Verilog vs. Chisel Side-by-Side](verilog-vs-chisel)
* [Naming Cookbook](naming)
* [Troubleshooting Guide](troubleshooting)
* [Hierarchy Cookbook](hierarchy)
diff --git a/docs/src/cookbooks/verilog-vs-chisel.md b/docs/src/cookbooks/verilog-vs-chisel.md
new file mode 100644
index 00000000..1adf609e
--- /dev/null
+++ b/docs/src/cookbooks/verilog-vs-chisel.md
@@ -0,0 +1,833 @@
+---
+layout: docs
+title: "Verilog-vs-Chisel"
+section: "chisel3"
+---
+
+<!Doctype html>
+<html>
+
+# Verilog vs Chisel Side-By-Side
+
+This page serves as a quick introduction to Chisel for those familiar with Verilog. It is by no means a comprehensive guide of everything Chisel can do. Feel free to file an issue with suggestions of things you'd like to see added to this page.
+
+```scala mdoc:invisible
+import chisel3._
+import chisel3.util.{switch, is}
+import chisel3.stage.ChiselStage
+import chisel3.experimental.ChiselEnum
+import chisel3.util.{Cat, Fill, DecoupledIO}
+```
+
+<body>
+ <!-- This script is needed so that Markdown and HTML will render together, see link to Stack overflow -->
+ <script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
+ <table border ="0">
+ <h1>Creating a Module</h1>
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module Foo (
+ input a,
+ output b
+);
+ assign b = a;
+endmodule
+```
+
+</td>
+ <td>
+
+```scala mdoc
+class Foo extends Module {
+ val a = IO(Input(Bool()))
+ val b = IO(Output(Bool()))
+ b := a
+}
+```
+</td>
+ </tr>
+ </table>
+</body>
+</html>
+
+# Parameterizing a Module
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+
+<tr>
+<td>
+
+```verilog
+module PassthroughGenerator(
+ input [width-1:0] in,
+ output [width-1:0] out
+);
+
+ parameter width = 8;
+
+ assign out = in;
+endmodule
+```
+</td>
+<td>
+
+```scala mdoc:silent
+class PassthroughGenerator(width: Int = 8) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+
+ out := in
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new PassthroughGenerator(10))
+```
+</td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module ParameterizedWidthAdder(
+ input [in0Width-1:0] in0,
+ input [in1Width-1:0] in1,
+ output [sumWidth-1:0] sum
+);
+ parameter in0Width = 8;
+ parameter in1Width = 1;
+ parameter sumWidth = 9;
+
+ assign sum = in0 + in1;
+
+endmodule
+```
+
+</td>
+<td>
+
+```scala mdoc:silent
+class ParameterizedWidthAdder(
+ in0Width: Int,
+ in1Width: Int,
+ sumWidth: Int) extends Module {
+
+ val in0 = IO(Input(UInt(in0Width.W)))
+ val in1 = IO(Input(UInt(in1Width.W)))
+ val sum = IO(Output(UInt(sumWidth.W)))
+
+ // a +& b includes the carry, a + b does not
+ sum := in0 +& in1
+}
+```
+</td>
+</tr>
+ </table>
+<html>
+<body>
+
+# Wire Assignment and Literal Values
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+<tr>
+<td>
+
+```verilog
+module MyWireAssignmentModule ();
+
+ wire [31:0] aa = 'd42;
+ // Logical reg for use in always block, not real register
+ reg [31:0] a;
+
+ //
+ always @(*) begin
+ a = aa;
+ end
+
+ // Hex value initialization
+ wire [31:0] b = 32'hbabecafe;
+
+ // Declaration separate from Assignment
+ wire [15:0] c;
+ wire d;
+
+ assign c = 16'b1;
+ assign d = 1'b1;
+
+ // Signed values
+ wire signed [63:0] g;
+ assign g = -’d5;
+
+ wire signed [31:0] h = 'd5;
+
+ reg signed[31:0] f;
+ always@(*) begin
+ f = ‘d5;
+ end
+endmodule
+```
+
+
+</td>
+<td>
+
+```scala mdoc:silent
+
+
+class MyWireAssignmentModule extends Module {
+
+ val aa = 42.U(32.W)
+ val a = Wire(UInt(32.W))
+ a := aa
+ val b = "hbabecafe".U(32.W)
+ val c = Wire(UInt(16.W))
+ val d = Wire(Bool())
+ c := "b1".U(16.W)
+ d := true.B
+ val g = Wire(SInt(64.W))
+ g := -5.S
+ val h = 5.asSInt(32.W)
+ val f = Wire(SInt(32.W))
+ f := 5.S
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new MyWireAssignmentModule)
+```
+
+</td>
+</tr>
+ </table>
+<html>
+<body>
+
+# Register Declaration and Assignment
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module RegisterModule(
+ input clock,
+ input reset,
+ input [7:0] in,
+ output [7:0] out,
+ input differentClock,
+ input differentSyncReset,
+ input differentAsyncReset
+);
+
+ reg [7:0] registerWithoutInit;
+ reg [7:0] registerWithInit;
+ reg [7:0] registerOnDifferentClockAndSyncReset;
+ reg [7:0] registerOnDifferentClockAndAsyncReset;
+
+
+ always @(posedge clock) begin
+ registerWithoutInit <= in + 8'h1;
+ end
+
+ always @(posedge clock) begin
+ if (reset) begin
+ registerWithInit <= 8'd42;
+ end else begin
+ registerWithInit <= registerWithInit - 8'h1;
+ end
+ end
+
+ always @(posedge differentClock) begin
+ if (differentSyncReset) begin
+ registerOnDifferentClockAndSyncReset <= 8'h42;
+ end else begin
+ registerOnDifferentClockAndSyncReset <= in - 8'h1;
+ end
+ end
+
+ always @(posedge differentClock or posedge differentAsyncReset) begin
+ if (differentAsyncReset) begin
+ registerOnDifferentClockAndAsyncReset <= 8'h24;
+ end else begin
+ registerOnDifferentClockAndAsyncReset <= in + 8'h2;
+ end
+ end
+
+ assign out = in +
+ registerWithoutInit +
+ registerWithInit +
+ registerOnDifferentClockAndSyncReset +
+ registerOnDifferentClockAndAsyncReset;
+endmodule
+
+```
+</td>
+<td>
+
+```scala mdoc:silent
+class RegisterModule extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ val differentClock = IO(Input(Clock()))
+ val differentSyncReset = IO(Input(Bool()))
+
+ val differentAsyncReset = IO(Input(AsyncReset()))
+
+ val registerWithoutInit = Reg(UInt(8.W))
+
+ val registerWithInit = RegInit(42.U(8.W))
+
+ registerWithoutInit := in + 1.U
+
+ registerWithInit := registerWithInit - 1.U
+
+ val registerOnDifferentClockAndSyncReset = withClockAndReset(differentClock, differentSyncReset) {
+ val reg = RegInit("h42".U(8.W))
+ reg
+ }
+ registerOnDifferentClockAndSyncReset := in - 1.U
+
+ val registerOnDifferentClockAndAsyncReset = withClockAndReset(differentClock, differentAsyncReset) {
+ val reg = RegInit("h24".U(8.W))
+ reg
+ }
+ registerOnDifferentClockAndAsyncReset := in + 2.U
+
+ out := in +
+ registerWithoutInit +
+ registerWithInit +
+ registerOnDifferentClockAndSyncReset +
+ registerOnDifferentClockAndAsyncReset
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new RegisterModule)
+```
+</td>
+ </tr>
+ </table>
+<html>
+<body>
+
+# Case Statements
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module CaseStatementModule(
+ input [2:0] a,
+ input [2:0] b,
+ input [2:0] c,
+ input [1:0] sel,
+ output reg [2:0] out
+);
+
+ always @(*)
+ case (sel)
+ 2'b00: out <= a;
+ 2'b01: out <= b;
+ 2'b10: out <= c;
+ default: out <= 3'b0;
+ end
+ end
+endmodule
+```
+</td>
+<td>
+
+```scala mdoc:silent
+class CaseStatementModule extends Module {
+ val a, b, c= IO(Input(UInt(3.W)))
+ val sel = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt(3.W)))
+
+ // default goes first
+ out := 0.U
+
+ switch (sel) {
+ is ("b00".U) { out := a }
+ is ("b01".U) { out := b }
+ is ("b10".U) { out := c }
+ }
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new CaseStatementModule)
+```
+</td>
+ </tr>
+ </table>
+<html>
+<body>
+
+# Case Statements Using Enums
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module CaseStatementEnumModule1 (
+ input [2:0] rs1,
+ input [2:0] pc,
+ input AluMux1Sel sel,
+ output reg [2:0] out);
+
+ typedef enum {SELECT_RS1, SELECT_PC} AluMux1Sel;
+
+ case(sel)
+ SELECT_RS1: out <= rs1;
+ SELECT_PC: out <= pc;
+ default: out <= 3'b0;
+ end
+endmodule
+```
+</td>
+<td>
+
+```scala mdoc:silent
+class CaseStatementEnumModule1 extends Module {
+
+ object AluMux1Sel extends ChiselEnum {
+ val selectRS1, selectPC = Value
+ }
+
+ import AluMux1Sel._
+ val rs1, pc = IO(Input(UInt(3.W)))
+ val sel = IO(Input(AluMux1Sel()))
+ val out = IO(Output(UInt(3.W)))
+
+ // default goes first
+ out := 0.U
+
+ switch (sel) {
+ is (selectRS1) { out := rs1 }
+ is (selectPC) { out := pc }
+ }
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new CaseStatementEnumModule1)
+```
+</td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module CaseStatementEnumModule2 (input clk);
+
+ typedef enum {
+ INIT = 3,
+ IDLE = 'h13,
+ START = 'h17,
+ READY = 'h23 } StateValue;
+
+ reg StateValue state;
+
+
+ always @(posedge clk) begin
+ case (state)
+ IDLE : state = START;
+ START : state = READY;
+ READY : state = IDLE ;
+ default : state = IDLE ;
+ endcase
+ end
+endmodule
+```
+</td>
+<td>
+
+```scala mdoc:silent
+class CaseStatementEnumModule2 extends Module {
+
+ object StateValue extends ChiselEnum {
+ val INIT = Value(0x03.U)
+ val IDLE = Value(0x13.U)
+ val START = Value(0x17.U)
+ val READY = Value(0x23.U)
+ }
+ import StateValue._
+ val state = Reg(StateValue())
+
+
+ switch (state) {
+ is (INIT) {state := IDLE}
+ is (IDLE) {state := START}
+ is (START) {state := READY}
+ is (READY) {state := IDLE}
+ }
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new CaseStatementEnumModule2)
+```
+</td>
+ </tr>
+ </table>
+<html>
+<body>
+
+<!--
+# SystemVerilog Interfaces
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```
+module MyInterfaceModule(
+ input clock,
+ input reset,
+ output io_in_ready,
+ input io_in_valid,
+ input [7:0] io_in_bits,
+ input io_out_ready,
+ output io_out_valid,
+ output [7:0] io_out_bits
+);
+ assign io_in_ready = io_out_ready; // @[main.scala 17:12]
+ assign io_out_valid = io_in_valid; // @[main.scala 17:12]
+ assign io_out_bits = io_in_bits; // @[main.scala 17:12]
+endmodule
+```
+</td>
+<td>
+
+```scala mdoc:silent
+class MyInterfaceModule extends Module {
+val io = IO(new Bundle {
+val in = Flipped(DecoupledIO(UInt(8.W)))
+val out = DecoupledIO(UInt(8.W))
+})
+
+val tmp = Wire(DecoupledIO(UInt(8.W)))
+tmp <> io.in
+io.out <> tmp
+io.out <> io.in
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new MyInterfaceModule)
+```
+
+</td>
+ </tr>
+ </table>
+
+<html>
+<body>
+-->
+
+
+# Multi-Dimensional Memories
+
+<html>
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+module ReadWriteSmem(
+ input clock,
+ input reset,
+ input io_enable,
+ input io_write,
+ input [9:0] io_addr,
+ input [31:0] io_dataIn,
+ output [31:0] io_dataOut
+);
+
+reg [31:0] mem [0:1023];
+reg [9:0] addr_delay;
+
+assign io_dataOut = mem[addr_delay]
+
+ always @(posedge clock) begin
+ if (io_enable & io_write) begin
+ mem[io_addr] <= io_data;
+ end
+ if (io_enable) begin
+ addr_delay <= io_addr;
+ end
+ end
+endmodule
+```
+</td>
+
+
+<td>
+
+```scala mdoc:silent
+class ReadWriteSmem extends Module {
+ val io = IO(new Bundle {
+ val enable = Input(Bool())
+ val write = Input(Bool())
+ val addr = Input(UInt(10.W))
+ val dataIn = Input(UInt(32.W))
+ val dataOut = Output(UInt(32.W))
+ })
+
+ val mem = SyncReadMem(1024, UInt(32.W))
+
+ // Create one write port and one read port
+ mem.write(io.addr, io.dataIn)
+ io.dataOut := mem.read(io.addr, io.enable)
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new ReadWriteSmem)
+```
+</td>
+</tr>
+<tr>
+<td>
+
+```verilog
+module ReadWriteMem(
+ input clock,
+ input io_enable,
+ input io_write,
+ input [9:0] io_addr,
+ input [31:0] io_dataIn,
+ output [31:0] io_dataOut
+ );
+
+ reg [31:0] mem [0:1023];
+
+ assign io_dataOut = mem[io_addr];
+
+ always @(posedge clock) begin
+ if (io_enable && io_write) begin
+ mem[io_addr] <= io_dataIn;
+ end
+ end
+
+endmodule
+```
+
+</td>
+
+<td>
+
+```scala mdoc:silent
+class ReadWriteMem extends Module {
+ val io = IO(new Bundle {
+ val enable = Input(Bool())
+ val write = Input(Bool())
+ val addr = Input(UInt(10.W))
+ val dataIn = Input(UInt(32.W))
+ val dataOut = Output(UInt(32.W))
+})
+ val mem = Mem(1024, UInt(32.W))
+ // Create one write port and one read port
+ mem.write(io.addr, io.dataIn)
+ io.dataOut := mem.read(io.addr)
+}
+```
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new ReadWriteMem)
+```
+</td>
+</tr>
+ </table>
+<html>
+<html>
+
+# Operators
+
+<body>
+ <table border ="0">
+ <tr>
+ <td><b style="font-size:30px">Verilog</b></td>
+ <td><b style="font-size:30px">Chisel</b></td>
+ </tr>
+ <tr>
+<td>
+
+```verilog
+ module OperatorExampleModule(
+ input clock,
+ input reset,
+ input [31:0] x,
+ input [31:0] y,
+ input [31:0] c,
+ output [31:0] add_res,
+ output [31:0] sub_res,
+ output [31:0] mod_res,
+ output [31:0] div_res,
+ output [31:0] and_res,
+ output [31:0] or_res,
+ output [31:0] xor_res,
+ output [31:0] not_res,
+ output [31:0] logical_not_res,
+ output [31:0] mux_res,
+ output [31:0] rshift_res,
+ output [31:0] lshift_res,
+ output andR_res,
+ output logical_and_res,
+ output logical_or_res,
+ output equ_res,
+ output not_equ_res,
+ output orR_res,
+ output xorR_res,
+ output gt_res,
+ output lt_res,
+ output geq_res,
+ output leq_res,
+ output single_bitselect_res,
+ output [63:0] mul_res,
+ output [63:0] cat_res,
+ output [1:0] multiple_bitselect_res,
+ output [95:0] fill_res
+);
+ assign add_res = x + y;
+ assign sub_res = x - y;
+ assign mod_res = x % y;
+ assign mul_res = x * y;
+ assign div_res = x / y;
+ assign equ_res = x == y;
+ assign not_equ_res = x != y;
+ assign and_res = x & y;
+ assign or_res = x | y;
+ assign xor_res = x ^ y;
+ assign not_res = ~x;
+ assign logical_not_res = !(x == 32'h0);
+ assign logical_and_res = x[0] && y[0];
+ assign logical_or_res = x[0] || y[0];
+ assign cat_res = {x,y};
+ assign mux_res = c[0] ? x : y;
+ assign rshift_res = x >> y[2:0];
+ assign lshift_res = x << y[2:0];
+ assign gt_res = x > y;
+ assign lt_res = x < y;
+ assign geq_res = x >= y;
+ assign leq_res = x <= y;
+ assign single_bitselect_res = x[1];
+ assign multiple_bitselect_res = x[1:0];
+ assign fill_res = {3{x}};
+ assign andR_res = &x;
+ assign orR_res = |x;
+ assign xorR_res = ^x;
+
+
+
+
+
+endmodule
+
+```
+
+</td>
+<td>
+
+```scala mdoc:silent
+class OperatorExampleModule extends Module {
+
+ val x, y, c = IO(Input(UInt(32.W)))
+
+ val add_res, sub_res,
+ mod_res, div_res, and_res,
+ or_res, xor_res, not_res,
+ logical_not_res, mux_res,
+ rshift_res , lshift_res = IO(Output(UInt(32.W)))
+
+ val logical_and_res, logical_or_res,
+ equ_res, not_equ_res, andR_res,
+ orR_res, xorR_res, gt_res,lt_res,
+ geq_res, leq_res,single_bitselect_res = IO(Output(Bool()))
+
+ val mul_res, cat_res= IO(Output(UInt(64.W)))
+
+ val multiple_bitselect_res = IO(Output(UInt(2.W)))
+
+ val fill_res = IO(Output(UInt((3*32).W)))
+
+ add_res := x + y
+ sub_res := x - y
+ mod_res := x % y
+ mul_res := x * y
+ div_res := x / y
+ equ_res := x === y
+ not_equ_res := x =/= y
+ and_res := x & y
+ or_res := x | y
+ xor_res := x ^ y
+ not_res := ~x
+ logical_not_res := !x
+ logical_and_res := x(0) && y(0)
+ logical_or_res := x(0) || y(0)
+ cat_res := Cat(x, y)
+ mux_res := Mux(c(0), x, y)
+ rshift_res := x >> y(2, 0)
+ lshift_res := x << y(2, 0)
+ gt_res := x > y
+ lt_res := x < y
+ geq_res := x >= y
+ leq_res := x <= y
+ single_bitselect_res := x(1)
+ multiple_bitselect_res := x(1, 0)
+ fill_res:= Fill(3,x)
+ andR_res := x.andR
+ orR_res := x.orR
+ xorR_res := x.xorR
+}
+```
+
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new OperatorExampleModule)
+```
+</td>
+ </tr>
+ </table>
+</body>
+</html>
diff --git a/docs/src/explanations/connection-operators.md b/docs/src/explanations/connection-operators.md
index 8a2117e1..86dca664 100644
--- a/docs/src/explanations/connection-operators.md
+++ b/docs/src/explanations/connection-operators.md
@@ -24,7 +24,7 @@ import chisel3.util.DecoupledIO
```
The diagram for the experiment can be viewed [here](https://docs.google.com/document/d/14C918Hdahk2xOGSJJBT-ZVqAx99_hg3JQIq-vaaifQU/edit?usp=sharing).
-![Experiment Image](https://raw.githubusercontent.com/chipsalliance/chisel3/master/docs/src/images/chisel_01.png?sanitize=true)
+![Experiment Image](https://raw.githubusercontent.com/chipsalliance/chisel3/master/docs/src/images/connection-operators-experiment.svg?sanitize=true)
```scala mdoc:silent
diff --git a/docs/src/images/connection-operators-experiment.svg b/docs/src/images/connection-operators-experiment.svg
new file mode 100644
index 00000000..c163cddc
--- /dev/null
+++ b/docs/src/images/connection-operators-experiment.svg
@@ -0,0 +1 @@
+<svg version="1.1" viewBox="0.0 0.0 800.0 600.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><clipPath id="p.0"><path d="m0 0l800.0 0l0 600.0l-800.0 0l0 -600.0z" clip-rule="nonzero"/></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l800.0 0l0 600.0l-800.0 0z" fill-rule="evenodd"/><path fill="#cfe2f3" d="m55.574802 83.362206l523.84247 0l0 389.00787l-523.84247 0z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m55.574802 83.362206l523.84247 0l0 389.00787l-523.84247 0z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m199.65617 108.062996l592.78735 0l0 42.01574l-592.78735 0z" fill-rule="evenodd"/><path fill="#000000" d="m212.4218 134.98299l-3.53125 -13.359367l1.8125 0l2.03125 8.765617q0.328125 1.375 0.5625 2.71875q0.5 -2.140625 0.59375 -2.46875l2.546875 -9.015617l2.125 0l1.921875 6.7656174q0.71875 2.515625 1.03125 4.71875q0.265625 -1.265625 0.671875 -2.890625l2.09375 -8.593742l1.78125 0l-3.671875 13.359367l-1.703125 0l-2.8125 -10.171867q-0.359375 -1.28125 -0.421875 -1.5625q-0.203125 0.90625 -0.390625 1.5625l-2.828125 10.171867l-1.8125 0zm14.724548 0l0 -9.671867l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.8749924 -0.28125 1.9218674l0 5.0625l-1.625 0zm12.540802 -1.1875q-0.921875 0.765625 -1.765625 1.09375q-0.828125 0.3125 -1.796875 0.3125q-1.59375 0 -2.453125 -0.78125q-0.859375 -0.78125 -0.859375 -1.984375q0 -0.71875 0.328125 -1.296875q0.328125 -0.59375 0.84375 -0.9375q0.53125 -0.359375 1.1875 -0.546875q0.46875 -0.125 1.453125 -0.25q1.984375 -0.234375 2.921875 -0.5625q0.015625 -0.34375 0.015625 -0.421875q0 -0.9999924 -0.46875 -1.4218674q-0.625 -0.546875 -1.875 -0.546875q-1.15625 0 -1.703125 0.40625q-0.546875 0.40625 -0.8125 1.4218674l-1.609375 -0.21875q0.21875 -1.0156174 0.71875 -1.6406174q0.5 -0.640625 1.453125 -0.984375q0.953125 -0.34375 2.1875 -0.34375q1.25 0 2.015625 0.296875q0.78125 0.28125 1.140625 0.734375q0.375 0.4375 0.515625 1.109375q0.078125 0.421875 0.078125 1.5156174l0 2.1875q0 2.28125 0.109375 2.890625q0.109375 0.59375 0.40625 1.15625l-1.703125 0q-0.265625 -0.515625 -0.328125 -1.1875zm-0.140625 -3.671875q-0.890625 0.375 -2.671875 0.625q-1.015625 0.140625 -1.4375 0.328125q-0.421875 0.1875 -0.65625 0.53125q-0.21875 0.34375 -0.21875 0.78125q0 0.65625 0.5 1.09375q0.5 0.4375 1.453125 0.4375q0.9375 0 1.671875 -0.40625q0.75 -0.421875 1.09375 -1.140625q0.265625 -0.5625 0.265625 -1.640625l0 -0.609375zm4.203842 8.5625l0 -13.374992l1.484375 0l0 1.25q0.53125 -0.734375 1.1875 -1.09375q0.671875 -0.375 1.625 -0.375q1.234375 0 2.171875 0.640625q0.953125 0.625 1.4375 1.796875q0.484375 1.1562424 0.484375 2.5468674q0 1.484375 -0.53125 2.671875q-0.53125 1.1875 -1.546875 1.828125q-1.015625 0.625 -2.140625 0.625q-0.8125 0 -1.46875 -0.34375q-0.65625 -0.34375 -1.0625 -0.875l0 4.703125l-1.640625 0zm1.484375 -8.484375q0 1.859375 0.75 2.765625q0.765625 0.890625 1.828125 0.890625q1.09375 0 1.875 -0.921875q0.78125 -0.9375 0.78125 -2.875q0 -1.84375 -0.765625 -2.7656174q-0.75 -0.921875 -1.8125 -0.921875q-1.046875 0 -1.859375 0.984375q-0.796875 0.9687424 -0.796875 2.8437424zm8.891342 8.484375l0 -13.374992l1.484375 0l0 1.25q0.53123474 -0.734375 1.1874847 -1.09375q0.671875 -0.375 1.625 -0.375q1.234375 0 2.171875 0.640625q0.953125 0.625 1.4375 1.796875q0.484375 1.1562424 0.484375 2.5468674q0 1.484375 -0.53125 2.671875q-0.53125 1.1875 -1.546875 1.828125q-1.015625 0.625 -2.140625 0.625q-0.8125 0 -1.46875 -0.34375q-0.65625 -0.34375 -1.0624847 -0.875l0 4.703125l-1.640625 0zm1.484375 -8.484375q0 1.859375 0.74998474 2.765625q0.765625 0.890625 1.828125 0.890625q1.09375 0 1.875 -0.921875q0.78125 -0.9375 0.78125 -2.875q0 -1.84375 -0.765625 -2.7656174q-0.75 -0.921875 -1.8125 -0.921875q-1.046875 0 -1.859375 0.984375q-0.79685974 0.9687424 -0.79685974 2.8437424zm15.516342 1.671875l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.4531174 1.25 -3.7968674q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.7031174q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.2187424 -0.625 -1.8281174q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.0156174zm9.125702 5.765625l0 -9.671867l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.8749924 -0.28125 1.9218674l0 5.0625l-1.625 0z" fill-rule="nonzero"/><path fill="#cfe2f3" d="m120.41207 225.38583l143.05511 0l0 152.31494l-143.05511 0z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m120.41207 225.38583l143.05511 0l0 152.31494l-143.05511 0z" fill-rule="evenodd"/><path fill="#000000" d="m130.84958 363.46332l0 -13.359375l5.046875 0q1.328125 0 2.03125 0.125q0.96875 0.171875 1.640625 0.640625q0.671875 0.453125 1.078125 1.28125q0.40625 0.828125 0.40625 1.828125q0 1.703125 -1.09375 2.890625q-1.078125 1.171875 -3.921875 1.171875l-3.421875 0l0 5.421875l-1.765625 0zm1.765625 -7.0l3.453125 0q1.71875 0 2.4375 -0.640625q0.71875 -0.640625 0.71875 -1.796875q0 -0.84375 -0.421875 -1.4375q-0.421875 -0.59375 -1.125 -0.78125q-0.4375 -0.125 -1.640625 -0.125l-3.421875 0l0 4.78125zm10.459198 7.0l0 -9.671875l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.875 -0.28125 1.921875l0 5.0625l-1.625 0zm5.618927 -4.84375q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm15.563217 4.84375l0 -1.21875q-0.90625 1.4375 -2.703125 1.4375q-1.15625 0 -2.125 -0.640625q-0.96875 -0.640625 -1.5 -1.78125q-0.53125 -1.140625 -0.53125 -2.625q0 -1.453125 0.484375 -2.625q0.484375 -1.1875 1.4375 -1.8125q0.96875 -0.625 2.171875 -0.625q0.875 0 1.546875 0.375q0.6875 0.359375 1.109375 0.953125l0 -4.796875l1.640625 0l0 13.359375l-1.53125 0zm-5.171875 -4.828125q0 1.859375 0.78125 2.78125q0.78125 0.921875 1.84375 0.921875q1.078125 0 1.828125 -0.875q0.75 -0.890625 0.75 -2.6875q0 -1.984375 -0.765625 -2.90625q-0.765625 -0.9375 -1.890625 -0.9375q-1.078125 0 -1.8125 0.890625q-0.734375 0.890625 -0.734375 2.8125zm15.610092 4.828125l0 -1.421875q-1.125 1.640625 -3.0625 1.640625q-0.859375 0 -1.609375 -0.328125q-0.734375 -0.328125 -1.09375 -0.828125q-0.359375 -0.5 -0.5 -1.21875q-0.109375 -0.46875 -0.109375 -1.53125l0 -5.984375l1.640625 0l0 5.359375q0 1.28125 0.109375 1.734375q0.15625 0.640625 0.65625 1.015625q0.5 0.375 1.234375 0.375q0.734375 0 1.375 -0.375q0.65625 -0.390625 0.921875 -1.03125q0.265625 -0.65625 0.265625 -1.890625l0 -5.1875l1.640625 0l0 9.671875l-1.46875 0zm10.360092 -3.546875l1.609375 0.21875q-0.265625 1.65625 -1.359375 2.609375q-1.078125 0.9375 -2.671875 0.9375q-1.984375 0 -3.1875 -1.296875q-1.203125 -1.296875 -1.203125 -3.71875q0 -1.578125 0.515625 -2.75q0.515625 -1.171875 1.578125 -1.75q1.0625 -0.59375 2.3125 -0.59375q1.578125 0 2.578125 0.796875q1.0 0.796875 1.28125 2.265625l-1.59375 0.234375q-0.234375 -0.96875 -0.8125 -1.453125q-0.578125 -0.5 -1.390625 -0.5q-1.234375 0 -2.015625 0.890625q-0.78125 0.890625 -0.78125 2.8125q0 1.953125 0.75 2.84375q0.75 0.875 1.953125 0.875q0.96875 0 1.609375 -0.59375q0.65625 -0.59375 0.828125 -1.828125zm9.640625 0.4375l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm9.125717 5.765625l0 -9.671875l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.875 -0.28125 1.921875l0 5.0625l-1.625 0z" fill-rule="nonzero"/><path fill="#cfe2f3" d="m374.14697 223.84251l143.05511 0l0 152.31496l-143.05511 0z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m374.14697 223.84251l143.05511 0l0 152.31496l-143.05511 0z" fill-rule="evenodd"/><path fill="#000000" d="m394.11572 357.2325l1.765625 0.453125q-0.5625 2.171875 -2.0 3.328125q-1.4375 1.140625 -3.53125 1.140625q-2.15625 0 -3.515625 -0.875q-1.34375 -0.890625 -2.0625 -2.546875q-0.703125 -1.671875 -0.703125 -3.59375q0 -2.078125 0.796875 -3.625q0.796875 -1.5625 2.265625 -2.359375q1.484375 -0.8125 3.25 -0.8125q2.0 0 3.359375 1.015625q1.375 1.015625 1.90625 2.875l-1.734375 0.40625q-0.46875 -1.453125 -1.359375 -2.109375q-0.875 -0.671875 -2.203125 -0.671875q-1.546875 0 -2.578125 0.734375q-1.03125 0.734375 -1.453125 1.984375q-0.421875 1.234375 -0.421875 2.5625q0 1.703125 0.5 2.96875q0.5 1.265625 1.546875 1.90625q1.046875 0.625 2.265625 0.625q1.484375 0 2.515625 -0.859375q1.03125 -0.859375 1.390625 -2.546875zm3.1292114 -0.15625q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm9.297577 4.84375l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0zm9.719482 -2.890625l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125zm16.3125 2.890625l0 -1.421875q-1.125 1.640625 -3.0625 1.640625q-0.859375 0 -1.609375 -0.328125q-0.734375 -0.328125 -1.09375 -0.828125q-0.359375 -0.5 -0.5 -1.21875q-0.109375 -0.46875 -0.109375 -1.53125l0 -5.984375l1.640625 0l0 5.359375q0 1.28125 0.109375 1.734375q0.15625 0.640625 0.65625 1.015625q0.5 0.375 1.234375 0.375q0.734375 0 1.375 -0.375q0.65625 -0.390625 0.921875 -1.03125q0.265625 -0.65625 0.265625 -1.890625l0 -5.1875l1.640625 0l0 9.671875l-1.46875 0zm4.047577 0l0 -9.671875l1.46875 0l0 1.359375q0.453125 -0.71875 1.203125 -1.140625q0.765625 -0.4375 1.71875 -0.4375q1.078125 0 1.765625 0.453125q0.6875 0.4375 0.96875 1.234375q1.15625 -1.6875 2.984375 -1.6875q1.453125 0 2.21875 0.796875q0.78125 0.796875 0.78125 2.453125l0 6.640625l-1.640625 0l0 -6.09375q0 -0.984375 -0.15625 -1.40625q-0.15625 -0.4375 -0.578125 -0.703125q-0.421875 -0.265625 -0.984375 -0.265625q-1.015625 0 -1.6875 0.6875q-0.671875 0.671875 -0.671875 2.15625l0 5.625l-1.640625 0l0 -6.28125q0 -1.09375 -0.40625 -1.640625q-0.40625 -0.546875 -1.3125 -0.546875q-0.6875 0 -1.28125 0.359375q-0.59375 0.359375 -0.859375 1.0625q-0.25 0.703125 -0.25 2.03125l0 5.015625l-1.640625 0zm22.165802 -3.109375l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm9.125732 5.765625l0 -9.671875l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.875 -0.28125 1.921875l0 5.0625l-1.625 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m55.574802 277.86615l64.85039 23.685028" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m55.574802 277.86615l59.21452 21.626678" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m114.22267 301.0443l4.829338 0.005340576l-3.696045 -3.1083374z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m263.5643 293.85828l110.58267 6.1417236" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m263.5643 293.85828l104.59192 5.8089905" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m368.0646 301.31647l4.622711 -1.397522l-4.439514 -1.9008484z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m517.2126 301.55118l62.204712 -23.685028" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m517.2126 301.55118l56.597473 -21.550018" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m574.39777 281.5448l3.6533203 -3.1584473l-4.8287964 0.07119751z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m579.4173 256.85828l592.7874 0l0 42.015747l-592.7874 0z" fill-rule="evenodd"/><path fill="#000000" d="m589.0423 278.9345q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm15.625732 4.84375l0 -1.421875q-1.125 1.640625 -3.0625 1.640625q-0.859375 0 -1.609375 -0.328125q-0.734375 -0.328125 -1.09375 -0.828125q-0.359375 -0.5 -0.5 -1.21875q-0.109375 -0.46875 -0.109375 -1.53125l0 -5.984375l1.640625 0l0 5.359375q0 1.28125 0.109375 1.734375q0.15625 0.640625 0.65625 1.015625q0.5 0.375 1.234375 0.375q0.734375 0 1.375 -0.375q0.65625 -0.390625 0.921875 -1.03125q0.265625 -0.65625 0.265625 -1.890625l0 -5.1875l1.640625 0l0 9.671875l-1.46875 0zm7.6257324 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m14.971128 245.07086l592.7874 0l0 42.015747l-592.7874 0z" fill-rule="evenodd"/><path fill="#000000" d="m25.205503 260.52213l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm4.144821 0l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078127 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125019 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m120.42519 277.55118l39.02363 0l0 42.015747l-39.02363 0z" fill-rule="evenodd"/><path fill="#000000" d="m130.65958 293.00244l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm4.144821 0l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m374.14697 314.12073l34.4252 0l0 42.015747l-34.4252 0z" fill-rule="evenodd"/><path fill="#000000" d="m384.38135 329.572l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm4.1448364 0l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m216.24803 269.55118l55.2126 0l0 42.015747l-55.2126 0z" fill-rule="evenodd"/><path fill="#000000" d="m225.87303 291.62744q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm15.625717 4.84375l0 -1.421875q-1.125 1.640625 -3.0625 1.640625q-0.859375 0 -1.609375 -0.328125q-0.734375 -0.328125 -1.09375 -0.828125q-0.359375 -0.5 -0.5 -1.21875q-0.109375 -0.46875 -0.109375 -1.53125l0 -5.984375l1.640625 0l0 5.359375q0 1.28125 0.109375 1.734375q0.15625 0.640625 0.65625 1.015625q0.5 0.375 1.234375 0.375q0.734375 0 1.375 -0.375q0.65625 -0.390625 0.921875 -1.03125q0.265625 -0.65625 0.265625 -1.890625l0 -5.1875l1.640625 0l0 9.671875l-1.46875 0zm7.625717 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m368.4252 277.55118l39.02362 0l0 42.015747l-39.02362 0z" fill-rule="evenodd"/><path fill="#000000" d="m378.65958 293.00244l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm4.144806 0l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m478.26248 277.55118l49.196808 0l0 42.015747l-49.196808 0z" fill-rule="evenodd"/><path fill="#000000" d="m487.88748 299.62744q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm15.625702 4.84375l0 -1.421875q-1.125 1.640625 -3.0625 1.640625q-0.859375 0 -1.609375 -0.328125q-0.734375 -0.328125 -1.09375 -0.828125q-0.359375 -0.5 -0.5 -1.21875q-0.109375 -0.46875 -0.109375 -1.53125l0 -5.984375l1.640625 0l0 5.359375q0 1.28125 0.109375 1.734375q0.15625 0.640625 0.65625 1.015625q0.5 0.375 1.234375 0.375q0.734375 0 1.375 -0.375q0.65625 -0.390625 0.921875 -1.03125q0.265625 -0.65625 0.265625 -1.890625l0 -5.1875l1.640625 0l0 9.671875l-1.46875 0zm7.6257324 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m72.24803 253.55118l55.2126 0l0 42.015747l-55.2126 0z" fill-rule="evenodd"/><path fill="#000000" d="m81.21678 280.4712l5.125 -13.359375l1.90625 0l5.46875 13.359375l-2.015625 0l-1.546875 -4.046875l-5.59375 0l-1.46875 4.046875l-1.875 0zm3.859375 -5.484375l4.53125 0l-1.40625 -3.703125q-0.625 -1.6875 -0.9375 -2.765625q-0.265625 1.28125 -0.71875 2.546875l-1.46875 3.921875z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m288.3386 256.85828l55.212585 0l0 42.015747l-55.212585 0z" fill-rule="evenodd"/><path fill="#000000" d="m298.69797 283.77826l0 -13.359375l5.015625 0q1.53125 0 2.453125 0.40625q0.921875 0.40625 1.4375 1.25q0.53125 0.84375 0.53125 1.765625q0 0.859375 -0.46875 1.625q-0.453125 0.75 -1.390625 1.203125q1.203125 0.359375 1.859375 1.21875q0.65625 0.859375 0.65625 2.015625q0 0.9375 -0.40625 1.75q-0.390625 0.796875 -0.984375 1.234375q-0.578125 0.4375 -1.453125 0.671875q-0.875 0.21875 -2.15625 0.21875l-5.09375 0zm1.78125 -7.75l2.875 0q1.1875 0 1.6875 -0.140625q0.671875 -0.203125 1.015625 -0.671875q0.34375 -0.46875 0.34375 -1.171875q0 -0.65625 -0.328125 -1.15625q-0.3125 -0.515625 -0.90625 -0.703125q-0.59375 -0.1875 -2.03125 -0.1875l-2.65625 0l0 4.03125zm0 6.171875l3.3125 0q0.859375 0 1.203125 -0.0625q0.609375 -0.109375 1.015625 -0.359375q0.421875 -0.265625 0.6875 -0.75q0.265625 -0.484375 0.265625 -1.125q0 -0.75 -0.390625 -1.296875q-0.375 -0.546875 -1.0625 -0.765625q-0.671875 -0.234375 -1.953125 -0.234375l-3.078125 0l0 4.59375z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m528.33856 256.85828l55.212646 0l0 42.015747l-55.212646 0z" fill-rule="evenodd"/><path fill="#000000" d="m538.69794 283.77826l0 -13.359375l5.015625 0q1.53125 0 2.453125 0.40625q0.921875 0.40625 1.4375 1.25q0.53125 0.84375 0.53125 1.765625q0 0.859375 -0.46875 1.625q-0.453125 0.75 -1.390625 1.203125q1.203125 0.359375 1.859375 1.21875q0.65625 0.859375 0.65625 2.015625q0 0.9375 -0.40625 1.75q-0.390625 0.796875 -0.984375 1.234375q-0.578125 0.4375 -1.453125 0.671875q-0.875 0.21875 -2.15625 0.21875l-5.09375 0zm1.78125 -7.75l2.875 0q1.1875 0 1.6875 -0.140625q0.671875 -0.203125 1.015625 -0.671875q0.34375 -0.46875 0.34375 -1.171875q0 -0.65625 -0.328125 -1.15625q-0.3125 -0.515625 -0.90625 -0.703125q-0.59375 -0.1875 -2.03125 -0.1875l-2.65625 0l0 4.03125zm0 6.171875l3.3125 0q0.859375 0 1.203125 -0.0625q0.609375 -0.109375 1.015625 -0.359375q0.421875 -0.265625 0.6875 -0.75q0.265625 -0.484375 0.265625 -1.125q0 -0.75 -0.390625 -1.296875q-0.375 -0.546875 -1.0625 -0.765625q-0.671875 -0.234375 -1.953125 -0.234375l-3.078125 0l0 4.59375z" fill-rule="nonzero"/></g></svg>
diff --git a/integration-tests/src/test/scala/chiselTests/util/experimental/algorithm/Bitwise.scala b/integration-tests/src/test/scala/chiselTests/util/experimental/algorithm/Bitwise.scala
new file mode 100644
index 00000000..6c8eb4b4
--- /dev/null
+++ b/integration-tests/src/test/scala/chiselTests/util/experimental/algorithm/Bitwise.scala
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import chisel3._
+import chisel3.util._
+import chiseltest._
+import chiseltest.formal._
+import org.scalatest.flatspec.AnyFlatSpec
+import scala.math.min
+
+class ScanLeftOrTestModule(width: Int) extends Module {
+ val input = IO(Input(UInt(width.W)))
+
+ var lsb = false.B
+ val vec = for(b <- input.asBools) yield {
+ val cur = b || lsb
+ lsb = cur
+ cur
+ }
+ val ref = VecInit(vec).asUInt
+
+ val testee = scanLeftOr(input)
+
+ assert(testee === ref)
+}
+
+class ScanRightOrTestModule(width: Int) extends Module {
+ val input = IO(Input(UInt(width.W)))
+
+ val ref = Reverse(scanLeftOr(Reverse(input)))
+ val testee = scanRightOr(input)
+
+ assert(testee === ref)
+}
+
+class scanOrTest extends AnyFlatSpec with ChiselScalatestTester with Formal {
+ "scanLeftOr" should "compute correctly" in {
+ for(i <- 1 to 16) {
+ verify(new ScanLeftOrTestModule(i), Seq(BoundedCheck(1)))
+ }
+ }
+
+ "scanRightOr" should "compute correctly" in {
+ for(i <- 1 to 16) {
+ verify(new ScanRightOrTestModule(i), Seq(BoundedCheck(1)))
+ }
+ }
+}
diff --git a/src/main/scala/chisel3/experimental/util/algorithm/Bitwise.scala b/src/main/scala/chisel3/experimental/util/algorithm/Bitwise.scala
new file mode 100644
index 00000000..6b4bb8f0
--- /dev/null
+++ b/src/main/scala/chisel3/experimental/util/algorithm/Bitwise.scala
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.util
+
+import chisel3._
+
+/** Map each bit to the logical OR of itself and all bits with lower index
+ *
+ * Here `scanLeft` means "start from the left and iterate to the right, where left is the lowest index", a common operation on arrays and lists.
+ * @example {{{
+ * scanLeftOr("b00001000".U(8.W)) // Returns "b11111000".U
+ * scanLeftOr("b00010100".U(8.W)) // Returns "b11111100".U
+ * scanLeftOr("b00000000".U(8.W)) // Returns "b00000000".U
+ * }}}
+ */
+object scanLeftOr {
+ def apply(data: UInt): UInt = {
+ val width = data.widthOption match {
+ case Some(w) => w
+ case None => throw new IllegalArgumentException("Cannot call scanLeftOr on data with unknown width.")
+ }
+
+ def helper(s: Int, x: UInt): UInt =
+ if (s >= width) x else helper(s + s, x | (x << s)(width - 1, 0))
+ helper(1, data)(width - 1, 0)
+ }
+}
+
+/** Map each bit to the logical OR of itself and all bits with higher index
+ *
+ * Here `scanRight` means "start from the right and iterate to the left, where right is the highest index", a common operation on arrays and lists.
+ * @example {{{
+ * scanRightOr("b00001000".U) // Returns "b00001111".U
+ * scanRightOr("b00010100".U) // Returns "b00011111".U
+ * scanRightOr("b00000000".U) // Returns "b00000000".U
+ * }}}
+ */
+object scanRightOr {
+ def apply(data: UInt): UInt = {
+ val width = data.widthOption match {
+ case Some(w) => w
+ case None => throw new IllegalArgumentException("Cannot call scanRightOr on data with unknown width.")
+ }
+ def helper(s: Int, x: UInt): UInt =
+ if (s >= width) x else helper(s + s, x | (x >> s))
+ helper(1, data)(width - 1, 0)
+ }
+}
diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
index e742fd66..00fa0f9c 100644
--- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
@@ -31,10 +31,15 @@ object TruthTable {
/** Convert a table and default output into a [[TruthTable]]. */
def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = {
- require(table.map(_._1.getWidth).toSet.size == 1, "input width not equal.")
+ val inputWidth = table.map(_._1.getWidth).max
require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.")
val outputWidth = table.map(_._2.getWidth).head
- val mergedTable = table
+ val mergedTable = table.map {
+ // pad input signals if necessary
+ case (in, out) if inputWidth > in.width =>
+ (BitPat.N(inputWidth - in.width) ## in, out)
+ case (in, out) => (in, out)
+ }
.groupBy(_._1.toString)
.map {
case (key, values) =>
diff --git a/src/main/scala/chisel3/verilog.scala b/src/main/scala/chisel3/verilog.scala
index b926a15c..c301ff98 100644
--- a/src/main/scala/chisel3/verilog.scala
+++ b/src/main/scala/chisel3/verilog.scala
@@ -4,7 +4,29 @@ import chisel3.stage.ChiselStage
import firrtl.AnnotationSeq
object getVerilogString {
+
+ /**
+ * Returns a string containing the Verilog for the module specified by
+ * the target.
+ *
+ * @param gen the module to be converted to Verilog
+ * @return a string containing the Verilog for the module specified by
+ * the target
+ */
def apply(gen: => RawModule): String = ChiselStage.emitVerilog(gen)
+
+ /**
+ * Returns a string containing the Verilog for the module specified by
+ * the target accepting arguments and annotations
+ *
+ * @param gen the module to be converted to Verilog
+ * @param args arguments to be passed to the compiler
+ * @param annotations annotations to be passed to the compiler
+ * @return a string containing the Verilog for the module specified by
+ * the target
+ */
+ def apply(gen: => RawModule, args: Array[String] = Array.empty, annotations: AnnotationSeq = Seq.empty): String =
+ (new ChiselStage).emitVerilog(gen, args, annotations)
}
object emitVerilog {
diff --git a/src/test/scala/chiselTests/BulkConnectSpec.scala b/src/test/scala/chiselTests/BulkConnectSpec.scala
new file mode 100644
index 00000000..463122bd
--- /dev/null
+++ b/src/test/scala/chiselTests/BulkConnectSpec.scala
@@ -0,0 +1,106 @@
+package chiselTests
+
+import chisel3._
+import chisel3.util.Decoupled
+import chisel3.stage.ChiselStage
+import chisel3.testers.BasicTester
+
+class BulkConnectSpec extends ChiselPropSpec {
+ property("Chisel connects should emit FIRRTL bulk connects when possible") {
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ val io = IO(new Bundle {
+ val inMono = Input(Vec(4, UInt(8.W)))
+ val outMono = Output(Vec(4, UInt(8.W)))
+ val inBi = Input(Vec(4, UInt(8.W)))
+ val outBi = Output(Vec(4, UInt(8.W)))
+ })
+ io.outMono := io.inMono
+ io.outBi <> io.inBi
+ })
+ chirrtl should include("io.outMono <= io.inMono")
+ chirrtl should include("io.outBi <= io.inBi")
+ }
+
+ property("Chisel connects should not emit FIRRTL bulk connects for Stringly-typed connections") {
+ object Foo {
+ import Chisel._
+ // Chisel._ bundle
+ class BundleParent extends Bundle {
+ val foo = UInt(width = 8)
+ }
+ class BundleChild extends BundleParent {
+ val bar = UInt(width = 8)
+ }
+ }
+
+ import Foo._
+
+ // chisel3._ bundle
+ class MyBundle(child: Boolean) extends Bundle {
+ val fizz = UInt(8.W)
+ val buzz = if (child) new BundleChild else new BundleParent
+ }
+
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ // Checking MonoConnect
+ val in = IO(Input(new MyBundle(true)))
+ val out = IO(Output(new MyBundle(false)))
+ out := in
+
+ // Checking BulkConnect (with Decoupled)
+ val enq = IO(Flipped(Decoupled(new BundleChild)))
+ val deq = IO(Decoupled(new BundleParent))
+ deq <> enq
+ })
+
+ chirrtl should include("out.buzz.foo <= in.buzz.foo")
+ chirrtl shouldNot include("deq <= enq")
+ }
+
+ property("Chisel connects should not emit FIRRTL bulk connects between differing FIRRTL types") {
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ val in = IO(Flipped(new Bundle {
+ val foo = Flipped(new Bundle {
+ val bar = Input(UInt(8.W))
+ })
+ }))
+ val out = IO(Output(new Bundle {
+ val foo = new Bundle {
+ val bar = UInt(8.W)
+ }
+ }))
+ // Both of these connections are legal in Chisel, but in and out do not have the same type
+ out := in
+ out <> in
+ })
+ // out <- in is illegal FIRRTL
+ chirrtl should include("out.foo.bar <= in.foo.bar")
+ }
+
+ property("Chisel connects should not emit a FIRRTL bulk connect for a bidirectional MonoConnect") {
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(UInt(8.W))))
+ val deq = IO(Decoupled(UInt(8.W)))
+
+ // Implicitly create a MonoConnect from enq to a wire
+ // enq is a Decoupled and so has input/output signals
+ // We should not bulk connect in this case
+ val wire = WireDefault(enq)
+ dontTouch(wire)
+ deq <> enq
+ })
+
+ chirrtl shouldNot include("wire <= enq")
+ chirrtl should include("deq <= enq")
+ }
+
+ property("MonoConnect should bulk connect undirectioned internal wires") {
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ val io = IO(new Bundle {})
+ val w1 = Wire(Vec(2, UInt(8.W)))
+ val w2 = Wire(Vec(2, UInt(8.W)))
+ w2 := w1
+ })
+ chirrtl should include("w2 <= w1")
+ }
+}
diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala
index 5dcbbefa..2d34b263 100644
--- a/src/test/scala/chiselTests/BundleSpec.scala
+++ b/src/test/scala/chiselTests/BundleSpec.scala
@@ -3,6 +3,7 @@
package chiselTests
import chisel3._
+import chisel3.util.Decoupled
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
index 8210b120..70dcda48 100644
--- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -74,7 +74,7 @@ object Chisel3Components {
class Chisel3ModuleChiselRecordB extends Chisel3PassthroughModule(Flipped(new ChiselRecord))
}
-class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec {
+class CompatibilityInteroperabilitySpec extends ChiselFlatSpec {
"Modules defined in the Chisel._" should "successfully bulk connect in chisel3._" in {
import chisel3._
diff --git a/src/test/scala/chiselTests/MixedVecSpec.scala b/src/test/scala/chiselTests/MixedVecSpec.scala
index 16efafd4..ee19d653 100644
--- a/src/test/scala/chiselTests/MixedVecSpec.scala
+++ b/src/test/scala/chiselTests/MixedVecSpec.scala
@@ -280,4 +280,20 @@ class MixedVecSpec extends ChiselPropSpec with Utils {
})
}
}
+
+ property("MixedVec connections should emit FIRRTL bulk connects when possible") {
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ val io = IO(new Bundle {
+ val inMono = Input(MixedVec(Seq(UInt(8.W), UInt(16.W), UInt(4.W), UInt(7.W))))
+ val outMono = Output(MixedVec(Seq(UInt(8.W), UInt(16.W), UInt(4.W), UInt(7.W))))
+ val inBi = Input(MixedVec(Seq(UInt(8.W), UInt(16.W), UInt(4.W), UInt(7.W))))
+ val outBi = Output(MixedVec(Seq(UInt(8.W), UInt(16.W), UInt(4.W), UInt(7.W))))
+ })
+ // Explicit upcast avoids weird issue where Scala 2.12 overloading resolution calls version of := accepting Seq[T] instead of normal Data version
+ io.outMono := (io.inMono: Data)
+ io.outBi <> io.inBi
+ })
+ chirrtl should include("io.outMono <= io.inMono @[MixedVecSpec.scala")
+ chirrtl should include("io.outBi <= io.inBi @[MixedVecSpec.scala")
+ }
}
diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala
index 13dbe1e9..b0fece3b 100644
--- a/src/test/scala/chiselTests/Module.scala
+++ b/src/test/scala/chiselTests/Module.scala
@@ -18,6 +18,8 @@ class SimpleIO extends Bundle {
class PlusOne extends Module {
val io = IO(new SimpleIO)
+ val myReg = RegInit(0.U(8.W))
+ dontTouch(myReg)
io.out := io.in + 1.asUInt
}
@@ -267,6 +269,13 @@ class ModuleSpec extends ChiselPropSpec with Utils {
property("getVerilogString(new PlusOne() should produce a valid Verilog string") {
val s = getVerilogString(new PlusOne())
assert(s.contains("assign io_out = io_in + 32'h1"))
+ assert(s.contains("RANDOMIZE_REG_INIT"))
+ }
+
+ property("getVerilogString(new PlusOne() should produce a valid Verilog string with arguments") {
+ val s = getVerilogString(new PlusOne(), Array("--emission-options=disableRegisterRandomization"))
+ assert(s.contains("assign io_out = io_in + 32'h1"))
+ assert(!s.contains("RANDOMIZE_REG_INIT"))
}
property("emitVerilog((new PlusOne()..) shall produce a valid Verilog file in a subfolder") {
diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala
index da3840dd..30b55812 100644
--- a/src/test/scala/chiselTests/RecordSpec.scala
+++ b/src/test/scala/chiselTests/RecordSpec.scala
@@ -27,6 +27,17 @@ trait RecordSpecUtils {
io.out <> io.in
}
+ class ConnectionTestModule(output: => Record, input: => Record) extends Module {
+ val io = IO(new Bundle {
+ val inMono = Input(input)
+ val outMono = Output(output)
+ val inBi = Input(input)
+ val outBi = Output(output)
+ })
+ io.outMono := io.inMono
+ io.outBi <> io.inBi
+ }
+
class RecordSerializationTest extends BasicTester {
val recordType = new CustomBundle("fizz" -> UInt(16.W), "buzz" -> UInt(16.W))
val record = Wire(recordType)
@@ -110,6 +121,14 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
ChiselStage.elaborate { new MyModule(new MyBundle, fooBarType) }
}
+ they should "emit FIRRTL bulk connects when possible" in {
+ val chirrtl = (new ChiselStage).emitChirrtl(
+ gen = new ConnectionTestModule(fooBarType, fooBarType)
+ )
+ chirrtl should include("io.outMono <= io.inMono @[RecordSpec.scala")
+ chirrtl should include("io.outBi <= io.inBi @[RecordSpec.scala")
+ }
+
they should "not allow aliased fields" in {
class AliasedFieldRecord extends Record {
val foo = UInt(8.W)
diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala
index 5fb86001..0010e9ac 100644
--- a/src/test/scala/chiselTests/UIntOps.scala
+++ b/src/test/scala/chiselTests/UIntOps.scala
@@ -199,6 +199,24 @@ class UIntOpsSpec extends ChiselPropSpec with Matchers with Utils {
a[Exception] should be thrownBy extractCause[Exception] { ChiselStage.elaborate(new BadBoolConversion) }
}
+ property("Out-of-bounds extraction from known-width UInts") {
+ a[ChiselException] should be thrownBy extractCause[ChiselException] {
+ ChiselStage.elaborate(new RawModule {
+ val u = IO(Input(UInt(2.W)))
+ u(2, 1)
+ })
+ }
+ }
+
+ property("Out-of-bounds single-bit extraction from known-width UInts") {
+ a[ChiselException] should be thrownBy extractCause[ChiselException] {
+ ChiselStage.elaborate(new RawModule {
+ val u = IO(Input(UInt(2.W)))
+ u(2)
+ })
+ }
+ }
+
property("UIntOps should elaborate") {
ChiselStage.elaborate { new UIntOps }
}
diff --git a/src/test/scala/chiselTests/VecLiteralSpec.scala b/src/test/scala/chiselTests/VecLiteralSpec.scala
index 228f409b..fa97a8c8 100644
--- a/src/test/scala/chiselTests/VecLiteralSpec.scala
+++ b/src/test/scala/chiselTests/VecLiteralSpec.scala
@@ -434,7 +434,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
exc.getMessage should include("field 0 specified with non-literal value UInt")
}
- "vec literals are instantiated on connect" in {
+ "vec literals are instantiated on connect and are not bulk connected" in {
class VecExample5 extends RawModule {
val out = IO(Output(Vec(2, UInt(4.W))))
val bundle = Vec(2, UInt(4.W)).Lit(
@@ -463,13 +463,12 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
out := bundle
}
- "vec literals can contain bundles" in {
+ "vec literals can contain bundles and should not be bulk connected" in {
val chirrtl = (new chisel3.stage.ChiselStage).emitChirrtl(new VecExample, args = Array("--full-stacktrace"))
chirrtl should include("""out[0].bar <= UInt<5>("h16")""")
chirrtl should include("""out[0].foo <= UInt<6>("h2a")""")
chirrtl should include("""out[1].bar <= UInt<2>("h3")""")
chirrtl should include("""out[1].foo <= UInt<3>("h7")""")
-
}
"vec literals can have bundle children" in {
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index 5ef062fa..0285a524 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -103,8 +103,8 @@ class DataViewSpec extends ChiselFlatSpec {
buzz.viewAs[MyBundle] := in
}
val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("fizz.foo <= in.foo")
- chirrtl should include("buzz.foo <= in.foo")
+ chirrtl should include("fizz <= in")
+ chirrtl should include("buzz <= in")
}
it should "handle viewing Vecs as their same concrete type" in {
@@ -116,8 +116,8 @@ class DataViewSpec extends ChiselFlatSpec {
buzz.viewAs[Vec[UInt]] := in
}
val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("fizz[0] <= in[0]")
- chirrtl should include("buzz[0] <= in[0]")
+ chirrtl should include("fizz <= in")
+ chirrtl should include("buzz <= in")
}
it should "handle viewing Vecs as Bundles and vice versa" in {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
index 2c1d2e9e..ec71fe09 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
@@ -4,10 +4,11 @@ package chiselTests.experimental.hierarchy
import _root_.firrtl.annotations._
import chisel3.experimental.{annotate, BaseModule}
-import chisel3.Data
+import chisel3.{Data, MemBase}
import chisel3.experimental.hierarchy.{Definition, Hierarchy, Instance}
-object Annotations {
+// These annotations exist purely for testing purposes
+private[hierarchy] object Annotations {
case class MarkAnnotation(target: IsMember, tag: String) extends SingleTargetAnnotation[IsMember] {
def duplicate(n: IsMember): Annotation = this.copy(target = n)
}
@@ -19,7 +20,12 @@ object Annotations {
extends chisel3.experimental.ChiselAnnotation {
def toFirrtl = if (isAbsolute) MarkAnnotation(d.toAbsoluteTarget, tag) else MarkAnnotation(d.toTarget, tag)
}
+ case class MarkChiselMemAnnotation[T <: Data](m: MemBase[T], tag: String, isAbsolute: Boolean)
+ extends chisel3.experimental.ChiselAnnotation {
+ def toFirrtl = if (isAbsolute) MarkAnnotation(m.toAbsoluteTarget, tag) else MarkAnnotation(m.toTarget, tag)
+ }
def mark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, false))
+ def mark[T <: Data](d: MemBase[T], tag: String): Unit = annotate(MarkChiselMemAnnotation(d, tag, false))
def mark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
def amark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, true))
def amark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
index 63beb394..6ff4a3eb 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
@@ -329,6 +329,39 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
annos should contain(MarkAnnotation("~Top|HasEither>x".rt, "xright"))
annos should contain(MarkAnnotation("~Top|HasEither>y".rt, "yleft"))
}
+ it("3.12: should work on tuple2") {
+ class Top() extends Module {
+ val i = Definition(new HasTuple2())
+ mark(i.xy._1, "x")
+ mark(i.xy._2, "y")
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain(MarkAnnotation("~Top|HasTuple2>x".rt, "x"))
+ annos should contain(MarkAnnotation("~Top|HasTuple2>y".rt, "y"))
+ }
+ it("3.13: should work on Mems/SyncReadMems") {
+ class Top() extends Module {
+ val i = Definition(new HasMems())
+ mark(i.mem, "Mem")
+ mark(i.syncReadMem, "SyncReadMem")
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain(MarkAnnotation("~Top|HasMems>mem".rt, "Mem"))
+ annos should contain(MarkAnnotation("~Top|HasMems>syncReadMem".rt, "SyncReadMem"))
+ }
+ it("3.14: should not create memory ports") {
+ class Top() extends Module {
+ val i = Definition(new HasMems())
+ i.mem(0) := 100.U // should be illegal!
+ }
+ val failure = intercept[ChiselException] {
+ getFirrtlAndAnnos(new Top)
+ }
+ assert(
+ failure.getMessage ==
+ "Cannot create a memory port in a different module (Top) than where the memory is (HasMems)."
+ )
+ }
}
describe("4: toDefinition") {
it("4.0: should work on modules") {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
index 5b78b7cc..fa26cbde 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
@@ -47,6 +47,13 @@ object Examples {
val addOneDef = Seq.fill(3)(Definition(new AddOne))
out := in + 1.U
}
+ @instantiable
+ class AddOneBlackBox extends BlackBox {
+ @public val io = IO(new Bundle {
+ val in = Input(UInt(32.W))
+ val out = Output(UInt(32.W))
+ })
+ }
@instantiable
class AddTwo extends Module {
@@ -200,6 +207,12 @@ object Examples {
@public val y: Either[Bool, UInt] = Left(Wire(Bool()).suggestName("y"))
}
@instantiable
+ class HasTuple2() extends Module {
+ val x = Wire(UInt(3.W))
+ val y = Wire(Bool())
+ @public val xy = (x, y)
+ }
+ @instantiable
class HasVec() extends Module {
@public val x = VecInit(1.U, 2.U, 3.U)
}
@@ -252,4 +265,10 @@ object Examples {
val i10 = Instance(tpDef1)
val i11 = Instance(tpDef1)
}
+
+ @instantiable
+ class HasMems() extends Module {
+ @public val mem = Mem(8, UInt(32.W))
+ @public val syncReadMem = SyncReadMem(8, UInt(32.W))
+ }
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
index 45d1f85f..8d8f7ea5 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
@@ -43,6 +43,29 @@ class InstanceSpec extends ChiselFunSpec with Utils {
val (chirrtl, _) = getFirrtlAndAnnos(new Top)
chirrtl.serialize should include("inst i0 of AddOne")
}
+ it("0.3: BlackBoxes should be supported") {
+ class Top extends Module {
+ val in = IO(Input(UInt(32.W)))
+ val out = IO(Output(UInt(32.W)))
+ val io = IO(new Bundle {
+ val in = Input(UInt(32.W))
+ val out = Output(UInt(32.W))
+ })
+ val definition = Definition(new AddOneBlackBox)
+ val i0 = Instance(definition)
+ val i1 = Instance(definition)
+ i0.io.in := in
+ out := i0.io.out
+ io <> i1.io
+ }
+ val chirrtl = getFirrtlAndAnnos(new Top)._1.serialize
+ chirrtl should include("inst i0 of AddOneBlackBox")
+ chirrtl should include("inst i1 of AddOneBlackBox")
+ chirrtl should include("i0.in <= in")
+ chirrtl should include("out <= i0.out")
+ chirrtl should include("i1.in <= io.in")
+ chirrtl should include("io.out <= i1.out")
+ }
}
describe("1: Annotations on instances in same chisel compilation") {
it("1.0: should work on a single instance, annotating the instance") {
@@ -298,7 +321,18 @@ class InstanceSpec extends ChiselFunSpec with Utils {
annos should contain(MarkAnnotation("~Top|Top/i:HasEither>x".rt, "xright"))
annos should contain(MarkAnnotation("~Top|Top/i:HasEither>y".rt, "yleft"))
}
- it("3.12: should properly support val modifiers") {
+ it("3.12: should work on tuple2") {
+ class Top() extends Module {
+ val i = Instance(Definition(new HasTuple2()))
+ mark(i.xy._1, "x")
+ mark(i.xy._2, "y")
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain(MarkAnnotation("~Top|Top/i:HasTuple2>x".rt, "x"))
+ annos should contain(MarkAnnotation("~Top|Top/i:HasTuple2>y".rt, "y"))
+ }
+
+ it("3.13: should properly support val modifiers") {
class SupClass extends Module {
val value = 10
val overriddenVal = 10
@@ -320,6 +354,16 @@ class InstanceSpec extends ChiselFunSpec with Utils {
@public override final lazy val y: Int = 4
}
}
+ it("3.13: should work with Mems/SyncReadMems") {
+ class Top() extends Module {
+ val i = Instance(Definition(new HasMems()))
+ mark(i.mem, "Mem")
+ mark(i.syncReadMem, "SyncReadMem")
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain(MarkAnnotation("~Top|Top/i:HasMems>mem".rt, "Mem"))
+ annos should contain(MarkAnnotation("~Top|Top/i:HasMems>syncReadMem".rt, "SyncReadMem"))
+ }
}
describe("4: toInstance") {
it("4.0: should work on modules") {
@@ -695,6 +739,51 @@ class InstanceSpec extends ChiselFunSpec with Utils {
annos should contain(e)
}
}
+
+ it("7.4: should work on Views of BlackBoxes") {
+ @instantiable
+ class MyBlackBox extends BlackBox {
+ @public val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ @public val innerView = io.viewAs
+ @public val foo = io.in.viewAs[UInt]
+ @public val bar = io.out.viewAs[UInt]
+ }
+ class Top extends RawModule {
+ val foo = IO(Input(UInt(8.W)))
+ val bar = IO(Output(UInt(8.W)))
+ val i = Instance(Definition(new MyBlackBox))
+ val outerView = i.io.viewAs
+ i.foo := foo
+ bar := i.bar
+ mark(i.foo, "i.foo")
+ mark(i.bar, "i.bar")
+ mark(i.innerView.in, "i.innerView.in")
+ mark(outerView.out, "outerView.out")
+ }
+ val inst = "~Top|Top/i:MyBlackBox"
+ val expectedAnnos = List(
+ s"$inst>in".rt -> "i.foo",
+ s"$inst>out".rt -> "i.bar",
+ s"$inst>in".rt -> "i.innerView.in",
+ s"$inst>out".rt -> "outerView.out"
+ )
+ val expectedLines = List(
+ "i.in <= foo",
+ "bar <= i.out"
+ )
+ val (chirrtl, annos) = getFirrtlAndAnnos(new Top)
+ val text = chirrtl.serialize
+ for (line <- expectedLines) {
+ text should include(line)
+ }
+ for (e <- expectedAnnos.map(MarkAnnotation.tupled)) {
+ annos should contain(e)
+ }
+ }
+
}
describe("8: @instantiable and @public should compose with CloneModuleAsRecord") {
diff --git a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
index 2ef316bb..fa2c6f08 100644
--- a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
+++ b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
@@ -80,4 +80,28 @@ class TruthTableSpec extends AnyFlatSpec {
}
assert(chisel3.stage.ChiselStage.emitChirrtl(new Foo) == chisel3.stage.ChiselStage.emitChirrtl(new Foo))
}
+ "TruthTable" should "accept unknown input width" in {
+ val t = TruthTable(
+ Seq(
+ BitPat(0.U) -> BitPat.dontCare(1),
+ BitPat(1.U) -> BitPat.dontCare(1),
+ BitPat(2.U) -> BitPat.dontCare(1),
+ BitPat(3.U) -> BitPat.dontCare(1),
+ BitPat(4.U) -> BitPat.dontCare(1),
+ BitPat(5.U) -> BitPat.dontCare(1),
+ BitPat(6.U) -> BitPat.dontCare(1),
+ BitPat(7.U) -> BitPat.dontCare(1)
+ ),
+ BitPat.N(1)
+ )
+ assert(t.toString contains "000->?")
+ assert(t.toString contains "001->?")
+ assert(t.toString contains "010->?")
+ assert(t.toString contains "011->?")
+ assert(t.toString contains "100->?")
+ assert(t.toString contains "101->?")
+ assert(t.toString contains "110->?")
+ assert(t.toString contains "111->?")
+ assert(t.toString contains " 0")
+ }
}