summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Chen2018-11-26 09:47:28 -0800
committerSchuyler Eldridge2018-11-26 12:47:28 -0500
commitab951049c2c60402e2318ba863520d4a16c8288d (patch)
tree496a62cb509f06711a01795bca7eafc8ae260a8b
parentdd82374f79005a2998b016712f0aec07775eb506 (diff)
Trim Stack Trace (#931)
- Trim stack trace to show better, reduced information to the user - Add --full-stacktrace to FIRRTL option to show full stack trace
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Attach.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala3
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Binding.scala3
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala3
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Error.scala62
-rw-r--r--src/main/scala/chisel3/ChiselExecutionOptions.scala9
-rw-r--r--src/main/scala/chisel3/Driver.scala118
-rw-r--r--src/test/scala/chiselTests/DontTouchSpec.scala2
9 files changed, 132 insertions, 72 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 9a2e9a38..5563092e 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -507,7 +507,7 @@ trait IgnoreSeqInBundle {
override def ignoreSeq: Boolean = true
}
-class AutoClonetypeException(message: String) extends ChiselException(message, null)
+class AutoClonetypeException(message: String) extends ChiselException(message)
/** Base class for data types defined as a bundle of other data types.
*
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Attach.scala b/chiselFrontend/src/main/scala/chisel3/core/Attach.scala
index edc0a7c9..b3096fd5 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Attach.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Attach.scala
@@ -9,7 +9,7 @@ import chisel3.internal.sourceinfo.{SourceInfo}
object attach { // scalastyle:ignore object.name
// Exceptions that can be generated by attach
- case class AttachException(message: String) extends Exception(message)
+ case class AttachException(message: String) extends ChiselException(message)
def ConditionalAttachException =
AttachException(": Conditional attach is not allowed!")
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
index 1dcb968d..ad7ba98a 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
@@ -2,6 +2,7 @@
package chisel3.core
+import chisel3.internal.ChiselException
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.{Connect, DefInvalid}
import scala.language.experimental.macros
@@ -23,7 +24,7 @@ import chisel3.internal.sourceinfo._
object BiConnect {
// These are all the possible exceptions that can be thrown.
- case class BiConnectException(message: String) extends Exception(message)
+ case class BiConnectException(message: String) extends ChiselException(message)
// These are from element-level connection
def BothDriversException =
BiConnectException(": Both Left and Right are drivers")
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
index b3b754de..60235477 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
@@ -1,10 +1,11 @@
package chisel3.core
+import chisel3.internal.ChiselException
import chisel3.internal.Builder.{forcedModule}
import chisel3.internal.firrtl.LitArg
object Binding {
- class BindingException(message: String) extends Exception(message)
+ class BindingException(message: String) extends ChiselException(message)
/** A function expected a Chisel type but got a hardware object
*/
case class ExpectedChiselTypeException(message: String) extends BindingException(message)
diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
index c9420ba7..d4c80405 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
@@ -2,6 +2,7 @@
package chisel3.core
+import chisel3.internal.ChiselException
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.{Connect, DefInvalid}
import scala.language.experimental.macros
@@ -33,7 +34,7 @@ import chisel3.internal.sourceinfo.SourceInfo
object MonoConnect {
// These are all the possible exceptions that can be thrown.
- case class MonoConnectException(message: String) extends Exception(message)
+ case class MonoConnectException(message: String) extends ChiselException(message)
// These are from element-level connection
def UnreadableSourceException =
MonoConnectException(": Source is unreadable from current module.")
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
index 2346181a..07f4db73 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
@@ -6,7 +6,38 @@ import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import chisel3.core._
-class ChiselException(message: String, cause: Throwable) extends Exception(message, cause)
+class ChiselException(message: String, cause: Throwable = null) extends Exception(message, cause) {
+
+ val blacklistPackages = Set("chisel3", "scala", "java", "sun", "sbt")
+ val builderName = "chisel3.internal.Builder"
+
+ /** trims the top of the stack of elements belonging to [[blacklistPackages]]
+ * then trims the bottom elements until it reaches [[builderName]]
+ * then continues trimming elements belonging to [[blacklistPackages]]
+ */
+ def trimmedStackTrace: Array[StackTraceElement] = {
+ def isBlacklisted(ste: StackTraceElement) = {
+ val packageName = ste.getClassName().takeWhile(_ != '.')
+ blacklistPackages.contains(packageName)
+ }
+
+ val trimmedLeft = getStackTrace().view.dropWhile(isBlacklisted)
+ val trimmedReverse = trimmedLeft.reverse
+ .dropWhile(ste => !ste.getClassName.startsWith(builderName))
+ .dropWhile(isBlacklisted)
+ trimmedReverse.reverse.toArray
+ }
+
+ def chiselStackTrace: String = {
+ val trimmed = trimmedStackTrace
+ val sw = new java.io.StringWriter
+ sw.write(toString + "\n")
+ sw.write("\t...\n")
+ trimmed.foreach(ste => sw.write(s"\tat $ste\n"))
+ sw.write("\t... (Stack trace trimmed to user code only, rerun with --full-stacktrace if you wish to see the full stack trace)\n")
+ sw.toString
+ }
+}
private[chisel3] object throwException {
def apply(s: String, t: Throwable = null): Nothing =
@@ -14,6 +45,12 @@ private[chisel3] object throwException {
}
/** Records and reports runtime errors and warnings. */
+private[chisel3] object ErrorLog {
+ val depTag = s"[${Console.BLUE}deprecated${Console.RESET}]"
+ val warnTag = s"[${Console.YELLOW}warn${Console.RESET}]"
+ val errTag = s"[${Console.RED}error${Console.RESET}]"
+}
+
private[chisel3] class ErrorLog {
/** Log an error message */
def error(m: => String): Unit =
@@ -43,33 +80,30 @@ private[chisel3] class ErrorLog {
/** Throw an exception if any errors have yet occurred. */
def checkpoint(): Unit = {
- val depTag = s"[${Console.BLUE}deprecated${Console.RESET}]"
- val warnTag = s"[${Console.YELLOW}warn${Console.RESET}]"
- val errTag = s"[${Console.RED}error${Console.RESET}]"
deprecations.foreach { case ((message, sourceLoc), count) =>
- println(s"$depTag $sourceLoc ($count calls): $message")
+ println(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message")
}
errors foreach println
if (!deprecations.isEmpty) {
- println(s"$warnTag ${Console.YELLOW}There were ${deprecations.size} deprecated function(s) used." +
+ println(s"${ErrorLog.warnTag} ${Console.YELLOW}There were ${deprecations.size} deprecated function(s) used." +
s" These may stop compiling in a future release - you are encouraged to fix these issues.${Console.RESET}")
- println(s"$warnTag Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods:")
- println(s"$warnTag In the sbt interactive console, enter:")
- println(s"""$warnTag set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")""")
- println(s"$warnTag or, in your build.sbt, add the line:")
- println(s"""$warnTag scalacOptions := Seq("-unchecked", "-deprecation")""")
+ println(s"${ErrorLog.warnTag} Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods:")
+ println(s"${ErrorLog.warnTag} In the sbt interactive console, enter:")
+ println(s"""${ErrorLog.warnTag} set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")""")
+ println(s"${ErrorLog.warnTag} or, in your build.sbt, add the line:")
+ println(s"""${ErrorLog.warnTag} scalacOptions := Seq("-unchecked", "-deprecation")""")
}
val allErrors = errors.filter(_.isFatal)
val allWarnings = errors.filter(!_.isFatal)
if (!allWarnings.isEmpty && !allErrors.isEmpty) {
- println(s"$errTag There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} and ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ println(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} and ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
} else if (!allWarnings.isEmpty) {
- println(s"$warnTag There were ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ println(s"${ErrorLog.warnTag} There were ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
} else if (!allErrors.isEmpty) {
- println(s"$errTag There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} during hardware elaboration.")
+ println(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} during hardware elaboration.")
}
if (!allErrors.isEmpty) {
diff --git a/src/main/scala/chisel3/ChiselExecutionOptions.scala b/src/main/scala/chisel3/ChiselExecutionOptions.scala
index 6f58153f..a3644829 100644
--- a/src/main/scala/chisel3/ChiselExecutionOptions.scala
+++ b/src/main/scala/chisel3/ChiselExecutionOptions.scala
@@ -13,7 +13,8 @@ import firrtl.{ExecutionOptionsManager, ComposableOptions}
* @note this extends FirrtlExecutionOptions which extends CommonOptions providing easy access to down chain options
*/
case class ChiselExecutionOptions(
- runFirrtlCompiler: Boolean = true
+ runFirrtlCompiler: Boolean = true,
+ printFullStackTrace: Boolean = false
// var runFirrtlAsProcess: Boolean = false
) extends ComposableOptions
@@ -30,5 +31,11 @@ trait HasChiselExecutionOptions {
chiselOptions = chiselOptions.copy(runFirrtlCompiler = false)
}
.text("Stop after chisel emits chirrtl file")
+
+ parser.opt[Unit]("full-stacktrace")
+ .foreach { _ =>
+ chiselOptions = chiselOptions.copy(printFullStackTrace = true)
+ }
+ .text("Do not trim stack trace")
}
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index c0570662..9be129be 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -2,6 +2,7 @@
package chisel3
+import chisel3.internal.ErrorLog
import chisel3.internal.firrtl.Converter
import chisel3.experimental.{RawModule, RunFirrtlTransform}
@@ -172,7 +173,7 @@ object Driver extends BackendCompilationUtilities {
/**
* Run the chisel3 compiler and possibly the firrtl compiler with options specified
- *
+ *
* @param optionsManager The options specified
* @param dut The device under test
* @return An execution result with useful stuff, or failure with message
@@ -180,57 +181,72 @@ object Driver extends BackendCompilationUtilities {
def execute(
optionsManager: ExecutionOptionsManager with HasChiselExecutionOptions with HasFirrtlOptions,
dut: () => RawModule): ChiselExecutionResult = {
- val circuit = elaborate(dut)
-
- // this little hack let's us set the topName with the circuit name if it has not been set from args
- optionsManager.setTopNameIfNotSet(circuit.name)
-
- val firrtlOptions = optionsManager.firrtlOptions
- val chiselOptions = optionsManager.chiselOptions
-
- val firrtlCircuit = Converter.convert(circuit)
-
- // Still emit to leave an artifact (and because this always has been the behavior)
- val firrtlString = Driver.emit(circuit)
- val firrtlFileName = firrtlOptions.getInputFileName(optionsManager)
- val firrtlFile = new File(firrtlFileName)
-
- val w = new FileWriter(firrtlFile)
- w.write(firrtlString)
- w.close()
-
- // Emit the annotations because it has always been the behavior
- val annotationFile = new File(optionsManager.getBuildFileName("anno.json"))
- val af = new FileWriter(annotationFile)
- val firrtlAnnos = circuit.annotations.map(_.toFirrtl)
- af.write(JsonProtocol.serialize(firrtlAnnos))
- af.close()
-
- /** Find the set of transform classes associated with annotations then
- * instantiate an instance of each transform
- * @note Annotations targeting firrtl.Transform will not result in any
- * transform being instantiated
- */
- val transforms = circuit.annotations
- .collect { case anno: RunFirrtlTransform => anno.transformClass }
- .distinct
- .filterNot(_ == classOf[firrtl.Transform])
- .map { transformClass: Class[_ <: Transform] =>
- transformClass.newInstance()
- }
- /* This passes the firrtl source and annotations directly to firrtl */
- optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy(
- firrtlCircuit = Some(firrtlCircuit),
- annotations = optionsManager.firrtlOptions.annotations ++ firrtlAnnos,
- customTransforms = optionsManager.firrtlOptions.customTransforms ++ transforms.toList)
-
- val firrtlExecutionResult = if(chiselOptions.runFirrtlCompiler) {
- Some(firrtl.Driver.execute(optionsManager))
- }
- else {
- None
+ val circuitOpt = try {
+ Some(elaborate(dut))
+ } catch {
+ case ce: ChiselException =>
+ val stackTrace = if (!optionsManager.chiselOptions.printFullStackTrace) {
+ ce.chiselStackTrace
+ } else {
+ val sw = new StringWriter
+ ce.printStackTrace(new PrintWriter(sw))
+ sw.toString
+ }
+ stackTrace.lines.foreach(line => println(s"${ErrorLog.errTag} $line"))
+ None
}
- ChiselExecutionSuccess(Some(circuit), firrtlString, firrtlExecutionResult)
+
+ circuitOpt.map { circuit =>
+ // this little hack let's us set the topName with the circuit name if it has not been set from args
+ optionsManager.setTopNameIfNotSet(circuit.name)
+
+ val firrtlOptions = optionsManager.firrtlOptions
+ val chiselOptions = optionsManager.chiselOptions
+
+ val firrtlCircuit = Converter.convert(circuit)
+
+ // Still emit to leave an artifact (and because this always has been the behavior)
+ val firrtlString = Driver.emit(circuit)
+ val firrtlFileName = firrtlOptions.getInputFileName(optionsManager)
+ val firrtlFile = new File(firrtlFileName)
+
+ val w = new FileWriter(firrtlFile)
+ w.write(firrtlString)
+ w.close()
+
+ // Emit the annotations because it has always been the behavior
+ val annotationFile = new File(optionsManager.getBuildFileName("anno.json"))
+ val af = new FileWriter(annotationFile)
+ val firrtlAnnos = circuit.annotations.map(_.toFirrtl)
+ af.write(JsonProtocol.serialize(firrtlAnnos))
+ af.close()
+
+ /** Find the set of transform classes associated with annotations then
+ * instantiate an instance of each transform
+ * @note Annotations targeting firrtl.Transform will not result in any
+ * transform being instantiated
+ */
+ val transforms = circuit.annotations
+ .collect { case anno: RunFirrtlTransform => anno.transformClass }
+ .distinct
+ .filterNot(_ == classOf[firrtl.Transform])
+ .map { transformClass: Class[_ <: Transform] =>
+ transformClass.newInstance()
+ }
+ /* This passes the firrtl source and annotations directly to firrtl */
+ optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy(
+ firrtlCircuit = Some(firrtlCircuit),
+ annotations = optionsManager.firrtlOptions.annotations ++ firrtlAnnos,
+ customTransforms = optionsManager.firrtlOptions.customTransforms ++ transforms.toList)
+
+ val firrtlExecutionResult = if(chiselOptions.runFirrtlCompiler) {
+ Some(firrtl.Driver.execute(optionsManager))
+ }
+ else {
+ None
+ }
+ ChiselExecutionSuccess(Some(circuit), firrtlString, firrtlExecutionResult)
+ }.getOrElse(ChiselExecutionFailure("could not elaborate circuit"))
}
/**
diff --git a/src/test/scala/chiselTests/DontTouchSpec.scala b/src/test/scala/chiselTests/DontTouchSpec.scala
index 7aa4d2e2..6759222c 100644
--- a/src/test/scala/chiselTests/DontTouchSpec.scala
+++ b/src/test/scala/chiselTests/DontTouchSpec.scala
@@ -53,7 +53,7 @@ class DontTouchSpec extends ChiselFlatSpec {
}
"Dont touch" should "only work on bound hardware" in {
a [chisel3.core.Binding.BindingException] should be thrownBy {
- compile(new Module {
+ elaborate(new Module {
val io = IO(new Bundle { })
dontTouch(new Bundle { val a = UInt(32.W) } )
})