summaryrefslogtreecommitdiff
path: root/src/main/scala/Chisel/internal
diff options
context:
space:
mode:
authorducky2015-10-26 17:42:03 -0700
committerducky2015-10-26 17:42:03 -0700
commitd6c7044bff31aae09931df8d4350d29414b37447 (patch)
treeba1d2f93fbd0af8acd54c55f13c38d51a1180f64 /src/main/scala/Chisel/internal
parent9430600381d52b10a6f5aad7140f355c3abf963c (diff)
Move internal files into their own directories
Diffstat (limited to 'src/main/scala/Chisel/internal')
-rw-r--r--src/main/scala/Chisel/internal/Builder.scala118
-rw-r--r--src/main/scala/Chisel/internal/Error.scala88
2 files changed, 206 insertions, 0 deletions
diff --git a/src/main/scala/Chisel/internal/Builder.scala b/src/main/scala/Chisel/internal/Builder.scala
new file mode 100644
index 00000000..b3c4ae40
--- /dev/null
+++ b/src/main/scala/Chisel/internal/Builder.scala
@@ -0,0 +1,118 @@
+// See LICENSE for license details.
+
+package Chisel
+import scala.util.DynamicVariable
+import scala.collection.mutable.{ArrayBuffer, HashMap}
+
+private class Namespace(parent: Option[Namespace], keywords: Set[String]) {
+ private var i = 0L
+ private val names = collection.mutable.HashSet[String]()
+
+ private def rename(n: String) = { i += 1; s"${n}_${i}" }
+
+ def contains(elem: String): Boolean = {
+ keywords.contains(elem) || names.contains(elem) ||
+ parent.map(_ contains elem).getOrElse(false)
+ }
+
+ def name(elem: String): String = {
+ if (this contains elem) {
+ name(rename(elem))
+ } else {
+ names += elem
+ elem
+ }
+ }
+
+ def child(kws: Set[String]): Namespace = new Namespace(Some(this), kws)
+ def child: Namespace = child(Set())
+}
+
+private class IdGen {
+ private var counter = -1L
+ def next: Long = {
+ counter += 1
+ counter
+ }
+}
+
+private[Chisel] trait HasId {
+ private[Chisel] def _onModuleClose {}
+ private[Chisel] val _parent = Builder.dynamicContext.currentModule
+ _parent.foreach(_.addId(this))
+
+ private[Chisel] val _refMap = Builder.globalRefMap
+ private[Chisel] val _id = Builder.idGen.next
+ private[Chisel] def setRef(imm: Arg) = _refMap.setRef(this, imm)
+ private[Chisel] def setRef(name: String) = _refMap.setRef(this, name)
+ private[Chisel] def setRef(parent: HasId, name: String) = _refMap.setField(parent, this, name)
+ private[Chisel] def setRef(parent: HasId, index: Int) = _refMap.setIndex(parent, this, index)
+ private[Chisel] def getRef = _refMap(this)
+}
+
+class RefMap {
+ private val _refmap = new HashMap[Long,Arg]()
+
+ private[Chisel] def setRef(id: HasId, ref: Arg): Unit =
+ _refmap(id._id) = ref
+
+ private[Chisel] def setRef(id: HasId, name: String): Unit =
+ if (!_refmap.contains(id._id)) setRef(id, Ref(name))
+
+ private[Chisel] def setField(parentid: HasId, id: HasId, name: String): Unit =
+ _refmap(id._id) = Slot(Node(parentid), name)
+
+ private[Chisel] def setIndex(parentid: HasId, id: HasId, index: Int): Unit =
+ _refmap(id._id) = Index(Node(parentid), index)
+
+ def apply(id: HasId): Arg = _refmap(id._id)
+}
+
+private class DynamicContext {
+ val idGen = new IdGen
+ val globalNamespace = new Namespace(None, Set())
+ val globalRefMap = new RefMap
+ val components = ArrayBuffer[Component]()
+ var currentModule: Option[Module] = None
+ val parameterDump = new ParameterDump
+ val errors = new ErrorLog
+}
+
+private object Builder {
+ // All global mutable state must be referenced via dynamicContextVar!!
+ private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)
+ private val currentParamsVar = new DynamicVariable[Parameters](Parameters.empty)
+
+ def dynamicContext: DynamicContext = dynamicContextVar.value.get
+ def idGen: IdGen = dynamicContext.idGen
+ def globalNamespace: Namespace = dynamicContext.globalNamespace
+ def globalRefMap: RefMap = dynamicContext.globalRefMap
+ def components: ArrayBuffer[Component] = dynamicContext.components
+ def parameterDump: ParameterDump = dynamicContext.parameterDump
+
+ def pushCommand[T <: Command](c: T): T = {
+ dynamicContext.currentModule.foreach(_._commands += c)
+ c
+ }
+ def pushOp[T <: Data](cmd: DefPrim[T]): T = pushCommand(cmd).id
+
+ def errors: ErrorLog = dynamicContext.errors
+ def error(m: => String): Unit = errors.error(m)
+
+ def getParams: Parameters = currentParamsVar.value
+ def paramsScope[T](p: Parameters)(body: => T): T = {
+ currentParamsVar.withValue(p)(body)
+ }
+
+ def build[T <: Module](f: => T): Circuit = {
+ dynamicContextVar.withValue(Some(new DynamicContext)) {
+ errors.info("Elaborating design...")
+ val mod = f
+ mod.setRef(globalNamespace.name(mod.name))
+ errors.checkpoint()
+ errors.info("Done elaborating.")
+
+ Circuit(components.last.name, components, globalRefMap, parameterDump)
+ }
+ }
+}
diff --git a/src/main/scala/Chisel/internal/Error.scala b/src/main/scala/Chisel/internal/Error.scala
new file mode 100644
index 00000000..30f6b527
--- /dev/null
+++ b/src/main/scala/Chisel/internal/Error.scala
@@ -0,0 +1,88 @@
+// See LICENSE for license details.
+
+package Chisel
+import scala.collection.mutable.ArrayBuffer
+
+class ChiselException(message: String, cause: Throwable) extends Exception(message, cause)
+
+private object throwException {
+ def apply(s: String, t: Throwable = null): Nothing =
+ throw new ChiselException(s, t)
+}
+
+/** Records and reports runtime errors and warnings. */
+private class ErrorLog {
+ def hasErrors: Boolean = errors.exists(_.isFatal)
+
+ /** Log an error message */
+ def error(m: => String): Unit =
+ errors += new Error(m, getUserLineNumber)
+
+ /** Log a warning message */
+ def warning(m: => String): Unit =
+ errors += new Warning(m, getUserLineNumber)
+
+ /** Emit an informational message */
+ def info(m: String): Unit =
+ println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None))
+
+ /** Prints error messages generated by Chisel at runtime. */
+ def report(): Unit = errors foreach println
+
+ /** Throw an exception if any errors have yet occurred. */
+ def checkpoint(): Unit = if(hasErrors) {
+ import Console._
+ throwException(errors.map(_ + "\n").reduce(_ + _) +
+ UNDERLINED + "CODE HAS " + errors.filter(_.isFatal).length + RESET +
+ UNDERLINED + " " + RED + "ERRORS" + RESET +
+ UNDERLINED + " and " + errors.filterNot(_.isFatal).length + RESET +
+ UNDERLINED + " " + YELLOW + "WARNINGS" + RESET)
+ }
+
+ private def findFirstUserFrame(stack: Array[StackTraceElement]): Option[StackTraceElement] = {
+ def isUserCode(ste: StackTraceElement): Boolean = {
+ def isUserModule(c: Class[_]): Boolean =
+ c != null && (c == classOf[Module] || isUserModule(c.getSuperclass))
+ isUserModule(Class.forName(ste.getClassName))
+ }
+
+ stack.indexWhere(isUserCode) match {
+ case x if x < 0 => None
+ case x => Some(stack(x))
+ }
+ }
+
+ private def getUserLineNumber =
+ findFirstUserFrame(Thread.currentThread().getStackTrace)
+
+ private val errors = ArrayBuffer[LogEntry]()
+
+ private val startTime = System.currentTimeMillis
+ private def elapsedTime: Long = System.currentTimeMillis - startTime
+}
+
+private abstract class LogEntry(msg: => String, line: Option[StackTraceElement]) {
+ def isFatal: Boolean = false
+ def format: String
+
+ override def toString: String = line match {
+ case Some(l) => s"${format} ${l.getFileName}:${l.getLineNumber}: ${msg} in class ${l.getClassName}"
+ case None => s"${format} ${msg}"
+ }
+
+ protected def tag(name: String, color: String): String =
+ s"[${color}${name}${Console.RESET}]"
+}
+
+private class Error(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ override def isFatal: Boolean = true
+ def format: String = tag("error", Console.RED)
+}
+
+private class Warning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("warn", Console.YELLOW)
+}
+
+private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("info", Console.MAGENTA)
+}