diff options
| author | ducky | 2015-10-26 17:42:03 -0700 |
|---|---|---|
| committer | ducky | 2015-10-26 17:42:03 -0700 |
| commit | d6c7044bff31aae09931df8d4350d29414b37447 (patch) | |
| tree | ba1d2f93fbd0af8acd54c55f13c38d51a1180f64 /src/main/scala/Chisel/internal | |
| parent | 9430600381d52b10a6f5aad7140f355c3abf963c (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.scala | 118 | ||||
| -rw-r--r-- | src/main/scala/Chisel/internal/Error.scala | 88 |
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) +} |
