summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt24
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala16
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Assert.scala13
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Binding.scala36
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Bits.scala5
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala9
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala79
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Mem.scala8
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Error.scala8
-rw-r--r--project/plugins.sbt3
-rw-r--r--src/main/scala/chisel3/Driver.scala9
-rw-r--r--src/main/scala/chisel3/util/TransitName.scala16
-rw-r--r--src/test/scala/chiselTests/CompileOptionsTest.scala4
-rw-r--r--src/test/scala/chiselTests/ComplexAssign.scala2
-rw-r--r--src/test/scala/chiselTests/IOCompatibility.scala16
-rw-r--r--src/test/scala/chiselTests/MultiAssign.scala5
-rw-r--r--src/test/scala/cookbook/Bundle2UInt.scala31
-rw-r--r--src/test/scala/cookbook/CookbookSpec.scala25
-rw-r--r--src/test/scala/cookbook/UInt2Bundle.scala30
-rw-r--r--src/test/scala/cookbook/UInt2VecOfBool.scala29
-rw-r--r--src/test/scala/cookbook/VecOfBool2UInt.scala28
22 files changed, 337 insertions, 61 deletions
diff --git a/build.sbt b/build.sbt
index fe22c95a..f4aae4aa 100644
--- a/build.sbt
+++ b/build.sbt
@@ -6,15 +6,23 @@ site.includeScaladoc()
ghpages.settings
+import UnidocKeys._
+
+lazy val customUnidocSettings = unidocSettings ++ Seq (
+ doc in Compile := (doc in ScalaUnidoc).value,
+ target in unidoc in ScalaUnidoc := crossTarget.value / "api"
+)
+
lazy val commonSettings = Seq (
organization := "edu.berkeley.cs",
version := "3.1-SNAPSHOT",
git.remoteRepo := "git@github.com:ucb-bar/chisel3.git",
+ autoAPIMappings := true,
scalaVersion := "2.11.7"
)
lazy val chiselSettings = Seq (
- name := "Chisel3",
+ name := "chisel3",
publishMavenStyle := true,
publishArtifact in Test := false,
@@ -50,8 +58,8 @@ lazy val chiselSettings = Seq (
},
resolvers ++= Seq(
- "Sonatype Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots",
- "Sonatype Releases" at "http://oss.sonatype.org/content/repositories/releases"
+ Resolver.sonatypeRepo("snapshots"),
+ Resolver.sonatypeRepo("releases")
),
/* Bumping "com.novocode" % "junit-interface" % "0.11", causes DelayTest testSeqReadBundle to fail
@@ -113,18 +121,16 @@ lazy val chisel = (project in file(".")).
mappings in (Compile, packageSrc) += { ((sourceManaged in Compile).value / "sbt-buildinfo" / "BuildInfo.scala") -> "BuildInfo.scala" }
).
settings(commonSettings: _*).
+ settings(customUnidocSettings: _*).
settings(chiselSettings: _*).
dependsOn(coreMacros).
dependsOn(chiselFrontend).
settings(
+ aggregate in doc := false,
// Include macro classes, resources, and sources main jar.
mappings in (Compile, packageBin) <++= mappings in (coreMacros, Compile, packageBin),
mappings in (Compile, packageSrc) <++= mappings in (coreMacros, Compile, packageSrc),
mappings in (Compile, packageBin) <++= mappings in (chiselFrontend, Compile, packageBin),
mappings in (Compile, packageSrc) <++= mappings in (chiselFrontend, Compile, packageSrc)
- )
-
-// This is ugly. There must be a better way.
-publish <<= (publish) dependsOn (publish in coreMacros, publish in chiselFrontend)
-
-publishLocal <<= (publishLocal) dependsOn (publishLocal in coreMacros, publishLocal in chiselFrontend)
+ ).
+ aggregate(coreMacros, chiselFrontend)
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 5cec54c2..9d8a9061 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -9,7 +9,7 @@ import scala.language.experimental.macros
import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
-import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform}
+import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform, UnlocatableSourceInfo}
/** An abstract class for data types that solely consist of (are an aggregate
* of) other Data objects.
@@ -17,6 +17,8 @@ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransfo
sealed abstract class Aggregate extends Data {
private[core] def cloneTypeWidth(width: Width): this.type = cloneType
private[core] def width: Width = flatten.map(_.width).reduce(_ + _)
+ private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
+ pushCommand(BulkConnect(sourceInfo, this.lref, that.lref))
}
object Vec {
@@ -113,6 +115,15 @@ object Vec {
def do_fill[T <: Data](n: Int)(gen: => T)(implicit sourceInfo: SourceInfo): Vec[T] =
apply(Seq.fill(n)(gen))
+
+ /** Truncate an index to implement modulo-power-of-2 addressing. */
+ private[core] def truncateIndex(idx: UInt, n: Int)(implicit sourceInfo: SourceInfo): UInt = {
+ val w = BigInt(n-1).bitLength
+ if (n <= 1) UInt(0)
+ else if (idx.width.known && idx.width.get <= w) idx
+ else if (idx.width.known) idx(w-1,0)
+ else Wire(UInt(width = w), init = idx)
+ }
}
/** A vector (array) of [[Data]] elements. Provides hardware versions of various
@@ -178,7 +189,8 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int)
def apply(idx: UInt): T = {
Binding.checkSynthesizable(idx ,s"'idx' ($idx)")
val port = sample_element.chiselCloneType
- port.setRef(this, idx) //TODO(twigg): This is a bit too magical
+ val i = Vec.truncateIndex(idx, length)(UnlocatableSourceInfo)
+ port.setRef(this, i)
// Bind each element of port to being whatever the base type is
// Using the head element as the sample_element
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala
index db62f4a8..4782a845 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala
@@ -24,21 +24,22 @@ object assert { // scalastyle:ignore object.name
*
* @param cond condition, assertion fires (simulation fails) when false
* @param message optional message to print when the assertion fires
+ * @param data optional bits to print in the message formatting
*
* @note currently cannot be used in core Chisel / libraries because macro
* defs need to be compiled first and the SBT project is not set up to do
* that
*/
// Macros currently can't take default arguments, so we need two functions to emulate defaults.
- def apply(cond: Bool, message: String)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl_msg
+ def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl_msg_data
def apply(cond: Bool)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl
- def apply_impl_msg(c: Context)(cond: c.Tree, message: c.Tree)(sourceInfo: c.Tree): c.Tree = {
+ def apply_impl_msg_data(c: Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree): c.Tree = {
import c.universe._
val p = c.enclosingPosition
val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}"
val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do"))
- q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message))($sourceInfo)"
+ q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message), ..$data)($sourceInfo)"
}
def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: c.Tree): c.Tree = {
@@ -49,11 +50,11 @@ object assert { // scalastyle:ignore object.name
q"$apply_impl_do($cond, $condStr, _root_.scala.None)($sourceInfo)"
}
- def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) {
+ def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo) {
when (!(cond || Builder.forcedModule.reset)) {
message match {
- case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n")
- case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n")
+ case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n", data:_*)
+ case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n", data:_*)
}
pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), 1))
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
index 5378f3ae..467cb4eb 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
@@ -53,6 +53,7 @@ object Binding {
case class BindingException(message: String) extends Exception(message)
def AlreadyBoundException(binding: String) = BindingException(s": Already bound to $binding")
def NotSynthesizableException = BindingException(s": Not bound to synthesizable node, currently only Type description")
+ def MissingIOWrapperException = BindingException(": Missing IO() wrapper")
// This recursively walks down the Data tree to look at all the leaf 'Element's
// Will build up an error string in case something goes wrong
@@ -138,6 +139,29 @@ object Binding {
}
}
}
+
+ /** Diagnose a binding error caused by a missing IO() wrapper.
+ * @param element the element triggering the binding error.
+ * @return true if the element is a member of the module's io but ioDefined is false.
+ */
+ def isMissingIOWrapper(element: Element): Boolean = {
+ element._parent match {
+ case None => false
+ case Some(x: Module) => {
+ // If the IO() wrapper has been executed, it isn't missing.
+ if (x.ioDefined) {
+ false
+ } else {
+ // TODO: We should issue the message only once, and if we get here,
+ // we know the wrapper is missing, whether or not the element is a member of io.
+ // But if it's not an io element, we want to issue the complementary "unbound" error.
+ // Revisit this when we collect error messages instead of throwing exceptions.
+ x.io.flatten.contains(element)
+ }
+ }
+ }
+ }
+
try walkToBinding(
target,
element => element.binding match {
@@ -145,10 +169,16 @@ object Binding {
case binding =>
// The following kludge is an attempt to provide backward compatibility
// It should be done at at higher level.
- if ((forcedModule.compileOptions.requireIOWrap || !elementOfIO(element)))
- throw NotSynthesizableException
- else
+ if ((forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) {
+ // Generate a better error message if this is a result of a missing IO() wrapper.
+ if (isMissingIOWrapper(element)) {
+ throw MissingIOWrapperException
+ } else {
+ throw NotSynthesizableException
+ }
+ } else {
Binding.bind(element, PortBinder(element._parent.get), "Error: IO")
+ }
}
)
catch {
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala
index 24abbdba..741f6aee 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala
@@ -5,7 +5,7 @@ package chisel3.core
import scala.language.experimental.macros
import chisel3.internal._
-import chisel3.internal.Builder.pushOp
+import chisel3.internal.Builder.{pushCommand, pushOp}
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform,
UIntTransform, MuxTransform}
@@ -40,6 +40,9 @@ abstract class Element(private[core] val width: Width) extends Data {
private[chisel3] final def allElements: Seq[Element] = Seq(this)
def widthKnown: Boolean = width.known
def name: String = getRef.name
+
+ private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
+ pushCommand(Connect(sourceInfo, this.lref, that.ref))
}
/** A data type for values represented by a single bitvector. Provides basic
diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
index 0e66a241..4dea39b5 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
@@ -17,6 +17,11 @@ trait CompileOptions {
val dontTryConnectionsSwapped: Boolean
// If connection directionality is not explicit, do not use heuristics to attempt to determine it.
val dontAssumeDirectionality: Boolean
+ // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used
+ // instead of Flipped, Input, or Output.
+ val deprecateOldDirectionMethods: Boolean
+ // Check that referenced Data have actually been declared.
+ val checkSynthesizable: Boolean
}
object CompileOptions {
@@ -34,6 +39,8 @@ object ExplicitCompileOptions {
val requireIOWrap = false
val dontTryConnectionsSwapped = false
val dontAssumeDirectionality = false
+ val deprecateOldDirectionMethods = false
+ val checkSynthesizable = false
}
// Collection of "strict" connection compile options, preferred for new code.
@@ -44,5 +51,7 @@ object ExplicitCompileOptions {
val requireIOWrap = true
val dontTryConnectionsSwapped = true
val dontAssumeDirectionality = true
+ val deprecateOldDirectionMethods = true
+ val checkSynthesizable = true
}
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
index 3f21a34c..bd2e9065 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
@@ -104,12 +104,21 @@ object Data {
}
implicit class AddDirectionToData[T<:Data](val target: T) extends AnyVal {
- @deprecated("Input(Data) should be used over Data.asInput", "gchisel")
- def asInput: T = Input(target)
- @deprecated("Output(Data) should be used over Data.asOutput", "gchisel")
- def asOutput: T = Output(target)
- @deprecated("Flipped(Data) should be used over Data.flip", "gchisel")
- def flip(): T = Flipped(target)
+ def asInput(implicit opts: CompileOptions): T = {
+ if (opts.deprecateOldDirectionMethods)
+ Builder.deprecated("Input(Data) should be used over Data.asInput")
+ Input(target)
+ }
+ def asOutput(implicit opts: CompileOptions): T = {
+ if (opts.deprecateOldDirectionMethods)
+ Builder.deprecated("Output(Data) should be used over Data.asOutput")
+ Output(target)
+ }
+ def flip()(implicit opts: CompileOptions): T = {
+ if (opts.deprecateOldDirectionMethods)
+ Builder.deprecated("Flipped(Data) should be used over Data.flip")
+ Flipped(target)
+ }
}
}
@@ -126,27 +135,35 @@ abstract class Data extends HasId {
private[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
throwException(s"cannot connect ${this} and ${that}")
private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = {
- Binding.checkSynthesizable(this, s"'this' ($this)")
- Binding.checkSynthesizable(that, s"'that' ($that)")
- try {
- MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule)
- } catch {
- case MonoConnect.MonoConnectException(message) =>
- throwException(
- s"Connection between sink ($this) and source ($that) failed @$message"
- )
+ if (connectCompileOptions.checkSynthesizable) {
+ Binding.checkSynthesizable(this, s"'this' ($this)")
+ Binding.checkSynthesizable(that, s"'that' ($that)")
+ try {
+ MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule)
+ } catch {
+ case MonoConnect.MonoConnectException(message) =>
+ throwException(
+ s"Connection between sink ($this) and source ($that) failed @$message"
+ )
+ }
+ } else {
+ this legacyConnect that
}
}
private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = {
- Binding.checkSynthesizable(this, s"'this' ($this)")
- Binding.checkSynthesizable(that, s"'that' ($that)")
- try {
- BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule)
- } catch {
- case BiConnect.BiConnectException(message) =>
- throwException(
- s"Connection between left ($this) and source ($that) failed @$message"
- )
+ if (connectCompileOptions.checkSynthesizable) {
+ Binding.checkSynthesizable(this, s"'this' ($this)")
+ Binding.checkSynthesizable(that, s"'that' ($that)")
+ try {
+ BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule)
+ } catch {
+ case BiConnect.BiConnectException(message) =>
+ throwException(
+ s"Connection between left ($this) and source ($that) failed @$message"
+ )
+ }
+ } else {
+ this legacyConnect that
}
}
private[chisel3] def lref: Node = Node(this)
@@ -154,8 +171,21 @@ abstract class Data extends HasId {
private[core] def cloneTypeWidth(width: Width): this.type
private[chisel3] def toType: String
private[core] def width: Width
+ private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit
+ /** cloneType must be defined for any Chisel object extending Data.
+ * It is responsible for constructing a basic copy of the object being cloned.
+ * If cloneType needs to recursively clone elements of an object, it should call
+ * the cloneType methods on those elements.
+ * @return a copy of the object.
+ */
def cloneType: this.type
+
+ /** chiselCloneType is called at the top-level of a clone chain.
+ * It calls the client's cloneType() method to construct a basic copy of the object being cloned,
+ * then performs any fixups required to reconstruct the appropriate core state of the cloned object.
+ * @return a copy of the object with appropriate core state.
+ */
def chiselCloneType: this.type = {
// Call the user-supplied cloneType method
val clone = this.cloneType
@@ -163,6 +193,7 @@ abstract class Data extends HasId {
//TODO(twigg): Do recursively for better error messages
for((clone_elem, source_elem) <- clone.allElements zip this.allElements) {
clone_elem.binding = UnboundBinding(source_elem.binding.direction)
+ Data.setFirrtlDirection(clone_elem, Data.getFirrtlDirection(source_elem))
}
clone
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala
index b24d463a..9cd5a4d8 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala
@@ -38,7 +38,10 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi
/** Creates a read accessor into the memory with static addressing. See the
* class documentation of the memory for more detailed information.
*/
- def apply(idx: Int): T = apply(UInt(idx))
+ def apply(idx: Int): T = {
+ require(idx >= 0 && idx < length)
+ apply(UInt(idx))
+ }
/** Creates a read/write accessor into the memory with dynamic addressing.
* See the class documentation of the memory for more detailed information.
@@ -85,10 +88,11 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi
private def makePort(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection): T = {
Binding.checkSynthesizable(idx, s"'idx' ($idx)")
+ val i = Vec.truncateIndex(idx, length)(sourceInfo)
val port = pushCommand(
DefMemPort(sourceInfo,
- t.chiselCloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock))
+ t.chiselCloneType, Node(this), dir, i.ref, Node(i._parent.get.clock))
).id
// Bind each element of port to being a MemoryPort
Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t")
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
index 8d376810..12cc840e 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
@@ -173,6 +173,8 @@ private[chisel3] object Builder {
def errors: ErrorLog = dynamicContext.errors
def error(m: => String): Unit = errors.error(m)
+ def warning(m: => String): Unit = errors.warning(m)
+ def deprecated(m: => String): Unit = errors.deprecated(m)
def build[T <: Module](f: => T): Circuit = {
dynamicContextVar.withValue(Some(new DynamicContext())) {
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
index 7ae0580f..c5c67da4 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
@@ -25,6 +25,10 @@ private[chisel3] class ErrorLog {
def warning(m: => String): Unit =
errors += new Warning(m, getUserLineNumber)
+ /** Log a deprecation warning message */
+ def deprecated(m: => String): Unit =
+ errors += new DeprecationWarning(m, getUserLineNumber)
+
/** Emit an informational message */
def info(m: String): Unit =
println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None)) // scalastyle:ignore regex
@@ -86,6 +90,10 @@ private class Warning(msg: => String, line: Option[StackTraceElement]) extends L
def format: String = tag("warn", Console.YELLOW)
}
+private class DeprecationWarning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("warn", Console.CYAN)
+}
+
private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
def format: String = tag("info", Console.MAGENTA)
}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 70e12de8..5ff66b4f 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -15,3 +15,6 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.4")
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.8.2")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1")
+
+addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.3.3")
+
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index e91b40b4..03f8547e 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -87,14 +87,17 @@ trait BackendCompilationUtilities {
def executeExpectingFailure(
prefix: String,
dir: File,
- assertionMsg: String = "Assertion failed"): Boolean = {
+ assertionMsg: String = ""): Boolean = {
var triggered = false
+ val assertionMessageSupplied = assertionMsg != ""
val e = Process(s"./V${prefix}", dir) !
ProcessLogger(line => {
- triggered = triggered || line.contains(assertionMsg)
+ triggered = triggered || (assertionMessageSupplied && line.contains(assertionMsg))
System.out.println(line) // scalastyle:ignore regex
})
- triggered
+ // Fail if a line contained an assertion or if we get a non-zero exit code
+ // or, we get a SIGABRT (assertion failure) and we didn't provide a specific assertion message
+ triggered || (e != 0 && (e != 134 || !assertionMessageSupplied))
}
def executeExpectingSuccess(prefix: String, dir: File): Boolean = {
diff --git a/src/main/scala/chisel3/util/TransitName.scala b/src/main/scala/chisel3/util/TransitName.scala
index ce6cb60f..a3220a13 100644
--- a/src/main/scala/chisel3/util/TransitName.scala
+++ b/src/main/scala/chisel3/util/TransitName.scala
@@ -5,14 +5,16 @@ package chisel3.util
import chisel3._
import internal.HasId
+/**
+ * The purpose of TransitName is to allow a library to 'move' a name
+ * call to a more appropriate place.
+ * For example, a library factory function may create a module and return
+ * the io. The only user-exposed field is that given IO, which can't use
+ * any name supplied by the user. This can add a hook so that the supplied
+ * name then names the Module.
+ * See Queue companion object for working example
+ */
object TransitName {
- // The purpose of this is to allow a library to 'move' a name call to a more
- // appropriate place.
- // For example, a library factory function may create a module and return
- // the io. The only user-exposed field is that given IO, which can't use
- // any name supplied by the user. This can add a hook so that the supplied
- // name then names the Module.
- // See Queue companion object for working example
def apply[T<:HasId](from: T, to: HasId): T = {
from.addPostnameHook((given_name: String) => {to.suggestName(given_name)})
from
diff --git a/src/test/scala/chiselTests/CompileOptionsTest.scala b/src/test/scala/chiselTests/CompileOptionsTest.scala
index 83077544..57ceff3f 100644
--- a/src/test/scala/chiselTests/CompileOptionsTest.scala
+++ b/src/test/scala/chiselTests/CompileOptionsTest.scala
@@ -22,6 +22,8 @@ class CompileOptionsSpec extends ChiselFlatSpec {
val requireIOWrap = false
val dontTryConnectionsSwapped = true
val dontAssumeDirectionality = true
+ val deprecateOldDirectionMethods = true
+ val checkSynthesizable = true
}
class SmallBundle extends Bundle {
@@ -265,6 +267,8 @@ class CompileOptionsSpec extends ChiselFlatSpec {
val requireIOWrap = false
val dontTryConnectionsSwapped = true
val dontAssumeDirectionality = true
+ val deprecateOldDirectionMethods = false
+ val checkSynthesizable = true
}
}
diff --git a/src/test/scala/chiselTests/ComplexAssign.scala b/src/test/scala/chiselTests/ComplexAssign.scala
index 0a1f31cc..c5a23f82 100644
--- a/src/test/scala/chiselTests/ComplexAssign.scala
+++ b/src/test/scala/chiselTests/ComplexAssign.scala
@@ -11,7 +11,7 @@ import chisel3.util._
class Complex[T <: Data](val re: T, val im: T) extends Bundle {
override def cloneType: this.type =
- new Complex(re.chiselCloneType, im.chiselCloneType).asInstanceOf[this.type]
+ new Complex(re.cloneType, im.cloneType).asInstanceOf[this.type]
}
class ComplexAssign(w: Int) extends Module {
diff --git a/src/test/scala/chiselTests/IOCompatibility.scala b/src/test/scala/chiselTests/IOCompatibility.scala
index 7bf3dded..552fe776 100644
--- a/src/test/scala/chiselTests/IOCompatibility.scala
+++ b/src/test/scala/chiselTests/IOCompatibility.scala
@@ -3,6 +3,8 @@
package chiselTests
import chisel3._
+import chisel3.core.Binding.BindingException
+import org.scalatest._
class IOCSimpleIO extends Bundle {
val in = Input(UInt(width=32))
@@ -33,7 +35,7 @@ class IOCModuleWire extends Module {
io.out := inc.out
}
-class IOCompatibilitySpec extends ChiselPropSpec {
+class IOCompatibilitySpec extends ChiselPropSpec with Matchers {
property("IOCModuleVec should elaborate") {
elaborate { new IOCModuleVec(2) }
@@ -42,4 +44,16 @@ class IOCompatibilitySpec extends ChiselPropSpec {
property("IOCModuleWire should elaborate") {
elaborate { new IOCModuleWire }
}
+
+
+ class IOUnwrapped extends Module {
+ val io = new IOCSimpleIO
+ io.out := io.in
+ }
+
+ property("Unwrapped IO should generate an exception") {
+ a [BindingException] should be thrownBy {
+ elaborate(new IOUnwrapped)
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/MultiAssign.scala b/src/test/scala/chiselTests/MultiAssign.scala
index fa4c4898..397ea4c2 100644
--- a/src/test/scala/chiselTests/MultiAssign.scala
+++ b/src/test/scala/chiselTests/MultiAssign.scala
@@ -9,7 +9,8 @@ import chisel3.testers.BasicTester
import chisel3.util._
class LastAssignTester() extends BasicTester {
- val cnt = Counter(2)
+ val countOnClockCycles = Bool(true)
+ val (cnt, wrap) = Counter(countOnClockCycles,2)
val test = Wire(UInt.width(4))
assert(test === 7.U) // allow read references before assign references
@@ -20,7 +21,7 @@ class LastAssignTester() extends BasicTester {
test := 7.U
assert(test === 7.U) // this obviously should work
- when(cnt.value === 1.U) {
+ when(cnt === 1.U) {
stop()
}
}
diff --git a/src/test/scala/cookbook/Bundle2UInt.scala b/src/test/scala/cookbook/Bundle2UInt.scala
new file mode 100644
index 00000000..d74218a8
--- /dev/null
+++ b/src/test/scala/cookbook/Bundle2UInt.scala
@@ -0,0 +1,31 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+
+/* ### How do I create a UInt from an instance of a Bundle?
+ *
+ * Call asUInt on the Bundle instance
+ */
+class Bundle2UInt extends CookbookTester(0) {
+ // Example
+ class MyBundle extends Bundle {
+ val foo = UInt(width = 4)
+ val bar = UInt(width = 4)
+ }
+ val bundle = Wire(new MyBundle)
+ bundle.foo := UInt(0xc)
+ bundle.bar := UInt(0x3)
+ val uint = bundle.asUInt
+ printf(p"$uint") // 195
+
+ // Test
+ assert(uint === UInt(0xc3))
+}
+
+class Bundle2UIntSpec extends CookbookSpec {
+ "Bundle2UInt" should "work" in {
+ assertTesterPasses { new Bundle2UInt }
+ }
+}
diff --git a/src/test/scala/cookbook/CookbookSpec.scala b/src/test/scala/cookbook/CookbookSpec.scala
new file mode 100644
index 00000000..b244f3cf
--- /dev/null
+++ b/src/test/scala/cookbook/CookbookSpec.scala
@@ -0,0 +1,25 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+import chisel3.util._
+import chisel3.testers.BasicTester
+
+import chiselTests.ChiselFlatSpec
+
+/** Tester for concise cookbook tests
+ *
+ * Provides a length of test after which the test will pass
+ */
+abstract class CookbookTester(length: Int) extends BasicTester {
+ require(length >= 0, "Simulation length must be non-negative!")
+
+ // No IO allowed, cookbook tests must be self-contained
+ override final val io = new Bundle { }
+
+ val (cycle, done) = Counter(Bool(true), length)
+ when (done) { stop() }
+}
+
+abstract class CookbookSpec extends ChiselFlatSpec
diff --git a/src/test/scala/cookbook/UInt2Bundle.scala b/src/test/scala/cookbook/UInt2Bundle.scala
new file mode 100644
index 00000000..fbf7fe8a
--- /dev/null
+++ b/src/test/scala/cookbook/UInt2Bundle.scala
@@ -0,0 +1,30 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+
+/* ### How do I create a Bundle from a UInt?
+ *
+ * On an instance of the Bundle, call the method fromBits with the UInt as the argument
+ */
+class UInt2Bundle extends CookbookTester(0) {
+ // Example
+ class MyBundle extends Bundle {
+ val foo = UInt(width = 4)
+ val bar = UInt(width = 4)
+ }
+ val uint = UInt(0xb4)
+ val bundle = (new MyBundle).fromBits(uint)
+ printf(p"$bundle") // Bundle(foo -> 11, bar -> 4)
+
+ // Test
+ assert(bundle.foo === UInt(0xb))
+ assert(bundle.bar === UInt(0x4))
+}
+
+class UInt2BundleSpec extends CookbookSpec {
+ "UInt2Bundle" should "work" in {
+ assertTesterPasses { new UInt2Bundle }
+ }
+}
diff --git a/src/test/scala/cookbook/UInt2VecOfBool.scala b/src/test/scala/cookbook/UInt2VecOfBool.scala
new file mode 100644
index 00000000..ad4a0334
--- /dev/null
+++ b/src/test/scala/cookbook/UInt2VecOfBool.scala
@@ -0,0 +1,29 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+
+/* ### How do I create a Vec of Bools from a UInt?
+ *
+ * Use the builtin function [[chisel3.core.Bits.toBools]] to create a Scala Seq of Bool,
+ * then wrap the resulting Seq in Vec(...)
+ */
+class UInt2VecOfBool extends CookbookTester(0) {
+ // Example
+ val uint = UInt(0xc)
+ val vec = Vec(uint.toBools)
+ printf(p"$vec") // Vec(0, 0, 1, 1)
+
+ // Test
+ assert(vec(0) === Bool(false))
+ assert(vec(1) === Bool(false))
+ assert(vec(2) === Bool(true))
+ assert(vec(3) === Bool(true))
+}
+
+class UInt2VecOfBoolSpec extends CookbookSpec {
+ "UInt2VecOfBool" should "work" in {
+ assertTesterPasses { new UInt2VecOfBool }
+ }
+}
diff --git a/src/test/scala/cookbook/VecOfBool2UInt.scala b/src/test/scala/cookbook/VecOfBool2UInt.scala
new file mode 100644
index 00000000..5852120c
--- /dev/null
+++ b/src/test/scala/cookbook/VecOfBool2UInt.scala
@@ -0,0 +1,28 @@
+// See LICENSE for license details.
+
+package cookbook
+
+import chisel3._
+
+/* ### How do I create a UInt from a Vec of Bool?
+ *
+ * Use the builtin function asUInt
+ */
+class VecOfBool2UInt extends CookbookTester(0) {
+ // Example
+ val vec = Vec(Bool(true), Bool(false), Bool(true), Bool(true))
+ val uint = vec.asUInt
+ printf(p"$uint") // 13
+
+ /* Test
+ *
+ * (remember leftmost Bool in Vec is low order bit)
+ */
+ assert(UInt(0xd) === uint)
+}
+
+class VecOfBool2UIntSpec extends CookbookSpec {
+ "VecOfBool2UInt" should "work" in {
+ assertTesterPasses { new VecOfBool2UInt }
+ }
+}