summaryrefslogtreecommitdiff
path: root/chiselFrontend
diff options
context:
space:
mode:
authorJim Lawson2016-10-06 11:15:08 -0700
committerJim Lawson2016-10-06 11:15:08 -0700
commitd9e46d06522102634b04a187d5e89fe84b94678a (patch)
tree3f44fc56acc334c1ffa7340583b29ad44ff8740b /chiselFrontend
parentf98171296f821034cf66ace070bcf179183e833d (diff)
parent7aea39d4deac62d5477904f4bf4381c3482c41d0 (diff)
Merge branch 'master' into buildinfo
Diffstat (limited to 'chiselFrontend')
-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
9 files changed, 138 insertions, 38 deletions
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)
}